@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.js
CHANGED
|
@@ -255,6 +255,11 @@ var JsonRpcMessageType = /* @__PURE__ */ ((JsonRpcMessageType2) => {
|
|
|
255
255
|
JsonRpcMessageType2["Notification"] = "notification";
|
|
256
256
|
return JsonRpcMessageType2;
|
|
257
257
|
})(JsonRpcMessageType || {});
|
|
258
|
+
var ServerRequestHandlerType = /* @__PURE__ */ ((ServerRequestHandlerType2) => {
|
|
259
|
+
ServerRequestHandlerType2["Permission"] = "permission";
|
|
260
|
+
ServerRequestHandlerType2["AskUser"] = "askUser";
|
|
261
|
+
return ServerRequestHandlerType2;
|
|
262
|
+
})(ServerRequestHandlerType || {});
|
|
258
263
|
var SettingsLevel = /* @__PURE__ */ ((SettingsLevel2) => {
|
|
259
264
|
SettingsLevel2["Org"] = "org";
|
|
260
265
|
SettingsLevel2["Runtime"] = "runtime";
|
|
@@ -275,7 +280,7 @@ var SkillLocation = /* @__PURE__ */ ((SkillLocation2) => {
|
|
|
275
280
|
// src/schemas/constants.ts
|
|
276
281
|
var JSONRPC_VERSION = "2.0";
|
|
277
282
|
var LEGACY_FACTORY_API_VERSION = "1.0.0";
|
|
278
|
-
var FACTORY_PROTOCOL_VERSION = "1.
|
|
283
|
+
var FACTORY_PROTOCOL_VERSION = "1.51.0";
|
|
279
284
|
var FACTORY_CLIENT_HEADER = "X-Factory-Client";
|
|
280
285
|
var FACTORY_CLIENT_VERSION = "X-Client-Version";
|
|
281
286
|
var DEFAULT_REQUEST_TIMEOUT = 3e4;
|
|
@@ -1135,6 +1140,19 @@ var ForkSessionResultSchema = z5.object({
|
|
|
1135
1140
|
newSessionId: z5.string()
|
|
1136
1141
|
}).passthrough();
|
|
1137
1142
|
var GetContextStatsResultSchema = ContextStatsSchema;
|
|
1143
|
+
var ContextBreakdownCategorySchema = z5.object({
|
|
1144
|
+
name: z5.string(),
|
|
1145
|
+
tokens: z5.number(),
|
|
1146
|
+
colorKey: z5.string()
|
|
1147
|
+
}).passthrough();
|
|
1148
|
+
var ContextBreakdownResultSchema = z5.object({
|
|
1149
|
+
modelId: z5.string(),
|
|
1150
|
+
modelDisplayName: z5.string(),
|
|
1151
|
+
contextBudget: z5.number(),
|
|
1152
|
+
usedTokens: z5.number(),
|
|
1153
|
+
freeTokens: z5.number(),
|
|
1154
|
+
categories: z5.array(ContextBreakdownCategorySchema)
|
|
1155
|
+
}).passthrough();
|
|
1138
1156
|
var RenameSessionResultSchema = SuccessResultSchema;
|
|
1139
1157
|
var InitializeSessionResponseSchema = createResponseSchema(
|
|
1140
1158
|
InitializeSessionResultSchema
|
|
@@ -1638,7 +1656,7 @@ var _CliRequestOrNotificationSchema = z8.union([
|
|
|
1638
1656
|
var CliRequestOrNotificationSchema = _CliRequestOrNotificationSchema;
|
|
1639
1657
|
|
|
1640
1658
|
// src/constants.ts
|
|
1641
|
-
var SDK_VERSION = "0.
|
|
1659
|
+
var SDK_VERSION = "0.4.0";
|
|
1642
1660
|
var SDK_TAG = {
|
|
1643
1661
|
name: "sdk",
|
|
1644
1662
|
metadata: { language: "typescript", version: SDK_VERSION }
|
|
@@ -1972,9 +1990,14 @@ function dispatchNotification(notification, listeners) {
|
|
|
1972
1990
|
}
|
|
1973
1991
|
}
|
|
1974
1992
|
}
|
|
1993
|
+
var DEFAULT_SERVER_REQUEST_METHOD_MAP = {
|
|
1994
|
+
["droid.request_permission" /* REQUEST_PERMISSION */]: "permission" /* Permission */,
|
|
1995
|
+
["droid.ask_user" /* ASK_USER */]: "askUser" /* AskUser */
|
|
1996
|
+
};
|
|
1975
1997
|
var ProtocolEngine = class {
|
|
1976
1998
|
_transport;
|
|
1977
1999
|
_defaultTimeout;
|
|
2000
|
+
_serverRequestMethodMap;
|
|
1978
2001
|
_pendingRequests = /* @__PURE__ */ new Map();
|
|
1979
2002
|
_notificationListeners = /* @__PURE__ */ new Set();
|
|
1980
2003
|
_permissionHandler = null;
|
|
@@ -1984,6 +2007,7 @@ var ProtocolEngine = class {
|
|
|
1984
2007
|
constructor(options) {
|
|
1985
2008
|
this._transport = options.transport;
|
|
1986
2009
|
this._defaultTimeout = options.defaultTimeout ?? DEFAULT_REQUEST_TIMEOUT;
|
|
2010
|
+
this._serverRequestMethodMap = options.serverRequestMethodMap ?? DEFAULT_SERVER_REQUEST_METHOD_MAP;
|
|
1987
2011
|
this._transport.onMessage((message) => {
|
|
1988
2012
|
this._handleMessage(message);
|
|
1989
2013
|
});
|
|
@@ -2139,9 +2163,10 @@ var ProtocolEngine = class {
|
|
|
2139
2163
|
dispatchNotification(notification, this._notificationListeners);
|
|
2140
2164
|
}
|
|
2141
2165
|
async _handleServerRequest(method, requestId, params) {
|
|
2142
|
-
|
|
2166
|
+
const handlerType = this._serverRequestMethodMap[method];
|
|
2167
|
+
if (handlerType === "permission" /* Permission */) {
|
|
2143
2168
|
await this._handlePermissionRequest(requestId, params);
|
|
2144
|
-
} else if (
|
|
2169
|
+
} else if (handlerType === "askUser" /* AskUser */) {
|
|
2145
2170
|
await this._handleAskUserRequest(requestId, params);
|
|
2146
2171
|
}
|
|
2147
2172
|
}
|
|
@@ -2999,6 +3024,69 @@ function wireAbortSignal(signal, onAbort) {
|
|
|
2999
3024
|
return () => signal.removeEventListener("abort", listener);
|
|
3000
3025
|
}
|
|
3001
3026
|
}
|
|
3027
|
+
function getAbortError(signal) {
|
|
3028
|
+
if (signal.reason instanceof Error) {
|
|
3029
|
+
return signal.reason;
|
|
3030
|
+
}
|
|
3031
|
+
return new Error(
|
|
3032
|
+
typeof signal.reason === "string" ? signal.reason : "Operation aborted"
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
function throwIfAborted(signal) {
|
|
3036
|
+
if (signal?.aborted) {
|
|
3037
|
+
throw getAbortError(signal);
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
async function* streamFromClient(client, sessionId, activeBridges, prompt, options) {
|
|
3041
|
+
throwIfAborted(options?.abortSignal);
|
|
3042
|
+
const startedAt = Date.now();
|
|
3043
|
+
let resolveDone = () => {
|
|
3044
|
+
};
|
|
3045
|
+
const donePromise = new Promise((resolve2) => {
|
|
3046
|
+
resolveDone = resolve2;
|
|
3047
|
+
});
|
|
3048
|
+
const bridge = new MessageBridge(resolveDone, {
|
|
3049
|
+
includePartialMessages: options?.includePartialMessages,
|
|
3050
|
+
sessionId,
|
|
3051
|
+
startedAt,
|
|
3052
|
+
outputFormat: options?.outputFormat
|
|
3053
|
+
});
|
|
3054
|
+
activeBridges.add(bridge);
|
|
3055
|
+
const unsubscribe = client.onNotification(bridge.notificationHandler);
|
|
3056
|
+
let resolveAbort = () => {
|
|
3057
|
+
};
|
|
3058
|
+
const abortPromise = new Promise((resolve2) => {
|
|
3059
|
+
resolveAbort = resolve2;
|
|
3060
|
+
});
|
|
3061
|
+
const cleanupAbortSignal = wireAbortSignal(options?.abortSignal, () => {
|
|
3062
|
+
bridge.signalDone();
|
|
3063
|
+
resolveAbort();
|
|
3064
|
+
void client.interruptSession().catch(() => {
|
|
3065
|
+
});
|
|
3066
|
+
});
|
|
3067
|
+
try {
|
|
3068
|
+
await Promise.race([
|
|
3069
|
+
client.addUserMessage({
|
|
3070
|
+
text: prompt,
|
|
3071
|
+
images: options?.images,
|
|
3072
|
+
files: options?.files,
|
|
3073
|
+
outputFormat: options?.outputFormat
|
|
3074
|
+
}),
|
|
3075
|
+
donePromise,
|
|
3076
|
+
abortPromise
|
|
3077
|
+
]);
|
|
3078
|
+
throwIfAborted(options?.abortSignal);
|
|
3079
|
+
for await (const msg of bridge.messages()) {
|
|
3080
|
+
throwIfAborted(options?.abortSignal);
|
|
3081
|
+
yield msg;
|
|
3082
|
+
}
|
|
3083
|
+
throwIfAborted(options?.abortSignal);
|
|
3084
|
+
} finally {
|
|
3085
|
+
cleanupAbortSignal();
|
|
3086
|
+
unsubscribe();
|
|
3087
|
+
activeBridges.delete(bridge);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3002
3090
|
function extractInnerNotification(notification) {
|
|
3003
3091
|
const parsed = SessionNotificationSchema.safeParse(notification);
|
|
3004
3092
|
return parsed.success ? parsed.data.params.notification : null;
|
|
@@ -3094,7 +3182,7 @@ async function createTransport(options) {
|
|
|
3094
3182
|
execPath: options.execPath,
|
|
3095
3183
|
execArgs: options.execArgs,
|
|
3096
3184
|
cwd: options.cwd,
|
|
3097
|
-
env: options.env
|
|
3185
|
+
env: { ...options.env, FACTORY_API_KEY: options.apiKey }
|
|
3098
3186
|
};
|
|
3099
3187
|
const processTransport = new ProcessTransport(transportOptions);
|
|
3100
3188
|
await processTransport.connect();
|
|
@@ -3152,6 +3240,9 @@ function buildInitParams(options) {
|
|
|
3152
3240
|
...options.disabledToolIds !== void 0 && {
|
|
3153
3241
|
disabledToolIds: options.disabledToolIds
|
|
3154
3242
|
},
|
|
3243
|
+
...options.sessionSource !== void 0 && {
|
|
3244
|
+
sessionSource: options.sessionSource
|
|
3245
|
+
},
|
|
3155
3246
|
tags: [...options.tags ?? [], SDK_TAG]
|
|
3156
3247
|
};
|
|
3157
3248
|
}
|
|
@@ -3352,19 +3443,6 @@ async function startSdkMcpServers(servers) {
|
|
|
3352
3443
|
}
|
|
3353
3444
|
|
|
3354
3445
|
// src/session.ts
|
|
3355
|
-
function getAbortError(signal) {
|
|
3356
|
-
if (signal.reason instanceof Error) {
|
|
3357
|
-
return signal.reason;
|
|
3358
|
-
}
|
|
3359
|
-
return new Error(
|
|
3360
|
-
typeof signal.reason === "string" ? signal.reason : "Operation aborted"
|
|
3361
|
-
);
|
|
3362
|
-
}
|
|
3363
|
-
function throwIfAborted(signal) {
|
|
3364
|
-
if (signal?.aborted) {
|
|
3365
|
-
throw getAbortError(signal);
|
|
3366
|
-
}
|
|
3367
|
-
}
|
|
3368
3446
|
var DroidSession = class {
|
|
3369
3447
|
_client;
|
|
3370
3448
|
_sessionId;
|
|
@@ -3395,54 +3473,13 @@ var DroidSession = class {
|
|
|
3395
3473
|
}
|
|
3396
3474
|
async *stream(prompt, options) {
|
|
3397
3475
|
this._ensureNotClosed();
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
const bridge = new MessageBridge(resolveDone, {
|
|
3406
|
-
includePartialMessages: options?.includePartialMessages,
|
|
3407
|
-
sessionId: this._sessionId,
|
|
3408
|
-
startedAt,
|
|
3409
|
-
outputFormat: options?.outputFormat
|
|
3410
|
-
});
|
|
3411
|
-
this._activeBridges.add(bridge);
|
|
3412
|
-
const unsubscribe = this._client.onNotification(bridge.notificationHandler);
|
|
3413
|
-
let resolveAbort = () => {
|
|
3414
|
-
};
|
|
3415
|
-
const abortPromise = new Promise((resolve2) => {
|
|
3416
|
-
resolveAbort = resolve2;
|
|
3417
|
-
});
|
|
3418
|
-
const cleanupAbortSignal = wireAbortSignal(options?.abortSignal, () => {
|
|
3419
|
-
bridge.signalDone();
|
|
3420
|
-
resolveAbort();
|
|
3421
|
-
void this._client.interruptSession().catch(() => {
|
|
3422
|
-
});
|
|
3423
|
-
});
|
|
3424
|
-
try {
|
|
3425
|
-
await Promise.race([
|
|
3426
|
-
this._client.addUserMessage({
|
|
3427
|
-
text: prompt,
|
|
3428
|
-
images: options?.images,
|
|
3429
|
-
files: options?.files,
|
|
3430
|
-
outputFormat: options?.outputFormat
|
|
3431
|
-
}),
|
|
3432
|
-
donePromise,
|
|
3433
|
-
abortPromise
|
|
3434
|
-
]);
|
|
3435
|
-
throwIfAborted(options?.abortSignal);
|
|
3436
|
-
for await (const msg of bridge.messages()) {
|
|
3437
|
-
throwIfAborted(options?.abortSignal);
|
|
3438
|
-
yield msg;
|
|
3439
|
-
}
|
|
3440
|
-
throwIfAborted(options?.abortSignal);
|
|
3441
|
-
} finally {
|
|
3442
|
-
cleanupAbortSignal();
|
|
3443
|
-
unsubscribe();
|
|
3444
|
-
this._activeBridges.delete(bridge);
|
|
3445
|
-
}
|
|
3476
|
+
yield* streamFromClient(
|
|
3477
|
+
this._client,
|
|
3478
|
+
this._sessionId,
|
|
3479
|
+
this._activeBridges,
|
|
3480
|
+
prompt,
|
|
3481
|
+
options
|
|
3482
|
+
);
|
|
3446
3483
|
}
|
|
3447
3484
|
async interrupt() {
|
|
3448
3485
|
this._ensureNotClosed();
|
|
@@ -3545,7 +3582,7 @@ var DroidSession = class {
|
|
|
3545
3582
|
}
|
|
3546
3583
|
}
|
|
3547
3584
|
};
|
|
3548
|
-
async function createSession(options
|
|
3585
|
+
async function createSession(options) {
|
|
3549
3586
|
const { client } = await createConfiguredClient(options);
|
|
3550
3587
|
let cleanupInitAbortSignal = options.abortSignal?.aborted ? () => {
|
|
3551
3588
|
} : wireAbortSignal(options.abortSignal, () => {
|
|
@@ -3575,7 +3612,7 @@ async function createSession(options = {}) {
|
|
|
3575
3612
|
throw error;
|
|
3576
3613
|
}
|
|
3577
3614
|
}
|
|
3578
|
-
async function resumeSession(sessionId, options
|
|
3615
|
+
async function resumeSession(sessionId, options) {
|
|
3579
3616
|
const { client } = await createConfiguredClient(options);
|
|
3580
3617
|
let sdkMcpServers;
|
|
3581
3618
|
try {
|
|
@@ -3599,7 +3636,7 @@ async function resumeSession(sessionId, options = {}) {
|
|
|
3599
3636
|
}
|
|
3600
3637
|
|
|
3601
3638
|
// src/run.ts
|
|
3602
|
-
async function run(prompt, options
|
|
3639
|
+
async function run(prompt, options) {
|
|
3603
3640
|
const session = await createSession(options);
|
|
3604
3641
|
try {
|
|
3605
3642
|
for await (const msg of session.stream(prompt, {
|
|
@@ -3839,6 +3876,1431 @@ async function listSessions(options = {}) {
|
|
|
3839
3876
|
}
|
|
3840
3877
|
return sorted;
|
|
3841
3878
|
}
|
|
3879
|
+
|
|
3880
|
+
// src/api-types.ts
|
|
3881
|
+
import { z as z10 } from "zod";
|
|
3882
|
+
var EnvironmentVariableSchema = z10.object({
|
|
3883
|
+
key: z10.string(),
|
|
3884
|
+
value: z10.string()
|
|
3885
|
+
});
|
|
3886
|
+
var MachineTemplateBuildStatusSchema = z10.object({
|
|
3887
|
+
status: z10.enum(["building", "success", "failed"]),
|
|
3888
|
+
failureReason: z10.enum(["setup_script_error", "system_error"]).optional(),
|
|
3889
|
+
buildStartedAt: z10.number().int().optional(),
|
|
3890
|
+
builtAt: z10.number().int().optional(),
|
|
3891
|
+
logs: z10.string().optional()
|
|
3892
|
+
});
|
|
3893
|
+
var MachineTemplateSchema = z10.object({
|
|
3894
|
+
templateId: z10.string(),
|
|
3895
|
+
repoUrl: z10.string(),
|
|
3896
|
+
templateName: z10.string(),
|
|
3897
|
+
defaultBranch: z10.string(),
|
|
3898
|
+
createdBy: z10.string(),
|
|
3899
|
+
createdAt: z10.number().int().optional(),
|
|
3900
|
+
buildStatus: MachineTemplateBuildStatusSchema.optional(),
|
|
3901
|
+
lastUpdatedAt: z10.number().int().nullable().optional(),
|
|
3902
|
+
environmentVariables: z10.array(EnvironmentVariableSchema).optional(),
|
|
3903
|
+
userEnvironmentVariablesByUser: z10.array(EnvironmentVariableSchema).optional(),
|
|
3904
|
+
setupScript: z10.string().optional()
|
|
3905
|
+
});
|
|
3906
|
+
var MachineTemplateListResponseSchema = z10.object({
|
|
3907
|
+
templates: z10.array(MachineTemplateSchema),
|
|
3908
|
+
pagination: z10.object({
|
|
3909
|
+
hasMore: z10.boolean(),
|
|
3910
|
+
nextCursor: z10.string().nullable()
|
|
3911
|
+
})
|
|
3912
|
+
});
|
|
3913
|
+
var ComputerSchema = z10.object({
|
|
3914
|
+
id: z10.string(),
|
|
3915
|
+
name: z10.string(),
|
|
3916
|
+
hostname: z10.string().optional(),
|
|
3917
|
+
providerType: z10.enum(["byom", "e2b"]),
|
|
3918
|
+
status: z10.enum(["provisioning", "active", "error"]).optional(),
|
|
3919
|
+
createdAt: z10.number().int(),
|
|
3920
|
+
relayClientUrl: z10.string().optional(),
|
|
3921
|
+
remoteUser: z10.string().optional()
|
|
3922
|
+
}).passthrough();
|
|
3923
|
+
var ComputerListResponseSchema = z10.object({
|
|
3924
|
+
computers: z10.array(ComputerSchema)
|
|
3925
|
+
});
|
|
3926
|
+
var RefreshComputerResponseSchema = z10.object({
|
|
3927
|
+
configured: z10.number().int()
|
|
3928
|
+
});
|
|
3929
|
+
var ComputerMetricSchema = z10.object({
|
|
3930
|
+
timestamp: z10.string(),
|
|
3931
|
+
cpuUsedPct: z10.number(),
|
|
3932
|
+
cpuCount: z10.number(),
|
|
3933
|
+
memUsed: z10.number(),
|
|
3934
|
+
memTotal: z10.number(),
|
|
3935
|
+
diskUsed: z10.number(),
|
|
3936
|
+
diskTotal: z10.number()
|
|
3937
|
+
});
|
|
3938
|
+
var ComputerMetricsResponseSchema = z10.array(ComputerMetricSchema);
|
|
3939
|
+
var RemoteSessionSchema = z10.object({
|
|
3940
|
+
sessionId: z10.string(),
|
|
3941
|
+
title: z10.string().optional(),
|
|
3942
|
+
status: z10.enum(["idle", "pending", "running"]),
|
|
3943
|
+
messageCount: z10.number().int(),
|
|
3944
|
+
createdAt: z10.number().int(),
|
|
3945
|
+
updatedAt: z10.number().int(),
|
|
3946
|
+
completedAt: z10.number().int().optional(),
|
|
3947
|
+
computerId: z10.string().optional()
|
|
3948
|
+
});
|
|
3949
|
+
var RemoteSessionListResponseSchema = z10.object({
|
|
3950
|
+
sessions: z10.array(RemoteSessionSchema),
|
|
3951
|
+
pagination: z10.object({
|
|
3952
|
+
hasMore: z10.boolean(),
|
|
3953
|
+
nextCursor: z10.string().nullable()
|
|
3954
|
+
})
|
|
3955
|
+
});
|
|
3956
|
+
|
|
3957
|
+
// src/api.ts
|
|
3958
|
+
var DEFAULT_BASE_URL = "https://api.factory.ai";
|
|
3959
|
+
function extractErrorMessage(body, status) {
|
|
3960
|
+
if (isRecord(body) && typeof body["error"] === "string") {
|
|
3961
|
+
return body["error"];
|
|
3962
|
+
}
|
|
3963
|
+
return `Factory API error (status ${status})`;
|
|
3964
|
+
}
|
|
3965
|
+
async function factoryFetch(path3, apiKey, baseUrl, options) {
|
|
3966
|
+
const url = `${baseUrl ?? DEFAULT_BASE_URL}${path3}`;
|
|
3967
|
+
const method = options?.method ?? "GET";
|
|
3968
|
+
const headers = {
|
|
3969
|
+
Authorization: `Bearer ${apiKey}`,
|
|
3970
|
+
Accept: "application/json"
|
|
3971
|
+
};
|
|
3972
|
+
if (options?.body) {
|
|
3973
|
+
headers["Content-Type"] = "application/json";
|
|
3974
|
+
}
|
|
3975
|
+
let response;
|
|
3976
|
+
try {
|
|
3977
|
+
response = await fetch(url, {
|
|
3978
|
+
method,
|
|
3979
|
+
headers,
|
|
3980
|
+
...options?.body ? { body: JSON.stringify(options.body) } : {}
|
|
3981
|
+
});
|
|
3982
|
+
} catch (error) {
|
|
3983
|
+
throw new ConnectionError(
|
|
3984
|
+
`Failed to reach Factory API: ${error instanceof Error ? error.message : String(error)}`
|
|
3985
|
+
);
|
|
3986
|
+
}
|
|
3987
|
+
if (response.status === 204) {
|
|
3988
|
+
return void 0;
|
|
3989
|
+
}
|
|
3990
|
+
let body;
|
|
3991
|
+
try {
|
|
3992
|
+
body = await response.json();
|
|
3993
|
+
} catch {
|
|
3994
|
+
throw new ProtocolError(
|
|
3995
|
+
`Factory API returned non-JSON response (status ${response.status})`
|
|
3996
|
+
);
|
|
3997
|
+
}
|
|
3998
|
+
if (!response.ok) {
|
|
3999
|
+
const message = extractErrorMessage(body, response.status);
|
|
4000
|
+
if (response.status === 401 || response.status === 403) {
|
|
4001
|
+
throw new ProtocolError(`Invalid or expired API key: ${message}`, {
|
|
4002
|
+
code: response.status
|
|
4003
|
+
});
|
|
4004
|
+
}
|
|
4005
|
+
throw new ProtocolError(message, { code: response.status });
|
|
4006
|
+
}
|
|
4007
|
+
return body;
|
|
4008
|
+
}
|
|
4009
|
+
function parseResponse(body, schema) {
|
|
4010
|
+
const parsed = schema.safeParse(body);
|
|
4011
|
+
if (!parsed.success) {
|
|
4012
|
+
throw new ProtocolError(
|
|
4013
|
+
`Unexpected response format from Factory API: ${parsed.error.message}`
|
|
4014
|
+
);
|
|
4015
|
+
}
|
|
4016
|
+
return parsed.data;
|
|
4017
|
+
}
|
|
4018
|
+
async function listMachineTemplates(options) {
|
|
4019
|
+
const params = new URLSearchParams();
|
|
4020
|
+
if (options.limit != null) {
|
|
4021
|
+
params.set("limit", String(options.limit));
|
|
4022
|
+
}
|
|
4023
|
+
if (options.cursor != null) {
|
|
4024
|
+
params.set("cursor", options.cursor);
|
|
4025
|
+
}
|
|
4026
|
+
const query = params.toString();
|
|
4027
|
+
const path3 = `/api/v0/machines/templates${query ? `?${query}` : ""}`;
|
|
4028
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4029
|
+
return parseResponse(body, MachineTemplateListResponseSchema);
|
|
4030
|
+
}
|
|
4031
|
+
async function getMachineTemplate(options) {
|
|
4032
|
+
const path3 = `/api/v0/machines/templates/${encodeURIComponent(options.templateId)}`;
|
|
4033
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4034
|
+
return parseResponse(body, MachineTemplateSchema);
|
|
4035
|
+
}
|
|
4036
|
+
async function listComputers(options) {
|
|
4037
|
+
const path3 = "/api/v0/computers";
|
|
4038
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4039
|
+
return parseResponse(body, ComputerListResponseSchema);
|
|
4040
|
+
}
|
|
4041
|
+
async function getComputer(options) {
|
|
4042
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}`;
|
|
4043
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4044
|
+
return parseResponse(body, ComputerSchema);
|
|
4045
|
+
}
|
|
4046
|
+
async function createComputer(options) {
|
|
4047
|
+
const path3 = "/api/v0/computers";
|
|
4048
|
+
const reqBody = {
|
|
4049
|
+
name: options.name,
|
|
4050
|
+
remoteUser: options.remoteUser
|
|
4051
|
+
};
|
|
4052
|
+
if (options.provider != null) reqBody["provider"] = options.provider;
|
|
4053
|
+
if (options.hostId != null) reqBody["hostId"] = options.hostId;
|
|
4054
|
+
if (options.repos != null) reqBody["repos"] = options.repos;
|
|
4055
|
+
if (options.autoInstallDeps != null)
|
|
4056
|
+
reqBody["autoInstallDeps"] = options.autoInstallDeps;
|
|
4057
|
+
if (options.serviceAccountId != null)
|
|
4058
|
+
reqBody["serviceAccountId"] = options.serviceAccountId;
|
|
4059
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4060
|
+
method: "POST",
|
|
4061
|
+
body: reqBody
|
|
4062
|
+
});
|
|
4063
|
+
return parseResponse(body, ComputerSchema);
|
|
4064
|
+
}
|
|
4065
|
+
async function getComputerByName(options) {
|
|
4066
|
+
const path3 = `/api/v0/computers/name/${encodeURIComponent(options.name)}`;
|
|
4067
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4068
|
+
return parseResponse(body, ComputerSchema);
|
|
4069
|
+
}
|
|
4070
|
+
async function updateComputer(options) {
|
|
4071
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}`;
|
|
4072
|
+
const reqBody = {};
|
|
4073
|
+
if (options.name != null) reqBody["name"] = options.name;
|
|
4074
|
+
if (options.remoteUser != null) reqBody["remoteUser"] = options.remoteUser;
|
|
4075
|
+
if (options.hostId != null) reqBody["hostId"] = options.hostId;
|
|
4076
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4077
|
+
method: "PATCH",
|
|
4078
|
+
body: reqBody
|
|
4079
|
+
});
|
|
4080
|
+
return parseResponse(body, ComputerSchema);
|
|
4081
|
+
}
|
|
4082
|
+
async function deleteComputer(options) {
|
|
4083
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}`;
|
|
4084
|
+
await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4085
|
+
method: "DELETE"
|
|
4086
|
+
});
|
|
4087
|
+
}
|
|
4088
|
+
async function restartComputer(options) {
|
|
4089
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/restart`;
|
|
4090
|
+
await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4091
|
+
method: "POST"
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4094
|
+
async function refreshComputer(options) {
|
|
4095
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/refresh`;
|
|
4096
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4097
|
+
method: "POST"
|
|
4098
|
+
});
|
|
4099
|
+
return parseResponse(body, RefreshComputerResponseSchema);
|
|
4100
|
+
}
|
|
4101
|
+
async function getComputerMetrics(options) {
|
|
4102
|
+
const params = new URLSearchParams();
|
|
4103
|
+
if (options.start != null) {
|
|
4104
|
+
params.set("start", options.start);
|
|
4105
|
+
}
|
|
4106
|
+
const query = params.toString();
|
|
4107
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/metrics${query ? `?${query}` : ""}`;
|
|
4108
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4109
|
+
return parseResponse(body, ComputerMetricsResponseSchema);
|
|
4110
|
+
}
|
|
4111
|
+
async function retryInstallDeps(options) {
|
|
4112
|
+
const path3 = `/api/v0/computers/${encodeURIComponent(options.computerId)}/install-deps`;
|
|
4113
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl, {
|
|
4114
|
+
method: "POST"
|
|
4115
|
+
});
|
|
4116
|
+
return parseResponse(body, ComputerSchema);
|
|
4117
|
+
}
|
|
4118
|
+
async function listRemoteSessions(options) {
|
|
4119
|
+
const params = new URLSearchParams();
|
|
4120
|
+
if (options.computerId != null) {
|
|
4121
|
+
params.set("computerId", options.computerId);
|
|
4122
|
+
}
|
|
4123
|
+
if (options.limit != null) {
|
|
4124
|
+
params.set("limit", String(options.limit));
|
|
4125
|
+
}
|
|
4126
|
+
if (options.cursor != null) {
|
|
4127
|
+
params.set("cursor", options.cursor);
|
|
4128
|
+
}
|
|
4129
|
+
const query = params.toString();
|
|
4130
|
+
const path3 = `/api/v0/sessions${query ? `?${query}` : ""}`;
|
|
4131
|
+
const body = await factoryFetch(path3, options.apiKey, options.baseUrl);
|
|
4132
|
+
return parseResponse(body, RemoteSessionListResponseSchema);
|
|
4133
|
+
}
|
|
4134
|
+
|
|
4135
|
+
// src/daemon/client.ts
|
|
4136
|
+
var DAEMON_SERVER_REQUEST_METHODS = {
|
|
4137
|
+
"daemon.request_permission": "permission" /* Permission */,
|
|
4138
|
+
"daemon.ask_user": "askUser" /* AskUser */
|
|
4139
|
+
};
|
|
4140
|
+
var DaemonClient = class {
|
|
4141
|
+
_engine;
|
|
4142
|
+
_apiKey;
|
|
4143
|
+
_sessionId = null;
|
|
4144
|
+
_closed = false;
|
|
4145
|
+
_notificationListeners = [];
|
|
4146
|
+
_permissionHandler = null;
|
|
4147
|
+
_askUserHandler = null;
|
|
4148
|
+
constructor(options) {
|
|
4149
|
+
this._apiKey = options.apiKey;
|
|
4150
|
+
this._engine = new ProtocolEngine({
|
|
4151
|
+
transport: options.transport,
|
|
4152
|
+
serverRequestMethodMap: DAEMON_SERVER_REQUEST_METHODS
|
|
4153
|
+
});
|
|
4154
|
+
this._engine.onNotification((notification) => {
|
|
4155
|
+
const normalized = notification["method"] === "daemon.session_notification" ? { ...notification, method: "droid.session_notification" } : notification;
|
|
4156
|
+
dispatchNotification(normalized, [...this._notificationListeners]);
|
|
4157
|
+
});
|
|
4158
|
+
this._engine.setPermissionHandler(
|
|
4159
|
+
(params) => this._dispatchPermissionRequest(params)
|
|
4160
|
+
);
|
|
4161
|
+
this._engine.setAskUserHandler(
|
|
4162
|
+
(params) => this._dispatchAskUserRequest(params)
|
|
4163
|
+
);
|
|
4164
|
+
}
|
|
4165
|
+
get sessionId() {
|
|
4166
|
+
return this._sessionId;
|
|
4167
|
+
}
|
|
4168
|
+
get isConnected() {
|
|
4169
|
+
return !this._closed && this._engine.isHealthy;
|
|
4170
|
+
}
|
|
4171
|
+
async initializeSession(params) {
|
|
4172
|
+
this._ensureNotClosed();
|
|
4173
|
+
const result = await this._rpc(
|
|
4174
|
+
"daemon.initialize_session" /* INITIALIZE_SESSION */,
|
|
4175
|
+
{ ...params, token: this._apiKey },
|
|
4176
|
+
InitializeSessionResultSchema,
|
|
4177
|
+
SESSION_INIT_TIMEOUT
|
|
4178
|
+
);
|
|
4179
|
+
this._sessionId = result.sessionId;
|
|
4180
|
+
return result;
|
|
4181
|
+
}
|
|
4182
|
+
async loadSession(params) {
|
|
4183
|
+
this._ensureNotClosed();
|
|
4184
|
+
const result = await this._rpc(
|
|
4185
|
+
"daemon.load_session" /* LOAD_SESSION */,
|
|
4186
|
+
{ ...params, token: this._apiKey },
|
|
4187
|
+
LoadSessionResultSchema,
|
|
4188
|
+
SESSION_INIT_TIMEOUT
|
|
4189
|
+
);
|
|
4190
|
+
this._sessionId = params.sessionId;
|
|
4191
|
+
return result;
|
|
4192
|
+
}
|
|
4193
|
+
async addUserMessage(params) {
|
|
4194
|
+
return this._sessionRpc(
|
|
4195
|
+
"daemon.add_user_message" /* ADD_USER_MESSAGE */,
|
|
4196
|
+
params,
|
|
4197
|
+
AddUserMessageResultSchema
|
|
4198
|
+
);
|
|
4199
|
+
}
|
|
4200
|
+
async interruptSession() {
|
|
4201
|
+
return this._sessionRpc(
|
|
4202
|
+
"daemon.interrupt_session" /* INTERRUPT_SESSION */,
|
|
4203
|
+
{},
|
|
4204
|
+
InterruptSessionResultSchema
|
|
4205
|
+
);
|
|
4206
|
+
}
|
|
4207
|
+
async closeSession(params = {}) {
|
|
4208
|
+
return this._sessionRpc(
|
|
4209
|
+
"daemon.close_session" /* CLOSE_SESSION */,
|
|
4210
|
+
params,
|
|
4211
|
+
CloseSessionResultSchema
|
|
4212
|
+
);
|
|
4213
|
+
}
|
|
4214
|
+
async updateSessionSettings(params) {
|
|
4215
|
+
return this._sessionRpc(
|
|
4216
|
+
"daemon.update_session_settings" /* UPDATE_SESSION_SETTINGS */,
|
|
4217
|
+
params,
|
|
4218
|
+
UpdateSessionSettingsResultSchema
|
|
4219
|
+
);
|
|
4220
|
+
}
|
|
4221
|
+
async compactSession(params = {}) {
|
|
4222
|
+
return this._sessionRpc(
|
|
4223
|
+
"daemon.compact_session" /* COMPACT_SESSION */,
|
|
4224
|
+
params,
|
|
4225
|
+
CompactSessionResultSchema,
|
|
4226
|
+
COMPACTION_TIMEOUT
|
|
4227
|
+
);
|
|
4228
|
+
}
|
|
4229
|
+
async forkSession() {
|
|
4230
|
+
return this._sessionRpc(
|
|
4231
|
+
"daemon.fork_session" /* FORK_SESSION */,
|
|
4232
|
+
{},
|
|
4233
|
+
ForkSessionResultSchema
|
|
4234
|
+
);
|
|
4235
|
+
}
|
|
4236
|
+
async getContextBreakdown() {
|
|
4237
|
+
return this._sessionRpc(
|
|
4238
|
+
"daemon.get_context_breakdown" /* GET_CONTEXT_STATS */,
|
|
4239
|
+
{},
|
|
4240
|
+
ContextBreakdownResultSchema
|
|
4241
|
+
);
|
|
4242
|
+
}
|
|
4243
|
+
async renameSession(params) {
|
|
4244
|
+
return this._sessionRpc(
|
|
4245
|
+
"daemon.rename_session" /* RENAME_SESSION */,
|
|
4246
|
+
params,
|
|
4247
|
+
RenameSessionResultSchema
|
|
4248
|
+
);
|
|
4249
|
+
}
|
|
4250
|
+
async getRewindInfo(params) {
|
|
4251
|
+
return this._sessionRpc(
|
|
4252
|
+
"daemon.get_rewind_info" /* GET_REWIND_INFO */,
|
|
4253
|
+
params,
|
|
4254
|
+
GetRewindInfoResultSchema,
|
|
4255
|
+
REWIND_TIMEOUT
|
|
4256
|
+
);
|
|
4257
|
+
}
|
|
4258
|
+
async executeRewind(params) {
|
|
4259
|
+
return this._sessionRpc(
|
|
4260
|
+
"daemon.execute_rewind" /* EXECUTE_REWIND */,
|
|
4261
|
+
params,
|
|
4262
|
+
ExecuteRewindResultSchema,
|
|
4263
|
+
REWIND_TIMEOUT
|
|
4264
|
+
);
|
|
4265
|
+
}
|
|
4266
|
+
async addMcpServer(params) {
|
|
4267
|
+
return this._sessionRpc(
|
|
4268
|
+
"daemon.add_mcp_server" /* ADD_MCP_SERVER */,
|
|
4269
|
+
params,
|
|
4270
|
+
AddMcpServerResultSchema
|
|
4271
|
+
);
|
|
4272
|
+
}
|
|
4273
|
+
async removeMcpServer(params) {
|
|
4274
|
+
return this._sessionRpc(
|
|
4275
|
+
"daemon.remove_mcp_server" /* REMOVE_MCP_SERVER */,
|
|
4276
|
+
params,
|
|
4277
|
+
RemoveMcpServerResultSchema
|
|
4278
|
+
);
|
|
4279
|
+
}
|
|
4280
|
+
async toggleMcpServer(params) {
|
|
4281
|
+
return this._sessionRpc(
|
|
4282
|
+
"daemon.toggle_mcp_server" /* TOGGLE_MCP_SERVER */,
|
|
4283
|
+
params,
|
|
4284
|
+
ToggleMcpServerResultSchema
|
|
4285
|
+
);
|
|
4286
|
+
}
|
|
4287
|
+
async listMcpServers() {
|
|
4288
|
+
return this._sessionRpc(
|
|
4289
|
+
"daemon.list_mcp_servers" /* LIST_MCP_SERVERS */,
|
|
4290
|
+
{},
|
|
4291
|
+
ListMcpServersResultSchema
|
|
4292
|
+
);
|
|
4293
|
+
}
|
|
4294
|
+
async listMcpTools() {
|
|
4295
|
+
return this._sessionRpc(
|
|
4296
|
+
"daemon.list_mcp_tools" /* LIST_MCP_TOOLS */,
|
|
4297
|
+
{},
|
|
4298
|
+
ListMcpToolsResultSchema
|
|
4299
|
+
);
|
|
4300
|
+
}
|
|
4301
|
+
async authenticateMcpServer(params) {
|
|
4302
|
+
return this._sessionRpc(
|
|
4303
|
+
"daemon.authenticate_mcp_server" /* AUTHENTICATE_MCP_SERVER */,
|
|
4304
|
+
params,
|
|
4305
|
+
AuthenticateMcpServerResultSchema
|
|
4306
|
+
);
|
|
4307
|
+
}
|
|
4308
|
+
async listSkills() {
|
|
4309
|
+
return this._sessionRpc(
|
|
4310
|
+
"daemon.list_skills" /* LIST_SKILLS */,
|
|
4311
|
+
{},
|
|
4312
|
+
ListSkillsResultSchema
|
|
4313
|
+
);
|
|
4314
|
+
}
|
|
4315
|
+
onNotification(callback, filter) {
|
|
4316
|
+
const entry = { callback, filter };
|
|
4317
|
+
this._notificationListeners.push(entry);
|
|
4318
|
+
let unsubscribed = false;
|
|
4319
|
+
return () => {
|
|
4320
|
+
if (!unsubscribed) {
|
|
4321
|
+
unsubscribed = true;
|
|
4322
|
+
const idx = this._notificationListeners.indexOf(entry);
|
|
4323
|
+
if (idx !== -1) {
|
|
4324
|
+
this._notificationListeners.splice(idx, 1);
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
};
|
|
4328
|
+
}
|
|
4329
|
+
setPermissionHandler(handler) {
|
|
4330
|
+
this._permissionHandler = handler;
|
|
4331
|
+
}
|
|
4332
|
+
setAskUserHandler(handler) {
|
|
4333
|
+
this._askUserHandler = handler;
|
|
4334
|
+
}
|
|
4335
|
+
async close() {
|
|
4336
|
+
if (this._closed) {
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
this._closed = true;
|
|
4340
|
+
this._notificationListeners.length = 0;
|
|
4341
|
+
this._permissionHandler = null;
|
|
4342
|
+
this._askUserHandler = null;
|
|
4343
|
+
await this._engine.close();
|
|
4344
|
+
}
|
|
4345
|
+
async _rpc(method, params, schema, timeout) {
|
|
4346
|
+
const raw = await this._engine.sendRequest(method, params, timeout);
|
|
4347
|
+
return schema.parse(raw);
|
|
4348
|
+
}
|
|
4349
|
+
async _sessionRpc(method, params, schema, timeout) {
|
|
4350
|
+
this._ensureNotClosed();
|
|
4351
|
+
this._ensureSession();
|
|
4352
|
+
return this._rpc(
|
|
4353
|
+
method,
|
|
4354
|
+
{ sessionId: this._sessionId, ...params },
|
|
4355
|
+
schema,
|
|
4356
|
+
timeout
|
|
4357
|
+
);
|
|
4358
|
+
}
|
|
4359
|
+
_dispatchPermissionRequest(params) {
|
|
4360
|
+
const handler = this._permissionHandler;
|
|
4361
|
+
if (handler == null) {
|
|
4362
|
+
return "cancel" /* Cancel */;
|
|
4363
|
+
}
|
|
4364
|
+
return handler(params);
|
|
4365
|
+
}
|
|
4366
|
+
_dispatchAskUserRequest(params) {
|
|
4367
|
+
const handler = this._askUserHandler;
|
|
4368
|
+
if (handler == null) {
|
|
4369
|
+
return { cancelled: true, answers: [] };
|
|
4370
|
+
}
|
|
4371
|
+
return handler(params);
|
|
4372
|
+
}
|
|
4373
|
+
_ensureNotClosed() {
|
|
4374
|
+
if (this._closed) {
|
|
4375
|
+
throw new ConnectionError(
|
|
4376
|
+
"Daemon client has been closed. Create a new DaemonClient instance."
|
|
4377
|
+
);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
_ensureSession() {
|
|
4381
|
+
if (this._sessionId == null) {
|
|
4382
|
+
throw new SessionError(
|
|
4383
|
+
"No active session. Call initializeSession or loadSession first."
|
|
4384
|
+
);
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
};
|
|
4388
|
+
|
|
4389
|
+
// src/daemon/local.ts
|
|
4390
|
+
import { spawn as spawn2 } from "child_process";
|
|
4391
|
+
import * as fs2 from "fs";
|
|
4392
|
+
import * as net from "net";
|
|
4393
|
+
import * as os2 from "os";
|
|
4394
|
+
import * as path2 from "path";
|
|
4395
|
+
var SOCKET_TIMEOUT_MS = 2e3;
|
|
4396
|
+
var STARTUP_POLL_INTERVAL_MS = 250;
|
|
4397
|
+
var STARTUP_TIMEOUT_MS = 3e4;
|
|
4398
|
+
var MAX_STARTUP_ATTEMPTS = 3;
|
|
4399
|
+
var FACTORY_DIR = ".factory";
|
|
4400
|
+
var DEFAULT_PORT = 37643;
|
|
4401
|
+
var DAEMON_PORT_FILE = "daemon.port";
|
|
4402
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
4403
|
+
var spawnedDaemonProcess = null;
|
|
4404
|
+
var daemonTarget = null;
|
|
4405
|
+
var daemonEnsureInflight = null;
|
|
4406
|
+
function getFactoryHome() {
|
|
4407
|
+
return process.env.FACTORY_HOME_OVERRIDE || os2.homedir();
|
|
4408
|
+
}
|
|
4409
|
+
function getFactoryDirName() {
|
|
4410
|
+
return FACTORY_DIR;
|
|
4411
|
+
}
|
|
4412
|
+
function getFactoryDir() {
|
|
4413
|
+
return path2.join(getFactoryHome(), getFactoryDirName());
|
|
4414
|
+
}
|
|
4415
|
+
function getSdkDir() {
|
|
4416
|
+
return path2.join(getFactoryDir(), "sdk");
|
|
4417
|
+
}
|
|
4418
|
+
function getDefaultDaemonPort() {
|
|
4419
|
+
return DEFAULT_PORT;
|
|
4420
|
+
}
|
|
4421
|
+
function resolveExecPath() {
|
|
4422
|
+
const override = process.env.FACTORY_DROID_BINARY?.trim();
|
|
4423
|
+
if (override && override.length > 0) {
|
|
4424
|
+
if (override.includes("/") || override.includes("\\")) {
|
|
4425
|
+
try {
|
|
4426
|
+
fs2.accessSync(override, fs2.constants.X_OK);
|
|
4427
|
+
return override;
|
|
4428
|
+
} catch {
|
|
4429
|
+
}
|
|
4430
|
+
} else {
|
|
4431
|
+
return override;
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
return "droid";
|
|
4435
|
+
}
|
|
4436
|
+
async function allocatePort() {
|
|
4437
|
+
return new Promise((resolve2, reject) => {
|
|
4438
|
+
const server = net.createServer();
|
|
4439
|
+
server.once("error", reject);
|
|
4440
|
+
server.listen(0, DEFAULT_HOST, () => {
|
|
4441
|
+
const address = server.address();
|
|
4442
|
+
if (!address || typeof address === "string") {
|
|
4443
|
+
server.close();
|
|
4444
|
+
reject(new Error("Failed to determine dynamic port"));
|
|
4445
|
+
return;
|
|
4446
|
+
}
|
|
4447
|
+
const port = address.port;
|
|
4448
|
+
server.close((err) => {
|
|
4449
|
+
if (err) reject(err);
|
|
4450
|
+
else resolve2(port);
|
|
4451
|
+
});
|
|
4452
|
+
});
|
|
4453
|
+
});
|
|
4454
|
+
}
|
|
4455
|
+
async function isDaemonReachable(port) {
|
|
4456
|
+
return new Promise((resolve2) => {
|
|
4457
|
+
const socket = net.createConnection({ host: DEFAULT_HOST, port });
|
|
4458
|
+
const cleanup = () => {
|
|
4459
|
+
socket.removeAllListeners();
|
|
4460
|
+
socket.destroy();
|
|
4461
|
+
};
|
|
4462
|
+
const fail = () => {
|
|
4463
|
+
cleanup();
|
|
4464
|
+
resolve2(false);
|
|
4465
|
+
};
|
|
4466
|
+
socket.setTimeout(SOCKET_TIMEOUT_MS, fail);
|
|
4467
|
+
socket.once("error", fail);
|
|
4468
|
+
socket.once("connect", () => {
|
|
4469
|
+
cleanup();
|
|
4470
|
+
resolve2(true);
|
|
4471
|
+
});
|
|
4472
|
+
});
|
|
4473
|
+
}
|
|
4474
|
+
async function waitForDaemonReady(child, port, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
4475
|
+
return new Promise((resolve2) => {
|
|
4476
|
+
let settled = false;
|
|
4477
|
+
let exited = false;
|
|
4478
|
+
const deadline = Date.now() + timeoutMs;
|
|
4479
|
+
const settle = (result) => {
|
|
4480
|
+
if (settled) return;
|
|
4481
|
+
settled = true;
|
|
4482
|
+
child.removeListener("exit", onExit);
|
|
4483
|
+
child.removeListener("error", onExit);
|
|
4484
|
+
resolve2(result);
|
|
4485
|
+
};
|
|
4486
|
+
const onExit = () => {
|
|
4487
|
+
exited = true;
|
|
4488
|
+
settle("exited");
|
|
4489
|
+
};
|
|
4490
|
+
child.once("exit", onExit);
|
|
4491
|
+
child.once("error", onExit);
|
|
4492
|
+
const poll = async () => {
|
|
4493
|
+
while (!exited && !settled) {
|
|
4494
|
+
if (await isDaemonReachable(port)) {
|
|
4495
|
+
settle("ready");
|
|
4496
|
+
return;
|
|
4497
|
+
}
|
|
4498
|
+
if (Date.now() >= deadline) {
|
|
4499
|
+
settle("timeout");
|
|
4500
|
+
return;
|
|
4501
|
+
}
|
|
4502
|
+
await new Promise((r) => setTimeout(r, STARTUP_POLL_INTERVAL_MS));
|
|
4503
|
+
}
|
|
4504
|
+
};
|
|
4505
|
+
void poll();
|
|
4506
|
+
});
|
|
4507
|
+
}
|
|
4508
|
+
function readPortFile() {
|
|
4509
|
+
try {
|
|
4510
|
+
const portPath = path2.join(getSdkDir(), DAEMON_PORT_FILE);
|
|
4511
|
+
const content = fs2.readFileSync(portPath, "utf-8").trim();
|
|
4512
|
+
const port = parseInt(content, 10);
|
|
4513
|
+
if (Number.isFinite(port) && port > 0 && port < 65536) {
|
|
4514
|
+
return port;
|
|
4515
|
+
}
|
|
4516
|
+
return null;
|
|
4517
|
+
} catch {
|
|
4518
|
+
return null;
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
function writePortFile(port) {
|
|
4522
|
+
try {
|
|
4523
|
+
const sdkDir = getSdkDir();
|
|
4524
|
+
fs2.mkdirSync(sdkDir, { recursive: true });
|
|
4525
|
+
fs2.writeFileSync(path2.join(sdkDir, DAEMON_PORT_FILE), String(port), {
|
|
4526
|
+
mode: 384
|
|
4527
|
+
});
|
|
4528
|
+
} catch {
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
function cacheTarget(port) {
|
|
4532
|
+
daemonTarget = { host: DEFAULT_HOST, port };
|
|
4533
|
+
return { port };
|
|
4534
|
+
}
|
|
4535
|
+
function clearSpawnedDaemonProcess(child) {
|
|
4536
|
+
if (spawnedDaemonProcess === child) {
|
|
4537
|
+
spawnedDaemonProcess = null;
|
|
4538
|
+
}
|
|
4539
|
+
}
|
|
4540
|
+
async function spawnDaemon(execPath, port) {
|
|
4541
|
+
const args = ["daemon", "--host", DEFAULT_HOST, "--port", String(port)];
|
|
4542
|
+
let stderrFd;
|
|
4543
|
+
try {
|
|
4544
|
+
const logsDir = path2.join(getSdkDir(), "logs");
|
|
4545
|
+
fs2.mkdirSync(logsDir, { recursive: true });
|
|
4546
|
+
stderrFd = fs2.openSync(path2.join(logsDir, "daemon-stderr.log"), "a");
|
|
4547
|
+
} catch {
|
|
4548
|
+
}
|
|
4549
|
+
const child = spawn2(execPath, args, {
|
|
4550
|
+
detached: true,
|
|
4551
|
+
stdio: ["ignore", "ignore", stderrFd ?? "ignore"],
|
|
4552
|
+
cwd: os2.homedir(),
|
|
4553
|
+
env: { ...process.env }
|
|
4554
|
+
});
|
|
4555
|
+
if (stderrFd !== void 0) {
|
|
4556
|
+
try {
|
|
4557
|
+
fs2.closeSync(stderrFd);
|
|
4558
|
+
} catch {
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
spawnedDaemonProcess = child;
|
|
4562
|
+
child.unref();
|
|
4563
|
+
child.once("exit", () => {
|
|
4564
|
+
clearSpawnedDaemonProcess(child);
|
|
4565
|
+
});
|
|
4566
|
+
child.on("error", () => {
|
|
4567
|
+
clearSpawnedDaemonProcess(child);
|
|
4568
|
+
});
|
|
4569
|
+
const result = await waitForDaemonReady(child, port);
|
|
4570
|
+
if (result !== "ready") {
|
|
4571
|
+
clearSpawnedDaemonProcess(child);
|
|
4572
|
+
if (result === "timeout") {
|
|
4573
|
+
try {
|
|
4574
|
+
child.kill("SIGTERM");
|
|
4575
|
+
} catch {
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
return result;
|
|
4580
|
+
}
|
|
4581
|
+
async function _ensureLocalDaemon() {
|
|
4582
|
+
const execPath = resolveExecPath();
|
|
4583
|
+
const wellKnownPort = getDefaultDaemonPort();
|
|
4584
|
+
if (await isDaemonReachable(wellKnownPort)) {
|
|
4585
|
+
return cacheTarget(wellKnownPort);
|
|
4586
|
+
}
|
|
4587
|
+
const portFilePort = readPortFile();
|
|
4588
|
+
if (portFilePort !== null && portFilePort !== wellKnownPort) {
|
|
4589
|
+
if (await isDaemonReachable(portFilePort)) {
|
|
4590
|
+
return cacheTarget(portFilePort);
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
const firstResult = await spawnDaemon(execPath, wellKnownPort);
|
|
4594
|
+
if (firstResult === "ready") {
|
|
4595
|
+
writePortFile(wellKnownPort);
|
|
4596
|
+
return cacheTarget(wellKnownPort);
|
|
4597
|
+
}
|
|
4598
|
+
for (let attempt = 2; attempt <= MAX_STARTUP_ATTEMPTS; attempt++) {
|
|
4599
|
+
const port = await allocatePort();
|
|
4600
|
+
const result = await spawnDaemon(execPath, port);
|
|
4601
|
+
if (result === "ready") {
|
|
4602
|
+
writePortFile(port);
|
|
4603
|
+
return cacheTarget(port);
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
throw new ConnectionError(
|
|
4607
|
+
`Failed to start local droid daemon after ${MAX_STARTUP_ATTEMPTS} attempts. Ensure the \`droid\` CLI is installed and \`droid auth login\` has been run.`
|
|
4608
|
+
);
|
|
4609
|
+
}
|
|
4610
|
+
async function ensureLocalDaemon() {
|
|
4611
|
+
if (daemonTarget) {
|
|
4612
|
+
if (await isDaemonReachable(daemonTarget.port)) {
|
|
4613
|
+
return { port: daemonTarget.port };
|
|
4614
|
+
}
|
|
4615
|
+
daemonTarget = null;
|
|
4616
|
+
}
|
|
4617
|
+
if (!daemonEnsureInflight) {
|
|
4618
|
+
daemonEnsureInflight = _ensureLocalDaemon().finally(() => {
|
|
4619
|
+
daemonEnsureInflight = null;
|
|
4620
|
+
});
|
|
4621
|
+
}
|
|
4622
|
+
return daemonEnsureInflight;
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4625
|
+
// src/daemon/session.ts
|
|
4626
|
+
var DaemonSession = class {
|
|
4627
|
+
_client;
|
|
4628
|
+
_sessionId;
|
|
4629
|
+
_closed = false;
|
|
4630
|
+
_activeBridges = /* @__PURE__ */ new Set();
|
|
4631
|
+
_cleanupCallbacks = [];
|
|
4632
|
+
/** @internal */
|
|
4633
|
+
constructor(client, sessionId) {
|
|
4634
|
+
this._client = client;
|
|
4635
|
+
this._sessionId = sessionId;
|
|
4636
|
+
}
|
|
4637
|
+
/** @internal */
|
|
4638
|
+
addCleanup(cleanup) {
|
|
4639
|
+
this._cleanupCallbacks.push(cleanup);
|
|
4640
|
+
}
|
|
4641
|
+
get sessionId() {
|
|
4642
|
+
return this._sessionId;
|
|
4643
|
+
}
|
|
4644
|
+
async *stream(prompt, options) {
|
|
4645
|
+
this._ensureNotClosed();
|
|
4646
|
+
yield* streamFromClient(
|
|
4647
|
+
this._client,
|
|
4648
|
+
this._sessionId,
|
|
4649
|
+
this._activeBridges,
|
|
4650
|
+
prompt,
|
|
4651
|
+
options
|
|
4652
|
+
);
|
|
4653
|
+
}
|
|
4654
|
+
async send(prompt, options) {
|
|
4655
|
+
this._ensureNotClosed();
|
|
4656
|
+
await this._client.addUserMessage({
|
|
4657
|
+
text: prompt,
|
|
4658
|
+
images: options?.images,
|
|
4659
|
+
files: options?.files,
|
|
4660
|
+
outputFormat: options?.outputFormat
|
|
4661
|
+
});
|
|
4662
|
+
}
|
|
4663
|
+
async interrupt() {
|
|
4664
|
+
this._ensureNotClosed();
|
|
4665
|
+
await this._client.interruptSession();
|
|
4666
|
+
}
|
|
4667
|
+
async close() {
|
|
4668
|
+
if (this._closed) {
|
|
4669
|
+
return;
|
|
4670
|
+
}
|
|
4671
|
+
this._closed = true;
|
|
4672
|
+
for (const bridge of this._activeBridges) {
|
|
4673
|
+
bridge.signalDone();
|
|
4674
|
+
}
|
|
4675
|
+
try {
|
|
4676
|
+
await this._client.closeSession({ reason: "other" }).catch(() => {
|
|
4677
|
+
});
|
|
4678
|
+
} finally {
|
|
4679
|
+
await this._client.close();
|
|
4680
|
+
for (const cleanup of this._cleanupCallbacks) {
|
|
4681
|
+
try {
|
|
4682
|
+
await cleanup();
|
|
4683
|
+
} catch {
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
this._cleanupCallbacks.length = 0;
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
async updateSettings(params) {
|
|
4690
|
+
this._ensureNotClosed();
|
|
4691
|
+
return this._client.updateSessionSettings(params);
|
|
4692
|
+
}
|
|
4693
|
+
async enterSpecMode(params = {}) {
|
|
4694
|
+
this._ensureNotClosed();
|
|
4695
|
+
return this._client.updateSessionSettings({
|
|
4696
|
+
interactionMode: "spec" /* Spec */,
|
|
4697
|
+
...params
|
|
4698
|
+
});
|
|
4699
|
+
}
|
|
4700
|
+
async compactSession(params) {
|
|
4701
|
+
this._ensureNotClosed();
|
|
4702
|
+
return this._client.compactSession(params ?? {});
|
|
4703
|
+
}
|
|
4704
|
+
async forkSession() {
|
|
4705
|
+
this._ensureNotClosed();
|
|
4706
|
+
return this._client.forkSession();
|
|
4707
|
+
}
|
|
4708
|
+
async getContextBreakdown() {
|
|
4709
|
+
this._ensureNotClosed();
|
|
4710
|
+
return this._client.getContextBreakdown();
|
|
4711
|
+
}
|
|
4712
|
+
async renameSession(params) {
|
|
4713
|
+
this._ensureNotClosed();
|
|
4714
|
+
return this._client.renameSession(params);
|
|
4715
|
+
}
|
|
4716
|
+
async getRewindInfo(params) {
|
|
4717
|
+
this._ensureNotClosed();
|
|
4718
|
+
return this._client.getRewindInfo(params);
|
|
4719
|
+
}
|
|
4720
|
+
async executeRewind(params) {
|
|
4721
|
+
this._ensureNotClosed();
|
|
4722
|
+
return this._client.executeRewind(params);
|
|
4723
|
+
}
|
|
4724
|
+
async addMcpServer(params) {
|
|
4725
|
+
this._ensureNotClosed();
|
|
4726
|
+
return this._client.addMcpServer(params);
|
|
4727
|
+
}
|
|
4728
|
+
async removeMcpServer(params) {
|
|
4729
|
+
this._ensureNotClosed();
|
|
4730
|
+
return this._client.removeMcpServer(params);
|
|
4731
|
+
}
|
|
4732
|
+
async toggleMcpServer(params) {
|
|
4733
|
+
this._ensureNotClosed();
|
|
4734
|
+
return this._client.toggleMcpServer(params);
|
|
4735
|
+
}
|
|
4736
|
+
async listMcpServers() {
|
|
4737
|
+
this._ensureNotClosed();
|
|
4738
|
+
return this._client.listMcpServers();
|
|
4739
|
+
}
|
|
4740
|
+
async listMcpTools() {
|
|
4741
|
+
this._ensureNotClosed();
|
|
4742
|
+
return this._client.listMcpTools();
|
|
4743
|
+
}
|
|
4744
|
+
async authenticateMcpServer(params) {
|
|
4745
|
+
this._ensureNotClosed();
|
|
4746
|
+
return this._client.authenticateMcpServer(params);
|
|
4747
|
+
}
|
|
4748
|
+
async listSkills() {
|
|
4749
|
+
this._ensureNotClosed();
|
|
4750
|
+
return this._client.listSkills();
|
|
4751
|
+
}
|
|
4752
|
+
onNotification(callback, filter) {
|
|
4753
|
+
return this._client.onNotification(callback, filter);
|
|
4754
|
+
}
|
|
4755
|
+
_ensureNotClosed() {
|
|
4756
|
+
if (this._closed) {
|
|
4757
|
+
throw new ConnectionError(
|
|
4758
|
+
"Daemon session has been closed. Create a new session to continue."
|
|
4759
|
+
);
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
};
|
|
4763
|
+
|
|
4764
|
+
// src/daemon/transport.ts
|
|
4765
|
+
import WebSocket from "ws";
|
|
4766
|
+
|
|
4767
|
+
// src/daemon/types.ts
|
|
4768
|
+
var MachineType = /* @__PURE__ */ ((MachineType2) => {
|
|
4769
|
+
MachineType2["Local"] = "local";
|
|
4770
|
+
MachineType2["Computer"] = "computer";
|
|
4771
|
+
return MachineType2;
|
|
4772
|
+
})(MachineType || {});
|
|
4773
|
+
var DEFAULT_DAEMON_PORT = 37643;
|
|
4774
|
+
var DEFAULT_RELAY_BASE_URL = "wss://relay.factory.ai";
|
|
4775
|
+
var DEFAULT_WS_CONFIG = {
|
|
4776
|
+
maxConnectRetries: 5,
|
|
4777
|
+
initialRetryDelayMs: 500,
|
|
4778
|
+
maxRetryDelayMs: 5e3,
|
|
4779
|
+
connectionTimeoutMs: 5e3
|
|
4780
|
+
};
|
|
4781
|
+
var COMPUTER_WS_CONFIG = {
|
|
4782
|
+
connectionTimeoutMs: 45e3,
|
|
4783
|
+
maxConnectRetries: 10,
|
|
4784
|
+
initialRetryDelayMs: 2e3,
|
|
4785
|
+
maxRetryDelayMs: 1e4
|
|
4786
|
+
};
|
|
4787
|
+
|
|
4788
|
+
// src/daemon/transport.ts
|
|
4789
|
+
var WebSocketTransport = class {
|
|
4790
|
+
maxConnectRetries;
|
|
4791
|
+
initialRetryDelayMs;
|
|
4792
|
+
maxRetryDelayMs;
|
|
4793
|
+
connectionTimeoutMs;
|
|
4794
|
+
ws = null;
|
|
4795
|
+
messageHandler = null;
|
|
4796
|
+
errorHandler = null;
|
|
4797
|
+
_isConnected = false;
|
|
4798
|
+
isClosing = false;
|
|
4799
|
+
constructor(options = {}) {
|
|
4800
|
+
this.maxConnectRetries = options.maxConnectRetries ?? DEFAULT_WS_CONFIG.maxConnectRetries;
|
|
4801
|
+
this.initialRetryDelayMs = options.initialRetryDelayMs ?? DEFAULT_WS_CONFIG.initialRetryDelayMs;
|
|
4802
|
+
this.maxRetryDelayMs = options.maxRetryDelayMs ?? DEFAULT_WS_CONFIG.maxRetryDelayMs;
|
|
4803
|
+
this.connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_WS_CONFIG.connectionTimeoutMs;
|
|
4804
|
+
}
|
|
4805
|
+
get isConnected() {
|
|
4806
|
+
return this._isConnected;
|
|
4807
|
+
}
|
|
4808
|
+
async connect(url) {
|
|
4809
|
+
if (!url) {
|
|
4810
|
+
throw new ConnectionError("WebSocket URL is required");
|
|
4811
|
+
}
|
|
4812
|
+
if (this._isConnected) {
|
|
4813
|
+
throw new ConnectionError("Transport already connected");
|
|
4814
|
+
}
|
|
4815
|
+
this.isClosing = false;
|
|
4816
|
+
let lastError;
|
|
4817
|
+
for (let attempt = 0; attempt <= this.maxConnectRetries; attempt++) {
|
|
4818
|
+
try {
|
|
4819
|
+
await this._doConnect(url);
|
|
4820
|
+
return;
|
|
4821
|
+
} catch (error) {
|
|
4822
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
4823
|
+
if (attempt < this.maxConnectRetries) {
|
|
4824
|
+
const delay = Math.min(
|
|
4825
|
+
this.initialRetryDelayMs * 2 ** attempt,
|
|
4826
|
+
this.maxRetryDelayMs
|
|
4827
|
+
);
|
|
4828
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4832
|
+
throw lastError;
|
|
4833
|
+
}
|
|
4834
|
+
send(message) {
|
|
4835
|
+
if (!this._isConnected || !this.ws) {
|
|
4836
|
+
throw new ConnectionError("WebSocket transport not connected");
|
|
4837
|
+
}
|
|
4838
|
+
try {
|
|
4839
|
+
this.ws.send(JSON.stringify(message));
|
|
4840
|
+
} catch (error) {
|
|
4841
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
4842
|
+
throw new ConnectionError(`Failed to send WebSocket message: ${msg}`);
|
|
4843
|
+
}
|
|
4844
|
+
}
|
|
4845
|
+
onMessage(callback) {
|
|
4846
|
+
this.messageHandler = callback;
|
|
4847
|
+
}
|
|
4848
|
+
onError(callback) {
|
|
4849
|
+
this.errorHandler = callback;
|
|
4850
|
+
}
|
|
4851
|
+
async close() {
|
|
4852
|
+
if (this.isClosing) {
|
|
4853
|
+
return;
|
|
4854
|
+
}
|
|
4855
|
+
this.isClosing = true;
|
|
4856
|
+
this._isConnected = false;
|
|
4857
|
+
const ws = this.ws;
|
|
4858
|
+
this.ws = null;
|
|
4859
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
4860
|
+
await new Promise((resolve2) => {
|
|
4861
|
+
ws.once("close", () => resolve2());
|
|
4862
|
+
ws.close(1e3, "Client disconnect");
|
|
4863
|
+
setTimeout(() => resolve2(), 5e3);
|
|
4864
|
+
});
|
|
4865
|
+
}
|
|
4866
|
+
this.isClosing = false;
|
|
4867
|
+
}
|
|
4868
|
+
async _doConnect(url) {
|
|
4869
|
+
return new Promise((resolve2, reject) => {
|
|
4870
|
+
let settled = false;
|
|
4871
|
+
let timeoutId = null;
|
|
4872
|
+
const cleanup = () => {
|
|
4873
|
+
if (timeoutId) {
|
|
4874
|
+
clearTimeout(timeoutId);
|
|
4875
|
+
timeoutId = null;
|
|
4876
|
+
}
|
|
4877
|
+
};
|
|
4878
|
+
const ws = new WebSocket(url);
|
|
4879
|
+
const handleOpen = () => {
|
|
4880
|
+
if (settled) return;
|
|
4881
|
+
settled = true;
|
|
4882
|
+
cleanup();
|
|
4883
|
+
this.ws = ws;
|
|
4884
|
+
this._isConnected = true;
|
|
4885
|
+
this._setupOngoingHandlers(ws);
|
|
4886
|
+
resolve2();
|
|
4887
|
+
};
|
|
4888
|
+
const handleError = (error) => {
|
|
4889
|
+
if (settled) return;
|
|
4890
|
+
settled = true;
|
|
4891
|
+
cleanup();
|
|
4892
|
+
try {
|
|
4893
|
+
ws.close();
|
|
4894
|
+
} catch {
|
|
4895
|
+
}
|
|
4896
|
+
reject(
|
|
4897
|
+
new ConnectionError(`WebSocket connection failed: ${error.message}`)
|
|
4898
|
+
);
|
|
4899
|
+
};
|
|
4900
|
+
const handleClose = (code, reason) => {
|
|
4901
|
+
if (settled) return;
|
|
4902
|
+
settled = true;
|
|
4903
|
+
cleanup();
|
|
4904
|
+
reject(
|
|
4905
|
+
new ConnectionError(
|
|
4906
|
+
`WebSocket closed before opening (code: ${code}, reason: ${reason.toString()})`
|
|
4907
|
+
)
|
|
4908
|
+
);
|
|
4909
|
+
};
|
|
4910
|
+
ws.once("open", handleOpen);
|
|
4911
|
+
ws.once("error", handleError);
|
|
4912
|
+
ws.once("close", handleClose);
|
|
4913
|
+
timeoutId = setTimeout(() => {
|
|
4914
|
+
if (settled) return;
|
|
4915
|
+
settled = true;
|
|
4916
|
+
try {
|
|
4917
|
+
ws.close();
|
|
4918
|
+
} catch {
|
|
4919
|
+
}
|
|
4920
|
+
reject(
|
|
4921
|
+
new ConnectionError(
|
|
4922
|
+
`WebSocket connection timeout after ${this.connectionTimeoutMs}ms: ${url}`
|
|
4923
|
+
)
|
|
4924
|
+
);
|
|
4925
|
+
}, this.connectionTimeoutMs);
|
|
4926
|
+
});
|
|
4927
|
+
}
|
|
4928
|
+
_setupOngoingHandlers(ws) {
|
|
4929
|
+
ws.on("message", (data) => {
|
|
4930
|
+
if (!this.messageHandler) return;
|
|
4931
|
+
const text = typeof data === "string" ? data : data.toString();
|
|
4932
|
+
try {
|
|
4933
|
+
const parsed = JSON.parse(text);
|
|
4934
|
+
if (isRecord(parsed)) {
|
|
4935
|
+
this.messageHandler(parsed);
|
|
4936
|
+
}
|
|
4937
|
+
} catch {
|
|
4938
|
+
}
|
|
4939
|
+
});
|
|
4940
|
+
ws.on("error", (error) => {
|
|
4941
|
+
if (!this.isClosing && this.errorHandler) {
|
|
4942
|
+
this.errorHandler(
|
|
4943
|
+
new ConnectionError(`WebSocket error: ${error.message}`)
|
|
4944
|
+
);
|
|
4945
|
+
}
|
|
4946
|
+
});
|
|
4947
|
+
ws.on("close", (code, reason) => {
|
|
4948
|
+
this._isConnected = false;
|
|
4949
|
+
this.ws = null;
|
|
4950
|
+
if (!this.isClosing && this.errorHandler) {
|
|
4951
|
+
this.errorHandler(
|
|
4952
|
+
new ConnectionError(
|
|
4953
|
+
`WebSocket closed (code: ${code}, reason: ${reason.toString()})`
|
|
4954
|
+
)
|
|
4955
|
+
);
|
|
4956
|
+
}
|
|
4957
|
+
});
|
|
4958
|
+
}
|
|
4959
|
+
};
|
|
4960
|
+
|
|
4961
|
+
// src/daemon/connection.ts
|
|
4962
|
+
var DAEMON_AUTHENTICATE_METHOD = "daemon.authenticate";
|
|
4963
|
+
var DAEMON_AUTHENTICATE_TIMEOUT = 3e4;
|
|
4964
|
+
var SDK_CALLER = "droid-sdk";
|
|
4965
|
+
function resolveWebSocketUrl(options) {
|
|
4966
|
+
if (options.url) {
|
|
4967
|
+
return options.url;
|
|
4968
|
+
}
|
|
4969
|
+
const machine = options.machine;
|
|
4970
|
+
if (!machine || machine.type === "local" /* Local */) {
|
|
4971
|
+
const port = options._localPort ?? options.daemonPort ?? DEFAULT_DAEMON_PORT;
|
|
4972
|
+
return `ws://127.0.0.1:${port}`;
|
|
4973
|
+
}
|
|
4974
|
+
if (machine.type === "computer" /* Computer */) {
|
|
4975
|
+
const relayBase = options.relayBaseUrl ?? DEFAULT_RELAY_BASE_URL;
|
|
4976
|
+
return `${relayBase}/v0/computer/${machine.computerId}/client`;
|
|
4977
|
+
}
|
|
4978
|
+
const _exhaustive = machine;
|
|
4979
|
+
throw new ConnectionError(`Unsupported machine type: ${String(_exhaustive)}`);
|
|
4980
|
+
}
|
|
4981
|
+
function getWebSocketConfig(machine) {
|
|
4982
|
+
if (machine?.type === "computer" /* Computer */) {
|
|
4983
|
+
return { ...DEFAULT_WS_CONFIG, ...COMPUTER_WS_CONFIG };
|
|
4984
|
+
}
|
|
4985
|
+
if (!machine || machine.type === "local" /* Local */) {
|
|
4986
|
+
return { ...DEFAULT_WS_CONFIG, connectionTimeoutMs: 1e4 };
|
|
4987
|
+
}
|
|
4988
|
+
return { ...DEFAULT_WS_CONFIG };
|
|
4989
|
+
}
|
|
4990
|
+
var SharedTransportMultiplexer = class {
|
|
4991
|
+
constructor(_inner) {
|
|
4992
|
+
this._inner = _inner;
|
|
4993
|
+
this._inner.onMessage((message) => {
|
|
4994
|
+
this._routeMessage(message);
|
|
4995
|
+
});
|
|
4996
|
+
this._inner.onError((error) => {
|
|
4997
|
+
for (const view of this._views) {
|
|
4998
|
+
if (view.errorCallback) {
|
|
4999
|
+
try {
|
|
5000
|
+
view.errorCallback(error);
|
|
5001
|
+
} catch {
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
});
|
|
5006
|
+
}
|
|
5007
|
+
_views = /* @__PURE__ */ new Set();
|
|
5008
|
+
createView() {
|
|
5009
|
+
const inner = this._inner;
|
|
5010
|
+
const viewState = {
|
|
5011
|
+
messageCallback: null,
|
|
5012
|
+
errorCallback: null,
|
|
5013
|
+
pendingRequestIds: /* @__PURE__ */ new Set(),
|
|
5014
|
+
sessionId: null
|
|
5015
|
+
};
|
|
5016
|
+
this._views.add(viewState);
|
|
5017
|
+
const view = {
|
|
5018
|
+
send: (message) => {
|
|
5019
|
+
if (message["type"] === "request" && typeof message["id"] === "string") {
|
|
5020
|
+
viewState.pendingRequestIds.add(message["id"]);
|
|
5021
|
+
}
|
|
5022
|
+
inner.send(message);
|
|
5023
|
+
},
|
|
5024
|
+
onMessage: (callback) => {
|
|
5025
|
+
viewState.messageCallback = callback;
|
|
5026
|
+
},
|
|
5027
|
+
onError: (callback) => {
|
|
5028
|
+
viewState.errorCallback = callback;
|
|
5029
|
+
},
|
|
5030
|
+
close: async () => {
|
|
5031
|
+
viewState.messageCallback = null;
|
|
5032
|
+
viewState.errorCallback = null;
|
|
5033
|
+
viewState.pendingRequestIds.clear();
|
|
5034
|
+
this._views.delete(viewState);
|
|
5035
|
+
},
|
|
5036
|
+
get isConnected() {
|
|
5037
|
+
return inner.isConnected;
|
|
5038
|
+
}
|
|
5039
|
+
};
|
|
5040
|
+
return view;
|
|
5041
|
+
}
|
|
5042
|
+
_routeMessage(message) {
|
|
5043
|
+
const messageType = message["type"];
|
|
5044
|
+
const messageId = message["id"];
|
|
5045
|
+
if (messageType === "response" && typeof messageId === "string") {
|
|
5046
|
+
for (const view of this._views) {
|
|
5047
|
+
if (view.pendingRequestIds.has(messageId)) {
|
|
5048
|
+
view.pendingRequestIds.delete(messageId);
|
|
5049
|
+
const result = message["result"];
|
|
5050
|
+
if (isRecord(result) && typeof result["sessionId"] === "string") {
|
|
5051
|
+
view.sessionId = result["sessionId"];
|
|
5052
|
+
}
|
|
5053
|
+
if (view.messageCallback) {
|
|
5054
|
+
try {
|
|
5055
|
+
view.messageCallback(message);
|
|
5056
|
+
} catch {
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
return;
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
return;
|
|
5063
|
+
}
|
|
5064
|
+
if (messageType === "notification") {
|
|
5065
|
+
const params = message["params"];
|
|
5066
|
+
const sessionId = isRecord(params) && typeof params["sessionId"] === "string" ? params["sessionId"] : null;
|
|
5067
|
+
if (sessionId) {
|
|
5068
|
+
for (const view of this._views) {
|
|
5069
|
+
if (view.sessionId === sessionId && view.messageCallback) {
|
|
5070
|
+
try {
|
|
5071
|
+
view.messageCallback(message);
|
|
5072
|
+
} catch {
|
|
5073
|
+
}
|
|
5074
|
+
return;
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
for (const view of this._views) {
|
|
5079
|
+
if (view.messageCallback) {
|
|
5080
|
+
try {
|
|
5081
|
+
view.messageCallback(message);
|
|
5082
|
+
} catch {
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
return;
|
|
5087
|
+
}
|
|
5088
|
+
if (messageType === "request") {
|
|
5089
|
+
const params = message["params"];
|
|
5090
|
+
const sessionId = isRecord(params) && typeof params["sessionId"] === "string" ? params["sessionId"] : null;
|
|
5091
|
+
if (sessionId) {
|
|
5092
|
+
for (const view of this._views) {
|
|
5093
|
+
if (view.sessionId === sessionId && view.messageCallback) {
|
|
5094
|
+
try {
|
|
5095
|
+
view.messageCallback(message);
|
|
5096
|
+
} catch {
|
|
5097
|
+
}
|
|
5098
|
+
return;
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
for (const view of this._views) {
|
|
5103
|
+
if (view.messageCallback) {
|
|
5104
|
+
try {
|
|
5105
|
+
view.messageCallback(message);
|
|
5106
|
+
} catch {
|
|
5107
|
+
}
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
};
|
|
5113
|
+
async function authenticate(transport, options) {
|
|
5114
|
+
const requestId = crypto.randomUUID();
|
|
5115
|
+
const envelope = {
|
|
5116
|
+
jsonrpc: JSONRPC_VERSION,
|
|
5117
|
+
factoryApiVersion: LEGACY_FACTORY_API_VERSION,
|
|
5118
|
+
factoryProtocolVersion: FACTORY_PROTOCOL_VERSION,
|
|
5119
|
+
type: "request" /* Request */,
|
|
5120
|
+
id: requestId,
|
|
5121
|
+
method: DAEMON_AUTHENTICATE_METHOD,
|
|
5122
|
+
params: {
|
|
5123
|
+
apiKey: options.apiKey,
|
|
5124
|
+
caller: SDK_CALLER
|
|
5125
|
+
}
|
|
5126
|
+
};
|
|
5127
|
+
return new Promise((resolve2, reject) => {
|
|
5128
|
+
const timer = setTimeout(() => {
|
|
5129
|
+
transport.onMessage(() => {
|
|
5130
|
+
});
|
|
5131
|
+
reject(
|
|
5132
|
+
new ConnectionError(
|
|
5133
|
+
`Daemon authentication timed out after ${DAEMON_AUTHENTICATE_TIMEOUT}ms`
|
|
5134
|
+
)
|
|
5135
|
+
);
|
|
5136
|
+
}, DAEMON_AUTHENTICATE_TIMEOUT);
|
|
5137
|
+
transport.onMessage((message) => {
|
|
5138
|
+
if (message["id"] !== requestId) {
|
|
5139
|
+
return;
|
|
5140
|
+
}
|
|
5141
|
+
clearTimeout(timer);
|
|
5142
|
+
transport.onMessage(() => {
|
|
5143
|
+
});
|
|
5144
|
+
if (message["error"]) {
|
|
5145
|
+
const error = message["error"];
|
|
5146
|
+
const errorMessage = error && typeof error === "object" && "message" in error ? String(error.message) : "unknown error";
|
|
5147
|
+
reject(
|
|
5148
|
+
new ConnectionError(`Daemon authentication failed: ${errorMessage}`)
|
|
5149
|
+
);
|
|
5150
|
+
return;
|
|
5151
|
+
}
|
|
5152
|
+
resolve2();
|
|
5153
|
+
});
|
|
5154
|
+
transport.send(envelope);
|
|
5155
|
+
});
|
|
5156
|
+
}
|
|
5157
|
+
var DaemonConnection = class {
|
|
5158
|
+
_transport;
|
|
5159
|
+
_multiplexer;
|
|
5160
|
+
_apiKey;
|
|
5161
|
+
_closed = false;
|
|
5162
|
+
/** @internal */
|
|
5163
|
+
constructor(transport, apiKey) {
|
|
5164
|
+
this._transport = transport;
|
|
5165
|
+
this._multiplexer = new SharedTransportMultiplexer(transport);
|
|
5166
|
+
this._apiKey = apiKey;
|
|
5167
|
+
}
|
|
5168
|
+
async createSession(options = {}) {
|
|
5169
|
+
this._ensureNotClosed();
|
|
5170
|
+
const view = this._multiplexer.createView();
|
|
5171
|
+
const client = new DaemonClient({
|
|
5172
|
+
transport: view,
|
|
5173
|
+
apiKey: this._apiKey
|
|
5174
|
+
});
|
|
5175
|
+
if (options.permissionHandler) {
|
|
5176
|
+
client.setPermissionHandler(options.permissionHandler);
|
|
5177
|
+
}
|
|
5178
|
+
if (options.askUserHandler) {
|
|
5179
|
+
client.setAskUserHandler(options.askUserHandler);
|
|
5180
|
+
}
|
|
5181
|
+
let sdkMcpServers;
|
|
5182
|
+
try {
|
|
5183
|
+
sdkMcpServers = await startSdkMcpServers(options.mcpServers);
|
|
5184
|
+
const initParams = buildInitParams({
|
|
5185
|
+
...options,
|
|
5186
|
+
mcpServers: sdkMcpServers.mcpServers
|
|
5187
|
+
});
|
|
5188
|
+
const initResult = await client.initializeSession(initParams);
|
|
5189
|
+
const session = new DaemonSession(client, initResult.sessionId);
|
|
5190
|
+
if (sdkMcpServers) {
|
|
5191
|
+
session.addCleanup(sdkMcpServers.cleanup);
|
|
5192
|
+
}
|
|
5193
|
+
return session;
|
|
5194
|
+
} catch (error) {
|
|
5195
|
+
await sdkMcpServers?.cleanup();
|
|
5196
|
+
await client.close();
|
|
5197
|
+
throw error;
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
async resumeSession(sessionId, options = {}) {
|
|
5201
|
+
this._ensureNotClosed();
|
|
5202
|
+
const view = this._multiplexer.createView();
|
|
5203
|
+
const client = new DaemonClient({
|
|
5204
|
+
transport: view,
|
|
5205
|
+
apiKey: this._apiKey
|
|
5206
|
+
});
|
|
5207
|
+
if (options.permissionHandler) {
|
|
5208
|
+
client.setPermissionHandler(options.permissionHandler);
|
|
5209
|
+
}
|
|
5210
|
+
if (options.askUserHandler) {
|
|
5211
|
+
client.setAskUserHandler(options.askUserHandler);
|
|
5212
|
+
}
|
|
5213
|
+
let sdkMcpServers;
|
|
5214
|
+
try {
|
|
5215
|
+
sdkMcpServers = await startSdkMcpServers(options.mcpServers);
|
|
5216
|
+
await client.loadSession({
|
|
5217
|
+
sessionId,
|
|
5218
|
+
mcpServers: sdkMcpServers.mcpServers
|
|
5219
|
+
});
|
|
5220
|
+
const session = new DaemonSession(client, sessionId);
|
|
5221
|
+
if (sdkMcpServers) {
|
|
5222
|
+
session.addCleanup(sdkMcpServers.cleanup);
|
|
5223
|
+
}
|
|
5224
|
+
return session;
|
|
5225
|
+
} catch (error) {
|
|
5226
|
+
await sdkMcpServers?.cleanup();
|
|
5227
|
+
await client.close();
|
|
5228
|
+
throw error;
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
async interruptSession(sessionId) {
|
|
5232
|
+
this._ensureNotClosed();
|
|
5233
|
+
const view = this._multiplexer.createView();
|
|
5234
|
+
const client = new DaemonClient({
|
|
5235
|
+
transport: view,
|
|
5236
|
+
apiKey: this._apiKey
|
|
5237
|
+
});
|
|
5238
|
+
try {
|
|
5239
|
+
await client.loadSession({ sessionId });
|
|
5240
|
+
await client.interruptSession();
|
|
5241
|
+
} finally {
|
|
5242
|
+
await client.close();
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
async close() {
|
|
5246
|
+
if (this._closed) {
|
|
5247
|
+
return;
|
|
5248
|
+
}
|
|
5249
|
+
this._closed = true;
|
|
5250
|
+
await this._transport.close();
|
|
5251
|
+
}
|
|
5252
|
+
_ensureNotClosed() {
|
|
5253
|
+
if (this._closed) {
|
|
5254
|
+
throw new ConnectionError(
|
|
5255
|
+
"Daemon connection has been closed. Call connectDaemon() to create a new connection."
|
|
5256
|
+
);
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
};
|
|
5260
|
+
async function connectDaemon(options) {
|
|
5261
|
+
const isLocal = !options.url && (!options.machine || options.machine.type === "local" /* Local */);
|
|
5262
|
+
let resolvedOptions = options;
|
|
5263
|
+
if (isLocal) {
|
|
5264
|
+
const { port } = await ensureLocalDaemon();
|
|
5265
|
+
resolvedOptions = { ...options, _localPort: port };
|
|
5266
|
+
}
|
|
5267
|
+
const url = resolveWebSocketUrl(resolvedOptions);
|
|
5268
|
+
const wsConfig = getWebSocketConfig(resolvedOptions.machine);
|
|
5269
|
+
const transport = new WebSocketTransport(wsConfig);
|
|
5270
|
+
const apiKey = resolvedOptions.apiKey;
|
|
5271
|
+
const maxRetries = resolvedOptions.maxRetries ?? 0;
|
|
5272
|
+
try {
|
|
5273
|
+
if (maxRetries > 0) {
|
|
5274
|
+
let lastError;
|
|
5275
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
5276
|
+
try {
|
|
5277
|
+
await transport.connect(url);
|
|
5278
|
+
await authenticate(transport, resolvedOptions);
|
|
5279
|
+
return new DaemonConnection(transport, apiKey);
|
|
5280
|
+
} catch (error) {
|
|
5281
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
5282
|
+
try {
|
|
5283
|
+
await transport.close();
|
|
5284
|
+
} catch {
|
|
5285
|
+
}
|
|
5286
|
+
if (attempt < maxRetries) {
|
|
5287
|
+
await new Promise((resolve2) => setTimeout(resolve2, 2e3));
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
}
|
|
5291
|
+
throw lastError;
|
|
5292
|
+
}
|
|
5293
|
+
await transport.connect(url);
|
|
5294
|
+
await authenticate(transport, resolvedOptions);
|
|
5295
|
+
return new DaemonConnection(transport, apiKey);
|
|
5296
|
+
} catch (error) {
|
|
5297
|
+
try {
|
|
5298
|
+
await transport.close();
|
|
5299
|
+
} catch {
|
|
5300
|
+
}
|
|
5301
|
+
throw error;
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
3842
5304
|
export {
|
|
3843
5305
|
AddMcpServerRequestParamsSchema,
|
|
3844
5306
|
AddMcpServerRequestSchema,
|
|
@@ -3889,13 +5351,22 @@ export {
|
|
|
3889
5351
|
CompactSessionRequestSchema,
|
|
3890
5352
|
CompactSessionResponseSchema,
|
|
3891
5353
|
CompactSessionResultSchema,
|
|
5354
|
+
ComputerListResponseSchema,
|
|
5355
|
+
ComputerMetricSchema,
|
|
5356
|
+
ComputerMetricsResponseSchema,
|
|
5357
|
+
ComputerSchema,
|
|
3892
5358
|
ConnectionError,
|
|
3893
5359
|
ContentBlockSchema,
|
|
5360
|
+
ContextBreakdownCategorySchema,
|
|
5361
|
+
ContextBreakdownResultSchema,
|
|
3894
5362
|
ContextStatsAccuracy,
|
|
3895
5363
|
ContextStatsSchema,
|
|
3896
5364
|
CreateMessageNotificationSchema,
|
|
3897
5365
|
CreateToolConfirmationDetailsSchema,
|
|
3898
5366
|
DEFAULT_REQUEST_TIMEOUT,
|
|
5367
|
+
DaemonClient,
|
|
5368
|
+
DaemonConnection,
|
|
5369
|
+
DaemonSession,
|
|
3899
5370
|
DecompSessionType,
|
|
3900
5371
|
DiscoveredIssueSchema,
|
|
3901
5372
|
DismissalRecordSchema,
|
|
@@ -4010,6 +5481,10 @@ export {
|
|
|
4010
5481
|
LoadSessionResponseSchema,
|
|
4011
5482
|
LoadSessionResultSchema,
|
|
4012
5483
|
MCP_AUTH_TIMEOUT,
|
|
5484
|
+
MachineTemplateBuildStatusSchema,
|
|
5485
|
+
MachineTemplateListResponseSchema,
|
|
5486
|
+
MachineTemplateSchema,
|
|
5487
|
+
MachineType,
|
|
4013
5488
|
McpAuthCompletedNotificationSchema,
|
|
4014
5489
|
McpAuthOutcome,
|
|
4015
5490
|
McpAuthRequiredNotificationSchema,
|
|
@@ -4055,6 +5530,9 @@ export {
|
|
|
4055
5530
|
REWIND_TIMEOUT,
|
|
4056
5531
|
ReasoningEffort,
|
|
4057
5532
|
RedactedThinkingBlockSchema,
|
|
5533
|
+
RefreshComputerResponseSchema,
|
|
5534
|
+
RemoteSessionListResponseSchema,
|
|
5535
|
+
RemoteSessionSchema,
|
|
4058
5536
|
RemoveMcpServerRequestParamsSchema,
|
|
4059
5537
|
RemoveMcpServerRequestSchema,
|
|
4060
5538
|
RemoveMcpServerResponseSchema,
|
|
@@ -4074,6 +5552,7 @@ export {
|
|
|
4074
5552
|
SDK_VERSION,
|
|
4075
5553
|
SESSION_INIT_TIMEOUT,
|
|
4076
5554
|
SdkMcpServer,
|
|
5555
|
+
ServerRequestHandlerType,
|
|
4077
5556
|
SessionError,
|
|
4078
5557
|
SessionMetadataSchema,
|
|
4079
5558
|
SessionNotFoundError,
|
|
@@ -4149,20 +5628,37 @@ export {
|
|
|
4149
5628
|
UpdateSessionSettingsResultSchema,
|
|
4150
5629
|
VerificationCommandSchema,
|
|
4151
5630
|
VerificationSchema,
|
|
5631
|
+
WebSocketTransport,
|
|
4152
5632
|
WorkerCompletedEntrySchema,
|
|
4153
5633
|
WorkerFailedEntrySchema,
|
|
4154
5634
|
WorkerPausedEntrySchema,
|
|
4155
5635
|
WorkerSelectedFeatureEntrySchema,
|
|
4156
5636
|
WorkerStartedEntrySchema,
|
|
4157
5637
|
WorkerStateInfoSchema,
|
|
5638
|
+
connectDaemon,
|
|
4158
5639
|
convertNotificationToStreamMessage,
|
|
5640
|
+
createComputer,
|
|
4159
5641
|
createResponseSchema,
|
|
4160
5642
|
createSdkMcpServer,
|
|
4161
5643
|
createSession,
|
|
5644
|
+
deleteComputer,
|
|
4162
5645
|
dispatchNotification,
|
|
5646
|
+
ensureLocalDaemon,
|
|
5647
|
+
getComputer,
|
|
5648
|
+
getComputerByName,
|
|
5649
|
+
getComputerMetrics,
|
|
5650
|
+
getMachineTemplate,
|
|
5651
|
+
listComputers,
|
|
5652
|
+
listMachineTemplates,
|
|
5653
|
+
listRemoteSessions,
|
|
4163
5654
|
listSessions,
|
|
5655
|
+
refreshComputer,
|
|
5656
|
+
resolveWebSocketUrl,
|
|
5657
|
+
restartComputer,
|
|
4164
5658
|
resumeSession,
|
|
5659
|
+
retryInstallDeps,
|
|
4165
5660
|
run,
|
|
4166
|
-
tool
|
|
5661
|
+
tool,
|
|
5662
|
+
updateComputer
|
|
4167
5663
|
};
|
|
4168
5664
|
//# sourceMappingURL=index.js.map
|