@factory/droid-sdk 0.3.0 → 0.4.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/dist/index.cjs +1601 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +908 -13
- package/dist/index.d.ts +908 -13
- package/dist/index.js +1566 -70
- package/dist/index.js.map +1 -1
- package/docs/daemon-usage-guide.md +544 -0
- package/docs/sdk-usage-guide.md +103 -33
- package/examples/abort-session-stream.ts +4 -1
- package/examples/daemon-multi-session.ts +67 -0
- package/examples/droid-dev-structured-output.ts +1 -0
- package/examples/fork-session.ts +10 -3
- package/examples/hook-execution.ts +7 -1
- package/examples/init-metadata.ts +7 -2
- package/examples/interrupt-session.ts +7 -4
- package/examples/multi-turn-session.ts +7 -2
- package/examples/permission-handler.ts +1 -0
- package/examples/readme-structured-output.ts +1 -0
- package/examples/result-metadata.ts +1 -0
- package/examples/run.ts +1 -0
- package/examples/sdk-mcp-tool.ts +3 -1
- package/examples/session-stream.ts +4 -1
- package/examples/spec-mode-new-session.ts +1 -0
- package/examples/spec-mode-same-session.ts +1 -0
- package/examples/structured-output.ts +1 -0
- package/examples/test-compact.ts +4 -1
- package/examples/tool-controls.ts +1 -0
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -79,13 +79,22 @@ __export(index_exports, {
|
|
|
79
79
|
CompactSessionRequestSchema: () => CompactSessionRequestSchema,
|
|
80
80
|
CompactSessionResponseSchema: () => CompactSessionResponseSchema,
|
|
81
81
|
CompactSessionResultSchema: () => CompactSessionResultSchema,
|
|
82
|
+
ComputerListResponseSchema: () => ComputerListResponseSchema,
|
|
83
|
+
ComputerMetricSchema: () => ComputerMetricSchema,
|
|
84
|
+
ComputerMetricsResponseSchema: () => ComputerMetricsResponseSchema,
|
|
85
|
+
ComputerSchema: () => ComputerSchema,
|
|
82
86
|
ConnectionError: () => ConnectionError,
|
|
83
87
|
ContentBlockSchema: () => ContentBlockSchema,
|
|
88
|
+
ContextBreakdownCategorySchema: () => ContextBreakdownCategorySchema,
|
|
89
|
+
ContextBreakdownResultSchema: () => ContextBreakdownResultSchema,
|
|
84
90
|
ContextStatsAccuracy: () => ContextStatsAccuracy,
|
|
85
91
|
ContextStatsSchema: () => ContextStatsSchema,
|
|
86
92
|
CreateMessageNotificationSchema: () => CreateMessageNotificationSchema,
|
|
87
93
|
CreateToolConfirmationDetailsSchema: () => CreateToolConfirmationDetailsSchema,
|
|
88
94
|
DEFAULT_REQUEST_TIMEOUT: () => DEFAULT_REQUEST_TIMEOUT,
|
|
95
|
+
DaemonClient: () => DaemonClient,
|
|
96
|
+
DaemonConnection: () => DaemonConnection,
|
|
97
|
+
DaemonSession: () => DaemonSession,
|
|
89
98
|
DecompSessionType: () => DecompSessionType,
|
|
90
99
|
DiscoveredIssueSchema: () => DiscoveredIssueSchema,
|
|
91
100
|
DismissalRecordSchema: () => DismissalRecordSchema,
|
|
@@ -200,6 +209,10 @@ __export(index_exports, {
|
|
|
200
209
|
LoadSessionResponseSchema: () => LoadSessionResponseSchema,
|
|
201
210
|
LoadSessionResultSchema: () => LoadSessionResultSchema,
|
|
202
211
|
MCP_AUTH_TIMEOUT: () => MCP_AUTH_TIMEOUT,
|
|
212
|
+
MachineTemplateBuildStatusSchema: () => MachineTemplateBuildStatusSchema,
|
|
213
|
+
MachineTemplateListResponseSchema: () => MachineTemplateListResponseSchema,
|
|
214
|
+
MachineTemplateSchema: () => MachineTemplateSchema,
|
|
215
|
+
MachineType: () => MachineType,
|
|
203
216
|
McpAuthCompletedNotificationSchema: () => McpAuthCompletedNotificationSchema,
|
|
204
217
|
McpAuthOutcome: () => McpAuthOutcome,
|
|
205
218
|
McpAuthRequiredNotificationSchema: () => McpAuthRequiredNotificationSchema,
|
|
@@ -245,6 +258,9 @@ __export(index_exports, {
|
|
|
245
258
|
REWIND_TIMEOUT: () => REWIND_TIMEOUT,
|
|
246
259
|
ReasoningEffort: () => ReasoningEffort,
|
|
247
260
|
RedactedThinkingBlockSchema: () => RedactedThinkingBlockSchema,
|
|
261
|
+
RefreshComputerResponseSchema: () => RefreshComputerResponseSchema,
|
|
262
|
+
RemoteSessionListResponseSchema: () => RemoteSessionListResponseSchema,
|
|
263
|
+
RemoteSessionSchema: () => RemoteSessionSchema,
|
|
248
264
|
RemoveMcpServerRequestParamsSchema: () => RemoveMcpServerRequestParamsSchema,
|
|
249
265
|
RemoveMcpServerRequestSchema: () => RemoveMcpServerRequestSchema,
|
|
250
266
|
RemoveMcpServerResponseSchema: () => RemoveMcpServerResponseSchema,
|
|
@@ -264,6 +280,7 @@ __export(index_exports, {
|
|
|
264
280
|
SDK_VERSION: () => SDK_VERSION,
|
|
265
281
|
SESSION_INIT_TIMEOUT: () => SESSION_INIT_TIMEOUT,
|
|
266
282
|
SdkMcpServer: () => SdkMcpServer,
|
|
283
|
+
ServerRequestHandlerType: () => ServerRequestHandlerType,
|
|
267
284
|
SessionError: () => SessionError,
|
|
268
285
|
SessionMetadataSchema: () => SessionMetadataSchema,
|
|
269
286
|
SessionNotFoundError: () => SessionNotFoundError,
|
|
@@ -339,21 +356,38 @@ __export(index_exports, {
|
|
|
339
356
|
UpdateSessionSettingsResultSchema: () => UpdateSessionSettingsResultSchema,
|
|
340
357
|
VerificationCommandSchema: () => VerificationCommandSchema,
|
|
341
358
|
VerificationSchema: () => VerificationSchema,
|
|
359
|
+
WebSocketTransport: () => WebSocketTransport,
|
|
342
360
|
WorkerCompletedEntrySchema: () => WorkerCompletedEntrySchema,
|
|
343
361
|
WorkerFailedEntrySchema: () => WorkerFailedEntrySchema,
|
|
344
362
|
WorkerPausedEntrySchema: () => WorkerPausedEntrySchema,
|
|
345
363
|
WorkerSelectedFeatureEntrySchema: () => WorkerSelectedFeatureEntrySchema,
|
|
346
364
|
WorkerStartedEntrySchema: () => WorkerStartedEntrySchema,
|
|
347
365
|
WorkerStateInfoSchema: () => WorkerStateInfoSchema,
|
|
366
|
+
connectDaemon: () => connectDaemon,
|
|
348
367
|
convertNotificationToStreamMessage: () => convertNotificationToStreamMessage,
|
|
368
|
+
createComputer: () => createComputer,
|
|
349
369
|
createResponseSchema: () => createResponseSchema,
|
|
350
370
|
createSdkMcpServer: () => createSdkMcpServer,
|
|
351
371
|
createSession: () => createSession,
|
|
372
|
+
deleteComputer: () => deleteComputer,
|
|
352
373
|
dispatchNotification: () => dispatchNotification,
|
|
374
|
+
ensureLocalDaemon: () => ensureLocalDaemon,
|
|
375
|
+
getComputer: () => getComputer,
|
|
376
|
+
getComputerByName: () => getComputerByName,
|
|
377
|
+
getComputerMetrics: () => getComputerMetrics,
|
|
378
|
+
getMachineTemplate: () => getMachineTemplate,
|
|
379
|
+
listComputers: () => listComputers,
|
|
380
|
+
listMachineTemplates: () => listMachineTemplates,
|
|
381
|
+
listRemoteSessions: () => listRemoteSessions,
|
|
353
382
|
listSessions: () => listSessions,
|
|
383
|
+
refreshComputer: () => refreshComputer,
|
|
384
|
+
resolveWebSocketUrl: () => resolveWebSocketUrl,
|
|
385
|
+
restartComputer: () => restartComputer,
|
|
354
386
|
resumeSession: () => resumeSession,
|
|
387
|
+
retryInstallDeps: () => retryInstallDeps,
|
|
355
388
|
run: () => run,
|
|
356
|
-
tool: () => tool
|
|
389
|
+
tool: () => tool,
|
|
390
|
+
updateComputer: () => updateComputer
|
|
357
391
|
});
|
|
358
392
|
module.exports = __toCommonJS(index_exports);
|
|
359
393
|
|
|
@@ -614,6 +648,11 @@ var JsonRpcMessageType = /* @__PURE__ */ ((JsonRpcMessageType2) => {
|
|
|
614
648
|
JsonRpcMessageType2["Notification"] = "notification";
|
|
615
649
|
return JsonRpcMessageType2;
|
|
616
650
|
})(JsonRpcMessageType || {});
|
|
651
|
+
var ServerRequestHandlerType = /* @__PURE__ */ ((ServerRequestHandlerType2) => {
|
|
652
|
+
ServerRequestHandlerType2["Permission"] = "permission";
|
|
653
|
+
ServerRequestHandlerType2["AskUser"] = "askUser";
|
|
654
|
+
return ServerRequestHandlerType2;
|
|
655
|
+
})(ServerRequestHandlerType || {});
|
|
617
656
|
var SettingsLevel = /* @__PURE__ */ ((SettingsLevel2) => {
|
|
618
657
|
SettingsLevel2["Org"] = "org";
|
|
619
658
|
SettingsLevel2["Runtime"] = "runtime";
|
|
@@ -634,7 +673,7 @@ var SkillLocation = /* @__PURE__ */ ((SkillLocation2) => {
|
|
|
634
673
|
// src/schemas/constants.ts
|
|
635
674
|
var JSONRPC_VERSION = "2.0";
|
|
636
675
|
var LEGACY_FACTORY_API_VERSION = "1.0.0";
|
|
637
|
-
var FACTORY_PROTOCOL_VERSION = "1.
|
|
676
|
+
var FACTORY_PROTOCOL_VERSION = "1.51.0";
|
|
638
677
|
var FACTORY_CLIENT_HEADER = "X-Factory-Client";
|
|
639
678
|
var FACTORY_CLIENT_VERSION = "X-Client-Version";
|
|
640
679
|
var DEFAULT_REQUEST_TIMEOUT = 3e4;
|
|
@@ -1494,6 +1533,19 @@ var ForkSessionResultSchema = import_zod5.z.object({
|
|
|
1494
1533
|
newSessionId: import_zod5.z.string()
|
|
1495
1534
|
}).passthrough();
|
|
1496
1535
|
var GetContextStatsResultSchema = ContextStatsSchema;
|
|
1536
|
+
var ContextBreakdownCategorySchema = import_zod5.z.object({
|
|
1537
|
+
name: import_zod5.z.string(),
|
|
1538
|
+
tokens: import_zod5.z.number(),
|
|
1539
|
+
colorKey: import_zod5.z.string()
|
|
1540
|
+
}).passthrough();
|
|
1541
|
+
var ContextBreakdownResultSchema = import_zod5.z.object({
|
|
1542
|
+
modelId: import_zod5.z.string(),
|
|
1543
|
+
modelDisplayName: import_zod5.z.string(),
|
|
1544
|
+
contextBudget: import_zod5.z.number(),
|
|
1545
|
+
usedTokens: import_zod5.z.number(),
|
|
1546
|
+
freeTokens: import_zod5.z.number(),
|
|
1547
|
+
categories: import_zod5.z.array(ContextBreakdownCategorySchema)
|
|
1548
|
+
}).passthrough();
|
|
1497
1549
|
var RenameSessionResultSchema = SuccessResultSchema;
|
|
1498
1550
|
var InitializeSessionResponseSchema = createResponseSchema(
|
|
1499
1551
|
InitializeSessionResultSchema
|
|
@@ -1997,7 +2049,7 @@ var _CliRequestOrNotificationSchema = import_zod8.z.union([
|
|
|
1997
2049
|
var CliRequestOrNotificationSchema = _CliRequestOrNotificationSchema;
|
|
1998
2050
|
|
|
1999
2051
|
// src/constants.ts
|
|
2000
|
-
var SDK_VERSION = "0.
|
|
2052
|
+
var SDK_VERSION = "0.4.0";
|
|
2001
2053
|
var SDK_TAG = {
|
|
2002
2054
|
name: "sdk",
|
|
2003
2055
|
metadata: { language: "typescript", version: SDK_VERSION }
|
|
@@ -2331,9 +2383,14 @@ function dispatchNotification(notification, listeners) {
|
|
|
2331
2383
|
}
|
|
2332
2384
|
}
|
|
2333
2385
|
}
|
|
2386
|
+
var DEFAULT_SERVER_REQUEST_METHOD_MAP = {
|
|
2387
|
+
["droid.request_permission" /* REQUEST_PERMISSION */]: "permission" /* Permission */,
|
|
2388
|
+
["droid.ask_user" /* ASK_USER */]: "askUser" /* AskUser */
|
|
2389
|
+
};
|
|
2334
2390
|
var ProtocolEngine = class {
|
|
2335
2391
|
_transport;
|
|
2336
2392
|
_defaultTimeout;
|
|
2393
|
+
_serverRequestMethodMap;
|
|
2337
2394
|
_pendingRequests = /* @__PURE__ */ new Map();
|
|
2338
2395
|
_notificationListeners = /* @__PURE__ */ new Set();
|
|
2339
2396
|
_permissionHandler = null;
|
|
@@ -2343,6 +2400,7 @@ var ProtocolEngine = class {
|
|
|
2343
2400
|
constructor(options) {
|
|
2344
2401
|
this._transport = options.transport;
|
|
2345
2402
|
this._defaultTimeout = options.defaultTimeout ?? DEFAULT_REQUEST_TIMEOUT;
|
|
2403
|
+
this._serverRequestMethodMap = options.serverRequestMethodMap ?? DEFAULT_SERVER_REQUEST_METHOD_MAP;
|
|
2346
2404
|
this._transport.onMessage((message) => {
|
|
2347
2405
|
this._handleMessage(message);
|
|
2348
2406
|
});
|
|
@@ -2498,9 +2556,10 @@ var ProtocolEngine = class {
|
|
|
2498
2556
|
dispatchNotification(notification, this._notificationListeners);
|
|
2499
2557
|
}
|
|
2500
2558
|
async _handleServerRequest(method, requestId, params) {
|
|
2501
|
-
|
|
2559
|
+
const handlerType = this._serverRequestMethodMap[method];
|
|
2560
|
+
if (handlerType === "permission" /* Permission */) {
|
|
2502
2561
|
await this._handlePermissionRequest(requestId, params);
|
|
2503
|
-
} else if (
|
|
2562
|
+
} else if (handlerType === "askUser" /* AskUser */) {
|
|
2504
2563
|
await this._handleAskUserRequest(requestId, params);
|
|
2505
2564
|
}
|
|
2506
2565
|
}
|
|
@@ -3358,6 +3417,69 @@ function wireAbortSignal(signal, onAbort) {
|
|
|
3358
3417
|
return () => signal.removeEventListener("abort", listener);
|
|
3359
3418
|
}
|
|
3360
3419
|
}
|
|
3420
|
+
function getAbortError(signal) {
|
|
3421
|
+
if (signal.reason instanceof Error) {
|
|
3422
|
+
return signal.reason;
|
|
3423
|
+
}
|
|
3424
|
+
return new Error(
|
|
3425
|
+
typeof signal.reason === "string" ? signal.reason : "Operation aborted"
|
|
3426
|
+
);
|
|
3427
|
+
}
|
|
3428
|
+
function throwIfAborted(signal) {
|
|
3429
|
+
if (signal?.aborted) {
|
|
3430
|
+
throw getAbortError(signal);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
async function* streamFromClient(client, sessionId, activeBridges, prompt, options) {
|
|
3434
|
+
throwIfAborted(options?.abortSignal);
|
|
3435
|
+
const startedAt = Date.now();
|
|
3436
|
+
let resolveDone = () => {
|
|
3437
|
+
};
|
|
3438
|
+
const donePromise = new Promise((resolve2) => {
|
|
3439
|
+
resolveDone = resolve2;
|
|
3440
|
+
});
|
|
3441
|
+
const bridge = new MessageBridge(resolveDone, {
|
|
3442
|
+
includePartialMessages: options?.includePartialMessages,
|
|
3443
|
+
sessionId,
|
|
3444
|
+
startedAt,
|
|
3445
|
+
outputFormat: options?.outputFormat
|
|
3446
|
+
});
|
|
3447
|
+
activeBridges.add(bridge);
|
|
3448
|
+
const unsubscribe = client.onNotification(bridge.notificationHandler);
|
|
3449
|
+
let resolveAbort = () => {
|
|
3450
|
+
};
|
|
3451
|
+
const abortPromise = new Promise((resolve2) => {
|
|
3452
|
+
resolveAbort = resolve2;
|
|
3453
|
+
});
|
|
3454
|
+
const cleanupAbortSignal = wireAbortSignal(options?.abortSignal, () => {
|
|
3455
|
+
bridge.signalDone();
|
|
3456
|
+
resolveAbort();
|
|
3457
|
+
void client.interruptSession().catch(() => {
|
|
3458
|
+
});
|
|
3459
|
+
});
|
|
3460
|
+
try {
|
|
3461
|
+
await Promise.race([
|
|
3462
|
+
client.addUserMessage({
|
|
3463
|
+
text: prompt,
|
|
3464
|
+
images: options?.images,
|
|
3465
|
+
files: options?.files,
|
|
3466
|
+
outputFormat: options?.outputFormat
|
|
3467
|
+
}),
|
|
3468
|
+
donePromise,
|
|
3469
|
+
abortPromise
|
|
3470
|
+
]);
|
|
3471
|
+
throwIfAborted(options?.abortSignal);
|
|
3472
|
+
for await (const msg of bridge.messages()) {
|
|
3473
|
+
throwIfAborted(options?.abortSignal);
|
|
3474
|
+
yield msg;
|
|
3475
|
+
}
|
|
3476
|
+
throwIfAborted(options?.abortSignal);
|
|
3477
|
+
} finally {
|
|
3478
|
+
cleanupAbortSignal();
|
|
3479
|
+
unsubscribe();
|
|
3480
|
+
activeBridges.delete(bridge);
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3361
3483
|
function extractInnerNotification(notification) {
|
|
3362
3484
|
const parsed = SessionNotificationSchema.safeParse(notification);
|
|
3363
3485
|
return parsed.success ? parsed.data.params.notification : null;
|
|
@@ -3453,7 +3575,7 @@ async function createTransport(options) {
|
|
|
3453
3575
|
execPath: options.execPath,
|
|
3454
3576
|
execArgs: options.execArgs,
|
|
3455
3577
|
cwd: options.cwd,
|
|
3456
|
-
env: options.env
|
|
3578
|
+
env: { ...options.env, FACTORY_API_KEY: options.apiKey }
|
|
3457
3579
|
};
|
|
3458
3580
|
const processTransport = new ProcessTransport(transportOptions);
|
|
3459
3581
|
await processTransport.connect();
|
|
@@ -3511,6 +3633,9 @@ function buildInitParams(options) {
|
|
|
3511
3633
|
...options.disabledToolIds !== void 0 && {
|
|
3512
3634
|
disabledToolIds: options.disabledToolIds
|
|
3513
3635
|
},
|
|
3636
|
+
...options.sessionSource !== void 0 && {
|
|
3637
|
+
sessionSource: options.sessionSource
|
|
3638
|
+
},
|
|
3514
3639
|
tags: [...options.tags ?? [], SDK_TAG]
|
|
3515
3640
|
};
|
|
3516
3641
|
}
|
|
@@ -3711,19 +3836,6 @@ async function startSdkMcpServers(servers) {
|
|
|
3711
3836
|
}
|
|
3712
3837
|
|
|
3713
3838
|
// src/session.ts
|
|
3714
|
-
function getAbortError(signal) {
|
|
3715
|
-
if (signal.reason instanceof Error) {
|
|
3716
|
-
return signal.reason;
|
|
3717
|
-
}
|
|
3718
|
-
return new Error(
|
|
3719
|
-
typeof signal.reason === "string" ? signal.reason : "Operation aborted"
|
|
3720
|
-
);
|
|
3721
|
-
}
|
|
3722
|
-
function throwIfAborted(signal) {
|
|
3723
|
-
if (signal?.aborted) {
|
|
3724
|
-
throw getAbortError(signal);
|
|
3725
|
-
}
|
|
3726
|
-
}
|
|
3727
3839
|
var DroidSession = class {
|
|
3728
3840
|
_client;
|
|
3729
3841
|
_sessionId;
|
|
@@ -3754,54 +3866,13 @@ var DroidSession = class {
|
|
|
3754
3866
|
}
|
|
3755
3867
|
async *stream(prompt, options) {
|
|
3756
3868
|
this._ensureNotClosed();
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
const bridge = new MessageBridge(resolveDone, {
|
|
3765
|
-
includePartialMessages: options?.includePartialMessages,
|
|
3766
|
-
sessionId: this._sessionId,
|
|
3767
|
-
startedAt,
|
|
3768
|
-
outputFormat: options?.outputFormat
|
|
3769
|
-
});
|
|
3770
|
-
this._activeBridges.add(bridge);
|
|
3771
|
-
const unsubscribe = this._client.onNotification(bridge.notificationHandler);
|
|
3772
|
-
let resolveAbort = () => {
|
|
3773
|
-
};
|
|
3774
|
-
const abortPromise = new Promise((resolve2) => {
|
|
3775
|
-
resolveAbort = resolve2;
|
|
3776
|
-
});
|
|
3777
|
-
const cleanupAbortSignal = wireAbortSignal(options?.abortSignal, () => {
|
|
3778
|
-
bridge.signalDone();
|
|
3779
|
-
resolveAbort();
|
|
3780
|
-
void this._client.interruptSession().catch(() => {
|
|
3781
|
-
});
|
|
3782
|
-
});
|
|
3783
|
-
try {
|
|
3784
|
-
await Promise.race([
|
|
3785
|
-
this._client.addUserMessage({
|
|
3786
|
-
text: prompt,
|
|
3787
|
-
images: options?.images,
|
|
3788
|
-
files: options?.files,
|
|
3789
|
-
outputFormat: options?.outputFormat
|
|
3790
|
-
}),
|
|
3791
|
-
donePromise,
|
|
3792
|
-
abortPromise
|
|
3793
|
-
]);
|
|
3794
|
-
throwIfAborted(options?.abortSignal);
|
|
3795
|
-
for await (const msg of bridge.messages()) {
|
|
3796
|
-
throwIfAborted(options?.abortSignal);
|
|
3797
|
-
yield msg;
|
|
3798
|
-
}
|
|
3799
|
-
throwIfAborted(options?.abortSignal);
|
|
3800
|
-
} finally {
|
|
3801
|
-
cleanupAbortSignal();
|
|
3802
|
-
unsubscribe();
|
|
3803
|
-
this._activeBridges.delete(bridge);
|
|
3804
|
-
}
|
|
3869
|
+
yield* streamFromClient(
|
|
3870
|
+
this._client,
|
|
3871
|
+
this._sessionId,
|
|
3872
|
+
this._activeBridges,
|
|
3873
|
+
prompt,
|
|
3874
|
+
options
|
|
3875
|
+
);
|
|
3805
3876
|
}
|
|
3806
3877
|
async interrupt() {
|
|
3807
3878
|
this._ensureNotClosed();
|
|
@@ -3904,7 +3975,7 @@ var DroidSession = class {
|
|
|
3904
3975
|
}
|
|
3905
3976
|
}
|
|
3906
3977
|
};
|
|
3907
|
-
async function createSession(options
|
|
3978
|
+
async function createSession(options) {
|
|
3908
3979
|
const { client } = await createConfiguredClient(options);
|
|
3909
3980
|
let cleanupInitAbortSignal = options.abortSignal?.aborted ? () => {
|
|
3910
3981
|
} : wireAbortSignal(options.abortSignal, () => {
|
|
@@ -3934,7 +4005,7 @@ async function createSession(options = {}) {
|
|
|
3934
4005
|
throw error;
|
|
3935
4006
|
}
|
|
3936
4007
|
}
|
|
3937
|
-
async function resumeSession(sessionId, options
|
|
4008
|
+
async function resumeSession(sessionId, options) {
|
|
3938
4009
|
const { client } = await createConfiguredClient(options);
|
|
3939
4010
|
let sdkMcpServers;
|
|
3940
4011
|
try {
|
|
@@ -3958,7 +4029,7 @@ async function resumeSession(sessionId, options = {}) {
|
|
|
3958
4029
|
}
|
|
3959
4030
|
|
|
3960
4031
|
// src/run.ts
|
|
3961
|
-
async function run(prompt, options
|
|
4032
|
+
async function run(prompt, options) {
|
|
3962
4033
|
const session = await createSession(options);
|
|
3963
4034
|
try {
|
|
3964
4035
|
for await (const msg of session.stream(prompt, {
|
|
@@ -4198,6 +4269,1431 @@ async function listSessions(options = {}) {
|
|
|
4198
4269
|
}
|
|
4199
4270
|
return sorted;
|
|
4200
4271
|
}
|
|
4272
|
+
|
|
4273
|
+
// src/api-types.ts
|
|
4274
|
+
var import_zod10 = require("zod");
|
|
4275
|
+
var EnvironmentVariableSchema = import_zod10.z.object({
|
|
4276
|
+
key: import_zod10.z.string(),
|
|
4277
|
+
value: import_zod10.z.string()
|
|
4278
|
+
});
|
|
4279
|
+
var MachineTemplateBuildStatusSchema = import_zod10.z.object({
|
|
4280
|
+
status: import_zod10.z.enum(["building", "success", "failed"]),
|
|
4281
|
+
failureReason: import_zod10.z.enum(["setup_script_error", "system_error"]).optional(),
|
|
4282
|
+
buildStartedAt: import_zod10.z.number().int().optional(),
|
|
4283
|
+
builtAt: import_zod10.z.number().int().optional(),
|
|
4284
|
+
logs: import_zod10.z.string().optional()
|
|
4285
|
+
});
|
|
4286
|
+
var MachineTemplateSchema = import_zod10.z.object({
|
|
4287
|
+
templateId: import_zod10.z.string(),
|
|
4288
|
+
repoUrl: import_zod10.z.string(),
|
|
4289
|
+
templateName: import_zod10.z.string(),
|
|
4290
|
+
defaultBranch: import_zod10.z.string(),
|
|
4291
|
+
createdBy: import_zod10.z.string(),
|
|
4292
|
+
createdAt: import_zod10.z.number().int().optional(),
|
|
4293
|
+
buildStatus: MachineTemplateBuildStatusSchema.optional(),
|
|
4294
|
+
lastUpdatedAt: import_zod10.z.number().int().nullable().optional(),
|
|
4295
|
+
environmentVariables: import_zod10.z.array(EnvironmentVariableSchema).optional(),
|
|
4296
|
+
userEnvironmentVariablesByUser: import_zod10.z.array(EnvironmentVariableSchema).optional(),
|
|
4297
|
+
setupScript: import_zod10.z.string().optional()
|
|
4298
|
+
});
|
|
4299
|
+
var MachineTemplateListResponseSchema = import_zod10.z.object({
|
|
4300
|
+
templates: import_zod10.z.array(MachineTemplateSchema),
|
|
4301
|
+
pagination: import_zod10.z.object({
|
|
4302
|
+
hasMore: import_zod10.z.boolean(),
|
|
4303
|
+
nextCursor: import_zod10.z.string().nullable()
|
|
4304
|
+
})
|
|
4305
|
+
});
|
|
4306
|
+
var ComputerSchema = import_zod10.z.object({
|
|
4307
|
+
id: import_zod10.z.string(),
|
|
4308
|
+
name: import_zod10.z.string(),
|
|
4309
|
+
hostname: import_zod10.z.string().optional(),
|
|
4310
|
+
providerType: import_zod10.z.enum(["byom", "e2b"]),
|
|
4311
|
+
status: import_zod10.z.enum(["provisioning", "active", "error"]).optional(),
|
|
4312
|
+
createdAt: import_zod10.z.number().int(),
|
|
4313
|
+
relayClientUrl: import_zod10.z.string().optional(),
|
|
4314
|
+
remoteUser: import_zod10.z.string().optional()
|
|
4315
|
+
}).passthrough();
|
|
4316
|
+
var ComputerListResponseSchema = import_zod10.z.object({
|
|
4317
|
+
computers: import_zod10.z.array(ComputerSchema)
|
|
4318
|
+
});
|
|
4319
|
+
var RefreshComputerResponseSchema = import_zod10.z.object({
|
|
4320
|
+
configured: import_zod10.z.number().int()
|
|
4321
|
+
});
|
|
4322
|
+
var ComputerMetricSchema = import_zod10.z.object({
|
|
4323
|
+
timestamp: import_zod10.z.string(),
|
|
4324
|
+
cpuUsedPct: import_zod10.z.number(),
|
|
4325
|
+
cpuCount: import_zod10.z.number(),
|
|
4326
|
+
memUsed: import_zod10.z.number(),
|
|
4327
|
+
memTotal: import_zod10.z.number(),
|
|
4328
|
+
diskUsed: import_zod10.z.number(),
|
|
4329
|
+
diskTotal: import_zod10.z.number()
|
|
4330
|
+
});
|
|
4331
|
+
var ComputerMetricsResponseSchema = import_zod10.z.array(ComputerMetricSchema);
|
|
4332
|
+
var RemoteSessionSchema = import_zod10.z.object({
|
|
4333
|
+
sessionId: import_zod10.z.string(),
|
|
4334
|
+
title: import_zod10.z.string().optional(),
|
|
4335
|
+
status: import_zod10.z.enum(["idle", "pending", "running"]),
|
|
4336
|
+
messageCount: import_zod10.z.number().int(),
|
|
4337
|
+
createdAt: import_zod10.z.number().int(),
|
|
4338
|
+
updatedAt: import_zod10.z.number().int(),
|
|
4339
|
+
completedAt: import_zod10.z.number().int().optional(),
|
|
4340
|
+
computerId: import_zod10.z.string().optional()
|
|
4341
|
+
});
|
|
4342
|
+
var RemoteSessionListResponseSchema = import_zod10.z.object({
|
|
4343
|
+
sessions: import_zod10.z.array(RemoteSessionSchema),
|
|
4344
|
+
pagination: import_zod10.z.object({
|
|
4345
|
+
hasMore: import_zod10.z.boolean(),
|
|
4346
|
+
nextCursor: import_zod10.z.string().nullable()
|
|
4347
|
+
})
|
|
4348
|
+
});
|
|
4349
|
+
|
|
4350
|
+
// src/api.ts
|
|
4351
|
+
var DEFAULT_BASE_URL = "https://api.factory.ai";
|
|
4352
|
+
function extractErrorMessage(body, status) {
|
|
4353
|
+
if (isRecord(body) && typeof body["error"] === "string") {
|
|
4354
|
+
return body["error"];
|
|
4355
|
+
}
|
|
4356
|
+
return `Factory API error (status ${status})`;
|
|
4357
|
+
}
|
|
4358
|
+
async function factoryFetch(path3, apiKey, baseUrl, options) {
|
|
4359
|
+
const url = `${baseUrl ?? DEFAULT_BASE_URL}${path3}`;
|
|
4360
|
+
const method = options?.method ?? "GET";
|
|
4361
|
+
const headers = {
|
|
4362
|
+
Authorization: `Bearer ${apiKey}`,
|
|
4363
|
+
Accept: "application/json"
|
|
4364
|
+
};
|
|
4365
|
+
if (options?.body) {
|
|
4366
|
+
headers["Content-Type"] = "application/json";
|
|
4367
|
+
}
|
|
4368
|
+
let response;
|
|
4369
|
+
try {
|
|
4370
|
+
response = await fetch(url, {
|
|
4371
|
+
method,
|
|
4372
|
+
headers,
|
|
4373
|
+
...options?.body ? { body: JSON.stringify(options.body) } : {}
|
|
4374
|
+
});
|
|
4375
|
+
} catch (error) {
|
|
4376
|
+
throw new ConnectionError(
|
|
4377
|
+
`Failed to reach Factory API: ${error instanceof Error ? error.message : String(error)}`
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
if (response.status === 204) {
|
|
4381
|
+
return void 0;
|
|
4382
|
+
}
|
|
4383
|
+
let body;
|
|
4384
|
+
try {
|
|
4385
|
+
body = await response.json();
|
|
4386
|
+
} catch {
|
|
4387
|
+
throw new ProtocolError(
|
|
4388
|
+
`Factory API returned non-JSON response (status ${response.status})`
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
if (!response.ok) {
|
|
4392
|
+
const message = extractErrorMessage(body, response.status);
|
|
4393
|
+
if (response.status === 401 || response.status === 403) {
|
|
4394
|
+
throw new ProtocolError(`Invalid or expired API key: ${message}`, {
|
|
4395
|
+
code: response.status
|
|
4396
|
+
});
|
|
4397
|
+
}
|
|
4398
|
+
throw new ProtocolError(message, { code: response.status });
|
|
4399
|
+
}
|
|
4400
|
+
return body;
|
|
4401
|
+
}
|
|
4402
|
+
function parseResponse(body, schema) {
|
|
4403
|
+
const parsed = schema.safeParse(body);
|
|
4404
|
+
if (!parsed.success) {
|
|
4405
|
+
throw new ProtocolError(
|
|
4406
|
+
`Unexpected response format from Factory API: ${parsed.error.message}`
|
|
4407
|
+
);
|
|
4408
|
+
}
|
|
4409
|
+
return parsed.data;
|
|
4410
|
+
}
|
|
4411
|
+
async function listMachineTemplates(options) {
|
|
4412
|
+
const params = new URLSearchParams();
|
|
4413
|
+
if (options.limit != null) {
|
|
4414
|
+
params.set("limit", String(options.limit));
|
|
4415
|
+
}
|
|
4416
|
+
if (options.cursor != null) {
|
|
4417
|
+
params.set("cursor", options.cursor);
|
|
4418
|
+
}
|
|
4419
|
+
const query = params.toString();
|
|
4420
|
+
const path3 = `/api/v0/machines/templates${query ? `?${query}` : ""}`;
|
|
4421
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4422
|
+
return parseResponse(body, MachineTemplateListResponseSchema);
|
|
4423
|
+
}
|
|
4424
|
+
async function getMachineTemplate(options) {
|
|
4425
|
+
const path3 = `/api/v0/machines/templates/${encodeURIComponent(options.templateId)}`;
|
|
4426
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4427
|
+
return parseResponse(body, MachineTemplateSchema);
|
|
4428
|
+
}
|
|
4429
|
+
async function listComputers(options) {
|
|
4430
|
+
const path3 = "/api/v0/computers";
|
|
4431
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4432
|
+
return parseResponse(body, ComputerListResponseSchema);
|
|
4433
|
+
}
|
|
4434
|
+
async function getComputer(options) {
|
|
4435
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}`;
|
|
4436
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4437
|
+
return parseResponse(body, ComputerSchema);
|
|
4438
|
+
}
|
|
4439
|
+
async function createComputer(options) {
|
|
4440
|
+
const path3 = "/api/v0/computers";
|
|
4441
|
+
const reqBody = {
|
|
4442
|
+
name: options.name,
|
|
4443
|
+
remoteUser: options.remoteUser
|
|
4444
|
+
};
|
|
4445
|
+
if (options.provider != null) reqBody["provider"] = options.provider;
|
|
4446
|
+
if (options.hostId != null) reqBody["hostId"] = options.hostId;
|
|
4447
|
+
if (options.repos != null) reqBody["repos"] = options.repos;
|
|
4448
|
+
if (options.autoInstallDeps != null)
|
|
4449
|
+
reqBody["autoInstallDeps"] = options.autoInstallDeps;
|
|
4450
|
+
if (options.serviceAccountId != null)
|
|
4451
|
+
reqBody["serviceAccountId"] = options.serviceAccountId;
|
|
4452
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4453
|
+
method: "POST",
|
|
4454
|
+
body: reqBody
|
|
4455
|
+
});
|
|
4456
|
+
return parseResponse(body, ComputerSchema);
|
|
4457
|
+
}
|
|
4458
|
+
async function getComputerByName(options) {
|
|
4459
|
+
const path3 = `/api/v0/computers/name/${encodeURIComponent(options.name)}`;
|
|
4460
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4461
|
+
return parseResponse(body, ComputerSchema);
|
|
4462
|
+
}
|
|
4463
|
+
async function updateComputer(options) {
|
|
4464
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}`;
|
|
4465
|
+
const reqBody = {};
|
|
4466
|
+
if (options.name != null) reqBody["name"] = options.name;
|
|
4467
|
+
if (options.remoteUser != null) reqBody["remoteUser"] = options.remoteUser;
|
|
4468
|
+
if (options.hostId != null) reqBody["hostId"] = options.hostId;
|
|
4469
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4470
|
+
method: "PATCH",
|
|
4471
|
+
body: reqBody
|
|
4472
|
+
});
|
|
4473
|
+
return parseResponse(body, ComputerSchema);
|
|
4474
|
+
}
|
|
4475
|
+
async function deleteComputer(options) {
|
|
4476
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}`;
|
|
4477
|
+
await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4478
|
+
method: "DELETE"
|
|
4479
|
+
});
|
|
4480
|
+
}
|
|
4481
|
+
async function restartComputer(options) {
|
|
4482
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/restart`;
|
|
4483
|
+
await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4484
|
+
method: "POST"
|
|
4485
|
+
});
|
|
4486
|
+
}
|
|
4487
|
+
async function refreshComputer(options) {
|
|
4488
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/refresh`;
|
|
4489
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4490
|
+
method: "POST"
|
|
4491
|
+
});
|
|
4492
|
+
return parseResponse(body, RefreshComputerResponseSchema);
|
|
4493
|
+
}
|
|
4494
|
+
async function getComputerMetrics(options) {
|
|
4495
|
+
const params = new URLSearchParams();
|
|
4496
|
+
if (options.start != null) {
|
|
4497
|
+
params.set("start", options.start);
|
|
4498
|
+
}
|
|
4499
|
+
const query = params.toString();
|
|
4500
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/metrics${query ? `?${query}` : ""}`;
|
|
4501
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4502
|
+
return parseResponse(body, ComputerMetricsResponseSchema);
|
|
4503
|
+
}
|
|
4504
|
+
async function retryInstallDeps(options) {
|
|
4505
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/install-deps`;
|
|
4506
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4507
|
+
method: "POST"
|
|
4508
|
+
});
|
|
4509
|
+
return parseResponse(body, ComputerSchema);
|
|
4510
|
+
}
|
|
4511
|
+
async function listRemoteSessions(options) {
|
|
4512
|
+
const params = new URLSearchParams();
|
|
4513
|
+
if (options.computerId != null) {
|
|
4514
|
+
params.set("computerId", options.computerId);
|
|
4515
|
+
}
|
|
4516
|
+
if (options.limit != null) {
|
|
4517
|
+
params.set("limit", String(options.limit));
|
|
4518
|
+
}
|
|
4519
|
+
if (options.cursor != null) {
|
|
4520
|
+
params.set("cursor", options.cursor);
|
|
4521
|
+
}
|
|
4522
|
+
const query = params.toString();
|
|
4523
|
+
const path3 = `/api/v0/sessions${query ? `?${query}` : ""}`;
|
|
4524
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4525
|
+
return parseResponse(body, RemoteSessionListResponseSchema);
|
|
4526
|
+
}
|
|
4527
|
+
|
|
4528
|
+
// src/daemon/client.ts
|
|
4529
|
+
var DAEMON_SERVER_REQUEST_METHODS = {
|
|
4530
|
+
"daemon.request_permission": "permission" /* Permission */,
|
|
4531
|
+
"daemon.ask_user": "askUser" /* AskUser */
|
|
4532
|
+
};
|
|
4533
|
+
var DaemonClient = class {
|
|
4534
|
+
_engine;
|
|
4535
|
+
_apiKey;
|
|
4536
|
+
_sessionId = null;
|
|
4537
|
+
_closed = false;
|
|
4538
|
+
_notificationListeners = [];
|
|
4539
|
+
_permissionHandler = null;
|
|
4540
|
+
_askUserHandler = null;
|
|
4541
|
+
constructor(options) {
|
|
4542
|
+
this._apiKey = options.apiKey;
|
|
4543
|
+
this._engine = new ProtocolEngine({
|
|
4544
|
+
transport: options.transport,
|
|
4545
|
+
serverRequestMethodMap: DAEMON_SERVER_REQUEST_METHODS
|
|
4546
|
+
});
|
|
4547
|
+
this._engine.onNotification((notification) => {
|
|
4548
|
+
const normalized = notification["method"] === "daemon.session_notification" ? { ...notification, method: "droid.session_notification" } : notification;
|
|
4549
|
+
dispatchNotification(normalized, [...this._notificationListeners]);
|
|
4550
|
+
});
|
|
4551
|
+
this._engine.setPermissionHandler(
|
|
4552
|
+
(params) => this._dispatchPermissionRequest(params)
|
|
4553
|
+
);
|
|
4554
|
+
this._engine.setAskUserHandler(
|
|
4555
|
+
(params) => this._dispatchAskUserRequest(params)
|
|
4556
|
+
);
|
|
4557
|
+
}
|
|
4558
|
+
get sessionId() {
|
|
4559
|
+
return this._sessionId;
|
|
4560
|
+
}
|
|
4561
|
+
get isConnected() {
|
|
4562
|
+
return !this._closed && this._engine.isHealthy;
|
|
4563
|
+
}
|
|
4564
|
+
async initializeSession(params) {
|
|
4565
|
+
this._ensureNotClosed();
|
|
4566
|
+
const result = await this._rpc(
|
|
4567
|
+
"daemon.initialize_session" /* INITIALIZE_SESSION */,
|
|
4568
|
+
{ ...params, token: this._apiKey },
|
|
4569
|
+
InitializeSessionResultSchema,
|
|
4570
|
+
SESSION_INIT_TIMEOUT
|
|
4571
|
+
);
|
|
4572
|
+
this._sessionId = result.sessionId;
|
|
4573
|
+
return result;
|
|
4574
|
+
}
|
|
4575
|
+
async loadSession(params) {
|
|
4576
|
+
this._ensureNotClosed();
|
|
4577
|
+
const result = await this._rpc(
|
|
4578
|
+
"daemon.load_session" /* LOAD_SESSION */,
|
|
4579
|
+
{ ...params, token: this._apiKey },
|
|
4580
|
+
LoadSessionResultSchema,
|
|
4581
|
+
SESSION_INIT_TIMEOUT
|
|
4582
|
+
);
|
|
4583
|
+
this._sessionId = params.sessionId;
|
|
4584
|
+
return result;
|
|
4585
|
+
}
|
|
4586
|
+
async addUserMessage(params) {
|
|
4587
|
+
return this._sessionRpc(
|
|
4588
|
+
"daemon.add_user_message" /* ADD_USER_MESSAGE */,
|
|
4589
|
+
params,
|
|
4590
|
+
AddUserMessageResultSchema
|
|
4591
|
+
);
|
|
4592
|
+
}
|
|
4593
|
+
async interruptSession() {
|
|
4594
|
+
return this._sessionRpc(
|
|
4595
|
+
"daemon.interrupt_session" /* INTERRUPT_SESSION */,
|
|
4596
|
+
{},
|
|
4597
|
+
InterruptSessionResultSchema
|
|
4598
|
+
);
|
|
4599
|
+
}
|
|
4600
|
+
async closeSession(params = {}) {
|
|
4601
|
+
return this._sessionRpc(
|
|
4602
|
+
"daemon.close_session" /* CLOSE_SESSION */,
|
|
4603
|
+
params,
|
|
4604
|
+
CloseSessionResultSchema
|
|
4605
|
+
);
|
|
4606
|
+
}
|
|
4607
|
+
async updateSessionSettings(params) {
|
|
4608
|
+
return this._sessionRpc(
|
|
4609
|
+
"daemon.update_session_settings" /* UPDATE_SESSION_SETTINGS */,
|
|
4610
|
+
params,
|
|
4611
|
+
UpdateSessionSettingsResultSchema
|
|
4612
|
+
);
|
|
4613
|
+
}
|
|
4614
|
+
async compactSession(params = {}) {
|
|
4615
|
+
return this._sessionRpc(
|
|
4616
|
+
"daemon.compact_session" /* COMPACT_SESSION */,
|
|
4617
|
+
params,
|
|
4618
|
+
CompactSessionResultSchema,
|
|
4619
|
+
COMPACTION_TIMEOUT
|
|
4620
|
+
);
|
|
4621
|
+
}
|
|
4622
|
+
async forkSession() {
|
|
4623
|
+
return this._sessionRpc(
|
|
4624
|
+
"daemon.fork_session" /* FORK_SESSION */,
|
|
4625
|
+
{},
|
|
4626
|
+
ForkSessionResultSchema
|
|
4627
|
+
);
|
|
4628
|
+
}
|
|
4629
|
+
async getContextBreakdown() {
|
|
4630
|
+
return this._sessionRpc(
|
|
4631
|
+
"daemon.get_context_breakdown" /* GET_CONTEXT_STATS */,
|
|
4632
|
+
{},
|
|
4633
|
+
ContextBreakdownResultSchema
|
|
4634
|
+
);
|
|
4635
|
+
}
|
|
4636
|
+
async renameSession(params) {
|
|
4637
|
+
return this._sessionRpc(
|
|
4638
|
+
"daemon.rename_session" /* RENAME_SESSION */,
|
|
4639
|
+
params,
|
|
4640
|
+
RenameSessionResultSchema
|
|
4641
|
+
);
|
|
4642
|
+
}
|
|
4643
|
+
async getRewindInfo(params) {
|
|
4644
|
+
return this._sessionRpc(
|
|
4645
|
+
"daemon.get_rewind_info" /* GET_REWIND_INFO */,
|
|
4646
|
+
params,
|
|
4647
|
+
GetRewindInfoResultSchema,
|
|
4648
|
+
REWIND_TIMEOUT
|
|
4649
|
+
);
|
|
4650
|
+
}
|
|
4651
|
+
async executeRewind(params) {
|
|
4652
|
+
return this._sessionRpc(
|
|
4653
|
+
"daemon.execute_rewind" /* EXECUTE_REWIND */,
|
|
4654
|
+
params,
|
|
4655
|
+
ExecuteRewindResultSchema,
|
|
4656
|
+
REWIND_TIMEOUT
|
|
4657
|
+
);
|
|
4658
|
+
}
|
|
4659
|
+
async addMcpServer(params) {
|
|
4660
|
+
return this._sessionRpc(
|
|
4661
|
+
"daemon.add_mcp_server" /* ADD_MCP_SERVER */,
|
|
4662
|
+
params,
|
|
4663
|
+
AddMcpServerResultSchema
|
|
4664
|
+
);
|
|
4665
|
+
}
|
|
4666
|
+
async removeMcpServer(params) {
|
|
4667
|
+
return this._sessionRpc(
|
|
4668
|
+
"daemon.remove_mcp_server" /* REMOVE_MCP_SERVER */,
|
|
4669
|
+
params,
|
|
4670
|
+
RemoveMcpServerResultSchema
|
|
4671
|
+
);
|
|
4672
|
+
}
|
|
4673
|
+
async toggleMcpServer(params) {
|
|
4674
|
+
return this._sessionRpc(
|
|
4675
|
+
"daemon.toggle_mcp_server" /* TOGGLE_MCP_SERVER */,
|
|
4676
|
+
params,
|
|
4677
|
+
ToggleMcpServerResultSchema
|
|
4678
|
+
);
|
|
4679
|
+
}
|
|
4680
|
+
async listMcpServers() {
|
|
4681
|
+
return this._sessionRpc(
|
|
4682
|
+
"daemon.list_mcp_servers" /* LIST_MCP_SERVERS */,
|
|
4683
|
+
{},
|
|
4684
|
+
ListMcpServersResultSchema
|
|
4685
|
+
);
|
|
4686
|
+
}
|
|
4687
|
+
async listMcpTools() {
|
|
4688
|
+
return this._sessionRpc(
|
|
4689
|
+
"daemon.list_mcp_tools" /* LIST_MCP_TOOLS */,
|
|
4690
|
+
{},
|
|
4691
|
+
ListMcpToolsResultSchema
|
|
4692
|
+
);
|
|
4693
|
+
}
|
|
4694
|
+
async authenticateMcpServer(params) {
|
|
4695
|
+
return this._sessionRpc(
|
|
4696
|
+
"daemon.authenticate_mcp_server" /* AUTHENTICATE_MCP_SERVER */,
|
|
4697
|
+
params,
|
|
4698
|
+
AuthenticateMcpServerResultSchema
|
|
4699
|
+
);
|
|
4700
|
+
}
|
|
4701
|
+
async listSkills() {
|
|
4702
|
+
return this._sessionRpc(
|
|
4703
|
+
"daemon.list_skills" /* LIST_SKILLS */,
|
|
4704
|
+
{},
|
|
4705
|
+
ListSkillsResultSchema
|
|
4706
|
+
);
|
|
4707
|
+
}
|
|
4708
|
+
onNotification(callback, filter) {
|
|
4709
|
+
const entry = { callback, filter };
|
|
4710
|
+
this._notificationListeners.push(entry);
|
|
4711
|
+
let unsubscribed = false;
|
|
4712
|
+
return () => {
|
|
4713
|
+
if (!unsubscribed) {
|
|
4714
|
+
unsubscribed = true;
|
|
4715
|
+
const idx = this._notificationListeners.indexOf(entry);
|
|
4716
|
+
if (idx !== -1) {
|
|
4717
|
+
this._notificationListeners.splice(idx, 1);
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
setPermissionHandler(handler) {
|
|
4723
|
+
this._permissionHandler = handler;
|
|
4724
|
+
}
|
|
4725
|
+
setAskUserHandler(handler) {
|
|
4726
|
+
this._askUserHandler = handler;
|
|
4727
|
+
}
|
|
4728
|
+
async close() {
|
|
4729
|
+
if (this._closed) {
|
|
4730
|
+
return;
|
|
4731
|
+
}
|
|
4732
|
+
this._closed = true;
|
|
4733
|
+
this._notificationListeners.length = 0;
|
|
4734
|
+
this._permissionHandler = null;
|
|
4735
|
+
this._askUserHandler = null;
|
|
4736
|
+
await this._engine.close();
|
|
4737
|
+
}
|
|
4738
|
+
async _rpc(method, params, schema, timeout) {
|
|
4739
|
+
const raw = await this._engine.sendRequest(method, params, timeout);
|
|
4740
|
+
return schema.parse(raw);
|
|
4741
|
+
}
|
|
4742
|
+
async _sessionRpc(method, params, schema, timeout) {
|
|
4743
|
+
this._ensureNotClosed();
|
|
4744
|
+
this._ensureSession();
|
|
4745
|
+
return this._rpc(
|
|
4746
|
+
method,
|
|
4747
|
+
{ sessionId: this._sessionId, ...params },
|
|
4748
|
+
schema,
|
|
4749
|
+
timeout
|
|
4750
|
+
);
|
|
4751
|
+
}
|
|
4752
|
+
_dispatchPermissionRequest(params) {
|
|
4753
|
+
const handler = this._permissionHandler;
|
|
4754
|
+
if (handler == null) {
|
|
4755
|
+
return "cancel" /* Cancel */;
|
|
4756
|
+
}
|
|
4757
|
+
return handler(params);
|
|
4758
|
+
}
|
|
4759
|
+
_dispatchAskUserRequest(params) {
|
|
4760
|
+
const handler = this._askUserHandler;
|
|
4761
|
+
if (handler == null) {
|
|
4762
|
+
return { cancelled: true, answers: [] };
|
|
4763
|
+
}
|
|
4764
|
+
return handler(params);
|
|
4765
|
+
}
|
|
4766
|
+
_ensureNotClosed() {
|
|
4767
|
+
if (this._closed) {
|
|
4768
|
+
throw new ConnectionError(
|
|
4769
|
+
"Daemon client has been closed. Create a new DaemonClient instance."
|
|
4770
|
+
);
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
_ensureSession() {
|
|
4774
|
+
if (this._sessionId == null) {
|
|
4775
|
+
throw new SessionError(
|
|
4776
|
+
"No active session. Call initializeSession or loadSession first."
|
|
4777
|
+
);
|
|
4778
|
+
}
|
|
4779
|
+
}
|
|
4780
|
+
};
|
|
4781
|
+
|
|
4782
|
+
// src/daemon/local.ts
|
|
4783
|
+
var import_node_child_process2 = require("child_process");
|
|
4784
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
4785
|
+
var net = __toESM(require("net"), 1);
|
|
4786
|
+
var os2 = __toESM(require("os"), 1);
|
|
4787
|
+
var path2 = __toESM(require("path"), 1);
|
|
4788
|
+
var SOCKET_TIMEOUT_MS = 2e3;
|
|
4789
|
+
var STARTUP_POLL_INTERVAL_MS = 250;
|
|
4790
|
+
var STARTUP_TIMEOUT_MS = 3e4;
|
|
4791
|
+
var MAX_STARTUP_ATTEMPTS = 3;
|
|
4792
|
+
var FACTORY_DIR = ".factory";
|
|
4793
|
+
var DEFAULT_PORT = 37643;
|
|
4794
|
+
var DAEMON_PORT_FILE = "daemon.port";
|
|
4795
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
4796
|
+
var spawnedDaemonProcess = null;
|
|
4797
|
+
var daemonTarget = null;
|
|
4798
|
+
var daemonEnsureInflight = null;
|
|
4799
|
+
function getFactoryHome() {
|
|
4800
|
+
return process.env.FACTORY_HOME_OVERRIDE || os2.homedir();
|
|
4801
|
+
}
|
|
4802
|
+
function getFactoryDirName() {
|
|
4803
|
+
return FACTORY_DIR;
|
|
4804
|
+
}
|
|
4805
|
+
function getFactoryDir() {
|
|
4806
|
+
return path2.join(getFactoryHome(), getFactoryDirName());
|
|
4807
|
+
}
|
|
4808
|
+
function getSdkDir() {
|
|
4809
|
+
return path2.join(getFactoryDir(), "sdk");
|
|
4810
|
+
}
|
|
4811
|
+
function getDefaultDaemonPort() {
|
|
4812
|
+
return DEFAULT_PORT;
|
|
4813
|
+
}
|
|
4814
|
+
function resolveExecPath() {
|
|
4815
|
+
const override = process.env.FACTORY_DROID_BINARY?.trim();
|
|
4816
|
+
if (override && override.length > 0) {
|
|
4817
|
+
if (override.includes("/") || override.includes("\\")) {
|
|
4818
|
+
try {
|
|
4819
|
+
fs2.accessSync(override, fs2.constants.X_OK);
|
|
4820
|
+
return override;
|
|
4821
|
+
} catch {
|
|
4822
|
+
}
|
|
4823
|
+
} else {
|
|
4824
|
+
return override;
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
return "droid";
|
|
4828
|
+
}
|
|
4829
|
+
async function allocatePort() {
|
|
4830
|
+
return new Promise((resolve2, reject) => {
|
|
4831
|
+
const server = net.createServer();
|
|
4832
|
+
server.once("error", reject);
|
|
4833
|
+
server.listen(0, DEFAULT_HOST, () => {
|
|
4834
|
+
const address = server.address();
|
|
4835
|
+
if (!address || typeof address === "string") {
|
|
4836
|
+
server.close();
|
|
4837
|
+
reject(new Error("Failed to determine dynamic port"));
|
|
4838
|
+
return;
|
|
4839
|
+
}
|
|
4840
|
+
const port = address.port;
|
|
4841
|
+
server.close((err) => {
|
|
4842
|
+
if (err) reject(err);
|
|
4843
|
+
else resolve2(port);
|
|
4844
|
+
});
|
|
4845
|
+
});
|
|
4846
|
+
});
|
|
4847
|
+
}
|
|
4848
|
+
async function isDaemonReachable(port) {
|
|
4849
|
+
return new Promise((resolve2) => {
|
|
4850
|
+
const socket = net.createConnection({ host: DEFAULT_HOST, port });
|
|
4851
|
+
const cleanup = () => {
|
|
4852
|
+
socket.removeAllListeners();
|
|
4853
|
+
socket.destroy();
|
|
4854
|
+
};
|
|
4855
|
+
const fail = () => {
|
|
4856
|
+
cleanup();
|
|
4857
|
+
resolve2(false);
|
|
4858
|
+
};
|
|
4859
|
+
socket.setTimeout(SOCKET_TIMEOUT_MS, fail);
|
|
4860
|
+
socket.once("error", fail);
|
|
4861
|
+
socket.once("connect", () => {
|
|
4862
|
+
cleanup();
|
|
4863
|
+
resolve2(true);
|
|
4864
|
+
});
|
|
4865
|
+
});
|
|
4866
|
+
}
|
|
4867
|
+
async function waitForDaemonReady(child, port, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
4868
|
+
return new Promise((resolve2) => {
|
|
4869
|
+
let settled = false;
|
|
4870
|
+
let exited = false;
|
|
4871
|
+
const deadline = Date.now() + timeoutMs;
|
|
4872
|
+
const settle = (result) => {
|
|
4873
|
+
if (settled) return;
|
|
4874
|
+
settled = true;
|
|
4875
|
+
child.removeListener("exit", onExit);
|
|
4876
|
+
child.removeListener("error", onExit);
|
|
4877
|
+
resolve2(result);
|
|
4878
|
+
};
|
|
4879
|
+
const onExit = () => {
|
|
4880
|
+
exited = true;
|
|
4881
|
+
settle("exited");
|
|
4882
|
+
};
|
|
4883
|
+
child.once("exit", onExit);
|
|
4884
|
+
child.once("error", onExit);
|
|
4885
|
+
const poll = async () => {
|
|
4886
|
+
while (!exited && !settled) {
|
|
4887
|
+
if (await isDaemonReachable(port)) {
|
|
4888
|
+
settle("ready");
|
|
4889
|
+
return;
|
|
4890
|
+
}
|
|
4891
|
+
if (Date.now() >= deadline) {
|
|
4892
|
+
settle("timeout");
|
|
4893
|
+
return;
|
|
4894
|
+
}
|
|
4895
|
+
await new Promise((r) => setTimeout(r, STARTUP_POLL_INTERVAL_MS));
|
|
4896
|
+
}
|
|
4897
|
+
};
|
|
4898
|
+
void poll();
|
|
4899
|
+
});
|
|
4900
|
+
}
|
|
4901
|
+
function readPortFile() {
|
|
4902
|
+
try {
|
|
4903
|
+
const portPath = path2.join(getSdkDir(), DAEMON_PORT_FILE);
|
|
4904
|
+
const content = fs2.readFileSync(portPath, "utf-8").trim();
|
|
4905
|
+
const port = parseInt(content, 10);
|
|
4906
|
+
if (Number.isFinite(port) && port > 0 && port < 65536) {
|
|
4907
|
+
return port;
|
|
4908
|
+
}
|
|
4909
|
+
return null;
|
|
4910
|
+
} catch {
|
|
4911
|
+
return null;
|
|
4912
|
+
}
|
|
4913
|
+
}
|
|
4914
|
+
function writePortFile(port) {
|
|
4915
|
+
try {
|
|
4916
|
+
const sdkDir = getSdkDir();
|
|
4917
|
+
fs2.mkdirSync(sdkDir, { recursive: true });
|
|
4918
|
+
fs2.writeFileSync(path2.join(sdkDir, DAEMON_PORT_FILE), String(port), {
|
|
4919
|
+
mode: 384
|
|
4920
|
+
});
|
|
4921
|
+
} catch {
|
|
4922
|
+
}
|
|
4923
|
+
}
|
|
4924
|
+
function cacheTarget(port) {
|
|
4925
|
+
daemonTarget = { host: DEFAULT_HOST, port };
|
|
4926
|
+
return { port };
|
|
4927
|
+
}
|
|
4928
|
+
function clearSpawnedDaemonProcess(child) {
|
|
4929
|
+
if (spawnedDaemonProcess === child) {
|
|
4930
|
+
spawnedDaemonProcess = null;
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
async function spawnDaemon(execPath, port) {
|
|
4934
|
+
const args = ["daemon", "--host", DEFAULT_HOST, "--port", String(port)];
|
|
4935
|
+
let stderrFd;
|
|
4936
|
+
try {
|
|
4937
|
+
const logsDir = path2.join(getSdkDir(), "logs");
|
|
4938
|
+
fs2.mkdirSync(logsDir, { recursive: true });
|
|
4939
|
+
stderrFd = fs2.openSync(path2.join(logsDir, "daemon-stderr.log"), "a");
|
|
4940
|
+
} catch {
|
|
4941
|
+
}
|
|
4942
|
+
const child = (0, import_node_child_process2.spawn)(execPath, args, {
|
|
4943
|
+
detached: true,
|
|
4944
|
+
stdio: ["ignore", "ignore", stderrFd ?? "ignore"],
|
|
4945
|
+
cwd: os2.homedir(),
|
|
4946
|
+
env: { ...process.env }
|
|
4947
|
+
});
|
|
4948
|
+
if (stderrFd !== void 0) {
|
|
4949
|
+
try {
|
|
4950
|
+
fs2.closeSync(stderrFd);
|
|
4951
|
+
} catch {
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
spawnedDaemonProcess = child;
|
|
4955
|
+
child.unref();
|
|
4956
|
+
child.once("exit", () => {
|
|
4957
|
+
clearSpawnedDaemonProcess(child);
|
|
4958
|
+
});
|
|
4959
|
+
child.on("error", () => {
|
|
4960
|
+
clearSpawnedDaemonProcess(child);
|
|
4961
|
+
});
|
|
4962
|
+
const result = await waitForDaemonReady(child, port);
|
|
4963
|
+
if (result !== "ready") {
|
|
4964
|
+
clearSpawnedDaemonProcess(child);
|
|
4965
|
+
if (result === "timeout") {
|
|
4966
|
+
try {
|
|
4967
|
+
child.kill("SIGTERM");
|
|
4968
|
+
} catch {
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
return result;
|
|
4973
|
+
}
|
|
4974
|
+
async function _ensureLocalDaemon() {
|
|
4975
|
+
const execPath = resolveExecPath();
|
|
4976
|
+
const wellKnownPort = getDefaultDaemonPort();
|
|
4977
|
+
if (await isDaemonReachable(wellKnownPort)) {
|
|
4978
|
+
return cacheTarget(wellKnownPort);
|
|
4979
|
+
}
|
|
4980
|
+
const portFilePort = readPortFile();
|
|
4981
|
+
if (portFilePort !== null && portFilePort !== wellKnownPort) {
|
|
4982
|
+
if (await isDaemonReachable(portFilePort)) {
|
|
4983
|
+
return cacheTarget(portFilePort);
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
const firstResult = await spawnDaemon(execPath, wellKnownPort);
|
|
4987
|
+
if (firstResult === "ready") {
|
|
4988
|
+
writePortFile(wellKnownPort);
|
|
4989
|
+
return cacheTarget(wellKnownPort);
|
|
4990
|
+
}
|
|
4991
|
+
for (let attempt = 2; attempt <= MAX_STARTUP_ATTEMPTS; attempt++) {
|
|
4992
|
+
const port = await allocatePort();
|
|
4993
|
+
const result = await spawnDaemon(execPath, port);
|
|
4994
|
+
if (result === "ready") {
|
|
4995
|
+
writePortFile(port);
|
|
4996
|
+
return cacheTarget(port);
|
|
4997
|
+
}
|
|
4998
|
+
}
|
|
4999
|
+
throw new ConnectionError(
|
|
5000
|
+
`Failed to start local droid daemon after ${MAX_STARTUP_ATTEMPTS} attempts. Ensure the \`droid\` CLI is installed and \`droid auth login\` has been run.`
|
|
5001
|
+
);
|
|
5002
|
+
}
|
|
5003
|
+
async function ensureLocalDaemon() {
|
|
5004
|
+
if (daemonTarget) {
|
|
5005
|
+
if (await isDaemonReachable(daemonTarget.port)) {
|
|
5006
|
+
return { port: daemonTarget.port };
|
|
5007
|
+
}
|
|
5008
|
+
daemonTarget = null;
|
|
5009
|
+
}
|
|
5010
|
+
if (!daemonEnsureInflight) {
|
|
5011
|
+
daemonEnsureInflight = _ensureLocalDaemon().finally(() => {
|
|
5012
|
+
daemonEnsureInflight = null;
|
|
5013
|
+
});
|
|
5014
|
+
}
|
|
5015
|
+
return daemonEnsureInflight;
|
|
5016
|
+
}
|
|
5017
|
+
|
|
5018
|
+
// src/daemon/session.ts
|
|
5019
|
+
var DaemonSession = class {
|
|
5020
|
+
_client;
|
|
5021
|
+
_sessionId;
|
|
5022
|
+
_closed = false;
|
|
5023
|
+
_activeBridges = /* @__PURE__ */ new Set();
|
|
5024
|
+
_cleanupCallbacks = [];
|
|
5025
|
+
/** @internal */
|
|
5026
|
+
constructor(client, sessionId) {
|
|
5027
|
+
this._client = client;
|
|
5028
|
+
this._sessionId = sessionId;
|
|
5029
|
+
}
|
|
5030
|
+
/** @internal */
|
|
5031
|
+
addCleanup(cleanup) {
|
|
5032
|
+
this._cleanupCallbacks.push(cleanup);
|
|
5033
|
+
}
|
|
5034
|
+
get sessionId() {
|
|
5035
|
+
return this._sessionId;
|
|
5036
|
+
}
|
|
5037
|
+
async *stream(prompt, options) {
|
|
5038
|
+
this._ensureNotClosed();
|
|
5039
|
+
yield* streamFromClient(
|
|
5040
|
+
this._client,
|
|
5041
|
+
this._sessionId,
|
|
5042
|
+
this._activeBridges,
|
|
5043
|
+
prompt,
|
|
5044
|
+
options
|
|
5045
|
+
);
|
|
5046
|
+
}
|
|
5047
|
+
async send(prompt, options) {
|
|
5048
|
+
this._ensureNotClosed();
|
|
5049
|
+
await this._client.addUserMessage({
|
|
5050
|
+
text: prompt,
|
|
5051
|
+
images: options?.images,
|
|
5052
|
+
files: options?.files,
|
|
5053
|
+
outputFormat: options?.outputFormat
|
|
5054
|
+
});
|
|
5055
|
+
}
|
|
5056
|
+
async interrupt() {
|
|
5057
|
+
this._ensureNotClosed();
|
|
5058
|
+
await this._client.interruptSession();
|
|
5059
|
+
}
|
|
5060
|
+
async close() {
|
|
5061
|
+
if (this._closed) {
|
|
5062
|
+
return;
|
|
5063
|
+
}
|
|
5064
|
+
this._closed = true;
|
|
5065
|
+
for (const bridge of this._activeBridges) {
|
|
5066
|
+
bridge.signalDone();
|
|
5067
|
+
}
|
|
5068
|
+
try {
|
|
5069
|
+
await this._client.closeSession({ reason: "other" }).catch(() => {
|
|
5070
|
+
});
|
|
5071
|
+
} finally {
|
|
5072
|
+
await this._client.close();
|
|
5073
|
+
for (const cleanup of this._cleanupCallbacks) {
|
|
5074
|
+
try {
|
|
5075
|
+
await cleanup();
|
|
5076
|
+
} catch {
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
5079
|
+
this._cleanupCallbacks.length = 0;
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
async updateSettings(params) {
|
|
5083
|
+
this._ensureNotClosed();
|
|
5084
|
+
return this._client.updateSessionSettings(params);
|
|
5085
|
+
}
|
|
5086
|
+
async enterSpecMode(params = {}) {
|
|
5087
|
+
this._ensureNotClosed();
|
|
5088
|
+
return this._client.updateSessionSettings({
|
|
5089
|
+
interactionMode: "spec" /* Spec */,
|
|
5090
|
+
...params
|
|
5091
|
+
});
|
|
5092
|
+
}
|
|
5093
|
+
async compactSession(params) {
|
|
5094
|
+
this._ensureNotClosed();
|
|
5095
|
+
return this._client.compactSession(params ?? {});
|
|
5096
|
+
}
|
|
5097
|
+
async forkSession() {
|
|
5098
|
+
this._ensureNotClosed();
|
|
5099
|
+
return this._client.forkSession();
|
|
5100
|
+
}
|
|
5101
|
+
async getContextBreakdown() {
|
|
5102
|
+
this._ensureNotClosed();
|
|
5103
|
+
return this._client.getContextBreakdown();
|
|
5104
|
+
}
|
|
5105
|
+
async renameSession(params) {
|
|
5106
|
+
this._ensureNotClosed();
|
|
5107
|
+
return this._client.renameSession(params);
|
|
5108
|
+
}
|
|
5109
|
+
async getRewindInfo(params) {
|
|
5110
|
+
this._ensureNotClosed();
|
|
5111
|
+
return this._client.getRewindInfo(params);
|
|
5112
|
+
}
|
|
5113
|
+
async executeRewind(params) {
|
|
5114
|
+
this._ensureNotClosed();
|
|
5115
|
+
return this._client.executeRewind(params);
|
|
5116
|
+
}
|
|
5117
|
+
async addMcpServer(params) {
|
|
5118
|
+
this._ensureNotClosed();
|
|
5119
|
+
return this._client.addMcpServer(params);
|
|
5120
|
+
}
|
|
5121
|
+
async removeMcpServer(params) {
|
|
5122
|
+
this._ensureNotClosed();
|
|
5123
|
+
return this._client.removeMcpServer(params);
|
|
5124
|
+
}
|
|
5125
|
+
async toggleMcpServer(params) {
|
|
5126
|
+
this._ensureNotClosed();
|
|
5127
|
+
return this._client.toggleMcpServer(params);
|
|
5128
|
+
}
|
|
5129
|
+
async listMcpServers() {
|
|
5130
|
+
this._ensureNotClosed();
|
|
5131
|
+
return this._client.listMcpServers();
|
|
5132
|
+
}
|
|
5133
|
+
async listMcpTools() {
|
|
5134
|
+
this._ensureNotClosed();
|
|
5135
|
+
return this._client.listMcpTools();
|
|
5136
|
+
}
|
|
5137
|
+
async authenticateMcpServer(params) {
|
|
5138
|
+
this._ensureNotClosed();
|
|
5139
|
+
return this._client.authenticateMcpServer(params);
|
|
5140
|
+
}
|
|
5141
|
+
async listSkills() {
|
|
5142
|
+
this._ensureNotClosed();
|
|
5143
|
+
return this._client.listSkills();
|
|
5144
|
+
}
|
|
5145
|
+
onNotification(callback, filter) {
|
|
5146
|
+
return this._client.onNotification(callback, filter);
|
|
5147
|
+
}
|
|
5148
|
+
_ensureNotClosed() {
|
|
5149
|
+
if (this._closed) {
|
|
5150
|
+
throw new ConnectionError(
|
|
5151
|
+
"Daemon session has been closed. Create a new session to continue."
|
|
5152
|
+
);
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
};
|
|
5156
|
+
|
|
5157
|
+
// src/daemon/transport.ts
|
|
5158
|
+
var import_ws = __toESM(require("ws"), 1);
|
|
5159
|
+
|
|
5160
|
+
// src/daemon/types.ts
|
|
5161
|
+
var MachineType = /* @__PURE__ */ ((MachineType2) => {
|
|
5162
|
+
MachineType2["Local"] = "local";
|
|
5163
|
+
MachineType2["Computer"] = "computer";
|
|
5164
|
+
return MachineType2;
|
|
5165
|
+
})(MachineType || {});
|
|
5166
|
+
var DEFAULT_DAEMON_PORT = 37643;
|
|
5167
|
+
var DEFAULT_RELAY_BASE_URL = "wss://relay.factory.ai";
|
|
5168
|
+
var DEFAULT_WS_CONFIG = {
|
|
5169
|
+
maxConnectRetries: 5,
|
|
5170
|
+
initialRetryDelayMs: 500,
|
|
5171
|
+
maxRetryDelayMs: 5e3,
|
|
5172
|
+
connectionTimeoutMs: 5e3
|
|
5173
|
+
};
|
|
5174
|
+
var COMPUTER_WS_CONFIG = {
|
|
5175
|
+
connectionTimeoutMs: 45e3,
|
|
5176
|
+
maxConnectRetries: 10,
|
|
5177
|
+
initialRetryDelayMs: 2e3,
|
|
5178
|
+
maxRetryDelayMs: 1e4
|
|
5179
|
+
};
|
|
5180
|
+
|
|
5181
|
+
// src/daemon/transport.ts
|
|
5182
|
+
var WebSocketTransport = class {
|
|
5183
|
+
maxConnectRetries;
|
|
5184
|
+
initialRetryDelayMs;
|
|
5185
|
+
maxRetryDelayMs;
|
|
5186
|
+
connectionTimeoutMs;
|
|
5187
|
+
ws = null;
|
|
5188
|
+
messageHandler = null;
|
|
5189
|
+
errorHandler = null;
|
|
5190
|
+
_isConnected = false;
|
|
5191
|
+
isClosing = false;
|
|
5192
|
+
constructor(options = {}) {
|
|
5193
|
+
this.maxConnectRetries = options.maxConnectRetries ?? DEFAULT_WS_CONFIG.maxConnectRetries;
|
|
5194
|
+
this.initialRetryDelayMs = options.initialRetryDelayMs ?? DEFAULT_WS_CONFIG.initialRetryDelayMs;
|
|
5195
|
+
this.maxRetryDelayMs = options.maxRetryDelayMs ?? DEFAULT_WS_CONFIG.maxRetryDelayMs;
|
|
5196
|
+
this.connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_WS_CONFIG.connectionTimeoutMs;
|
|
5197
|
+
}
|
|
5198
|
+
get isConnected() {
|
|
5199
|
+
return this._isConnected;
|
|
5200
|
+
}
|
|
5201
|
+
async connect(url) {
|
|
5202
|
+
if (!url) {
|
|
5203
|
+
throw new ConnectionError("WebSocket URL is required");
|
|
5204
|
+
}
|
|
5205
|
+
if (this._isConnected) {
|
|
5206
|
+
throw new ConnectionError("Transport already connected");
|
|
5207
|
+
}
|
|
5208
|
+
this.isClosing = false;
|
|
5209
|
+
let lastError;
|
|
5210
|
+
for (let attempt = 0; attempt <= this.maxConnectRetries; attempt++) {
|
|
5211
|
+
try {
|
|
5212
|
+
await this._doConnect(url);
|
|
5213
|
+
return;
|
|
5214
|
+
} catch (error) {
|
|
5215
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
5216
|
+
if (attempt < this.maxConnectRetries) {
|
|
5217
|
+
const delay = Math.min(
|
|
5218
|
+
this.initialRetryDelayMs * 2 ** attempt,
|
|
5219
|
+
this.maxRetryDelayMs
|
|
5220
|
+
);
|
|
5221
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
throw lastError;
|
|
5226
|
+
}
|
|
5227
|
+
send(message) {
|
|
5228
|
+
if (!this._isConnected || !this.ws) {
|
|
5229
|
+
throw new ConnectionError("WebSocket transport not connected");
|
|
5230
|
+
}
|
|
5231
|
+
try {
|
|
5232
|
+
this.ws.send(JSON.stringify(message));
|
|
5233
|
+
} catch (error) {
|
|
5234
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
5235
|
+
throw new ConnectionError(`Failed to send WebSocket message: ${msg}`);
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
onMessage(callback) {
|
|
5239
|
+
this.messageHandler = callback;
|
|
5240
|
+
}
|
|
5241
|
+
onError(callback) {
|
|
5242
|
+
this.errorHandler = callback;
|
|
5243
|
+
}
|
|
5244
|
+
async close() {
|
|
5245
|
+
if (this.isClosing) {
|
|
5246
|
+
return;
|
|
5247
|
+
}
|
|
5248
|
+
this.isClosing = true;
|
|
5249
|
+
this._isConnected = false;
|
|
5250
|
+
const ws = this.ws;
|
|
5251
|
+
this.ws = null;
|
|
5252
|
+
if (ws && ws.readyState === import_ws.default.OPEN) {
|
|
5253
|
+
await new Promise((resolve2) => {
|
|
5254
|
+
ws.once("close", () => resolve2());
|
|
5255
|
+
ws.close(1e3, "Client disconnect");
|
|
5256
|
+
setTimeout(() => resolve2(), 5e3);
|
|
5257
|
+
});
|
|
5258
|
+
}
|
|
5259
|
+
this.isClosing = false;
|
|
5260
|
+
}
|
|
5261
|
+
async _doConnect(url) {
|
|
5262
|
+
return new Promise((resolve2, reject) => {
|
|
5263
|
+
let settled = false;
|
|
5264
|
+
let timeoutId = null;
|
|
5265
|
+
const cleanup = () => {
|
|
5266
|
+
if (timeoutId) {
|
|
5267
|
+
clearTimeout(timeoutId);
|
|
5268
|
+
timeoutId = null;
|
|
5269
|
+
}
|
|
5270
|
+
};
|
|
5271
|
+
const ws = new import_ws.default(url);
|
|
5272
|
+
const handleOpen = () => {
|
|
5273
|
+
if (settled) return;
|
|
5274
|
+
settled = true;
|
|
5275
|
+
cleanup();
|
|
5276
|
+
this.ws = ws;
|
|
5277
|
+
this._isConnected = true;
|
|
5278
|
+
this._setupOngoingHandlers(ws);
|
|
5279
|
+
resolve2();
|
|
5280
|
+
};
|
|
5281
|
+
const handleError = (error) => {
|
|
5282
|
+
if (settled) return;
|
|
5283
|
+
settled = true;
|
|
5284
|
+
cleanup();
|
|
5285
|
+
try {
|
|
5286
|
+
ws.close();
|
|
5287
|
+
} catch {
|
|
5288
|
+
}
|
|
5289
|
+
reject(
|
|
5290
|
+
new ConnectionError(`WebSocket connection failed: ${error.message}`)
|
|
5291
|
+
);
|
|
5292
|
+
};
|
|
5293
|
+
const handleClose = (code, reason) => {
|
|
5294
|
+
if (settled) return;
|
|
5295
|
+
settled = true;
|
|
5296
|
+
cleanup();
|
|
5297
|
+
reject(
|
|
5298
|
+
new ConnectionError(
|
|
5299
|
+
`WebSocket closed before opening (code: ${code}, reason: ${reason.toString()})`
|
|
5300
|
+
)
|
|
5301
|
+
);
|
|
5302
|
+
};
|
|
5303
|
+
ws.once("open", handleOpen);
|
|
5304
|
+
ws.once("error", handleError);
|
|
5305
|
+
ws.once("close", handleClose);
|
|
5306
|
+
timeoutId = setTimeout(() => {
|
|
5307
|
+
if (settled) return;
|
|
5308
|
+
settled = true;
|
|
5309
|
+
try {
|
|
5310
|
+
ws.close();
|
|
5311
|
+
} catch {
|
|
5312
|
+
}
|
|
5313
|
+
reject(
|
|
5314
|
+
new ConnectionError(
|
|
5315
|
+
`WebSocket connection timeout after ${this.connectionTimeoutMs}ms: ${url}`
|
|
5316
|
+
)
|
|
5317
|
+
);
|
|
5318
|
+
}, this.connectionTimeoutMs);
|
|
5319
|
+
});
|
|
5320
|
+
}
|
|
5321
|
+
_setupOngoingHandlers(ws) {
|
|
5322
|
+
ws.on("message", (data) => {
|
|
5323
|
+
if (!this.messageHandler) return;
|
|
5324
|
+
const text = typeof data === "string" ? data : data.toString();
|
|
5325
|
+
try {
|
|
5326
|
+
const parsed = JSON.parse(text);
|
|
5327
|
+
if (isRecord(parsed)) {
|
|
5328
|
+
this.messageHandler(parsed);
|
|
5329
|
+
}
|
|
5330
|
+
} catch {
|
|
5331
|
+
}
|
|
5332
|
+
});
|
|
5333
|
+
ws.on("error", (error) => {
|
|
5334
|
+
if (!this.isClosing && this.errorHandler) {
|
|
5335
|
+
this.errorHandler(
|
|
5336
|
+
new ConnectionError(`WebSocket error: ${error.message}`)
|
|
5337
|
+
);
|
|
5338
|
+
}
|
|
5339
|
+
});
|
|
5340
|
+
ws.on("close", (code, reason) => {
|
|
5341
|
+
this._isConnected = false;
|
|
5342
|
+
this.ws = null;
|
|
5343
|
+
if (!this.isClosing && this.errorHandler) {
|
|
5344
|
+
this.errorHandler(
|
|
5345
|
+
new ConnectionError(
|
|
5346
|
+
`WebSocket closed (code: ${code}, reason: ${reason.toString()})`
|
|
5347
|
+
)
|
|
5348
|
+
);
|
|
5349
|
+
}
|
|
5350
|
+
});
|
|
5351
|
+
}
|
|
5352
|
+
};
|
|
5353
|
+
|
|
5354
|
+
// src/daemon/connection.ts
|
|
5355
|
+
var DAEMON_AUTHENTICATE_METHOD = "daemon.authenticate";
|
|
5356
|
+
var DAEMON_AUTHENTICATE_TIMEOUT = 3e4;
|
|
5357
|
+
var SDK_CALLER = "droid-sdk";
|
|
5358
|
+
function resolveWebSocketUrl(options) {
|
|
5359
|
+
if (options.url) {
|
|
5360
|
+
return options.url;
|
|
5361
|
+
}
|
|
5362
|
+
const machine = options.machine;
|
|
5363
|
+
if (!machine || machine.type === "local" /* Local */) {
|
|
5364
|
+
const port = options._localPort ?? options.daemonPort ?? DEFAULT_DAEMON_PORT;
|
|
5365
|
+
return `ws://127.0.0.1:${port}`;
|
|
5366
|
+
}
|
|
5367
|
+
if (machine.type === "computer" /* Computer */) {
|
|
5368
|
+
const relayBase = options.relayBaseUrl ?? DEFAULT_RELAY_BASE_URL;
|
|
5369
|
+
return `${relayBase}/v0/computer/${machine.computerId}/client`;
|
|
5370
|
+
}
|
|
5371
|
+
const _exhaustive = machine;
|
|
5372
|
+
throw new ConnectionError(`Unsupported machine type: ${String(_exhaustive)}`);
|
|
5373
|
+
}
|
|
5374
|
+
function getWebSocketConfig(machine) {
|
|
5375
|
+
if (machine?.type === "computer" /* Computer */) {
|
|
5376
|
+
return { ...DEFAULT_WS_CONFIG, ...COMPUTER_WS_CONFIG };
|
|
5377
|
+
}
|
|
5378
|
+
if (!machine || machine.type === "local" /* Local */) {
|
|
5379
|
+
return { ...DEFAULT_WS_CONFIG, connectionTimeoutMs: 1e4 };
|
|
5380
|
+
}
|
|
5381
|
+
return { ...DEFAULT_WS_CONFIG };
|
|
5382
|
+
}
|
|
5383
|
+
var SharedTransportMultiplexer = class {
|
|
5384
|
+
constructor(_inner) {
|
|
5385
|
+
this._inner = _inner;
|
|
5386
|
+
this._inner.onMessage((message) => {
|
|
5387
|
+
this._routeMessage(message);
|
|
5388
|
+
});
|
|
5389
|
+
this._inner.onError((error) => {
|
|
5390
|
+
for (const view of this._views) {
|
|
5391
|
+
if (view.errorCallback) {
|
|
5392
|
+
try {
|
|
5393
|
+
view.errorCallback(error);
|
|
5394
|
+
} catch {
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
}
|
|
5398
|
+
});
|
|
5399
|
+
}
|
|
5400
|
+
_views = /* @__PURE__ */ new Set();
|
|
5401
|
+
createView() {
|
|
5402
|
+
const inner = this._inner;
|
|
5403
|
+
const viewState = {
|
|
5404
|
+
messageCallback: null,
|
|
5405
|
+
errorCallback: null,
|
|
5406
|
+
pendingRequestIds: /* @__PURE__ */ new Set(),
|
|
5407
|
+
sessionId: null
|
|
5408
|
+
};
|
|
5409
|
+
this._views.add(viewState);
|
|
5410
|
+
const view = {
|
|
5411
|
+
send: (message) => {
|
|
5412
|
+
if (message["type"] === "request" && typeof message["id"] === "string") {
|
|
5413
|
+
viewState.pendingRequestIds.add(message["id"]);
|
|
5414
|
+
}
|
|
5415
|
+
inner.send(message);
|
|
5416
|
+
},
|
|
5417
|
+
onMessage: (callback) => {
|
|
5418
|
+
viewState.messageCallback = callback;
|
|
5419
|
+
},
|
|
5420
|
+
onError: (callback) => {
|
|
5421
|
+
viewState.errorCallback = callback;
|
|
5422
|
+
},
|
|
5423
|
+
close: async () => {
|
|
5424
|
+
viewState.messageCallback = null;
|
|
5425
|
+
viewState.errorCallback = null;
|
|
5426
|
+
viewState.pendingRequestIds.clear();
|
|
5427
|
+
this._views.delete(viewState);
|
|
5428
|
+
},
|
|
5429
|
+
get isConnected() {
|
|
5430
|
+
return inner.isConnected;
|
|
5431
|
+
}
|
|
5432
|
+
};
|
|
5433
|
+
return view;
|
|
5434
|
+
}
|
|
5435
|
+
_routeMessage(message) {
|
|
5436
|
+
const messageType = message["type"];
|
|
5437
|
+
const messageId = message["id"];
|
|
5438
|
+
if (messageType === "response" && typeof messageId === "string") {
|
|
5439
|
+
for (const view of this._views) {
|
|
5440
|
+
if (view.pendingRequestIds.has(messageId)) {
|
|
5441
|
+
view.pendingRequestIds.delete(messageId);
|
|
5442
|
+
const result = message["result"];
|
|
5443
|
+
if (isRecord(result) && typeof result["sessionId"] === "string") {
|
|
5444
|
+
view.sessionId = result["sessionId"];
|
|
5445
|
+
}
|
|
5446
|
+
if (view.messageCallback) {
|
|
5447
|
+
try {
|
|
5448
|
+
view.messageCallback(message);
|
|
5449
|
+
} catch {
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
return;
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
return;
|
|
5456
|
+
}
|
|
5457
|
+
if (messageType === "notification") {
|
|
5458
|
+
const params = message["params"];
|
|
5459
|
+
const sessionId = isRecord(params) && typeof params["sessionId"] === "string" ? params["sessionId"] : null;
|
|
5460
|
+
if (sessionId) {
|
|
5461
|
+
for (const view of this._views) {
|
|
5462
|
+
if (view.sessionId === sessionId && view.messageCallback) {
|
|
5463
|
+
try {
|
|
5464
|
+
view.messageCallback(message);
|
|
5465
|
+
} catch {
|
|
5466
|
+
}
|
|
5467
|
+
return;
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
for (const view of this._views) {
|
|
5472
|
+
if (view.messageCallback) {
|
|
5473
|
+
try {
|
|
5474
|
+
view.messageCallback(message);
|
|
5475
|
+
} catch {
|
|
5476
|
+
}
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
return;
|
|
5480
|
+
}
|
|
5481
|
+
if (messageType === "request") {
|
|
5482
|
+
const params = message["params"];
|
|
5483
|
+
const sessionId = isRecord(params) && typeof params["sessionId"] === "string" ? params["sessionId"] : null;
|
|
5484
|
+
if (sessionId) {
|
|
5485
|
+
for (const view of this._views) {
|
|
5486
|
+
if (view.sessionId === sessionId && view.messageCallback) {
|
|
5487
|
+
try {
|
|
5488
|
+
view.messageCallback(message);
|
|
5489
|
+
} catch {
|
|
5490
|
+
}
|
|
5491
|
+
return;
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
}
|
|
5495
|
+
for (const view of this._views) {
|
|
5496
|
+
if (view.messageCallback) {
|
|
5497
|
+
try {
|
|
5498
|
+
view.messageCallback(message);
|
|
5499
|
+
} catch {
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5505
|
+
};
|
|
5506
|
+
async function authenticate(transport, options) {
|
|
5507
|
+
const requestId = crypto.randomUUID();
|
|
5508
|
+
const envelope = {
|
|
5509
|
+
jsonrpc: JSONRPC_VERSION,
|
|
5510
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION,
|
|
5511
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
5512
|
+
type: "request" /* Request */,
|
|
5513
|
+
id: requestId,
|
|
5514
|
+
method: DAEMON_AUTHENTICATE_METHOD,
|
|
5515
|
+
params: {
|
|
5516
|
+
apiKey: options.apiKey,
|
|
5517
|
+
caller: SDK_CALLER
|
|
5518
|
+
}
|
|
5519
|
+
};
|
|
5520
|
+
return new Promise((resolve2, reject) => {
|
|
5521
|
+
const timer = setTimeout(() => {
|
|
5522
|
+
transport.onMessage(() => {
|
|
5523
|
+
});
|
|
5524
|
+
reject(
|
|
5525
|
+
new ConnectionError(
|
|
5526
|
+
`Daemon authentication timed out after ${DAEMON_AUTHENTICATE_TIMEOUT}ms`
|
|
5527
|
+
)
|
|
5528
|
+
);
|
|
5529
|
+
}, DAEMON_AUTHENTICATE_TIMEOUT);
|
|
5530
|
+
transport.onMessage((message) => {
|
|
5531
|
+
if (message["id"] !== requestId) {
|
|
5532
|
+
return;
|
|
5533
|
+
}
|
|
5534
|
+
clearTimeout(timer);
|
|
5535
|
+
transport.onMessage(() => {
|
|
5536
|
+
});
|
|
5537
|
+
if (message["error"]) {
|
|
5538
|
+
const error = message["error"];
|
|
5539
|
+
const errorMessage = error && typeof error === "object" && "message" in error ? String(error.message) : "unknown error";
|
|
5540
|
+
reject(
|
|
5541
|
+
new ConnectionError(`Daemon authentication failed: ${errorMessage}`)
|
|
5542
|
+
);
|
|
5543
|
+
return;
|
|
5544
|
+
}
|
|
5545
|
+
resolve2();
|
|
5546
|
+
});
|
|
5547
|
+
transport.send(envelope);
|
|
5548
|
+
});
|
|
5549
|
+
}
|
|
5550
|
+
var DaemonConnection = class {
|
|
5551
|
+
_transport;
|
|
5552
|
+
_multiplexer;
|
|
5553
|
+
_apiKey;
|
|
5554
|
+
_closed = false;
|
|
5555
|
+
/** @internal */
|
|
5556
|
+
constructor(transport, apiKey) {
|
|
5557
|
+
this._transport = transport;
|
|
5558
|
+
this._multiplexer = new SharedTransportMultiplexer(transport);
|
|
5559
|
+
this._apiKey = apiKey;
|
|
5560
|
+
}
|
|
5561
|
+
async createSession(options = {}) {
|
|
5562
|
+
this._ensureNotClosed();
|
|
5563
|
+
const view = this._multiplexer.createView();
|
|
5564
|
+
const client = new DaemonClient({
|
|
5565
|
+
transport: view,
|
|
5566
|
+
apiKey: this._apiKey
|
|
5567
|
+
});
|
|
5568
|
+
if (options.permissionHandler) {
|
|
5569
|
+
client.setPermissionHandler(options.permissionHandler);
|
|
5570
|
+
}
|
|
5571
|
+
if (options.askUserHandler) {
|
|
5572
|
+
client.setAskUserHandler(options.askUserHandler);
|
|
5573
|
+
}
|
|
5574
|
+
let sdkMcpServers;
|
|
5575
|
+
try {
|
|
5576
|
+
sdkMcpServers = await startSdkMcpServers(options.mcpServers);
|
|
5577
|
+
const initParams = buildInitParams({
|
|
5578
|
+
...options,
|
|
5579
|
+
mcpServers: sdkMcpServers.mcpServers
|
|
5580
|
+
});
|
|
5581
|
+
const initResult = await client.initializeSession(initParams);
|
|
5582
|
+
const session = new DaemonSession(client, initResult.sessionId);
|
|
5583
|
+
if (sdkMcpServers) {
|
|
5584
|
+
session.addCleanup(sdkMcpServers.cleanup);
|
|
5585
|
+
}
|
|
5586
|
+
return session;
|
|
5587
|
+
} catch (error) {
|
|
5588
|
+
await sdkMcpServers?.cleanup();
|
|
5589
|
+
await client.close();
|
|
5590
|
+
throw error;
|
|
5591
|
+
}
|
|
5592
|
+
}
|
|
5593
|
+
async resumeSession(sessionId, options = {}) {
|
|
5594
|
+
this._ensureNotClosed();
|
|
5595
|
+
const view = this._multiplexer.createView();
|
|
5596
|
+
const client = new DaemonClient({
|
|
5597
|
+
transport: view,
|
|
5598
|
+
apiKey: this._apiKey
|
|
5599
|
+
});
|
|
5600
|
+
if (options.permissionHandler) {
|
|
5601
|
+
client.setPermissionHandler(options.permissionHandler);
|
|
5602
|
+
}
|
|
5603
|
+
if (options.askUserHandler) {
|
|
5604
|
+
client.setAskUserHandler(options.askUserHandler);
|
|
5605
|
+
}
|
|
5606
|
+
let sdkMcpServers;
|
|
5607
|
+
try {
|
|
5608
|
+
sdkMcpServers = await startSdkMcpServers(options.mcpServers);
|
|
5609
|
+
await client.loadSession({
|
|
5610
|
+
sessionId,
|
|
5611
|
+
mcpServers: sdkMcpServers.mcpServers
|
|
5612
|
+
});
|
|
5613
|
+
const session = new DaemonSession(client, sessionId);
|
|
5614
|
+
if (sdkMcpServers) {
|
|
5615
|
+
session.addCleanup(sdkMcpServers.cleanup);
|
|
5616
|
+
}
|
|
5617
|
+
return session;
|
|
5618
|
+
} catch (error) {
|
|
5619
|
+
await sdkMcpServers?.cleanup();
|
|
5620
|
+
await client.close();
|
|
5621
|
+
throw error;
|
|
5622
|
+
}
|
|
5623
|
+
}
|
|
5624
|
+
async interruptSession(sessionId) {
|
|
5625
|
+
this._ensureNotClosed();
|
|
5626
|
+
const view = this._multiplexer.createView();
|
|
5627
|
+
const client = new DaemonClient({
|
|
5628
|
+
transport: view,
|
|
5629
|
+
apiKey: this._apiKey
|
|
5630
|
+
});
|
|
5631
|
+
try {
|
|
5632
|
+
await client.loadSession({ sessionId });
|
|
5633
|
+
await client.interruptSession();
|
|
5634
|
+
} finally {
|
|
5635
|
+
await client.close();
|
|
5636
|
+
}
|
|
5637
|
+
}
|
|
5638
|
+
async close() {
|
|
5639
|
+
if (this._closed) {
|
|
5640
|
+
return;
|
|
5641
|
+
}
|
|
5642
|
+
this._closed = true;
|
|
5643
|
+
await this._transport.close();
|
|
5644
|
+
}
|
|
5645
|
+
_ensureNotClosed() {
|
|
5646
|
+
if (this._closed) {
|
|
5647
|
+
throw new ConnectionError(
|
|
5648
|
+
"Daemon connection has been closed. Call connectDaemon() to create a new connection."
|
|
5649
|
+
);
|
|
5650
|
+
}
|
|
5651
|
+
}
|
|
5652
|
+
};
|
|
5653
|
+
async function connectDaemon(options) {
|
|
5654
|
+
const isLocal = !options.url && (!options.machine || options.machine.type === "local" /* Local */);
|
|
5655
|
+
let resolvedOptions = options;
|
|
5656
|
+
if (isLocal) {
|
|
5657
|
+
const { port } = await ensureLocalDaemon();
|
|
5658
|
+
resolvedOptions = { ...options, _localPort: port };
|
|
5659
|
+
}
|
|
5660
|
+
const url = resolveWebSocketUrl(resolvedOptions);
|
|
5661
|
+
const wsConfig = getWebSocketConfig(resolvedOptions.machine);
|
|
5662
|
+
const transport = new WebSocketTransport(wsConfig);
|
|
5663
|
+
const apiKey = resolvedOptions.apiKey;
|
|
5664
|
+
const maxRetries = resolvedOptions.maxRetries ?? 0;
|
|
5665
|
+
try {
|
|
5666
|
+
if (maxRetries > 0) {
|
|
5667
|
+
let lastError;
|
|
5668
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
5669
|
+
try {
|
|
5670
|
+
await transport.connect(url);
|
|
5671
|
+
await authenticate(transport, resolvedOptions);
|
|
5672
|
+
return new DaemonConnection(transport, apiKey);
|
|
5673
|
+
} catch (error) {
|
|
5674
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
5675
|
+
try {
|
|
5676
|
+
await transport.close();
|
|
5677
|
+
} catch {
|
|
5678
|
+
}
|
|
5679
|
+
if (attempt < maxRetries) {
|
|
5680
|
+
await new Promise((resolve2) => setTimeout(resolve2, 2e3));
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
throw lastError;
|
|
5685
|
+
}
|
|
5686
|
+
await transport.connect(url);
|
|
5687
|
+
await authenticate(transport, resolvedOptions);
|
|
5688
|
+
return new DaemonConnection(transport, apiKey);
|
|
5689
|
+
} catch (error) {
|
|
5690
|
+
try {
|
|
5691
|
+
await transport.close();
|
|
5692
|
+
} catch {
|
|
5693
|
+
}
|
|
5694
|
+
throw error;
|
|
5695
|
+
}
|
|
5696
|
+
}
|
|
4201
5697
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4202
5698
|
0 && (module.exports = {
|
|
4203
5699
|
AddMcpServerRequestParamsSchema,
|
|
@@ -4249,13 +5745,22 @@ async function listSessions(options = {}) {
|
|
|
4249
5745
|
CompactSessionRequestSchema,
|
|
4250
5746
|
CompactSessionResponseSchema,
|
|
4251
5747
|
CompactSessionResultSchema,
|
|
5748
|
+
ComputerListResponseSchema,
|
|
5749
|
+
ComputerMetricSchema,
|
|
5750
|
+
ComputerMetricsResponseSchema,
|
|
5751
|
+
ComputerSchema,
|
|
4252
5752
|
ConnectionError,
|
|
4253
5753
|
ContentBlockSchema,
|
|
5754
|
+
ContextBreakdownCategorySchema,
|
|
5755
|
+
ContextBreakdownResultSchema,
|
|
4254
5756
|
ContextStatsAccuracy,
|
|
4255
5757
|
ContextStatsSchema,
|
|
4256
5758
|
CreateMessageNotificationSchema,
|
|
4257
5759
|
CreateToolConfirmationDetailsSchema,
|
|
4258
5760
|
DEFAULT_REQUEST_TIMEOUT,
|
|
5761
|
+
DaemonClient,
|
|
5762
|
+
DaemonConnection,
|
|
5763
|
+
DaemonSession,
|
|
4259
5764
|
DecompSessionType,
|
|
4260
5765
|
DiscoveredIssueSchema,
|
|
4261
5766
|
DismissalRecordSchema,
|
|
@@ -4370,6 +5875,10 @@ async function listSessions(options = {}) {
|
|
|
4370
5875
|
LoadSessionResponseSchema,
|
|
4371
5876
|
LoadSessionResultSchema,
|
|
4372
5877
|
MCP_AUTH_TIMEOUT,
|
|
5878
|
+
MachineTemplateBuildStatusSchema,
|
|
5879
|
+
MachineTemplateListResponseSchema,
|
|
5880
|
+
MachineTemplateSchema,
|
|
5881
|
+
MachineType,
|
|
4373
5882
|
McpAuthCompletedNotificationSchema,
|
|
4374
5883
|
McpAuthOutcome,
|
|
4375
5884
|
McpAuthRequiredNotificationSchema,
|
|
@@ -4415,6 +5924,9 @@ async function listSessions(options = {}) {
|
|
|
4415
5924
|
REWIND_TIMEOUT,
|
|
4416
5925
|
ReasoningEffort,
|
|
4417
5926
|
RedactedThinkingBlockSchema,
|
|
5927
|
+
RefreshComputerResponseSchema,
|
|
5928
|
+
RemoteSessionListResponseSchema,
|
|
5929
|
+
RemoteSessionSchema,
|
|
4418
5930
|
RemoveMcpServerRequestParamsSchema,
|
|
4419
5931
|
RemoveMcpServerRequestSchema,
|
|
4420
5932
|
RemoveMcpServerResponseSchema,
|
|
@@ -4434,6 +5946,7 @@ async function listSessions(options = {}) {
|
|
|
4434
5946
|
SDK_VERSION,
|
|
4435
5947
|
SESSION_INIT_TIMEOUT,
|
|
4436
5948
|
SdkMcpServer,
|
|
5949
|
+
ServerRequestHandlerType,
|
|
4437
5950
|
SessionError,
|
|
4438
5951
|
SessionMetadataSchema,
|
|
4439
5952
|
SessionNotFoundError,
|
|
@@ -4509,20 +6022,37 @@ async function listSessions(options = {}) {
|
|
|
4509
6022
|
UpdateSessionSettingsResultSchema,
|
|
4510
6023
|
VerificationCommandSchema,
|
|
4511
6024
|
VerificationSchema,
|
|
6025
|
+
WebSocketTransport,
|
|
4512
6026
|
WorkerCompletedEntrySchema,
|
|
4513
6027
|
WorkerFailedEntrySchema,
|
|
4514
6028
|
WorkerPausedEntrySchema,
|
|
4515
6029
|
WorkerSelectedFeatureEntrySchema,
|
|
4516
6030
|
WorkerStartedEntrySchema,
|
|
4517
6031
|
WorkerStateInfoSchema,
|
|
6032
|
+
connectDaemon,
|
|
4518
6033
|
convertNotificationToStreamMessage,
|
|
6034
|
+
createComputer,
|
|
4519
6035
|
createResponseSchema,
|
|
4520
6036
|
createSdkMcpServer,
|
|
4521
6037
|
createSession,
|
|
6038
|
+
deleteComputer,
|
|
4522
6039
|
dispatchNotification,
|
|
6040
|
+
ensureLocalDaemon,
|
|
6041
|
+
getComputer,
|
|
6042
|
+
getComputerByName,
|
|
6043
|
+
getComputerMetrics,
|
|
6044
|
+
getMachineTemplate,
|
|
6045
|
+
listComputers,
|
|
6046
|
+
listMachineTemplates,
|
|
6047
|
+
listRemoteSessions,
|
|
4523
6048
|
listSessions,
|
|
6049
|
+
refreshComputer,
|
|
6050
|
+
resolveWebSocketUrl,
|
|
6051
|
+
restartComputer,
|
|
4524
6052
|
resumeSession,
|
|
6053
|
+
retryInstallDeps,
|
|
4525
6054
|
run,
|
|
4526
|
-
tool
|
|
6055
|
+
tool,
|
|
6056
|
+
updateComputer
|
|
4527
6057
|
});
|
|
4528
6058
|
//# sourceMappingURL=index.cjs.map
|