opensteer 0.4.6 → 0.4.7

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.
@@ -752,7 +752,7 @@ var BrowserPool = class {
752
752
  const context = contexts[0];
753
753
  const pages = context.pages();
754
754
  const page = pages.length > 0 ? pages[0] : await context.newPage();
755
- return { browser, context, page, isRemote: true };
755
+ return { browser, context, page, isExternal: true };
756
756
  } catch (error) {
757
757
  if (browser) {
758
758
  await browser.close().catch(() => void 0);
@@ -787,7 +787,7 @@ var BrowserPool = class {
787
787
  context = await browser.newContext(options.context || {});
788
788
  page = await context.newPage();
789
789
  }
790
- return { browser, context, page, isRemote: false };
790
+ return { browser, context, page, isExternal: false };
791
791
  }
792
792
  async launchSandbox(options) {
793
793
  const browser = await import_playwright.chromium.launch({
@@ -798,7 +798,7 @@ var BrowserPool = class {
798
798
  const context = await browser.newContext(options.context || {});
799
799
  const page = await context.newPage();
800
800
  this.browser = browser;
801
- return { browser, context, page, isRemote: false };
801
+ return { browser, context, page, isExternal: false };
802
802
  }
803
803
  };
804
804
 
@@ -869,28 +869,27 @@ function assertNoLegacyAiConfig(source, config) {
869
869
  );
870
870
  }
871
871
  }
872
- function assertNoLegacyModeConfig(source, config) {
872
+ function assertNoLegacyRuntimeConfig(source, config) {
873
873
  if (!config || typeof config !== "object") return;
874
874
  const configRecord = config;
875
875
  if (hasOwn(configRecord, "runtime")) {
876
876
  throw new Error(
877
- `Legacy "runtime" config is no longer supported in ${source}. Use top-level "mode" instead.`
877
+ `Legacy "runtime" config is no longer supported in ${source}. Use top-level "cloud" instead.`
878
878
  );
879
879
  }
880
- if (hasOwn(configRecord, "apiKey")) {
880
+ if (hasOwn(configRecord, "mode")) {
881
881
  throw new Error(
882
- `Top-level "apiKey" config is not supported in ${source}. Use "remote.apiKey" instead.`
882
+ `Top-level "mode" config is no longer supported in ${source}. Use "cloud: true" to enable cloud mode.`
883
883
  );
884
884
  }
885
- const remoteValue = configRecord.remote;
886
- if (typeof remoteValue === "boolean") {
885
+ if (hasOwn(configRecord, "remote")) {
887
886
  throw new Error(
888
- `Boolean "remote" config is no longer supported in ${source}. Use "mode: \\"remote\\"" with "remote" options.`
887
+ `Top-level "remote" config is no longer supported in ${source}. Use "cloud" options instead.`
889
888
  );
890
889
  }
891
- if (remoteValue && typeof remoteValue === "object" && !Array.isArray(remoteValue) && hasOwn(remoteValue, "key")) {
890
+ if (hasOwn(configRecord, "apiKey")) {
892
891
  throw new Error(
893
- `Legacy "remote.key" config is no longer supported in ${source}. Use "remote.apiKey" instead.`
892
+ `Top-level "apiKey" config is not supported in ${source}. Use "cloud.apiKey" instead.`
894
893
  );
895
894
  }
896
895
  }
@@ -936,20 +935,20 @@ function parseNumber(value) {
936
935
  if (!Number.isFinite(parsed)) return void 0;
937
936
  return parsed;
938
937
  }
939
- function parseMode(value, source) {
938
+ function parseRuntimeMode(value, source) {
940
939
  if (value == null) return void 0;
941
940
  if (typeof value !== "string") {
942
941
  throw new Error(
943
- `Invalid ${source} value "${String(value)}". Use "local" or "remote".`
942
+ `Invalid ${source} value "${String(value)}". Use "local" or "cloud".`
944
943
  );
945
944
  }
946
945
  const normalized = value.trim().toLowerCase();
947
946
  if (!normalized) return void 0;
948
- if (normalized === "local" || normalized === "remote") {
947
+ if (normalized === "local" || normalized === "cloud") {
949
948
  return normalized;
950
949
  }
951
950
  throw new Error(
952
- `Invalid ${source} value "${value}". Use "local" or "remote".`
951
+ `Invalid ${source} value "${value}". Use "local" or "cloud".`
953
952
  );
954
953
  }
955
954
  function parseAuthScheme(value, source) {
@@ -968,6 +967,22 @@ function parseAuthScheme(value, source) {
968
967
  `Invalid ${source} value "${value}". Use "api-key" or "bearer".`
969
968
  );
970
969
  }
970
+ function parseCloudAnnounce(value, source) {
971
+ if (value == null) return void 0;
972
+ if (typeof value !== "string") {
973
+ throw new Error(
974
+ `Invalid ${source} value "${String(value)}". Use "always", "off", or "tty".`
975
+ );
976
+ }
977
+ const normalized = value.trim().toLowerCase();
978
+ if (!normalized) return void 0;
979
+ if (normalized === "always" || normalized === "off" || normalized === "tty") {
980
+ return normalized;
981
+ }
982
+ throw new Error(
983
+ `Invalid ${source} value "${value}". Use "always", "off", or "tty".`
984
+ );
985
+ }
971
986
  function resolveOpensteerApiKey() {
972
987
  const value = process.env.OPENSTEER_API_KEY?.trim();
973
988
  if (!value) return void 0;
@@ -979,29 +994,40 @@ function resolveOpensteerAuthScheme() {
979
994
  "OPENSTEER_AUTH_SCHEME"
980
995
  );
981
996
  }
982
- function normalizeRemoteOptions(value) {
997
+ function normalizeCloudOptions(value) {
983
998
  if (!value || typeof value !== "object" || Array.isArray(value)) {
984
999
  return void 0;
985
1000
  }
986
1001
  return value;
987
1002
  }
988
- function resolveModeSelection(config) {
989
- const configMode = parseMode(config.mode, "mode");
990
- if (configMode) {
1003
+ function parseCloudEnabled(value, source) {
1004
+ if (value == null) return void 0;
1005
+ if (typeof value === "boolean") return value;
1006
+ if (typeof value === "object" && !Array.isArray(value)) return true;
1007
+ throw new Error(
1008
+ `Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
1009
+ );
1010
+ }
1011
+ function resolveCloudSelection(config) {
1012
+ const configCloud = parseCloudEnabled(config.cloud, "cloud");
1013
+ if (configCloud !== void 0) {
991
1014
  return {
992
- mode: configMode,
993
- source: "config.mode"
1015
+ cloud: configCloud,
1016
+ source: "config.cloud"
994
1017
  };
995
1018
  }
996
- const envMode = parseMode(process.env.OPENSTEER_MODE, "OPENSTEER_MODE");
1019
+ const envMode = parseRuntimeMode(
1020
+ process.env.OPENSTEER_MODE,
1021
+ "OPENSTEER_MODE"
1022
+ );
997
1023
  if (envMode) {
998
1024
  return {
999
- mode: envMode,
1025
+ cloud: envMode === "cloud",
1000
1026
  source: "env.OPENSTEER_MODE"
1001
1027
  };
1002
1028
  }
1003
1029
  return {
1004
- mode: "local",
1030
+ cloud: false,
1005
1031
  source: "default"
1006
1032
  };
1007
1033
  }
@@ -1017,11 +1043,11 @@ function resolveConfig(input = {}) {
1017
1043
  );
1018
1044
  }
1019
1045
  assertNoLegacyAiConfig("Opensteer constructor config", input);
1020
- assertNoLegacyModeConfig("Opensteer constructor config", input);
1046
+ assertNoLegacyRuntimeConfig("Opensteer constructor config", input);
1021
1047
  const rootDir = input.storage?.rootDir ?? DEFAULT_CONFIG.storage.rootDir ?? process.cwd();
1022
1048
  const fileConfig = loadConfigFile(rootDir);
1023
1049
  assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
1024
- assertNoLegacyModeConfig(".opensteer/config.json", fileConfig);
1050
+ assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
1025
1051
  const envConfig = {
1026
1052
  browser: {
1027
1053
  headless: parseBool(process.env.OPENSTEER_HEADLESS),
@@ -1039,28 +1065,38 @@ function resolveConfig(input = {}) {
1039
1065
  const resolved = mergeDeep(mergedWithEnv, input);
1040
1066
  const envApiKey = resolveOpensteerApiKey();
1041
1067
  const envAuthScheme = resolveOpensteerAuthScheme();
1042
- const inputRemoteOptions = normalizeRemoteOptions(input.remote);
1068
+ const envCloudAnnounce = parseCloudAnnounce(
1069
+ process.env.OPENSTEER_REMOTE_ANNOUNCE,
1070
+ "OPENSTEER_REMOTE_ANNOUNCE"
1071
+ );
1072
+ const inputCloudOptions = normalizeCloudOptions(input.cloud);
1043
1073
  const inputAuthScheme = parseAuthScheme(
1044
- inputRemoteOptions?.authScheme,
1045
- "remote.authScheme"
1074
+ inputCloudOptions?.authScheme,
1075
+ "cloud.authScheme"
1046
1076
  );
1047
- const inputHasRemoteApiKey = Boolean(
1048
- inputRemoteOptions && Object.prototype.hasOwnProperty.call(inputRemoteOptions, "apiKey")
1077
+ const inputCloudAnnounce = parseCloudAnnounce(
1078
+ inputCloudOptions?.announce,
1079
+ "cloud.announce"
1049
1080
  );
1050
- const modeSelection = resolveModeSelection({
1051
- mode: resolved.mode
1081
+ const inputHasCloudApiKey = Boolean(
1082
+ inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "apiKey")
1083
+ );
1084
+ const cloudSelection = resolveCloudSelection({
1085
+ cloud: resolved.cloud
1052
1086
  });
1053
- if (modeSelection.mode === "remote") {
1054
- const resolvedRemote = normalizeRemoteOptions(resolved.remote) ?? {};
1055
- const authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedRemote.authScheme, "remote.authScheme") ?? "api-key";
1056
- resolved.remote = {
1057
- ...resolvedRemote,
1058
- authScheme
1087
+ if (cloudSelection.cloud) {
1088
+ const resolvedCloud = normalizeCloudOptions(resolved.cloud) ?? {};
1089
+ const authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
1090
+ const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
1091
+ resolved.cloud = {
1092
+ ...resolvedCloud,
1093
+ authScheme,
1094
+ announce
1059
1095
  };
1060
1096
  }
1061
- if (envApiKey && modeSelection.mode === "remote" && !inputHasRemoteApiKey) {
1062
- resolved.remote = {
1063
- ...normalizeRemoteOptions(resolved.remote) ?? {},
1097
+ if (envApiKey && cloudSelection.cloud && !inputHasCloudApiKey) {
1098
+ resolved.cloud = {
1099
+ ...normalizeCloudOptions(resolved.cloud) ?? {},
1064
1100
  apiKey: envApiKey
1065
1101
  };
1066
1102
  }
@@ -7357,36 +7393,39 @@ function clonePersistedExtractNode(node) {
7357
7393
  return JSON.parse(JSON.stringify(node));
7358
7394
  }
7359
7395
 
7360
- // src/remote/action-ws-client.ts
7396
+ // src/cloud/contracts.ts
7397
+ var cloudSessionContractVersion = "v3";
7398
+
7399
+ // src/cloud/action-ws-client.ts
7361
7400
  var import_ws2 = __toESM(require("ws"), 1);
7362
7401
 
7363
- // src/remote/errors.ts
7364
- var OpensteerRemoteError = class extends Error {
7402
+ // src/cloud/errors.ts
7403
+ var OpensteerCloudError = class extends Error {
7365
7404
  code;
7366
7405
  status;
7367
7406
  details;
7368
7407
  constructor(code, message, status, details) {
7369
7408
  super(message);
7370
- this.name = "OpensteerRemoteError";
7409
+ this.name = "OpensteerCloudError";
7371
7410
  this.code = code;
7372
7411
  this.status = status;
7373
7412
  this.details = details;
7374
7413
  }
7375
7414
  };
7376
- function remoteUnsupportedMethodError(method, message) {
7377
- return new OpensteerRemoteError(
7378
- "REMOTE_UNSUPPORTED_METHOD",
7379
- message || `${method} is not supported in remote mode.`
7415
+ function cloudUnsupportedMethodError(method, message) {
7416
+ return new OpensteerCloudError(
7417
+ "CLOUD_UNSUPPORTED_METHOD",
7418
+ message || `${method} is not supported in cloud mode.`
7380
7419
  );
7381
7420
  }
7382
- function remoteNotLaunchedError() {
7383
- return new OpensteerRemoteError(
7384
- "REMOTE_SESSION_NOT_FOUND",
7385
- "Remote session is not connected. Call launch() first."
7421
+ function cloudNotLaunchedError() {
7422
+ return new OpensteerCloudError(
7423
+ "CLOUD_SESSION_NOT_FOUND",
7424
+ "Cloud session is not connected. Call launch() first."
7386
7425
  );
7387
7426
  }
7388
7427
 
7389
- // src/remote/action-ws-client.ts
7428
+ // src/cloud/action-ws-client.ts
7390
7429
  var ActionWsClient = class _ActionWsClient {
7391
7430
  ws;
7392
7431
  sessionId;
@@ -7403,18 +7442,18 @@ var ActionWsClient = class _ActionWsClient {
7403
7442
  });
7404
7443
  ws.on("error", (error) => {
7405
7444
  this.rejectAll(
7406
- new OpensteerRemoteError(
7407
- "REMOTE_TRANSPORT_ERROR",
7408
- `Remote action websocket error: ${error.message}`
7445
+ new OpensteerCloudError(
7446
+ "CLOUD_TRANSPORT_ERROR",
7447
+ `Cloud action websocket error: ${error.message}`
7409
7448
  )
7410
7449
  );
7411
7450
  });
7412
7451
  ws.on("close", () => {
7413
7452
  this.closed = true;
7414
7453
  this.rejectAll(
7415
- new OpensteerRemoteError(
7416
- "REMOTE_SESSION_CLOSED",
7417
- "Remote action websocket closed."
7454
+ new OpensteerCloudError(
7455
+ "CLOUD_SESSION_CLOSED",
7456
+ "Cloud action websocket closed."
7418
7457
  )
7419
7458
  );
7420
7459
  });
@@ -7426,8 +7465,8 @@ var ActionWsClient = class _ActionWsClient {
7426
7465
  ws.once("open", () => resolve());
7427
7466
  ws.once("error", (error) => {
7428
7467
  reject(
7429
- new OpensteerRemoteError(
7430
- "REMOTE_TRANSPORT_ERROR",
7468
+ new OpensteerCloudError(
7469
+ "CLOUD_TRANSPORT_ERROR",
7431
7470
  `Failed to connect action websocket: ${error.message}`
7432
7471
  )
7433
7472
  );
@@ -7437,9 +7476,9 @@ var ActionWsClient = class _ActionWsClient {
7437
7476
  }
7438
7477
  async request(method, args) {
7439
7478
  if (this.closed || this.ws.readyState !== import_ws2.default.OPEN) {
7440
- throw new OpensteerRemoteError(
7441
- "REMOTE_SESSION_CLOSED",
7442
- "Remote action websocket is closed."
7479
+ throw new OpensteerCloudError(
7480
+ "CLOUD_SESSION_CLOSED",
7481
+ "Cloud action websocket is closed."
7443
7482
  );
7444
7483
  }
7445
7484
  const id = this.nextRequestId;
@@ -7458,8 +7497,8 @@ var ActionWsClient = class _ActionWsClient {
7458
7497
  this.ws.send(JSON.stringify(payload));
7459
7498
  } catch (error) {
7460
7499
  this.pending.delete(id);
7461
- const message = error instanceof Error ? error.message : "Failed to send remote action request.";
7462
- throw new OpensteerRemoteError("REMOTE_TRANSPORT_ERROR", message);
7500
+ const message = error instanceof Error ? error.message : "Failed to send cloud action request.";
7501
+ throw new OpensteerCloudError("CLOUD_TRANSPORT_ERROR", message);
7463
7502
  }
7464
7503
  return await resultPromise;
7465
7504
  }
@@ -7477,9 +7516,9 @@ var ActionWsClient = class _ActionWsClient {
7477
7516
  parsed = JSON.parse(rawDataToUtf8(raw));
7478
7517
  } catch {
7479
7518
  this.rejectAll(
7480
- new OpensteerRemoteError(
7481
- "REMOTE_TRANSPORT_ERROR",
7482
- "Invalid remote action response payload."
7519
+ new OpensteerCloudError(
7520
+ "CLOUD_TRANSPORT_ERROR",
7521
+ "Invalid cloud action response payload."
7483
7522
  )
7484
7523
  );
7485
7524
  return;
@@ -7492,7 +7531,7 @@ var ActionWsClient = class _ActionWsClient {
7492
7531
  return;
7493
7532
  }
7494
7533
  pending.reject(
7495
- new OpensteerRemoteError(
7534
+ new OpensteerCloudError(
7496
7535
  parsed.code,
7497
7536
  parsed.error,
7498
7537
  void 0,
@@ -7520,7 +7559,7 @@ function withTokenQuery(wsUrl, token) {
7520
7559
  return url.toString();
7521
7560
  }
7522
7561
 
7523
- // src/remote/local-cache-sync.ts
7562
+ // src/cloud/local-cache-sync.ts
7524
7563
  var import_fs3 = __toESM(require("fs"), 1);
7525
7564
  var import_path5 = __toESM(require("path"), 1);
7526
7565
  function collectLocalSelectorCacheEntries(storage) {
@@ -7644,24 +7683,24 @@ function dedupeNewest(entries) {
7644
7683
  return [...byKey.values()];
7645
7684
  }
7646
7685
 
7647
- // src/remote/cdp-client.ts
7686
+ // src/cloud/cdp-client.ts
7648
7687
  var import_playwright2 = require("playwright");
7649
- var RemoteCdpClient = class {
7688
+ var CloudCdpClient = class {
7650
7689
  async connect(args) {
7651
7690
  const endpoint = withTokenQuery2(args.wsUrl, args.token);
7652
7691
  let browser;
7653
7692
  try {
7654
7693
  browser = await import_playwright2.chromium.connectOverCDP(endpoint);
7655
7694
  } catch (error) {
7656
- const message = error instanceof Error ? error.message : "Failed to connect to remote CDP endpoint.";
7657
- throw new OpensteerRemoteError("REMOTE_TRANSPORT_ERROR", message);
7695
+ const message = error instanceof Error ? error.message : "Failed to connect to cloud CDP endpoint.";
7696
+ throw new OpensteerCloudError("CLOUD_TRANSPORT_ERROR", message);
7658
7697
  }
7659
7698
  const context = browser.contexts()[0];
7660
7699
  if (!context) {
7661
7700
  await browser.close();
7662
- throw new OpensteerRemoteError(
7663
- "REMOTE_INTERNAL",
7664
- "Remote browser returned no context."
7701
+ throw new OpensteerCloudError(
7702
+ "CLOUD_INTERNAL",
7703
+ "Cloud browser returned no context."
7665
7704
  );
7666
7705
  }
7667
7706
  const page = context.pages()[0] || await context.newPage();
@@ -7674,9 +7713,9 @@ function withTokenQuery2(wsUrl, token) {
7674
7713
  return url.toString();
7675
7714
  }
7676
7715
 
7677
- // src/remote/session-client.ts
7716
+ // src/cloud/session-client.ts
7678
7717
  var CACHE_IMPORT_BATCH_SIZE = 200;
7679
- var RemoteSessionClient = class {
7718
+ var CloudSessionClient = class {
7680
7719
  baseUrl;
7681
7720
  key;
7682
7721
  authScheme;
@@ -7697,7 +7736,17 @@ var RemoteSessionClient = class {
7697
7736
  if (!response.ok) {
7698
7737
  throw await parseHttpError(response);
7699
7738
  }
7700
- return await response.json();
7739
+ let body;
7740
+ try {
7741
+ body = await response.json();
7742
+ } catch {
7743
+ throw new OpensteerCloudError(
7744
+ "CLOUD_CONTRACT_MISMATCH",
7745
+ "Invalid cloud session create response: expected a JSON object.",
7746
+ response.status
7747
+ );
7748
+ }
7749
+ return parseCreateResponse(body, response.status);
7701
7750
  }
7702
7751
  async close(sessionId) {
7703
7752
  const response = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
@@ -7756,6 +7805,134 @@ var RemoteSessionClient = class {
7756
7805
  function normalizeBaseUrl(baseUrl) {
7757
7806
  return baseUrl.replace(/\/+$/, "");
7758
7807
  }
7808
+ function parseCreateResponse(body, status) {
7809
+ const root = requireObject(
7810
+ body,
7811
+ "Invalid cloud session create response: expected a JSON object.",
7812
+ status
7813
+ );
7814
+ const sessionId = requireString(root, "sessionId", status);
7815
+ const actionWsUrl = requireString(root, "actionWsUrl", status);
7816
+ const cdpWsUrl = requireString(root, "cdpWsUrl", status);
7817
+ const actionToken = requireString(root, "actionToken", status);
7818
+ const cdpToken = requireString(root, "cdpToken", status);
7819
+ const cloudSessionUrl = requireString(root, "cloudSessionUrl", status);
7820
+ const cloudSessionRoot = requireObject(
7821
+ root.cloudSession,
7822
+ "Invalid cloud session create response: cloudSession must be an object.",
7823
+ status
7824
+ );
7825
+ const cloudSession = {
7826
+ sessionId: requireString(cloudSessionRoot, "sessionId", status, "cloudSession"),
7827
+ workspaceId: requireString(
7828
+ cloudSessionRoot,
7829
+ "workspaceId",
7830
+ status,
7831
+ "cloudSession"
7832
+ ),
7833
+ state: requireString(cloudSessionRoot, "state", status, "cloudSession"),
7834
+ createdAt: requireNumber(cloudSessionRoot, "createdAt", status, "cloudSession"),
7835
+ sourceType: requireSourceType(cloudSessionRoot, "sourceType", status, "cloudSession"),
7836
+ sourceRef: optionalString(cloudSessionRoot, "sourceRef", status, "cloudSession"),
7837
+ label: optionalString(cloudSessionRoot, "label", status, "cloudSession")
7838
+ };
7839
+ const expiresAt = optionalNumber(root, "expiresAt", status);
7840
+ return {
7841
+ sessionId,
7842
+ actionWsUrl,
7843
+ cdpWsUrl,
7844
+ actionToken,
7845
+ cdpToken,
7846
+ expiresAt,
7847
+ cloudSessionUrl,
7848
+ cloudSession
7849
+ };
7850
+ }
7851
+ function requireObject(value, message, status) {
7852
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7853
+ throw new OpensteerCloudError("CLOUD_CONTRACT_MISMATCH", message, status);
7854
+ }
7855
+ return value;
7856
+ }
7857
+ function requireString(source, field, status, parent) {
7858
+ const value = source[field];
7859
+ if (typeof value !== "string" || !value.trim()) {
7860
+ throw new OpensteerCloudError(
7861
+ "CLOUD_CONTRACT_MISMATCH",
7862
+ `Invalid cloud session create response: ${formatFieldPath(
7863
+ field,
7864
+ parent
7865
+ )} must be a non-empty string.`,
7866
+ status
7867
+ );
7868
+ }
7869
+ return value;
7870
+ }
7871
+ function requireNumber(source, field, status, parent) {
7872
+ const value = source[field];
7873
+ if (typeof value !== "number" || !Number.isFinite(value)) {
7874
+ throw new OpensteerCloudError(
7875
+ "CLOUD_CONTRACT_MISMATCH",
7876
+ `Invalid cloud session create response: ${formatFieldPath(
7877
+ field,
7878
+ parent
7879
+ )} must be a finite number.`,
7880
+ status
7881
+ );
7882
+ }
7883
+ return value;
7884
+ }
7885
+ function optionalString(source, field, status, parent) {
7886
+ const value = source[field];
7887
+ if (value == null) {
7888
+ return void 0;
7889
+ }
7890
+ if (typeof value !== "string") {
7891
+ throw new OpensteerCloudError(
7892
+ "CLOUD_CONTRACT_MISMATCH",
7893
+ `Invalid cloud session create response: ${formatFieldPath(
7894
+ field,
7895
+ parent
7896
+ )} must be a string when present.`,
7897
+ status
7898
+ );
7899
+ }
7900
+ return value;
7901
+ }
7902
+ function optionalNumber(source, field, status, parent) {
7903
+ const value = source[field];
7904
+ if (value == null) {
7905
+ return void 0;
7906
+ }
7907
+ if (typeof value !== "number" || !Number.isFinite(value)) {
7908
+ throw new OpensteerCloudError(
7909
+ "CLOUD_CONTRACT_MISMATCH",
7910
+ `Invalid cloud session create response: ${formatFieldPath(
7911
+ field,
7912
+ parent
7913
+ )} must be a finite number when present.`,
7914
+ status
7915
+ );
7916
+ }
7917
+ return value;
7918
+ }
7919
+ function requireSourceType(source, field, status, parent) {
7920
+ const value = source[field];
7921
+ if (value === "agent-thread" || value === "agent-run" || value === "local-cloud" || value === "manual") {
7922
+ return value;
7923
+ }
7924
+ throw new OpensteerCloudError(
7925
+ "CLOUD_CONTRACT_MISMATCH",
7926
+ `Invalid cloud session create response: ${formatFieldPath(
7927
+ field,
7928
+ parent
7929
+ )} must be one of "agent-thread", "agent-run", "local-cloud", or "manual".`,
7930
+ status
7931
+ );
7932
+ }
7933
+ function formatFieldPath(field, parent) {
7934
+ return parent ? `"${parent}.${field}"` : `"${field}"`;
7935
+ }
7759
7936
  function zeroImportResponse() {
7760
7937
  return {
7761
7938
  imported: 0,
@@ -7779,33 +7956,46 @@ async function parseHttpError(response) {
7779
7956
  } catch {
7780
7957
  body = null;
7781
7958
  }
7782
- const code = typeof body?.code === "string" ? toRemoteErrorCode(body.code) : "REMOTE_TRANSPORT_ERROR";
7783
- const message = typeof body?.error === "string" ? body.error : `Remote request failed with status ${response.status}.`;
7784
- return new OpensteerRemoteError(code, message, response.status, body?.details);
7959
+ const code = typeof body?.code === "string" ? toCloudErrorCode(body.code) : "CLOUD_TRANSPORT_ERROR";
7960
+ const message = typeof body?.error === "string" ? body.error : `Cloud request failed with status ${response.status}.`;
7961
+ return new OpensteerCloudError(code, message, response.status, body?.details);
7785
7962
  }
7786
- function toRemoteErrorCode(code) {
7787
- if (code === "REMOTE_AUTH_FAILED" || code === "REMOTE_SESSION_NOT_FOUND" || code === "REMOTE_SESSION_CLOSED" || code === "REMOTE_UNSUPPORTED_METHOD" || code === "REMOTE_INVALID_REQUEST" || code === "REMOTE_MODEL_NOT_ALLOWED" || code === "REMOTE_ACTION_FAILED" || code === "REMOTE_INTERNAL" || code === "REMOTE_CAPACITY_EXHAUSTED" || code === "REMOTE_RUNTIME_UNAVAILABLE" || code === "REMOTE_RUNTIME_MISMATCH" || code === "REMOTE_SESSION_STALE" || code === "REMOTE_CONTROL_PLANE_ERROR") {
7963
+ function toCloudErrorCode(code) {
7964
+ if (code === "CLOUD_AUTH_FAILED" || code === "CLOUD_SESSION_NOT_FOUND" || code === "CLOUD_SESSION_CLOSED" || code === "CLOUD_UNSUPPORTED_METHOD" || code === "CLOUD_INVALID_REQUEST" || code === "CLOUD_MODEL_NOT_ALLOWED" || code === "CLOUD_ACTION_FAILED" || code === "CLOUD_INTERNAL" || code === "CLOUD_CAPACITY_EXHAUSTED" || code === "CLOUD_RUNTIME_UNAVAILABLE" || code === "CLOUD_RUNTIME_MISMATCH" || code === "CLOUD_SESSION_STALE" || code === "CLOUD_CONTRACT_MISMATCH" || code === "CLOUD_CONTROL_PLANE_ERROR") {
7788
7965
  return code;
7789
7966
  }
7790
- return "REMOTE_TRANSPORT_ERROR";
7967
+ return "CLOUD_TRANSPORT_ERROR";
7791
7968
  }
7792
7969
 
7793
- // src/remote/runtime.ts
7794
- var DEFAULT_REMOTE_BASE_URL = "https://remote.opensteer.com";
7795
- function createRemoteRuntimeState(key, baseUrl = resolveRemoteBaseUrl(), authScheme = "api-key") {
7970
+ // src/cloud/runtime.ts
7971
+ var DEFAULT_CLOUD_BASE_URL = "https://remote.opensteer.com";
7972
+ var DEFAULT_CLOUD_APP_URL = "https://opensteer.com";
7973
+ function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authScheme = "api-key", appUrl = resolveCloudAppUrl()) {
7796
7974
  return {
7797
- sessionClient: new RemoteSessionClient(baseUrl, key, authScheme),
7798
- cdpClient: new RemoteCdpClient(),
7975
+ sessionClient: new CloudSessionClient(baseUrl, key, authScheme),
7976
+ cdpClient: new CloudCdpClient(),
7977
+ appUrl: normalizeCloudAppUrl(appUrl),
7799
7978
  actionClient: null,
7800
- sessionId: null
7979
+ sessionId: null,
7980
+ localRunId: null,
7981
+ cloudSessionUrl: null
7801
7982
  };
7802
7983
  }
7803
- function resolveRemoteBaseUrl() {
7984
+ function resolveCloudBaseUrl() {
7804
7985
  const value = process.env.OPENSTEER_BASE_URL?.trim();
7805
- if (!value) return DEFAULT_REMOTE_BASE_URL;
7986
+ if (!value) return DEFAULT_CLOUD_BASE_URL;
7806
7987
  return value.replace(/\/+$/, "");
7807
7988
  }
7808
- function readRemoteActionDescription(payload) {
7989
+ function resolveCloudAppUrl() {
7990
+ const value = process.env.OPENSTEER_APP_URL?.trim();
7991
+ if (!value) return DEFAULT_CLOUD_APP_URL;
7992
+ return normalizeCloudAppUrl(value);
7993
+ }
7994
+ function normalizeCloudAppUrl(value) {
7995
+ if (!value) return null;
7996
+ return value.replace(/\/+$/, "");
7997
+ }
7998
+ function readCloudActionDescription(payload) {
7809
7999
  const description = payload.description;
7810
8000
  if (typeof description !== "string") return void 0;
7811
8001
  const normalized = description.trim();
@@ -7813,7 +8003,7 @@ function readRemoteActionDescription(payload) {
7813
8003
  }
7814
8004
 
7815
8005
  // src/opensteer.ts
7816
- var REMOTE_INTERACTION_METHODS = /* @__PURE__ */ new Set([
8006
+ var CLOUD_INTERACTION_METHODS = /* @__PURE__ */ new Set([
7817
8007
  "click",
7818
8008
  "dblclick",
7819
8009
  "rightclick",
@@ -7830,7 +8020,7 @@ var Opensteer = class _Opensteer {
7830
8020
  namespace;
7831
8021
  storage;
7832
8022
  pool;
7833
- remote;
8023
+ cloud;
7834
8024
  browser = null;
7835
8025
  pageRef = null;
7836
8026
  contextRef = null;
@@ -7838,8 +8028,8 @@ var Opensteer = class _Opensteer {
7838
8028
  snapshotCache = null;
7839
8029
  constructor(config = {}) {
7840
8030
  const resolved = resolveConfig(config);
7841
- const modeSelection = resolveModeSelection({
7842
- mode: resolved.mode
8031
+ const cloudSelection = resolveCloudSelection({
8032
+ cloud: resolved.cloud
7843
8033
  });
7844
8034
  const model = resolved.model;
7845
8035
  this.config = resolved;
@@ -7849,21 +8039,22 @@ var Opensteer = class _Opensteer {
7849
8039
  this.namespace = resolveNamespace(resolved, rootDir);
7850
8040
  this.storage = new LocalSelectorStorage(rootDir, this.namespace);
7851
8041
  this.pool = new BrowserPool(resolved.browser || {});
7852
- if (modeSelection.mode === "remote") {
7853
- const remoteConfig = resolved.remote && typeof resolved.remote === "object" ? resolved.remote : void 0;
7854
- const apiKey = remoteConfig?.apiKey?.trim();
8042
+ if (cloudSelection.cloud) {
8043
+ const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
8044
+ const apiKey = cloudConfig?.apiKey?.trim();
7855
8045
  if (!apiKey) {
7856
8046
  throw new Error(
7857
- "Remote mode requires a non-empty API key via remote.apiKey or OPENSTEER_API_KEY."
8047
+ "Cloud mode requires a non-empty API key via cloud.apiKey or OPENSTEER_API_KEY."
7858
8048
  );
7859
8049
  }
7860
- this.remote = createRemoteRuntimeState(
8050
+ this.cloud = createCloudRuntimeState(
7861
8051
  apiKey,
7862
- remoteConfig?.baseUrl,
7863
- remoteConfig?.authScheme
8052
+ cloudConfig?.baseUrl,
8053
+ cloudConfig?.authScheme,
8054
+ cloudConfig?.appUrl
7864
8055
  );
7865
8056
  } else {
7866
- this.remote = null;
8057
+ this.cloud = null;
7867
8058
  }
7868
8059
  }
7869
8060
  createLazyResolveCallback(model) {
@@ -7901,32 +8092,32 @@ var Opensteer = class _Opensteer {
7901
8092
  };
7902
8093
  return extract;
7903
8094
  }
7904
- async invokeRemoteActionAndResetCache(method, args) {
7905
- const result = await this.invokeRemoteAction(method, args);
8095
+ async invokeCloudActionAndResetCache(method, args) {
8096
+ const result = await this.invokeCloudAction(method, args);
7906
8097
  this.snapshotCache = null;
7907
8098
  return result;
7908
8099
  }
7909
- async invokeRemoteAction(method, args) {
7910
- const actionClient = this.remote?.actionClient;
7911
- const sessionId = this.remote?.sessionId;
8100
+ async invokeCloudAction(method, args) {
8101
+ const actionClient = this.cloud?.actionClient;
8102
+ const sessionId = this.cloud?.sessionId;
7912
8103
  if (!actionClient || !sessionId) {
7913
- throw remoteNotLaunchedError();
8104
+ throw cloudNotLaunchedError();
7914
8105
  }
7915
8106
  const payload = args && typeof args === "object" ? args : {};
7916
8107
  try {
7917
8108
  return await actionClient.request(method, payload);
7918
8109
  } catch (err) {
7919
- if (err instanceof OpensteerRemoteError && err.code === "REMOTE_ACTION_FAILED" && REMOTE_INTERACTION_METHODS.has(method)) {
8110
+ if (err instanceof OpensteerCloudError && err.code === "CLOUD_ACTION_FAILED" && CLOUD_INTERACTION_METHODS.has(method)) {
7920
8111
  const detailsRecord = err.details && typeof err.details === "object" ? err.details : null;
7921
- const remoteFailure = normalizeActionFailure(
8112
+ const cloudFailure = normalizeActionFailure(
7922
8113
  detailsRecord?.actionFailure
7923
8114
  );
7924
- const failure = remoteFailure || classifyActionFailure({
8115
+ const failure = cloudFailure || classifyActionFailure({
7925
8116
  action: method,
7926
8117
  error: err,
7927
8118
  fallbackMessage: defaultActionFailureMessage(method)
7928
8119
  });
7929
- const description = readRemoteActionDescription(payload);
8120
+ const description = readCloudActionDescription(payload);
7930
8121
  throw this.buildActionError(
7931
8122
  method,
7932
8123
  description,
@@ -7967,8 +8158,36 @@ var Opensteer = class _Opensteer {
7967
8158
  }
7968
8159
  return this.contextRef;
7969
8160
  }
7970
- getRemoteSessionId() {
7971
- return this.remote?.sessionId ?? null;
8161
+ getCloudSessionId() {
8162
+ return this.cloud?.sessionId ?? null;
8163
+ }
8164
+ getCloudSessionUrl() {
8165
+ return this.cloud?.cloudSessionUrl ?? null;
8166
+ }
8167
+ announceCloudSession(args) {
8168
+ if (!this.shouldAnnounceCloudSession()) {
8169
+ return;
8170
+ }
8171
+ const fields = [
8172
+ `sessionId=${args.sessionId}`,
8173
+ `workspaceId=${args.workspaceId}`
8174
+ ];
8175
+ if (args.cloudSessionUrl) {
8176
+ fields.push(`url=${args.cloudSessionUrl}`);
8177
+ }
8178
+ process.stderr.write(`[opensteer] cloud session ready ${fields.join(" ")}
8179
+ `);
8180
+ }
8181
+ shouldAnnounceCloudSession() {
8182
+ const cloudConfig = this.config.cloud && typeof this.config.cloud === "object" ? this.config.cloud : null;
8183
+ const announce = cloudConfig?.announce ?? "always";
8184
+ if (announce === "off") {
8185
+ return false;
8186
+ }
8187
+ if (announce === "tty") {
8188
+ return Boolean(process.stderr.isTTY);
8189
+ }
8190
+ return true;
7972
8191
  }
7973
8192
  async launch(options = {}) {
7974
8193
  if (this.pageRef && !this.ownsBrowser) {
@@ -7979,22 +8198,29 @@ var Opensteer = class _Opensteer {
7979
8198
  if (this.pageRef && this.ownsBrowser) {
7980
8199
  return;
7981
8200
  }
7982
- if (this.remote) {
8201
+ if (this.cloud) {
7983
8202
  let actionClient = null;
7984
8203
  let browser = null;
7985
8204
  let sessionId = null;
8205
+ let localRunId = null;
7986
8206
  try {
7987
8207
  try {
7988
- await this.syncLocalSelectorCacheToRemote();
8208
+ await this.syncLocalSelectorCacheToCloud();
7989
8209
  } catch (error) {
7990
8210
  if (this.config.debug) {
7991
8211
  const message = error instanceof Error ? error.message : String(error);
7992
8212
  console.warn(
7993
- `[opensteer] remote selector cache sync failed: ${message}`
8213
+ `[opensteer] cloud selector cache sync failed: ${message}`
7994
8214
  );
7995
8215
  }
7996
8216
  }
7997
- const session3 = await this.remote.sessionClient.create({
8217
+ localRunId = this.cloud.localRunId || buildLocalRunId(this.namespace);
8218
+ this.cloud.localRunId = localRunId;
8219
+ const session3 = await this.cloud.sessionClient.create({
8220
+ cloudSessionContractVersion,
8221
+ sourceType: "local-cloud",
8222
+ clientSessionHint: this.namespace,
8223
+ localRunId,
7998
8224
  name: this.namespace,
7999
8225
  model: this.config.model,
8000
8226
  launchContext: options.context || void 0
@@ -8005,7 +8231,7 @@ var Opensteer = class _Opensteer {
8005
8231
  token: session3.actionToken,
8006
8232
  sessionId: session3.sessionId
8007
8233
  });
8008
- const cdpConnection = await this.remote.cdpClient.connect({
8234
+ const cdpConnection = await this.cloud.cdpClient.connect({
8009
8235
  wsUrl: session3.cdpWsUrl,
8010
8236
  token: session3.cdpToken
8011
8237
  });
@@ -8015,8 +8241,17 @@ var Opensteer = class _Opensteer {
8015
8241
  this.pageRef = cdpConnection.page;
8016
8242
  this.ownsBrowser = true;
8017
8243
  this.snapshotCache = null;
8018
- this.remote.actionClient = actionClient;
8019
- this.remote.sessionId = sessionId;
8244
+ this.cloud.actionClient = actionClient;
8245
+ this.cloud.sessionId = sessionId;
8246
+ this.cloud.cloudSessionUrl = buildCloudSessionUrl(
8247
+ this.cloud.appUrl,
8248
+ session3.cloudSession.sessionId
8249
+ );
8250
+ this.announceCloudSession({
8251
+ sessionId: session3.sessionId,
8252
+ workspaceId: session3.cloudSession.workspaceId,
8253
+ cloudSessionUrl: this.cloud.cloudSessionUrl
8254
+ });
8020
8255
  return;
8021
8256
  } catch (error) {
8022
8257
  if (actionClient) {
@@ -8026,8 +8261,9 @@ var Opensteer = class _Opensteer {
8026
8261
  await browser.close().catch(() => void 0);
8027
8262
  }
8028
8263
  if (sessionId) {
8029
- await this.remote.sessionClient.close(sessionId).catch(() => void 0);
8264
+ await this.cloud.sessionClient.close(sessionId).catch(() => void 0);
8030
8265
  }
8266
+ this.cloud.cloudSessionUrl = null;
8031
8267
  throw error;
8032
8268
  }
8033
8269
  }
@@ -8045,13 +8281,13 @@ var Opensteer = class _Opensteer {
8045
8281
  }
8046
8282
  static from(page, config = {}) {
8047
8283
  const resolvedConfig = resolveConfig(config);
8048
- const modeSelection = resolveModeSelection({
8049
- mode: resolvedConfig.mode
8284
+ const cloudSelection = resolveCloudSelection({
8285
+ cloud: resolvedConfig.cloud
8050
8286
  });
8051
- if (modeSelection.mode === "remote") {
8052
- throw remoteUnsupportedMethodError(
8287
+ if (cloudSelection.cloud) {
8288
+ throw cloudUnsupportedMethodError(
8053
8289
  "Opensteer.from(page)",
8054
- "Opensteer.from(page) is not supported in remote mode."
8290
+ "Opensteer.from(page) is not supported in cloud mode."
8055
8291
  );
8056
8292
  }
8057
8293
  const instance2 = new _Opensteer(config);
@@ -8064,12 +8300,14 @@ var Opensteer = class _Opensteer {
8064
8300
  }
8065
8301
  async close() {
8066
8302
  this.snapshotCache = null;
8067
- if (this.remote) {
8068
- const actionClient = this.remote.actionClient;
8069
- const sessionId = this.remote.sessionId;
8303
+ if (this.cloud) {
8304
+ const actionClient = this.cloud.actionClient;
8305
+ const sessionId = this.cloud.sessionId;
8070
8306
  const browser = this.browser;
8071
- this.remote.actionClient = null;
8072
- this.remote.sessionId = null;
8307
+ this.cloud.actionClient = null;
8308
+ this.cloud.sessionId = null;
8309
+ this.cloud.localRunId = null;
8310
+ this.cloud.cloudSessionUrl = null;
8073
8311
  this.browser = null;
8074
8312
  this.pageRef = null;
8075
8313
  this.contextRef = null;
@@ -8081,7 +8319,7 @@ var Opensteer = class _Opensteer {
8081
8319
  await browser.close().catch(() => void 0);
8082
8320
  }
8083
8321
  if (sessionId) {
8084
- await this.remote.sessionClient.close(sessionId).catch(() => void 0);
8322
+ await this.cloud.sessionClient.close(sessionId).catch(() => void 0);
8085
8323
  }
8086
8324
  return;
8087
8325
  }
@@ -8093,17 +8331,17 @@ var Opensteer = class _Opensteer {
8093
8331
  this.contextRef = null;
8094
8332
  this.ownsBrowser = false;
8095
8333
  }
8096
- async syncLocalSelectorCacheToRemote() {
8097
- if (!this.remote) return;
8334
+ async syncLocalSelectorCacheToCloud() {
8335
+ if (!this.cloud) return;
8098
8336
  const entries = collectLocalSelectorCacheEntries(this.storage);
8099
8337
  if (!entries.length) return;
8100
- await this.remote.sessionClient.importSelectorCache({
8338
+ await this.cloud.sessionClient.importSelectorCache({
8101
8339
  entries
8102
8340
  });
8103
8341
  }
8104
8342
  async goto(url, options) {
8105
- if (this.remote) {
8106
- await this.invokeRemoteActionAndResetCache("goto", { url, options });
8343
+ if (this.cloud) {
8344
+ await this.invokeCloudActionAndResetCache("goto", { url, options });
8107
8345
  return;
8108
8346
  }
8109
8347
  const { waitUntil = "domcontentloaded", ...rest } = options ?? {};
@@ -8112,8 +8350,8 @@ var Opensteer = class _Opensteer {
8112
8350
  this.snapshotCache = null;
8113
8351
  }
8114
8352
  async snapshot(options = {}) {
8115
- if (this.remote) {
8116
- return await this.invokeRemoteActionAndResetCache("snapshot", {
8353
+ if (this.cloud) {
8354
+ return await this.invokeCloudActionAndResetCache("snapshot", {
8117
8355
  options
8118
8356
  });
8119
8357
  }
@@ -8122,8 +8360,8 @@ var Opensteer = class _Opensteer {
8122
8360
  return prepared.cleanedHtml;
8123
8361
  }
8124
8362
  async state() {
8125
- if (this.remote) {
8126
- return await this.invokeRemoteAction("state", {});
8363
+ if (this.cloud) {
8364
+ return await this.invokeCloudAction("state", {});
8127
8365
  }
8128
8366
  const html = await this.snapshot({ mode: "action" });
8129
8367
  return {
@@ -8133,8 +8371,8 @@ var Opensteer = class _Opensteer {
8133
8371
  };
8134
8372
  }
8135
8373
  async screenshot(options = {}) {
8136
- if (this.remote) {
8137
- const b64 = await this.invokeRemoteAction(
8374
+ if (this.cloud) {
8375
+ const b64 = await this.invokeCloudAction(
8138
8376
  "screenshot",
8139
8377
  options
8140
8378
  );
@@ -8148,8 +8386,8 @@ var Opensteer = class _Opensteer {
8148
8386
  });
8149
8387
  }
8150
8388
  async click(options) {
8151
- if (this.remote) {
8152
- return await this.invokeRemoteActionAndResetCache(
8389
+ if (this.cloud) {
8390
+ return await this.invokeCloudActionAndResetCache(
8153
8391
  "click",
8154
8392
  options
8155
8393
  );
@@ -8161,8 +8399,8 @@ var Opensteer = class _Opensteer {
8161
8399
  });
8162
8400
  }
8163
8401
  async dblclick(options) {
8164
- if (this.remote) {
8165
- return await this.invokeRemoteActionAndResetCache(
8402
+ if (this.cloud) {
8403
+ return await this.invokeCloudActionAndResetCache(
8166
8404
  "dblclick",
8167
8405
  options
8168
8406
  );
@@ -8174,8 +8412,8 @@ var Opensteer = class _Opensteer {
8174
8412
  });
8175
8413
  }
8176
8414
  async rightclick(options) {
8177
- if (this.remote) {
8178
- return await this.invokeRemoteActionAndResetCache(
8415
+ if (this.cloud) {
8416
+ return await this.invokeCloudActionAndResetCache(
8179
8417
  "rightclick",
8180
8418
  options
8181
8419
  );
@@ -8187,8 +8425,8 @@ var Opensteer = class _Opensteer {
8187
8425
  });
8188
8426
  }
8189
8427
  async hover(options) {
8190
- if (this.remote) {
8191
- return await this.invokeRemoteActionAndResetCache(
8428
+ if (this.cloud) {
8429
+ return await this.invokeCloudActionAndResetCache(
8192
8430
  "hover",
8193
8431
  options
8194
8432
  );
@@ -8286,8 +8524,8 @@ var Opensteer = class _Opensteer {
8286
8524
  );
8287
8525
  }
8288
8526
  async input(options) {
8289
- if (this.remote) {
8290
- return await this.invokeRemoteActionAndResetCache(
8527
+ if (this.cloud) {
8528
+ return await this.invokeCloudActionAndResetCache(
8291
8529
  "input",
8292
8530
  options
8293
8531
  );
@@ -8389,8 +8627,8 @@ var Opensteer = class _Opensteer {
8389
8627
  );
8390
8628
  }
8391
8629
  async select(options) {
8392
- if (this.remote) {
8393
- return await this.invokeRemoteActionAndResetCache(
8630
+ if (this.cloud) {
8631
+ return await this.invokeCloudActionAndResetCache(
8394
8632
  "select",
8395
8633
  options
8396
8634
  );
@@ -8499,8 +8737,8 @@ var Opensteer = class _Opensteer {
8499
8737
  );
8500
8738
  }
8501
8739
  async scroll(options = {}) {
8502
- if (this.remote) {
8503
- return await this.invokeRemoteActionAndResetCache(
8740
+ if (this.cloud) {
8741
+ return await this.invokeCloudActionAndResetCache(
8504
8742
  "scroll",
8505
8743
  options
8506
8744
  );
@@ -8601,14 +8839,14 @@ var Opensteer = class _Opensteer {
8601
8839
  }
8602
8840
  // --- Tab Management ---
8603
8841
  async tabs() {
8604
- if (this.remote) {
8605
- return await this.invokeRemoteAction("tabs", {});
8842
+ if (this.cloud) {
8843
+ return await this.invokeCloudAction("tabs", {});
8606
8844
  }
8607
8845
  return listTabs(this.context, this.page);
8608
8846
  }
8609
8847
  async newTab(url) {
8610
- if (this.remote) {
8611
- return await this.invokeRemoteActionAndResetCache("newTab", {
8848
+ if (this.cloud) {
8849
+ return await this.invokeCloudActionAndResetCache("newTab", {
8612
8850
  url
8613
8851
  });
8614
8852
  }
@@ -8618,8 +8856,8 @@ var Opensteer = class _Opensteer {
8618
8856
  return info;
8619
8857
  }
8620
8858
  async switchTab(index) {
8621
- if (this.remote) {
8622
- await this.invokeRemoteActionAndResetCache("switchTab", { index });
8859
+ if (this.cloud) {
8860
+ await this.invokeCloudActionAndResetCache("switchTab", { index });
8623
8861
  return;
8624
8862
  }
8625
8863
  const page = await switchTab(this.context, index);
@@ -8627,8 +8865,8 @@ var Opensteer = class _Opensteer {
8627
8865
  this.snapshotCache = null;
8628
8866
  }
8629
8867
  async closeTab(index) {
8630
- if (this.remote) {
8631
- await this.invokeRemoteActionAndResetCache("closeTab", { index });
8868
+ if (this.cloud) {
8869
+ await this.invokeCloudActionAndResetCache("closeTab", { index });
8632
8870
  return;
8633
8871
  }
8634
8872
  const newPage = await closeTab(this.context, this.page, index);
@@ -8639,8 +8877,8 @@ var Opensteer = class _Opensteer {
8639
8877
  }
8640
8878
  // --- Cookie Management ---
8641
8879
  async getCookies(url) {
8642
- if (this.remote) {
8643
- return await this.invokeRemoteAction(
8880
+ if (this.cloud) {
8881
+ return await this.invokeCloudAction(
8644
8882
  "getCookies",
8645
8883
  { url }
8646
8884
  );
@@ -8648,41 +8886,41 @@ var Opensteer = class _Opensteer {
8648
8886
  return getCookies(this.context, url);
8649
8887
  }
8650
8888
  async setCookie(cookie) {
8651
- if (this.remote) {
8652
- await this.invokeRemoteAction("setCookie", cookie);
8889
+ if (this.cloud) {
8890
+ await this.invokeCloudAction("setCookie", cookie);
8653
8891
  return;
8654
8892
  }
8655
8893
  return setCookie(this.context, cookie);
8656
8894
  }
8657
8895
  async clearCookies() {
8658
- if (this.remote) {
8659
- await this.invokeRemoteAction("clearCookies", {});
8896
+ if (this.cloud) {
8897
+ await this.invokeCloudAction("clearCookies", {});
8660
8898
  return;
8661
8899
  }
8662
8900
  return clearCookies(this.context);
8663
8901
  }
8664
8902
  async exportCookies(filePath, url) {
8665
- if (this.remote) {
8666
- throw remoteUnsupportedMethodError(
8903
+ if (this.cloud) {
8904
+ throw cloudUnsupportedMethodError(
8667
8905
  "exportCookies",
8668
- "exportCookies() is not supported in remote mode because it depends on local filesystem paths."
8906
+ "exportCookies() is not supported in cloud mode because it depends on local filesystem paths."
8669
8907
  );
8670
8908
  }
8671
8909
  return exportCookies(this.context, filePath, url);
8672
8910
  }
8673
8911
  async importCookies(filePath) {
8674
- if (this.remote) {
8675
- throw remoteUnsupportedMethodError(
8912
+ if (this.cloud) {
8913
+ throw cloudUnsupportedMethodError(
8676
8914
  "importCookies",
8677
- "importCookies() is not supported in remote mode because it depends on local filesystem paths."
8915
+ "importCookies() is not supported in cloud mode because it depends on local filesystem paths."
8678
8916
  );
8679
8917
  }
8680
8918
  return importCookies(this.context, filePath);
8681
8919
  }
8682
8920
  // --- Keyboard Input ---
8683
8921
  async pressKey(key) {
8684
- if (this.remote) {
8685
- await this.invokeRemoteActionAndResetCache("pressKey", { key });
8922
+ if (this.cloud) {
8923
+ await this.invokeCloudActionAndResetCache("pressKey", { key });
8686
8924
  return;
8687
8925
  }
8688
8926
  await this.runWithPostActionWait("pressKey", void 0, async () => {
@@ -8691,8 +8929,8 @@ var Opensteer = class _Opensteer {
8691
8929
  this.snapshotCache = null;
8692
8930
  }
8693
8931
  async type(text) {
8694
- if (this.remote) {
8695
- await this.invokeRemoteActionAndResetCache("type", { text });
8932
+ if (this.cloud) {
8933
+ await this.invokeCloudActionAndResetCache("type", { text });
8696
8934
  return;
8697
8935
  }
8698
8936
  await this.runWithPostActionWait("type", void 0, async () => {
@@ -8702,8 +8940,8 @@ var Opensteer = class _Opensteer {
8702
8940
  }
8703
8941
  // --- Element Info ---
8704
8942
  async getElementText(options) {
8705
- if (this.remote) {
8706
- return await this.invokeRemoteAction("getElementText", options);
8943
+ if (this.cloud) {
8944
+ return await this.invokeCloudAction("getElementText", options);
8707
8945
  }
8708
8946
  return this.executeElementInfoAction(
8709
8947
  "getElementText",
@@ -8716,8 +8954,8 @@ var Opensteer = class _Opensteer {
8716
8954
  );
8717
8955
  }
8718
8956
  async getElementValue(options) {
8719
- if (this.remote) {
8720
- return await this.invokeRemoteAction(
8957
+ if (this.cloud) {
8958
+ return await this.invokeCloudAction(
8721
8959
  "getElementValue",
8722
8960
  options
8723
8961
  );
@@ -8732,8 +8970,8 @@ var Opensteer = class _Opensteer {
8732
8970
  );
8733
8971
  }
8734
8972
  async getElementAttributes(options) {
8735
- if (this.remote) {
8736
- return await this.invokeRemoteAction(
8973
+ if (this.cloud) {
8974
+ return await this.invokeCloudAction(
8737
8975
  "getElementAttributes",
8738
8976
  options
8739
8977
  );
@@ -8754,8 +8992,8 @@ var Opensteer = class _Opensteer {
8754
8992
  );
8755
8993
  }
8756
8994
  async getElementBoundingBox(options) {
8757
- if (this.remote) {
8758
- return await this.invokeRemoteAction(
8995
+ if (this.cloud) {
8996
+ return await this.invokeCloudAction(
8759
8997
  "getElementBoundingBox",
8760
8998
  options
8761
8999
  );
@@ -8770,14 +9008,14 @@ var Opensteer = class _Opensteer {
8770
9008
  );
8771
9009
  }
8772
9010
  async getHtml(selector) {
8773
- if (this.remote) {
8774
- return await this.invokeRemoteAction("getHtml", { selector });
9011
+ if (this.cloud) {
9012
+ return await this.invokeCloudAction("getHtml", { selector });
8775
9013
  }
8776
9014
  return getPageHtml(this.page, selector);
8777
9015
  }
8778
9016
  async getTitle() {
8779
- if (this.remote) {
8780
- return await this.invokeRemoteAction("getTitle", {});
9017
+ if (this.cloud) {
9018
+ return await this.invokeCloudAction("getTitle", {});
8781
9019
  }
8782
9020
  return getPageTitle(this.page);
8783
9021
  }
@@ -8815,10 +9053,10 @@ var Opensteer = class _Opensteer {
8815
9053
  }
8816
9054
  // --- File Upload ---
8817
9055
  async uploadFile(options) {
8818
- if (this.remote) {
8819
- throw remoteUnsupportedMethodError(
9056
+ if (this.cloud) {
9057
+ throw cloudUnsupportedMethodError(
8820
9058
  "uploadFile",
8821
- "uploadFile() is not supported in remote mode because file paths must be accessible on the remote server."
9059
+ "uploadFile() is not supported in cloud mode because file paths must be accessible on the cloud runtime."
8822
9060
  );
8823
9061
  }
8824
9062
  const storageKey = this.resolveStorageKey(options.description);
@@ -8920,15 +9158,15 @@ var Opensteer = class _Opensteer {
8920
9158
  }
8921
9159
  // --- Wait for Text ---
8922
9160
  async waitForText(text, options) {
8923
- if (this.remote) {
8924
- await this.invokeRemoteAction("waitForText", { text, options });
9161
+ if (this.cloud) {
9162
+ await this.invokeCloudAction("waitForText", { text, options });
8925
9163
  return;
8926
9164
  }
8927
9165
  await this.page.getByText(text).first().waitFor({ timeout: options?.timeout ?? 3e4 });
8928
9166
  }
8929
9167
  async extract(options) {
8930
- if (this.remote) {
8931
- return await this.invokeRemoteAction("extract", options);
9168
+ if (this.cloud) {
9169
+ return await this.invokeCloudAction("extract", options);
8932
9170
  }
8933
9171
  const storageKey = this.resolveStorageKey(options.description);
8934
9172
  const schemaHash = options.schema ? computeSchemaHash(options.schema) : null;
@@ -8980,8 +9218,8 @@ var Opensteer = class _Opensteer {
8980
9218
  return inflateDataPathObject(data);
8981
9219
  }
8982
9220
  async extractFromPlan(options) {
8983
- if (this.remote) {
8984
- return await this.invokeRemoteAction(
9221
+ if (this.cloud) {
9222
+ return await this.invokeCloudAction(
8985
9223
  "extractFromPlan",
8986
9224
  options
8987
9225
  );
@@ -9030,10 +9268,10 @@ var Opensteer = class _Opensteer {
9030
9268
  return this.storage;
9031
9269
  }
9032
9270
  clearCache() {
9033
- if (this.remote) {
9271
+ if (this.cloud) {
9034
9272
  this.snapshotCache = null;
9035
- if (!this.remote.actionClient) return;
9036
- void this.invokeRemoteAction("clearCache", {});
9273
+ if (!this.cloud.actionClient) return;
9274
+ void this.invokeCloudAction("clearCache", {});
9037
9275
  return;
9038
9276
  }
9039
9277
  this.storage.clearNamespace();
@@ -10061,6 +10299,16 @@ function getScrollDelta2(options) {
10061
10299
  return { x: 0, y: absoluteAmount };
10062
10300
  }
10063
10301
  }
10302
+ function buildLocalRunId(namespace) {
10303
+ const normalized = namespace.trim() || "default";
10304
+ return `${normalized}-${Date.now().toString(36)}-${(0, import_crypto2.randomUUID)().slice(0, 8)}`;
10305
+ }
10306
+ function buildCloudSessionUrl(appUrl, sessionId) {
10307
+ if (!appUrl) {
10308
+ return null;
10309
+ }
10310
+ return `${appUrl}/browser/${encodeURIComponent(sessionId)}`;
10311
+ }
10064
10312
 
10065
10313
  // src/cli/paths.ts
10066
10314
  var import_os2 = require("os");
@@ -10462,7 +10710,8 @@ async function handleRequest(request, socket) {
10462
10710
  url: instance.page.url(),
10463
10711
  session,
10464
10712
  name: activeNamespace,
10465
- remoteSessionId: instance.getRemoteSessionId() ?? void 0
10713
+ cloudSessionId: instance.getCloudSessionId() ?? void 0,
10714
+ cloudSessionUrl: instance.getCloudSessionUrl() ?? void 0
10466
10715
  }
10467
10716
  });
10468
10717
  } catch (err) {