opensteer 0.8.2 → 0.8.3

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.
@@ -14,6 +14,7 @@ import * as cheerio from 'cheerio';
14
14
  import * as prettier from 'prettier';
15
15
  import vm from 'vm';
16
16
  import { gzip as gzip$1 } from 'zlib';
17
+ import WebSocket2 from 'ws';
17
18
 
18
19
  // ../protocol/src/dom-action-bridge.ts
19
20
  var OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL = /* @__PURE__ */ Symbol.for("@opensteer/dom-action-bridge");
@@ -25,7 +26,7 @@ function resolveDomActionBridge(engine) {
25
26
  return isDomActionBridgeFactory(candidate) ? candidate.call(engine) : void 0;
26
27
  }
27
28
 
28
- // src/json.ts
29
+ // ../runtime-core/src/json.ts
29
30
  function isPlainObject(value) {
30
31
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
31
32
  return false;
@@ -33,30 +34,30 @@ function isPlainObject(value) {
33
34
  const prototype = Object.getPrototypeOf(value);
34
35
  return prototype === Object.prototype || prototype === null;
35
36
  }
36
- function canonicalizeJsonValue(value, path11) {
37
+ function canonicalizeJsonValue(value, path13) {
37
38
  if (value === null || typeof value === "string" || typeof value === "boolean") {
38
39
  return value;
39
40
  }
40
41
  if (typeof value === "number") {
41
42
  if (!Number.isFinite(value)) {
42
- throw new TypeError(`${path11} must be a finite JSON number`);
43
+ throw new TypeError(`${path13} must be a finite JSON number`);
43
44
  }
44
45
  return value;
45
46
  }
46
47
  if (Array.isArray(value)) {
47
- return value.map((entry, index) => canonicalizeJsonValue(entry, `${path11}[${index}]`));
48
+ return value.map((entry, index) => canonicalizeJsonValue(entry, `${path13}[${index}]`));
48
49
  }
49
50
  if (!isPlainObject(value)) {
50
- throw new TypeError(`${path11} must be a plain JSON object`);
51
+ throw new TypeError(`${path13} must be a plain JSON object`);
51
52
  }
52
53
  const sorted = Object.keys(value).sort((left, right) => left.localeCompare(right));
53
54
  const result = {};
54
55
  for (const key of sorted) {
55
56
  const entry = value[key];
56
57
  if (entry === void 0) {
57
- throw new TypeError(`${path11}.${key} must not be undefined`);
58
+ throw new TypeError(`${path13}.${key} must not be undefined`);
58
59
  }
59
- result[key] = canonicalizeJsonValue(entry, `${path11}.${key}`);
60
+ result[key] = canonicalizeJsonValue(entry, `${path13}.${key}`);
60
61
  }
61
62
  return result;
62
63
  }
@@ -71,7 +72,7 @@ function stableJsonString(value) {
71
72
  `;
72
73
  }
73
74
 
74
- // src/internal/filesystem.ts
75
+ // ../runtime-core/src/internal/filesystem.ts
75
76
  var LOCK_RETRY_DELAYS_MS = [1, 2, 5, 10, 20, 50];
76
77
  function normalizeNonEmptyString(name, value) {
77
78
  const normalized = value.trim();
@@ -199,7 +200,7 @@ async function withFilesystemLock(lockPath, task) {
199
200
  }
200
201
  }
201
202
 
202
- // src/artifacts.ts
203
+ // ../runtime-core/src/artifacts.ts
203
204
  function normalizeScope(scope) {
204
205
  if (scope === void 0) {
205
206
  return {};
@@ -553,31 +554,31 @@ function oneOfSchema(members, options = {}) {
553
554
  }
554
555
 
555
556
  // ../protocol/src/validation.ts
556
- function validateJsonSchema(schema, value, path11 = "$") {
557
- return validateSchemaNode(schema, value, path11);
557
+ function validateJsonSchema(schema, value, path13 = "$") {
558
+ return validateSchemaNode(schema, value, path13);
558
559
  }
559
- function validateSchemaNode(schema, value, path11) {
560
+ function validateSchemaNode(schema, value, path13) {
560
561
  const issues = [];
561
562
  if ("const" in schema && !isJsonValueEqual(schema.const, value)) {
562
563
  issues.push({
563
- path: path11,
564
+ path: path13,
564
565
  message: `must equal ${JSON.stringify(schema.const)}`
565
566
  });
566
567
  return issues;
567
568
  }
568
569
  if (schema.enum !== void 0 && !schema.enum.some((candidate) => isJsonValueEqual(candidate, value))) {
569
570
  issues.push({
570
- path: path11,
571
+ path: path13,
571
572
  message: `must be one of ${schema.enum.map((candidate) => JSON.stringify(candidate)).join(", ")}`
572
573
  });
573
574
  return issues;
574
575
  }
575
576
  if (schema.oneOf !== void 0) {
576
- const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path11));
577
+ const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path13));
577
578
  const validBranches = branchIssues.filter((current) => current.length === 0).length;
578
579
  if (validBranches !== 1) {
579
580
  issues.push({
580
- path: path11,
581
+ path: path13,
581
582
  message: validBranches === 0 ? "must match exactly one supported shape" : "matches multiple supported shapes"
582
583
  });
583
584
  return issues;
@@ -585,11 +586,11 @@ function validateSchemaNode(schema, value, path11) {
585
586
  }
586
587
  if (schema.anyOf !== void 0) {
587
588
  const hasMatch = schema.anyOf.some(
588
- (member) => validateSchemaNode(member, value, path11).length === 0
589
+ (member) => validateSchemaNode(member, value, path13).length === 0
589
590
  );
590
591
  if (!hasMatch) {
591
592
  issues.push({
592
- path: path11,
593
+ path: path13,
593
594
  message: "must match at least one supported shape"
594
595
  });
595
596
  return issues;
@@ -597,7 +598,7 @@ function validateSchemaNode(schema, value, path11) {
597
598
  }
598
599
  if (schema.allOf !== void 0) {
599
600
  for (const member of schema.allOf) {
600
- issues.push(...validateSchemaNode(member, value, path11));
601
+ issues.push(...validateSchemaNode(member, value, path13));
601
602
  }
602
603
  if (issues.length > 0) {
603
604
  return issues;
@@ -605,7 +606,7 @@ function validateSchemaNode(schema, value, path11) {
605
606
  }
606
607
  if (schema.type !== void 0 && !matchesSchemaType(schema.type, value)) {
607
608
  issues.push({
608
- path: path11,
609
+ path: path13,
609
610
  message: `must be ${describeSchemaType(schema.type)}`
610
611
  });
611
612
  return issues;
@@ -613,19 +614,19 @@ function validateSchemaNode(schema, value, path11) {
613
614
  if (typeof value === "string") {
614
615
  if (schema.minLength !== void 0 && value.length < schema.minLength) {
615
616
  issues.push({
616
- path: path11,
617
+ path: path13,
617
618
  message: `must have length >= ${String(schema.minLength)}`
618
619
  });
619
620
  }
620
621
  if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
621
622
  issues.push({
622
- path: path11,
623
+ path: path13,
623
624
  message: `must have length <= ${String(schema.maxLength)}`
624
625
  });
625
626
  }
626
627
  if (schema.pattern !== void 0 && !new RegExp(schema.pattern).test(value)) {
627
628
  issues.push({
628
- path: path11,
629
+ path: path13,
629
630
  message: `must match pattern ${schema.pattern}`
630
631
  });
631
632
  }
@@ -634,25 +635,25 @@ function validateSchemaNode(schema, value, path11) {
634
635
  if (typeof value === "number") {
635
636
  if (schema.minimum !== void 0 && value < schema.minimum) {
636
637
  issues.push({
637
- path: path11,
638
+ path: path13,
638
639
  message: `must be >= ${String(schema.minimum)}`
639
640
  });
640
641
  }
641
642
  if (schema.maximum !== void 0 && value > schema.maximum) {
642
643
  issues.push({
643
- path: path11,
644
+ path: path13,
644
645
  message: `must be <= ${String(schema.maximum)}`
645
646
  });
646
647
  }
647
648
  if (schema.exclusiveMinimum !== void 0 && value <= schema.exclusiveMinimum) {
648
649
  issues.push({
649
- path: path11,
650
+ path: path13,
650
651
  message: `must be > ${String(schema.exclusiveMinimum)}`
651
652
  });
652
653
  }
653
654
  if (schema.exclusiveMaximum !== void 0 && value >= schema.exclusiveMaximum) {
654
655
  issues.push({
655
- path: path11,
656
+ path: path13,
656
657
  message: `must be < ${String(schema.exclusiveMaximum)}`
657
658
  });
658
659
  }
@@ -661,13 +662,13 @@ function validateSchemaNode(schema, value, path11) {
661
662
  if (Array.isArray(value)) {
662
663
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
663
664
  issues.push({
664
- path: path11,
665
+ path: path13,
665
666
  message: `must have at least ${String(schema.minItems)} items`
666
667
  });
667
668
  }
668
669
  if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
669
670
  issues.push({
670
- path: path11,
671
+ path: path13,
671
672
  message: `must have at most ${String(schema.maxItems)} items`
672
673
  });
673
674
  }
@@ -677,7 +678,7 @@ function validateSchemaNode(schema, value, path11) {
677
678
  const key = JSON.stringify(item);
678
679
  if (seen.has(key)) {
679
680
  issues.push({
680
- path: path11,
681
+ path: path13,
681
682
  message: "must not contain duplicate items"
682
683
  });
683
684
  break;
@@ -687,7 +688,7 @@ function validateSchemaNode(schema, value, path11) {
687
688
  }
688
689
  if (schema.items !== void 0) {
689
690
  for (let index = 0; index < value.length; index += 1) {
690
- issues.push(...validateSchemaNode(schema.items, value[index], `${path11}[${String(index)}]`));
691
+ issues.push(...validateSchemaNode(schema.items, value[index], `${path13}[${String(index)}]`));
691
692
  }
692
693
  }
693
694
  return issues;
@@ -697,7 +698,7 @@ function validateSchemaNode(schema, value, path11) {
697
698
  for (const requiredKey of schema.required ?? []) {
698
699
  if (!(requiredKey in value)) {
699
700
  issues.push({
700
- path: joinObjectPath(path11, requiredKey),
701
+ path: joinObjectPath(path13, requiredKey),
701
702
  message: "is required"
702
703
  });
703
704
  }
@@ -706,13 +707,13 @@ function validateSchemaNode(schema, value, path11) {
706
707
  const propertySchema = properties[key];
707
708
  if (propertySchema !== void 0) {
708
709
  issues.push(
709
- ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path11, key))
710
+ ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path13, key))
710
711
  );
711
712
  continue;
712
713
  }
713
714
  if (schema.additionalProperties === false) {
714
715
  issues.push({
715
- path: joinObjectPath(path11, key),
716
+ path: joinObjectPath(path13, key),
716
717
  message: "is not allowed"
717
718
  });
718
719
  continue;
@@ -722,7 +723,7 @@ function validateSchemaNode(schema, value, path11) {
722
723
  ...validateSchemaNode(
723
724
  schema.additionalProperties,
724
725
  propertyValue,
725
- joinObjectPath(path11, key)
726
+ joinObjectPath(path13, key)
726
727
  )
727
728
  );
728
729
  }
@@ -966,8 +967,8 @@ function matchesNetworkRecordFilters(record, filters) {
966
967
  }
967
968
  }
968
969
  if (filters.path !== void 0) {
969
- const path11 = getParsedUrl().pathname;
970
- if (!includesCaseInsensitive(path11, filters.path)) {
970
+ const path13 = getParsedUrl().pathname;
971
+ if (!includesCaseInsensitive(path13, filters.path)) {
971
972
  return false;
972
973
  }
973
974
  }
@@ -5682,6 +5683,65 @@ var opensteerComputerAnnotationNames = [
5682
5683
  "grid",
5683
5684
  "selected"
5684
5685
  ];
5686
+ var opensteerSemanticOperationNames = [
5687
+ "session.open",
5688
+ "page.list",
5689
+ "page.new",
5690
+ "page.activate",
5691
+ "page.close",
5692
+ "page.goto",
5693
+ "page.evaluate",
5694
+ "page.add-init-script",
5695
+ "page.snapshot",
5696
+ "dom.click",
5697
+ "dom.hover",
5698
+ "dom.input",
5699
+ "dom.scroll",
5700
+ "dom.extract",
5701
+ "network.query",
5702
+ "network.save",
5703
+ "network.clear",
5704
+ "network.minimize",
5705
+ "network.diff",
5706
+ "network.probe",
5707
+ "reverse.discover",
5708
+ "reverse.query",
5709
+ "reverse.package.create",
5710
+ "reverse.package.run",
5711
+ "reverse.export",
5712
+ "reverse.report",
5713
+ "reverse.package.get",
5714
+ "reverse.package.list",
5715
+ "reverse.package.patch",
5716
+ "interaction.capture",
5717
+ "interaction.get",
5718
+ "interaction.diff",
5719
+ "interaction.replay",
5720
+ "artifact.read",
5721
+ "inspect.cookies",
5722
+ "inspect.storage",
5723
+ "scripts.capture",
5724
+ "scripts.beautify",
5725
+ "scripts.deobfuscate",
5726
+ "scripts.sandbox",
5727
+ "captcha.solve",
5728
+ "request.raw",
5729
+ "request-plan.infer",
5730
+ "request-plan.write",
5731
+ "request-plan.get",
5732
+ "request-plan.list",
5733
+ "recipe.write",
5734
+ "recipe.get",
5735
+ "recipe.list",
5736
+ "recipe.run",
5737
+ "auth-recipe.write",
5738
+ "auth-recipe.get",
5739
+ "auth-recipe.list",
5740
+ "auth-recipe.run",
5741
+ "request.execute",
5742
+ "computer.execute",
5743
+ "session.close"
5744
+ ];
5685
5745
  function defineSemanticOperationSpec(spec) {
5686
5746
  return spec;
5687
5747
  }
@@ -6971,7 +7031,7 @@ function resolveComputerUseBridge(engine) {
6971
7031
  return isComputerUseBridgeFactory(candidate) ? candidate.call(engine) : void 0;
6972
7032
  }
6973
7033
 
6974
- // src/registry.ts
7034
+ // ../runtime-core/src/registry.ts
6975
7035
  function normalizeTags(tags) {
6976
7036
  if (tags === void 0) {
6977
7037
  return [];
@@ -8205,7 +8265,7 @@ function createTraceStore(rootPath, artifacts) {
8205
8265
  return new FilesystemTraceStore(rootPath, artifacts);
8206
8266
  }
8207
8267
 
8208
- // src/root.ts
8268
+ // ../runtime-core/src/root.ts
8209
8269
  var OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT = "opensteer-workspace";
8210
8270
  var OPENSTEER_FILESYSTEM_WORKSPACE_VERSION = 2;
8211
8271
  function normalizeWorkspaceId(workspace) {
@@ -8226,6 +8286,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8226
8286
  const browserManifestPath = path6.join(browserPath, "manifest.json");
8227
8287
  const browserUserDataDir = path6.join(browserPath, "user-data");
8228
8288
  const livePath = path6.join(options.rootPath, "live");
8289
+ const liveSessionPath = path6.join(livePath, "session.json");
8229
8290
  const liveBrowserPath = path6.join(livePath, "browser.json");
8230
8291
  const artifactsPath = path6.join(options.rootPath, "artifacts");
8231
8292
  const tracesPath = path6.join(options.rootPath, "traces");
@@ -8301,6 +8362,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8301
8362
  browserManifestPath,
8302
8363
  browserUserDataDir,
8303
8364
  livePath,
8365
+ liveSessionPath,
8304
8366
  liveBrowserPath,
8305
8367
  artifactsPath,
8306
8368
  tracesPath,
@@ -8325,7 +8387,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8325
8387
  };
8326
8388
  }
8327
8389
 
8328
- // src/policy/defaults.ts
8390
+ // ../runtime-core/src/policy/defaults.ts
8329
8391
  var DEFAULT_TIMEOUTS = {
8330
8392
  "session.open": 3e4,
8331
8393
  "page.goto": 3e4,
@@ -8408,7 +8470,7 @@ function defaultPolicy() {
8408
8470
  return DEFAULT_POLICY;
8409
8471
  }
8410
8472
 
8411
- // src/policy/settle.ts
8473
+ // ../runtime-core/src/policy/settle.ts
8412
8474
  async function settleWithPolicy(policy, input) {
8413
8475
  for (const observer of policy.observers ?? []) {
8414
8476
  if (await observer.settle(input)) {
@@ -8447,7 +8509,7 @@ function abortError() {
8447
8509
  return error;
8448
8510
  }
8449
8511
 
8450
- // src/policy/timeout.ts
8512
+ // ../runtime-core/src/policy/timeout.ts
8451
8513
  var PolicyTimeoutController = class {
8452
8514
  constructor(input, budgetMs) {
8453
8515
  this.input = input;
@@ -8557,7 +8619,7 @@ function abortError2() {
8557
8619
  return error;
8558
8620
  }
8559
8621
 
8560
- // src/runtimes/dom/match-policy.ts
8622
+ // ../runtime-core/src/runtimes/dom/match-policy.ts
8561
8623
  var ATTRIBUTE_DENY_KEYS = /* @__PURE__ */ new Set([
8562
8624
  "style",
8563
8625
  "nonce",
@@ -8789,7 +8851,7 @@ function getClauseAttributeValue(node, clause) {
8789
8851
  return String(raw);
8790
8852
  }
8791
8853
 
8792
- // src/runtimes/dom/match-selectors.ts
8854
+ // ../runtime-core/src/runtimes/dom/match-selectors.ts
8793
8855
  function buildPathCandidates(domPath) {
8794
8856
  const nodes = Array.isArray(domPath) ? domPath : [];
8795
8857
  if (!nodes.length) {
@@ -8874,7 +8936,7 @@ function buildSuffixCandidates(segments) {
8874
8936
  return out;
8875
8937
  }
8876
8938
 
8877
- // src/runtimes/dom/extraction.ts
8939
+ // ../runtime-core/src/runtimes/dom/extraction.ts
8878
8940
  var URL_LIST_ATTRIBUTES = /* @__PURE__ */ new Set(["srcset", "imagesrcset", "ping"]);
8879
8941
  var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8880
8942
  "href",
@@ -8886,9 +8948,9 @@ var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8886
8948
  "poster",
8887
8949
  "ping"
8888
8950
  ]);
8889
- function buildArrayFieldPathCandidates(path11) {
8890
- const strict = path11.nodes.length ? buildPathCandidates(path11.nodes) : [];
8891
- const relaxedNodes = stripPositionClauses(path11.nodes);
8951
+ function buildArrayFieldPathCandidates(path13) {
8952
+ const strict = path13.nodes.length ? buildPathCandidates(path13.nodes) : [];
8953
+ const relaxedNodes = stripPositionClauses(path13.nodes);
8892
8954
  const relaxed = relaxedNodes.length ? buildPathCandidates(relaxedNodes) : [];
8893
8955
  return dedupeSelectors([...strict, ...relaxed]);
8894
8956
  }
@@ -9121,7 +9183,7 @@ function readDescriptorToken(value, index) {
9121
9183
  };
9122
9184
  }
9123
9185
 
9124
- // src/runtimes/dom/errors.ts
9186
+ // ../runtime-core/src/runtimes/dom/errors.ts
9125
9187
  var ElementPathError = class extends Error {
9126
9188
  code;
9127
9189
  constructor(code, message) {
@@ -9197,6 +9259,45 @@ var selectorAdapter = {
9197
9259
  },
9198
9260
  equals(left, right) {
9199
9261
  return left === right;
9262
+ },
9263
+ existsOne(test, nodes) {
9264
+ return selectorAdapter.findOne(test, nodes) !== null;
9265
+ },
9266
+ findAll(test, nodes) {
9267
+ const matches = [];
9268
+ const visit = (node) => {
9269
+ if (selectorAdapter.isTag(node) && test(node)) {
9270
+ matches.push(node);
9271
+ }
9272
+ for (const child of selectorAdapter.getChildren(node)) {
9273
+ visit(child);
9274
+ }
9275
+ };
9276
+ for (const node of nodes) {
9277
+ visit(node);
9278
+ }
9279
+ return matches;
9280
+ },
9281
+ findOne(test, nodes) {
9282
+ const visit = (node) => {
9283
+ if (selectorAdapter.isTag(node) && test(node)) {
9284
+ return node;
9285
+ }
9286
+ for (const child of selectorAdapter.getChildren(node)) {
9287
+ const match = visit(child);
9288
+ if (match !== null) {
9289
+ return match;
9290
+ }
9291
+ }
9292
+ return null;
9293
+ };
9294
+ for (const node of nodes) {
9295
+ const match = visit(node);
9296
+ if (match !== null) {
9297
+ return match;
9298
+ }
9299
+ }
9300
+ return null;
9200
9301
  }
9201
9302
  };
9202
9303
  function createDomSnapshotIndex(snapshot) {
@@ -9380,7 +9481,7 @@ function sortNodes(nodes) {
9380
9481
  return [...nodes].sort((left, right) => left.snapshotNodeId - right.snapshotNodeId);
9381
9482
  }
9382
9483
 
9383
- // src/runtimes/dom/path.ts
9484
+ // ../runtime-core/src/runtimes/dom/path.ts
9384
9485
  var MAX_ATTRIBUTE_VALUE_LENGTH = 300;
9385
9486
  function cloneStructuralElementAnchor(anchor) {
9386
9487
  return {
@@ -9389,18 +9490,18 @@ function cloneStructuralElementAnchor(anchor) {
9389
9490
  nodes: anchor.nodes.map(clonePathNode)
9390
9491
  };
9391
9492
  }
9392
- function cloneReplayElementPath(path11) {
9493
+ function cloneReplayElementPath(path13) {
9393
9494
  return {
9394
9495
  resolution: "deterministic",
9395
- context: cloneContext(path11.context),
9396
- nodes: path11.nodes.map(clonePathNode)
9496
+ context: cloneContext(path13.context),
9497
+ nodes: path13.nodes.map(clonePathNode)
9397
9498
  };
9398
9499
  }
9399
- function cloneElementPath(path11) {
9400
- return cloneReplayElementPath(path11);
9500
+ function cloneElementPath(path13) {
9501
+ return cloneReplayElementPath(path13);
9401
9502
  }
9402
- function buildPathSelectorHint(path11) {
9403
- const nodes = path11?.nodes || [];
9503
+ function buildPathSelectorHint(path13) {
9504
+ const nodes = path13?.nodes || [];
9404
9505
  const last = nodes[nodes.length - 1];
9405
9506
  if (!last) {
9406
9507
  return "*";
@@ -9449,15 +9550,15 @@ function sanitizeStructuralElementAnchor(anchor) {
9449
9550
  nodes: sanitizeNodes(anchor.nodes)
9450
9551
  };
9451
9552
  }
9452
- function sanitizeReplayElementPath(path11) {
9553
+ function sanitizeReplayElementPath(path13) {
9453
9554
  return {
9454
9555
  resolution: "deterministic",
9455
- context: sanitizeContext(path11.context),
9456
- nodes: sanitizeNodes(path11.nodes)
9556
+ context: sanitizeContext(path13.context),
9557
+ nodes: sanitizeNodes(path13.nodes)
9457
9558
  };
9458
9559
  }
9459
- function sanitizeElementPath(path11) {
9460
- return sanitizeReplayElementPath(path11);
9560
+ function sanitizeElementPath(path13) {
9561
+ return sanitizeReplayElementPath(path13);
9461
9562
  }
9462
9563
  function buildLocalStructuralElementAnchor(index, rawTargetNode) {
9463
9564
  const targetNode = requireElementNode(index, rawTargetNode);
@@ -9580,8 +9681,8 @@ function buildTargetNotFoundMessage(domPath, diagnostics) {
9580
9681
  }
9581
9682
  return `${base} Target depth ${String(depth)}. Candidate counts: ${sample}.`;
9582
9683
  }
9583
- function buildArrayFieldCandidates(path11) {
9584
- return buildArrayFieldPathCandidates(path11);
9684
+ function buildArrayFieldCandidates(path13) {
9685
+ return buildArrayFieldPathCandidates(path13);
9585
9686
  }
9586
9687
  function firstDefinedAttribute(node, keys) {
9587
9688
  for (const key of keys) {
@@ -9997,7 +10098,7 @@ var MemoryDomDescriptorStore = class {
9997
10098
  }
9998
10099
  };
9999
10100
 
10000
- // src/runtimes/dom/executor.ts
10101
+ // ../runtime-core/src/runtimes/dom/executor.ts
10001
10102
  var MAX_DOM_ACTION_ATTEMPTS = 3;
10002
10103
  var DEFAULT_SCROLL_OPTIONS = {
10003
10104
  block: "center",
@@ -10561,7 +10662,7 @@ function pointFallsWithinQuads(point, quads) {
10561
10662
  return quads.some((quad) => rectContainsPoint(quadBounds(quad), point));
10562
10663
  }
10563
10664
 
10564
- // src/runtimes/dom/runtime.ts
10665
+ // ../runtime-core/src/runtimes/dom/runtime.ts
10565
10666
  var SnapshotSession = class {
10566
10667
  constructor(engine) {
10567
10668
  this.engine = engine;
@@ -10965,21 +11066,21 @@ var DefaultDomRuntime = class {
10965
11066
  return match;
10966
11067
  }
10967
11068
  async resolvePathTarget(session, pageRef, rawPath, source, description, descriptor) {
10968
- const path11 = sanitizeReplayElementPath(rawPath);
10969
- const context = await this.resolvePathContext(session, pageRef, path11.context);
10970
- const target = resolveDomPathInScope(context.index, path11.nodes, context.scope);
11069
+ const path13 = sanitizeReplayElementPath(rawPath);
11070
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11071
+ const target = resolveDomPathInScope(context.index, path13.nodes, context.scope);
10971
11072
  if (!target) {
10972
- throwTargetNotFound(context.index, path11.nodes, context.scope);
11073
+ throwTargetNotFound(context.index, path13.nodes, context.scope);
10973
11074
  }
10974
11075
  if (target.node.nodeRef === void 0) {
10975
11076
  throw new Error(
10976
- `resolved path "${buildPathSelectorHint(path11)}" does not point to a live element`
11077
+ `resolved path "${buildPathSelectorHint(path13)}" does not point to a live element`
10977
11078
  );
10978
11079
  }
10979
11080
  const anchor = await this.buildAnchorFromSnapshotNode(session, context.snapshot, target.node);
10980
11081
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
10981
11082
  ...description === void 0 ? {} : { description },
10982
- replayPath: path11,
11083
+ replayPath: path13,
10983
11084
  ...source === "path" || source === "descriptor" ? { selectorUsed: target.selector } : {},
10984
11085
  ...descriptor === void 0 ? {} : { descriptor }
10985
11086
  });
@@ -11000,9 +11101,9 @@ var DefaultDomRuntime = class {
11000
11101
  });
11001
11102
  }
11002
11103
  async queryAllByElementPath(session, pageRef, rawPath) {
11003
- const path11 = sanitizeReplayElementPath(rawPath);
11004
- const context = await this.resolvePathContext(session, pageRef, path11.context);
11005
- return queryAllDomPathInScope(context.index, path11.nodes, context.scope).filter(
11104
+ const path13 = sanitizeReplayElementPath(rawPath);
11105
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11106
+ return queryAllDomPathInScope(context.index, path13.nodes, context.scope).filter(
11006
11107
  (node) => node.nodeRef !== void 0
11007
11108
  ).map((node) => this.createSnapshotTarget(context.snapshot, node));
11008
11109
  }
@@ -11188,16 +11289,16 @@ var DefaultDomRuntime = class {
11188
11289
  const index = createSnapshotIndex(item.snapshot);
11189
11290
  return this.resolveFirstArrayFieldTargetInNode(index, item.node, field.path);
11190
11291
  }
11191
- resolveFirstArrayFieldTargetInNode(index, rootNode, path11) {
11192
- const normalizedPath = sanitizeElementPath(path11);
11292
+ resolveFirstArrayFieldTargetInNode(index, rootNode, path13) {
11293
+ const normalizedPath = sanitizeElementPath(path13);
11193
11294
  const selectors = buildArrayFieldCandidates(normalizedPath);
11194
11295
  if (!selectors.length) {
11195
11296
  return rootNode;
11196
11297
  }
11197
11298
  return resolveFirstWithinNodeBySelectors(index, rootNode, selectors);
11198
11299
  }
11199
- resolveUniqueArrayFieldTargetInNode(index, rootNode, path11) {
11200
- const normalizedPath = sanitizeElementPath(path11);
11300
+ resolveUniqueArrayFieldTargetInNode(index, rootNode, path13) {
11301
+ const normalizedPath = sanitizeElementPath(path13);
11201
11302
  const selectors = buildArrayFieldCandidates(normalizedPath);
11202
11303
  if (!selectors.length) {
11203
11304
  return rootNode;
@@ -12007,8 +12108,8 @@ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
12007
12108
  const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
12008
12109
  return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
12009
12110
  }
12010
- function normalizeWebSocketPath(path11) {
12011
- return path11.startsWith("/") ? path11 : `/${path11}`;
12111
+ function normalizeWebSocketPath(path13) {
12112
+ return path13.startsWith("/") ? path13 : `/${path13}`;
12012
12113
  }
12013
12114
  function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
12014
12115
  try {
@@ -12025,8 +12126,115 @@ function readPort(url) {
12025
12126
  const port = Number.parseInt(url.port, 10);
12026
12127
  return Number.isInteger(port) && port > 0 ? port : void 0;
12027
12128
  }
12129
+ var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
12130
+ var OPENSTEER_LIVE_SESSION_VERSION = 1;
12131
+ var LEGACY_CLOUD_SESSION_LAYOUT = "opensteer-cloud-session";
12132
+ var LEGACY_CLOUD_SESSION_VERSION = 1;
12133
+ function resolveLiveSessionRecordPath(rootPath) {
12134
+ return path6.join(rootPath, "live", "session.json");
12135
+ }
12136
+ function resolveLegacyLiveBrowserRecordPath(rootPath) {
12137
+ return path6.join(rootPath, "live", "browser.json");
12138
+ }
12139
+ function resolveLegacyCloudSessionRecordPath(rootPath) {
12140
+ return path6.join(rootPath, "live", "cloud-session.json");
12141
+ }
12142
+ async function readPersistedSessionRecord(rootPath) {
12143
+ const sessionPath = resolveLiveSessionRecordPath(rootPath);
12144
+ if (await pathExists(sessionPath)) {
12145
+ const parsed = await readJsonFile(sessionPath);
12146
+ if (isPersistedLocalBrowserSessionRecord(parsed)) {
12147
+ return parsed;
12148
+ }
12149
+ if (isPersistedCloudSessionRecord(parsed)) {
12150
+ return parsed;
12151
+ }
12152
+ }
12153
+ const legacyCloudPath = resolveLegacyCloudSessionRecordPath(rootPath);
12154
+ if (await pathExists(legacyCloudPath)) {
12155
+ const parsed = await readJsonFile(legacyCloudPath);
12156
+ if (isLegacyCloudSessionRecord(parsed)) {
12157
+ return {
12158
+ layout: OPENSTEER_LIVE_SESSION_LAYOUT,
12159
+ version: OPENSTEER_LIVE_SESSION_VERSION,
12160
+ provider: "cloud",
12161
+ mode: "cloud",
12162
+ ...parsed.workspace === void 0 ? {} : { workspace: parsed.workspace },
12163
+ sessionId: parsed.sessionId,
12164
+ baseUrl: parsed.baseUrl,
12165
+ startedAt: parsed.startedAt,
12166
+ updatedAt: parsed.updatedAt
12167
+ };
12168
+ }
12169
+ }
12170
+ const legacyBrowserPath = resolveLegacyLiveBrowserRecordPath(rootPath);
12171
+ if (await pathExists(legacyBrowserPath)) {
12172
+ const parsed = await readJsonFile(legacyBrowserPath);
12173
+ if (isLegacyLocalBrowserSessionRecord(parsed)) {
12174
+ return {
12175
+ layout: OPENSTEER_LIVE_SESSION_LAYOUT,
12176
+ version: OPENSTEER_LIVE_SESSION_VERSION,
12177
+ provider: "local",
12178
+ mode: "browser",
12179
+ engine: parsed.engine ?? "playwright",
12180
+ ...parsed.endpoint === void 0 ? {} : { endpoint: parsed.endpoint },
12181
+ ...parsed.baseUrl === void 0 ? {} : { baseUrl: parsed.baseUrl },
12182
+ ...parsed.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: parsed.remoteDebuggingUrl },
12183
+ ...parsed.sessionDir === void 0 ? {} : { sessionDir: parsed.sessionDir },
12184
+ pid: parsed.pid,
12185
+ startedAt: parsed.startedAt,
12186
+ updatedAt: parsed.startedAt,
12187
+ ...parsed.executablePath === void 0 ? {} : { executablePath: parsed.executablePath },
12188
+ userDataDir: parsed.userDataDir
12189
+ };
12190
+ }
12191
+ }
12192
+ return void 0;
12193
+ }
12194
+ async function readPersistedCloudSessionRecord(rootPath) {
12195
+ const record = await readPersistedSessionRecord(rootPath);
12196
+ return record?.provider === "cloud" ? record : void 0;
12197
+ }
12198
+ async function readPersistedLocalBrowserSessionRecord(rootPath) {
12199
+ const record = await readPersistedSessionRecord(rootPath);
12200
+ return record?.provider === "local" ? record : void 0;
12201
+ }
12202
+ async function hasPersistedCloudSession(rootPath) {
12203
+ return await readPersistedCloudSessionRecord(rootPath) !== void 0;
12204
+ }
12205
+ async function writePersistedSessionRecord(rootPath, record) {
12206
+ await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath), record);
12207
+ await clearLegacySessionRecordPaths(rootPath);
12208
+ }
12209
+ async function clearPersistedSessionRecord(rootPath) {
12210
+ await Promise.all([
12211
+ removeIfPresent(resolveLiveSessionRecordPath(rootPath)),
12212
+ clearLegacySessionRecordPaths(rootPath)
12213
+ ]);
12214
+ }
12215
+ function isPersistedCloudSessionRecord(value) {
12216
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "cloud" && value.mode === "cloud" && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.baseUrl === "string" && value.baseUrl.length > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
12217
+ }
12218
+ function isPersistedLocalBrowserSessionRecord(value) {
12219
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "local" && value.mode === "browser" && (value.engine === "playwright" || value.engine === "abp") && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt) && typeof value.userDataDir === "string" && value.userDataDir.length > 0;
12220
+ }
12221
+ function isLegacyCloudSessionRecord(value) {
12222
+ return value.layout === LEGACY_CLOUD_SESSION_LAYOUT && value.version === LEGACY_CLOUD_SESSION_VERSION && value.mode === "cloud" && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.baseUrl === "string" && value.baseUrl.length > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
12223
+ }
12224
+ function isLegacyLocalBrowserSessionRecord(value) {
12225
+ return value.mode === "persistent" && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.userDataDir === "string" && value.userDataDir.length > 0;
12226
+ }
12227
+ async function clearLegacySessionRecordPaths(rootPath) {
12228
+ await Promise.all([
12229
+ removeIfPresent(resolveLegacyLiveBrowserRecordPath(rootPath)),
12230
+ removeIfPresent(resolveLegacyCloudSessionRecordPath(rootPath))
12231
+ ]);
12232
+ }
12233
+ async function removeIfPresent(filePath) {
12234
+ await rm(filePath, { force: true }).catch(() => void 0);
12235
+ }
12028
12236
 
12029
- // src/internal/engine-selection.ts
12237
+ // ../runtime-core/src/internal/engine-selection.ts
12030
12238
  var OPENSTEER_ENGINE_NAMES = ["playwright", "abp"];
12031
12239
  var DEFAULT_OPENSTEER_ENGINE = "playwright";
12032
12240
  function resolveOpensteerEngineName(input = {}) {
@@ -12147,9 +12355,6 @@ async function clearChromeSingletonEntries(userDataDir) {
12147
12355
  );
12148
12356
  }
12149
12357
  async function sanitizeChromeProfile(userDataDir) {
12150
- if (!existsSync(userDataDir)) {
12151
- return;
12152
- }
12153
12358
  const entries = await readdir(userDataDir).catch(() => []);
12154
12359
  const profileDirs = entries.filter(
12155
12360
  (entry) => entry === "Default" || /^Profile \d+$/i.test(entry)
@@ -12158,9 +12363,6 @@ async function sanitizeChromeProfile(userDataDir) {
12158
12363
  }
12159
12364
  async function sanitizeProfilePreferences(userDataDir, profileDir) {
12160
12365
  const prefsPath = join(userDataDir, profileDir, "Preferences");
12161
- if (!existsSync(prefsPath)) {
12162
- return;
12163
- }
12164
12366
  try {
12165
12367
  const raw = await readFile(prefsPath, "utf8");
12166
12368
  const prefs = JSON.parse(raw);
@@ -12297,20 +12499,121 @@ function shouldCopyEntry(input) {
12297
12499
 
12298
12500
  // src/local-browser/stealth-init-script.ts
12299
12501
  function generateStealthInitScript(profile) {
12300
- const encodedProfile = JSON.stringify(profile);
12502
+ const encodedProfile = JSON.stringify({
12503
+ ...profile,
12504
+ platformString: getPlatformString(profile.platform),
12505
+ userAgentData: buildUserAgentData(profile)
12506
+ });
12301
12507
  return `(() => {
12302
12508
  const profile = ${encodedProfile};
12509
+ var define = function(target, key, value) {
12510
+ Object.defineProperty(target, key, {
12511
+ configurable: true,
12512
+ get: typeof value === 'function' ? value : function() { return value; },
12513
+ });
12514
+ };
12303
12515
 
12304
- // --- navigator.webdriver safety net ---
12305
- // --disable-blink-features=AutomationControlled handles this at the flag level
12306
- // and CDP handles it at the protocol level, but some Chrome builds still leak
12307
- // webdriver=true when --remote-debugging-port is active.
12516
+ // --- navigator / screen mirrors for future pages ---
12308
12517
  if (navigator.webdriver === true) {
12309
12518
  Object.defineProperty(Navigator.prototype, 'webdriver', {
12310
12519
  configurable: true,
12311
12520
  get: function() { return false; },
12312
12521
  });
12313
12522
  }
12523
+ define(Navigator.prototype, 'platform', profile.platformString);
12524
+ define(Navigator.prototype, 'userAgent', profile.userAgent);
12525
+ define(Navigator.prototype, 'language', profile.locale);
12526
+ define(Navigator.prototype, 'languages', [profile.locale, 'en']);
12527
+ define(Navigator.prototype, 'maxTouchPoints', profile.maxTouchPoints);
12528
+ define(window, 'devicePixelRatio', profile.devicePixelRatio);
12529
+ define(window.screen, 'width', profile.screenResolution.width);
12530
+ define(window.screen, 'height', profile.screenResolution.height);
12531
+ define(window.screen, 'availWidth', profile.screenResolution.width);
12532
+ define(window.screen, 'availHeight', profile.screenResolution.height - 40);
12533
+ define(window.screen, 'colorDepth', 24);
12534
+ define(window.screen, 'pixelDepth', 24);
12535
+ define(Navigator.prototype, 'userAgentData', {
12536
+ brands: profile.userAgentData.brands,
12537
+ mobile: false,
12538
+ platform: profile.userAgentData.platform,
12539
+ toJSON: function() {
12540
+ return {
12541
+ brands: this.brands,
12542
+ mobile: this.mobile,
12543
+ platform: this.platform,
12544
+ };
12545
+ },
12546
+ getHighEntropyValues: async function(hints) {
12547
+ var source = {
12548
+ architecture: profile.userAgentData.architecture,
12549
+ bitness: profile.userAgentData.bitness,
12550
+ brands: profile.userAgentData.brands,
12551
+ fullVersionList: profile.userAgentData.fullVersionList,
12552
+ mobile: false,
12553
+ model: '',
12554
+ platform: profile.userAgentData.platform,
12555
+ platformVersion: profile.userAgentData.platformVersion,
12556
+ uaFullVersion: profile.browserVersion,
12557
+ wow64: false,
12558
+ };
12559
+ var values = {};
12560
+ for (var i = 0; i < hints.length; i++) {
12561
+ var hint = hints[i];
12562
+ if (Object.prototype.hasOwnProperty.call(source, hint)) {
12563
+ values[hint] = source[hint];
12564
+ }
12565
+ }
12566
+ return values;
12567
+ },
12568
+ });
12569
+
12570
+ if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
12571
+ var originalResolvedOptions = Intl.DateTimeFormat.prototype.resolvedOptions;
12572
+ Intl.DateTimeFormat.prototype.resolvedOptions = function() {
12573
+ var options = originalResolvedOptions.call(this);
12574
+ options.timeZone = profile.timezoneId;
12575
+ return options;
12576
+ };
12577
+ }
12578
+
12579
+ if (Date.prototype.getTimezoneOffset) {
12580
+ var originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
12581
+ var calculateTimezoneOffset = function(date) {
12582
+ try {
12583
+ var formatter = new Intl.DateTimeFormat('en-US', {
12584
+ timeZone: profile.timezoneId,
12585
+ hour12: false,
12586
+ year: 'numeric',
12587
+ month: '2-digit',
12588
+ day: '2-digit',
12589
+ hour: '2-digit',
12590
+ minute: '2-digit',
12591
+ second: '2-digit',
12592
+ });
12593
+ var parts = formatter.formatToParts(date);
12594
+ var values = {};
12595
+ for (var i = 0; i < parts.length; i++) {
12596
+ if (parts[i].type !== 'literal') {
12597
+ values[parts[i].type] = Number(parts[i].value);
12598
+ }
12599
+ }
12600
+ var utcTime = Date.UTC(
12601
+ values.year,
12602
+ values.month - 1,
12603
+ values.day,
12604
+ values.hour,
12605
+ values.minute,
12606
+ values.second,
12607
+ );
12608
+ return Math.round((date.getTime() - utcTime) / 60000);
12609
+ } catch {
12610
+ return originalGetTimezoneOffset.call(date);
12611
+ }
12612
+ };
12613
+ Date.prototype.getTimezoneOffset = function() {
12614
+ return calculateTimezoneOffset(this);
12615
+ };
12616
+ }
12314
12617
 
12315
12618
  // --- CDP Runtime.enable leak defense ---
12316
12619
  var _wrap = function(name) {
@@ -12384,6 +12687,34 @@ function generateStealthInitScript(profile) {
12384
12687
  }
12385
12688
  })();`;
12386
12689
  }
12690
+ function buildUserAgentData(profile) {
12691
+ const majorVersion = profile.browserVersion.split(".")[0] ?? "136";
12692
+ const platformData = {
12693
+ macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12694
+ windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12695
+ linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12696
+ };
12697
+ const platformInfo = platformData[profile.platform];
12698
+ return {
12699
+ architecture: platformInfo.architecture,
12700
+ bitness: "64",
12701
+ brands: [
12702
+ { brand: "Chromium", version: majorVersion },
12703
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: majorVersion }] : [{ brand: "Google Chrome", version: majorVersion }],
12704
+ { brand: "Not-A.Brand", version: "99" }
12705
+ ],
12706
+ fullVersionList: [
12707
+ { brand: "Chromium", version: profile.browserVersion },
12708
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: profile.browserVersion }] : [{ brand: "Google Chrome", version: profile.browserVersion }],
12709
+ { brand: "Not-A.Brand", version: "99.0.0.0" }
12710
+ ],
12711
+ platform: platformInfo.platform,
12712
+ platformVersion: platformInfo.platformVersion
12713
+ };
12714
+ }
12715
+ function getPlatformString(platform) {
12716
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12717
+ }
12387
12718
 
12388
12719
  // src/local-browser/stealth.ts
12389
12720
  var STEALTH_INIT_SCRIPT = `(() => {
@@ -12427,8 +12758,9 @@ var STEALTH_INIT_SCRIPT = `(() => {
12427
12758
  ['debug', 'log', 'info', 'error', 'warn', 'trace', 'dir'].forEach(_wrap);
12428
12759
  })();`;
12429
12760
  async function injectBrowserStealthScripts(context, input = {}) {
12430
- if (input.profile !== void 0 && input.page !== void 0) {
12431
- await applyCdpStealthOverrides(context, input.page, input.profile);
12761
+ if (input.profile !== void 0) {
12762
+ await installContextNetworkHeaders(context, input.profile);
12763
+ await installCdpStealthOverrides(context, input.profile, input.page);
12432
12764
  }
12433
12765
  if (typeof context.addInitScript === "function") {
12434
12766
  await context.addInitScript({
@@ -12449,11 +12781,12 @@ function buildUserAgentMetadata(profile) {
12449
12781
  { brand: "Not-A.Brand", version: "99.0.0.0" }
12450
12782
  ];
12451
12783
  const platformMap = {
12784
+ // Chromium keeps the reduced macOS UA token frozen to Intel even on Apple Silicon.
12452
12785
  macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12453
12786
  windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12454
12787
  linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12455
12788
  };
12456
- const platformInfo = platformMap[profile.platform] ?? platformMap.linux;
12789
+ const platformInfo = platformMap[profile.platform];
12457
12790
  return {
12458
12791
  brands,
12459
12792
  fullVersionList,
@@ -12466,7 +12799,28 @@ function buildUserAgentMetadata(profile) {
12466
12799
  wow64: false
12467
12800
  };
12468
12801
  }
12469
- async function applyCdpStealthOverrides(context, page, profile) {
12802
+ async function installCdpStealthOverrides(context, profile, initialPage) {
12803
+ const pages = initialPage === void 0 ? context.pages() : Array.from(/* @__PURE__ */ new Set([initialPage, ...context.pages()]));
12804
+ await Promise.all(pages.map((page) => applyPageOverrides(context, page, profile)));
12805
+ const appliedPages = /* @__PURE__ */ new WeakSet();
12806
+ const applyFuturePageOverrides = async (page) => {
12807
+ if (appliedPages.has(page)) {
12808
+ return;
12809
+ }
12810
+ appliedPages.add(page);
12811
+ await applyPageOverrides(context, page, profile);
12812
+ };
12813
+ if (typeof context.on === "function") {
12814
+ context.on("page", applyFuturePageOverrides);
12815
+ }
12816
+ }
12817
+ async function installContextNetworkHeaders(context, profile) {
12818
+ if (typeof context.setExtraHTTPHeaders !== "function") {
12819
+ return;
12820
+ }
12821
+ await context.setExtraHTTPHeaders(buildStealthRequestHeaders(profile)).catch(() => void 0);
12822
+ }
12823
+ async function applyPageOverrides(context, page, profile) {
12470
12824
  const contextWithCdp = context;
12471
12825
  if (typeof contextWithCdp.newCDPSession !== "function") {
12472
12826
  return;
@@ -12478,31 +12832,50 @@ async function applyCdpStealthOverrides(context, page, profile) {
12478
12832
  return;
12479
12833
  }
12480
12834
  try {
12481
- const platformString = profile.platform === "macos" ? "MacIntel" : profile.platform === "windows" ? "Win32" : "Linux x86_64";
12482
- await cdp.send("Network.setUserAgentOverride", {
12483
- userAgent: profile.userAgent,
12484
- acceptLanguage: `${profile.locale},en;q=0.9`,
12485
- platform: platformString,
12486
- userAgentMetadata: buildUserAgentMetadata(profile)
12487
- });
12488
- await cdp.send("Emulation.setDeviceMetricsOverride", {
12489
- width: profile.viewport.width,
12490
- height: profile.viewport.height,
12491
- deviceScaleFactor: profile.devicePixelRatio,
12492
- mobile: false,
12493
- screenWidth: profile.screenResolution.width,
12494
- screenHeight: profile.screenResolution.height
12495
- });
12496
- await cdp.send("Emulation.setLocaleOverride", {
12497
- locale: profile.locale
12498
- }).catch(() => void 0);
12499
- await cdp.send("Emulation.setTimezoneOverride", {
12500
- timezoneId: profile.timezoneId
12501
- }).catch(() => void 0);
12502
- await cdp.detach();
12835
+ await applyCdpStealthCommands((method, params) => cdp.send(method, params), profile);
12503
12836
  } catch {
12837
+ } finally {
12838
+ await cdp.detach().catch(() => void 0);
12504
12839
  }
12505
12840
  }
12841
+ async function applyCdpStealthCommands(send, profile) {
12842
+ await send("Network.setUserAgentOverride", {
12843
+ userAgent: profile.userAgent,
12844
+ acceptLanguage: `${profile.locale},en;q=0.9`,
12845
+ platform: getPlatformString2(profile.platform),
12846
+ userAgentMetadata: buildUserAgentMetadata(profile)
12847
+ });
12848
+ await send("Emulation.setDeviceMetricsOverride", {
12849
+ width: profile.viewport.width,
12850
+ height: profile.viewport.height,
12851
+ deviceScaleFactor: profile.devicePixelRatio,
12852
+ mobile: false,
12853
+ screenWidth: profile.screenResolution.width,
12854
+ screenHeight: profile.screenResolution.height
12855
+ });
12856
+ await send("Emulation.setLocaleOverride", {
12857
+ locale: profile.locale
12858
+ }).catch(() => void 0);
12859
+ await send("Emulation.setTimezoneOverride", {
12860
+ timezoneId: profile.timezoneId
12861
+ }).catch(() => void 0);
12862
+ }
12863
+ function buildStealthRequestHeaders(profile) {
12864
+ const metadata = buildUserAgentMetadata(profile);
12865
+ return {
12866
+ "Accept-Language": `${profile.locale},en;q=0.9`,
12867
+ "Sec-CH-UA": metadata.brands.map(formatClientHintBrand).join(", "),
12868
+ "Sec-CH-UA-Mobile": "?0",
12869
+ "Sec-CH-UA-Platform": `"${metadata.platform}"`,
12870
+ "User-Agent": profile.userAgent
12871
+ };
12872
+ }
12873
+ function formatClientHintBrand(brand2) {
12874
+ return `"${brand2.brand}";v="${brand2.version}"`;
12875
+ }
12876
+ function getPlatformString2(platform) {
12877
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12878
+ }
12506
12879
 
12507
12880
  // src/local-browser/stealth-profiles.ts
12508
12881
  var PROFILE_PRESETS = [
@@ -12709,7 +13082,7 @@ var OpensteerBrowserManager = class {
12709
13082
  await this.closePersistentBrowser(workspace);
12710
13083
  await rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12711
13084
  await rm(workspace.browserPath, { recursive: true, force: true });
12712
- await rm(workspace.liveBrowserPath, { force: true });
13085
+ await clearPersistedSessionRecord(workspace.rootPath);
12713
13086
  await ensureDirectory(workspace.browserUserDataDir);
12714
13087
  });
12715
13088
  }
@@ -12720,7 +13093,7 @@ var OpensteerBrowserManager = class {
12720
13093
  await this.closePersistentBrowser(workspace);
12721
13094
  await rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12722
13095
  await rm(workspace.browserPath, { recursive: true, force: true });
12723
- await rm(workspace.liveBrowserPath, { force: true });
13096
+ await clearPersistedSessionRecord(workspace.rootPath);
12724
13097
  });
12725
13098
  }
12726
13099
  async close() {
@@ -12798,12 +13171,12 @@ var OpensteerBrowserManager = class {
12798
13171
  sessionDir: resolveAbpSessionDir(workspace),
12799
13172
  ...launch?.browserExecutablePath === void 0 ? {} : { executablePath: launch.browserExecutablePath }
12800
13173
  };
12801
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13174
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12802
13175
  try {
12803
13176
  return await this.createAdoptedAbpEngine(liveRecord);
12804
13177
  } catch (error) {
12805
13178
  await terminateProcess(launched.process.pid ?? 0).catch(() => void 0);
12806
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13179
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
12807
13180
  throw error;
12808
13181
  }
12809
13182
  });
@@ -12886,7 +13259,7 @@ var OpensteerBrowserManager = class {
12886
13259
  executablePath: launched.executablePath,
12887
13260
  userDataDir: workspace.browserUserDataDir
12888
13261
  };
12889
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13262
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12890
13263
  try {
12891
13264
  return await this.createAttachedEngine({
12892
13265
  endpoint: launched.endpoint,
@@ -12895,7 +13268,7 @@ var OpensteerBrowserManager = class {
12895
13268
  });
12896
13269
  } catch (error) {
12897
13270
  await terminateProcess(launched.pid).catch(() => void 0);
12898
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13271
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
12899
13272
  throw error;
12900
13273
  }
12901
13274
  });
@@ -12915,7 +13288,10 @@ var OpensteerBrowserManager = class {
12915
13288
  const stealthProfile = resolveStealthProfile(this.contextOptions?.stealthProfile);
12916
13289
  await injectBrowserStealthScripts(
12917
13290
  context,
12918
- stealthProfile === void 0 ? {} : { profile: stealthProfile, page }
13291
+ stealthProfile === void 0 ? {} : {
13292
+ profile: stealthProfile,
13293
+ page
13294
+ }
12919
13295
  );
12920
13296
  const engine = await createPlaywrightBrowserCoreEngine({
12921
13297
  browser,
@@ -12998,7 +13374,7 @@ var OpensteerBrowserManager = class {
12998
13374
  return void 0;
12999
13375
  }
13000
13376
  if (!isProcessRunning(live.pid)) {
13001
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13377
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13002
13378
  return void 0;
13003
13379
  }
13004
13380
  if (live.engine === "playwright") {
@@ -13017,19 +13393,8 @@ var OpensteerBrowserManager = class {
13017
13393
  return live;
13018
13394
  }
13019
13395
  async readStoredLiveBrowser(workspace) {
13020
- if (!await pathExists(workspace.liveBrowserPath)) {
13021
- return void 0;
13022
- }
13023
- const live = await readJsonFile(
13024
- workspace.liveBrowserPath
13025
- );
13026
- if (live.engine === "abp") {
13027
- return live;
13028
- }
13029
- return {
13030
- ...live,
13031
- engine: "playwright"
13032
- };
13396
+ const live = await readPersistedLocalBrowserSessionRecord(workspace.rootPath);
13397
+ return live === void 0 ? void 0 : toWorkspaceLiveBrowserRecord(live);
13033
13398
  }
13034
13399
  async resolveLivePersistentEngineName() {
13035
13400
  if (this.mode !== "persistent") {
@@ -13049,7 +13414,7 @@ var OpensteerBrowserManager = class {
13049
13414
  async closePersistentBrowser(workspace) {
13050
13415
  const live = await this.readStoredLiveBrowser(workspace);
13051
13416
  if (!live) {
13052
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13417
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13053
13418
  return;
13054
13419
  }
13055
13420
  if (live.engine === "playwright") {
@@ -13057,15 +13422,21 @@ var OpensteerBrowserManager = class {
13057
13422
  await requestBrowserClose(live.endpoint).catch(() => void 0);
13058
13423
  }
13059
13424
  if (await waitForProcessExit(live.pid, BROWSER_CLOSE_TIMEOUT_MS)) {
13060
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13425
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13061
13426
  return;
13062
13427
  }
13063
13428
  await terminateProcess(live.pid).catch(() => void 0);
13064
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13429
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13065
13430
  return;
13066
13431
  }
13067
13432
  await terminateProcess(live.pid).catch(() => void 0);
13068
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13433
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13434
+ }
13435
+ async writeLivePersistentBrowser(workspace, live) {
13436
+ await writePersistedSessionRecord(
13437
+ workspace.rootPath,
13438
+ toPersistedLocalBrowserSessionRecord(this.workspace, live)
13439
+ );
13069
13440
  }
13070
13441
  requirePersistentMode(method) {
13071
13442
  if (this.mode !== "persistent" || this.workspace === void 0) {
@@ -13077,6 +13448,39 @@ function normalizeWorkspace(workspace) {
13077
13448
  const normalized = workspace?.trim();
13078
13449
  return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
13079
13450
  }
13451
+ function toPersistedLocalBrowserSessionRecord(workspace, live) {
13452
+ return {
13453
+ layout: "opensteer-session",
13454
+ version: 1,
13455
+ provider: "local",
13456
+ mode: "browser",
13457
+ ...workspace === void 0 ? {} : { workspace },
13458
+ engine: live.engine,
13459
+ ...live.endpoint === void 0 ? {} : { endpoint: live.endpoint },
13460
+ ...live.baseUrl === void 0 ? {} : { baseUrl: live.baseUrl },
13461
+ ...live.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: live.remoteDebuggingUrl },
13462
+ ...live.sessionDir === void 0 ? {} : { sessionDir: live.sessionDir },
13463
+ pid: live.pid,
13464
+ startedAt: live.startedAt,
13465
+ updatedAt: Date.now(),
13466
+ ...live.executablePath === void 0 ? {} : { executablePath: live.executablePath },
13467
+ userDataDir: live.userDataDir
13468
+ };
13469
+ }
13470
+ function toWorkspaceLiveBrowserRecord(record) {
13471
+ return {
13472
+ mode: "persistent",
13473
+ engine: record.engine,
13474
+ ...record.endpoint === void 0 ? {} : { endpoint: record.endpoint },
13475
+ ...record.baseUrl === void 0 ? {} : { baseUrl: record.baseUrl },
13476
+ ...record.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: record.remoteDebuggingUrl },
13477
+ ...record.sessionDir === void 0 ? {} : { sessionDir: record.sessionDir },
13478
+ pid: record.pid,
13479
+ startedAt: record.startedAt,
13480
+ ...record.executablePath === void 0 ? {} : { executablePath: record.executablePath },
13481
+ userDataDir: record.userDataDir
13482
+ };
13483
+ }
13080
13484
  function resolveBrowserMode(workspace, browser) {
13081
13485
  if (browser === void 0) {
13082
13486
  return workspace === void 0 ? "temporary" : "persistent";
@@ -13156,9 +13560,7 @@ function buildChromeArgs(userDataDir, launch, viewport) {
13156
13560
  if (isHeadless) {
13157
13561
  args.push("--headless=new");
13158
13562
  }
13159
- const hasUserWindowSize = (launch?.args ?? []).some(
13160
- (entry) => entry.startsWith("--window-size")
13161
- );
13563
+ const hasUserWindowSize = (launch?.args ?? []).some((entry) => entry.startsWith("--window-size"));
13162
13564
  if (!hasUserWindowSize) {
13163
13565
  const width = viewport?.width ?? 1440;
13164
13566
  const height = viewport?.height ?? 900;
@@ -13356,7 +13758,7 @@ async function sleep(ms) {
13356
13758
  await new Promise((resolve5) => setTimeout(resolve5, ms));
13357
13759
  }
13358
13760
 
13359
- // src/sdk/semantic-dispatch.ts
13761
+ // ../runtime-core/src/sdk/semantic-dispatch.ts
13360
13762
  async function dispatchSemanticOperation(runtime, operation, input, options = {}) {
13361
13763
  switch (operation) {
13362
13764
  case "session.open":
@@ -13617,7 +14019,14 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
13617
14019
  }
13618
14020
  }
13619
14021
 
13620
- // src/internal/errors.ts
14022
+ // ../runtime-core/package.json
14023
+ var package_default = {
14024
+ version: "0.1.0"};
14025
+
14026
+ // ../runtime-core/src/version.ts
14027
+ var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
14028
+
14029
+ // ../runtime-core/src/internal/errors.ts
13621
14030
  function normalizeThrownOpensteerError(error, fallbackMessage) {
13622
14031
  if (isOpensteerProtocolError(error)) {
13623
14032
  return toOpensteerError(error);
@@ -13628,15 +14037,6 @@ function normalizeThrownOpensteerError(error, fallbackMessage) {
13628
14037
  ...error.details === void 0 ? {} : { details: error.details }
13629
14038
  });
13630
14039
  }
13631
- if (error instanceof OpensteerAttachAmbiguousError) {
13632
- return createOpensteerError("conflict", error.message, {
13633
- details: {
13634
- candidates: error.candidates,
13635
- code: error.code,
13636
- name: error.name
13637
- }
13638
- });
13639
- }
13640
14040
  if (error instanceof Error) {
13641
14041
  return createOpensteerError("operation-failed", error.message, {
13642
14042
  details: {
@@ -13806,7 +14206,7 @@ function roundScale(value) {
13806
14206
  return Number(value.toFixed(6));
13807
14207
  }
13808
14208
 
13809
- // src/runtimes/computer-use/trace-enrichment.ts
14209
+ // ../runtime-core/src/runtimes/computer-use/trace-enrichment.ts
13810
14210
  async function enrichComputerUseTrace(input) {
13811
14211
  const tracePoints = toTracePoints(input.action);
13812
14212
  if (tracePoints.length === 0) {
@@ -13899,7 +14299,7 @@ function toOpensteerResolvedTarget(target) {
13899
14299
  };
13900
14300
  }
13901
14301
 
13902
- // src/runtimes/computer-use/runtime.ts
14302
+ // ../runtime-core/src/runtimes/computer-use/runtime.ts
13903
14303
  function createComputerUseRuntime(options) {
13904
14304
  return new DefaultComputerUseRuntime(options);
13905
14305
  }
@@ -13994,7 +14394,7 @@ function normalizeScreenshotOptions(input) {
13994
14394
  };
13995
14395
  }
13996
14396
 
13997
- // src/requests/shared.ts
14397
+ // ../runtime-core/src/requests/shared.ts
13998
14398
  var REDACTED_HEADER_VALUE = "[redacted]";
13999
14399
  var HTTP_HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
14000
14400
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
@@ -14210,14 +14610,14 @@ function resolveTextEncoding(charset) {
14210
14610
  }
14211
14611
  }
14212
14612
 
14213
- // src/requests/errors.ts
14613
+ // ../runtime-core/src/requests/errors.ts
14214
14614
  function invalidRequestPlanError(message, details = {}) {
14215
14615
  return new OpensteerProtocolError("invalid-request", message, {
14216
14616
  details
14217
14617
  });
14218
14618
  }
14219
14619
 
14220
- // src/requests/plans/index.ts
14620
+ // ../runtime-core/src/requests/plans/index.ts
14221
14621
  var HTTP_METHOD_PATTERN = /^[A-Za-z]+$/;
14222
14622
  var URL_TEMPLATE_PLACEHOLDER_PATTERN = /\{([A-Za-z][A-Za-z0-9_-]*)\}/g;
14223
14623
  function assertValidRequestPlanPayload(payload) {
@@ -14625,7 +15025,7 @@ function normalizeTrimmedString(field, value) {
14625
15025
  return normalized;
14626
15026
  }
14627
15027
 
14628
- // src/requests/inference.ts
15028
+ // ../runtime-core/src/requests/inference.ts
14629
15029
  function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14630
15030
  const url = new URL(record.record.url);
14631
15031
  const defaultQuery = Array.from(url.searchParams.entries()).map(
@@ -14638,6 +15038,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14638
15038
  const responseContentType = headerValue(record.record.responseHeaders, "content-type") ?? record.record.responseBody?.mimeType;
14639
15039
  const defaultHeaders = inferDefaultHeaders(record);
14640
15040
  const auth = inferAuth(record.record.requestHeaders);
15041
+ const body = inferRequestPlanBody(record.record.requestBody, requestContentType);
14641
15042
  const payload = normalizeRequestPlanPayload({
14642
15043
  transport: {
14643
15044
  kind: "context-http"
@@ -14648,12 +15049,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14648
15049
  ...defaultQuery.length === 0 ? {} : { defaultQuery },
14649
15050
  ...defaultHeaders.length === 0 ? {} : { defaultHeaders }
14650
15051
  },
14651
- ...requestContentType === void 0 && record.record.requestBody === void 0 ? {} : {
14652
- body: {
14653
- ...requestContentType === void 0 ? {} : { contentType: requestContentType },
14654
- required: true
14655
- }
14656
- },
15052
+ ...body === void 0 ? {} : { body },
14657
15053
  ...record.record.status === void 0 ? {} : {
14658
15054
  response: {
14659
15055
  status: record.record.status,
@@ -14709,8 +15105,52 @@ function inferAuth(headers) {
14709
15105
  }
14710
15106
  return void 0;
14711
15107
  }
15108
+ function inferRequestPlanBody(body, contentType) {
15109
+ if (body === void 0) {
15110
+ return void 0;
15111
+ }
15112
+ const text = Buffer.from(body.data, "base64").toString("utf8");
15113
+ const normalizedContentType = contentType?.toLowerCase();
15114
+ const trimmedText = text.trim();
15115
+ const parsedJson = parseJsonBody(trimmedText);
15116
+ if (normalizedContentType?.includes("application/json") === true || normalizedContentType?.includes("+json") === true || parsedJson !== void 0) {
15117
+ return {
15118
+ kind: "json",
15119
+ required: true,
15120
+ ...contentType === void 0 ? {} : { contentType },
15121
+ template: parsedJson ?? text
15122
+ };
15123
+ }
15124
+ if (normalizedContentType?.includes("application/x-www-form-urlencoded") === true) {
15125
+ return {
15126
+ kind: "form",
15127
+ required: true,
15128
+ ...contentType === void 0 ? {} : { contentType },
15129
+ fields: Array.from(new URLSearchParams(text).entries()).map(([name, value]) => ({
15130
+ name,
15131
+ value
15132
+ }))
15133
+ };
15134
+ }
15135
+ return {
15136
+ kind: "text",
15137
+ required: true,
15138
+ ...contentType === void 0 ? {} : { contentType },
15139
+ template: text
15140
+ };
15141
+ }
15142
+ function parseJsonBody(value) {
15143
+ if (value.length === 0 || !value.startsWith("{") && !value.startsWith("[")) {
15144
+ return void 0;
15145
+ }
15146
+ try {
15147
+ return JSON.parse(value);
15148
+ } catch {
15149
+ return void 0;
15150
+ }
15151
+ }
14712
15152
 
14713
- // src/reverse/materialization.ts
15153
+ // ../runtime-core/src/reverse/materialization.ts
14714
15154
  var ALWAYS_OMIT_HEADER_NAMES = /* @__PURE__ */ new Set(["content-length", "host", "priority"]);
14715
15155
  var BROWSER_OWNED_HEADER_PREFIXES = ["sec-"];
14716
15156
  function isManagedRequestHeaderName(name, transport) {
@@ -14746,7 +15186,7 @@ function finalizeMaterializedTransportRequest(request, transport) {
14746
15186
  };
14747
15187
  }
14748
15188
 
14749
- // src/network/diff.ts
15189
+ // ../runtime-core/src/network/diff.ts
14750
15190
  function diffNetworkRecords(left, right, input) {
14751
15191
  const requestDiffs = [];
14752
15192
  const responseDiffs = [];
@@ -14906,7 +15346,7 @@ function diffStringMap(prefix, left, right, includeUnchanged, output) {
14906
15346
  diffScalarField(`${prefix}.${key}`, left[key], right[key], includeUnchanged, output);
14907
15347
  }
14908
15348
  }
14909
- function diffScalarField(path11, left, right, includeUnchanged, output) {
15349
+ function diffScalarField(path13, left, right, includeUnchanged, output) {
14910
15350
  const leftValue = stringifyFieldValue(left);
14911
15351
  const rightValue = stringifyFieldValue(right);
14912
15352
  const kind = leftValue === void 0 ? rightValue === void 0 ? "unchanged" : "added" : rightValue === void 0 ? "removed" : leftValue === rightValue ? "unchanged" : "changed";
@@ -14914,7 +15354,7 @@ function diffScalarField(path11, left, right, includeUnchanged, output) {
14914
15354
  return;
14915
15355
  }
14916
15356
  output.push({
14917
- path: path11,
15357
+ path: path13,
14918
15358
  kind,
14919
15359
  ...leftValue === void 0 ? {} : { leftValue },
14920
15360
  ...rightValue === void 0 ? {} : { rightValue },
@@ -15103,7 +15543,7 @@ var NetworkJournal = class {
15103
15543
  }
15104
15544
  };
15105
15545
 
15106
- // src/network/minimize.ts
15546
+ // ../runtime-core/src/network/minimize.ts
15107
15547
  function prepareMinimizationRequest(record, preserve = []) {
15108
15548
  const requestUrl = new URL(record.record.url);
15109
15549
  const preservedNames = new Set(
@@ -15516,7 +15956,7 @@ function resolveBodyEncoding2(charset) {
15516
15956
  }
15517
15957
  }
15518
15958
 
15519
- // src/network/probe.ts
15959
+ // ../runtime-core/src/network/probe.ts
15520
15960
  var TRANSPORT_PROBE_LADDER = [
15521
15961
  "direct-http",
15522
15962
  "matched-tls",
@@ -15528,7 +15968,7 @@ function selectTransportProbeRecommendation(results) {
15528
15968
  return results.find((entry) => entry.success)?.transport ?? results.at(-1)?.transport ?? "session-http";
15529
15969
  }
15530
15970
 
15531
- // src/reverse/analysis.ts
15971
+ // ../runtime-core/src/reverse/analysis.ts
15532
15972
  var TELEMETRY_HOST_PATTERNS = [
15533
15973
  "google-analytics",
15534
15974
  "doubleclick",
@@ -15868,9 +16308,9 @@ function matchReverseTargetHints(channel, codec, targetHints) {
15868
16308
  matches.add(`host:${host}`);
15869
16309
  }
15870
16310
  }
15871
- for (const path11 of targetHints.paths ?? []) {
15872
- if (url.pathname.includes(path11)) {
15873
- matches.add(`path:${path11}`);
16311
+ for (const path13 of targetHints.paths ?? []) {
16312
+ if (url.pathname.includes(path13)) {
16313
+ matches.add(`path:${path13}`);
15874
16314
  }
15875
16315
  }
15876
16316
  for (const operationName of targetHints.operationNames ?? []) {
@@ -16722,7 +17162,7 @@ function looksHighEntropy(value) {
16722
17162
  return uniqueCharacters >= Math.min(20, Math.floor(trimmed.length * 0.6));
16723
17163
  }
16724
17164
 
16725
- // src/reverse/discovery.ts
17165
+ // ../runtime-core/src/reverse/discovery.ts
16726
17166
  function clusterReverseObservationRecords(input) {
16727
17167
  const groups = /* @__PURE__ */ new Map();
16728
17168
  for (const item of sortClusterableRecords(input.records)) {
@@ -17029,7 +17469,7 @@ async function readDirSafe(directory) {
17029
17469
  }
17030
17470
  }
17031
17471
 
17032
- // src/reverse/validation.ts
17472
+ // ../runtime-core/src/reverse/validation.ts
17033
17473
  function buildReverseValidationRules(input) {
17034
17474
  switch (input.channel.kind) {
17035
17475
  case "http":
@@ -17306,7 +17746,7 @@ function jsonStructureShape(value) {
17306
17746
  return typeof value;
17307
17747
  }
17308
17748
 
17309
- // src/reverse/workflows.ts
17749
+ // ../runtime-core/src/reverse/workflows.ts
17310
17750
  function buildReversePackageWorkflow(input) {
17311
17751
  if (input.template === void 0 && input.executeStepInput === void 0) {
17312
17752
  return [];
@@ -17675,7 +18115,7 @@ function dedupeSuggestedEdits(suggestions) {
17675
18115
  return [...new Map(suggestions.map((suggestion) => [suggestion.id, suggestion])).values()];
17676
18116
  }
17677
18117
 
17678
- // src/sdk/extraction-data-path.ts
18118
+ // ../runtime-core/src/sdk/extraction-data-path.ts
17679
18119
  function joinDataPath(base, key) {
17680
18120
  const normalizedBase = base.trim();
17681
18121
  const normalizedKey = key.trim();
@@ -17706,8 +18146,8 @@ function encodeDataPath(tokens) {
17706
18146
  }
17707
18147
  return out;
17708
18148
  }
17709
- function parseDataPath(path11) {
17710
- const input = path11.trim();
18149
+ function parseDataPath(path13) {
18150
+ const input = path13.trim();
17711
18151
  if (input.length === 0) {
17712
18152
  return [];
17713
18153
  }
@@ -17757,8 +18197,8 @@ function parseDataPath(path11) {
17757
18197
  function inflateDataPathObject(flat) {
17758
18198
  let root = {};
17759
18199
  let initialized = false;
17760
- for (const [path11, value] of Object.entries(flat)) {
17761
- const tokens = parseDataPath(path11);
18200
+ for (const [path13, value] of Object.entries(flat)) {
18201
+ const tokens = parseDataPath(path13);
17762
18202
  if (!tokens || tokens.length === 0) {
17763
18203
  continue;
17764
18204
  }
@@ -17816,7 +18256,7 @@ function assignDataPathValue(root, tokens, value) {
17816
18256
  }
17817
18257
  }
17818
18258
 
17819
- // src/sdk/extraction-consolidation.ts
18259
+ // ../runtime-core/src/sdk/extraction-consolidation.ts
17820
18260
  var STRUCTURAL_ATTR_KEYS = /* @__PURE__ */ new Set([
17821
18261
  "class",
17822
18262
  "role",
@@ -18090,8 +18530,8 @@ function buildVariantDescriptorFromCluster(descriptors) {
18090
18530
  fields: mergedFields
18091
18531
  };
18092
18532
  }
18093
- function minimizePathMatchClauses(path11, mode) {
18094
- const normalized = sanitizeElementPath(path11);
18533
+ function minimizePathMatchClauses(path13, mode) {
18534
+ const normalized = sanitizeElementPath(path13);
18095
18535
  const nodes = normalized.nodes.map((node, index) => {
18096
18536
  const isLast = index === normalized.nodes.length - 1;
18097
18537
  const attrs = node.attrs || {};
@@ -18195,8 +18635,8 @@ function seedMinimalAttrClause(attrs) {
18195
18635
  }
18196
18636
  return null;
18197
18637
  }
18198
- function relaxPathForSingleSample(path11, mode) {
18199
- const normalized = sanitizeElementPath(path11);
18638
+ function relaxPathForSingleSample(path13, mode) {
18639
+ const normalized = sanitizeElementPath(path13);
18200
18640
  const relaxedNodes = normalized.nodes.map((node, index) => {
18201
18641
  const isLast = index === normalized.nodes.length - 1;
18202
18642
  const attrs = normalizeAttrsForSingleSample(node.attrs || {});
@@ -18281,8 +18721,8 @@ function shouldKeepAttrForSingleSample(key) {
18281
18721
  }
18282
18722
  return true;
18283
18723
  }
18284
- function buildPathStructureKey(path11) {
18285
- const normalized = sanitizeElementPath(path11);
18724
+ function buildPathStructureKey(path13) {
18725
+ const normalized = sanitizeElementPath(path13);
18286
18726
  return canonicalJsonString({
18287
18727
  context: (normalized.context || []).map((hop) => ({
18288
18728
  kind: hop.kind,
@@ -18409,30 +18849,30 @@ function buildArrayItemNode(fields) {
18409
18849
  }
18410
18850
  return node;
18411
18851
  }
18412
- function insertNodeAtPath(root, path11, node) {
18413
- const tokens = parseDataPath(path11);
18852
+ function insertNodeAtPath(root, path13, node) {
18853
+ const tokens = parseDataPath(path13);
18414
18854
  if (!tokens || !tokens.length) {
18415
18855
  throw new Error(
18416
- `Invalid persisted extraction path "${path11}": expected a non-empty object path.`
18856
+ `Invalid persisted extraction path "${path13}": expected a non-empty object path.`
18417
18857
  );
18418
18858
  }
18419
18859
  if (tokens.some((token) => token.kind === "index")) {
18420
18860
  throw new Error(
18421
- `Invalid persisted extraction path "${path11}": nested array indices are not supported in cached descriptors.`
18861
+ `Invalid persisted extraction path "${path13}": nested array indices are not supported in cached descriptors.`
18422
18862
  );
18423
18863
  }
18424
18864
  let current = root;
18425
18865
  for (let index = 0; index < tokens.length; index += 1) {
18426
18866
  const token = tokens[index];
18427
18867
  if (!token || token.kind !== "prop") {
18428
- throw new Error(`Invalid persisted extraction path "${path11}": expected object segment.`);
18868
+ throw new Error(`Invalid persisted extraction path "${path13}": expected object segment.`);
18429
18869
  }
18430
18870
  const isLast = index === tokens.length - 1;
18431
18871
  if (isLast) {
18432
18872
  const existing = current[token.key];
18433
18873
  if (existing) {
18434
18874
  throw new Error(
18435
- `Conflicting persisted extraction path "${path11}" detected while building descriptor tree.`
18875
+ `Conflicting persisted extraction path "${path13}" detected while building descriptor tree.`
18436
18876
  );
18437
18877
  }
18438
18878
  current[token.key] = node;
@@ -18447,7 +18887,7 @@ function insertNodeAtPath(root, path11, node) {
18447
18887
  }
18448
18888
  if (!isPersistedObjectNode(next)) {
18449
18889
  throw new Error(
18450
- `Conflicting persisted extraction path "${path11}" detected at "${token.key}".`
18890
+ `Conflicting persisted extraction path "${path13}" detected at "${token.key}".`
18451
18891
  );
18452
18892
  }
18453
18893
  current = next;
@@ -18482,7 +18922,7 @@ function buildItemRootForArrayIndex(entries) {
18482
18922
  }
18483
18923
  const paths = entries.map(
18484
18924
  (entry) => isPersistablePathField(entry.source) ? sanitizeElementPath(entry.source.path) : null
18485
- ).filter((path11) => path11 !== null);
18925
+ ).filter((path13) => path13 !== null);
18486
18926
  if (!paths.length) {
18487
18927
  return null;
18488
18928
  }
@@ -18503,7 +18943,7 @@ function getCommonPathPrefixLength(paths) {
18503
18943
  if (!paths.length) {
18504
18944
  return 0;
18505
18945
  }
18506
- const nodeChains = paths.map((path11) => path11.nodes);
18946
+ const nodeChains = paths.map((path13) => path13.nodes);
18507
18947
  const minLength = Math.min(...nodeChains.map((nodes) => nodes.length));
18508
18948
  if (!Number.isFinite(minLength) || minLength <= 0) {
18509
18949
  return 0;
@@ -18572,30 +19012,30 @@ function mergeElementPathsByMajority(paths) {
18572
19012
  if (!paths.length) {
18573
19013
  return null;
18574
19014
  }
18575
- const normalized = paths.map((path11) => sanitizeElementPath(path11));
19015
+ const normalized = paths.map((path13) => sanitizeElementPath(path13));
18576
19016
  const contextKey = pickModeString(
18577
- normalized.map((path11) => canonicalJsonString(path11.context)),
19017
+ normalized.map((path13) => canonicalJsonString(path13.context)),
18578
19018
  1
18579
19019
  );
18580
19020
  if (!contextKey) {
18581
19021
  return null;
18582
19022
  }
18583
- const sameContext = normalized.filter((path11) => canonicalJsonString(path11.context) === contextKey);
19023
+ const sameContext = normalized.filter((path13) => canonicalJsonString(path13.context) === contextKey);
18584
19024
  if (!sameContext.length) {
18585
19025
  return null;
18586
19026
  }
18587
19027
  const targetLength = pickModeNumber(
18588
- sameContext.map((path11) => path11.nodes.length),
19028
+ sameContext.map((path13) => path13.nodes.length),
18589
19029
  1
18590
19030
  ) ?? sameContext[0]?.nodes.length ?? 0;
18591
- const aligned = sameContext.filter((path11) => path11.nodes.length === targetLength);
19031
+ const aligned = sameContext.filter((path13) => path13.nodes.length === targetLength);
18592
19032
  if (!aligned.length) {
18593
19033
  return null;
18594
19034
  }
18595
19035
  const threshold = majorityThreshold(aligned.length);
18596
19036
  const nodes = [];
18597
19037
  for (let index = 0; index < targetLength; index += 1) {
18598
- const nodesAtIndex = aligned.map((path11) => path11.nodes[index]).filter((node) => node !== void 0);
19038
+ const nodesAtIndex = aligned.map((path13) => path13.nodes[index]).filter((node) => node !== void 0);
18599
19039
  if (!nodesAtIndex.length) {
18600
19040
  return null;
18601
19041
  }
@@ -18841,8 +19281,8 @@ function clonePathContext(context) {
18841
19281
  function clonePathNodes(nodes) {
18842
19282
  return JSON.parse(JSON.stringify(nodes || []));
18843
19283
  }
18844
- function cloneElementPath2(path11) {
18845
- return JSON.parse(JSON.stringify(path11));
19284
+ function cloneElementPath2(path13) {
19285
+ return JSON.parse(JSON.stringify(path13));
18846
19286
  }
18847
19287
  function clonePersistedOpensteerExtractionNode(node) {
18848
19288
  return JSON.parse(JSON.stringify(node));
@@ -18863,7 +19303,7 @@ function isPersistedObjectNode(node) {
18863
19303
  return !!node && typeof node === "object" && !Array.isArray(node) && !isPersistedOpensteerExtractionValueNode(node) && !isPersistedOpensteerExtractionSourceNode(node) && !isPersistedOpensteerExtractionArrayNode(node);
18864
19304
  }
18865
19305
 
18866
- // src/sdk/extraction.ts
19306
+ // ../runtime-core/src/sdk/extraction.ts
18867
19307
  function assertValidOpensteerExtractionSchemaRoot(schema) {
18868
19308
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
18869
19309
  throw new Error("Invalid extraction schema: expected a JSON object at the top level.");
@@ -19128,12 +19568,12 @@ async function resolvePersistableFieldTargets(options) {
19128
19568
  anchor: field.anchor
19129
19569
  }
19130
19570
  });
19131
- const path11 = resolved.replayPath ?? await options.dom.buildPath({
19571
+ const path13 = resolved.replayPath ?? await options.dom.buildPath({
19132
19572
  locator: resolved.locator
19133
19573
  });
19134
19574
  fields.push({
19135
19575
  key: field.key,
19136
- path: sanitizeElementPath(path11),
19576
+ path: sanitizeElementPath(path13),
19137
19577
  ...field.attribute === void 0 ? {} : { attribute: field.attribute }
19138
19578
  });
19139
19579
  }
@@ -19216,8 +19656,8 @@ function collectPersistedValueNodeRefs(node) {
19216
19656
  return [
19217
19657
  {
19218
19658
  path: sanitizeElementPath(node.$path),
19219
- replacePath: (path11) => {
19220
- node.$path = sanitizeElementPath(path11);
19659
+ replacePath: (path13) => {
19660
+ node.$path = sanitizeElementPath(path13);
19221
19661
  }
19222
19662
  }
19223
19663
  ];
@@ -19231,13 +19671,13 @@ function collectPersistedValueNodeRefs(node) {
19231
19671
  }
19232
19672
  return refs;
19233
19673
  }
19234
- function hasPositionClause(path11) {
19235
- return path11.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19674
+ function hasPositionClause(path13) {
19675
+ return path13.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19236
19676
  }
19237
- function stripPositionClauses2(path11) {
19677
+ function stripPositionClauses2(path13) {
19238
19678
  return sanitizeElementPath({
19239
- context: path11.context,
19240
- nodes: path11.nodes.map((node) => ({
19679
+ context: path13.context,
19680
+ nodes: path13.nodes.map((node) => ({
19241
19681
  ...node,
19242
19682
  match: node.match.filter((clause) => clause.kind !== "position")
19243
19683
  }))
@@ -19647,14 +20087,14 @@ function normalizeNonEmptyString2(name, value) {
19647
20087
  function normalizeKey(value) {
19648
20088
  return String(value ?? "").trim();
19649
20089
  }
19650
- function labelForPath(path11) {
19651
- return path11.trim().length === 0 ? "$" : path11;
20090
+ function labelForPath(path13) {
20091
+ return path13.trim().length === 0 ? "$" : path13;
19652
20092
  }
19653
20093
  function sha256Hex3(value) {
19654
20094
  return createHash("sha256").update(value).digest("hex");
19655
20095
  }
19656
20096
 
19657
- // src/sdk/snapshot/constants.ts
20097
+ // ../runtime-core/src/sdk/snapshot/constants.ts
19658
20098
  var OPENSTEER_INTERACTIVE_ATTR = "data-opensteer-interactive";
19659
20099
  var OPENSTEER_HIDDEN_ATTR = "data-opensteer-hidden";
19660
20100
  var OPENSTEER_SCROLLABLE_ATTR = "data-opensteer-scrollable";
@@ -19722,7 +20162,7 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
19722
20162
  "wbr"
19723
20163
  ]);
19724
20164
 
19725
- // src/sdk/snapshot/cleaner.ts
20165
+ // ../runtime-core/src/sdk/snapshot/cleaner.ts
19726
20166
  var STRIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "meta", "link", "template"]);
19727
20167
  var TEXT_ATTR_MAX = 150;
19728
20168
  var URL_ATTR_MAX = 500;
@@ -20162,7 +20602,7 @@ var VOID_TAGS2 = /* @__PURE__ */ new Set([
20162
20602
  "wbr"
20163
20603
  ]);
20164
20604
 
20165
- // src/sdk/snapshot/compiler.ts
20605
+ // ../runtime-core/src/sdk/snapshot/compiler.ts
20166
20606
  async function compileOpensteerSnapshot(options) {
20167
20607
  const pageInfo = await options.engine.getPageInfo({ pageRef: options.pageRef });
20168
20608
  const mainSnapshot = await getMainDocumentSnapshot(options.engine, options.pageRef);
@@ -20713,7 +21153,7 @@ async function beautifyScriptContent(content) {
20713
21153
  });
20714
21154
  }
20715
21155
 
20716
- // src/scripts/deobfuscate.ts
21156
+ // ../runtime-core/src/scripts/deobfuscate.ts
20717
21157
  async function deobfuscateScriptContent(input) {
20718
21158
  const webcrack = await loadWebcrack();
20719
21159
  const result = await webcrack(input.content, {
@@ -20771,7 +21211,7 @@ function inferTransforms(original, deobfuscated) {
20771
21211
  return [...inferred];
20772
21212
  }
20773
21213
 
20774
- // src/scripts/sandbox-shims/minimal.ts
21214
+ // ../runtime-core/src/scripts/sandbox-shims/minimal.ts
20775
21215
  function createMinimalSandboxGlobals(options) {
20776
21216
  return {
20777
21217
  console: options.console,
@@ -20795,7 +21235,7 @@ function createMinimalSandboxGlobals(options) {
20795
21235
  };
20796
21236
  }
20797
21237
 
20798
- // src/scripts/sandbox-shims/standard.ts
21238
+ // ../runtime-core/src/scripts/sandbox-shims/standard.ts
20799
21239
  function createStandardSandboxGlobals(options) {
20800
21240
  const globals = createMinimalSandboxGlobals(options);
20801
21241
  const eventApi = createEventTargetApi();
@@ -21066,7 +21506,7 @@ function normalizeErrorMessage(error) {
21066
21506
  return error instanceof Error ? error.message : String(error);
21067
21507
  }
21068
21508
 
21069
- // src/scripts/sandbox-shims/full.ts
21509
+ // ../runtime-core/src/scripts/sandbox-shims/full.ts
21070
21510
  function createFullSandboxGlobals(options) {
21071
21511
  const globals = createStandardSandboxGlobals(options);
21072
21512
  const eventListeners = /* @__PURE__ */ new WeakMap();
@@ -21186,7 +21626,7 @@ function createFullSandboxGlobals(options) {
21186
21626
  };
21187
21627
  }
21188
21628
 
21189
- // src/scripts/sandbox.ts
21629
+ // ../runtime-core/src/scripts/sandbox.ts
21190
21630
  async function runScriptSandbox(input) {
21191
21631
  const startedAt = Date.now();
21192
21632
  const errors = [];
@@ -21410,7 +21850,7 @@ function normalizeErrorMessage2(error) {
21410
21850
  return error instanceof Error ? error.message : String(error);
21411
21851
  }
21412
21852
 
21413
- // src/captcha/solver-capsolver.ts
21853
+ // ../runtime-core/src/captcha/solver-capsolver.ts
21414
21854
  var CAPSOLVER_CREATE_TASK_URL = "https://api.capsolver.com/createTask";
21415
21855
  var CAPSOLVER_GET_TASK_RESULT_URL = "https://api.capsolver.com/getTaskResult";
21416
21856
  function createCapSolver(apiKey) {
@@ -21508,7 +21948,7 @@ function sleep2(ms, signal) {
21508
21948
  });
21509
21949
  }
21510
21950
 
21511
- // src/captcha/solver-2captcha.ts
21951
+ // ../runtime-core/src/captcha/solver-2captcha.ts
21512
21952
  var TWO_CAPTCHA_CREATE_TASK_URL = "https://api.2captcha.com/createTask";
21513
21953
  var TWO_CAPTCHA_GET_TASK_RESULT_URL = "https://api.2captcha.com/getTaskResult";
21514
21954
  function createTwoCaptchaSolver(apiKey) {
@@ -21606,7 +22046,7 @@ function sleep3(ms, signal) {
21606
22046
  });
21607
22047
  }
21608
22048
 
21609
- // src/captcha/detect.ts
22049
+ // ../runtime-core/src/captcha/detect.ts
21610
22050
  var CAPTCHA_DETECTION_SCRIPT = `(() => {
21611
22051
  const pageUrl = location.href;
21612
22052
  const findSiteKey = (selectors) => {
@@ -21668,7 +22108,7 @@ async function detectCaptchaOnPage(engine, pageRef) {
21668
22108
  return candidate;
21669
22109
  }
21670
22110
 
21671
- // src/captcha/inject.ts
22111
+ // ../runtime-core/src/captcha/inject.ts
21672
22112
  async function injectCaptchaToken(input) {
21673
22113
  const result = await input.engine.evaluatePage({
21674
22114
  pageRef: input.pageRef,
@@ -21724,7 +22164,7 @@ var CAPTCHA_INJECTION_SCRIPT = `(({ type, token }) => {
21724
22164
  return true;
21725
22165
  })`;
21726
22166
 
21727
- // src/interaction/diff.ts
22167
+ // ../runtime-core/src/interaction/diff.ts
21728
22168
  function diffInteractionTraces(left, right) {
21729
22169
  const eventSequenceMismatches = [];
21730
22170
  const eventPropertyMismatches = [];
@@ -21793,20 +22233,17 @@ function diffInteractionTraces(left, right) {
21793
22233
  };
21794
22234
  }
21795
22235
 
21796
- // src/sdk/runtime.ts
22236
+ // ../runtime-core/src/sdk/runtime.ts
21797
22237
  var requireForAuthRecipeHook = createRequire(import.meta.url);
21798
- var OpensteerRuntime = class {
22238
+ var OpensteerSessionRuntime = class {
21799
22239
  workspace;
21800
22240
  rootPath;
21801
- publicWorkspace;
21802
- configuredBrowser;
21803
- configuredLaunch;
21804
- configuredContext;
21805
- configuredEngineName;
22241
+ workspaceName;
21806
22242
  injectedEngine;
21807
22243
  engineFactory;
21808
22244
  policy;
21809
22245
  cleanupRootOnClose;
22246
+ sessionInfoBase;
21810
22247
  root;
21811
22248
  engine;
21812
22249
  dom;
@@ -21821,35 +22258,46 @@ var OpensteerRuntime = class {
21821
22258
  cookieJars = /* @__PURE__ */ new Map();
21822
22259
  recipeCache = /* @__PURE__ */ new Map();
21823
22260
  ownsEngine = false;
21824
- constructor(options = {}) {
21825
- this.publicWorkspace = options.workspace?.trim() === void 0 || options.workspace?.trim().length === 0 ? void 0 : options.workspace.trim();
21826
- this.workspace = normalizeNamespace3(options.workspace);
21827
- this.rootPath = options.rootPath ?? (this.publicWorkspace === void 0 ? path6.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", randomUUID()) : path6.resolve(
21828
- options.rootDir ?? process.cwd(),
21829
- ".opensteer",
21830
- "workspaces",
21831
- encodeURIComponent(this.publicWorkspace)
21832
- ));
21833
- this.configuredBrowser = options.browser;
21834
- this.configuredLaunch = options.launch;
21835
- this.configuredContext = options.context;
21836
- this.configuredEngineName = options.engineName;
22261
+ constructor(options) {
22262
+ this.workspace = normalizeNamespace3(options.name);
22263
+ this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
22264
+ this.root = options.workspace;
22265
+ this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6.resolve(process.cwd(), ".opensteer", "temporary", randomUUID());
21837
22266
  this.injectedEngine = options.engine;
21838
- this.engineFactory = options.engineFactory ?? ((factoryOptions) => {
21839
- const browser = factoryOptions.browser ?? this.configuredBrowser;
21840
- const launch = factoryOptions.launch ?? this.configuredLaunch;
21841
- const context = factoryOptions.context ?? this.configuredContext;
21842
- return new OpensteerBrowserManager({
21843
- rootPath: this.rootPath,
21844
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
21845
- ...this.configuredEngineName === void 0 ? {} : { engineName: this.configuredEngineName },
21846
- ...browser === void 0 ? {} : { browser },
21847
- ...launch === void 0 ? {} : { launch },
21848
- ...context === void 0 ? {} : { context }
21849
- }).createEngine();
21850
- });
22267
+ this.engineFactory = options.engineFactory;
21851
22268
  this.policy = options.policy ?? defaultPolicy();
21852
- this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.publicWorkspace === void 0;
22269
+ this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
22270
+ this.sessionInfoBase = options.sessionInfo ?? {};
22271
+ if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
22272
+ throw new Error("OpensteerSessionRuntime requires an engine or engineFactory.");
22273
+ }
22274
+ }
22275
+ async info() {
22276
+ const base = this.sessionInfoBase;
22277
+ return {
22278
+ provider: base.provider ?? {
22279
+ kind: "local",
22280
+ ownership: "owned",
22281
+ engine: "playwright"
22282
+ },
22283
+ ...base.workspace === void 0 ? {} : { workspace: base.workspace },
22284
+ ...this.sessionRef === void 0 ? {} : { sessionId: this.sessionRef },
22285
+ ...this.pageRef === void 0 ? {} : { activePageRef: this.pageRef },
22286
+ reconnectable: base.reconnectable ?? !this.cleanupRootOnClose,
22287
+ capabilities: base.capabilities ?? {
22288
+ semanticOperations: opensteerSemanticOperationNames,
22289
+ instrumentation: {
22290
+ route: true,
22291
+ interceptScript: true,
22292
+ networkStream: false
22293
+ }
22294
+ },
22295
+ ...base.grants === void 0 ? {} : { grants: base.grants },
22296
+ runtime: base.runtime ?? {
22297
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
22298
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
22299
+ }
22300
+ };
21853
22301
  }
21854
22302
  async open(input = {}, options = {}) {
21855
22303
  assertValidSemanticOperationInput("session.open", input);
@@ -26220,14 +26668,14 @@ var OpensteerRuntime = class {
26220
26668
  return saved;
26221
26669
  }
26222
26670
  resolveCurrentStateSource() {
26223
- const browser = this.configuredBrowser;
26224
- if (browser === void 0 || browser === "temporary") {
26225
- return "temporary";
26671
+ const ownership = this.sessionInfoBase.provider?.ownership;
26672
+ if (ownership === "attached") {
26673
+ return "attach";
26226
26674
  }
26227
- if (browser === "persistent") {
26675
+ if (this.workspaceName !== void 0 || this.cleanupRootOnClose === false) {
26228
26676
  return "persistent";
26229
26677
  }
26230
- return "attach";
26678
+ return "temporary";
26231
26679
  }
26232
26680
  async resolveReverseCaseById(caseId) {
26233
26681
  const record = await (await this.ensureRoot()).registry.reverseCases.getById(caseId);
@@ -27794,8 +28242,8 @@ var OpensteerRuntime = class {
27794
28242
  async ensureRoot() {
27795
28243
  this.root ??= await createFilesystemOpensteerWorkspace({
27796
28244
  rootPath: this.rootPath,
27797
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
27798
- scope: this.publicWorkspace === void 0 ? "temporary" : "workspace"
28245
+ ...this.workspaceName === void 0 ? {} : { workspace: this.workspaceName },
28246
+ scope: this.workspaceName === void 0 ? "temporary" : "workspace"
27799
28247
  });
27800
28248
  return this.root;
27801
28249
  }
@@ -27808,15 +28256,10 @@ var OpensteerRuntime = class {
27808
28256
  this.ownsEngine = false;
27809
28257
  return this.engine;
27810
28258
  }
27811
- const browser = overrides.browser ?? this.configuredBrowser;
27812
- const launch = overrides.launch ?? this.configuredLaunch;
27813
- const context = overrides.context ?? this.configuredContext;
27814
- const factoryOptions = {
27815
- ...browser === void 0 ? {} : { browser },
27816
- ...launch === void 0 ? {} : { launch },
27817
- ...context === void 0 ? {} : { context }
27818
- };
27819
- this.engine = await this.engineFactory(factoryOptions);
28259
+ if (this.engineFactory === void 0) {
28260
+ throw new Error("Opensteer engine factory is not initialized");
28261
+ }
28262
+ this.engine = await this.engineFactory(overrides);
27820
28263
  this.ownsEngine = true;
27821
28264
  return this.engine;
27822
28265
  }
@@ -28273,6 +28716,9 @@ function parseContentType2(contentType) {
28273
28716
  };
28274
28717
  }
28275
28718
  function toJsonValueOrNull(value) {
28719
+ if (value === void 0) {
28720
+ return null;
28721
+ }
28276
28722
  return toCanonicalJsonValue(value) ?? null;
28277
28723
  }
28278
28724
  function stringifyRecipeVariableValue(value) {
@@ -29070,12 +29516,12 @@ function extractReverseRuntimeValue(value, pointer) {
29070
29516
  }
29071
29517
  return readDotPath(value, pointer);
29072
29518
  }
29073
- function readDotPath(value, path11) {
29074
- if (path11.length === 0) {
29519
+ function readDotPath(value, path13) {
29520
+ if (path13.length === 0) {
29075
29521
  return value;
29076
29522
  }
29077
29523
  let current = value;
29078
- for (const segment of path11.split(".").filter((entry) => entry.length > 0)) {
29524
+ for (const segment of path13.split(".").filter((entry) => entry.length > 0)) {
29079
29525
  if (current === null || current === void 0) {
29080
29526
  return void 0;
29081
29527
  }
@@ -29548,7 +29994,7 @@ function parseSetCookieHeader(value, requestUrl) {
29548
29994
  }
29549
29995
  const url = new URL(requestUrl);
29550
29996
  let domain = url.hostname;
29551
- let path11 = defaultCookiePath(url.pathname);
29997
+ let path13 = defaultCookiePath(url.pathname);
29552
29998
  let secure = url.protocol === "https:";
29553
29999
  let expiresAt;
29554
30000
  const cookieValue = rawValueParts.join("=").trim();
@@ -29561,7 +30007,7 @@ function parseSetCookieHeader(value, requestUrl) {
29561
30007
  continue;
29562
30008
  }
29563
30009
  if (key === "path" && attributeValue.length > 0) {
29564
- path11 = attributeValue;
30010
+ path13 = attributeValue;
29565
30011
  continue;
29566
30012
  }
29567
30013
  if (key === "secure") {
@@ -29587,7 +30033,7 @@ function parseSetCookieHeader(value, requestUrl) {
29587
30033
  name,
29588
30034
  value: cookieValue,
29589
30035
  domain,
29590
- path: path11,
30036
+ path: path13,
29591
30037
  secure,
29592
30038
  ...expiresAt === void 0 ? {} : { expiresAt }
29593
30039
  }
@@ -30611,14 +31057,108 @@ function screenshotMediaType(format2) {
30611
31057
  }
30612
31058
  }
30613
31059
 
30614
- // src/mode/config.ts
30615
- var OPENSTEER_EXECUTION_MODES = ["local", "cloud"];
30616
- function assertExecutionModeSupportsEngine(mode, engine) {
30617
- if (engine !== "abp") {
30618
- return;
31060
+ // src/sdk/runtime.ts
31061
+ var OpensteerRuntime = class extends OpensteerSessionRuntime {
31062
+ constructor(options = {}) {
31063
+ const publicWorkspace = normalizeWorkspace2(options.workspace);
31064
+ const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path6.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", randomUUID()) : resolveFilesystemWorkspacePath({
31065
+ rootDir: path6.resolve(options.rootDir ?? process.cwd()),
31066
+ workspace: publicWorkspace
31067
+ }));
31068
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? publicWorkspace === void 0;
31069
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31070
+ assertSupportedEngineOptions({
31071
+ engineName,
31072
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31073
+ ...options.context === void 0 ? {} : { context: options.context }
31074
+ });
31075
+ super(buildSharedRuntimeOptions({
31076
+ name: publicWorkspace ?? "default",
31077
+ rootPath,
31078
+ ...publicWorkspace === void 0 ? {} : { workspaceName: publicWorkspace },
31079
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31080
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31081
+ ...options.context === void 0 ? {} : { context: options.context },
31082
+ engineName,
31083
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31084
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31085
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31086
+ cleanupRootOnClose
31087
+ }));
30619
31088
  }
30620
- if (mode === "cloud") {
30621
- throw new Error(
31089
+ };
31090
+ var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31091
+ constructor(options) {
31092
+ const rootPath = options.rootPath ?? path6.resolve(options.rootDir ?? process.cwd());
31093
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? false;
31094
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31095
+ assertSupportedEngineOptions({
31096
+ engineName,
31097
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31098
+ ...options.context === void 0 ? {} : { context: options.context }
31099
+ });
31100
+ super(buildSharedRuntimeOptions({
31101
+ name: options.name,
31102
+ rootPath,
31103
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31104
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31105
+ ...options.context === void 0 ? {} : { context: options.context },
31106
+ engineName,
31107
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31108
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31109
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31110
+ cleanupRootOnClose
31111
+ }));
31112
+ }
31113
+ };
31114
+ function buildSharedRuntimeOptions(input) {
31115
+ const ownership = resolveOwnership(input.browser);
31116
+ const engineFactory = input.engineFactory ?? ((factoryOptions) => new OpensteerBrowserManager({
31117
+ rootPath: input.rootPath,
31118
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31119
+ engineName: input.engineName,
31120
+ ...(factoryOptions.browser ?? input.browser) === void 0 ? {} : { browser: factoryOptions.browser ?? input.browser },
31121
+ ...(factoryOptions.launch ?? input.launch) === void 0 ? {} : { launch: factoryOptions.launch ?? input.launch },
31122
+ ...(factoryOptions.context ?? input.context) === void 0 ? {} : { context: factoryOptions.context ?? input.context }
31123
+ }).createEngine());
31124
+ return {
31125
+ name: input.name,
31126
+ ...input.workspaceName === void 0 ? {} : { workspaceName: input.workspaceName },
31127
+ rootPath: input.rootPath,
31128
+ ...input.engine === void 0 ? {} : { engine: input.engine },
31129
+ ...input.engine === void 0 ? { engineFactory } : {},
31130
+ ...input.policy === void 0 ? {} : { policy: input.policy },
31131
+ cleanupRootOnClose: input.cleanupRootOnClose,
31132
+ sessionInfo: {
31133
+ provider: {
31134
+ kind: "local",
31135
+ ownership,
31136
+ engine: input.engineName
31137
+ },
31138
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31139
+ reconnectable: !input.cleanupRootOnClose
31140
+ }
31141
+ };
31142
+ }
31143
+ function normalizeWorkspace2(workspace) {
31144
+ if (workspace === void 0) {
31145
+ return void 0;
31146
+ }
31147
+ const trimmed = workspace.trim();
31148
+ return trimmed.length === 0 ? void 0 : trimmed;
31149
+ }
31150
+ function resolveOwnership(browser) {
31151
+ return typeof browser === "object" && browser.mode === "attach" ? "attached" : "owned";
31152
+ }
31153
+
31154
+ // src/mode/config.ts
31155
+ var OPENSTEER_EXECUTION_MODES = ["local", "cloud"];
31156
+ function assertExecutionModeSupportsEngine(mode, engine) {
31157
+ if (engine !== "abp") {
31158
+ return;
31159
+ }
31160
+ if (mode === "cloud") {
31161
+ throw new Error(
30622
31162
  "ABP is not supported in cloud mode. Cloud mode currently requires Playwright."
30623
31163
  );
30624
31164
  }
@@ -31046,14 +31586,14 @@ function toPortableBrowserProfileCookieRecord(cookie) {
31046
31586
  if (!name || !domain) {
31047
31587
  return null;
31048
31588
  }
31049
- const path11 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31589
+ const path13 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31050
31590
  const expiresAt = typeof cookie.expires === "number" && Number.isFinite(cookie.expires) && cookie.expires > 0 ? Math.floor(cookie.expires * 1e3) : null;
31051
31591
  const sameSite = normalizeSameSite(cookie.sameSite);
31052
31592
  return {
31053
31593
  name,
31054
31594
  value: cookie.value,
31055
31595
  domain,
31056
- path: path11,
31596
+ path: path13,
31057
31597
  secure: cookie.secure,
31058
31598
  httpOnly: cookie.httpOnly,
31059
31599
  ...sameSite === void 0 ? {} : { sameSite },
@@ -31230,6 +31770,18 @@ var OpensteerCloudClient = class {
31230
31770
  });
31231
31771
  return await response.json();
31232
31772
  }
31773
+ async issueAccess(sessionId, capabilities) {
31774
+ const response = await this.request(
31775
+ `/v1/sessions/${encodeURIComponent(sessionId)}/access`,
31776
+ {
31777
+ method: "POST",
31778
+ body: {
31779
+ capabilities
31780
+ }
31781
+ }
31782
+ );
31783
+ return await response.json();
31784
+ }
31233
31785
  async closeSession(sessionId) {
31234
31786
  const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
31235
31787
  method: "DELETE"
@@ -31435,58 +31987,367 @@ function isFetchFailure(error) {
31435
31987
  }
31436
31988
  return error.name === "TypeError" || /fetch failed/i.test(error.message);
31437
31989
  }
31438
-
31439
- // src/cloud/session-proxy.ts
31440
- var CLOUD_SESSION_LAYOUT = "opensteer-cloud-session";
31441
- var CLOUD_SESSION_VERSION = 1;
31442
- var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31443
- var SUPPORTED_CLOUD_OPERATIONS = /* @__PURE__ */ new Set([
31444
- "session.open",
31445
- "page.goto",
31446
- "page.snapshot",
31447
- "dom.click",
31448
- "dom.hover",
31449
- "dom.input",
31450
- "dom.scroll",
31451
- "dom.extract",
31452
- "network.query",
31453
- "network.save",
31454
- "network.clear",
31455
- "request.raw",
31456
- "request-plan.infer",
31457
- "request-plan.write",
31458
- "request-plan.get",
31459
- "request-plan.list",
31460
- "request.execute",
31461
- "computer.execute",
31462
- "session.close"
31463
- ]);
31464
- function resolveCloudSessionRecordPath(rootPath) {
31465
- return path6.join(rootPath, "live", "cloud-session.json");
31990
+ var OpensteerCloudAutomationError = class extends Error {
31991
+ opensteerError;
31992
+ constructor(error) {
31993
+ super(error.message);
31994
+ this.name = "OpensteerCloudAutomationError";
31995
+ this.opensteerError = error;
31996
+ }
31997
+ };
31998
+ var OpensteerCloudAutomationClient = class {
31999
+ constructor(cloud, sessionId) {
32000
+ this.cloud = cloud;
32001
+ this.sessionId = sessionId;
32002
+ }
32003
+ socket;
32004
+ connectPromise;
32005
+ pending = /* @__PURE__ */ new Map();
32006
+ routes = /* @__PURE__ */ new Map();
32007
+ grant;
32008
+ async invoke(operation, input) {
32009
+ await this.ensureConnected();
32010
+ const requestId = `automation:${randomUUID()}`;
32011
+ const message = {
32012
+ protocol: OPENSTEER_PROTOCOL_NAME,
32013
+ version: OPENSTEER_PROTOCOL_VERSION,
32014
+ kind: "invoke",
32015
+ requestId,
32016
+ operation,
32017
+ sentAt: Date.now(),
32018
+ ...input === void 0 ? {} : { input }
32019
+ };
32020
+ return new Promise((resolve5, reject) => {
32021
+ this.pending.set(requestId, {
32022
+ resolve: (value) => resolve5(value),
32023
+ reject
32024
+ });
32025
+ try {
32026
+ this.requireSocket().send(JSON.stringify(message));
32027
+ } catch (error) {
32028
+ this.pending.delete(requestId);
32029
+ reject(error);
32030
+ }
32031
+ });
32032
+ }
32033
+ async getSessionInfo() {
32034
+ const result = await this.invoke("session.info", {});
32035
+ const sessionInfo = result;
32036
+ assertCompatibleRuntimeCoreVersion(sessionInfo);
32037
+ return sessionInfo;
32038
+ }
32039
+ async route(input) {
32040
+ const routeId = `route:${randomUUID()}`;
32041
+ const registration = await this.invoke("route.register", {
32042
+ routeId,
32043
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32044
+ urlPattern: input.urlPattern,
32045
+ ...input.resourceTypes === void 0 ? {} : { resourceTypes: input.resourceTypes },
32046
+ ...input.times === void 0 ? {} : { times: input.times },
32047
+ includeOriginal: true
32048
+ });
32049
+ this.routes.set(routeId, {
32050
+ kind: "route",
32051
+ routeId,
32052
+ input
32053
+ });
32054
+ return registration;
32055
+ }
32056
+ async interceptScript(input) {
32057
+ const routeId = `route:${randomUUID()}`;
32058
+ const registration = await this.invoke("route.register", {
32059
+ routeId,
32060
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32061
+ urlPattern: input.urlPattern,
32062
+ resourceTypes: ["script"],
32063
+ ...input.times === void 0 ? {} : { times: input.times },
32064
+ includeOriginal: true
32065
+ });
32066
+ this.routes.set(routeId, {
32067
+ kind: "intercept-script",
32068
+ routeId,
32069
+ input
32070
+ });
32071
+ return registration;
32072
+ }
32073
+ async close() {
32074
+ this.connectPromise = void 0;
32075
+ this.grant = void 0;
32076
+ if (!this.socket) {
32077
+ return;
32078
+ }
32079
+ const socket = this.socket;
32080
+ this.socket = void 0;
32081
+ for (const [requestId, pending] of this.pending) {
32082
+ pending.reject(new Error(`automation connection closed before ${requestId} completed`));
32083
+ }
32084
+ this.pending.clear();
32085
+ await new Promise((resolve5) => {
32086
+ socket.once("close", () => resolve5());
32087
+ socket.close();
32088
+ }).catch(() => void 0);
32089
+ }
32090
+ async ensureConnected() {
32091
+ if (this.socket?.readyState === WebSocket2.OPEN) {
32092
+ return;
32093
+ }
32094
+ if (this.connectPromise) {
32095
+ await this.connectPromise;
32096
+ return;
32097
+ }
32098
+ this.connectPromise = this.connect();
32099
+ try {
32100
+ await this.connectPromise;
32101
+ } finally {
32102
+ this.connectPromise = void 0;
32103
+ }
32104
+ }
32105
+ async connect() {
32106
+ const grant = await this.issueGrant("automation");
32107
+ const wsUrl = new URL(grant.wsUrl);
32108
+ wsUrl.searchParams.set("token", grant.token);
32109
+ const socket = new WebSocket2(wsUrl);
32110
+ this.socket = socket;
32111
+ socket.on("message", (data, isBinary) => {
32112
+ if (isBinary) {
32113
+ return;
32114
+ }
32115
+ this.handleMessage(data.toString());
32116
+ });
32117
+ socket.on("close", () => {
32118
+ if (this.socket === socket) {
32119
+ this.socket = void 0;
32120
+ }
32121
+ });
32122
+ socket.on("error", (error) => {
32123
+ for (const pending of this.pending.values()) {
32124
+ pending.reject(error);
32125
+ }
32126
+ this.pending.clear();
32127
+ });
32128
+ await new Promise((resolve5, reject) => {
32129
+ socket.once("open", () => resolve5());
32130
+ socket.once("error", reject);
32131
+ });
32132
+ this.send({
32133
+ protocol: OPENSTEER_PROTOCOL_NAME,
32134
+ version: OPENSTEER_PROTOCOL_VERSION,
32135
+ kind: "hello",
32136
+ sessionId: this.sessionId,
32137
+ grantKind: grant.kind
32138
+ });
32139
+ await this.restoreRoutes();
32140
+ }
32141
+ async restoreRoutes() {
32142
+ const stored = [...this.routes.values()];
32143
+ this.routes.clear();
32144
+ for (const registration of stored) {
32145
+ if (registration.kind === "route") {
32146
+ await this.route(registration.input);
32147
+ } else {
32148
+ await this.interceptScript(
32149
+ registration.input
32150
+ );
32151
+ }
32152
+ }
32153
+ }
32154
+ handleMessage(json) {
32155
+ const message = JSON.parse(json);
32156
+ if (message.protocol !== OPENSTEER_PROTOCOL_NAME) {
32157
+ return;
32158
+ }
32159
+ switch (message.kind) {
32160
+ case "result": {
32161
+ const pending = this.pending.get(message.requestId);
32162
+ if (!pending) {
32163
+ return;
32164
+ }
32165
+ this.pending.delete(message.requestId);
32166
+ pending.resolve(message.data);
32167
+ return;
32168
+ }
32169
+ case "error": {
32170
+ if (!message.requestId) {
32171
+ return;
32172
+ }
32173
+ const pending = this.pending.get(message.requestId);
32174
+ if (!pending) {
32175
+ return;
32176
+ }
32177
+ this.pending.delete(message.requestId);
32178
+ pending.reject(new OpensteerCloudAutomationError(message.error));
32179
+ return;
32180
+ }
32181
+ case "event":
32182
+ void this.handleEvent(message.event, message.data);
32183
+ return;
32184
+ case "pong":
32185
+ return;
32186
+ }
32187
+ }
32188
+ async handleEvent(event, payload) {
32189
+ if (event !== "route.request") {
32190
+ return;
32191
+ }
32192
+ const data = asRecord(payload);
32193
+ const request = asRecord(data.request);
32194
+ const original = asRecord(data.original);
32195
+ const routeId = typeof data.routeId === "string" ? data.routeId : "";
32196
+ const routeRequestId = typeof data.routeRequestId === "string" ? data.routeRequestId : "";
32197
+ if (!routeId || !routeRequestId) {
32198
+ return;
32199
+ }
32200
+ const registration = this.routes.get(routeId);
32201
+ if (!registration) {
32202
+ await this.invoke("route.resolve", {
32203
+ routeRequestId,
32204
+ decision: { kind: "continue" }
32205
+ }).catch(() => void 0);
32206
+ return;
32207
+ }
32208
+ try {
32209
+ const decision = registration.kind === "route" ? await registration.input.handler({
32210
+ request: toRouteRequest(request),
32211
+ fetchOriginal: async () => toFetchedRouteResponse(original)
32212
+ }) : {
32213
+ kind: "fulfill",
32214
+ body: await registration.input.handler({
32215
+ url: typeof request.url === "string" ? request.url : "",
32216
+ content: typeof original.body === "string" ? original.body : "",
32217
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32218
+ status: typeof original.status === "number" ? original.status : 200
32219
+ }),
32220
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32221
+ status: typeof original.status === "number" ? original.status : 200,
32222
+ contentType: findHeaderValue(
32223
+ Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32224
+ "content-type"
32225
+ ) ?? "application/javascript; charset=utf-8"
32226
+ };
32227
+ await this.invoke("route.resolve", {
32228
+ routeRequestId,
32229
+ decision: serializeRouteDecision(decision)
32230
+ }).catch(() => void 0);
32231
+ } catch {
32232
+ await this.invoke("route.resolve", {
32233
+ routeRequestId,
32234
+ decision: { kind: "continue" }
32235
+ }).catch(() => void 0);
32236
+ }
32237
+ }
32238
+ async issueGrant(kind) {
32239
+ if (this.grant && this.grant.kind === kind && this.grant.expiresAt > Date.now() + 1e4) {
32240
+ return this.grant;
32241
+ }
32242
+ const issued = await this.cloud.issueAccess(this.sessionId, [kind]);
32243
+ const grant = issued.grants[kind];
32244
+ if (!grant) {
32245
+ throw new OpensteerCloudAutomationError(
32246
+ createOpensteerError(
32247
+ "permission-denied",
32248
+ `cloud did not issue an ${kind} automation grant`
32249
+ )
32250
+ );
32251
+ }
32252
+ this.grant = grant;
32253
+ return grant;
32254
+ }
32255
+ requireSocket() {
32256
+ if (!this.socket || this.socket.readyState !== WebSocket2.OPEN) {
32257
+ throw new Error("cloud automation socket is not connected");
32258
+ }
32259
+ return this.socket;
32260
+ }
32261
+ send(message) {
32262
+ this.requireSocket().send(JSON.stringify(message));
32263
+ }
32264
+ };
32265
+ function assertCompatibleRuntimeCoreVersion(sessionInfo) {
32266
+ const runtimeCoreVersion = sessionInfo.runtime?.runtimeCoreVersion;
32267
+ if (runtimeCoreVersion === void 0) {
32268
+ return;
32269
+ }
32270
+ const expectedMajor = parseMajorVersion(OPENSTEER_RUNTIME_CORE_VERSION);
32271
+ const actualMajor = parseMajorVersion(runtimeCoreVersion);
32272
+ if (expectedMajor === null || actualMajor === null || expectedMajor === actualMajor) {
32273
+ return;
32274
+ }
32275
+ throw new Error(
32276
+ `cloud runtime-core major version ${runtimeCoreVersion} is incompatible with local SDK runtime-core ${OPENSTEER_RUNTIME_CORE_VERSION}`
32277
+ );
31466
32278
  }
31467
- async function readPersistedCloudSessionRecord(rootPath) {
31468
- const sessionPath = resolveCloudSessionRecordPath(rootPath);
31469
- if (!await pathExists(sessionPath)) {
31470
- return void 0;
32279
+ function parseMajorVersion(version) {
32280
+ const major = Number.parseInt(version.split(".", 1)[0] ?? "", 10);
32281
+ return Number.isFinite(major) ? major : null;
32282
+ }
32283
+ function serializeRouteDecision(decision) {
32284
+ if (decision.kind === "continue") {
32285
+ return { kind: "continue" };
31471
32286
  }
31472
- const parsed = await readJsonFile(sessionPath);
31473
- if (parsed.layout !== CLOUD_SESSION_LAYOUT || parsed.version !== CLOUD_SESSION_VERSION || parsed.mode !== "cloud" || typeof parsed.sessionId !== "string" || parsed.sessionId.length === 0 || typeof parsed.baseUrl !== "string" || parsed.baseUrl.length === 0 || typeof parsed.startedAt !== "number" || !Number.isFinite(parsed.startedAt) || typeof parsed.updatedAt !== "number" || !Number.isFinite(parsed.updatedAt)) {
31474
- return void 0;
32287
+ if (decision.kind === "abort") {
32288
+ return {
32289
+ kind: "abort",
32290
+ ...decision.errorCode === void 0 ? {} : { errorCode: decision.errorCode }
32291
+ };
31475
32292
  }
31476
32293
  return {
31477
- layout: CLOUD_SESSION_LAYOUT,
31478
- version: CLOUD_SESSION_VERSION,
31479
- mode: "cloud",
31480
- ...parsed.workspace === void 0 ? {} : { workspace: parsed.workspace },
31481
- sessionId: parsed.sessionId,
31482
- baseUrl: parsed.baseUrl,
31483
- startedAt: parsed.startedAt,
31484
- updatedAt: parsed.updatedAt
32294
+ kind: "fulfill",
32295
+ ...decision.status === void 0 ? {} : { status: decision.status },
32296
+ ...decision.headers === void 0 ? {} : { headers: decision.headers },
32297
+ ...decision.body === void 0 ? {} : typeof decision.body === "string" ? { body: decision.body } : { bodyBase64: Buffer.from(decision.body).toString("base64") },
32298
+ ...decision.contentType === void 0 ? {} : { contentType: decision.contentType }
31485
32299
  };
31486
32300
  }
31487
- async function hasPersistedCloudSession(rootPath) {
31488
- return await readPersistedCloudSessionRecord(rootPath) !== void 0;
32301
+ function toRouteRequest(record) {
32302
+ const pageRef = typeof record.pageRef === "string" ? record.pageRef : void 0;
32303
+ return {
32304
+ url: typeof record.url === "string" ? record.url : "",
32305
+ method: typeof record.method === "string" ? record.method : "GET",
32306
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32307
+ resourceType: typeof record.resourceType === "string" ? record.resourceType : "other",
32308
+ ...pageRef === void 0 ? {} : { pageRef },
32309
+ ...typeof record.postData === "string" ? {
32310
+ postData: {
32311
+ bytes: Uint8Array.from(Buffer.from(record.postData)),
32312
+ encoding: "identity",
32313
+ truncated: false,
32314
+ capturedByteLength: Buffer.byteLength(record.postData)
32315
+ }
32316
+ } : {}
32317
+ };
32318
+ }
32319
+ function toFetchedRouteResponse(record) {
32320
+ return {
32321
+ url: typeof record.url === "string" ? record.url : "",
32322
+ status: typeof record.status === "number" ? record.status : 200,
32323
+ statusText: typeof record.statusText === "string" ? record.statusText : "OK",
32324
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32325
+ ...typeof record.body === "string" ? {
32326
+ body: {
32327
+ bytes: Uint8Array.from(Buffer.from(record.body)),
32328
+ encoding: "identity",
32329
+ truncated: false,
32330
+ capturedByteLength: Buffer.byteLength(record.body)
32331
+ }
32332
+ } : {},
32333
+ redirected: Boolean(record.redirected)
32334
+ };
31489
32335
  }
32336
+ function findHeaderValue(headers, name) {
32337
+ return headers.find((header) => header.name.toLowerCase() === name)?.value;
32338
+ }
32339
+ function isHeaderEntry(value) {
32340
+ return value !== null && typeof value === "object" && typeof value.name === "string" && typeof value.value === "string";
32341
+ }
32342
+ function asRecord(value) {
32343
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
32344
+ return {};
32345
+ }
32346
+ return value;
32347
+ }
32348
+
32349
+ // src/cloud/session-proxy.ts
32350
+ var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31490
32351
  var CloudSessionProxy = class {
31491
32352
  rootPath;
31492
32353
  workspace;
@@ -31495,6 +32356,7 @@ var CloudSessionProxy = class {
31495
32356
  sessionId;
31496
32357
  sessionBaseUrl;
31497
32358
  client;
32359
+ automation;
31498
32360
  workspaceStore;
31499
32361
  constructor(cloud, options = {}) {
31500
32362
  this.cloud = cloud;
@@ -31515,27 +32377,73 @@ var CloudSessionProxy = class {
31515
32377
  ...input.url === void 0 ? {} : { url: input.url }
31516
32378
  });
31517
32379
  }
32380
+ async info() {
32381
+ const persisted = this.client !== void 0 || this.sessionId !== void 0 ? void 0 : await this.loadPersistedSession();
32382
+ if (this.client === void 0 && this.sessionId === void 0 && persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
32383
+ this.bindClient(persisted);
32384
+ }
32385
+ if (this.automation) {
32386
+ try {
32387
+ const sessionInfo = await this.automation.getSessionInfo();
32388
+ return {
32389
+ ...sessionInfo,
32390
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace }
32391
+ };
32392
+ } catch {
32393
+ }
32394
+ }
32395
+ return {
32396
+ provider: {
32397
+ kind: "cloud",
32398
+ ownership: "managed",
32399
+ engine: "playwright",
32400
+ baseUrl: this.cloud.getConfig().baseUrl
32401
+ },
32402
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace },
32403
+ ...this.sessionId === void 0 ? persisted?.sessionId === void 0 ? {} : { sessionId: persisted.sessionId } : { sessionId: this.sessionId },
32404
+ reconnectable: this.workspace !== void 0 || this.sessionId !== void 0 || persisted !== void 0,
32405
+ capabilities: {
32406
+ semanticOperations: opensteerSemanticOperationNames,
32407
+ sessionGrants: ["automation", "view", "cdp"],
32408
+ instrumentation: {
32409
+ route: true,
32410
+ interceptScript: true,
32411
+ networkStream: true
32412
+ }
32413
+ },
32414
+ runtime: {
32415
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
32416
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
32417
+ }
32418
+ };
32419
+ }
31518
32420
  async listPages(input = {}) {
31519
- throw unsupportedCloudOperation("page.list");
32421
+ await this.ensureSession();
32422
+ return this.requireClient().invoke("page.list", input);
31520
32423
  }
31521
32424
  async newPage(input = {}) {
31522
- throw unsupportedCloudOperation("page.new");
32425
+ await this.ensureSession();
32426
+ return this.requireAutomation().invoke("page.new", input);
31523
32427
  }
31524
32428
  async activatePage(input) {
31525
- throw unsupportedCloudOperation("page.activate");
32429
+ await this.ensureSession();
32430
+ return this.requireClient().invoke("page.activate", input);
31526
32431
  }
31527
32432
  async closePage(input = {}) {
31528
- throw unsupportedCloudOperation("page.close");
32433
+ await this.ensureSession();
32434
+ return this.requireClient().invoke("page.close", input);
31529
32435
  }
31530
32436
  async goto(input) {
31531
32437
  await this.ensureSession();
31532
32438
  return this.requireClient().invoke("page.goto", input);
31533
32439
  }
31534
32440
  async evaluate(input) {
31535
- throw unsupportedCloudOperation("page.evaluate");
32441
+ await this.ensureSession();
32442
+ return this.requireAutomation().invoke("page.evaluate", input);
31536
32443
  }
31537
32444
  async addInitScript(input) {
31538
- throw unsupportedCloudOperation("page.add-init-script");
32445
+ await this.ensureSession();
32446
+ return this.requireClient().invoke("page.add-init-script", input);
31539
32447
  }
31540
32448
  async snapshot(input = {}) {
31541
32449
  await this.ensureSession();
@@ -31570,80 +32478,112 @@ var CloudSessionProxy = class {
31570
32478
  return this.requireClient().invoke("network.save", input);
31571
32479
  }
31572
32480
  async minimizeNetwork(input) {
31573
- throw unsupportedCloudOperation("network.minimize");
32481
+ await this.ensureSession();
32482
+ return this.requireClient().invoke("network.minimize", input);
31574
32483
  }
31575
32484
  async diffNetwork(input) {
31576
- throw unsupportedCloudOperation("network.diff");
32485
+ await this.ensureSession();
32486
+ return this.requireClient().invoke("network.diff", input);
31577
32487
  }
31578
32488
  async probeNetwork(input) {
31579
- throw unsupportedCloudOperation("network.probe");
32489
+ await this.ensureSession();
32490
+ return this.requireClient().invoke("network.probe", input);
31580
32491
  }
31581
32492
  async discoverReverse(input) {
31582
- throw unsupportedCloudOperation("reverse.discover");
32493
+ await this.ensureSession();
32494
+ return this.requireClient().invoke("reverse.discover", input);
31583
32495
  }
31584
32496
  async queryReverse(input) {
31585
- throw unsupportedCloudOperation("reverse.query");
32497
+ await this.ensureSession();
32498
+ return this.requireClient().invoke("reverse.query", input);
31586
32499
  }
31587
32500
  async createReversePackage(input) {
31588
- throw unsupportedCloudOperation("reverse.package.create");
32501
+ await this.ensureSession();
32502
+ return this.requireClient().invoke("reverse.package.create", input);
31589
32503
  }
31590
32504
  async runReversePackage(input) {
31591
- throw unsupportedCloudOperation("reverse.package.run");
32505
+ await this.ensureSession();
32506
+ return this.requireClient().invoke("reverse.package.run", input);
31592
32507
  }
31593
32508
  async exportReverse(input) {
31594
- throw unsupportedCloudOperation("reverse.export");
32509
+ await this.ensureSession();
32510
+ return this.requireClient().invoke("reverse.export", input);
31595
32511
  }
31596
32512
  async getReverseReport(input) {
31597
- throw unsupportedCloudOperation("reverse.report");
32513
+ await this.ensureSession();
32514
+ return this.requireClient().invoke("reverse.report", input);
31598
32515
  }
31599
32516
  async getReversePackage(input) {
31600
- throw unsupportedCloudOperation("reverse.package.get");
32517
+ await this.ensureSession();
32518
+ return this.requireClient().invoke("reverse.package.get", input);
31601
32519
  }
31602
32520
  async listReversePackages(input = {}) {
31603
- throw unsupportedCloudOperation("reverse.package.list");
32521
+ await this.ensureSession();
32522
+ return this.requireClient().invoke("reverse.package.list", input);
31604
32523
  }
31605
32524
  async patchReversePackage(input) {
31606
- throw unsupportedCloudOperation("reverse.package.patch");
32525
+ await this.ensureSession();
32526
+ return this.requireClient().invoke("reverse.package.patch", input);
31607
32527
  }
31608
32528
  async captureInteraction(input) {
31609
- throw unsupportedCloudOperation("interaction.capture");
32529
+ await this.ensureSession();
32530
+ return this.requireClient().invoke("interaction.capture", input);
31610
32531
  }
31611
32532
  async getInteraction(input) {
31612
- throw unsupportedCloudOperation("interaction.get");
32533
+ await this.ensureSession();
32534
+ return this.requireClient().invoke("interaction.get", input);
31613
32535
  }
31614
32536
  async diffInteraction(input) {
31615
- throw unsupportedCloudOperation("interaction.diff");
32537
+ await this.ensureSession();
32538
+ return this.requireClient().invoke("interaction.diff", input);
31616
32539
  }
31617
32540
  async replayInteraction(input) {
31618
- throw unsupportedCloudOperation("interaction.replay");
32541
+ await this.ensureSession();
32542
+ return this.requireClient().invoke("interaction.replay", input);
31619
32543
  }
31620
32544
  async clearNetwork(input = {}) {
31621
32545
  await this.ensureSession();
31622
32546
  return this.requireClient().invoke("network.clear", input);
31623
32547
  }
31624
32548
  async captureScripts(input = {}) {
31625
- throw unsupportedCloudOperation("scripts.capture");
32549
+ await this.ensureSession();
32550
+ return this.requireClient().invoke("scripts.capture", input);
31626
32551
  }
31627
32552
  async readArtifact(input) {
31628
- throw unsupportedCloudOperation("artifact.read");
32553
+ await this.ensureSession();
32554
+ return this.requireClient().invoke("artifact.read", input);
31629
32555
  }
31630
32556
  async beautifyScript(input) {
31631
- throw unsupportedCloudOperation("scripts.beautify");
32557
+ await this.ensureSession();
32558
+ return this.requireClient().invoke("scripts.beautify", input);
31632
32559
  }
31633
32560
  async deobfuscateScript(input) {
31634
- throw unsupportedCloudOperation("scripts.deobfuscate");
32561
+ await this.ensureSession();
32562
+ return this.requireClient().invoke("scripts.deobfuscate", input);
31635
32563
  }
31636
32564
  async sandboxScript(input) {
31637
- throw unsupportedCloudOperation("scripts.sandbox");
32565
+ await this.ensureSession();
32566
+ return this.requireClient().invoke("scripts.sandbox", input);
31638
32567
  }
31639
32568
  async solveCaptcha(input) {
31640
- throw unsupportedCloudOperation("captcha.solve");
32569
+ await this.ensureSession();
32570
+ return this.requireClient().invoke("captcha.solve", input);
31641
32571
  }
31642
32572
  async getCookies(input = {}) {
31643
- throw unsupportedCloudOperation("inspect.cookies");
32573
+ await this.ensureSession();
32574
+ return this.requireAutomation().invoke("inspect.cookies", input);
32575
+ }
32576
+ async route(input) {
32577
+ await this.ensureSession();
32578
+ return this.requireAutomation().route(input);
32579
+ }
32580
+ async interceptScript(input) {
32581
+ await this.ensureSession();
32582
+ return this.requireAutomation().interceptScript(input);
31644
32583
  }
31645
32584
  async getStorageSnapshot(input = {}) {
31646
- throw unsupportedCloudOperation("inspect.storage");
32585
+ await this.ensureSession();
32586
+ return this.requireClient().invoke("inspect.storage", input);
31647
32587
  }
31648
32588
  async rawRequest(input) {
31649
32589
  await this.ensureSession();
@@ -31666,28 +32606,36 @@ var CloudSessionProxy = class {
31666
32606
  return this.requireClient().invoke("request-plan.list", input);
31667
32607
  }
31668
32608
  async writeAuthRecipe(input) {
31669
- throw unsupportedCloudOperation("auth-recipe.write");
32609
+ await this.ensureSession();
32610
+ return this.requireClient().invoke("auth-recipe.write", input);
31670
32611
  }
31671
32612
  async writeRecipe(input) {
31672
- throw unsupportedCloudOperation("recipe.write");
32613
+ await this.ensureSession();
32614
+ return this.requireClient().invoke("recipe.write", input);
31673
32615
  }
31674
32616
  async getAuthRecipe(input) {
31675
- throw unsupportedCloudOperation("auth-recipe.get");
32617
+ await this.ensureSession();
32618
+ return this.requireClient().invoke("auth-recipe.get", input);
31676
32619
  }
31677
32620
  async getRecipe(input) {
31678
- throw unsupportedCloudOperation("recipe.get");
32621
+ await this.ensureSession();
32622
+ return this.requireClient().invoke("recipe.get", input);
31679
32623
  }
31680
32624
  async listAuthRecipes(input = {}) {
31681
- throw unsupportedCloudOperation("auth-recipe.list");
32625
+ await this.ensureSession();
32626
+ return this.requireClient().invoke("auth-recipe.list", input);
31682
32627
  }
31683
32628
  async listRecipes(input = {}) {
31684
- throw unsupportedCloudOperation("recipe.list");
32629
+ await this.ensureSession();
32630
+ return this.requireClient().invoke("recipe.list", input);
31685
32631
  }
31686
32632
  async runAuthRecipe(input) {
31687
- throw unsupportedCloudOperation("auth-recipe.run");
32633
+ await this.ensureSession();
32634
+ return this.requireClient().invoke("auth-recipe.run", input);
31688
32635
  }
31689
32636
  async runRecipe(input) {
31690
- throw unsupportedCloudOperation("recipe.run");
32637
+ await this.ensureSession();
32638
+ return this.requireClient().invoke("recipe.run", input);
31691
32639
  }
31692
32640
  async request(input) {
31693
32641
  await this.ensureSession();
@@ -31699,8 +32647,9 @@ var CloudSessionProxy = class {
31699
32647
  }
31700
32648
  async close() {
31701
32649
  const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 || this.sessionBaseUrl === void 0 ? void 0 : {
31702
- layout: CLOUD_SESSION_LAYOUT,
31703
- version: CLOUD_SESSION_VERSION,
32650
+ layout: "opensteer-session",
32651
+ version: 1,
32652
+ provider: "cloud",
31704
32653
  mode: "cloud",
31705
32654
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31706
32655
  sessionId: this.sessionId,
@@ -31718,7 +32667,9 @@ var CloudSessionProxy = class {
31718
32667
  });
31719
32668
  }
31720
32669
  } finally {
32670
+ await this.automation?.close().catch(() => void 0);
31721
32671
  await this.clearPersistedSession();
32672
+ this.automation = void 0;
31722
32673
  this.client = void 0;
31723
32674
  this.sessionId = void 0;
31724
32675
  this.sessionBaseUrl = void 0;
@@ -31734,6 +32685,8 @@ var CloudSessionProxy = class {
31734
32685
  return;
31735
32686
  }
31736
32687
  this.client = void 0;
32688
+ await this.automation?.close().catch(() => void 0);
32689
+ this.automation = void 0;
31737
32690
  this.sessionId = void 0;
31738
32691
  this.sessionBaseUrl = void 0;
31739
32692
  }
@@ -31754,8 +32707,9 @@ var CloudSessionProxy = class {
31754
32707
  ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
31755
32708
  });
31756
32709
  const record = {
31757
- layout: CLOUD_SESSION_LAYOUT,
31758
- version: CLOUD_SESSION_VERSION,
32710
+ layout: "opensteer-session",
32711
+ version: 1,
32712
+ provider: "cloud",
31759
32713
  mode: "cloud",
31760
32714
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31761
32715
  sessionId: session.sessionId,
@@ -31773,6 +32727,7 @@ var CloudSessionProxy = class {
31773
32727
  baseUrl: record.baseUrl,
31774
32728
  getAuthorizationHeader: async () => this.cloud.buildAuthorizationHeader()
31775
32729
  });
32730
+ this.automation = new OpensteerCloudAutomationClient(this.cloud, record.sessionId);
31776
32731
  }
31777
32732
  async ensureWorkspaceStore() {
31778
32733
  if (this.workspaceStore !== void 0) {
@@ -31791,10 +32746,10 @@ var CloudSessionProxy = class {
31791
32746
  }
31792
32747
  async writePersistedSession(record) {
31793
32748
  const workspace = await this.ensureWorkspaceStore();
31794
- await writeJsonFileAtomic(resolveCloudSessionRecordPath(workspace.rootPath), record);
32749
+ await writePersistedSessionRecord(workspace.rootPath, record);
31795
32750
  }
31796
32751
  async clearPersistedSession() {
31797
- await rm(resolveCloudSessionRecordPath(this.rootPath), { force: true }).catch(() => void 0);
32752
+ await clearPersistedSessionRecord(this.rootPath).catch(() => void 0);
31798
32753
  }
31799
32754
  async isReusableCloudSession(sessionId) {
31800
32755
  try {
@@ -31813,6 +32768,12 @@ var CloudSessionProxy = class {
31813
32768
  }
31814
32769
  return this.client;
31815
32770
  }
32771
+ requireAutomation() {
32772
+ if (!this.automation) {
32773
+ throw new Error("Cloud automation session has not been initialized.");
32774
+ }
32775
+ return this.automation;
32776
+ }
31816
32777
  };
31817
32778
  function resolveCloudBrowserProfile(cloud, input) {
31818
32779
  return input.browserProfile ?? cloud.getConfig().browserProfile;
@@ -31828,22 +32789,24 @@ function assertSupportedCloudBrowserMode(browser) {
31828
32789
  function isMissingCloudSessionError(error) {
31829
32790
  return error instanceof Error && /\b404\b/.test(error.message);
31830
32791
  }
31831
- function unsupportedCloudOperation(operation) {
31832
- return new OpensteerProtocolError(
31833
- "unsupported-operation",
31834
- `Cloud mode does not currently support ${operation}.`,
31835
- {
31836
- details: {
31837
- mode: "cloud",
31838
- operation,
31839
- supportedOperations: [...SUPPORTED_CLOUD_OPERATIONS]
31840
- }
31841
- }
31842
- );
31843
- }
31844
32792
 
31845
32793
  // src/sdk/runtime-resolution.ts
31846
32794
  function resolveOpensteerRuntimeConfig(input = {}) {
32795
+ if (input.provider?.kind === "cloud") {
32796
+ return {
32797
+ mode: "cloud",
32798
+ cloud: resolveCloudConfig({
32799
+ enabled: true,
32800
+ ...input.provider,
32801
+ mode: "cloud"
32802
+ })
32803
+ };
32804
+ }
32805
+ if (input.provider?.kind === "local") {
32806
+ return {
32807
+ mode: "local"
32808
+ };
32809
+ }
31847
32810
  const mode = resolveOpensteerExecutionMode({
31848
32811
  ...input.mode === void 0 ? {} : { explicit: input.mode },
31849
32812
  cloud: input.cloud !== void 0 && input.cloud !== false,
@@ -31866,6 +32829,7 @@ function createOpensteerSemanticRuntime(input = {}) {
31866
32829
  const engine = input.engine ?? runtimeOptions.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31867
32830
  const config = resolveOpensteerRuntimeConfig({
31868
32831
  ...input.cloud === void 0 ? {} : { cloud: input.cloud },
32832
+ ...input.provider === void 0 ? {} : { provider: input.provider },
31869
32833
  ...input.mode === void 0 ? {} : { mode: input.mode },
31870
32834
  ...process.env.OPENSTEER_MODE === void 0 ? {} : { environmentMode: process.env.OPENSTEER_MODE }
31871
32835
  });
@@ -31884,6 +32848,6 @@ function createOpensteerSemanticRuntime(input = {}) {
31884
32848
  });
31885
32849
  }
31886
32850
 
31887
- export { CloudSessionProxy, DEFAULT_OPENSTEER_ENGINE, DEFERRED_MATCH_ATTR_KEYS, ElementPathError, MATCH_ATTRIBUTE_PRIORITY, OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL, OPENSTEER_ENGINE_NAMES, OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OpensteerAttachAmbiguousError, OpensteerBrowserManager, OpensteerCloudClient, OpensteerRuntime, STABLE_PRIMARY_ATTR_KEYS, assertExecutionModeSupportsEngine, buildArrayFieldPathCandidates, buildPathCandidates, buildPathSelectorHint, buildSegmentSelector, cloneElementPath, cloneReplayElementPath, cloneStructuralElementAnchor, createDomRuntime, createFilesystemOpensteerWorkspace, createOpensteerSemanticRuntime, defaultFallbackPolicy, defaultPolicy, defaultRetryPolicy, defaultSettlePolicy, defaultTimeoutPolicy, delayWithSignal, discoverLocalCdpBrowsers, dispatchSemanticOperation, hasPersistedCloudSession, inspectCdpEndpoint, isCurrentUrlField, isValidCssAttributeKey, listLocalChromeProfiles, normalizeExtractedValue, normalizeOpensteerEngineName, normalizeOpensteerExecutionMode, normalizeWorkspaceId, readPersistedCloudSessionRecord, resolveCloudConfig, resolveCloudSessionRecordPath, resolveDomActionBridge, resolveExtractedValueInContext, resolveFilesystemWorkspacePath, resolveOpensteerEngineName, resolveOpensteerExecutionMode, resolveOpensteerRuntimeConfig, runWithPolicyTimeout, sanitizeElementPath, sanitizeReplayElementPath, sanitizeStructuralElementAnchor, settleWithPolicy, shouldKeepAttributeForPath };
31888
- //# sourceMappingURL=chunk-X3G6QSCF.js.map
31889
- //# sourceMappingURL=chunk-X3G6QSCF.js.map
32851
+ export { CloudSessionProxy, DEFAULT_OPENSTEER_ENGINE, DEFERRED_MATCH_ATTR_KEYS, ElementPathError, MATCH_ATTRIBUTE_PRIORITY, OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL, OPENSTEER_ENGINE_NAMES, OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OpensteerAttachAmbiguousError, OpensteerBrowserManager, OpensteerCloudClient, OpensteerRuntime, OpensteerSessionRuntime2 as OpensteerSessionRuntime, STABLE_PRIMARY_ATTR_KEYS, assertExecutionModeSupportsEngine, buildArrayFieldPathCandidates, buildPathCandidates, buildPathSelectorHint, buildSegmentSelector, clearPersistedSessionRecord, cloneElementPath, cloneReplayElementPath, cloneStructuralElementAnchor, createDomRuntime, createFilesystemOpensteerWorkspace, createOpensteerSemanticRuntime, defaultFallbackPolicy, defaultPolicy, defaultRetryPolicy, defaultSettlePolicy, defaultTimeoutPolicy, delayWithSignal, discoverLocalCdpBrowsers, dispatchSemanticOperation, hasPersistedCloudSession, inspectCdpEndpoint, isCurrentUrlField, isValidCssAttributeKey, listLocalChromeProfiles, normalizeExtractedValue, normalizeOpensteerEngineName, normalizeOpensteerExecutionMode, normalizeWorkspaceId, readPersistedCloudSessionRecord, readPersistedLocalBrowserSessionRecord, readPersistedSessionRecord, resolveCloudConfig, resolveDomActionBridge, resolveExtractedValueInContext, resolveFilesystemWorkspacePath, resolveLiveSessionRecordPath, resolveOpensteerEngineName, resolveOpensteerExecutionMode, resolveOpensteerRuntimeConfig, runWithPolicyTimeout, sanitizeElementPath, sanitizeReplayElementPath, sanitizeStructuralElementAnchor, settleWithPolicy, shouldKeepAttributeForPath, writePersistedSessionRecord };
32852
+ //# sourceMappingURL=chunk-JK4NMMM2.js.map
32853
+ //# sourceMappingURL=chunk-JK4NMMM2.js.map