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.
package/dist/index.cjs CHANGED
@@ -16,6 +16,7 @@ var cheerio = require('cheerio');
16
16
  var prettier = require('prettier');
17
17
  var vm = require('vm');
18
18
  var zlib = require('zlib');
19
+ var WebSocket2 = require('ws');
19
20
 
20
21
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
21
22
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -43,10 +44,11 @@ var sharp__default = /*#__PURE__*/_interopDefault(sharp);
43
44
  var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio);
44
45
  var prettier__namespace = /*#__PURE__*/_interopNamespace(prettier);
45
46
  var vm__default = /*#__PURE__*/_interopDefault(vm);
47
+ var WebSocket2__default = /*#__PURE__*/_interopDefault(WebSocket2);
46
48
 
47
- // src/root.ts
49
+ // ../runtime-core/src/root.ts
48
50
 
49
- // src/json.ts
51
+ // ../runtime-core/src/json.ts
50
52
  function isPlainObject(value) {
51
53
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
52
54
  return false;
@@ -54,30 +56,30 @@ function isPlainObject(value) {
54
56
  const prototype = Object.getPrototypeOf(value);
55
57
  return prototype === Object.prototype || prototype === null;
56
58
  }
57
- function canonicalizeJsonValue(value, path11) {
59
+ function canonicalizeJsonValue(value, path13) {
58
60
  if (value === null || typeof value === "string" || typeof value === "boolean") {
59
61
  return value;
60
62
  }
61
63
  if (typeof value === "number") {
62
64
  if (!Number.isFinite(value)) {
63
- throw new TypeError(`${path11} must be a finite JSON number`);
65
+ throw new TypeError(`${path13} must be a finite JSON number`);
64
66
  }
65
67
  return value;
66
68
  }
67
69
  if (Array.isArray(value)) {
68
- return value.map((entry, index) => canonicalizeJsonValue(entry, `${path11}[${index}]`));
70
+ return value.map((entry, index) => canonicalizeJsonValue(entry, `${path13}[${index}]`));
69
71
  }
70
72
  if (!isPlainObject(value)) {
71
- throw new TypeError(`${path11} must be a plain JSON object`);
73
+ throw new TypeError(`${path13} must be a plain JSON object`);
72
74
  }
73
75
  const sorted = Object.keys(value).sort((left, right) => left.localeCompare(right));
74
76
  const result = {};
75
77
  for (const key of sorted) {
76
78
  const entry = value[key];
77
79
  if (entry === void 0) {
78
- throw new TypeError(`${path11}.${key} must not be undefined`);
80
+ throw new TypeError(`${path13}.${key} must not be undefined`);
79
81
  }
80
- result[key] = canonicalizeJsonValue(entry, `${path11}.${key}`);
82
+ result[key] = canonicalizeJsonValue(entry, `${path13}.${key}`);
81
83
  }
82
84
  return result;
83
85
  }
@@ -92,7 +94,7 @@ function stableJsonString(value) {
92
94
  `;
93
95
  }
94
96
 
95
- // src/internal/filesystem.ts
97
+ // ../runtime-core/src/internal/filesystem.ts
96
98
  var LOCK_RETRY_DELAYS_MS = [1, 2, 5, 10, 20, 50];
97
99
  function normalizeNonEmptyString(name, value) {
98
100
  const normalized = value.trim();
@@ -220,7 +222,7 @@ async function withFilesystemLock(lockPath, task) {
220
222
  }
221
223
  }
222
224
 
223
- // src/artifacts.ts
225
+ // ../runtime-core/src/artifacts.ts
224
226
  function normalizeScope(scope) {
225
227
  if (scope === void 0) {
226
228
  return {};
@@ -574,31 +576,31 @@ function oneOfSchema(members, options = {}) {
574
576
  }
575
577
 
576
578
  // ../protocol/src/validation.ts
577
- function validateJsonSchema(schema, value, path11 = "$") {
578
- return validateSchemaNode(schema, value, path11);
579
+ function validateJsonSchema(schema, value, path13 = "$") {
580
+ return validateSchemaNode(schema, value, path13);
579
581
  }
580
- function validateSchemaNode(schema, value, path11) {
582
+ function validateSchemaNode(schema, value, path13) {
581
583
  const issues = [];
582
584
  if ("const" in schema && !isJsonValueEqual(schema.const, value)) {
583
585
  issues.push({
584
- path: path11,
586
+ path: path13,
585
587
  message: `must equal ${JSON.stringify(schema.const)}`
586
588
  });
587
589
  return issues;
588
590
  }
589
591
  if (schema.enum !== void 0 && !schema.enum.some((candidate) => isJsonValueEqual(candidate, value))) {
590
592
  issues.push({
591
- path: path11,
593
+ path: path13,
592
594
  message: `must be one of ${schema.enum.map((candidate) => JSON.stringify(candidate)).join(", ")}`
593
595
  });
594
596
  return issues;
595
597
  }
596
598
  if (schema.oneOf !== void 0) {
597
- const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path11));
599
+ const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path13));
598
600
  const validBranches = branchIssues.filter((current) => current.length === 0).length;
599
601
  if (validBranches !== 1) {
600
602
  issues.push({
601
- path: path11,
603
+ path: path13,
602
604
  message: validBranches === 0 ? "must match exactly one supported shape" : "matches multiple supported shapes"
603
605
  });
604
606
  return issues;
@@ -606,11 +608,11 @@ function validateSchemaNode(schema, value, path11) {
606
608
  }
607
609
  if (schema.anyOf !== void 0) {
608
610
  const hasMatch = schema.anyOf.some(
609
- (member) => validateSchemaNode(member, value, path11).length === 0
611
+ (member) => validateSchemaNode(member, value, path13).length === 0
610
612
  );
611
613
  if (!hasMatch) {
612
614
  issues.push({
613
- path: path11,
615
+ path: path13,
614
616
  message: "must match at least one supported shape"
615
617
  });
616
618
  return issues;
@@ -618,7 +620,7 @@ function validateSchemaNode(schema, value, path11) {
618
620
  }
619
621
  if (schema.allOf !== void 0) {
620
622
  for (const member of schema.allOf) {
621
- issues.push(...validateSchemaNode(member, value, path11));
623
+ issues.push(...validateSchemaNode(member, value, path13));
622
624
  }
623
625
  if (issues.length > 0) {
624
626
  return issues;
@@ -626,7 +628,7 @@ function validateSchemaNode(schema, value, path11) {
626
628
  }
627
629
  if (schema.type !== void 0 && !matchesSchemaType(schema.type, value)) {
628
630
  issues.push({
629
- path: path11,
631
+ path: path13,
630
632
  message: `must be ${describeSchemaType(schema.type)}`
631
633
  });
632
634
  return issues;
@@ -634,19 +636,19 @@ function validateSchemaNode(schema, value, path11) {
634
636
  if (typeof value === "string") {
635
637
  if (schema.minLength !== void 0 && value.length < schema.minLength) {
636
638
  issues.push({
637
- path: path11,
639
+ path: path13,
638
640
  message: `must have length >= ${String(schema.minLength)}`
639
641
  });
640
642
  }
641
643
  if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
642
644
  issues.push({
643
- path: path11,
645
+ path: path13,
644
646
  message: `must have length <= ${String(schema.maxLength)}`
645
647
  });
646
648
  }
647
649
  if (schema.pattern !== void 0 && !new RegExp(schema.pattern).test(value)) {
648
650
  issues.push({
649
- path: path11,
651
+ path: path13,
650
652
  message: `must match pattern ${schema.pattern}`
651
653
  });
652
654
  }
@@ -655,25 +657,25 @@ function validateSchemaNode(schema, value, path11) {
655
657
  if (typeof value === "number") {
656
658
  if (schema.minimum !== void 0 && value < schema.minimum) {
657
659
  issues.push({
658
- path: path11,
660
+ path: path13,
659
661
  message: `must be >= ${String(schema.minimum)}`
660
662
  });
661
663
  }
662
664
  if (schema.maximum !== void 0 && value > schema.maximum) {
663
665
  issues.push({
664
- path: path11,
666
+ path: path13,
665
667
  message: `must be <= ${String(schema.maximum)}`
666
668
  });
667
669
  }
668
670
  if (schema.exclusiveMinimum !== void 0 && value <= schema.exclusiveMinimum) {
669
671
  issues.push({
670
- path: path11,
672
+ path: path13,
671
673
  message: `must be > ${String(schema.exclusiveMinimum)}`
672
674
  });
673
675
  }
674
676
  if (schema.exclusiveMaximum !== void 0 && value >= schema.exclusiveMaximum) {
675
677
  issues.push({
676
- path: path11,
678
+ path: path13,
677
679
  message: `must be < ${String(schema.exclusiveMaximum)}`
678
680
  });
679
681
  }
@@ -682,13 +684,13 @@ function validateSchemaNode(schema, value, path11) {
682
684
  if (Array.isArray(value)) {
683
685
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
684
686
  issues.push({
685
- path: path11,
687
+ path: path13,
686
688
  message: `must have at least ${String(schema.minItems)} items`
687
689
  });
688
690
  }
689
691
  if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
690
692
  issues.push({
691
- path: path11,
693
+ path: path13,
692
694
  message: `must have at most ${String(schema.maxItems)} items`
693
695
  });
694
696
  }
@@ -698,7 +700,7 @@ function validateSchemaNode(schema, value, path11) {
698
700
  const key = JSON.stringify(item);
699
701
  if (seen.has(key)) {
700
702
  issues.push({
701
- path: path11,
703
+ path: path13,
702
704
  message: "must not contain duplicate items"
703
705
  });
704
706
  break;
@@ -708,7 +710,7 @@ function validateSchemaNode(schema, value, path11) {
708
710
  }
709
711
  if (schema.items !== void 0) {
710
712
  for (let index = 0; index < value.length; index += 1) {
711
- issues.push(...validateSchemaNode(schema.items, value[index], `${path11}[${String(index)}]`));
713
+ issues.push(...validateSchemaNode(schema.items, value[index], `${path13}[${String(index)}]`));
712
714
  }
713
715
  }
714
716
  return issues;
@@ -718,7 +720,7 @@ function validateSchemaNode(schema, value, path11) {
718
720
  for (const requiredKey of schema.required ?? []) {
719
721
  if (!(requiredKey in value)) {
720
722
  issues.push({
721
- path: joinObjectPath(path11, requiredKey),
723
+ path: joinObjectPath(path13, requiredKey),
722
724
  message: "is required"
723
725
  });
724
726
  }
@@ -727,13 +729,13 @@ function validateSchemaNode(schema, value, path11) {
727
729
  const propertySchema = properties[key];
728
730
  if (propertySchema !== void 0) {
729
731
  issues.push(
730
- ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path11, key))
732
+ ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path13, key))
731
733
  );
732
734
  continue;
733
735
  }
734
736
  if (schema.additionalProperties === false) {
735
737
  issues.push({
736
- path: joinObjectPath(path11, key),
738
+ path: joinObjectPath(path13, key),
737
739
  message: "is not allowed"
738
740
  });
739
741
  continue;
@@ -743,7 +745,7 @@ function validateSchemaNode(schema, value, path11) {
743
745
  ...validateSchemaNode(
744
746
  schema.additionalProperties,
745
747
  propertyValue,
746
- joinObjectPath(path11, key)
748
+ joinObjectPath(path13, key)
747
749
  )
748
750
  );
749
751
  }
@@ -987,8 +989,8 @@ function matchesNetworkRecordFilters(record, filters) {
987
989
  }
988
990
  }
989
991
  if (filters.path !== void 0) {
990
- const path11 = getParsedUrl().pathname;
991
- if (!includesCaseInsensitive(path11, filters.path)) {
992
+ const path13 = getParsedUrl().pathname;
993
+ if (!includesCaseInsensitive(path13, filters.path)) {
992
994
  return false;
993
995
  }
994
996
  }
@@ -5703,6 +5705,65 @@ var opensteerComputerAnnotationNames = [
5703
5705
  "grid",
5704
5706
  "selected"
5705
5707
  ];
5708
+ var opensteerSemanticOperationNames = [
5709
+ "session.open",
5710
+ "page.list",
5711
+ "page.new",
5712
+ "page.activate",
5713
+ "page.close",
5714
+ "page.goto",
5715
+ "page.evaluate",
5716
+ "page.add-init-script",
5717
+ "page.snapshot",
5718
+ "dom.click",
5719
+ "dom.hover",
5720
+ "dom.input",
5721
+ "dom.scroll",
5722
+ "dom.extract",
5723
+ "network.query",
5724
+ "network.save",
5725
+ "network.clear",
5726
+ "network.minimize",
5727
+ "network.diff",
5728
+ "network.probe",
5729
+ "reverse.discover",
5730
+ "reverse.query",
5731
+ "reverse.package.create",
5732
+ "reverse.package.run",
5733
+ "reverse.export",
5734
+ "reverse.report",
5735
+ "reverse.package.get",
5736
+ "reverse.package.list",
5737
+ "reverse.package.patch",
5738
+ "interaction.capture",
5739
+ "interaction.get",
5740
+ "interaction.diff",
5741
+ "interaction.replay",
5742
+ "artifact.read",
5743
+ "inspect.cookies",
5744
+ "inspect.storage",
5745
+ "scripts.capture",
5746
+ "scripts.beautify",
5747
+ "scripts.deobfuscate",
5748
+ "scripts.sandbox",
5749
+ "captcha.solve",
5750
+ "request.raw",
5751
+ "request-plan.infer",
5752
+ "request-plan.write",
5753
+ "request-plan.get",
5754
+ "request-plan.list",
5755
+ "recipe.write",
5756
+ "recipe.get",
5757
+ "recipe.list",
5758
+ "recipe.run",
5759
+ "auth-recipe.write",
5760
+ "auth-recipe.get",
5761
+ "auth-recipe.list",
5762
+ "auth-recipe.run",
5763
+ "request.execute",
5764
+ "computer.execute",
5765
+ "session.close"
5766
+ ];
5706
5767
  function defineSemanticOperationSpec(spec) {
5707
5768
  return spec;
5708
5769
  }
@@ -7002,7 +7063,7 @@ function resolveDomActionBridge(engine) {
7002
7063
  return isDomActionBridgeFactory(candidate) ? candidate.call(engine) : void 0;
7003
7064
  }
7004
7065
 
7005
- // src/registry.ts
7066
+ // ../runtime-core/src/registry.ts
7006
7067
  function normalizeTags(tags) {
7007
7068
  if (tags === void 0) {
7008
7069
  return [];
@@ -8236,7 +8297,7 @@ function createTraceStore(rootPath, artifacts) {
8236
8297
  return new FilesystemTraceStore(rootPath, artifacts);
8237
8298
  }
8238
8299
 
8239
- // src/root.ts
8300
+ // ../runtime-core/src/root.ts
8240
8301
  var OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT = "opensteer-workspace";
8241
8302
  var OPENSTEER_FILESYSTEM_WORKSPACE_VERSION = 2;
8242
8303
  function normalizeWorkspaceId(workspace) {
@@ -8257,6 +8318,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8257
8318
  const browserManifestPath = path6__default.default.join(browserPath, "manifest.json");
8258
8319
  const browserUserDataDir = path6__default.default.join(browserPath, "user-data");
8259
8320
  const livePath = path6__default.default.join(options.rootPath, "live");
8321
+ const liveSessionPath = path6__default.default.join(livePath, "session.json");
8260
8322
  const liveBrowserPath = path6__default.default.join(livePath, "browser.json");
8261
8323
  const artifactsPath = path6__default.default.join(options.rootPath, "artifacts");
8262
8324
  const tracesPath = path6__default.default.join(options.rootPath, "traces");
@@ -8332,6 +8394,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8332
8394
  browserManifestPath,
8333
8395
  browserUserDataDir,
8334
8396
  livePath,
8397
+ liveSessionPath,
8335
8398
  liveBrowserPath,
8336
8399
  artifactsPath,
8337
8400
  tracesPath,
@@ -8356,7 +8419,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8356
8419
  };
8357
8420
  }
8358
8421
 
8359
- // src/policy/defaults.ts
8422
+ // ../runtime-core/src/policy/defaults.ts
8360
8423
  var DEFAULT_TIMEOUTS = {
8361
8424
  "session.open": 3e4,
8362
8425
  "page.goto": 3e4,
@@ -8439,7 +8502,7 @@ function defaultPolicy() {
8439
8502
  return DEFAULT_POLICY;
8440
8503
  }
8441
8504
 
8442
- // src/policy/settle.ts
8505
+ // ../runtime-core/src/policy/settle.ts
8443
8506
  async function settleWithPolicy(policy, input) {
8444
8507
  for (const observer of policy.observers ?? []) {
8445
8508
  if (await observer.settle(input)) {
@@ -8478,7 +8541,7 @@ function abortError() {
8478
8541
  return error;
8479
8542
  }
8480
8543
 
8481
- // src/policy/timeout.ts
8544
+ // ../runtime-core/src/policy/timeout.ts
8482
8545
  var PolicyTimeoutController = class {
8483
8546
  constructor(input, budgetMs) {
8484
8547
  this.input = input;
@@ -8588,7 +8651,7 @@ function abortError2() {
8588
8651
  return error;
8589
8652
  }
8590
8653
 
8591
- // src/runtimes/dom/match-policy.ts
8654
+ // ../runtime-core/src/runtimes/dom/match-policy.ts
8592
8655
  var ATTRIBUTE_DENY_KEYS = /* @__PURE__ */ new Set([
8593
8656
  "style",
8594
8657
  "nonce",
@@ -8820,7 +8883,7 @@ function getClauseAttributeValue(node, clause) {
8820
8883
  return String(raw);
8821
8884
  }
8822
8885
 
8823
- // src/runtimes/dom/match-selectors.ts
8886
+ // ../runtime-core/src/runtimes/dom/match-selectors.ts
8824
8887
  function buildPathCandidates(domPath) {
8825
8888
  const nodes = Array.isArray(domPath) ? domPath : [];
8826
8889
  if (!nodes.length) {
@@ -8905,7 +8968,7 @@ function buildSuffixCandidates(segments) {
8905
8968
  return out;
8906
8969
  }
8907
8970
 
8908
- // src/runtimes/dom/extraction.ts
8971
+ // ../runtime-core/src/runtimes/dom/extraction.ts
8909
8972
  var URL_LIST_ATTRIBUTES = /* @__PURE__ */ new Set(["srcset", "imagesrcset", "ping"]);
8910
8973
  var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8911
8974
  "href",
@@ -8917,9 +8980,9 @@ var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8917
8980
  "poster",
8918
8981
  "ping"
8919
8982
  ]);
8920
- function buildArrayFieldPathCandidates(path11) {
8921
- const strict = path11.nodes.length ? buildPathCandidates(path11.nodes) : [];
8922
- const relaxedNodes = stripPositionClauses(path11.nodes);
8983
+ function buildArrayFieldPathCandidates(path13) {
8984
+ const strict = path13.nodes.length ? buildPathCandidates(path13.nodes) : [];
8985
+ const relaxedNodes = stripPositionClauses(path13.nodes);
8923
8986
  const relaxed = relaxedNodes.length ? buildPathCandidates(relaxedNodes) : [];
8924
8987
  return dedupeSelectors([...strict, ...relaxed]);
8925
8988
  }
@@ -9152,7 +9215,7 @@ function readDescriptorToken(value, index) {
9152
9215
  };
9153
9216
  }
9154
9217
 
9155
- // src/runtimes/dom/errors.ts
9218
+ // ../runtime-core/src/runtimes/dom/errors.ts
9156
9219
  var ElementPathError = class extends Error {
9157
9220
  code;
9158
9221
  constructor(code, message) {
@@ -9228,6 +9291,45 @@ var selectorAdapter = {
9228
9291
  },
9229
9292
  equals(left, right) {
9230
9293
  return left === right;
9294
+ },
9295
+ existsOne(test, nodes) {
9296
+ return selectorAdapter.findOne(test, nodes) !== null;
9297
+ },
9298
+ findAll(test, nodes) {
9299
+ const matches = [];
9300
+ const visit = (node) => {
9301
+ if (selectorAdapter.isTag(node) && test(node)) {
9302
+ matches.push(node);
9303
+ }
9304
+ for (const child of selectorAdapter.getChildren(node)) {
9305
+ visit(child);
9306
+ }
9307
+ };
9308
+ for (const node of nodes) {
9309
+ visit(node);
9310
+ }
9311
+ return matches;
9312
+ },
9313
+ findOne(test, nodes) {
9314
+ const visit = (node) => {
9315
+ if (selectorAdapter.isTag(node) && test(node)) {
9316
+ return node;
9317
+ }
9318
+ for (const child of selectorAdapter.getChildren(node)) {
9319
+ const match = visit(child);
9320
+ if (match !== null) {
9321
+ return match;
9322
+ }
9323
+ }
9324
+ return null;
9325
+ };
9326
+ for (const node of nodes) {
9327
+ const match = visit(node);
9328
+ if (match !== null) {
9329
+ return match;
9330
+ }
9331
+ }
9332
+ return null;
9231
9333
  }
9232
9334
  };
9233
9335
  function createDomSnapshotIndex(snapshot) {
@@ -9411,7 +9513,7 @@ function sortNodes(nodes) {
9411
9513
  return [...nodes].sort((left, right) => left.snapshotNodeId - right.snapshotNodeId);
9412
9514
  }
9413
9515
 
9414
- // src/runtimes/dom/path.ts
9516
+ // ../runtime-core/src/runtimes/dom/path.ts
9415
9517
  var MAX_ATTRIBUTE_VALUE_LENGTH = 300;
9416
9518
  function cloneStructuralElementAnchor(anchor) {
9417
9519
  return {
@@ -9420,18 +9522,18 @@ function cloneStructuralElementAnchor(anchor) {
9420
9522
  nodes: anchor.nodes.map(clonePathNode)
9421
9523
  };
9422
9524
  }
9423
- function cloneReplayElementPath(path11) {
9525
+ function cloneReplayElementPath(path13) {
9424
9526
  return {
9425
9527
  resolution: "deterministic",
9426
- context: cloneContext(path11.context),
9427
- nodes: path11.nodes.map(clonePathNode)
9528
+ context: cloneContext(path13.context),
9529
+ nodes: path13.nodes.map(clonePathNode)
9428
9530
  };
9429
9531
  }
9430
- function cloneElementPath(path11) {
9431
- return cloneReplayElementPath(path11);
9532
+ function cloneElementPath(path13) {
9533
+ return cloneReplayElementPath(path13);
9432
9534
  }
9433
- function buildPathSelectorHint(path11) {
9434
- const nodes = path11?.nodes || [];
9535
+ function buildPathSelectorHint(path13) {
9536
+ const nodes = path13?.nodes || [];
9435
9537
  const last = nodes[nodes.length - 1];
9436
9538
  if (!last) {
9437
9539
  return "*";
@@ -9480,15 +9582,15 @@ function sanitizeStructuralElementAnchor(anchor) {
9480
9582
  nodes: sanitizeNodes(anchor.nodes)
9481
9583
  };
9482
9584
  }
9483
- function sanitizeReplayElementPath(path11) {
9585
+ function sanitizeReplayElementPath(path13) {
9484
9586
  return {
9485
9587
  resolution: "deterministic",
9486
- context: sanitizeContext(path11.context),
9487
- nodes: sanitizeNodes(path11.nodes)
9588
+ context: sanitizeContext(path13.context),
9589
+ nodes: sanitizeNodes(path13.nodes)
9488
9590
  };
9489
9591
  }
9490
- function sanitizeElementPath(path11) {
9491
- return sanitizeReplayElementPath(path11);
9592
+ function sanitizeElementPath(path13) {
9593
+ return sanitizeReplayElementPath(path13);
9492
9594
  }
9493
9595
  function buildLocalStructuralElementAnchor(index, rawTargetNode) {
9494
9596
  const targetNode = requireElementNode(index, rawTargetNode);
@@ -9611,8 +9713,8 @@ function buildTargetNotFoundMessage(domPath, diagnostics) {
9611
9713
  }
9612
9714
  return `${base} Target depth ${String(depth)}. Candidate counts: ${sample}.`;
9613
9715
  }
9614
- function buildArrayFieldCandidates(path11) {
9615
- return buildArrayFieldPathCandidates(path11);
9716
+ function buildArrayFieldCandidates(path13) {
9717
+ return buildArrayFieldPathCandidates(path13);
9616
9718
  }
9617
9719
  function firstDefinedAttribute(node, keys) {
9618
9720
  for (const key of keys) {
@@ -10028,7 +10130,7 @@ var MemoryDomDescriptorStore = class {
10028
10130
  }
10029
10131
  };
10030
10132
 
10031
- // src/runtimes/dom/executor.ts
10133
+ // ../runtime-core/src/runtimes/dom/executor.ts
10032
10134
  var MAX_DOM_ACTION_ATTEMPTS = 3;
10033
10135
  var DEFAULT_SCROLL_OPTIONS = {
10034
10136
  block: "center",
@@ -10592,7 +10694,7 @@ function pointFallsWithinQuads(point, quads) {
10592
10694
  return quads.some((quad) => rectContainsPoint(quadBounds(quad), point));
10593
10695
  }
10594
10696
 
10595
- // src/runtimes/dom/runtime.ts
10697
+ // ../runtime-core/src/runtimes/dom/runtime.ts
10596
10698
  var SnapshotSession = class {
10597
10699
  constructor(engine) {
10598
10700
  this.engine = engine;
@@ -10996,21 +11098,21 @@ var DefaultDomRuntime = class {
10996
11098
  return match;
10997
11099
  }
10998
11100
  async resolvePathTarget(session, pageRef, rawPath, source, description, descriptor) {
10999
- const path11 = sanitizeReplayElementPath(rawPath);
11000
- const context = await this.resolvePathContext(session, pageRef, path11.context);
11001
- const target = resolveDomPathInScope(context.index, path11.nodes, context.scope);
11101
+ const path13 = sanitizeReplayElementPath(rawPath);
11102
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11103
+ const target = resolveDomPathInScope(context.index, path13.nodes, context.scope);
11002
11104
  if (!target) {
11003
- throwTargetNotFound(context.index, path11.nodes, context.scope);
11105
+ throwTargetNotFound(context.index, path13.nodes, context.scope);
11004
11106
  }
11005
11107
  if (target.node.nodeRef === void 0) {
11006
11108
  throw new Error(
11007
- `resolved path "${buildPathSelectorHint(path11)}" does not point to a live element`
11109
+ `resolved path "${buildPathSelectorHint(path13)}" does not point to a live element`
11008
11110
  );
11009
11111
  }
11010
11112
  const anchor = await this.buildAnchorFromSnapshotNode(session, context.snapshot, target.node);
11011
11113
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
11012
11114
  ...description === void 0 ? {} : { description },
11013
- replayPath: path11,
11115
+ replayPath: path13,
11014
11116
  ...source === "path" || source === "descriptor" ? { selectorUsed: target.selector } : {},
11015
11117
  ...descriptor === void 0 ? {} : { descriptor }
11016
11118
  });
@@ -11031,9 +11133,9 @@ var DefaultDomRuntime = class {
11031
11133
  });
11032
11134
  }
11033
11135
  async queryAllByElementPath(session, pageRef, rawPath) {
11034
- const path11 = sanitizeReplayElementPath(rawPath);
11035
- const context = await this.resolvePathContext(session, pageRef, path11.context);
11036
- return queryAllDomPathInScope(context.index, path11.nodes, context.scope).filter(
11136
+ const path13 = sanitizeReplayElementPath(rawPath);
11137
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11138
+ return queryAllDomPathInScope(context.index, path13.nodes, context.scope).filter(
11037
11139
  (node) => node.nodeRef !== void 0
11038
11140
  ).map((node) => this.createSnapshotTarget(context.snapshot, node));
11039
11141
  }
@@ -11219,16 +11321,16 @@ var DefaultDomRuntime = class {
11219
11321
  const index = createSnapshotIndex(item.snapshot);
11220
11322
  return this.resolveFirstArrayFieldTargetInNode(index, item.node, field.path);
11221
11323
  }
11222
- resolveFirstArrayFieldTargetInNode(index, rootNode, path11) {
11223
- const normalizedPath = sanitizeElementPath(path11);
11324
+ resolveFirstArrayFieldTargetInNode(index, rootNode, path13) {
11325
+ const normalizedPath = sanitizeElementPath(path13);
11224
11326
  const selectors = buildArrayFieldCandidates(normalizedPath);
11225
11327
  if (!selectors.length) {
11226
11328
  return rootNode;
11227
11329
  }
11228
11330
  return resolveFirstWithinNodeBySelectors(index, rootNode, selectors);
11229
11331
  }
11230
- resolveUniqueArrayFieldTargetInNode(index, rootNode, path11) {
11231
- const normalizedPath = sanitizeElementPath(path11);
11332
+ resolveUniqueArrayFieldTargetInNode(index, rootNode, path13) {
11333
+ const normalizedPath = sanitizeElementPath(path13);
11232
11334
  const selectors = buildArrayFieldCandidates(normalizedPath);
11233
11335
  if (!selectors.length) {
11234
11336
  return rootNode;
@@ -11317,9 +11419,6 @@ async function clearChromeSingletonEntries(userDataDir) {
11317
11419
  );
11318
11420
  }
11319
11421
  async function sanitizeChromeProfile(userDataDir) {
11320
- if (!fs.existsSync(userDataDir)) {
11321
- return;
11322
- }
11323
11422
  const entries = await promises.readdir(userDataDir).catch(() => []);
11324
11423
  const profileDirs = entries.filter(
11325
11424
  (entry) => entry === "Default" || /^Profile \d+$/i.test(entry)
@@ -11328,9 +11427,6 @@ async function sanitizeChromeProfile(userDataDir) {
11328
11427
  }
11329
11428
  async function sanitizeProfilePreferences(userDataDir, profileDir) {
11330
11429
  const prefsPath = path6.join(userDataDir, profileDir, "Preferences");
11331
- if (!fs.existsSync(prefsPath)) {
11332
- return;
11333
- }
11334
11430
  try {
11335
11431
  const raw = await promises.readFile(prefsPath, "utf8");
11336
11432
  const prefs = JSON.parse(raw);
@@ -12101,8 +12197,8 @@ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
12101
12197
  const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
12102
12198
  return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
12103
12199
  }
12104
- function normalizeWebSocketPath(path11) {
12105
- return path11.startsWith("/") ? path11 : `/${path11}`;
12200
+ function normalizeWebSocketPath(path13) {
12201
+ return path13.startsWith("/") ? path13 : `/${path13}`;
12106
12202
  }
12107
12203
  function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
12108
12204
  try {
@@ -12238,20 +12334,121 @@ function shouldCopyEntry(input) {
12238
12334
 
12239
12335
  // src/local-browser/stealth-init-script.ts
12240
12336
  function generateStealthInitScript(profile) {
12241
- const encodedProfile = JSON.stringify(profile);
12337
+ const encodedProfile = JSON.stringify({
12338
+ ...profile,
12339
+ platformString: getPlatformString(profile.platform),
12340
+ userAgentData: buildUserAgentData(profile)
12341
+ });
12242
12342
  return `(() => {
12243
12343
  const profile = ${encodedProfile};
12344
+ var define = function(target, key, value) {
12345
+ Object.defineProperty(target, key, {
12346
+ configurable: true,
12347
+ get: typeof value === 'function' ? value : function() { return value; },
12348
+ });
12349
+ };
12244
12350
 
12245
- // --- navigator.webdriver safety net ---
12246
- // --disable-blink-features=AutomationControlled handles this at the flag level
12247
- // and CDP handles it at the protocol level, but some Chrome builds still leak
12248
- // webdriver=true when --remote-debugging-port is active.
12351
+ // --- navigator / screen mirrors for future pages ---
12249
12352
  if (navigator.webdriver === true) {
12250
12353
  Object.defineProperty(Navigator.prototype, 'webdriver', {
12251
12354
  configurable: true,
12252
12355
  get: function() { return false; },
12253
12356
  });
12254
12357
  }
12358
+ define(Navigator.prototype, 'platform', profile.platformString);
12359
+ define(Navigator.prototype, 'userAgent', profile.userAgent);
12360
+ define(Navigator.prototype, 'language', profile.locale);
12361
+ define(Navigator.prototype, 'languages', [profile.locale, 'en']);
12362
+ define(Navigator.prototype, 'maxTouchPoints', profile.maxTouchPoints);
12363
+ define(window, 'devicePixelRatio', profile.devicePixelRatio);
12364
+ define(window.screen, 'width', profile.screenResolution.width);
12365
+ define(window.screen, 'height', profile.screenResolution.height);
12366
+ define(window.screen, 'availWidth', profile.screenResolution.width);
12367
+ define(window.screen, 'availHeight', profile.screenResolution.height - 40);
12368
+ define(window.screen, 'colorDepth', 24);
12369
+ define(window.screen, 'pixelDepth', 24);
12370
+ define(Navigator.prototype, 'userAgentData', {
12371
+ brands: profile.userAgentData.brands,
12372
+ mobile: false,
12373
+ platform: profile.userAgentData.platform,
12374
+ toJSON: function() {
12375
+ return {
12376
+ brands: this.brands,
12377
+ mobile: this.mobile,
12378
+ platform: this.platform,
12379
+ };
12380
+ },
12381
+ getHighEntropyValues: async function(hints) {
12382
+ var source = {
12383
+ architecture: profile.userAgentData.architecture,
12384
+ bitness: profile.userAgentData.bitness,
12385
+ brands: profile.userAgentData.brands,
12386
+ fullVersionList: profile.userAgentData.fullVersionList,
12387
+ mobile: false,
12388
+ model: '',
12389
+ platform: profile.userAgentData.platform,
12390
+ platformVersion: profile.userAgentData.platformVersion,
12391
+ uaFullVersion: profile.browserVersion,
12392
+ wow64: false,
12393
+ };
12394
+ var values = {};
12395
+ for (var i = 0; i < hints.length; i++) {
12396
+ var hint = hints[i];
12397
+ if (Object.prototype.hasOwnProperty.call(source, hint)) {
12398
+ values[hint] = source[hint];
12399
+ }
12400
+ }
12401
+ return values;
12402
+ },
12403
+ });
12404
+
12405
+ if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
12406
+ var originalResolvedOptions = Intl.DateTimeFormat.prototype.resolvedOptions;
12407
+ Intl.DateTimeFormat.prototype.resolvedOptions = function() {
12408
+ var options = originalResolvedOptions.call(this);
12409
+ options.timeZone = profile.timezoneId;
12410
+ return options;
12411
+ };
12412
+ }
12413
+
12414
+ if (Date.prototype.getTimezoneOffset) {
12415
+ var originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
12416
+ var calculateTimezoneOffset = function(date) {
12417
+ try {
12418
+ var formatter = new Intl.DateTimeFormat('en-US', {
12419
+ timeZone: profile.timezoneId,
12420
+ hour12: false,
12421
+ year: 'numeric',
12422
+ month: '2-digit',
12423
+ day: '2-digit',
12424
+ hour: '2-digit',
12425
+ minute: '2-digit',
12426
+ second: '2-digit',
12427
+ });
12428
+ var parts = formatter.formatToParts(date);
12429
+ var values = {};
12430
+ for (var i = 0; i < parts.length; i++) {
12431
+ if (parts[i].type !== 'literal') {
12432
+ values[parts[i].type] = Number(parts[i].value);
12433
+ }
12434
+ }
12435
+ var utcTime = Date.UTC(
12436
+ values.year,
12437
+ values.month - 1,
12438
+ values.day,
12439
+ values.hour,
12440
+ values.minute,
12441
+ values.second,
12442
+ );
12443
+ return Math.round((date.getTime() - utcTime) / 60000);
12444
+ } catch {
12445
+ return originalGetTimezoneOffset.call(date);
12446
+ }
12447
+ };
12448
+ Date.prototype.getTimezoneOffset = function() {
12449
+ return calculateTimezoneOffset(this);
12450
+ };
12451
+ }
12255
12452
 
12256
12453
  // --- CDP Runtime.enable leak defense ---
12257
12454
  var _wrap = function(name) {
@@ -12325,6 +12522,34 @@ function generateStealthInitScript(profile) {
12325
12522
  }
12326
12523
  })();`;
12327
12524
  }
12525
+ function buildUserAgentData(profile) {
12526
+ const majorVersion = profile.browserVersion.split(".")[0] ?? "136";
12527
+ const platformData = {
12528
+ macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12529
+ windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12530
+ linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12531
+ };
12532
+ const platformInfo = platformData[profile.platform];
12533
+ return {
12534
+ architecture: platformInfo.architecture,
12535
+ bitness: "64",
12536
+ brands: [
12537
+ { brand: "Chromium", version: majorVersion },
12538
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: majorVersion }] : [{ brand: "Google Chrome", version: majorVersion }],
12539
+ { brand: "Not-A.Brand", version: "99" }
12540
+ ],
12541
+ fullVersionList: [
12542
+ { brand: "Chromium", version: profile.browserVersion },
12543
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: profile.browserVersion }] : [{ brand: "Google Chrome", version: profile.browserVersion }],
12544
+ { brand: "Not-A.Brand", version: "99.0.0.0" }
12545
+ ],
12546
+ platform: platformInfo.platform,
12547
+ platformVersion: platformInfo.platformVersion
12548
+ };
12549
+ }
12550
+ function getPlatformString(platform) {
12551
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12552
+ }
12328
12553
 
12329
12554
  // src/local-browser/stealth.ts
12330
12555
  var STEALTH_INIT_SCRIPT = `(() => {
@@ -12368,8 +12593,9 @@ var STEALTH_INIT_SCRIPT = `(() => {
12368
12593
  ['debug', 'log', 'info', 'error', 'warn', 'trace', 'dir'].forEach(_wrap);
12369
12594
  })();`;
12370
12595
  async function injectBrowserStealthScripts(context, input = {}) {
12371
- if (input.profile !== void 0 && input.page !== void 0) {
12372
- await applyCdpStealthOverrides(context, input.page, input.profile);
12596
+ if (input.profile !== void 0) {
12597
+ await installContextNetworkHeaders(context, input.profile);
12598
+ await installCdpStealthOverrides(context, input.profile, input.page);
12373
12599
  }
12374
12600
  if (typeof context.addInitScript === "function") {
12375
12601
  await context.addInitScript({
@@ -12390,11 +12616,12 @@ function buildUserAgentMetadata(profile) {
12390
12616
  { brand: "Not-A.Brand", version: "99.0.0.0" }
12391
12617
  ];
12392
12618
  const platformMap = {
12619
+ // Chromium keeps the reduced macOS UA token frozen to Intel even on Apple Silicon.
12393
12620
  macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12394
12621
  windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12395
12622
  linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12396
12623
  };
12397
- const platformInfo = platformMap[profile.platform] ?? platformMap.linux;
12624
+ const platformInfo = platformMap[profile.platform];
12398
12625
  return {
12399
12626
  brands,
12400
12627
  fullVersionList,
@@ -12407,7 +12634,28 @@ function buildUserAgentMetadata(profile) {
12407
12634
  wow64: false
12408
12635
  };
12409
12636
  }
12410
- async function applyCdpStealthOverrides(context, page, profile) {
12637
+ async function installCdpStealthOverrides(context, profile, initialPage) {
12638
+ const pages = initialPage === void 0 ? context.pages() : Array.from(/* @__PURE__ */ new Set([initialPage, ...context.pages()]));
12639
+ await Promise.all(pages.map((page) => applyPageOverrides(context, page, profile)));
12640
+ const appliedPages = /* @__PURE__ */ new WeakSet();
12641
+ const applyFuturePageOverrides = async (page) => {
12642
+ if (appliedPages.has(page)) {
12643
+ return;
12644
+ }
12645
+ appliedPages.add(page);
12646
+ await applyPageOverrides(context, page, profile);
12647
+ };
12648
+ if (typeof context.on === "function") {
12649
+ context.on("page", applyFuturePageOverrides);
12650
+ }
12651
+ }
12652
+ async function installContextNetworkHeaders(context, profile) {
12653
+ if (typeof context.setExtraHTTPHeaders !== "function") {
12654
+ return;
12655
+ }
12656
+ await context.setExtraHTTPHeaders(buildStealthRequestHeaders(profile)).catch(() => void 0);
12657
+ }
12658
+ async function applyPageOverrides(context, page, profile) {
12411
12659
  const contextWithCdp = context;
12412
12660
  if (typeof contextWithCdp.newCDPSession !== "function") {
12413
12661
  return;
@@ -12419,31 +12667,50 @@ async function applyCdpStealthOverrides(context, page, profile) {
12419
12667
  return;
12420
12668
  }
12421
12669
  try {
12422
- const platformString = profile.platform === "macos" ? "MacIntel" : profile.platform === "windows" ? "Win32" : "Linux x86_64";
12423
- await cdp.send("Network.setUserAgentOverride", {
12424
- userAgent: profile.userAgent,
12425
- acceptLanguage: `${profile.locale},en;q=0.9`,
12426
- platform: platformString,
12427
- userAgentMetadata: buildUserAgentMetadata(profile)
12428
- });
12429
- await cdp.send("Emulation.setDeviceMetricsOverride", {
12430
- width: profile.viewport.width,
12431
- height: profile.viewport.height,
12432
- deviceScaleFactor: profile.devicePixelRatio,
12433
- mobile: false,
12434
- screenWidth: profile.screenResolution.width,
12435
- screenHeight: profile.screenResolution.height
12436
- });
12437
- await cdp.send("Emulation.setLocaleOverride", {
12438
- locale: profile.locale
12439
- }).catch(() => void 0);
12440
- await cdp.send("Emulation.setTimezoneOverride", {
12441
- timezoneId: profile.timezoneId
12442
- }).catch(() => void 0);
12443
- await cdp.detach();
12670
+ await applyCdpStealthCommands((method, params) => cdp.send(method, params), profile);
12444
12671
  } catch {
12672
+ } finally {
12673
+ await cdp.detach().catch(() => void 0);
12445
12674
  }
12446
12675
  }
12676
+ async function applyCdpStealthCommands(send, profile) {
12677
+ await send("Network.setUserAgentOverride", {
12678
+ userAgent: profile.userAgent,
12679
+ acceptLanguage: `${profile.locale},en;q=0.9`,
12680
+ platform: getPlatformString2(profile.platform),
12681
+ userAgentMetadata: buildUserAgentMetadata(profile)
12682
+ });
12683
+ await send("Emulation.setDeviceMetricsOverride", {
12684
+ width: profile.viewport.width,
12685
+ height: profile.viewport.height,
12686
+ deviceScaleFactor: profile.devicePixelRatio,
12687
+ mobile: false,
12688
+ screenWidth: profile.screenResolution.width,
12689
+ screenHeight: profile.screenResolution.height
12690
+ });
12691
+ await send("Emulation.setLocaleOverride", {
12692
+ locale: profile.locale
12693
+ }).catch(() => void 0);
12694
+ await send("Emulation.setTimezoneOverride", {
12695
+ timezoneId: profile.timezoneId
12696
+ }).catch(() => void 0);
12697
+ }
12698
+ function buildStealthRequestHeaders(profile) {
12699
+ const metadata = buildUserAgentMetadata(profile);
12700
+ return {
12701
+ "Accept-Language": `${profile.locale},en;q=0.9`,
12702
+ "Sec-CH-UA": metadata.brands.map(formatClientHintBrand).join(", "),
12703
+ "Sec-CH-UA-Mobile": "?0",
12704
+ "Sec-CH-UA-Platform": `"${metadata.platform}"`,
12705
+ "User-Agent": profile.userAgent
12706
+ };
12707
+ }
12708
+ function formatClientHintBrand(brand2) {
12709
+ return `"${brand2.brand}";v="${brand2.version}"`;
12710
+ }
12711
+ function getPlatformString2(platform) {
12712
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12713
+ }
12447
12714
 
12448
12715
  // src/local-browser/stealth-profiles.ts
12449
12716
  var PROFILE_PRESETS = [
@@ -12536,8 +12803,115 @@ function pickStealthProfilePreset(overrides) {
12536
12803
  const pool = candidates.length > 0 ? candidates : PROFILE_PRESETS;
12537
12804
  return pool[Math.floor(Math.random() * pool.length)];
12538
12805
  }
12806
+ var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
12807
+ var OPENSTEER_LIVE_SESSION_VERSION = 1;
12808
+ var LEGACY_CLOUD_SESSION_LAYOUT = "opensteer-cloud-session";
12809
+ var LEGACY_CLOUD_SESSION_VERSION = 1;
12810
+ function resolveLiveSessionRecordPath(rootPath) {
12811
+ return path6__default.default.join(rootPath, "live", "session.json");
12812
+ }
12813
+ function resolveLegacyLiveBrowserRecordPath(rootPath) {
12814
+ return path6__default.default.join(rootPath, "live", "browser.json");
12815
+ }
12816
+ function resolveLegacyCloudSessionRecordPath(rootPath) {
12817
+ return path6__default.default.join(rootPath, "live", "cloud-session.json");
12818
+ }
12819
+ async function readPersistedSessionRecord(rootPath) {
12820
+ const sessionPath = resolveLiveSessionRecordPath(rootPath);
12821
+ if (await pathExists(sessionPath)) {
12822
+ const parsed = await readJsonFile(sessionPath);
12823
+ if (isPersistedLocalBrowserSessionRecord(parsed)) {
12824
+ return parsed;
12825
+ }
12826
+ if (isPersistedCloudSessionRecord(parsed)) {
12827
+ return parsed;
12828
+ }
12829
+ }
12830
+ const legacyCloudPath = resolveLegacyCloudSessionRecordPath(rootPath);
12831
+ if (await pathExists(legacyCloudPath)) {
12832
+ const parsed = await readJsonFile(legacyCloudPath);
12833
+ if (isLegacyCloudSessionRecord(parsed)) {
12834
+ return {
12835
+ layout: OPENSTEER_LIVE_SESSION_LAYOUT,
12836
+ version: OPENSTEER_LIVE_SESSION_VERSION,
12837
+ provider: "cloud",
12838
+ mode: "cloud",
12839
+ ...parsed.workspace === void 0 ? {} : { workspace: parsed.workspace },
12840
+ sessionId: parsed.sessionId,
12841
+ baseUrl: parsed.baseUrl,
12842
+ startedAt: parsed.startedAt,
12843
+ updatedAt: parsed.updatedAt
12844
+ };
12845
+ }
12846
+ }
12847
+ const legacyBrowserPath = resolveLegacyLiveBrowserRecordPath(rootPath);
12848
+ if (await pathExists(legacyBrowserPath)) {
12849
+ const parsed = await readJsonFile(legacyBrowserPath);
12850
+ if (isLegacyLocalBrowserSessionRecord(parsed)) {
12851
+ return {
12852
+ layout: OPENSTEER_LIVE_SESSION_LAYOUT,
12853
+ version: OPENSTEER_LIVE_SESSION_VERSION,
12854
+ provider: "local",
12855
+ mode: "browser",
12856
+ engine: parsed.engine ?? "playwright",
12857
+ ...parsed.endpoint === void 0 ? {} : { endpoint: parsed.endpoint },
12858
+ ...parsed.baseUrl === void 0 ? {} : { baseUrl: parsed.baseUrl },
12859
+ ...parsed.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: parsed.remoteDebuggingUrl },
12860
+ ...parsed.sessionDir === void 0 ? {} : { sessionDir: parsed.sessionDir },
12861
+ pid: parsed.pid,
12862
+ startedAt: parsed.startedAt,
12863
+ updatedAt: parsed.startedAt,
12864
+ ...parsed.executablePath === void 0 ? {} : { executablePath: parsed.executablePath },
12865
+ userDataDir: parsed.userDataDir
12866
+ };
12867
+ }
12868
+ }
12869
+ return void 0;
12870
+ }
12871
+ async function readPersistedCloudSessionRecord(rootPath) {
12872
+ const record = await readPersistedSessionRecord(rootPath);
12873
+ return record?.provider === "cloud" ? record : void 0;
12874
+ }
12875
+ async function readPersistedLocalBrowserSessionRecord(rootPath) {
12876
+ const record = await readPersistedSessionRecord(rootPath);
12877
+ return record?.provider === "local" ? record : void 0;
12878
+ }
12879
+ async function hasPersistedCloudSession(rootPath) {
12880
+ return await readPersistedCloudSessionRecord(rootPath) !== void 0;
12881
+ }
12882
+ async function writePersistedSessionRecord(rootPath, record) {
12883
+ await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath), record);
12884
+ await clearLegacySessionRecordPaths(rootPath);
12885
+ }
12886
+ async function clearPersistedSessionRecord(rootPath) {
12887
+ await Promise.all([
12888
+ removeIfPresent(resolveLiveSessionRecordPath(rootPath)),
12889
+ clearLegacySessionRecordPaths(rootPath)
12890
+ ]);
12891
+ }
12892
+ function isPersistedCloudSessionRecord(value) {
12893
+ 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);
12894
+ }
12895
+ function isPersistedLocalBrowserSessionRecord(value) {
12896
+ 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;
12897
+ }
12898
+ function isLegacyCloudSessionRecord(value) {
12899
+ 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);
12900
+ }
12901
+ function isLegacyLocalBrowserSessionRecord(value) {
12902
+ 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;
12903
+ }
12904
+ async function clearLegacySessionRecordPaths(rootPath) {
12905
+ await Promise.all([
12906
+ removeIfPresent(resolveLegacyLiveBrowserRecordPath(rootPath)),
12907
+ removeIfPresent(resolveLegacyCloudSessionRecordPath(rootPath))
12908
+ ]);
12909
+ }
12910
+ async function removeIfPresent(filePath) {
12911
+ await promises.rm(filePath, { force: true }).catch(() => void 0);
12912
+ }
12539
12913
 
12540
- // src/internal/engine-selection.ts
12914
+ // ../runtime-core/src/internal/engine-selection.ts
12541
12915
  var OPENSTEER_ENGINE_NAMES = ["playwright", "abp"];
12542
12916
  var DEFAULT_OPENSTEER_ENGINE = "playwright";
12543
12917
  function resolveOpensteerEngineName(input = {}) {
@@ -12740,7 +13114,7 @@ var OpensteerBrowserManager = class {
12740
13114
  await this.closePersistentBrowser(workspace);
12741
13115
  await promises.rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12742
13116
  await promises.rm(workspace.browserPath, { recursive: true, force: true });
12743
- await promises.rm(workspace.liveBrowserPath, { force: true });
13117
+ await clearPersistedSessionRecord(workspace.rootPath);
12744
13118
  await ensureDirectory(workspace.browserUserDataDir);
12745
13119
  });
12746
13120
  }
@@ -12751,7 +13125,7 @@ var OpensteerBrowserManager = class {
12751
13125
  await this.closePersistentBrowser(workspace);
12752
13126
  await promises.rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12753
13127
  await promises.rm(workspace.browserPath, { recursive: true, force: true });
12754
- await promises.rm(workspace.liveBrowserPath, { force: true });
13128
+ await clearPersistedSessionRecord(workspace.rootPath);
12755
13129
  });
12756
13130
  }
12757
13131
  async close() {
@@ -12829,12 +13203,12 @@ var OpensteerBrowserManager = class {
12829
13203
  sessionDir: resolveAbpSessionDir(workspace),
12830
13204
  ...launch?.browserExecutablePath === void 0 ? {} : { executablePath: launch.browserExecutablePath }
12831
13205
  };
12832
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13206
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12833
13207
  try {
12834
13208
  return await this.createAdoptedAbpEngine(liveRecord);
12835
13209
  } catch (error) {
12836
13210
  await terminateProcess(launched.process.pid ?? 0).catch(() => void 0);
12837
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13211
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
12838
13212
  throw error;
12839
13213
  }
12840
13214
  });
@@ -12917,7 +13291,7 @@ var OpensteerBrowserManager = class {
12917
13291
  executablePath: launched.executablePath,
12918
13292
  userDataDir: workspace.browserUserDataDir
12919
13293
  };
12920
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13294
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12921
13295
  try {
12922
13296
  return await this.createAttachedEngine({
12923
13297
  endpoint: launched.endpoint,
@@ -12926,7 +13300,7 @@ var OpensteerBrowserManager = class {
12926
13300
  });
12927
13301
  } catch (error) {
12928
13302
  await terminateProcess(launched.pid).catch(() => void 0);
12929
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13303
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
12930
13304
  throw error;
12931
13305
  }
12932
13306
  });
@@ -12946,7 +13320,10 @@ var OpensteerBrowserManager = class {
12946
13320
  const stealthProfile = resolveStealthProfile(this.contextOptions?.stealthProfile);
12947
13321
  await injectBrowserStealthScripts(
12948
13322
  context,
12949
- stealthProfile === void 0 ? {} : { profile: stealthProfile, page }
13323
+ stealthProfile === void 0 ? {} : {
13324
+ profile: stealthProfile,
13325
+ page
13326
+ }
12950
13327
  );
12951
13328
  const engine = await enginePlaywright.createPlaywrightBrowserCoreEngine({
12952
13329
  browser,
@@ -13029,7 +13406,7 @@ var OpensteerBrowserManager = class {
13029
13406
  return void 0;
13030
13407
  }
13031
13408
  if (!isProcessRunning(live.pid)) {
13032
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13409
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13033
13410
  return void 0;
13034
13411
  }
13035
13412
  if (live.engine === "playwright") {
@@ -13048,19 +13425,8 @@ var OpensteerBrowserManager = class {
13048
13425
  return live;
13049
13426
  }
13050
13427
  async readStoredLiveBrowser(workspace) {
13051
- if (!await pathExists(workspace.liveBrowserPath)) {
13052
- return void 0;
13053
- }
13054
- const live = await readJsonFile(
13055
- workspace.liveBrowserPath
13056
- );
13057
- if (live.engine === "abp") {
13058
- return live;
13059
- }
13060
- return {
13061
- ...live,
13062
- engine: "playwright"
13063
- };
13428
+ const live = await readPersistedLocalBrowserSessionRecord(workspace.rootPath);
13429
+ return live === void 0 ? void 0 : toWorkspaceLiveBrowserRecord(live);
13064
13430
  }
13065
13431
  async resolveLivePersistentEngineName() {
13066
13432
  if (this.mode !== "persistent") {
@@ -13080,7 +13446,7 @@ var OpensteerBrowserManager = class {
13080
13446
  async closePersistentBrowser(workspace) {
13081
13447
  const live = await this.readStoredLiveBrowser(workspace);
13082
13448
  if (!live) {
13083
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13449
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13084
13450
  return;
13085
13451
  }
13086
13452
  if (live.engine === "playwright") {
@@ -13088,15 +13454,21 @@ var OpensteerBrowserManager = class {
13088
13454
  await requestBrowserClose(live.endpoint).catch(() => void 0);
13089
13455
  }
13090
13456
  if (await waitForProcessExit(live.pid, BROWSER_CLOSE_TIMEOUT_MS)) {
13091
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13457
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13092
13458
  return;
13093
13459
  }
13094
13460
  await terminateProcess(live.pid).catch(() => void 0);
13095
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13461
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13096
13462
  return;
13097
13463
  }
13098
13464
  await terminateProcess(live.pid).catch(() => void 0);
13099
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13465
+ await clearPersistedSessionRecord(workspace.rootPath).catch(() => void 0);
13466
+ }
13467
+ async writeLivePersistentBrowser(workspace, live) {
13468
+ await writePersistedSessionRecord(
13469
+ workspace.rootPath,
13470
+ toPersistedLocalBrowserSessionRecord(this.workspace, live)
13471
+ );
13100
13472
  }
13101
13473
  requirePersistentMode(method) {
13102
13474
  if (this.mode !== "persistent" || this.workspace === void 0) {
@@ -13108,6 +13480,39 @@ function normalizeWorkspace(workspace) {
13108
13480
  const normalized = workspace?.trim();
13109
13481
  return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
13110
13482
  }
13483
+ function toPersistedLocalBrowserSessionRecord(workspace, live) {
13484
+ return {
13485
+ layout: "opensteer-session",
13486
+ version: 1,
13487
+ provider: "local",
13488
+ mode: "browser",
13489
+ ...workspace === void 0 ? {} : { workspace },
13490
+ engine: live.engine,
13491
+ ...live.endpoint === void 0 ? {} : { endpoint: live.endpoint },
13492
+ ...live.baseUrl === void 0 ? {} : { baseUrl: live.baseUrl },
13493
+ ...live.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: live.remoteDebuggingUrl },
13494
+ ...live.sessionDir === void 0 ? {} : { sessionDir: live.sessionDir },
13495
+ pid: live.pid,
13496
+ startedAt: live.startedAt,
13497
+ updatedAt: Date.now(),
13498
+ ...live.executablePath === void 0 ? {} : { executablePath: live.executablePath },
13499
+ userDataDir: live.userDataDir
13500
+ };
13501
+ }
13502
+ function toWorkspaceLiveBrowserRecord(record) {
13503
+ return {
13504
+ mode: "persistent",
13505
+ engine: record.engine,
13506
+ ...record.endpoint === void 0 ? {} : { endpoint: record.endpoint },
13507
+ ...record.baseUrl === void 0 ? {} : { baseUrl: record.baseUrl },
13508
+ ...record.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: record.remoteDebuggingUrl },
13509
+ ...record.sessionDir === void 0 ? {} : { sessionDir: record.sessionDir },
13510
+ pid: record.pid,
13511
+ startedAt: record.startedAt,
13512
+ ...record.executablePath === void 0 ? {} : { executablePath: record.executablePath },
13513
+ userDataDir: record.userDataDir
13514
+ };
13515
+ }
13111
13516
  function resolveBrowserMode(workspace, browser) {
13112
13517
  if (browser === void 0) {
13113
13518
  return workspace === void 0 ? "temporary" : "persistent";
@@ -13187,9 +13592,7 @@ function buildChromeArgs(userDataDir, launch, viewport) {
13187
13592
  if (isHeadless) {
13188
13593
  args.push("--headless=new");
13189
13594
  }
13190
- const hasUserWindowSize = (launch?.args ?? []).some(
13191
- (entry) => entry.startsWith("--window-size")
13192
- );
13595
+ const hasUserWindowSize = (launch?.args ?? []).some((entry) => entry.startsWith("--window-size"));
13193
13596
  if (!hasUserWindowSize) {
13194
13597
  const width = viewport?.width ?? 1440;
13195
13598
  const height = viewport?.height ?? 900;
@@ -13387,7 +13790,14 @@ async function sleep(ms) {
13387
13790
  await new Promise((resolve5) => setTimeout(resolve5, ms));
13388
13791
  }
13389
13792
 
13390
- // src/internal/errors.ts
13793
+ // ../runtime-core/package.json
13794
+ var package_default = {
13795
+ version: "0.1.0"};
13796
+
13797
+ // ../runtime-core/src/version.ts
13798
+ var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
13799
+
13800
+ // ../runtime-core/src/internal/errors.ts
13391
13801
  function normalizeThrownOpensteerError(error, fallbackMessage) {
13392
13802
  if (isOpensteerProtocolError(error)) {
13393
13803
  return toOpensteerError(error);
@@ -13398,15 +13808,6 @@ function normalizeThrownOpensteerError(error, fallbackMessage) {
13398
13808
  ...error.details === void 0 ? {} : { details: error.details }
13399
13809
  });
13400
13810
  }
13401
- if (error instanceof OpensteerAttachAmbiguousError) {
13402
- return createOpensteerError("conflict", error.message, {
13403
- details: {
13404
- candidates: error.candidates,
13405
- code: error.code,
13406
- name: error.name
13407
- }
13408
- });
13409
- }
13410
13811
  if (error instanceof Error) {
13411
13812
  return createOpensteerError("operation-failed", error.message, {
13412
13813
  details: {
@@ -13576,7 +13977,7 @@ function roundScale(value) {
13576
13977
  return Number(value.toFixed(6));
13577
13978
  }
13578
13979
 
13579
- // src/runtimes/computer-use/trace-enrichment.ts
13980
+ // ../runtime-core/src/runtimes/computer-use/trace-enrichment.ts
13580
13981
  async function enrichComputerUseTrace(input) {
13581
13982
  const tracePoints = toTracePoints(input.action);
13582
13983
  if (tracePoints.length === 0) {
@@ -13669,7 +14070,7 @@ function toOpensteerResolvedTarget(target) {
13669
14070
  };
13670
14071
  }
13671
14072
 
13672
- // src/runtimes/computer-use/runtime.ts
14073
+ // ../runtime-core/src/runtimes/computer-use/runtime.ts
13673
14074
  function createComputerUseRuntime(options) {
13674
14075
  return new DefaultComputerUseRuntime(options);
13675
14076
  }
@@ -13764,7 +14165,7 @@ function normalizeScreenshotOptions(input) {
13764
14165
  };
13765
14166
  }
13766
14167
 
13767
- // src/sdk/semantic-dispatch.ts
14168
+ // ../runtime-core/src/sdk/semantic-dispatch.ts
13768
14169
  async function dispatchSemanticOperation(runtime, operation, input, options = {}) {
13769
14170
  switch (operation) {
13770
14171
  case "session.open":
@@ -14025,7 +14426,7 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
14025
14426
  }
14026
14427
  }
14027
14428
 
14028
- // src/requests/shared.ts
14429
+ // ../runtime-core/src/requests/shared.ts
14029
14430
  var REDACTED_HEADER_VALUE = "[redacted]";
14030
14431
  var HTTP_HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
14031
14432
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
@@ -14241,14 +14642,14 @@ function resolveTextEncoding(charset) {
14241
14642
  }
14242
14643
  }
14243
14644
 
14244
- // src/requests/errors.ts
14645
+ // ../runtime-core/src/requests/errors.ts
14245
14646
  function invalidRequestPlanError(message, details = {}) {
14246
14647
  return new OpensteerProtocolError("invalid-request", message, {
14247
14648
  details
14248
14649
  });
14249
14650
  }
14250
14651
 
14251
- // src/requests/plans/index.ts
14652
+ // ../runtime-core/src/requests/plans/index.ts
14252
14653
  var HTTP_METHOD_PATTERN = /^[A-Za-z]+$/;
14253
14654
  var URL_TEMPLATE_PLACEHOLDER_PATTERN = /\{([A-Za-z][A-Za-z0-9_-]*)\}/g;
14254
14655
  function assertValidRequestPlanPayload(payload) {
@@ -14656,7 +15057,7 @@ function normalizeTrimmedString(field, value) {
14656
15057
  return normalized;
14657
15058
  }
14658
15059
 
14659
- // src/requests/inference.ts
15060
+ // ../runtime-core/src/requests/inference.ts
14660
15061
  function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14661
15062
  const url = new URL(record.record.url);
14662
15063
  const defaultQuery = Array.from(url.searchParams.entries()).map(
@@ -14669,6 +15070,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14669
15070
  const responseContentType = headerValue(record.record.responseHeaders, "content-type") ?? record.record.responseBody?.mimeType;
14670
15071
  const defaultHeaders = inferDefaultHeaders(record);
14671
15072
  const auth = inferAuth(record.record.requestHeaders);
15073
+ const body = inferRequestPlanBody(record.record.requestBody, requestContentType);
14672
15074
  const payload = normalizeRequestPlanPayload({
14673
15075
  transport: {
14674
15076
  kind: "context-http"
@@ -14679,12 +15081,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14679
15081
  ...defaultQuery.length === 0 ? {} : { defaultQuery },
14680
15082
  ...defaultHeaders.length === 0 ? {} : { defaultHeaders }
14681
15083
  },
14682
- ...requestContentType === void 0 && record.record.requestBody === void 0 ? {} : {
14683
- body: {
14684
- ...requestContentType === void 0 ? {} : { contentType: requestContentType },
14685
- required: true
14686
- }
14687
- },
15084
+ ...body === void 0 ? {} : { body },
14688
15085
  ...record.record.status === void 0 ? {} : {
14689
15086
  response: {
14690
15087
  status: record.record.status,
@@ -14740,8 +15137,52 @@ function inferAuth(headers) {
14740
15137
  }
14741
15138
  return void 0;
14742
15139
  }
15140
+ function inferRequestPlanBody(body, contentType) {
15141
+ if (body === void 0) {
15142
+ return void 0;
15143
+ }
15144
+ const text = Buffer.from(body.data, "base64").toString("utf8");
15145
+ const normalizedContentType = contentType?.toLowerCase();
15146
+ const trimmedText = text.trim();
15147
+ const parsedJson = parseJsonBody(trimmedText);
15148
+ if (normalizedContentType?.includes("application/json") === true || normalizedContentType?.includes("+json") === true || parsedJson !== void 0) {
15149
+ return {
15150
+ kind: "json",
15151
+ required: true,
15152
+ ...contentType === void 0 ? {} : { contentType },
15153
+ template: parsedJson ?? text
15154
+ };
15155
+ }
15156
+ if (normalizedContentType?.includes("application/x-www-form-urlencoded") === true) {
15157
+ return {
15158
+ kind: "form",
15159
+ required: true,
15160
+ ...contentType === void 0 ? {} : { contentType },
15161
+ fields: Array.from(new URLSearchParams(text).entries()).map(([name, value]) => ({
15162
+ name,
15163
+ value
15164
+ }))
15165
+ };
15166
+ }
15167
+ return {
15168
+ kind: "text",
15169
+ required: true,
15170
+ ...contentType === void 0 ? {} : { contentType },
15171
+ template: text
15172
+ };
15173
+ }
15174
+ function parseJsonBody(value) {
15175
+ if (value.length === 0 || !value.startsWith("{") && !value.startsWith("[")) {
15176
+ return void 0;
15177
+ }
15178
+ try {
15179
+ return JSON.parse(value);
15180
+ } catch {
15181
+ return void 0;
15182
+ }
15183
+ }
14743
15184
 
14744
- // src/reverse/materialization.ts
15185
+ // ../runtime-core/src/reverse/materialization.ts
14745
15186
  var ALWAYS_OMIT_HEADER_NAMES = /* @__PURE__ */ new Set(["content-length", "host", "priority"]);
14746
15187
  var BROWSER_OWNED_HEADER_PREFIXES = ["sec-"];
14747
15188
  function isManagedRequestHeaderName(name, transport) {
@@ -14777,7 +15218,7 @@ function finalizeMaterializedTransportRequest(request, transport) {
14777
15218
  };
14778
15219
  }
14779
15220
 
14780
- // src/network/diff.ts
15221
+ // ../runtime-core/src/network/diff.ts
14781
15222
  function diffNetworkRecords(left, right, input) {
14782
15223
  const requestDiffs = [];
14783
15224
  const responseDiffs = [];
@@ -14937,7 +15378,7 @@ function diffStringMap(prefix, left, right, includeUnchanged, output) {
14937
15378
  diffScalarField(`${prefix}.${key}`, left[key], right[key], includeUnchanged, output);
14938
15379
  }
14939
15380
  }
14940
- function diffScalarField(path11, left, right, includeUnchanged, output) {
15381
+ function diffScalarField(path13, left, right, includeUnchanged, output) {
14941
15382
  const leftValue = stringifyFieldValue(left);
14942
15383
  const rightValue = stringifyFieldValue(right);
14943
15384
  const kind = leftValue === void 0 ? rightValue === void 0 ? "unchanged" : "added" : rightValue === void 0 ? "removed" : leftValue === rightValue ? "unchanged" : "changed";
@@ -14945,7 +15386,7 @@ function diffScalarField(path11, left, right, includeUnchanged, output) {
14945
15386
  return;
14946
15387
  }
14947
15388
  output.push({
14948
- path: path11,
15389
+ path: path13,
14949
15390
  kind,
14950
15391
  ...leftValue === void 0 ? {} : { leftValue },
14951
15392
  ...rightValue === void 0 ? {} : { rightValue },
@@ -15134,7 +15575,7 @@ var NetworkJournal = class {
15134
15575
  }
15135
15576
  };
15136
15577
 
15137
- // src/network/minimize.ts
15578
+ // ../runtime-core/src/network/minimize.ts
15138
15579
  function prepareMinimizationRequest(record, preserve = []) {
15139
15580
  const requestUrl = new URL(record.record.url);
15140
15581
  const preservedNames = new Set(
@@ -15547,7 +15988,7 @@ function resolveBodyEncoding2(charset) {
15547
15988
  }
15548
15989
  }
15549
15990
 
15550
- // src/network/probe.ts
15991
+ // ../runtime-core/src/network/probe.ts
15551
15992
  var TRANSPORT_PROBE_LADDER = [
15552
15993
  "direct-http",
15553
15994
  "matched-tls",
@@ -15559,7 +16000,7 @@ function selectTransportProbeRecommendation(results) {
15559
16000
  return results.find((entry) => entry.success)?.transport ?? results.at(-1)?.transport ?? "session-http";
15560
16001
  }
15561
16002
 
15562
- // src/reverse/analysis.ts
16003
+ // ../runtime-core/src/reverse/analysis.ts
15563
16004
  var TELEMETRY_HOST_PATTERNS = [
15564
16005
  "google-analytics",
15565
16006
  "doubleclick",
@@ -15899,9 +16340,9 @@ function matchReverseTargetHints(channel, codec, targetHints) {
15899
16340
  matches.add(`host:${host}`);
15900
16341
  }
15901
16342
  }
15902
- for (const path11 of targetHints.paths ?? []) {
15903
- if (url.pathname.includes(path11)) {
15904
- matches.add(`path:${path11}`);
16343
+ for (const path13 of targetHints.paths ?? []) {
16344
+ if (url.pathname.includes(path13)) {
16345
+ matches.add(`path:${path13}`);
15905
16346
  }
15906
16347
  }
15907
16348
  for (const operationName of targetHints.operationNames ?? []) {
@@ -16753,7 +17194,7 @@ function looksHighEntropy(value) {
16753
17194
  return uniqueCharacters >= Math.min(20, Math.floor(trimmed.length * 0.6));
16754
17195
  }
16755
17196
 
16756
- // src/reverse/discovery.ts
17197
+ // ../runtime-core/src/reverse/discovery.ts
16757
17198
  function clusterReverseObservationRecords(input) {
16758
17199
  const groups = /* @__PURE__ */ new Map();
16759
17200
  for (const item of sortClusterableRecords(input.records)) {
@@ -17060,7 +17501,7 @@ async function readDirSafe(directory) {
17060
17501
  }
17061
17502
  }
17062
17503
 
17063
- // src/reverse/validation.ts
17504
+ // ../runtime-core/src/reverse/validation.ts
17064
17505
  function buildReverseValidationRules(input) {
17065
17506
  switch (input.channel.kind) {
17066
17507
  case "http":
@@ -17337,7 +17778,7 @@ function jsonStructureShape(value) {
17337
17778
  return typeof value;
17338
17779
  }
17339
17780
 
17340
- // src/reverse/workflows.ts
17781
+ // ../runtime-core/src/reverse/workflows.ts
17341
17782
  function buildReversePackageWorkflow(input) {
17342
17783
  if (input.template === void 0 && input.executeStepInput === void 0) {
17343
17784
  return [];
@@ -17706,7 +18147,7 @@ function dedupeSuggestedEdits(suggestions) {
17706
18147
  return [...new Map(suggestions.map((suggestion) => [suggestion.id, suggestion])).values()];
17707
18148
  }
17708
18149
 
17709
- // src/sdk/extraction-data-path.ts
18150
+ // ../runtime-core/src/sdk/extraction-data-path.ts
17710
18151
  function joinDataPath(base, key) {
17711
18152
  const normalizedBase = base.trim();
17712
18153
  const normalizedKey = key.trim();
@@ -17737,8 +18178,8 @@ function encodeDataPath(tokens) {
17737
18178
  }
17738
18179
  return out;
17739
18180
  }
17740
- function parseDataPath(path11) {
17741
- const input = path11.trim();
18181
+ function parseDataPath(path13) {
18182
+ const input = path13.trim();
17742
18183
  if (input.length === 0) {
17743
18184
  return [];
17744
18185
  }
@@ -17788,8 +18229,8 @@ function parseDataPath(path11) {
17788
18229
  function inflateDataPathObject(flat) {
17789
18230
  let root = {};
17790
18231
  let initialized = false;
17791
- for (const [path11, value] of Object.entries(flat)) {
17792
- const tokens = parseDataPath(path11);
18232
+ for (const [path13, value] of Object.entries(flat)) {
18233
+ const tokens = parseDataPath(path13);
17793
18234
  if (!tokens || tokens.length === 0) {
17794
18235
  continue;
17795
18236
  }
@@ -17847,7 +18288,7 @@ function assignDataPathValue(root, tokens, value) {
17847
18288
  }
17848
18289
  }
17849
18290
 
17850
- // src/sdk/extraction-consolidation.ts
18291
+ // ../runtime-core/src/sdk/extraction-consolidation.ts
17851
18292
  var STRUCTURAL_ATTR_KEYS = /* @__PURE__ */ new Set([
17852
18293
  "class",
17853
18294
  "role",
@@ -18121,8 +18562,8 @@ function buildVariantDescriptorFromCluster(descriptors) {
18121
18562
  fields: mergedFields
18122
18563
  };
18123
18564
  }
18124
- function minimizePathMatchClauses(path11, mode) {
18125
- const normalized = sanitizeElementPath(path11);
18565
+ function minimizePathMatchClauses(path13, mode) {
18566
+ const normalized = sanitizeElementPath(path13);
18126
18567
  const nodes = normalized.nodes.map((node, index) => {
18127
18568
  const isLast = index === normalized.nodes.length - 1;
18128
18569
  const attrs = node.attrs || {};
@@ -18226,8 +18667,8 @@ function seedMinimalAttrClause(attrs) {
18226
18667
  }
18227
18668
  return null;
18228
18669
  }
18229
- function relaxPathForSingleSample(path11, mode) {
18230
- const normalized = sanitizeElementPath(path11);
18670
+ function relaxPathForSingleSample(path13, mode) {
18671
+ const normalized = sanitizeElementPath(path13);
18231
18672
  const relaxedNodes = normalized.nodes.map((node, index) => {
18232
18673
  const isLast = index === normalized.nodes.length - 1;
18233
18674
  const attrs = normalizeAttrsForSingleSample(node.attrs || {});
@@ -18312,8 +18753,8 @@ function shouldKeepAttrForSingleSample(key) {
18312
18753
  }
18313
18754
  return true;
18314
18755
  }
18315
- function buildPathStructureKey(path11) {
18316
- const normalized = sanitizeElementPath(path11);
18756
+ function buildPathStructureKey(path13) {
18757
+ const normalized = sanitizeElementPath(path13);
18317
18758
  return canonicalJsonString({
18318
18759
  context: (normalized.context || []).map((hop) => ({
18319
18760
  kind: hop.kind,
@@ -18440,30 +18881,30 @@ function buildArrayItemNode(fields) {
18440
18881
  }
18441
18882
  return node;
18442
18883
  }
18443
- function insertNodeAtPath(root, path11, node) {
18444
- const tokens = parseDataPath(path11);
18884
+ function insertNodeAtPath(root, path13, node) {
18885
+ const tokens = parseDataPath(path13);
18445
18886
  if (!tokens || !tokens.length) {
18446
18887
  throw new Error(
18447
- `Invalid persisted extraction path "${path11}": expected a non-empty object path.`
18888
+ `Invalid persisted extraction path "${path13}": expected a non-empty object path.`
18448
18889
  );
18449
18890
  }
18450
18891
  if (tokens.some((token) => token.kind === "index")) {
18451
18892
  throw new Error(
18452
- `Invalid persisted extraction path "${path11}": nested array indices are not supported in cached descriptors.`
18893
+ `Invalid persisted extraction path "${path13}": nested array indices are not supported in cached descriptors.`
18453
18894
  );
18454
18895
  }
18455
18896
  let current = root;
18456
18897
  for (let index = 0; index < tokens.length; index += 1) {
18457
18898
  const token = tokens[index];
18458
18899
  if (!token || token.kind !== "prop") {
18459
- throw new Error(`Invalid persisted extraction path "${path11}": expected object segment.`);
18900
+ throw new Error(`Invalid persisted extraction path "${path13}": expected object segment.`);
18460
18901
  }
18461
18902
  const isLast = index === tokens.length - 1;
18462
18903
  if (isLast) {
18463
18904
  const existing = current[token.key];
18464
18905
  if (existing) {
18465
18906
  throw new Error(
18466
- `Conflicting persisted extraction path "${path11}" detected while building descriptor tree.`
18907
+ `Conflicting persisted extraction path "${path13}" detected while building descriptor tree.`
18467
18908
  );
18468
18909
  }
18469
18910
  current[token.key] = node;
@@ -18478,7 +18919,7 @@ function insertNodeAtPath(root, path11, node) {
18478
18919
  }
18479
18920
  if (!isPersistedObjectNode(next)) {
18480
18921
  throw new Error(
18481
- `Conflicting persisted extraction path "${path11}" detected at "${token.key}".`
18922
+ `Conflicting persisted extraction path "${path13}" detected at "${token.key}".`
18482
18923
  );
18483
18924
  }
18484
18925
  current = next;
@@ -18513,7 +18954,7 @@ function buildItemRootForArrayIndex(entries) {
18513
18954
  }
18514
18955
  const paths = entries.map(
18515
18956
  (entry) => isPersistablePathField(entry.source) ? sanitizeElementPath(entry.source.path) : null
18516
- ).filter((path11) => path11 !== null);
18957
+ ).filter((path13) => path13 !== null);
18517
18958
  if (!paths.length) {
18518
18959
  return null;
18519
18960
  }
@@ -18534,7 +18975,7 @@ function getCommonPathPrefixLength(paths) {
18534
18975
  if (!paths.length) {
18535
18976
  return 0;
18536
18977
  }
18537
- const nodeChains = paths.map((path11) => path11.nodes);
18978
+ const nodeChains = paths.map((path13) => path13.nodes);
18538
18979
  const minLength = Math.min(...nodeChains.map((nodes) => nodes.length));
18539
18980
  if (!Number.isFinite(minLength) || minLength <= 0) {
18540
18981
  return 0;
@@ -18603,30 +19044,30 @@ function mergeElementPathsByMajority(paths) {
18603
19044
  if (!paths.length) {
18604
19045
  return null;
18605
19046
  }
18606
- const normalized = paths.map((path11) => sanitizeElementPath(path11));
19047
+ const normalized = paths.map((path13) => sanitizeElementPath(path13));
18607
19048
  const contextKey = pickModeString(
18608
- normalized.map((path11) => canonicalJsonString(path11.context)),
19049
+ normalized.map((path13) => canonicalJsonString(path13.context)),
18609
19050
  1
18610
19051
  );
18611
19052
  if (!contextKey) {
18612
19053
  return null;
18613
19054
  }
18614
- const sameContext = normalized.filter((path11) => canonicalJsonString(path11.context) === contextKey);
19055
+ const sameContext = normalized.filter((path13) => canonicalJsonString(path13.context) === contextKey);
18615
19056
  if (!sameContext.length) {
18616
19057
  return null;
18617
19058
  }
18618
19059
  const targetLength = pickModeNumber(
18619
- sameContext.map((path11) => path11.nodes.length),
19060
+ sameContext.map((path13) => path13.nodes.length),
18620
19061
  1
18621
19062
  ) ?? sameContext[0]?.nodes.length ?? 0;
18622
- const aligned = sameContext.filter((path11) => path11.nodes.length === targetLength);
19063
+ const aligned = sameContext.filter((path13) => path13.nodes.length === targetLength);
18623
19064
  if (!aligned.length) {
18624
19065
  return null;
18625
19066
  }
18626
19067
  const threshold = majorityThreshold(aligned.length);
18627
19068
  const nodes = [];
18628
19069
  for (let index = 0; index < targetLength; index += 1) {
18629
- const nodesAtIndex = aligned.map((path11) => path11.nodes[index]).filter((node) => node !== void 0);
19070
+ const nodesAtIndex = aligned.map((path13) => path13.nodes[index]).filter((node) => node !== void 0);
18630
19071
  if (!nodesAtIndex.length) {
18631
19072
  return null;
18632
19073
  }
@@ -18872,8 +19313,8 @@ function clonePathContext(context) {
18872
19313
  function clonePathNodes(nodes) {
18873
19314
  return JSON.parse(JSON.stringify(nodes || []));
18874
19315
  }
18875
- function cloneElementPath2(path11) {
18876
- return JSON.parse(JSON.stringify(path11));
19316
+ function cloneElementPath2(path13) {
19317
+ return JSON.parse(JSON.stringify(path13));
18877
19318
  }
18878
19319
  function clonePersistedOpensteerExtractionNode(node) {
18879
19320
  return JSON.parse(JSON.stringify(node));
@@ -18894,7 +19335,7 @@ function isPersistedObjectNode(node) {
18894
19335
  return !!node && typeof node === "object" && !Array.isArray(node) && !isPersistedOpensteerExtractionValueNode(node) && !isPersistedOpensteerExtractionSourceNode(node) && !isPersistedOpensteerExtractionArrayNode(node);
18895
19336
  }
18896
19337
 
18897
- // src/sdk/extraction.ts
19338
+ // ../runtime-core/src/sdk/extraction.ts
18898
19339
  function assertValidOpensteerExtractionSchemaRoot(schema) {
18899
19340
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
18900
19341
  throw new Error("Invalid extraction schema: expected a JSON object at the top level.");
@@ -19159,12 +19600,12 @@ async function resolvePersistableFieldTargets(options) {
19159
19600
  anchor: field.anchor
19160
19601
  }
19161
19602
  });
19162
- const path11 = resolved.replayPath ?? await options.dom.buildPath({
19603
+ const path13 = resolved.replayPath ?? await options.dom.buildPath({
19163
19604
  locator: resolved.locator
19164
19605
  });
19165
19606
  fields.push({
19166
19607
  key: field.key,
19167
- path: sanitizeElementPath(path11),
19608
+ path: sanitizeElementPath(path13),
19168
19609
  ...field.attribute === void 0 ? {} : { attribute: field.attribute }
19169
19610
  });
19170
19611
  }
@@ -19247,8 +19688,8 @@ function collectPersistedValueNodeRefs(node) {
19247
19688
  return [
19248
19689
  {
19249
19690
  path: sanitizeElementPath(node.$path),
19250
- replacePath: (path11) => {
19251
- node.$path = sanitizeElementPath(path11);
19691
+ replacePath: (path13) => {
19692
+ node.$path = sanitizeElementPath(path13);
19252
19693
  }
19253
19694
  }
19254
19695
  ];
@@ -19262,13 +19703,13 @@ function collectPersistedValueNodeRefs(node) {
19262
19703
  }
19263
19704
  return refs;
19264
19705
  }
19265
- function hasPositionClause(path11) {
19266
- return path11.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19706
+ function hasPositionClause(path13) {
19707
+ return path13.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19267
19708
  }
19268
- function stripPositionClauses2(path11) {
19709
+ function stripPositionClauses2(path13) {
19269
19710
  return sanitizeElementPath({
19270
- context: path11.context,
19271
- nodes: path11.nodes.map((node) => ({
19711
+ context: path13.context,
19712
+ nodes: path13.nodes.map((node) => ({
19272
19713
  ...node,
19273
19714
  match: node.match.filter((clause) => clause.kind !== "position")
19274
19715
  }))
@@ -19678,14 +20119,14 @@ function normalizeNonEmptyString2(name, value) {
19678
20119
  function normalizeKey(value) {
19679
20120
  return String(value ?? "").trim();
19680
20121
  }
19681
- function labelForPath(path11) {
19682
- return path11.trim().length === 0 ? "$" : path11;
20122
+ function labelForPath(path13) {
20123
+ return path13.trim().length === 0 ? "$" : path13;
19683
20124
  }
19684
20125
  function sha256Hex3(value) {
19685
20126
  return crypto.createHash("sha256").update(value).digest("hex");
19686
20127
  }
19687
20128
 
19688
- // src/sdk/snapshot/constants.ts
20129
+ // ../runtime-core/src/sdk/snapshot/constants.ts
19689
20130
  var OPENSTEER_INTERACTIVE_ATTR = "data-opensteer-interactive";
19690
20131
  var OPENSTEER_HIDDEN_ATTR = "data-opensteer-hidden";
19691
20132
  var OPENSTEER_SCROLLABLE_ATTR = "data-opensteer-scrollable";
@@ -19753,7 +20194,7 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
19753
20194
  "wbr"
19754
20195
  ]);
19755
20196
 
19756
- // src/sdk/snapshot/cleaner.ts
20197
+ // ../runtime-core/src/sdk/snapshot/cleaner.ts
19757
20198
  var STRIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "meta", "link", "template"]);
19758
20199
  var TEXT_ATTR_MAX = 150;
19759
20200
  var URL_ATTR_MAX = 500;
@@ -20193,7 +20634,7 @@ var VOID_TAGS2 = /* @__PURE__ */ new Set([
20193
20634
  "wbr"
20194
20635
  ]);
20195
20636
 
20196
- // src/sdk/snapshot/compiler.ts
20637
+ // ../runtime-core/src/sdk/snapshot/compiler.ts
20197
20638
  async function compileOpensteerSnapshot(options) {
20198
20639
  const pageInfo = await options.engine.getPageInfo({ pageRef: options.pageRef });
20199
20640
  const mainSnapshot = await getMainDocumentSnapshot(options.engine, options.pageRef);
@@ -20744,7 +21185,7 @@ async function beautifyScriptContent(content) {
20744
21185
  });
20745
21186
  }
20746
21187
 
20747
- // src/scripts/deobfuscate.ts
21188
+ // ../runtime-core/src/scripts/deobfuscate.ts
20748
21189
  async function deobfuscateScriptContent(input) {
20749
21190
  const webcrack = await loadWebcrack();
20750
21191
  const result = await webcrack(input.content, {
@@ -20802,7 +21243,7 @@ function inferTransforms(original, deobfuscated) {
20802
21243
  return [...inferred];
20803
21244
  }
20804
21245
 
20805
- // src/scripts/sandbox-shims/minimal.ts
21246
+ // ../runtime-core/src/scripts/sandbox-shims/minimal.ts
20806
21247
  function createMinimalSandboxGlobals(options) {
20807
21248
  return {
20808
21249
  console: options.console,
@@ -20826,7 +21267,7 @@ function createMinimalSandboxGlobals(options) {
20826
21267
  };
20827
21268
  }
20828
21269
 
20829
- // src/scripts/sandbox-shims/standard.ts
21270
+ // ../runtime-core/src/scripts/sandbox-shims/standard.ts
20830
21271
  function createStandardSandboxGlobals(options) {
20831
21272
  const globals = createMinimalSandboxGlobals(options);
20832
21273
  const eventApi = createEventTargetApi();
@@ -21097,7 +21538,7 @@ function normalizeErrorMessage(error) {
21097
21538
  return error instanceof Error ? error.message : String(error);
21098
21539
  }
21099
21540
 
21100
- // src/scripts/sandbox-shims/full.ts
21541
+ // ../runtime-core/src/scripts/sandbox-shims/full.ts
21101
21542
  function createFullSandboxGlobals(options) {
21102
21543
  const globals = createStandardSandboxGlobals(options);
21103
21544
  const eventListeners = /* @__PURE__ */ new WeakMap();
@@ -21217,7 +21658,7 @@ function createFullSandboxGlobals(options) {
21217
21658
  };
21218
21659
  }
21219
21660
 
21220
- // src/scripts/sandbox.ts
21661
+ // ../runtime-core/src/scripts/sandbox.ts
21221
21662
  async function runScriptSandbox(input) {
21222
21663
  const startedAt = Date.now();
21223
21664
  const errors = [];
@@ -21441,7 +21882,7 @@ function normalizeErrorMessage2(error) {
21441
21882
  return error instanceof Error ? error.message : String(error);
21442
21883
  }
21443
21884
 
21444
- // src/captcha/solver-capsolver.ts
21885
+ // ../runtime-core/src/captcha/solver-capsolver.ts
21445
21886
  var CAPSOLVER_CREATE_TASK_URL = "https://api.capsolver.com/createTask";
21446
21887
  var CAPSOLVER_GET_TASK_RESULT_URL = "https://api.capsolver.com/getTaskResult";
21447
21888
  function createCapSolver(apiKey) {
@@ -21539,7 +21980,7 @@ function sleep2(ms, signal) {
21539
21980
  });
21540
21981
  }
21541
21982
 
21542
- // src/captcha/solver-2captcha.ts
21983
+ // ../runtime-core/src/captcha/solver-2captcha.ts
21543
21984
  var TWO_CAPTCHA_CREATE_TASK_URL = "https://api.2captcha.com/createTask";
21544
21985
  var TWO_CAPTCHA_GET_TASK_RESULT_URL = "https://api.2captcha.com/getTaskResult";
21545
21986
  function createTwoCaptchaSolver(apiKey) {
@@ -21637,7 +22078,7 @@ function sleep3(ms, signal) {
21637
22078
  });
21638
22079
  }
21639
22080
 
21640
- // src/captcha/detect.ts
22081
+ // ../runtime-core/src/captcha/detect.ts
21641
22082
  var CAPTCHA_DETECTION_SCRIPT = `(() => {
21642
22083
  const pageUrl = location.href;
21643
22084
  const findSiteKey = (selectors) => {
@@ -21699,7 +22140,7 @@ async function detectCaptchaOnPage(engine, pageRef) {
21699
22140
  return candidate;
21700
22141
  }
21701
22142
 
21702
- // src/captcha/inject.ts
22143
+ // ../runtime-core/src/captcha/inject.ts
21703
22144
  async function injectCaptchaToken(input) {
21704
22145
  const result = await input.engine.evaluatePage({
21705
22146
  pageRef: input.pageRef,
@@ -21755,7 +22196,7 @@ var CAPTCHA_INJECTION_SCRIPT = `(({ type, token }) => {
21755
22196
  return true;
21756
22197
  })`;
21757
22198
 
21758
- // src/interaction/diff.ts
22199
+ // ../runtime-core/src/interaction/diff.ts
21759
22200
  function diffInteractionTraces(left, right) {
21760
22201
  const eventSequenceMismatches = [];
21761
22202
  const eventPropertyMismatches = [];
@@ -21824,20 +22265,17 @@ function diffInteractionTraces(left, right) {
21824
22265
  };
21825
22266
  }
21826
22267
 
21827
- // src/sdk/runtime.ts
22268
+ // ../runtime-core/src/sdk/runtime.ts
21828
22269
  var requireForAuthRecipeHook = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
21829
- var OpensteerRuntime = class {
22270
+ var OpensteerSessionRuntime = class {
21830
22271
  workspace;
21831
22272
  rootPath;
21832
- publicWorkspace;
21833
- configuredBrowser;
21834
- configuredLaunch;
21835
- configuredContext;
21836
- configuredEngineName;
22273
+ workspaceName;
21837
22274
  injectedEngine;
21838
22275
  engineFactory;
21839
22276
  policy;
21840
22277
  cleanupRootOnClose;
22278
+ sessionInfoBase;
21841
22279
  root;
21842
22280
  engine;
21843
22281
  dom;
@@ -21852,35 +22290,46 @@ var OpensteerRuntime = class {
21852
22290
  cookieJars = /* @__PURE__ */ new Map();
21853
22291
  recipeCache = /* @__PURE__ */ new Map();
21854
22292
  ownsEngine = false;
21855
- constructor(options = {}) {
21856
- this.publicWorkspace = options.workspace?.trim() === void 0 || options.workspace?.trim().length === 0 ? void 0 : options.workspace.trim();
21857
- this.workspace = normalizeNamespace3(options.workspace);
21858
- this.rootPath = options.rootPath ?? (this.publicWorkspace === void 0 ? path6__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : path6__default.default.resolve(
21859
- options.rootDir ?? process.cwd(),
21860
- ".opensteer",
21861
- "workspaces",
21862
- encodeURIComponent(this.publicWorkspace)
21863
- ));
21864
- this.configuredBrowser = options.browser;
21865
- this.configuredLaunch = options.launch;
21866
- this.configuredContext = options.context;
21867
- this.configuredEngineName = options.engineName;
22293
+ constructor(options) {
22294
+ this.workspace = normalizeNamespace3(options.name);
22295
+ this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
22296
+ this.root = options.workspace;
22297
+ this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6__default.default.resolve(process.cwd(), ".opensteer", "temporary", crypto.randomUUID());
21868
22298
  this.injectedEngine = options.engine;
21869
- this.engineFactory = options.engineFactory ?? ((factoryOptions) => {
21870
- const browser = factoryOptions.browser ?? this.configuredBrowser;
21871
- const launch = factoryOptions.launch ?? this.configuredLaunch;
21872
- const context = factoryOptions.context ?? this.configuredContext;
21873
- return new OpensteerBrowserManager({
21874
- rootPath: this.rootPath,
21875
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
21876
- ...this.configuredEngineName === void 0 ? {} : { engineName: this.configuredEngineName },
21877
- ...browser === void 0 ? {} : { browser },
21878
- ...launch === void 0 ? {} : { launch },
21879
- ...context === void 0 ? {} : { context }
21880
- }).createEngine();
21881
- });
22299
+ this.engineFactory = options.engineFactory;
21882
22300
  this.policy = options.policy ?? defaultPolicy();
21883
- this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.publicWorkspace === void 0;
22301
+ this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
22302
+ this.sessionInfoBase = options.sessionInfo ?? {};
22303
+ if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
22304
+ throw new Error("OpensteerSessionRuntime requires an engine or engineFactory.");
22305
+ }
22306
+ }
22307
+ async info() {
22308
+ const base = this.sessionInfoBase;
22309
+ return {
22310
+ provider: base.provider ?? {
22311
+ kind: "local",
22312
+ ownership: "owned",
22313
+ engine: "playwright"
22314
+ },
22315
+ ...base.workspace === void 0 ? {} : { workspace: base.workspace },
22316
+ ...this.sessionRef === void 0 ? {} : { sessionId: this.sessionRef },
22317
+ ...this.pageRef === void 0 ? {} : { activePageRef: this.pageRef },
22318
+ reconnectable: base.reconnectable ?? !this.cleanupRootOnClose,
22319
+ capabilities: base.capabilities ?? {
22320
+ semanticOperations: opensteerSemanticOperationNames,
22321
+ instrumentation: {
22322
+ route: true,
22323
+ interceptScript: true,
22324
+ networkStream: false
22325
+ }
22326
+ },
22327
+ ...base.grants === void 0 ? {} : { grants: base.grants },
22328
+ runtime: base.runtime ?? {
22329
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
22330
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
22331
+ }
22332
+ };
21884
22333
  }
21885
22334
  async open(input = {}, options = {}) {
21886
22335
  assertValidSemanticOperationInput("session.open", input);
@@ -26251,14 +26700,14 @@ var OpensteerRuntime = class {
26251
26700
  return saved;
26252
26701
  }
26253
26702
  resolveCurrentStateSource() {
26254
- const browser = this.configuredBrowser;
26255
- if (browser === void 0 || browser === "temporary") {
26256
- return "temporary";
26703
+ const ownership = this.sessionInfoBase.provider?.ownership;
26704
+ if (ownership === "attached") {
26705
+ return "attach";
26257
26706
  }
26258
- if (browser === "persistent") {
26707
+ if (this.workspaceName !== void 0 || this.cleanupRootOnClose === false) {
26259
26708
  return "persistent";
26260
26709
  }
26261
- return "attach";
26710
+ return "temporary";
26262
26711
  }
26263
26712
  async resolveReverseCaseById(caseId) {
26264
26713
  const record = await (await this.ensureRoot()).registry.reverseCases.getById(caseId);
@@ -27825,8 +28274,8 @@ var OpensteerRuntime = class {
27825
28274
  async ensureRoot() {
27826
28275
  this.root ??= await createFilesystemOpensteerWorkspace({
27827
28276
  rootPath: this.rootPath,
27828
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
27829
- scope: this.publicWorkspace === void 0 ? "temporary" : "workspace"
28277
+ ...this.workspaceName === void 0 ? {} : { workspace: this.workspaceName },
28278
+ scope: this.workspaceName === void 0 ? "temporary" : "workspace"
27830
28279
  });
27831
28280
  return this.root;
27832
28281
  }
@@ -27839,15 +28288,10 @@ var OpensteerRuntime = class {
27839
28288
  this.ownsEngine = false;
27840
28289
  return this.engine;
27841
28290
  }
27842
- const browser = overrides.browser ?? this.configuredBrowser;
27843
- const launch = overrides.launch ?? this.configuredLaunch;
27844
- const context = overrides.context ?? this.configuredContext;
27845
- const factoryOptions = {
27846
- ...browser === void 0 ? {} : { browser },
27847
- ...launch === void 0 ? {} : { launch },
27848
- ...context === void 0 ? {} : { context }
27849
- };
27850
- this.engine = await this.engineFactory(factoryOptions);
28291
+ if (this.engineFactory === void 0) {
28292
+ throw new Error("Opensteer engine factory is not initialized");
28293
+ }
28294
+ this.engine = await this.engineFactory(overrides);
27851
28295
  this.ownsEngine = true;
27852
28296
  return this.engine;
27853
28297
  }
@@ -28304,6 +28748,9 @@ function parseContentType2(contentType) {
28304
28748
  };
28305
28749
  }
28306
28750
  function toJsonValueOrNull(value) {
28751
+ if (value === void 0) {
28752
+ return null;
28753
+ }
28307
28754
  return toCanonicalJsonValue(value) ?? null;
28308
28755
  }
28309
28756
  function stringifyRecipeVariableValue(value) {
@@ -29101,12 +29548,12 @@ function extractReverseRuntimeValue(value, pointer) {
29101
29548
  }
29102
29549
  return readDotPath(value, pointer);
29103
29550
  }
29104
- function readDotPath(value, path11) {
29105
- if (path11.length === 0) {
29551
+ function readDotPath(value, path13) {
29552
+ if (path13.length === 0) {
29106
29553
  return value;
29107
29554
  }
29108
29555
  let current = value;
29109
- for (const segment of path11.split(".").filter((entry) => entry.length > 0)) {
29556
+ for (const segment of path13.split(".").filter((entry) => entry.length > 0)) {
29110
29557
  if (current === null || current === void 0) {
29111
29558
  return void 0;
29112
29559
  }
@@ -29579,7 +30026,7 @@ function parseSetCookieHeader(value, requestUrl) {
29579
30026
  }
29580
30027
  const url = new URL(requestUrl);
29581
30028
  let domain = url.hostname;
29582
- let path11 = defaultCookiePath(url.pathname);
30029
+ let path13 = defaultCookiePath(url.pathname);
29583
30030
  let secure = url.protocol === "https:";
29584
30031
  let expiresAt;
29585
30032
  const cookieValue = rawValueParts.join("=").trim();
@@ -29592,7 +30039,7 @@ function parseSetCookieHeader(value, requestUrl) {
29592
30039
  continue;
29593
30040
  }
29594
30041
  if (key === "path" && attributeValue.length > 0) {
29595
- path11 = attributeValue;
30042
+ path13 = attributeValue;
29596
30043
  continue;
29597
30044
  }
29598
30045
  if (key === "secure") {
@@ -29618,7 +30065,7 @@ function parseSetCookieHeader(value, requestUrl) {
29618
30065
  name,
29619
30066
  value: cookieValue,
29620
30067
  domain,
29621
- path: path11,
30068
+ path: path13,
29622
30069
  secure,
29623
30070
  ...expiresAt === void 0 ? {} : { expiresAt }
29624
30071
  }
@@ -30642,11 +31089,105 @@ function screenshotMediaType(format2) {
30642
31089
  }
30643
31090
  }
30644
31091
 
30645
- // src/mode/config.ts
30646
- var OPENSTEER_EXECUTION_MODES = ["local", "cloud"];
30647
- function assertExecutionModeSupportsEngine(mode, engine) {
30648
- if (engine !== "abp") {
30649
- return;
31092
+ // src/sdk/runtime.ts
31093
+ var OpensteerRuntime = class extends OpensteerSessionRuntime {
31094
+ constructor(options = {}) {
31095
+ const publicWorkspace = normalizeWorkspace2(options.workspace);
31096
+ const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path6__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : resolveFilesystemWorkspacePath({
31097
+ rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
31098
+ workspace: publicWorkspace
31099
+ }));
31100
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? publicWorkspace === void 0;
31101
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31102
+ assertSupportedEngineOptions({
31103
+ engineName,
31104
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31105
+ ...options.context === void 0 ? {} : { context: options.context }
31106
+ });
31107
+ super(buildSharedRuntimeOptions({
31108
+ name: publicWorkspace ?? "default",
31109
+ rootPath,
31110
+ ...publicWorkspace === void 0 ? {} : { workspaceName: publicWorkspace },
31111
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31112
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31113
+ ...options.context === void 0 ? {} : { context: options.context },
31114
+ engineName,
31115
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31116
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31117
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31118
+ cleanupRootOnClose
31119
+ }));
31120
+ }
31121
+ };
31122
+ var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31123
+ constructor(options) {
31124
+ const rootPath = options.rootPath ?? path6__default.default.resolve(options.rootDir ?? process.cwd());
31125
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? false;
31126
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31127
+ assertSupportedEngineOptions({
31128
+ engineName,
31129
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31130
+ ...options.context === void 0 ? {} : { context: options.context }
31131
+ });
31132
+ super(buildSharedRuntimeOptions({
31133
+ name: options.name,
31134
+ rootPath,
31135
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31136
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31137
+ ...options.context === void 0 ? {} : { context: options.context },
31138
+ engineName,
31139
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31140
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31141
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31142
+ cleanupRootOnClose
31143
+ }));
31144
+ }
31145
+ };
31146
+ function buildSharedRuntimeOptions(input) {
31147
+ const ownership = resolveOwnership(input.browser);
31148
+ const engineFactory = input.engineFactory ?? ((factoryOptions) => new OpensteerBrowserManager({
31149
+ rootPath: input.rootPath,
31150
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31151
+ engineName: input.engineName,
31152
+ ...(factoryOptions.browser ?? input.browser) === void 0 ? {} : { browser: factoryOptions.browser ?? input.browser },
31153
+ ...(factoryOptions.launch ?? input.launch) === void 0 ? {} : { launch: factoryOptions.launch ?? input.launch },
31154
+ ...(factoryOptions.context ?? input.context) === void 0 ? {} : { context: factoryOptions.context ?? input.context }
31155
+ }).createEngine());
31156
+ return {
31157
+ name: input.name,
31158
+ ...input.workspaceName === void 0 ? {} : { workspaceName: input.workspaceName },
31159
+ rootPath: input.rootPath,
31160
+ ...input.engine === void 0 ? {} : { engine: input.engine },
31161
+ ...input.engine === void 0 ? { engineFactory } : {},
31162
+ ...input.policy === void 0 ? {} : { policy: input.policy },
31163
+ cleanupRootOnClose: input.cleanupRootOnClose,
31164
+ sessionInfo: {
31165
+ provider: {
31166
+ kind: "local",
31167
+ ownership,
31168
+ engine: input.engineName
31169
+ },
31170
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31171
+ reconnectable: !input.cleanupRootOnClose
31172
+ }
31173
+ };
31174
+ }
31175
+ function normalizeWorkspace2(workspace) {
31176
+ if (workspace === void 0) {
31177
+ return void 0;
31178
+ }
31179
+ const trimmed = workspace.trim();
31180
+ return trimmed.length === 0 ? void 0 : trimmed;
31181
+ }
31182
+ function resolveOwnership(browser) {
31183
+ return typeof browser === "object" && browser.mode === "attach" ? "attached" : "owned";
31184
+ }
31185
+
31186
+ // src/mode/config.ts
31187
+ var OPENSTEER_EXECUTION_MODES = ["local", "cloud"];
31188
+ function assertExecutionModeSupportsEngine(mode, engine) {
31189
+ if (engine !== "abp") {
31190
+ return;
30650
31191
  }
30651
31192
  if (mode === "cloud") {
30652
31193
  throw new Error(
@@ -31077,14 +31618,14 @@ function toPortableBrowserProfileCookieRecord(cookie) {
31077
31618
  if (!name || !domain) {
31078
31619
  return null;
31079
31620
  }
31080
- const path11 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31621
+ const path13 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31081
31622
  const expiresAt = typeof cookie.expires === "number" && Number.isFinite(cookie.expires) && cookie.expires > 0 ? Math.floor(cookie.expires * 1e3) : null;
31082
31623
  const sameSite = normalizeSameSite(cookie.sameSite);
31083
31624
  return {
31084
31625
  name,
31085
31626
  value: cookie.value,
31086
31627
  domain,
31087
- path: path11,
31628
+ path: path13,
31088
31629
  secure: cookie.secure,
31089
31630
  httpOnly: cookie.httpOnly,
31090
31631
  ...sameSite === void 0 ? {} : { sameSite },
@@ -31261,6 +31802,18 @@ var OpensteerCloudClient = class {
31261
31802
  });
31262
31803
  return await response.json();
31263
31804
  }
31805
+ async issueAccess(sessionId, capabilities) {
31806
+ const response = await this.request(
31807
+ `/v1/sessions/${encodeURIComponent(sessionId)}/access`,
31808
+ {
31809
+ method: "POST",
31810
+ body: {
31811
+ capabilities
31812
+ }
31813
+ }
31814
+ );
31815
+ return await response.json();
31816
+ }
31264
31817
  async closeSession(sessionId) {
31265
31818
  const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
31266
31819
  method: "DELETE"
@@ -31466,58 +32019,367 @@ function isFetchFailure(error) {
31466
32019
  }
31467
32020
  return error.name === "TypeError" || /fetch failed/i.test(error.message);
31468
32021
  }
31469
-
31470
- // src/cloud/session-proxy.ts
31471
- var CLOUD_SESSION_LAYOUT = "opensteer-cloud-session";
31472
- var CLOUD_SESSION_VERSION = 1;
31473
- var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31474
- var SUPPORTED_CLOUD_OPERATIONS = /* @__PURE__ */ new Set([
31475
- "session.open",
31476
- "page.goto",
31477
- "page.snapshot",
31478
- "dom.click",
31479
- "dom.hover",
31480
- "dom.input",
31481
- "dom.scroll",
31482
- "dom.extract",
31483
- "network.query",
31484
- "network.save",
31485
- "network.clear",
31486
- "request.raw",
31487
- "request-plan.infer",
31488
- "request-plan.write",
31489
- "request-plan.get",
31490
- "request-plan.list",
31491
- "request.execute",
31492
- "computer.execute",
31493
- "session.close"
31494
- ]);
31495
- function resolveCloudSessionRecordPath(rootPath) {
31496
- return path6__default.default.join(rootPath, "live", "cloud-session.json");
32022
+ var OpensteerCloudAutomationError = class extends Error {
32023
+ opensteerError;
32024
+ constructor(error) {
32025
+ super(error.message);
32026
+ this.name = "OpensteerCloudAutomationError";
32027
+ this.opensteerError = error;
32028
+ }
32029
+ };
32030
+ var OpensteerCloudAutomationClient = class {
32031
+ constructor(cloud, sessionId) {
32032
+ this.cloud = cloud;
32033
+ this.sessionId = sessionId;
32034
+ }
32035
+ socket;
32036
+ connectPromise;
32037
+ pending = /* @__PURE__ */ new Map();
32038
+ routes = /* @__PURE__ */ new Map();
32039
+ grant;
32040
+ async invoke(operation, input) {
32041
+ await this.ensureConnected();
32042
+ const requestId = `automation:${crypto.randomUUID()}`;
32043
+ const message = {
32044
+ protocol: OPENSTEER_PROTOCOL_NAME,
32045
+ version: OPENSTEER_PROTOCOL_VERSION,
32046
+ kind: "invoke",
32047
+ requestId,
32048
+ operation,
32049
+ sentAt: Date.now(),
32050
+ ...input === void 0 ? {} : { input }
32051
+ };
32052
+ return new Promise((resolve5, reject) => {
32053
+ this.pending.set(requestId, {
32054
+ resolve: (value) => resolve5(value),
32055
+ reject
32056
+ });
32057
+ try {
32058
+ this.requireSocket().send(JSON.stringify(message));
32059
+ } catch (error) {
32060
+ this.pending.delete(requestId);
32061
+ reject(error);
32062
+ }
32063
+ });
32064
+ }
32065
+ async getSessionInfo() {
32066
+ const result = await this.invoke("session.info", {});
32067
+ const sessionInfo = result;
32068
+ assertCompatibleRuntimeCoreVersion(sessionInfo);
32069
+ return sessionInfo;
32070
+ }
32071
+ async route(input) {
32072
+ const routeId = `route:${crypto.randomUUID()}`;
32073
+ const registration = await this.invoke("route.register", {
32074
+ routeId,
32075
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32076
+ urlPattern: input.urlPattern,
32077
+ ...input.resourceTypes === void 0 ? {} : { resourceTypes: input.resourceTypes },
32078
+ ...input.times === void 0 ? {} : { times: input.times },
32079
+ includeOriginal: true
32080
+ });
32081
+ this.routes.set(routeId, {
32082
+ kind: "route",
32083
+ routeId,
32084
+ input
32085
+ });
32086
+ return registration;
32087
+ }
32088
+ async interceptScript(input) {
32089
+ const routeId = `route:${crypto.randomUUID()}`;
32090
+ const registration = await this.invoke("route.register", {
32091
+ routeId,
32092
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32093
+ urlPattern: input.urlPattern,
32094
+ resourceTypes: ["script"],
32095
+ ...input.times === void 0 ? {} : { times: input.times },
32096
+ includeOriginal: true
32097
+ });
32098
+ this.routes.set(routeId, {
32099
+ kind: "intercept-script",
32100
+ routeId,
32101
+ input
32102
+ });
32103
+ return registration;
32104
+ }
32105
+ async close() {
32106
+ this.connectPromise = void 0;
32107
+ this.grant = void 0;
32108
+ if (!this.socket) {
32109
+ return;
32110
+ }
32111
+ const socket = this.socket;
32112
+ this.socket = void 0;
32113
+ for (const [requestId, pending] of this.pending) {
32114
+ pending.reject(new Error(`automation connection closed before ${requestId} completed`));
32115
+ }
32116
+ this.pending.clear();
32117
+ await new Promise((resolve5) => {
32118
+ socket.once("close", () => resolve5());
32119
+ socket.close();
32120
+ }).catch(() => void 0);
32121
+ }
32122
+ async ensureConnected() {
32123
+ if (this.socket?.readyState === WebSocket2__default.default.OPEN) {
32124
+ return;
32125
+ }
32126
+ if (this.connectPromise) {
32127
+ await this.connectPromise;
32128
+ return;
32129
+ }
32130
+ this.connectPromise = this.connect();
32131
+ try {
32132
+ await this.connectPromise;
32133
+ } finally {
32134
+ this.connectPromise = void 0;
32135
+ }
32136
+ }
32137
+ async connect() {
32138
+ const grant = await this.issueGrant("automation");
32139
+ const wsUrl = new URL(grant.wsUrl);
32140
+ wsUrl.searchParams.set("token", grant.token);
32141
+ const socket = new WebSocket2__default.default(wsUrl);
32142
+ this.socket = socket;
32143
+ socket.on("message", (data, isBinary) => {
32144
+ if (isBinary) {
32145
+ return;
32146
+ }
32147
+ this.handleMessage(data.toString());
32148
+ });
32149
+ socket.on("close", () => {
32150
+ if (this.socket === socket) {
32151
+ this.socket = void 0;
32152
+ }
32153
+ });
32154
+ socket.on("error", (error) => {
32155
+ for (const pending of this.pending.values()) {
32156
+ pending.reject(error);
32157
+ }
32158
+ this.pending.clear();
32159
+ });
32160
+ await new Promise((resolve5, reject) => {
32161
+ socket.once("open", () => resolve5());
32162
+ socket.once("error", reject);
32163
+ });
32164
+ this.send({
32165
+ protocol: OPENSTEER_PROTOCOL_NAME,
32166
+ version: OPENSTEER_PROTOCOL_VERSION,
32167
+ kind: "hello",
32168
+ sessionId: this.sessionId,
32169
+ grantKind: grant.kind
32170
+ });
32171
+ await this.restoreRoutes();
32172
+ }
32173
+ async restoreRoutes() {
32174
+ const stored = [...this.routes.values()];
32175
+ this.routes.clear();
32176
+ for (const registration of stored) {
32177
+ if (registration.kind === "route") {
32178
+ await this.route(registration.input);
32179
+ } else {
32180
+ await this.interceptScript(
32181
+ registration.input
32182
+ );
32183
+ }
32184
+ }
32185
+ }
32186
+ handleMessage(json) {
32187
+ const message = JSON.parse(json);
32188
+ if (message.protocol !== OPENSTEER_PROTOCOL_NAME) {
32189
+ return;
32190
+ }
32191
+ switch (message.kind) {
32192
+ case "result": {
32193
+ const pending = this.pending.get(message.requestId);
32194
+ if (!pending) {
32195
+ return;
32196
+ }
32197
+ this.pending.delete(message.requestId);
32198
+ pending.resolve(message.data);
32199
+ return;
32200
+ }
32201
+ case "error": {
32202
+ if (!message.requestId) {
32203
+ return;
32204
+ }
32205
+ const pending = this.pending.get(message.requestId);
32206
+ if (!pending) {
32207
+ return;
32208
+ }
32209
+ this.pending.delete(message.requestId);
32210
+ pending.reject(new OpensteerCloudAutomationError(message.error));
32211
+ return;
32212
+ }
32213
+ case "event":
32214
+ void this.handleEvent(message.event, message.data);
32215
+ return;
32216
+ case "pong":
32217
+ return;
32218
+ }
32219
+ }
32220
+ async handleEvent(event, payload) {
32221
+ if (event !== "route.request") {
32222
+ return;
32223
+ }
32224
+ const data = asRecord(payload);
32225
+ const request = asRecord(data.request);
32226
+ const original = asRecord(data.original);
32227
+ const routeId = typeof data.routeId === "string" ? data.routeId : "";
32228
+ const routeRequestId = typeof data.routeRequestId === "string" ? data.routeRequestId : "";
32229
+ if (!routeId || !routeRequestId) {
32230
+ return;
32231
+ }
32232
+ const registration = this.routes.get(routeId);
32233
+ if (!registration) {
32234
+ await this.invoke("route.resolve", {
32235
+ routeRequestId,
32236
+ decision: { kind: "continue" }
32237
+ }).catch(() => void 0);
32238
+ return;
32239
+ }
32240
+ try {
32241
+ const decision = registration.kind === "route" ? await registration.input.handler({
32242
+ request: toRouteRequest(request),
32243
+ fetchOriginal: async () => toFetchedRouteResponse(original)
32244
+ }) : {
32245
+ kind: "fulfill",
32246
+ body: await registration.input.handler({
32247
+ url: typeof request.url === "string" ? request.url : "",
32248
+ content: typeof original.body === "string" ? original.body : "",
32249
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32250
+ status: typeof original.status === "number" ? original.status : 200
32251
+ }),
32252
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32253
+ status: typeof original.status === "number" ? original.status : 200,
32254
+ contentType: findHeaderValue(
32255
+ Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32256
+ "content-type"
32257
+ ) ?? "application/javascript; charset=utf-8"
32258
+ };
32259
+ await this.invoke("route.resolve", {
32260
+ routeRequestId,
32261
+ decision: serializeRouteDecision(decision)
32262
+ }).catch(() => void 0);
32263
+ } catch {
32264
+ await this.invoke("route.resolve", {
32265
+ routeRequestId,
32266
+ decision: { kind: "continue" }
32267
+ }).catch(() => void 0);
32268
+ }
32269
+ }
32270
+ async issueGrant(kind) {
32271
+ if (this.grant && this.grant.kind === kind && this.grant.expiresAt > Date.now() + 1e4) {
32272
+ return this.grant;
32273
+ }
32274
+ const issued = await this.cloud.issueAccess(this.sessionId, [kind]);
32275
+ const grant = issued.grants[kind];
32276
+ if (!grant) {
32277
+ throw new OpensteerCloudAutomationError(
32278
+ createOpensteerError(
32279
+ "permission-denied",
32280
+ `cloud did not issue an ${kind} automation grant`
32281
+ )
32282
+ );
32283
+ }
32284
+ this.grant = grant;
32285
+ return grant;
32286
+ }
32287
+ requireSocket() {
32288
+ if (!this.socket || this.socket.readyState !== WebSocket2__default.default.OPEN) {
32289
+ throw new Error("cloud automation socket is not connected");
32290
+ }
32291
+ return this.socket;
32292
+ }
32293
+ send(message) {
32294
+ this.requireSocket().send(JSON.stringify(message));
32295
+ }
32296
+ };
32297
+ function assertCompatibleRuntimeCoreVersion(sessionInfo) {
32298
+ const runtimeCoreVersion = sessionInfo.runtime?.runtimeCoreVersion;
32299
+ if (runtimeCoreVersion === void 0) {
32300
+ return;
32301
+ }
32302
+ const expectedMajor = parseMajorVersion(OPENSTEER_RUNTIME_CORE_VERSION);
32303
+ const actualMajor = parseMajorVersion(runtimeCoreVersion);
32304
+ if (expectedMajor === null || actualMajor === null || expectedMajor === actualMajor) {
32305
+ return;
32306
+ }
32307
+ throw new Error(
32308
+ `cloud runtime-core major version ${runtimeCoreVersion} is incompatible with local SDK runtime-core ${OPENSTEER_RUNTIME_CORE_VERSION}`
32309
+ );
31497
32310
  }
31498
- async function readPersistedCloudSessionRecord(rootPath) {
31499
- const sessionPath = resolveCloudSessionRecordPath(rootPath);
31500
- if (!await pathExists(sessionPath)) {
31501
- return void 0;
32311
+ function parseMajorVersion(version) {
32312
+ const major = Number.parseInt(version.split(".", 1)[0] ?? "", 10);
32313
+ return Number.isFinite(major) ? major : null;
32314
+ }
32315
+ function serializeRouteDecision(decision) {
32316
+ if (decision.kind === "continue") {
32317
+ return { kind: "continue" };
31502
32318
  }
31503
- const parsed = await readJsonFile(sessionPath);
31504
- 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)) {
31505
- return void 0;
32319
+ if (decision.kind === "abort") {
32320
+ return {
32321
+ kind: "abort",
32322
+ ...decision.errorCode === void 0 ? {} : { errorCode: decision.errorCode }
32323
+ };
31506
32324
  }
31507
32325
  return {
31508
- layout: CLOUD_SESSION_LAYOUT,
31509
- version: CLOUD_SESSION_VERSION,
31510
- mode: "cloud",
31511
- ...parsed.workspace === void 0 ? {} : { workspace: parsed.workspace },
31512
- sessionId: parsed.sessionId,
31513
- baseUrl: parsed.baseUrl,
31514
- startedAt: parsed.startedAt,
31515
- updatedAt: parsed.updatedAt
32326
+ kind: "fulfill",
32327
+ ...decision.status === void 0 ? {} : { status: decision.status },
32328
+ ...decision.headers === void 0 ? {} : { headers: decision.headers },
32329
+ ...decision.body === void 0 ? {} : typeof decision.body === "string" ? { body: decision.body } : { bodyBase64: Buffer.from(decision.body).toString("base64") },
32330
+ ...decision.contentType === void 0 ? {} : { contentType: decision.contentType }
31516
32331
  };
31517
32332
  }
31518
- async function hasPersistedCloudSession(rootPath) {
31519
- return await readPersistedCloudSessionRecord(rootPath) !== void 0;
32333
+ function toRouteRequest(record) {
32334
+ const pageRef = typeof record.pageRef === "string" ? record.pageRef : void 0;
32335
+ return {
32336
+ url: typeof record.url === "string" ? record.url : "",
32337
+ method: typeof record.method === "string" ? record.method : "GET",
32338
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32339
+ resourceType: typeof record.resourceType === "string" ? record.resourceType : "other",
32340
+ ...pageRef === void 0 ? {} : { pageRef },
32341
+ ...typeof record.postData === "string" ? {
32342
+ postData: {
32343
+ bytes: Uint8Array.from(Buffer.from(record.postData)),
32344
+ encoding: "identity",
32345
+ truncated: false,
32346
+ capturedByteLength: Buffer.byteLength(record.postData)
32347
+ }
32348
+ } : {}
32349
+ };
32350
+ }
32351
+ function toFetchedRouteResponse(record) {
32352
+ return {
32353
+ url: typeof record.url === "string" ? record.url : "",
32354
+ status: typeof record.status === "number" ? record.status : 200,
32355
+ statusText: typeof record.statusText === "string" ? record.statusText : "OK",
32356
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32357
+ ...typeof record.body === "string" ? {
32358
+ body: {
32359
+ bytes: Uint8Array.from(Buffer.from(record.body)),
32360
+ encoding: "identity",
32361
+ truncated: false,
32362
+ capturedByteLength: Buffer.byteLength(record.body)
32363
+ }
32364
+ } : {},
32365
+ redirected: Boolean(record.redirected)
32366
+ };
32367
+ }
32368
+ function findHeaderValue(headers, name) {
32369
+ return headers.find((header) => header.name.toLowerCase() === name)?.value;
31520
32370
  }
32371
+ function isHeaderEntry(value) {
32372
+ return value !== null && typeof value === "object" && typeof value.name === "string" && typeof value.value === "string";
32373
+ }
32374
+ function asRecord(value) {
32375
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
32376
+ return {};
32377
+ }
32378
+ return value;
32379
+ }
32380
+
32381
+ // src/cloud/session-proxy.ts
32382
+ var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31521
32383
  var CloudSessionProxy = class {
31522
32384
  rootPath;
31523
32385
  workspace;
@@ -31526,6 +32388,7 @@ var CloudSessionProxy = class {
31526
32388
  sessionId;
31527
32389
  sessionBaseUrl;
31528
32390
  client;
32391
+ automation;
31529
32392
  workspaceStore;
31530
32393
  constructor(cloud, options = {}) {
31531
32394
  this.cloud = cloud;
@@ -31546,27 +32409,73 @@ var CloudSessionProxy = class {
31546
32409
  ...input.url === void 0 ? {} : { url: input.url }
31547
32410
  });
31548
32411
  }
32412
+ async info() {
32413
+ const persisted = this.client !== void 0 || this.sessionId !== void 0 ? void 0 : await this.loadPersistedSession();
32414
+ if (this.client === void 0 && this.sessionId === void 0 && persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
32415
+ this.bindClient(persisted);
32416
+ }
32417
+ if (this.automation) {
32418
+ try {
32419
+ const sessionInfo = await this.automation.getSessionInfo();
32420
+ return {
32421
+ ...sessionInfo,
32422
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace }
32423
+ };
32424
+ } catch {
32425
+ }
32426
+ }
32427
+ return {
32428
+ provider: {
32429
+ kind: "cloud",
32430
+ ownership: "managed",
32431
+ engine: "playwright",
32432
+ baseUrl: this.cloud.getConfig().baseUrl
32433
+ },
32434
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace },
32435
+ ...this.sessionId === void 0 ? persisted?.sessionId === void 0 ? {} : { sessionId: persisted.sessionId } : { sessionId: this.sessionId },
32436
+ reconnectable: this.workspace !== void 0 || this.sessionId !== void 0 || persisted !== void 0,
32437
+ capabilities: {
32438
+ semanticOperations: opensteerSemanticOperationNames,
32439
+ sessionGrants: ["automation", "view", "cdp"],
32440
+ instrumentation: {
32441
+ route: true,
32442
+ interceptScript: true,
32443
+ networkStream: true
32444
+ }
32445
+ },
32446
+ runtime: {
32447
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
32448
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
32449
+ }
32450
+ };
32451
+ }
31549
32452
  async listPages(input = {}) {
31550
- throw unsupportedCloudOperation("page.list");
32453
+ await this.ensureSession();
32454
+ return this.requireClient().invoke("page.list", input);
31551
32455
  }
31552
32456
  async newPage(input = {}) {
31553
- throw unsupportedCloudOperation("page.new");
32457
+ await this.ensureSession();
32458
+ return this.requireAutomation().invoke("page.new", input);
31554
32459
  }
31555
32460
  async activatePage(input) {
31556
- throw unsupportedCloudOperation("page.activate");
32461
+ await this.ensureSession();
32462
+ return this.requireClient().invoke("page.activate", input);
31557
32463
  }
31558
32464
  async closePage(input = {}) {
31559
- throw unsupportedCloudOperation("page.close");
32465
+ await this.ensureSession();
32466
+ return this.requireClient().invoke("page.close", input);
31560
32467
  }
31561
32468
  async goto(input) {
31562
32469
  await this.ensureSession();
31563
32470
  return this.requireClient().invoke("page.goto", input);
31564
32471
  }
31565
32472
  async evaluate(input) {
31566
- throw unsupportedCloudOperation("page.evaluate");
32473
+ await this.ensureSession();
32474
+ return this.requireAutomation().invoke("page.evaluate", input);
31567
32475
  }
31568
32476
  async addInitScript(input) {
31569
- throw unsupportedCloudOperation("page.add-init-script");
32477
+ await this.ensureSession();
32478
+ return this.requireClient().invoke("page.add-init-script", input);
31570
32479
  }
31571
32480
  async snapshot(input = {}) {
31572
32481
  await this.ensureSession();
@@ -31601,80 +32510,112 @@ var CloudSessionProxy = class {
31601
32510
  return this.requireClient().invoke("network.save", input);
31602
32511
  }
31603
32512
  async minimizeNetwork(input) {
31604
- throw unsupportedCloudOperation("network.minimize");
32513
+ await this.ensureSession();
32514
+ return this.requireClient().invoke("network.minimize", input);
31605
32515
  }
31606
32516
  async diffNetwork(input) {
31607
- throw unsupportedCloudOperation("network.diff");
32517
+ await this.ensureSession();
32518
+ return this.requireClient().invoke("network.diff", input);
31608
32519
  }
31609
32520
  async probeNetwork(input) {
31610
- throw unsupportedCloudOperation("network.probe");
32521
+ await this.ensureSession();
32522
+ return this.requireClient().invoke("network.probe", input);
31611
32523
  }
31612
32524
  async discoverReverse(input) {
31613
- throw unsupportedCloudOperation("reverse.discover");
32525
+ await this.ensureSession();
32526
+ return this.requireClient().invoke("reverse.discover", input);
31614
32527
  }
31615
32528
  async queryReverse(input) {
31616
- throw unsupportedCloudOperation("reverse.query");
32529
+ await this.ensureSession();
32530
+ return this.requireClient().invoke("reverse.query", input);
31617
32531
  }
31618
32532
  async createReversePackage(input) {
31619
- throw unsupportedCloudOperation("reverse.package.create");
32533
+ await this.ensureSession();
32534
+ return this.requireClient().invoke("reverse.package.create", input);
31620
32535
  }
31621
32536
  async runReversePackage(input) {
31622
- throw unsupportedCloudOperation("reverse.package.run");
32537
+ await this.ensureSession();
32538
+ return this.requireClient().invoke("reverse.package.run", input);
31623
32539
  }
31624
32540
  async exportReverse(input) {
31625
- throw unsupportedCloudOperation("reverse.export");
32541
+ await this.ensureSession();
32542
+ return this.requireClient().invoke("reverse.export", input);
31626
32543
  }
31627
32544
  async getReverseReport(input) {
31628
- throw unsupportedCloudOperation("reverse.report");
32545
+ await this.ensureSession();
32546
+ return this.requireClient().invoke("reverse.report", input);
31629
32547
  }
31630
32548
  async getReversePackage(input) {
31631
- throw unsupportedCloudOperation("reverse.package.get");
32549
+ await this.ensureSession();
32550
+ return this.requireClient().invoke("reverse.package.get", input);
31632
32551
  }
31633
32552
  async listReversePackages(input = {}) {
31634
- throw unsupportedCloudOperation("reverse.package.list");
32553
+ await this.ensureSession();
32554
+ return this.requireClient().invoke("reverse.package.list", input);
31635
32555
  }
31636
32556
  async patchReversePackage(input) {
31637
- throw unsupportedCloudOperation("reverse.package.patch");
32557
+ await this.ensureSession();
32558
+ return this.requireClient().invoke("reverse.package.patch", input);
31638
32559
  }
31639
32560
  async captureInteraction(input) {
31640
- throw unsupportedCloudOperation("interaction.capture");
32561
+ await this.ensureSession();
32562
+ return this.requireClient().invoke("interaction.capture", input);
31641
32563
  }
31642
32564
  async getInteraction(input) {
31643
- throw unsupportedCloudOperation("interaction.get");
32565
+ await this.ensureSession();
32566
+ return this.requireClient().invoke("interaction.get", input);
31644
32567
  }
31645
32568
  async diffInteraction(input) {
31646
- throw unsupportedCloudOperation("interaction.diff");
32569
+ await this.ensureSession();
32570
+ return this.requireClient().invoke("interaction.diff", input);
31647
32571
  }
31648
32572
  async replayInteraction(input) {
31649
- throw unsupportedCloudOperation("interaction.replay");
32573
+ await this.ensureSession();
32574
+ return this.requireClient().invoke("interaction.replay", input);
31650
32575
  }
31651
32576
  async clearNetwork(input = {}) {
31652
32577
  await this.ensureSession();
31653
32578
  return this.requireClient().invoke("network.clear", input);
31654
32579
  }
31655
32580
  async captureScripts(input = {}) {
31656
- throw unsupportedCloudOperation("scripts.capture");
32581
+ await this.ensureSession();
32582
+ return this.requireClient().invoke("scripts.capture", input);
31657
32583
  }
31658
32584
  async readArtifact(input) {
31659
- throw unsupportedCloudOperation("artifact.read");
32585
+ await this.ensureSession();
32586
+ return this.requireClient().invoke("artifact.read", input);
31660
32587
  }
31661
32588
  async beautifyScript(input) {
31662
- throw unsupportedCloudOperation("scripts.beautify");
32589
+ await this.ensureSession();
32590
+ return this.requireClient().invoke("scripts.beautify", input);
31663
32591
  }
31664
32592
  async deobfuscateScript(input) {
31665
- throw unsupportedCloudOperation("scripts.deobfuscate");
32593
+ await this.ensureSession();
32594
+ return this.requireClient().invoke("scripts.deobfuscate", input);
31666
32595
  }
31667
32596
  async sandboxScript(input) {
31668
- throw unsupportedCloudOperation("scripts.sandbox");
32597
+ await this.ensureSession();
32598
+ return this.requireClient().invoke("scripts.sandbox", input);
31669
32599
  }
31670
32600
  async solveCaptcha(input) {
31671
- throw unsupportedCloudOperation("captcha.solve");
32601
+ await this.ensureSession();
32602
+ return this.requireClient().invoke("captcha.solve", input);
31672
32603
  }
31673
32604
  async getCookies(input = {}) {
31674
- throw unsupportedCloudOperation("inspect.cookies");
32605
+ await this.ensureSession();
32606
+ return this.requireAutomation().invoke("inspect.cookies", input);
32607
+ }
32608
+ async route(input) {
32609
+ await this.ensureSession();
32610
+ return this.requireAutomation().route(input);
32611
+ }
32612
+ async interceptScript(input) {
32613
+ await this.ensureSession();
32614
+ return this.requireAutomation().interceptScript(input);
31675
32615
  }
31676
32616
  async getStorageSnapshot(input = {}) {
31677
- throw unsupportedCloudOperation("inspect.storage");
32617
+ await this.ensureSession();
32618
+ return this.requireClient().invoke("inspect.storage", input);
31678
32619
  }
31679
32620
  async rawRequest(input) {
31680
32621
  await this.ensureSession();
@@ -31697,28 +32638,36 @@ var CloudSessionProxy = class {
31697
32638
  return this.requireClient().invoke("request-plan.list", input);
31698
32639
  }
31699
32640
  async writeAuthRecipe(input) {
31700
- throw unsupportedCloudOperation("auth-recipe.write");
32641
+ await this.ensureSession();
32642
+ return this.requireClient().invoke("auth-recipe.write", input);
31701
32643
  }
31702
32644
  async writeRecipe(input) {
31703
- throw unsupportedCloudOperation("recipe.write");
32645
+ await this.ensureSession();
32646
+ return this.requireClient().invoke("recipe.write", input);
31704
32647
  }
31705
32648
  async getAuthRecipe(input) {
31706
- throw unsupportedCloudOperation("auth-recipe.get");
32649
+ await this.ensureSession();
32650
+ return this.requireClient().invoke("auth-recipe.get", input);
31707
32651
  }
31708
32652
  async getRecipe(input) {
31709
- throw unsupportedCloudOperation("recipe.get");
32653
+ await this.ensureSession();
32654
+ return this.requireClient().invoke("recipe.get", input);
31710
32655
  }
31711
32656
  async listAuthRecipes(input = {}) {
31712
- throw unsupportedCloudOperation("auth-recipe.list");
32657
+ await this.ensureSession();
32658
+ return this.requireClient().invoke("auth-recipe.list", input);
31713
32659
  }
31714
32660
  async listRecipes(input = {}) {
31715
- throw unsupportedCloudOperation("recipe.list");
32661
+ await this.ensureSession();
32662
+ return this.requireClient().invoke("recipe.list", input);
31716
32663
  }
31717
32664
  async runAuthRecipe(input) {
31718
- throw unsupportedCloudOperation("auth-recipe.run");
32665
+ await this.ensureSession();
32666
+ return this.requireClient().invoke("auth-recipe.run", input);
31719
32667
  }
31720
32668
  async runRecipe(input) {
31721
- throw unsupportedCloudOperation("recipe.run");
32669
+ await this.ensureSession();
32670
+ return this.requireClient().invoke("recipe.run", input);
31722
32671
  }
31723
32672
  async request(input) {
31724
32673
  await this.ensureSession();
@@ -31730,8 +32679,9 @@ var CloudSessionProxy = class {
31730
32679
  }
31731
32680
  async close() {
31732
32681
  const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 || this.sessionBaseUrl === void 0 ? void 0 : {
31733
- layout: CLOUD_SESSION_LAYOUT,
31734
- version: CLOUD_SESSION_VERSION,
32682
+ layout: "opensteer-session",
32683
+ version: 1,
32684
+ provider: "cloud",
31735
32685
  mode: "cloud",
31736
32686
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31737
32687
  sessionId: this.sessionId,
@@ -31749,7 +32699,9 @@ var CloudSessionProxy = class {
31749
32699
  });
31750
32700
  }
31751
32701
  } finally {
32702
+ await this.automation?.close().catch(() => void 0);
31752
32703
  await this.clearPersistedSession();
32704
+ this.automation = void 0;
31753
32705
  this.client = void 0;
31754
32706
  this.sessionId = void 0;
31755
32707
  this.sessionBaseUrl = void 0;
@@ -31765,6 +32717,8 @@ var CloudSessionProxy = class {
31765
32717
  return;
31766
32718
  }
31767
32719
  this.client = void 0;
32720
+ await this.automation?.close().catch(() => void 0);
32721
+ this.automation = void 0;
31768
32722
  this.sessionId = void 0;
31769
32723
  this.sessionBaseUrl = void 0;
31770
32724
  }
@@ -31785,8 +32739,9 @@ var CloudSessionProxy = class {
31785
32739
  ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
31786
32740
  });
31787
32741
  const record = {
31788
- layout: CLOUD_SESSION_LAYOUT,
31789
- version: CLOUD_SESSION_VERSION,
32742
+ layout: "opensteer-session",
32743
+ version: 1,
32744
+ provider: "cloud",
31790
32745
  mode: "cloud",
31791
32746
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31792
32747
  sessionId: session.sessionId,
@@ -31804,6 +32759,7 @@ var CloudSessionProxy = class {
31804
32759
  baseUrl: record.baseUrl,
31805
32760
  getAuthorizationHeader: async () => this.cloud.buildAuthorizationHeader()
31806
32761
  });
32762
+ this.automation = new OpensteerCloudAutomationClient(this.cloud, record.sessionId);
31807
32763
  }
31808
32764
  async ensureWorkspaceStore() {
31809
32765
  if (this.workspaceStore !== void 0) {
@@ -31822,10 +32778,10 @@ var CloudSessionProxy = class {
31822
32778
  }
31823
32779
  async writePersistedSession(record) {
31824
32780
  const workspace = await this.ensureWorkspaceStore();
31825
- await writeJsonFileAtomic(resolveCloudSessionRecordPath(workspace.rootPath), record);
32781
+ await writePersistedSessionRecord(workspace.rootPath, record);
31826
32782
  }
31827
32783
  async clearPersistedSession() {
31828
- await promises.rm(resolveCloudSessionRecordPath(this.rootPath), { force: true }).catch(() => void 0);
32784
+ await clearPersistedSessionRecord(this.rootPath).catch(() => void 0);
31829
32785
  }
31830
32786
  async isReusableCloudSession(sessionId) {
31831
32787
  try {
@@ -31844,6 +32800,12 @@ var CloudSessionProxy = class {
31844
32800
  }
31845
32801
  return this.client;
31846
32802
  }
32803
+ requireAutomation() {
32804
+ if (!this.automation) {
32805
+ throw new Error("Cloud automation session has not been initialized.");
32806
+ }
32807
+ return this.automation;
32808
+ }
31847
32809
  };
31848
32810
  function resolveCloudBrowserProfile(cloud, input) {
31849
32811
  return input.browserProfile ?? cloud.getConfig().browserProfile;
@@ -31859,22 +32821,24 @@ function assertSupportedCloudBrowserMode(browser) {
31859
32821
  function isMissingCloudSessionError(error) {
31860
32822
  return error instanceof Error && /\b404\b/.test(error.message);
31861
32823
  }
31862
- function unsupportedCloudOperation(operation) {
31863
- return new OpensteerProtocolError(
31864
- "unsupported-operation",
31865
- `Cloud mode does not currently support ${operation}.`,
31866
- {
31867
- details: {
31868
- mode: "cloud",
31869
- operation,
31870
- supportedOperations: [...SUPPORTED_CLOUD_OPERATIONS]
31871
- }
31872
- }
31873
- );
31874
- }
31875
32824
 
31876
32825
  // src/sdk/runtime-resolution.ts
31877
32826
  function resolveOpensteerRuntimeConfig(input = {}) {
32827
+ if (input.provider?.kind === "cloud") {
32828
+ return {
32829
+ mode: "cloud",
32830
+ cloud: resolveCloudConfig({
32831
+ enabled: true,
32832
+ ...input.provider,
32833
+ mode: "cloud"
32834
+ })
32835
+ };
32836
+ }
32837
+ if (input.provider?.kind === "local") {
32838
+ return {
32839
+ mode: "local"
32840
+ };
32841
+ }
31878
32842
  const mode = resolveOpensteerExecutionMode({
31879
32843
  ...input.mode === void 0 ? {} : { explicit: input.mode },
31880
32844
  cloud: input.cloud !== void 0 && input.cloud !== false,
@@ -31897,6 +32861,7 @@ function createOpensteerSemanticRuntime(input = {}) {
31897
32861
  const engine = input.engine ?? runtimeOptions.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31898
32862
  const config = resolveOpensteerRuntimeConfig({
31899
32863
  ...input.cloud === void 0 ? {} : { cloud: input.cloud },
32864
+ ...input.provider === void 0 ? {} : { provider: input.provider },
31900
32865
  ...input.mode === void 0 ? {} : { mode: input.mode },
31901
32866
  ...process.env.OPENSTEER_MODE === void 0 ? {} : { environmentMode: process.env.OPENSTEER_MODE }
31902
32867
  });
@@ -31923,6 +32888,7 @@ var Opensteer = class {
31923
32888
  constructor(options = {}) {
31924
32889
  const runtimeConfig = resolveOpensteerRuntimeConfig({
31925
32890
  ...options.cloud === void 0 ? {} : { cloud: options.cloud },
32891
+ ...options.provider === void 0 ? {} : { provider: options.provider },
31926
32892
  ...process.env.OPENSTEER_MODE === void 0 ? {} : { environmentMode: process.env.OPENSTEER_MODE }
31927
32893
  });
31928
32894
  if (runtimeConfig.mode === "cloud") {
@@ -31930,6 +32896,7 @@ var Opensteer = class {
31930
32896
  this.runtime = createOpensteerSemanticRuntime({
31931
32897
  mode: runtimeConfig.mode,
31932
32898
  ...options.cloud === void 0 ? {} : { cloud: options.cloud },
32899
+ ...options.provider === void 0 ? {} : { provider: options.provider },
31933
32900
  ...options.engineName === void 0 ? {} : { engine: options.engineName },
31934
32901
  runtimeOptions: {
31935
32902
  ...options
@@ -31950,6 +32917,7 @@ var Opensteer = class {
31950
32917
  this.runtime = createOpensteerSemanticRuntime({
31951
32918
  mode: runtimeConfig.mode,
31952
32919
  ...options.cloud === void 0 ? {} : { cloud: options.cloud },
32920
+ ...options.provider === void 0 ? {} : { provider: options.provider },
31953
32921
  ...options.engineName === void 0 ? {} : { engine: options.engineName },
31954
32922
  runtimeOptions: {
31955
32923
  ...options,
@@ -31967,6 +32935,9 @@ var Opensteer = class {
31967
32935
  async open(input = {}) {
31968
32936
  return this.runtime.open(typeof input === "string" ? { url: input } : input);
31969
32937
  }
32938
+ async info() {
32939
+ return this.runtime.info();
32940
+ }
31970
32941
  async listPages(input = {}) {
31971
32942
  return this.runtime.listPages(input);
31972
32943
  }
@@ -32225,12 +33196,15 @@ var Opensteer = class {
32225
33196
  await this.runtime.disconnect();
32226
33197
  }
32227
33198
  requireOwnedInstrumentationRuntime(method) {
32228
- if (this.runtime instanceof OpensteerRuntime) {
33199
+ if (isInstrumentableRuntime(this.runtime)) {
32229
33200
  return this.runtime;
32230
33201
  }
32231
- throw new Error(`${method}() is only available on owned local SDK sessions.`);
33202
+ throw new Error(`${method}() is not available for this session runtime.`);
32232
33203
  }
32233
33204
  };
33205
+ function isInstrumentableRuntime(runtime) {
33206
+ return typeof runtime.route === "function" && typeof runtime.interceptScript === "function";
33207
+ }
32234
33208
  function createUnsupportedBrowserController() {
32235
33209
  const fail = async () => {
32236
33210
  throw new Error("browser.* helpers are only available in local mode.");
@@ -32297,11 +33271,13 @@ exports.OpensteerAttachAmbiguousError = OpensteerAttachAmbiguousError;
32297
33271
  exports.OpensteerBrowserManager = OpensteerBrowserManager;
32298
33272
  exports.OpensteerCloudClient = OpensteerCloudClient;
32299
33273
  exports.OpensteerRuntime = OpensteerRuntime;
33274
+ exports.OpensteerSessionRuntime = OpensteerSessionRuntime2;
32300
33275
  exports.STABLE_PRIMARY_ATTR_KEYS = STABLE_PRIMARY_ATTR_KEYS;
32301
33276
  exports.buildArrayFieldPathCandidates = buildArrayFieldPathCandidates;
32302
33277
  exports.buildPathCandidates = buildPathCandidates;
32303
33278
  exports.buildPathSelectorHint = buildPathSelectorHint;
32304
33279
  exports.buildSegmentSelector = buildSegmentSelector;
33280
+ exports.clearPersistedSessionRecord = clearPersistedSessionRecord;
32305
33281
  exports.cloneElementPath = cloneElementPath;
32306
33282
  exports.cloneReplayElementPath = cloneReplayElementPath;
32307
33283
  exports.cloneStructuralElementAnchor = cloneStructuralElementAnchor;
@@ -32326,11 +33302,14 @@ exports.normalizeOpensteerEngineName = normalizeOpensteerEngineName;
32326
33302
  exports.normalizeOpensteerExecutionMode = normalizeOpensteerExecutionMode;
32327
33303
  exports.normalizeWorkspaceId = normalizeWorkspaceId;
32328
33304
  exports.readPersistedCloudSessionRecord = readPersistedCloudSessionRecord;
33305
+ exports.readPersistedLocalBrowserSessionRecord = readPersistedLocalBrowserSessionRecord;
33306
+ exports.readPersistedSessionRecord = readPersistedSessionRecord;
32329
33307
  exports.resolveCloudConfig = resolveCloudConfig;
32330
- exports.resolveCloudSessionRecordPath = resolveCloudSessionRecordPath;
33308
+ exports.resolveCloudSessionRecordPath = resolveLiveSessionRecordPath;
32331
33309
  exports.resolveDomActionBridge = resolveDomActionBridge;
32332
33310
  exports.resolveExtractedValueInContext = resolveExtractedValueInContext;
32333
33311
  exports.resolveFilesystemWorkspacePath = resolveFilesystemWorkspacePath;
33312
+ exports.resolveLiveSessionRecordPath = resolveLiveSessionRecordPath;
32334
33313
  exports.resolveOpensteerEngineName = resolveOpensteerEngineName;
32335
33314
  exports.resolveOpensteerExecutionMode = resolveOpensteerExecutionMode;
32336
33315
  exports.resolveOpensteerRuntimeConfig = resolveOpensteerRuntimeConfig;
@@ -32340,5 +33319,6 @@ exports.sanitizeReplayElementPath = sanitizeReplayElementPath;
32340
33319
  exports.sanitizeStructuralElementAnchor = sanitizeStructuralElementAnchor;
32341
33320
  exports.settleWithPolicy = settleWithPolicy;
32342
33321
  exports.shouldKeepAttributeForPath = shouldKeepAttributeForPath;
33322
+ exports.writePersistedSessionRecord = writePersistedSessionRecord;
32343
33323
  //# sourceMappingURL=index.cjs.map
32344
33324
  //# sourceMappingURL=index.cjs.map