@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 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.3.0";
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.3.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
- if (method === "droid.request_permission" /* REQUEST_PERMISSION */) {
2559
+ const handlerType = this._serverRequestMethodMap[method];
2560
+ if (handlerType === "permission" /* Permission */) {
2502
2561
  await this._handlePermissionRequest(requestId, params);
2503
- } else if (method === "droid.ask_user" /* ASK_USER */) {
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
- throwIfAborted(options?.abortSignal);
3758
- const startedAt = Date.now();
3759
- let resolveDone = () => {
3760
- };
3761
- const donePromise = new Promise((resolve2) => {
3762
- resolveDone = resolve2;
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