opensteer 0.8.2 → 0.8.4

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
  }
@@ -1785,12 +1787,6 @@ var opensteerRegistryProvenanceSchema = objectSchema(
1785
1787
  required: ["source"]
1786
1788
  }
1787
1789
  );
1788
- var opensteerRequestPlanLifecycleSchema = enumSchema(
1789
- ["draft", "active", "deprecated", "retired"],
1790
- {
1791
- title: "OpensteerRequestPlanLifecycle"
1792
- }
1793
- );
1794
1790
  var opensteerRequestPlanFreshnessSchema = objectSchema(
1795
1791
  {
1796
1792
  lastValidatedAt: integerSchema({ minimum: 0 }),
@@ -1813,23 +1809,12 @@ var opensteerRequestPlanRecordSchema = objectSchema(
1813
1809
  uniqueItems: true
1814
1810
  }),
1815
1811
  provenance: opensteerRegistryProvenanceSchema,
1816
- lifecycle: opensteerRequestPlanLifecycleSchema,
1817
1812
  freshness: opensteerRequestPlanFreshnessSchema,
1818
1813
  payload: opensteerRequestPlanPayloadSchema
1819
1814
  },
1820
1815
  {
1821
1816
  title: "OpensteerRequestPlanRecord",
1822
- required: [
1823
- "id",
1824
- "key",
1825
- "version",
1826
- "createdAt",
1827
- "updatedAt",
1828
- "contentHash",
1829
- "tags",
1830
- "lifecycle",
1831
- "payload"
1832
- ]
1817
+ required: ["id", "key", "version", "createdAt", "updatedAt", "contentHash", "tags", "payload"]
1833
1818
  }
1834
1819
  );
1835
1820
  var jsonValueSchema = defineSchema({
@@ -2272,7 +2257,6 @@ var opensteerWriteRequestPlanInputSchema = objectSchema(
2272
2257
  uniqueItems: true
2273
2258
  }),
2274
2259
  provenance: opensteerRegistryProvenanceSchema,
2275
- lifecycle: opensteerRequestPlanLifecycleSchema,
2276
2260
  freshness: opensteerRequestPlanFreshnessSchema,
2277
2261
  payload: opensteerRequestPlanPayloadSchema
2278
2262
  },
@@ -2513,7 +2497,7 @@ var opensteerInferRequestPlanInputSchema = objectSchema(
2513
2497
  recordId: stringSchema({ minLength: 1 }),
2514
2498
  key: stringSchema({ minLength: 1 }),
2515
2499
  version: stringSchema({ minLength: 1 }),
2516
- lifecycle: opensteerRequestPlanLifecycleSchema
2500
+ transport: transportKindSchema
2517
2501
  },
2518
2502
  {
2519
2503
  title: "OpensteerInferRequestPlanInput",
@@ -5703,6 +5687,65 @@ var opensteerComputerAnnotationNames = [
5703
5687
  "grid",
5704
5688
  "selected"
5705
5689
  ];
5690
+ var opensteerSemanticOperationNames = [
5691
+ "session.open",
5692
+ "page.list",
5693
+ "page.new",
5694
+ "page.activate",
5695
+ "page.close",
5696
+ "page.goto",
5697
+ "page.evaluate",
5698
+ "page.add-init-script",
5699
+ "page.snapshot",
5700
+ "dom.click",
5701
+ "dom.hover",
5702
+ "dom.input",
5703
+ "dom.scroll",
5704
+ "dom.extract",
5705
+ "network.query",
5706
+ "network.save",
5707
+ "network.clear",
5708
+ "network.minimize",
5709
+ "network.diff",
5710
+ "network.probe",
5711
+ "reverse.discover",
5712
+ "reverse.query",
5713
+ "reverse.package.create",
5714
+ "reverse.package.run",
5715
+ "reverse.export",
5716
+ "reverse.report",
5717
+ "reverse.package.get",
5718
+ "reverse.package.list",
5719
+ "reverse.package.patch",
5720
+ "interaction.capture",
5721
+ "interaction.get",
5722
+ "interaction.diff",
5723
+ "interaction.replay",
5724
+ "artifact.read",
5725
+ "inspect.cookies",
5726
+ "inspect.storage",
5727
+ "scripts.capture",
5728
+ "scripts.beautify",
5729
+ "scripts.deobfuscate",
5730
+ "scripts.sandbox",
5731
+ "captcha.solve",
5732
+ "request.raw",
5733
+ "request-plan.infer",
5734
+ "request-plan.write",
5735
+ "request-plan.get",
5736
+ "request-plan.list",
5737
+ "recipe.write",
5738
+ "recipe.get",
5739
+ "recipe.list",
5740
+ "recipe.run",
5741
+ "auth-recipe.write",
5742
+ "auth-recipe.get",
5743
+ "auth-recipe.list",
5744
+ "auth-recipe.run",
5745
+ "request.execute",
5746
+ "computer.execute",
5747
+ "session.close"
5748
+ ];
5706
5749
  function defineSemanticOperationSpec(spec) {
5707
5750
  return spec;
5708
5751
  }
@@ -7002,7 +7045,7 @@ function resolveDomActionBridge(engine) {
7002
7045
  return isDomActionBridgeFactory(candidate) ? candidate.call(engine) : void 0;
7003
7046
  }
7004
7047
 
7005
- // src/registry.ts
7048
+ // ../runtime-core/src/registry.ts
7006
7049
  function normalizeTags(tags) {
7007
7050
  if (tags === void 0) {
7008
7051
  return [];
@@ -7068,9 +7111,7 @@ var FilesystemRegistryStore = class {
7068
7111
  if (input.version !== void 0) {
7069
7112
  return this.resolveIndexedRecord(key, normalizeNonEmptyString("version", input.version));
7070
7113
  }
7071
- const matches = (await this.readAllRecords()).filter(
7072
- (record) => this.isActive(record) && record.key === key
7073
- );
7114
+ const matches = (await this.readAllRecords()).filter((record) => record.key === key);
7074
7115
  matches.sort(compareByCreatedAtAndId);
7075
7116
  return matches[0];
7076
7117
  }
@@ -7193,8 +7234,10 @@ var FilesystemDescriptorRegistry = class extends FilesystemRegistryStore {
7193
7234
  };
7194
7235
  return this.writeRecord(record);
7195
7236
  }
7196
- isActive(_record) {
7197
- return true;
7237
+ async list(input = {}) {
7238
+ const key = input.key === void 0 ? void 0 : normalizeNonEmptyString("key", input.key);
7239
+ const records = await this.readAllRecords();
7240
+ return key === void 0 ? records : records.filter((record) => record.key === key);
7198
7241
  }
7199
7242
  };
7200
7243
  var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
@@ -7224,7 +7267,6 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7224
7267
  tags: normalizeTags(input.tags),
7225
7268
  ...provenance === void 0 ? {} : { provenance },
7226
7269
  payload,
7227
- lifecycle: input.lifecycle ?? "active",
7228
7270
  ...freshness === void 0 ? {} : { freshness }
7229
7271
  };
7230
7272
  return this.writeRecord(record);
@@ -7234,7 +7276,7 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7234
7276
  const records = await this.readAllRecords();
7235
7277
  return key === void 0 ? records : records.filter((record) => record.key === key);
7236
7278
  }
7237
- async updateMetadata(input) {
7279
+ async updateFreshness(input) {
7238
7280
  const id = normalizeNonEmptyString("id", input.id);
7239
7281
  return withFilesystemLock(this.writeLockPath(), async () => {
7240
7282
  const existing = await this.getById(id);
@@ -7252,16 +7294,12 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7252
7294
  const nextRecord = {
7253
7295
  ...existing,
7254
7296
  updatedAt: nextUpdatedAt,
7255
- lifecycle: input.lifecycle ?? existing.lifecycle,
7256
7297
  ...nextFreshness === void 0 ? {} : { freshness: nextFreshness }
7257
7298
  };
7258
7299
  await writeJsonFileAtomic(this.recordPath(id), nextRecord);
7259
7300
  return nextRecord;
7260
7301
  });
7261
7302
  }
7262
- isActive(record) {
7263
- return record.lifecycle === "active";
7264
- }
7265
7303
  };
7266
7304
  var FilesystemAuthRecipeRegistry = class extends FilesystemRegistryStore {
7267
7305
  constructor(rootPath) {
@@ -7297,9 +7335,6 @@ var FilesystemAuthRecipeRegistry = class extends FilesystemRegistryStore {
7297
7335
  const records = await this.readAllRecords();
7298
7336
  return key === void 0 ? records : records.filter((record) => record.key === key);
7299
7337
  }
7300
- isActive(_record) {
7301
- return true;
7302
- }
7303
7338
  };
7304
7339
  var FilesystemRecipeRegistry = class extends FilesystemRegistryStore {
7305
7340
  constructor(rootPath) {
@@ -7335,9 +7370,6 @@ var FilesystemRecipeRegistry = class extends FilesystemRegistryStore {
7335
7370
  const records = await this.readAllRecords();
7336
7371
  return key === void 0 ? records : records.filter((record) => record.key === key);
7337
7372
  }
7338
- isActive(_record) {
7339
- return true;
7340
- }
7341
7373
  };
7342
7374
  var FilesystemInteractionTraceRegistry = class extends FilesystemRegistryStore {
7343
7375
  constructor(rootPath) {
@@ -7373,9 +7405,6 @@ var FilesystemInteractionTraceRegistry = class extends FilesystemRegistryStore {
7373
7405
  const records = await this.readAllRecords();
7374
7406
  return key === void 0 ? records : records.filter((record) => record.key === key);
7375
7407
  }
7376
- isActive(_record) {
7377
- return true;
7378
- }
7379
7408
  };
7380
7409
  var FilesystemReverseCaseRegistry = class extends FilesystemRegistryStore {
7381
7410
  constructor(rootPath) {
@@ -7439,9 +7468,6 @@ var FilesystemReverseCaseRegistry = class extends FilesystemRegistryStore {
7439
7468
  return nextRecord;
7440
7469
  });
7441
7470
  }
7442
- isActive(_record) {
7443
- return true;
7444
- }
7445
7471
  };
7446
7472
  var FilesystemReversePackageRegistry = class extends FilesystemRegistryStore {
7447
7473
  constructor(rootPath) {
@@ -7477,9 +7503,6 @@ var FilesystemReversePackageRegistry = class extends FilesystemRegistryStore {
7477
7503
  const records = await this.readAllRecords();
7478
7504
  return key === void 0 ? records : records.filter((record) => record.key === key);
7479
7505
  }
7480
- isActive(_record) {
7481
- return true;
7482
- }
7483
7506
  };
7484
7507
  var FilesystemReverseReportRegistry = class extends FilesystemRegistryStore {
7485
7508
  constructor(rootPath) {
@@ -7515,9 +7538,6 @@ var FilesystemReverseReportRegistry = class extends FilesystemRegistryStore {
7515
7538
  const records = await this.readAllRecords();
7516
7539
  return key === void 0 ? records : records.filter((record) => record.key === key);
7517
7540
  }
7518
- isActive(_record) {
7519
- return true;
7520
- }
7521
7541
  };
7522
7542
  function createDescriptorRegistry(rootPath) {
7523
7543
  return new FilesystemDescriptorRegistry(rootPath);
@@ -8236,7 +8256,7 @@ function createTraceStore(rootPath, artifacts) {
8236
8256
  return new FilesystemTraceStore(rootPath, artifacts);
8237
8257
  }
8238
8258
 
8239
- // src/root.ts
8259
+ // ../runtime-core/src/root.ts
8240
8260
  var OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT = "opensteer-workspace";
8241
8261
  var OPENSTEER_FILESYSTEM_WORKSPACE_VERSION = 2;
8242
8262
  function normalizeWorkspaceId(workspace) {
@@ -8257,7 +8277,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8257
8277
  const browserManifestPath = path6__default.default.join(browserPath, "manifest.json");
8258
8278
  const browserUserDataDir = path6__default.default.join(browserPath, "user-data");
8259
8279
  const livePath = path6__default.default.join(options.rootPath, "live");
8260
- const liveBrowserPath = path6__default.default.join(livePath, "browser.json");
8280
+ const liveLocalPath = path6__default.default.join(livePath, "local.json");
8281
+ const liveCloudPath = path6__default.default.join(livePath, "cloud.json");
8261
8282
  const artifactsPath = path6__default.default.join(options.rootPath, "artifacts");
8262
8283
  const tracesPath = path6__default.default.join(options.rootPath, "traces");
8263
8284
  const registryPath = path6__default.default.join(options.rootPath, "registry");
@@ -8332,7 +8353,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8332
8353
  browserManifestPath,
8333
8354
  browserUserDataDir,
8334
8355
  livePath,
8335
- liveBrowserPath,
8356
+ liveLocalPath,
8357
+ liveCloudPath,
8336
8358
  artifactsPath,
8337
8359
  tracesPath,
8338
8360
  registryPath,
@@ -8356,7 +8378,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8356
8378
  };
8357
8379
  }
8358
8380
 
8359
- // src/policy/defaults.ts
8381
+ // ../runtime-core/src/policy/defaults.ts
8360
8382
  var DEFAULT_TIMEOUTS = {
8361
8383
  "session.open": 3e4,
8362
8384
  "page.goto": 3e4,
@@ -8439,7 +8461,7 @@ function defaultPolicy() {
8439
8461
  return DEFAULT_POLICY;
8440
8462
  }
8441
8463
 
8442
- // src/policy/settle.ts
8464
+ // ../runtime-core/src/policy/settle.ts
8443
8465
  async function settleWithPolicy(policy, input) {
8444
8466
  for (const observer of policy.observers ?? []) {
8445
8467
  if (await observer.settle(input)) {
@@ -8478,7 +8500,7 @@ function abortError() {
8478
8500
  return error;
8479
8501
  }
8480
8502
 
8481
- // src/policy/timeout.ts
8503
+ // ../runtime-core/src/policy/timeout.ts
8482
8504
  var PolicyTimeoutController = class {
8483
8505
  constructor(input, budgetMs) {
8484
8506
  this.input = input;
@@ -8588,7 +8610,17 @@ function abortError2() {
8588
8610
  return error;
8589
8611
  }
8590
8612
 
8591
- // src/runtimes/dom/match-policy.ts
8613
+ // ../runtime-core/src/runtimes/dom/errors.ts
8614
+ var ElementPathError = class extends Error {
8615
+ code;
8616
+ constructor(code, message) {
8617
+ super(message);
8618
+ this.name = "ElementPathError";
8619
+ this.code = code;
8620
+ }
8621
+ };
8622
+
8623
+ // ../runtime-core/src/runtimes/dom/match-policy.ts
8592
8624
  var ATTRIBUTE_DENY_KEYS = /* @__PURE__ */ new Set([
8593
8625
  "style",
8594
8626
  "nonce",
@@ -8820,7 +8852,7 @@ function getClauseAttributeValue(node, clause) {
8820
8852
  return String(raw);
8821
8853
  }
8822
8854
 
8823
- // src/runtimes/dom/match-selectors.ts
8855
+ // ../runtime-core/src/runtimes/dom/match-selectors.ts
8824
8856
  function buildPathCandidates(domPath) {
8825
8857
  const nodes = Array.isArray(domPath) ? domPath : [];
8826
8858
  if (!nodes.length) {
@@ -8905,7 +8937,7 @@ function buildSuffixCandidates(segments) {
8905
8937
  return out;
8906
8938
  }
8907
8939
 
8908
- // src/runtimes/dom/extraction.ts
8940
+ // ../runtime-core/src/runtimes/dom/extraction.ts
8909
8941
  var URL_LIST_ATTRIBUTES = /* @__PURE__ */ new Set(["srcset", "imagesrcset", "ping"]);
8910
8942
  var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8911
8943
  "href",
@@ -8917,9 +8949,9 @@ var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8917
8949
  "poster",
8918
8950
  "ping"
8919
8951
  ]);
8920
- function buildArrayFieldPathCandidates(path11) {
8921
- const strict = path11.nodes.length ? buildPathCandidates(path11.nodes) : [];
8922
- const relaxedNodes = stripPositionClauses(path11.nodes);
8952
+ function buildArrayFieldPathCandidates(path13) {
8953
+ const strict = path13.nodes.length ? buildPathCandidates(path13.nodes) : [];
8954
+ const relaxedNodes = stripPositionClauses(path13.nodes);
8923
8955
  const relaxed = relaxedNodes.length ? buildPathCandidates(relaxedNodes) : [];
8924
8956
  return dedupeSelectors([...strict, ...relaxed]);
8925
8957
  }
@@ -9151,16 +9183,6 @@ function readDescriptorToken(value, index) {
9151
9183
  nextIndex: cursor
9152
9184
  };
9153
9185
  }
9154
-
9155
- // src/runtimes/dom/errors.ts
9156
- var ElementPathError = class extends Error {
9157
- code;
9158
- constructor(code, message) {
9159
- super(message);
9160
- this.name = "ElementPathError";
9161
- this.code = code;
9162
- }
9163
- };
9164
9186
  var selectorAdapter = {
9165
9187
  isTag(node) {
9166
9188
  return node.kind === "element" && node.source.nodeType === 1;
@@ -9228,6 +9250,45 @@ var selectorAdapter = {
9228
9250
  },
9229
9251
  equals(left, right) {
9230
9252
  return left === right;
9253
+ },
9254
+ existsOne(test, nodes) {
9255
+ return selectorAdapter.findOne(test, nodes) !== null;
9256
+ },
9257
+ findAll(test, nodes) {
9258
+ const matches = [];
9259
+ const visit = (node) => {
9260
+ if (selectorAdapter.isTag(node) && test(node)) {
9261
+ matches.push(node);
9262
+ }
9263
+ for (const child of selectorAdapter.getChildren(node)) {
9264
+ visit(child);
9265
+ }
9266
+ };
9267
+ for (const node of nodes) {
9268
+ visit(node);
9269
+ }
9270
+ return matches;
9271
+ },
9272
+ findOne(test, nodes) {
9273
+ const visit = (node) => {
9274
+ if (selectorAdapter.isTag(node) && test(node)) {
9275
+ return node;
9276
+ }
9277
+ for (const child of selectorAdapter.getChildren(node)) {
9278
+ const match = visit(child);
9279
+ if (match !== null) {
9280
+ return match;
9281
+ }
9282
+ }
9283
+ return null;
9284
+ };
9285
+ for (const node of nodes) {
9286
+ const match = visit(node);
9287
+ if (match !== null) {
9288
+ return match;
9289
+ }
9290
+ }
9291
+ return null;
9231
9292
  }
9232
9293
  };
9233
9294
  function createDomSnapshotIndex(snapshot) {
@@ -9411,7 +9472,7 @@ function sortNodes(nodes) {
9411
9472
  return [...nodes].sort((left, right) => left.snapshotNodeId - right.snapshotNodeId);
9412
9473
  }
9413
9474
 
9414
- // src/runtimes/dom/path.ts
9475
+ // ../runtime-core/src/runtimes/dom/path.ts
9415
9476
  var MAX_ATTRIBUTE_VALUE_LENGTH = 300;
9416
9477
  function cloneStructuralElementAnchor(anchor) {
9417
9478
  return {
@@ -9420,18 +9481,18 @@ function cloneStructuralElementAnchor(anchor) {
9420
9481
  nodes: anchor.nodes.map(clonePathNode)
9421
9482
  };
9422
9483
  }
9423
- function cloneReplayElementPath(path11) {
9484
+ function cloneReplayElementPath(path13) {
9424
9485
  return {
9425
9486
  resolution: "deterministic",
9426
- context: cloneContext(path11.context),
9427
- nodes: path11.nodes.map(clonePathNode)
9487
+ context: cloneContext(path13.context),
9488
+ nodes: path13.nodes.map(clonePathNode)
9428
9489
  };
9429
9490
  }
9430
- function cloneElementPath(path11) {
9431
- return cloneReplayElementPath(path11);
9491
+ function cloneElementPath(path13) {
9492
+ return cloneReplayElementPath(path13);
9432
9493
  }
9433
- function buildPathSelectorHint(path11) {
9434
- const nodes = path11?.nodes || [];
9494
+ function buildPathSelectorHint(path13) {
9495
+ const nodes = path13?.nodes || [];
9435
9496
  const last = nodes[nodes.length - 1];
9436
9497
  if (!last) {
9437
9498
  return "*";
@@ -9480,15 +9541,15 @@ function sanitizeStructuralElementAnchor(anchor) {
9480
9541
  nodes: sanitizeNodes(anchor.nodes)
9481
9542
  };
9482
9543
  }
9483
- function sanitizeReplayElementPath(path11) {
9544
+ function sanitizeReplayElementPath(path13) {
9484
9545
  return {
9485
9546
  resolution: "deterministic",
9486
- context: sanitizeContext(path11.context),
9487
- nodes: sanitizeNodes(path11.nodes)
9547
+ context: sanitizeContext(path13.context),
9548
+ nodes: sanitizeNodes(path13.nodes)
9488
9549
  };
9489
9550
  }
9490
- function sanitizeElementPath(path11) {
9491
- return sanitizeReplayElementPath(path11);
9551
+ function sanitizeElementPath(path13) {
9552
+ return sanitizeReplayElementPath(path13);
9492
9553
  }
9493
9554
  function buildLocalStructuralElementAnchor(index, rawTargetNode) {
9494
9555
  const targetNode = requireElementNode(index, rawTargetNode);
@@ -9611,8 +9672,8 @@ function buildTargetNotFoundMessage(domPath, diagnostics) {
9611
9672
  }
9612
9673
  return `${base} Target depth ${String(depth)}. Candidate counts: ${sample}.`;
9613
9674
  }
9614
- function buildArrayFieldCandidates(path11) {
9615
- return buildArrayFieldPathCandidates(path11);
9675
+ function buildArrayFieldCandidates(path13) {
9676
+ return buildArrayFieldPathCandidates(path13);
9616
9677
  }
9617
9678
  function firstDefinedAttribute(node, keys) {
9618
9679
  for (const key of keys) {
@@ -9886,24 +9947,31 @@ function collectChildrenInScope(index, node, scopeHostNodeRef) {
9886
9947
  function getShadowScopeNodeRef(index, node) {
9887
9948
  return findContainingShadowHostNode(index, node)?.nodeRef;
9888
9949
  }
9950
+
9951
+ // ../runtime-core/src/runtimes/dom/descriptors.ts
9889
9952
  function createDomDescriptorStore(options) {
9890
- const namespace = normalizeNamespace(options.namespace);
9953
+ const namespace = normalizeDomDescriptorNamespace(options.namespace);
9891
9954
  if (options.root) {
9892
9955
  return new FilesystemDomDescriptorStore(options.root.registry.descriptors, namespace);
9893
9956
  }
9894
9957
  return new MemoryDomDescriptorStore(namespace);
9895
9958
  }
9896
- function descriptionKey(namespace, method, description) {
9897
- return `dom:${namespace}:${method}:${sha256Hex2(description.trim())}`;
9959
+ function hashDomDescriptorDescription(description) {
9960
+ return sha256Hex2(description.trim());
9898
9961
  }
9899
- function normalizeNamespace(namespace) {
9962
+ function buildDomDescriptorKey(options) {
9963
+ return `dom:${normalizeDomDescriptorNamespace(options.namespace)}:${options.method}:${hashDomDescriptorDescription(
9964
+ options.description
9965
+ )}`;
9966
+ }
9967
+ function normalizeDomDescriptorNamespace(namespace) {
9900
9968
  const normalized = String(namespace || "default").trim();
9901
9969
  return normalized.length === 0 ? "default" : normalized;
9902
9970
  }
9903
9971
  function sha256Hex2(value) {
9904
9972
  return crypto.createHash("sha256").update(value).digest("hex");
9905
9973
  }
9906
- function buildPayload(input) {
9974
+ function buildDomDescriptorPayload(input) {
9907
9975
  return {
9908
9976
  kind: "dom-target",
9909
9977
  method: input.method,
@@ -9912,6 +9980,9 @@ function buildPayload(input) {
9912
9980
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
9913
9981
  };
9914
9982
  }
9983
+ function buildDomDescriptorVersion(payload) {
9984
+ return sha256Hex2(canonicalJsonString(payload));
9985
+ }
9915
9986
  function parseDomDescriptorRecord(record) {
9916
9987
  const payload = record.payload;
9917
9988
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
@@ -9953,7 +10024,11 @@ var FilesystemDomDescriptorStore = class {
9953
10024
  }
9954
10025
  async read(input) {
9955
10026
  const record = await this.registry.resolve({
9956
- key: descriptionKey(this.namespace, input.method, input.description)
10027
+ key: buildDomDescriptorKey({
10028
+ namespace: this.namespace,
10029
+ method: input.method,
10030
+ description: input.description
10031
+ })
9957
10032
  });
9958
10033
  if (!record) {
9959
10034
  return void 0;
@@ -9961,9 +10036,13 @@ var FilesystemDomDescriptorStore = class {
9961
10036
  return parseDomDescriptorRecord(record);
9962
10037
  }
9963
10038
  async write(input) {
9964
- const payload = buildPayload(input);
9965
- const key = descriptionKey(this.namespace, input.method, input.description);
9966
- const version = sha256Hex2(canonicalJsonString(payload));
10039
+ const payload = buildDomDescriptorPayload(input);
10040
+ const key = buildDomDescriptorKey({
10041
+ namespace: this.namespace,
10042
+ method: input.method,
10043
+ description: input.description
10044
+ });
10045
+ const version = buildDomDescriptorVersion(payload);
9967
10046
  const existing = await this.registry.resolve({ key, version });
9968
10047
  if (existing) {
9969
10048
  const parsed2 = parseDomDescriptorRecord(existing);
@@ -10001,12 +10080,22 @@ var MemoryDomDescriptorStore = class {
10001
10080
  latestByKey = /* @__PURE__ */ new Map();
10002
10081
  recordsByKey = /* @__PURE__ */ new Map();
10003
10082
  async read(input) {
10004
- return this.latestByKey.get(descriptionKey(this.namespace, input.method, input.description));
10083
+ return this.latestByKey.get(
10084
+ buildDomDescriptorKey({
10085
+ namespace: this.namespace,
10086
+ method: input.method,
10087
+ description: input.description
10088
+ })
10089
+ );
10005
10090
  }
10006
10091
  async write(input) {
10007
- const payload = buildPayload(input);
10008
- const key = descriptionKey(this.namespace, input.method, input.description);
10009
- const version = sha256Hex2(canonicalJsonString(payload));
10092
+ const payload = buildDomDescriptorPayload(input);
10093
+ const key = buildDomDescriptorKey({
10094
+ namespace: this.namespace,
10095
+ method: input.method,
10096
+ description: input.description
10097
+ });
10098
+ const version = buildDomDescriptorVersion(payload);
10010
10099
  const existing = this.recordsByKey.get(key)?.get(version);
10011
10100
  if (existing) {
10012
10101
  return existing;
@@ -10028,7 +10117,7 @@ var MemoryDomDescriptorStore = class {
10028
10117
  }
10029
10118
  };
10030
10119
 
10031
- // src/runtimes/dom/executor.ts
10120
+ // ../runtime-core/src/runtimes/dom/executor.ts
10032
10121
  var MAX_DOM_ACTION_ATTEMPTS = 3;
10033
10122
  var DEFAULT_SCROLL_OPTIONS = {
10034
10123
  block: "center",
@@ -10592,7 +10681,7 @@ function pointFallsWithinQuads(point, quads) {
10592
10681
  return quads.some((quad) => rectContainsPoint(quadBounds(quad), point));
10593
10682
  }
10594
10683
 
10595
- // src/runtimes/dom/runtime.ts
10684
+ // ../runtime-core/src/runtimes/dom/runtime.ts
10596
10685
  var SnapshotSession = class {
10597
10686
  constructor(engine) {
10598
10687
  this.engine = engine;
@@ -10649,7 +10738,7 @@ var DefaultDomRuntime = class {
10649
10738
  bridge;
10650
10739
  constructor(options) {
10651
10740
  this.engine = options.engine;
10652
- this.descriptors = createDomDescriptorStore({
10741
+ this.descriptors = options.descriptorStore ?? createDomDescriptorStore({
10653
10742
  ...options.root === void 0 ? {} : { root: options.root },
10654
10743
  ...options.namespace === void 0 ? {} : { namespace: options.namespace }
10655
10744
  });
@@ -10996,21 +11085,21 @@ var DefaultDomRuntime = class {
10996
11085
  return match;
10997
11086
  }
10998
11087
  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);
11088
+ const path13 = sanitizeReplayElementPath(rawPath);
11089
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11090
+ const target = resolveDomPathInScope(context.index, path13.nodes, context.scope);
11002
11091
  if (!target) {
11003
- throwTargetNotFound(context.index, path11.nodes, context.scope);
11092
+ throwTargetNotFound(context.index, path13.nodes, context.scope);
11004
11093
  }
11005
11094
  if (target.node.nodeRef === void 0) {
11006
11095
  throw new Error(
11007
- `resolved path "${buildPathSelectorHint(path11)}" does not point to a live element`
11096
+ `resolved path "${buildPathSelectorHint(path13)}" does not point to a live element`
11008
11097
  );
11009
11098
  }
11010
11099
  const anchor = await this.buildAnchorFromSnapshotNode(session, context.snapshot, target.node);
11011
11100
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
11012
11101
  ...description === void 0 ? {} : { description },
11013
- replayPath: path11,
11102
+ replayPath: path13,
11014
11103
  ...source === "path" || source === "descriptor" ? { selectorUsed: target.selector } : {},
11015
11104
  ...descriptor === void 0 ? {} : { descriptor }
11016
11105
  });
@@ -11031,9 +11120,9 @@ var DefaultDomRuntime = class {
11031
11120
  });
11032
11121
  }
11033
11122
  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(
11123
+ const path13 = sanitizeReplayElementPath(rawPath);
11124
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11125
+ return queryAllDomPathInScope(context.index, path13.nodes, context.scope).filter(
11037
11126
  (node) => node.nodeRef !== void 0
11038
11127
  ).map((node) => this.createSnapshotTarget(context.snapshot, node));
11039
11128
  }
@@ -11219,16 +11308,16 @@ var DefaultDomRuntime = class {
11219
11308
  const index = createSnapshotIndex(item.snapshot);
11220
11309
  return this.resolveFirstArrayFieldTargetInNode(index, item.node, field.path);
11221
11310
  }
11222
- resolveFirstArrayFieldTargetInNode(index, rootNode, path11) {
11223
- const normalizedPath = sanitizeElementPath(path11);
11311
+ resolveFirstArrayFieldTargetInNode(index, rootNode, path13) {
11312
+ const normalizedPath = sanitizeElementPath(path13);
11224
11313
  const selectors = buildArrayFieldCandidates(normalizedPath);
11225
11314
  if (!selectors.length) {
11226
11315
  return rootNode;
11227
11316
  }
11228
11317
  return resolveFirstWithinNodeBySelectors(index, rootNode, selectors);
11229
11318
  }
11230
- resolveUniqueArrayFieldTargetInNode(index, rootNode, path11) {
11231
- const normalizedPath = sanitizeElementPath(path11);
11319
+ resolveUniqueArrayFieldTargetInNode(index, rootNode, path13) {
11320
+ const normalizedPath = sanitizeElementPath(path13);
11232
11321
  const selectors = buildArrayFieldCandidates(normalizedPath);
11233
11322
  if (!selectors.length) {
11234
11323
  return rootNode;
@@ -11317,9 +11406,6 @@ async function clearChromeSingletonEntries(userDataDir) {
11317
11406
  );
11318
11407
  }
11319
11408
  async function sanitizeChromeProfile(userDataDir) {
11320
- if (!fs.existsSync(userDataDir)) {
11321
- return;
11322
- }
11323
11409
  const entries = await promises.readdir(userDataDir).catch(() => []);
11324
11410
  const profileDirs = entries.filter(
11325
11411
  (entry) => entry === "Default" || /^Profile \d+$/i.test(entry)
@@ -11328,9 +11414,6 @@ async function sanitizeChromeProfile(userDataDir) {
11328
11414
  }
11329
11415
  async function sanitizeProfilePreferences(userDataDir, profileDir) {
11330
11416
  const prefsPath = path6.join(userDataDir, profileDir, "Preferences");
11331
- if (!fs.existsSync(prefsPath)) {
11332
- return;
11333
- }
11334
11417
  try {
11335
11418
  const raw = await promises.readFile(prefsPath, "utf8");
11336
11419
  const prefs = JSON.parse(raw);
@@ -12101,8 +12184,8 @@ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
12101
12184
  const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
12102
12185
  return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
12103
12186
  }
12104
- function normalizeWebSocketPath(path11) {
12105
- return path11.startsWith("/") ? path11 : `/${path11}`;
12187
+ function normalizeWebSocketPath(path13) {
12188
+ return path13.startsWith("/") ? path13 : `/${path13}`;
12106
12189
  }
12107
12190
  function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
12108
12191
  try {
@@ -12238,20 +12321,121 @@ function shouldCopyEntry(input) {
12238
12321
 
12239
12322
  // src/local-browser/stealth-init-script.ts
12240
12323
  function generateStealthInitScript(profile) {
12241
- const encodedProfile = JSON.stringify(profile);
12324
+ const encodedProfile = JSON.stringify({
12325
+ ...profile,
12326
+ platformString: getPlatformString(profile.platform),
12327
+ userAgentData: buildUserAgentData(profile)
12328
+ });
12242
12329
  return `(() => {
12243
12330
  const profile = ${encodedProfile};
12331
+ var define = function(target, key, value) {
12332
+ Object.defineProperty(target, key, {
12333
+ configurable: true,
12334
+ get: typeof value === 'function' ? value : function() { return value; },
12335
+ });
12336
+ };
12244
12337
 
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.
12338
+ // --- navigator / screen mirrors for future pages ---
12249
12339
  if (navigator.webdriver === true) {
12250
12340
  Object.defineProperty(Navigator.prototype, 'webdriver', {
12251
12341
  configurable: true,
12252
12342
  get: function() { return false; },
12253
12343
  });
12254
12344
  }
12345
+ define(Navigator.prototype, 'platform', profile.platformString);
12346
+ define(Navigator.prototype, 'userAgent', profile.userAgent);
12347
+ define(Navigator.prototype, 'language', profile.locale);
12348
+ define(Navigator.prototype, 'languages', [profile.locale, 'en']);
12349
+ define(Navigator.prototype, 'maxTouchPoints', profile.maxTouchPoints);
12350
+ define(window, 'devicePixelRatio', profile.devicePixelRatio);
12351
+ define(window.screen, 'width', profile.screenResolution.width);
12352
+ define(window.screen, 'height', profile.screenResolution.height);
12353
+ define(window.screen, 'availWidth', profile.screenResolution.width);
12354
+ define(window.screen, 'availHeight', profile.screenResolution.height - 40);
12355
+ define(window.screen, 'colorDepth', 24);
12356
+ define(window.screen, 'pixelDepth', 24);
12357
+ define(Navigator.prototype, 'userAgentData', {
12358
+ brands: profile.userAgentData.brands,
12359
+ mobile: false,
12360
+ platform: profile.userAgentData.platform,
12361
+ toJSON: function() {
12362
+ return {
12363
+ brands: this.brands,
12364
+ mobile: this.mobile,
12365
+ platform: this.platform,
12366
+ };
12367
+ },
12368
+ getHighEntropyValues: async function(hints) {
12369
+ var source = {
12370
+ architecture: profile.userAgentData.architecture,
12371
+ bitness: profile.userAgentData.bitness,
12372
+ brands: profile.userAgentData.brands,
12373
+ fullVersionList: profile.userAgentData.fullVersionList,
12374
+ mobile: false,
12375
+ model: '',
12376
+ platform: profile.userAgentData.platform,
12377
+ platformVersion: profile.userAgentData.platformVersion,
12378
+ uaFullVersion: profile.browserVersion,
12379
+ wow64: false,
12380
+ };
12381
+ var values = {};
12382
+ for (var i = 0; i < hints.length; i++) {
12383
+ var hint = hints[i];
12384
+ if (Object.prototype.hasOwnProperty.call(source, hint)) {
12385
+ values[hint] = source[hint];
12386
+ }
12387
+ }
12388
+ return values;
12389
+ },
12390
+ });
12391
+
12392
+ if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
12393
+ var originalResolvedOptions = Intl.DateTimeFormat.prototype.resolvedOptions;
12394
+ Intl.DateTimeFormat.prototype.resolvedOptions = function() {
12395
+ var options = originalResolvedOptions.call(this);
12396
+ options.timeZone = profile.timezoneId;
12397
+ return options;
12398
+ };
12399
+ }
12400
+
12401
+ if (Date.prototype.getTimezoneOffset) {
12402
+ var originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
12403
+ var calculateTimezoneOffset = function(date) {
12404
+ try {
12405
+ var formatter = new Intl.DateTimeFormat('en-US', {
12406
+ timeZone: profile.timezoneId,
12407
+ hour12: false,
12408
+ year: 'numeric',
12409
+ month: '2-digit',
12410
+ day: '2-digit',
12411
+ hour: '2-digit',
12412
+ minute: '2-digit',
12413
+ second: '2-digit',
12414
+ });
12415
+ var parts = formatter.formatToParts(date);
12416
+ var values = {};
12417
+ for (var i = 0; i < parts.length; i++) {
12418
+ if (parts[i].type !== 'literal') {
12419
+ values[parts[i].type] = Number(parts[i].value);
12420
+ }
12421
+ }
12422
+ var utcTime = Date.UTC(
12423
+ values.year,
12424
+ values.month - 1,
12425
+ values.day,
12426
+ values.hour,
12427
+ values.minute,
12428
+ values.second,
12429
+ );
12430
+ return Math.round((date.getTime() - utcTime) / 60000);
12431
+ } catch {
12432
+ return originalGetTimezoneOffset.call(date);
12433
+ }
12434
+ };
12435
+ Date.prototype.getTimezoneOffset = function() {
12436
+ return calculateTimezoneOffset(this);
12437
+ };
12438
+ }
12255
12439
 
12256
12440
  // --- CDP Runtime.enable leak defense ---
12257
12441
  var _wrap = function(name) {
@@ -12325,6 +12509,34 @@ function generateStealthInitScript(profile) {
12325
12509
  }
12326
12510
  })();`;
12327
12511
  }
12512
+ function buildUserAgentData(profile) {
12513
+ const majorVersion = profile.browserVersion.split(".")[0] ?? "136";
12514
+ const platformData = {
12515
+ macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12516
+ windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12517
+ linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12518
+ };
12519
+ const platformInfo = platformData[profile.platform];
12520
+ return {
12521
+ architecture: platformInfo.architecture,
12522
+ bitness: "64",
12523
+ brands: [
12524
+ { brand: "Chromium", version: majorVersion },
12525
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: majorVersion }] : [{ brand: "Google Chrome", version: majorVersion }],
12526
+ { brand: "Not-A.Brand", version: "99" }
12527
+ ],
12528
+ fullVersionList: [
12529
+ { brand: "Chromium", version: profile.browserVersion },
12530
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: profile.browserVersion }] : [{ brand: "Google Chrome", version: profile.browserVersion }],
12531
+ { brand: "Not-A.Brand", version: "99.0.0.0" }
12532
+ ],
12533
+ platform: platformInfo.platform,
12534
+ platformVersion: platformInfo.platformVersion
12535
+ };
12536
+ }
12537
+ function getPlatformString(platform) {
12538
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12539
+ }
12328
12540
 
12329
12541
  // src/local-browser/stealth.ts
12330
12542
  var STEALTH_INIT_SCRIPT = `(() => {
@@ -12368,8 +12580,9 @@ var STEALTH_INIT_SCRIPT = `(() => {
12368
12580
  ['debug', 'log', 'info', 'error', 'warn', 'trace', 'dir'].forEach(_wrap);
12369
12581
  })();`;
12370
12582
  async function injectBrowserStealthScripts(context, input = {}) {
12371
- if (input.profile !== void 0 && input.page !== void 0) {
12372
- await applyCdpStealthOverrides(context, input.page, input.profile);
12583
+ if (input.profile !== void 0) {
12584
+ await installContextNetworkHeaders(context, input.profile);
12585
+ await installCdpStealthOverrides(context, input.profile, input.page);
12373
12586
  }
12374
12587
  if (typeof context.addInitScript === "function") {
12375
12588
  await context.addInitScript({
@@ -12390,11 +12603,12 @@ function buildUserAgentMetadata(profile) {
12390
12603
  { brand: "Not-A.Brand", version: "99.0.0.0" }
12391
12604
  ];
12392
12605
  const platformMap = {
12606
+ // Chromium keeps the reduced macOS UA token frozen to Intel even on Apple Silicon.
12393
12607
  macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12394
12608
  windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12395
12609
  linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12396
12610
  };
12397
- const platformInfo = platformMap[profile.platform] ?? platformMap.linux;
12611
+ const platformInfo = platformMap[profile.platform];
12398
12612
  return {
12399
12613
  brands,
12400
12614
  fullVersionList,
@@ -12407,7 +12621,28 @@ function buildUserAgentMetadata(profile) {
12407
12621
  wow64: false
12408
12622
  };
12409
12623
  }
12410
- async function applyCdpStealthOverrides(context, page, profile) {
12624
+ async function installCdpStealthOverrides(context, profile, initialPage) {
12625
+ const pages = initialPage === void 0 ? context.pages() : Array.from(/* @__PURE__ */ new Set([initialPage, ...context.pages()]));
12626
+ await Promise.all(pages.map((page) => applyPageOverrides(context, page, profile)));
12627
+ const appliedPages = /* @__PURE__ */ new WeakSet();
12628
+ const applyFuturePageOverrides = async (page) => {
12629
+ if (appliedPages.has(page)) {
12630
+ return;
12631
+ }
12632
+ appliedPages.add(page);
12633
+ await applyPageOverrides(context, page, profile);
12634
+ };
12635
+ if (typeof context.on === "function") {
12636
+ context.on("page", applyFuturePageOverrides);
12637
+ }
12638
+ }
12639
+ async function installContextNetworkHeaders(context, profile) {
12640
+ if (typeof context.setExtraHTTPHeaders !== "function") {
12641
+ return;
12642
+ }
12643
+ await context.setExtraHTTPHeaders(buildStealthRequestHeaders(profile)).catch(() => void 0);
12644
+ }
12645
+ async function applyPageOverrides(context, page, profile) {
12411
12646
  const contextWithCdp = context;
12412
12647
  if (typeof contextWithCdp.newCDPSession !== "function") {
12413
12648
  return;
@@ -12419,31 +12654,50 @@ async function applyCdpStealthOverrides(context, page, profile) {
12419
12654
  return;
12420
12655
  }
12421
12656
  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();
12657
+ await applyCdpStealthCommands((method, params) => cdp.send(method, params), profile);
12444
12658
  } catch {
12659
+ } finally {
12660
+ await cdp.detach().catch(() => void 0);
12445
12661
  }
12446
12662
  }
12663
+ async function applyCdpStealthCommands(send, profile) {
12664
+ await send("Network.setUserAgentOverride", {
12665
+ userAgent: profile.userAgent,
12666
+ acceptLanguage: `${profile.locale},en;q=0.9`,
12667
+ platform: getPlatformString2(profile.platform),
12668
+ userAgentMetadata: buildUserAgentMetadata(profile)
12669
+ });
12670
+ await send("Emulation.setDeviceMetricsOverride", {
12671
+ width: profile.viewport.width,
12672
+ height: profile.viewport.height,
12673
+ deviceScaleFactor: profile.devicePixelRatio,
12674
+ mobile: false,
12675
+ screenWidth: profile.screenResolution.width,
12676
+ screenHeight: profile.screenResolution.height
12677
+ });
12678
+ await send("Emulation.setLocaleOverride", {
12679
+ locale: profile.locale
12680
+ }).catch(() => void 0);
12681
+ await send("Emulation.setTimezoneOverride", {
12682
+ timezoneId: profile.timezoneId
12683
+ }).catch(() => void 0);
12684
+ }
12685
+ function buildStealthRequestHeaders(profile) {
12686
+ const metadata = buildUserAgentMetadata(profile);
12687
+ return {
12688
+ "Accept-Language": `${profile.locale},en;q=0.9`,
12689
+ "Sec-CH-UA": metadata.brands.map(formatClientHintBrand).join(", "),
12690
+ "Sec-CH-UA-Mobile": "?0",
12691
+ "Sec-CH-UA-Platform": `"${metadata.platform}"`,
12692
+ "User-Agent": profile.userAgent
12693
+ };
12694
+ }
12695
+ function formatClientHintBrand(brand2) {
12696
+ return `"${brand2.brand}";v="${brand2.version}"`;
12697
+ }
12698
+ function getPlatformString2(platform) {
12699
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12700
+ }
12447
12701
 
12448
12702
  // src/local-browser/stealth-profiles.ts
12449
12703
  var PROFILE_PRESETS = [
@@ -12536,8 +12790,53 @@ function pickStealthProfilePreset(overrides) {
12536
12790
  const pool = candidates.length > 0 ? candidates : PROFILE_PRESETS;
12537
12791
  return pool[Math.floor(Math.random() * pool.length)];
12538
12792
  }
12793
+ var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
12794
+ var OPENSTEER_LIVE_SESSION_VERSION = 1;
12795
+ function resolveLiveSessionRecordPath(rootPath, provider) {
12796
+ return path6__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
12797
+ }
12798
+ function resolveLocalSessionRecordPath(rootPath) {
12799
+ return resolveLiveSessionRecordPath(rootPath, "local");
12800
+ }
12801
+ function resolveCloudSessionRecordPath(rootPath) {
12802
+ return resolveLiveSessionRecordPath(rootPath, "cloud");
12803
+ }
12804
+ async function readPersistedSessionRecord(rootPath, provider) {
12805
+ const sessionPath = resolveLiveSessionRecordPath(rootPath, provider);
12806
+ if (!await pathExists(sessionPath)) {
12807
+ return void 0;
12808
+ }
12809
+ const parsed = await readJsonFile(sessionPath);
12810
+ if (provider === "local" && isPersistedLocalBrowserSessionRecord(parsed)) {
12811
+ return parsed;
12812
+ }
12813
+ if (provider === "cloud" && isPersistedCloudSessionRecord(parsed)) {
12814
+ return parsed;
12815
+ }
12816
+ return void 0;
12817
+ }
12818
+ async function readPersistedCloudSessionRecord(rootPath) {
12819
+ const record = await readPersistedSessionRecord(rootPath, "cloud");
12820
+ return record?.provider === "cloud" ? record : void 0;
12821
+ }
12822
+ async function readPersistedLocalBrowserSessionRecord(rootPath) {
12823
+ const record = await readPersistedSessionRecord(rootPath, "local");
12824
+ return record?.provider === "local" ? record : void 0;
12825
+ }
12826
+ async function writePersistedSessionRecord(rootPath, record) {
12827
+ await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath, record.provider), record);
12828
+ }
12829
+ async function clearPersistedSessionRecord(rootPath, provider) {
12830
+ await promises.rm(resolveLiveSessionRecordPath(rootPath, provider), { force: true });
12831
+ }
12832
+ function isPersistedCloudSessionRecord(value) {
12833
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "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);
12834
+ }
12835
+ function isPersistedLocalBrowserSessionRecord(value) {
12836
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "local" && (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;
12837
+ }
12539
12838
 
12540
- // src/internal/engine-selection.ts
12839
+ // ../runtime-core/src/internal/engine-selection.ts
12541
12840
  var OPENSTEER_ENGINE_NAMES = ["playwright", "abp"];
12542
12841
  var DEFAULT_OPENSTEER_ENGINE = "playwright";
12543
12842
  function resolveOpensteerEngineName(input = {}) {
@@ -12740,7 +13039,7 @@ var OpensteerBrowserManager = class {
12740
13039
  await this.closePersistentBrowser(workspace);
12741
13040
  await promises.rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12742
13041
  await promises.rm(workspace.browserPath, { recursive: true, force: true });
12743
- await promises.rm(workspace.liveBrowserPath, { force: true });
13042
+ await clearPersistedSessionRecord(workspace.rootPath, "local");
12744
13043
  await ensureDirectory(workspace.browserUserDataDir);
12745
13044
  });
12746
13045
  }
@@ -12751,7 +13050,7 @@ var OpensteerBrowserManager = class {
12751
13050
  await this.closePersistentBrowser(workspace);
12752
13051
  await promises.rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12753
13052
  await promises.rm(workspace.browserPath, { recursive: true, force: true });
12754
- await promises.rm(workspace.liveBrowserPath, { force: true });
13053
+ await clearPersistedSessionRecord(workspace.rootPath, "local");
12755
13054
  });
12756
13055
  }
12757
13056
  async close() {
@@ -12829,12 +13128,12 @@ var OpensteerBrowserManager = class {
12829
13128
  sessionDir: resolveAbpSessionDir(workspace),
12830
13129
  ...launch?.browserExecutablePath === void 0 ? {} : { executablePath: launch.browserExecutablePath }
12831
13130
  };
12832
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13131
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12833
13132
  try {
12834
13133
  return await this.createAdoptedAbpEngine(liveRecord);
12835
13134
  } catch (error) {
12836
13135
  await terminateProcess(launched.process.pid ?? 0).catch(() => void 0);
12837
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13136
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
12838
13137
  throw error;
12839
13138
  }
12840
13139
  });
@@ -12917,7 +13216,7 @@ var OpensteerBrowserManager = class {
12917
13216
  executablePath: launched.executablePath,
12918
13217
  userDataDir: workspace.browserUserDataDir
12919
13218
  };
12920
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13219
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12921
13220
  try {
12922
13221
  return await this.createAttachedEngine({
12923
13222
  endpoint: launched.endpoint,
@@ -12926,7 +13225,7 @@ var OpensteerBrowserManager = class {
12926
13225
  });
12927
13226
  } catch (error) {
12928
13227
  await terminateProcess(launched.pid).catch(() => void 0);
12929
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13228
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
12930
13229
  throw error;
12931
13230
  }
12932
13231
  });
@@ -12946,7 +13245,10 @@ var OpensteerBrowserManager = class {
12946
13245
  const stealthProfile = resolveStealthProfile(this.contextOptions?.stealthProfile);
12947
13246
  await injectBrowserStealthScripts(
12948
13247
  context,
12949
- stealthProfile === void 0 ? {} : { profile: stealthProfile, page }
13248
+ stealthProfile === void 0 ? {} : {
13249
+ profile: stealthProfile,
13250
+ page
13251
+ }
12950
13252
  );
12951
13253
  const engine = await enginePlaywright.createPlaywrightBrowserCoreEngine({
12952
13254
  browser,
@@ -13029,7 +13331,7 @@ var OpensteerBrowserManager = class {
13029
13331
  return void 0;
13030
13332
  }
13031
13333
  if (!isProcessRunning(live.pid)) {
13032
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13334
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13033
13335
  return void 0;
13034
13336
  }
13035
13337
  if (live.engine === "playwright") {
@@ -13048,19 +13350,8 @@ var OpensteerBrowserManager = class {
13048
13350
  return live;
13049
13351
  }
13050
13352
  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
- };
13353
+ const live = await readPersistedLocalBrowserSessionRecord(workspace.rootPath);
13354
+ return live === void 0 ? void 0 : toWorkspaceLiveBrowserRecord(live);
13064
13355
  }
13065
13356
  async resolveLivePersistentEngineName() {
13066
13357
  if (this.mode !== "persistent") {
@@ -13080,7 +13371,7 @@ var OpensteerBrowserManager = class {
13080
13371
  async closePersistentBrowser(workspace) {
13081
13372
  const live = await this.readStoredLiveBrowser(workspace);
13082
13373
  if (!live) {
13083
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13374
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13084
13375
  return;
13085
13376
  }
13086
13377
  if (live.engine === "playwright") {
@@ -13088,15 +13379,21 @@ var OpensteerBrowserManager = class {
13088
13379
  await requestBrowserClose(live.endpoint).catch(() => void 0);
13089
13380
  }
13090
13381
  if (await waitForProcessExit(live.pid, BROWSER_CLOSE_TIMEOUT_MS)) {
13091
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13382
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13092
13383
  return;
13093
13384
  }
13094
13385
  await terminateProcess(live.pid).catch(() => void 0);
13095
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13386
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13096
13387
  return;
13097
13388
  }
13098
13389
  await terminateProcess(live.pid).catch(() => void 0);
13099
- await promises.rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13390
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13391
+ }
13392
+ async writeLivePersistentBrowser(workspace, live) {
13393
+ await writePersistedSessionRecord(
13394
+ workspace.rootPath,
13395
+ toPersistedLocalBrowserSessionRecord(this.workspace, live)
13396
+ );
13100
13397
  }
13101
13398
  requirePersistentMode(method) {
13102
13399
  if (this.mode !== "persistent" || this.workspace === void 0) {
@@ -13108,6 +13405,38 @@ function normalizeWorkspace(workspace) {
13108
13405
  const normalized = workspace?.trim();
13109
13406
  return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
13110
13407
  }
13408
+ function toPersistedLocalBrowserSessionRecord(workspace, live) {
13409
+ return {
13410
+ layout: "opensteer-session",
13411
+ version: 1,
13412
+ provider: "local",
13413
+ ...workspace === void 0 ? {} : { workspace },
13414
+ engine: live.engine,
13415
+ ...live.endpoint === void 0 ? {} : { endpoint: live.endpoint },
13416
+ ...live.baseUrl === void 0 ? {} : { baseUrl: live.baseUrl },
13417
+ ...live.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: live.remoteDebuggingUrl },
13418
+ ...live.sessionDir === void 0 ? {} : { sessionDir: live.sessionDir },
13419
+ pid: live.pid,
13420
+ startedAt: live.startedAt,
13421
+ updatedAt: Date.now(),
13422
+ ...live.executablePath === void 0 ? {} : { executablePath: live.executablePath },
13423
+ userDataDir: live.userDataDir
13424
+ };
13425
+ }
13426
+ function toWorkspaceLiveBrowserRecord(record) {
13427
+ return {
13428
+ mode: "persistent",
13429
+ engine: record.engine,
13430
+ ...record.endpoint === void 0 ? {} : { endpoint: record.endpoint },
13431
+ ...record.baseUrl === void 0 ? {} : { baseUrl: record.baseUrl },
13432
+ ...record.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: record.remoteDebuggingUrl },
13433
+ ...record.sessionDir === void 0 ? {} : { sessionDir: record.sessionDir },
13434
+ pid: record.pid,
13435
+ startedAt: record.startedAt,
13436
+ ...record.executablePath === void 0 ? {} : { executablePath: record.executablePath },
13437
+ userDataDir: record.userDataDir
13438
+ };
13439
+ }
13111
13440
  function resolveBrowserMode(workspace, browser) {
13112
13441
  if (browser === void 0) {
13113
13442
  return workspace === void 0 ? "temporary" : "persistent";
@@ -13187,9 +13516,7 @@ function buildChromeArgs(userDataDir, launch, viewport) {
13187
13516
  if (isHeadless) {
13188
13517
  args.push("--headless=new");
13189
13518
  }
13190
- const hasUserWindowSize = (launch?.args ?? []).some(
13191
- (entry) => entry.startsWith("--window-size")
13192
- );
13519
+ const hasUserWindowSize = (launch?.args ?? []).some((entry) => entry.startsWith("--window-size"));
13193
13520
  if (!hasUserWindowSize) {
13194
13521
  const width = viewport?.width ?? 1440;
13195
13522
  const height = viewport?.height ?? 900;
@@ -13387,7 +13714,14 @@ async function sleep(ms) {
13387
13714
  await new Promise((resolve5) => setTimeout(resolve5, ms));
13388
13715
  }
13389
13716
 
13390
- // src/internal/errors.ts
13717
+ // ../runtime-core/package.json
13718
+ var package_default = {
13719
+ version: "0.1.0"};
13720
+
13721
+ // ../runtime-core/src/version.ts
13722
+ var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
13723
+
13724
+ // ../runtime-core/src/internal/errors.ts
13391
13725
  function normalizeThrownOpensteerError(error, fallbackMessage) {
13392
13726
  if (isOpensteerProtocolError(error)) {
13393
13727
  return toOpensteerError(error);
@@ -13398,15 +13732,6 @@ function normalizeThrownOpensteerError(error, fallbackMessage) {
13398
13732
  ...error.details === void 0 ? {} : { details: error.details }
13399
13733
  });
13400
13734
  }
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
13735
  if (error instanceof Error) {
13411
13736
  return createOpensteerError("operation-failed", error.message, {
13412
13737
  details: {
@@ -13576,7 +13901,7 @@ function roundScale(value) {
13576
13901
  return Number(value.toFixed(6));
13577
13902
  }
13578
13903
 
13579
- // src/runtimes/computer-use/trace-enrichment.ts
13904
+ // ../runtime-core/src/runtimes/computer-use/trace-enrichment.ts
13580
13905
  async function enrichComputerUseTrace(input) {
13581
13906
  const tracePoints = toTracePoints(input.action);
13582
13907
  if (tracePoints.length === 0) {
@@ -13669,7 +13994,7 @@ function toOpensteerResolvedTarget(target) {
13669
13994
  };
13670
13995
  }
13671
13996
 
13672
- // src/runtimes/computer-use/runtime.ts
13997
+ // ../runtime-core/src/runtimes/computer-use/runtime.ts
13673
13998
  function createComputerUseRuntime(options) {
13674
13999
  return new DefaultComputerUseRuntime(options);
13675
14000
  }
@@ -13764,7 +14089,7 @@ function normalizeScreenshotOptions(input) {
13764
14089
  };
13765
14090
  }
13766
14091
 
13767
- // src/sdk/semantic-dispatch.ts
14092
+ // ../runtime-core/src/sdk/semantic-dispatch.ts
13768
14093
  async function dispatchSemanticOperation(runtime, operation, input, options = {}) {
13769
14094
  switch (operation) {
13770
14095
  case "session.open":
@@ -14025,7 +14350,7 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
14025
14350
  }
14026
14351
  }
14027
14352
 
14028
- // src/requests/shared.ts
14353
+ // ../runtime-core/src/requests/shared.ts
14029
14354
  var REDACTED_HEADER_VALUE = "[redacted]";
14030
14355
  var HTTP_HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
14031
14356
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
@@ -14241,14 +14566,14 @@ function resolveTextEncoding(charset) {
14241
14566
  }
14242
14567
  }
14243
14568
 
14244
- // src/requests/errors.ts
14569
+ // ../runtime-core/src/requests/errors.ts
14245
14570
  function invalidRequestPlanError(message, details = {}) {
14246
14571
  return new OpensteerProtocolError("invalid-request", message, {
14247
14572
  details
14248
14573
  });
14249
14574
  }
14250
14575
 
14251
- // src/requests/plans/index.ts
14576
+ // ../runtime-core/src/requests/plans/index.ts
14252
14577
  var HTTP_METHOD_PATTERN = /^[A-Za-z]+$/;
14253
14578
  var URL_TEMPLATE_PLACEHOLDER_PATTERN = /\{([A-Za-z][A-Za-z0-9_-]*)\}/g;
14254
14579
  function assertValidRequestPlanPayload(payload) {
@@ -14656,7 +14981,7 @@ function normalizeTrimmedString(field, value) {
14656
14981
  return normalized;
14657
14982
  }
14658
14983
 
14659
- // src/requests/inference.ts
14984
+ // ../runtime-core/src/requests/inference.ts
14660
14985
  function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14661
14986
  const url = new URL(record.record.url);
14662
14987
  const defaultQuery = Array.from(url.searchParams.entries()).map(
@@ -14669,9 +14994,10 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14669
14994
  const responseContentType = headerValue(record.record.responseHeaders, "content-type") ?? record.record.responseBody?.mimeType;
14670
14995
  const defaultHeaders = inferDefaultHeaders(record);
14671
14996
  const auth = inferAuth(record.record.requestHeaders);
14997
+ const body = inferRequestPlanBody(record.record.requestBody, requestContentType);
14672
14998
  const payload = normalizeRequestPlanPayload({
14673
14999
  transport: {
14674
- kind: "context-http"
15000
+ kind: input.transport ?? "context-http"
14675
15001
  },
14676
15002
  endpoint: {
14677
15003
  method: record.record.method,
@@ -14679,12 +15005,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14679
15005
  ...defaultQuery.length === 0 ? {} : { defaultQuery },
14680
15006
  ...defaultHeaders.length === 0 ? {} : { defaultHeaders }
14681
15007
  },
14682
- ...requestContentType === void 0 && record.record.requestBody === void 0 ? {} : {
14683
- body: {
14684
- ...requestContentType === void 0 ? {} : { contentType: requestContentType },
14685
- required: true
14686
- }
14687
- },
15008
+ ...body === void 0 ? {} : { body },
14688
15009
  ...record.record.status === void 0 ? {} : {
14689
15010
  response: {
14690
15011
  status: record.record.status,
@@ -14696,7 +15017,6 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14696
15017
  return {
14697
15018
  key: input.key,
14698
15019
  version: input.version,
14699
- lifecycle: input.lifecycle ?? "draft",
14700
15020
  provenance: {
14701
15021
  source: record.source === "saved" ? "saved-network-record" : "live-network-record",
14702
15022
  sourceId: record.recordId,
@@ -14740,34 +15060,78 @@ function inferAuth(headers) {
14740
15060
  }
14741
15061
  return void 0;
14742
15062
  }
14743
-
14744
- // src/reverse/materialization.ts
14745
- var ALWAYS_OMIT_HEADER_NAMES = /* @__PURE__ */ new Set(["content-length", "host", "priority"]);
14746
- var BROWSER_OWNED_HEADER_PREFIXES = ["sec-"];
14747
- function isManagedRequestHeaderName(name, transport) {
14748
- const normalized = normalizeHeaderName(name);
14749
- if (!isValidHttpHeaderName(name)) {
14750
- return true;
14751
- }
14752
- if (normalized.startsWith(":")) {
14753
- return true;
14754
- }
14755
- if (ALWAYS_OMIT_HEADER_NAMES.has(normalized)) {
14756
- return true;
14757
- }
14758
- if (transport !== void 0 && (transport === "page-http" || transport === "session-http")) {
14759
- if (BROWSER_OWNED_HEADER_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
14760
- return true;
14761
- }
14762
- }
14763
- return false;
14764
- }
14765
- function stripManagedRequestHeaders(headers, transport) {
14766
- if (headers === void 0 || headers.length === 0) {
15063
+ function inferRequestPlanBody(body, contentType) {
15064
+ if (body === void 0) {
14767
15065
  return void 0;
14768
15066
  }
14769
- const filtered = headers.filter((header) => !isManagedRequestHeaderName(header.name, transport));
14770
- return filtered.length === 0 ? void 0 : filtered.map((header) => ({ ...header }));
15067
+ const text = Buffer.from(body.data, "base64").toString("utf8");
15068
+ const normalizedContentType = contentType?.toLowerCase();
15069
+ const trimmedText = text.trim();
15070
+ const parsedJson = parseJsonBody(trimmedText);
15071
+ if (normalizedContentType?.includes("application/json") === true || normalizedContentType?.includes("+json") === true || parsedJson !== void 0) {
15072
+ return {
15073
+ kind: "json",
15074
+ required: true,
15075
+ ...contentType === void 0 ? {} : { contentType },
15076
+ template: parsedJson ?? text
15077
+ };
15078
+ }
15079
+ if (normalizedContentType?.includes("application/x-www-form-urlencoded") === true) {
15080
+ return {
15081
+ kind: "form",
15082
+ required: true,
15083
+ ...contentType === void 0 ? {} : { contentType },
15084
+ fields: Array.from(new URLSearchParams(text).entries()).map(([name, value]) => ({
15085
+ name,
15086
+ value
15087
+ }))
15088
+ };
15089
+ }
15090
+ return {
15091
+ kind: "text",
15092
+ required: true,
15093
+ ...contentType === void 0 ? {} : { contentType },
15094
+ template: text
15095
+ };
15096
+ }
15097
+ function parseJsonBody(value) {
15098
+ if (value.length === 0 || !value.startsWith("{") && !value.startsWith("[")) {
15099
+ return void 0;
15100
+ }
15101
+ try {
15102
+ return JSON.parse(value);
15103
+ } catch {
15104
+ return void 0;
15105
+ }
15106
+ }
15107
+
15108
+ // ../runtime-core/src/reverse/materialization.ts
15109
+ var ALWAYS_OMIT_HEADER_NAMES = /* @__PURE__ */ new Set(["content-length", "host", "priority"]);
15110
+ var BROWSER_OWNED_HEADER_PREFIXES = ["sec-"];
15111
+ function isManagedRequestHeaderName(name, transport) {
15112
+ const normalized = normalizeHeaderName(name);
15113
+ if (!isValidHttpHeaderName(name)) {
15114
+ return true;
15115
+ }
15116
+ if (normalized.startsWith(":")) {
15117
+ return true;
15118
+ }
15119
+ if (ALWAYS_OMIT_HEADER_NAMES.has(normalized)) {
15120
+ return true;
15121
+ }
15122
+ if (transport !== void 0 && (transport === "page-http" || transport === "session-http")) {
15123
+ if (BROWSER_OWNED_HEADER_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
15124
+ return true;
15125
+ }
15126
+ }
15127
+ return false;
15128
+ }
15129
+ function stripManagedRequestHeaders(headers, transport) {
15130
+ if (headers === void 0 || headers.length === 0) {
15131
+ return void 0;
15132
+ }
15133
+ const filtered = headers.filter((header) => !isManagedRequestHeaderName(header.name, transport));
15134
+ return filtered.length === 0 ? void 0 : filtered.map((header) => ({ ...header }));
14771
15135
  }
14772
15136
  function finalizeMaterializedTransportRequest(request, transport) {
14773
15137
  const headers = stripManagedRequestHeaders(request.headers, transport);
@@ -14777,7 +15141,7 @@ function finalizeMaterializedTransportRequest(request, transport) {
14777
15141
  };
14778
15142
  }
14779
15143
 
14780
- // src/network/diff.ts
15144
+ // ../runtime-core/src/network/diff.ts
14781
15145
  function diffNetworkRecords(left, right, input) {
14782
15146
  const requestDiffs = [];
14783
15147
  const responseDiffs = [];
@@ -14937,7 +15301,7 @@ function diffStringMap(prefix, left, right, includeUnchanged, output) {
14937
15301
  diffScalarField(`${prefix}.${key}`, left[key], right[key], includeUnchanged, output);
14938
15302
  }
14939
15303
  }
14940
- function diffScalarField(path11, left, right, includeUnchanged, output) {
15304
+ function diffScalarField(path13, left, right, includeUnchanged, output) {
14941
15305
  const leftValue = stringifyFieldValue(left);
14942
15306
  const rightValue = stringifyFieldValue(right);
14943
15307
  const kind = leftValue === void 0 ? rightValue === void 0 ? "unchanged" : "added" : rightValue === void 0 ? "removed" : leftValue === rightValue ? "unchanged" : "changed";
@@ -14945,7 +15309,7 @@ function diffScalarField(path11, left, right, includeUnchanged, output) {
14945
15309
  return;
14946
15310
  }
14947
15311
  output.push({
14948
- path: path11,
15312
+ path: path13,
14949
15313
  kind,
14950
15314
  ...leftValue === void 0 ? {} : { leftValue },
14951
15315
  ...rightValue === void 0 ? {} : { rightValue },
@@ -15134,7 +15498,7 @@ var NetworkJournal = class {
15134
15498
  }
15135
15499
  };
15136
15500
 
15137
- // src/network/minimize.ts
15501
+ // ../runtime-core/src/network/minimize.ts
15138
15502
  function prepareMinimizationRequest(record, preserve = []) {
15139
15503
  const requestUrl = new URL(record.record.url);
15140
15504
  const preservedNames = new Set(
@@ -15547,7 +15911,7 @@ function resolveBodyEncoding2(charset) {
15547
15911
  }
15548
15912
  }
15549
15913
 
15550
- // src/network/probe.ts
15914
+ // ../runtime-core/src/network/probe.ts
15551
15915
  var TRANSPORT_PROBE_LADDER = [
15552
15916
  "direct-http",
15553
15917
  "matched-tls",
@@ -15559,7 +15923,7 @@ function selectTransportProbeRecommendation(results) {
15559
15923
  return results.find((entry) => entry.success)?.transport ?? results.at(-1)?.transport ?? "session-http";
15560
15924
  }
15561
15925
 
15562
- // src/reverse/analysis.ts
15926
+ // ../runtime-core/src/reverse/analysis.ts
15563
15927
  var TELEMETRY_HOST_PATTERNS = [
15564
15928
  "google-analytics",
15565
15929
  "doubleclick",
@@ -15899,9 +16263,9 @@ function matchReverseTargetHints(channel, codec, targetHints) {
15899
16263
  matches.add(`host:${host}`);
15900
16264
  }
15901
16265
  }
15902
- for (const path11 of targetHints.paths ?? []) {
15903
- if (url.pathname.includes(path11)) {
15904
- matches.add(`path:${path11}`);
16266
+ for (const path13 of targetHints.paths ?? []) {
16267
+ if (url.pathname.includes(path13)) {
16268
+ matches.add(`path:${path13}`);
15905
16269
  }
15906
16270
  }
15907
16271
  for (const operationName of targetHints.operationNames ?? []) {
@@ -16753,7 +17117,7 @@ function looksHighEntropy(value) {
16753
17117
  return uniqueCharacters >= Math.min(20, Math.floor(trimmed.length * 0.6));
16754
17118
  }
16755
17119
 
16756
- // src/reverse/discovery.ts
17120
+ // ../runtime-core/src/reverse/discovery.ts
16757
17121
  function clusterReverseObservationRecords(input) {
16758
17122
  const groups = /* @__PURE__ */ new Map();
16759
17123
  for (const item of sortClusterableRecords(input.records)) {
@@ -17060,7 +17424,7 @@ async function readDirSafe(directory) {
17060
17424
  }
17061
17425
  }
17062
17426
 
17063
- // src/reverse/validation.ts
17427
+ // ../runtime-core/src/reverse/validation.ts
17064
17428
  function buildReverseValidationRules(input) {
17065
17429
  switch (input.channel.kind) {
17066
17430
  case "http":
@@ -17337,7 +17701,7 @@ function jsonStructureShape(value) {
17337
17701
  return typeof value;
17338
17702
  }
17339
17703
 
17340
- // src/reverse/workflows.ts
17704
+ // ../runtime-core/src/reverse/workflows.ts
17341
17705
  function buildReversePackageWorkflow(input) {
17342
17706
  if (input.template === void 0 && input.executeStepInput === void 0) {
17343
17707
  return [];
@@ -17706,7 +18070,7 @@ function dedupeSuggestedEdits(suggestions) {
17706
18070
  return [...new Map(suggestions.map((suggestion) => [suggestion.id, suggestion])).values()];
17707
18071
  }
17708
18072
 
17709
- // src/sdk/extraction-data-path.ts
18073
+ // ../runtime-core/src/sdk/extraction-data-path.ts
17710
18074
  function joinDataPath(base, key) {
17711
18075
  const normalizedBase = base.trim();
17712
18076
  const normalizedKey = key.trim();
@@ -17737,8 +18101,8 @@ function encodeDataPath(tokens) {
17737
18101
  }
17738
18102
  return out;
17739
18103
  }
17740
- function parseDataPath(path11) {
17741
- const input = path11.trim();
18104
+ function parseDataPath(path13) {
18105
+ const input = path13.trim();
17742
18106
  if (input.length === 0) {
17743
18107
  return [];
17744
18108
  }
@@ -17788,8 +18152,8 @@ function parseDataPath(path11) {
17788
18152
  function inflateDataPathObject(flat) {
17789
18153
  let root = {};
17790
18154
  let initialized = false;
17791
- for (const [path11, value] of Object.entries(flat)) {
17792
- const tokens = parseDataPath(path11);
18155
+ for (const [path13, value] of Object.entries(flat)) {
18156
+ const tokens = parseDataPath(path13);
17793
18157
  if (!tokens || tokens.length === 0) {
17794
18158
  continue;
17795
18159
  }
@@ -17847,7 +18211,7 @@ function assignDataPathValue(root, tokens, value) {
17847
18211
  }
17848
18212
  }
17849
18213
 
17850
- // src/sdk/extraction-consolidation.ts
18214
+ // ../runtime-core/src/sdk/extraction-consolidation.ts
17851
18215
  var STRUCTURAL_ATTR_KEYS = /* @__PURE__ */ new Set([
17852
18216
  "class",
17853
18217
  "role",
@@ -18121,8 +18485,8 @@ function buildVariantDescriptorFromCluster(descriptors) {
18121
18485
  fields: mergedFields
18122
18486
  };
18123
18487
  }
18124
- function minimizePathMatchClauses(path11, mode) {
18125
- const normalized = sanitizeElementPath(path11);
18488
+ function minimizePathMatchClauses(path13, mode) {
18489
+ const normalized = sanitizeElementPath(path13);
18126
18490
  const nodes = normalized.nodes.map((node, index) => {
18127
18491
  const isLast = index === normalized.nodes.length - 1;
18128
18492
  const attrs = node.attrs || {};
@@ -18226,8 +18590,8 @@ function seedMinimalAttrClause(attrs) {
18226
18590
  }
18227
18591
  return null;
18228
18592
  }
18229
- function relaxPathForSingleSample(path11, mode) {
18230
- const normalized = sanitizeElementPath(path11);
18593
+ function relaxPathForSingleSample(path13, mode) {
18594
+ const normalized = sanitizeElementPath(path13);
18231
18595
  const relaxedNodes = normalized.nodes.map((node, index) => {
18232
18596
  const isLast = index === normalized.nodes.length - 1;
18233
18597
  const attrs = normalizeAttrsForSingleSample(node.attrs || {});
@@ -18312,8 +18676,8 @@ function shouldKeepAttrForSingleSample(key) {
18312
18676
  }
18313
18677
  return true;
18314
18678
  }
18315
- function buildPathStructureKey(path11) {
18316
- const normalized = sanitizeElementPath(path11);
18679
+ function buildPathStructureKey(path13) {
18680
+ const normalized = sanitizeElementPath(path13);
18317
18681
  return canonicalJsonString({
18318
18682
  context: (normalized.context || []).map((hop) => ({
18319
18683
  kind: hop.kind,
@@ -18440,30 +18804,30 @@ function buildArrayItemNode(fields) {
18440
18804
  }
18441
18805
  return node;
18442
18806
  }
18443
- function insertNodeAtPath(root, path11, node) {
18444
- const tokens = parseDataPath(path11);
18807
+ function insertNodeAtPath(root, path13, node) {
18808
+ const tokens = parseDataPath(path13);
18445
18809
  if (!tokens || !tokens.length) {
18446
18810
  throw new Error(
18447
- `Invalid persisted extraction path "${path11}": expected a non-empty object path.`
18811
+ `Invalid persisted extraction path "${path13}": expected a non-empty object path.`
18448
18812
  );
18449
18813
  }
18450
18814
  if (tokens.some((token) => token.kind === "index")) {
18451
18815
  throw new Error(
18452
- `Invalid persisted extraction path "${path11}": nested array indices are not supported in cached descriptors.`
18816
+ `Invalid persisted extraction path "${path13}": nested array indices are not supported in cached descriptors.`
18453
18817
  );
18454
18818
  }
18455
18819
  let current = root;
18456
18820
  for (let index = 0; index < tokens.length; index += 1) {
18457
18821
  const token = tokens[index];
18458
18822
  if (!token || token.kind !== "prop") {
18459
- throw new Error(`Invalid persisted extraction path "${path11}": expected object segment.`);
18823
+ throw new Error(`Invalid persisted extraction path "${path13}": expected object segment.`);
18460
18824
  }
18461
18825
  const isLast = index === tokens.length - 1;
18462
18826
  if (isLast) {
18463
18827
  const existing = current[token.key];
18464
18828
  if (existing) {
18465
18829
  throw new Error(
18466
- `Conflicting persisted extraction path "${path11}" detected while building descriptor tree.`
18830
+ `Conflicting persisted extraction path "${path13}" detected while building descriptor tree.`
18467
18831
  );
18468
18832
  }
18469
18833
  current[token.key] = node;
@@ -18478,7 +18842,7 @@ function insertNodeAtPath(root, path11, node) {
18478
18842
  }
18479
18843
  if (!isPersistedObjectNode(next)) {
18480
18844
  throw new Error(
18481
- `Conflicting persisted extraction path "${path11}" detected at "${token.key}".`
18845
+ `Conflicting persisted extraction path "${path13}" detected at "${token.key}".`
18482
18846
  );
18483
18847
  }
18484
18848
  current = next;
@@ -18513,7 +18877,7 @@ function buildItemRootForArrayIndex(entries) {
18513
18877
  }
18514
18878
  const paths = entries.map(
18515
18879
  (entry) => isPersistablePathField(entry.source) ? sanitizeElementPath(entry.source.path) : null
18516
- ).filter((path11) => path11 !== null);
18880
+ ).filter((path13) => path13 !== null);
18517
18881
  if (!paths.length) {
18518
18882
  return null;
18519
18883
  }
@@ -18534,7 +18898,7 @@ function getCommonPathPrefixLength(paths) {
18534
18898
  if (!paths.length) {
18535
18899
  return 0;
18536
18900
  }
18537
- const nodeChains = paths.map((path11) => path11.nodes);
18901
+ const nodeChains = paths.map((path13) => path13.nodes);
18538
18902
  const minLength = Math.min(...nodeChains.map((nodes) => nodes.length));
18539
18903
  if (!Number.isFinite(minLength) || minLength <= 0) {
18540
18904
  return 0;
@@ -18603,30 +18967,30 @@ function mergeElementPathsByMajority(paths) {
18603
18967
  if (!paths.length) {
18604
18968
  return null;
18605
18969
  }
18606
- const normalized = paths.map((path11) => sanitizeElementPath(path11));
18970
+ const normalized = paths.map((path13) => sanitizeElementPath(path13));
18607
18971
  const contextKey = pickModeString(
18608
- normalized.map((path11) => canonicalJsonString(path11.context)),
18972
+ normalized.map((path13) => canonicalJsonString(path13.context)),
18609
18973
  1
18610
18974
  );
18611
18975
  if (!contextKey) {
18612
18976
  return null;
18613
18977
  }
18614
- const sameContext = normalized.filter((path11) => canonicalJsonString(path11.context) === contextKey);
18978
+ const sameContext = normalized.filter((path13) => canonicalJsonString(path13.context) === contextKey);
18615
18979
  if (!sameContext.length) {
18616
18980
  return null;
18617
18981
  }
18618
18982
  const targetLength = pickModeNumber(
18619
- sameContext.map((path11) => path11.nodes.length),
18983
+ sameContext.map((path13) => path13.nodes.length),
18620
18984
  1
18621
18985
  ) ?? sameContext[0]?.nodes.length ?? 0;
18622
- const aligned = sameContext.filter((path11) => path11.nodes.length === targetLength);
18986
+ const aligned = sameContext.filter((path13) => path13.nodes.length === targetLength);
18623
18987
  if (!aligned.length) {
18624
18988
  return null;
18625
18989
  }
18626
18990
  const threshold = majorityThreshold(aligned.length);
18627
18991
  const nodes = [];
18628
18992
  for (let index = 0; index < targetLength; index += 1) {
18629
- const nodesAtIndex = aligned.map((path11) => path11.nodes[index]).filter((node) => node !== void 0);
18993
+ const nodesAtIndex = aligned.map((path13) => path13.nodes[index]).filter((node) => node !== void 0);
18630
18994
  if (!nodesAtIndex.length) {
18631
18995
  return null;
18632
18996
  }
@@ -18872,8 +19236,8 @@ function clonePathContext(context) {
18872
19236
  function clonePathNodes(nodes) {
18873
19237
  return JSON.parse(JSON.stringify(nodes || []));
18874
19238
  }
18875
- function cloneElementPath2(path11) {
18876
- return JSON.parse(JSON.stringify(path11));
19239
+ function cloneElementPath2(path13) {
19240
+ return JSON.parse(JSON.stringify(path13));
18877
19241
  }
18878
19242
  function clonePersistedOpensteerExtractionNode(node) {
18879
19243
  return JSON.parse(JSON.stringify(node));
@@ -18894,7 +19258,7 @@ function isPersistedObjectNode(node) {
18894
19258
  return !!node && typeof node === "object" && !Array.isArray(node) && !isPersistedOpensteerExtractionValueNode(node) && !isPersistedOpensteerExtractionSourceNode(node) && !isPersistedOpensteerExtractionArrayNode(node);
18895
19259
  }
18896
19260
 
18897
- // src/sdk/extraction.ts
19261
+ // ../runtime-core/src/sdk/extraction.ts
18898
19262
  function assertValidOpensteerExtractionSchemaRoot(schema) {
18899
19263
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
18900
19264
  throw new Error("Invalid extraction schema: expected a JSON object at the top level.");
@@ -18981,7 +19345,7 @@ async function replayOpensteerExtractionPayload(options) {
18981
19345
  return extractPersistedObjectNode(options.pageRef, options.dom, options.payload);
18982
19346
  }
18983
19347
  function createOpensteerExtractionDescriptorStore(options) {
18984
- const namespace = normalizeNamespace2(options.namespace);
19348
+ const namespace = normalizeNamespace(options.namespace);
18985
19349
  if (options.root) {
18986
19350
  return new FilesystemOpensteerExtractionDescriptorStore(
18987
19351
  options.root.registry.descriptors,
@@ -19159,12 +19523,12 @@ async function resolvePersistableFieldTargets(options) {
19159
19523
  anchor: field.anchor
19160
19524
  }
19161
19525
  });
19162
- const path11 = resolved.replayPath ?? await options.dom.buildPath({
19526
+ const path13 = resolved.replayPath ?? await options.dom.buildPath({
19163
19527
  locator: resolved.locator
19164
19528
  });
19165
19529
  fields.push({
19166
19530
  key: field.key,
19167
- path: sanitizeElementPath(path11),
19531
+ path: sanitizeElementPath(path13),
19168
19532
  ...field.attribute === void 0 ? {} : { attribute: field.attribute }
19169
19533
  });
19170
19534
  }
@@ -19247,8 +19611,8 @@ function collectPersistedValueNodeRefs(node) {
19247
19611
  return [
19248
19612
  {
19249
19613
  path: sanitizeElementPath(node.$path),
19250
- replacePath: (path11) => {
19251
- node.$path = sanitizeElementPath(path11);
19614
+ replacePath: (path13) => {
19615
+ node.$path = sanitizeElementPath(path13);
19252
19616
  }
19253
19617
  }
19254
19618
  ];
@@ -19262,13 +19626,13 @@ function collectPersistedValueNodeRefs(node) {
19262
19626
  }
19263
19627
  return refs;
19264
19628
  }
19265
- function hasPositionClause(path11) {
19266
- return path11.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19629
+ function hasPositionClause(path13) {
19630
+ return path13.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19267
19631
  }
19268
- function stripPositionClauses2(path11) {
19632
+ function stripPositionClauses2(path13) {
19269
19633
  return sanitizeElementPath({
19270
- context: path11.context,
19271
- nodes: path11.nodes.map((node) => ({
19634
+ context: path13.context,
19635
+ nodes: path13.nodes.map((node) => ({
19272
19636
  ...node,
19273
19637
  match: node.match.filter((clause) => clause.kind !== "position")
19274
19638
  }))
@@ -19478,11 +19842,11 @@ function normalizeSchemaField(value) {
19478
19842
  ...attribute === void 0 ? {} : { attribute }
19479
19843
  };
19480
19844
  }
19481
- function normalizeNamespace2(namespace) {
19845
+ function normalizeNamespace(namespace) {
19482
19846
  const normalized = String(namespace ?? "default").trim();
19483
19847
  return normalized.length === 0 ? "default" : normalized;
19484
19848
  }
19485
- function descriptionKey2(namespace, description) {
19849
+ function descriptionKey(namespace, description) {
19486
19850
  return `extract:${namespace}:${sha256Hex3(description.trim())}`;
19487
19851
  }
19488
19852
  function parseExtractionDescriptorRecord(record) {
@@ -19585,7 +19949,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
19585
19949
  }
19586
19950
  async read(input) {
19587
19951
  const record = await this.registry.resolve({
19588
- key: descriptionKey2(this.namespace, input.description)
19952
+ key: descriptionKey(this.namespace, input.description)
19589
19953
  });
19590
19954
  return record === void 0 ? void 0 : parseExtractionDescriptorRecord(record);
19591
19955
  }
@@ -19597,7 +19961,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
19597
19961
  ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
19598
19962
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
19599
19963
  };
19600
- const key = descriptionKey2(this.namespace, input.description);
19964
+ const key = descriptionKey(this.namespace, input.description);
19601
19965
  const version = sha256Hex3(canonicalJsonString(payload));
19602
19966
  const existing = await this.registry.resolve({ key, version });
19603
19967
  if (existing) {
@@ -19636,7 +20000,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
19636
20000
  latestByKey = /* @__PURE__ */ new Map();
19637
20001
  recordsByKey = /* @__PURE__ */ new Map();
19638
20002
  async read(input) {
19639
- return this.latestByKey.get(descriptionKey2(this.namespace, input.description));
20003
+ return this.latestByKey.get(descriptionKey(this.namespace, input.description));
19640
20004
  }
19641
20005
  async write(input) {
19642
20006
  const payload = {
@@ -19646,7 +20010,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
19646
20010
  ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
19647
20011
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
19648
20012
  };
19649
- const key = descriptionKey2(this.namespace, input.description);
20013
+ const key = descriptionKey(this.namespace, input.description);
19650
20014
  const version = sha256Hex3(canonicalJsonString(payload));
19651
20015
  const existing = this.recordsByKey.get(key)?.get(version);
19652
20016
  if (existing) {
@@ -19678,18 +20042,19 @@ function normalizeNonEmptyString2(name, value) {
19678
20042
  function normalizeKey(value) {
19679
20043
  return String(value ?? "").trim();
19680
20044
  }
19681
- function labelForPath(path11) {
19682
- return path11.trim().length === 0 ? "$" : path11;
20045
+ function labelForPath(path13) {
20046
+ return path13.trim().length === 0 ? "$" : path13;
19683
20047
  }
19684
20048
  function sha256Hex3(value) {
19685
20049
  return crypto.createHash("sha256").update(value).digest("hex");
19686
20050
  }
19687
20051
 
19688
- // src/sdk/snapshot/constants.ts
20052
+ // ../runtime-core/src/sdk/snapshot/constants.ts
19689
20053
  var OPENSTEER_INTERACTIVE_ATTR = "data-opensteer-interactive";
19690
20054
  var OPENSTEER_HIDDEN_ATTR = "data-opensteer-hidden";
19691
20055
  var OPENSTEER_SCROLLABLE_ATTR = "data-opensteer-scrollable";
19692
20056
  var OPENSTEER_NODE_ID_ATTR = "data-os-node-id";
20057
+ var OPENSTEER_SPARSE_COUNTER_ATTR = "data-os-c";
19693
20058
  var OPENSTEER_BOUNDARY_ATTR = "data-os-boundary";
19694
20059
  var OPENSTEER_UNAVAILABLE_ATTR = "data-os-unavailable";
19695
20060
  var OPENSTEER_IFRAME_BOUNDARY_TAG = "os-iframe-root";
@@ -19753,7 +20118,7 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
19753
20118
  "wbr"
19754
20119
  ]);
19755
20120
 
19756
- // src/sdk/snapshot/cleaner.ts
20121
+ // ../runtime-core/src/sdk/snapshot/cleaner.ts
19757
20122
  var STRIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "meta", "link", "template"]);
19758
20123
  var TEXT_ATTR_MAX = 150;
19759
20124
  var URL_ATTR_MAX = 500;
@@ -20193,8 +20558,83 @@ var VOID_TAGS2 = /* @__PURE__ */ new Set([
20193
20558
  "wbr"
20194
20559
  ]);
20195
20560
 
20196
- // src/sdk/snapshot/compiler.ts
20561
+ // ../runtime-core/src/sdk/snapshot/compiler.ts
20562
+ async function assignSparseCountersToLiveDom(engine, pageRef) {
20563
+ try {
20564
+ await engine.evaluatePage({
20565
+ pageRef,
20566
+ script: `(() => {
20567
+ let counter = 1;
20568
+ const walk = (root) => {
20569
+ for (const child of root.children) {
20570
+ child.setAttribute('data-os-c', String(counter++));
20571
+ walk(child);
20572
+ if (child.shadowRoot) walk(child.shadowRoot);
20573
+ }
20574
+ };
20575
+ walk(document);
20576
+ })()`
20577
+ });
20578
+ return true;
20579
+ } catch {
20580
+ return false;
20581
+ }
20582
+ }
20583
+ async function syncDenseCountersToLiveDom(engine, pageRef, sparseToDirectMapping) {
20584
+ const mappingObj = Object.fromEntries(sparseToDirectMapping);
20585
+ await engine.evaluatePage({
20586
+ pageRef,
20587
+ script: `((mapping) => {
20588
+ const walk = (root) => {
20589
+ for (const child of root.children) {
20590
+ child.removeAttribute('c');
20591
+ const sparse = child.getAttribute('data-os-c');
20592
+ if (sparse !== null) {
20593
+ const dense = mapping[sparse];
20594
+ if (dense !== undefined) {
20595
+ child.setAttribute('c', String(dense));
20596
+ }
20597
+ child.removeAttribute('data-os-c');
20598
+ }
20599
+ walk(child);
20600
+ if (child.shadowRoot) walk(child.shadowRoot);
20601
+ }
20602
+ };
20603
+ walk(document);
20604
+ })`,
20605
+ args: [mappingObj]
20606
+ });
20607
+ }
20608
+ function renumberCountersDensely(cleanedHtml, counterRecords) {
20609
+ const $ = cheerio__namespace.load(cleanedHtml, { xmlMode: false });
20610
+ const newRecords = /* @__PURE__ */ new Map();
20611
+ const sparseToDirectMapping = /* @__PURE__ */ new Map();
20612
+ let nextDense = 1;
20613
+ $("[c]").each(function renumberElement() {
20614
+ const el = $(this);
20615
+ const oldC = Number.parseInt(String(el.attr("c") || ""), 10);
20616
+ if (!Number.isFinite(oldC)) {
20617
+ return;
20618
+ }
20619
+ const record = counterRecords.get(oldC);
20620
+ if (!record) {
20621
+ return;
20622
+ }
20623
+ const denseC = nextDense++;
20624
+ el.attr("c", String(denseC));
20625
+ newRecords.set(denseC, { ...record, element: denseC });
20626
+ if (record.sparseCounter !== void 0) {
20627
+ sparseToDirectMapping.set(record.sparseCounter, denseC);
20628
+ }
20629
+ });
20630
+ return {
20631
+ html: $.html(),
20632
+ counterRecords: newRecords,
20633
+ sparseToDirectMapping
20634
+ };
20635
+ }
20197
20636
  async function compileOpensteerSnapshot(options) {
20637
+ const liveCountersEnabled = await assignSparseCountersToLiveDom(options.engine, options.pageRef);
20198
20638
  const pageInfo = await options.engine.getPageInfo({ pageRef: options.pageRef });
20199
20639
  const mainSnapshot = await getMainDocumentSnapshot(options.engine, options.pageRef);
20200
20640
  const snapshotsByDocumentRef = await collectDocumentSnapshots(options.engine, mainSnapshot);
@@ -20213,13 +20653,24 @@ async function compileOpensteerSnapshot(options) {
20213
20653
  const compiledHtml = assignCounters(rawHtml, renderedNodes);
20214
20654
  const cleanedHtml = options.mode === "extraction" ? cleanForExtraction(compiledHtml.html) : cleanForAction(compiledHtml.html);
20215
20655
  const filtered = retainVisibleCounterRecords(cleanedHtml, compiledHtml.counterRecords);
20656
+ const dense = renumberCountersDensely(cleanedHtml, filtered);
20657
+ if (liveCountersEnabled && dense.sparseToDirectMapping.size > 0) {
20658
+ try {
20659
+ await syncDenseCountersToLiveDom(
20660
+ options.engine,
20661
+ options.pageRef,
20662
+ dense.sparseToDirectMapping
20663
+ );
20664
+ } catch {
20665
+ }
20666
+ }
20216
20667
  return {
20217
20668
  url: pageInfo.url,
20218
20669
  title: pageInfo.title,
20219
20670
  mode: options.mode,
20220
- html: cleanedHtml,
20221
- counters: [...filtered.values()].map(toPublicCounterRecord),
20222
- counterRecords: filtered
20671
+ html: dense.html,
20672
+ counters: [...dense.counterRecords.values()].map(toPublicCounterRecord),
20673
+ counterRecords: dense.counterRecords
20223
20674
  };
20224
20675
  }
20225
20676
  async function getMainDocumentSnapshot(engine, pageRef) {
@@ -20448,6 +20899,9 @@ function assignCounters(rawHtml, renderedNodes) {
20448
20899
  if (!rendered) {
20449
20900
  return;
20450
20901
  }
20902
+ const rawSparseCounter = el.attr(OPENSTEER_SPARSE_COUNTER_ATTR);
20903
+ el.removeAttr(OPENSTEER_SPARSE_COUNTER_ATTR);
20904
+ const sparseCounter = rawSparseCounter ? Number.parseInt(rawSparseCounter, 10) : void 0;
20451
20905
  const counter = nextCounter++;
20452
20906
  el.attr("c", String(counter));
20453
20907
  counterRecords.set(counter, {
@@ -20465,7 +20919,8 @@ function assignCounters(rawHtml, renderedNodes) {
20465
20919
  shadowDepth: rendered.shadowDepth,
20466
20920
  interactive: rendered.interactive,
20467
20921
  locator: rendered.locator,
20468
- anchor: rendered.anchor
20922
+ anchor: rendered.anchor,
20923
+ ...sparseCounter !== void 0 && Number.isFinite(sparseCounter) ? { sparseCounter } : {}
20469
20924
  });
20470
20925
  });
20471
20926
  return {
@@ -20744,7 +21199,7 @@ async function beautifyScriptContent(content) {
20744
21199
  });
20745
21200
  }
20746
21201
 
20747
- // src/scripts/deobfuscate.ts
21202
+ // ../runtime-core/src/scripts/deobfuscate.ts
20748
21203
  async function deobfuscateScriptContent(input) {
20749
21204
  const webcrack = await loadWebcrack();
20750
21205
  const result = await webcrack(input.content, {
@@ -20802,7 +21257,7 @@ function inferTransforms(original, deobfuscated) {
20802
21257
  return [...inferred];
20803
21258
  }
20804
21259
 
20805
- // src/scripts/sandbox-shims/minimal.ts
21260
+ // ../runtime-core/src/scripts/sandbox-shims/minimal.ts
20806
21261
  function createMinimalSandboxGlobals(options) {
20807
21262
  return {
20808
21263
  console: options.console,
@@ -20826,7 +21281,7 @@ function createMinimalSandboxGlobals(options) {
20826
21281
  };
20827
21282
  }
20828
21283
 
20829
- // src/scripts/sandbox-shims/standard.ts
21284
+ // ../runtime-core/src/scripts/sandbox-shims/standard.ts
20830
21285
  function createStandardSandboxGlobals(options) {
20831
21286
  const globals = createMinimalSandboxGlobals(options);
20832
21287
  const eventApi = createEventTargetApi();
@@ -21097,7 +21552,7 @@ function normalizeErrorMessage(error) {
21097
21552
  return error instanceof Error ? error.message : String(error);
21098
21553
  }
21099
21554
 
21100
- // src/scripts/sandbox-shims/full.ts
21555
+ // ../runtime-core/src/scripts/sandbox-shims/full.ts
21101
21556
  function createFullSandboxGlobals(options) {
21102
21557
  const globals = createStandardSandboxGlobals(options);
21103
21558
  const eventListeners = /* @__PURE__ */ new WeakMap();
@@ -21217,7 +21672,7 @@ function createFullSandboxGlobals(options) {
21217
21672
  };
21218
21673
  }
21219
21674
 
21220
- // src/scripts/sandbox.ts
21675
+ // ../runtime-core/src/scripts/sandbox.ts
21221
21676
  async function runScriptSandbox(input) {
21222
21677
  const startedAt = Date.now();
21223
21678
  const errors = [];
@@ -21441,7 +21896,7 @@ function normalizeErrorMessage2(error) {
21441
21896
  return error instanceof Error ? error.message : String(error);
21442
21897
  }
21443
21898
 
21444
- // src/captcha/solver-capsolver.ts
21899
+ // ../runtime-core/src/captcha/solver-capsolver.ts
21445
21900
  var CAPSOLVER_CREATE_TASK_URL = "https://api.capsolver.com/createTask";
21446
21901
  var CAPSOLVER_GET_TASK_RESULT_URL = "https://api.capsolver.com/getTaskResult";
21447
21902
  function createCapSolver(apiKey) {
@@ -21539,7 +21994,7 @@ function sleep2(ms, signal) {
21539
21994
  });
21540
21995
  }
21541
21996
 
21542
- // src/captcha/solver-2captcha.ts
21997
+ // ../runtime-core/src/captcha/solver-2captcha.ts
21543
21998
  var TWO_CAPTCHA_CREATE_TASK_URL = "https://api.2captcha.com/createTask";
21544
21999
  var TWO_CAPTCHA_GET_TASK_RESULT_URL = "https://api.2captcha.com/getTaskResult";
21545
22000
  function createTwoCaptchaSolver(apiKey) {
@@ -21637,7 +22092,7 @@ function sleep3(ms, signal) {
21637
22092
  });
21638
22093
  }
21639
22094
 
21640
- // src/captcha/detect.ts
22095
+ // ../runtime-core/src/captcha/detect.ts
21641
22096
  var CAPTCHA_DETECTION_SCRIPT = `(() => {
21642
22097
  const pageUrl = location.href;
21643
22098
  const findSiteKey = (selectors) => {
@@ -21699,7 +22154,7 @@ async function detectCaptchaOnPage(engine, pageRef) {
21699
22154
  return candidate;
21700
22155
  }
21701
22156
 
21702
- // src/captcha/inject.ts
22157
+ // ../runtime-core/src/captcha/inject.ts
21703
22158
  async function injectCaptchaToken(input) {
21704
22159
  const result = await input.engine.evaluatePage({
21705
22160
  pageRef: input.pageRef,
@@ -21755,7 +22210,7 @@ var CAPTCHA_INJECTION_SCRIPT = `(({ type, token }) => {
21755
22210
  return true;
21756
22211
  })`;
21757
22212
 
21758
- // src/interaction/diff.ts
22213
+ // ../runtime-core/src/interaction/diff.ts
21759
22214
  function diffInteractionTraces(left, right) {
21760
22215
  const eventSequenceMismatches = [];
21761
22216
  const eventPropertyMismatches = [];
@@ -21824,20 +22279,19 @@ function diffInteractionTraces(left, right) {
21824
22279
  };
21825
22280
  }
21826
22281
 
21827
- // src/sdk/runtime.ts
22282
+ // ../runtime-core/src/sdk/runtime.ts
21828
22283
  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 {
22284
+ var OpensteerSessionRuntime = class {
21830
22285
  workspace;
21831
22286
  rootPath;
21832
- publicWorkspace;
21833
- configuredBrowser;
21834
- configuredLaunch;
21835
- configuredContext;
21836
- configuredEngineName;
22287
+ workspaceName;
21837
22288
  injectedEngine;
21838
22289
  engineFactory;
21839
22290
  policy;
22291
+ injectedDescriptorStore;
22292
+ registryOverrides;
21840
22293
  cleanupRootOnClose;
22294
+ sessionInfoBase;
21841
22295
  root;
21842
22296
  engine;
21843
22297
  dom;
@@ -21852,39 +22306,52 @@ var OpensteerRuntime = class {
21852
22306
  cookieJars = /* @__PURE__ */ new Map();
21853
22307
  recipeCache = /* @__PURE__ */ new Map();
21854
22308
  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;
22309
+ constructor(options) {
22310
+ this.workspace = normalizeNamespace2(options.name);
22311
+ this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
22312
+ this.root = options.workspace;
22313
+ this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6__default.default.resolve(process.cwd(), ".opensteer", "temporary", crypto.randomUUID());
21868
22314
  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
- });
22315
+ this.engineFactory = options.engineFactory;
21882
22316
  this.policy = options.policy ?? defaultPolicy();
21883
- this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.publicWorkspace === void 0;
22317
+ this.injectedDescriptorStore = options.descriptorStore;
22318
+ this.registryOverrides = options.registryOverrides;
22319
+ this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
22320
+ this.sessionInfoBase = options.sessionInfo ?? {};
22321
+ if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
22322
+ throw new Error("OpensteerSessionRuntime requires an engine or engineFactory.");
22323
+ }
22324
+ }
22325
+ async info() {
22326
+ const base = this.sessionInfoBase;
22327
+ return {
22328
+ provider: base.provider ?? {
22329
+ kind: "local",
22330
+ ownership: "owned",
22331
+ engine: "playwright"
22332
+ },
22333
+ ...base.workspace === void 0 ? {} : { workspace: base.workspace },
22334
+ ...this.sessionRef === void 0 ? {} : { sessionId: this.sessionRef },
22335
+ ...this.pageRef === void 0 ? {} : { activePageRef: this.pageRef },
22336
+ reconnectable: base.reconnectable ?? !this.cleanupRootOnClose,
22337
+ capabilities: base.capabilities ?? {
22338
+ semanticOperations: opensteerSemanticOperationNames,
22339
+ instrumentation: {
22340
+ route: true,
22341
+ interceptScript: true,
22342
+ networkStream: false
22343
+ }
22344
+ },
22345
+ ...base.grants === void 0 ? {} : { grants: base.grants },
22346
+ runtime: base.runtime ?? {
22347
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
22348
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
22349
+ }
22350
+ };
21884
22351
  }
21885
22352
  async open(input = {}, options = {}) {
21886
22353
  assertValidSemanticOperationInput("session.open", input);
21887
- if (input.workspace !== void 0 && normalizeNamespace3(input.workspace) !== this.workspace) {
22354
+ if (input.workspace !== void 0 && normalizeNamespace2(input.workspace) !== this.workspace) {
21888
22355
  throw new Error(
21889
22356
  `session.open requested workspace "${input.workspace}" but runtime is bound to "${this.workspace}"`
21890
22357
  );
@@ -24300,8 +24767,7 @@ var OpensteerRuntime = class {
24300
24767
  const inferred = inferRequestPlanFromNetworkRecord(record, {
24301
24768
  recordId: candidate.recordId,
24302
24769
  key: input.key,
24303
- version: input.version,
24304
- lifecycle: "draft"
24770
+ version: input.version
24305
24771
  });
24306
24772
  const defaultHeaders = inferred.payload.endpoint.defaultHeaders === void 0 ? void 0 : stripManagedRequestHeaders(
24307
24773
  inferred.payload.endpoint.defaultHeaders,
@@ -24929,8 +25395,7 @@ var OpensteerRuntime = class {
24929
25395
  recordId: input.recordId,
24930
25396
  id: record.id,
24931
25397
  key: record.key,
24932
- version: record.version,
24933
- lifecycle: record.lifecycle
25398
+ version: record.version
24934
25399
  }
24935
25400
  });
24936
25401
  return record;
@@ -24971,8 +25436,7 @@ var OpensteerRuntime = class {
24971
25436
  data: {
24972
25437
  id: record.id,
24973
25438
  key: record.key,
24974
- version: record.version,
24975
- lifecycle: record.lifecycle
25439
+ version: record.version
24976
25440
  }
24977
25441
  });
24978
25442
  return record;
@@ -25018,8 +25482,7 @@ var OpensteerRuntime = class {
25018
25482
  data: {
25019
25483
  id: record.id,
25020
25484
  key: record.key,
25021
- version: record.version,
25022
- lifecycle: record.lifecycle
25485
+ version: record.version
25023
25486
  }
25024
25487
  });
25025
25488
  return record;
@@ -25890,18 +26353,12 @@ var OpensteerRuntime = class {
25890
26353
  }
25891
26354
  if (target.kind === "element") {
25892
26355
  const counter = this.latestSnapshot?.counterRecords.get(target.element);
25893
- if (!counter) {
25894
- throw new Error(`no counter ${String(target.element)} is available in the latest snapshot`);
25895
- }
26356
+ const elementTarget = counter ? { kind: "live", locator: counter.locator, anchor: counter.anchor } : { kind: "selector", selector: `[c="${String(target.element)}"]` };
25896
26357
  const resolved2 = await timeout.runStep(
25897
26358
  () => this.requireDom().resolveTarget({
25898
26359
  pageRef,
25899
26360
  method,
25900
- target: {
25901
- kind: "live",
25902
- locator: counter.locator,
25903
- anchor: counter.anchor
25904
- }
26361
+ target: elementTarget
25905
26362
  })
25906
26363
  );
25907
26364
  const stablePath2 = resolved2.replayPath ?? await timeout.runStep(
@@ -26251,14 +26708,14 @@ var OpensteerRuntime = class {
26251
26708
  return saved;
26252
26709
  }
26253
26710
  resolveCurrentStateSource() {
26254
- const browser = this.configuredBrowser;
26255
- if (browser === void 0 || browser === "temporary") {
26256
- return "temporary";
26711
+ const ownership = this.sessionInfoBase.provider?.ownership;
26712
+ if (ownership === "attached") {
26713
+ return "attach";
26257
26714
  }
26258
- if (browser === "persistent") {
26715
+ if (this.workspaceName !== void 0 || this.cleanupRootOnClose === false) {
26259
26716
  return "persistent";
26260
26717
  }
26261
- return "attach";
26718
+ return "temporary";
26262
26719
  }
26263
26720
  async resolveReverseCaseById(caseId) {
26264
26721
  const record = await (await this.ensureRoot()).registry.reverseCases.getById(caseId);
@@ -27144,7 +27601,7 @@ var OpensteerRuntime = class {
27144
27601
  }
27145
27602
  async touchRequestPlanFreshness(plan) {
27146
27603
  const freshness = touchFreshness(plan.freshness);
27147
- await this.requireRoot().registry.requestPlans.updateMetadata({
27604
+ await this.requireRoot().registry.requestPlans.updateFreshness({
27148
27605
  id: plan.id,
27149
27606
  ...freshness === void 0 ? {} : { freshness }
27150
27607
  });
@@ -27813,21 +28270,40 @@ var OpensteerRuntime = class {
27813
28270
  };
27814
28271
  }
27815
28272
  const counter = this.latestSnapshot?.counterRecords.get(target.element);
27816
- if (!counter) {
27817
- throw new Error(`no counter ${String(target.element)} is available in the latest snapshot`);
28273
+ if (counter) {
28274
+ return {
28275
+ kind: "live",
28276
+ locator: counter.locator,
28277
+ anchor: counter.anchor
28278
+ };
27818
28279
  }
27819
28280
  return {
27820
- kind: "live",
27821
- locator: counter.locator,
27822
- anchor: counter.anchor
28281
+ kind: "selector",
28282
+ selector: `[c="${String(target.element)}"]`
27823
28283
  };
27824
28284
  }
27825
28285
  async ensureRoot() {
27826
- this.root ??= await createFilesystemOpensteerWorkspace({
27827
- rootPath: this.rootPath,
27828
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
27829
- scope: this.publicWorkspace === void 0 ? "temporary" : "workspace"
27830
- });
28286
+ if (!this.root) {
28287
+ const workspace = await createFilesystemOpensteerWorkspace({
28288
+ rootPath: this.rootPath,
28289
+ ...this.workspaceName === void 0 ? {} : { workspace: this.workspaceName },
28290
+ scope: this.workspaceName === void 0 ? "temporary" : "workspace"
28291
+ });
28292
+ if (this.registryOverrides) {
28293
+ const overrides = this.registryOverrides;
28294
+ this.root = {
28295
+ ...workspace,
28296
+ registry: {
28297
+ ...workspace.registry,
28298
+ ...overrides.requestPlans === void 0 ? {} : { requestPlans: overrides.requestPlans },
28299
+ ...overrides.authRecipes === void 0 ? {} : { authRecipes: overrides.authRecipes },
28300
+ ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes }
28301
+ }
28302
+ };
28303
+ } else {
28304
+ this.root = workspace;
28305
+ }
28306
+ }
27831
28307
  return this.root;
27832
28308
  }
27833
28309
  async ensureEngine(overrides = {}) {
@@ -27839,15 +28315,10 @@ var OpensteerRuntime = class {
27839
28315
  this.ownsEngine = false;
27840
28316
  return this.engine;
27841
28317
  }
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);
28318
+ if (this.engineFactory === void 0) {
28319
+ throw new Error("Opensteer engine factory is not initialized");
28320
+ }
28321
+ this.engine = await this.engineFactory(overrides);
27851
28322
  this.ownsEngine = true;
27852
28323
  return this.engine;
27853
28324
  }
@@ -27858,6 +28329,7 @@ var OpensteerRuntime = class {
27858
28329
  engine,
27859
28330
  root,
27860
28331
  namespace: this.workspace,
28332
+ ...this.injectedDescriptorStore === void 0 ? {} : { descriptorStore: this.injectedDescriptorStore },
27861
28333
  policy: this.policy
27862
28334
  });
27863
28335
  this.computer = createComputerUseRuntime({
@@ -28304,6 +28776,9 @@ function parseContentType2(contentType) {
28304
28776
  };
28305
28777
  }
28306
28778
  function toJsonValueOrNull(value) {
28779
+ if (value === void 0) {
28780
+ return null;
28781
+ }
28307
28782
  return toCanonicalJsonValue(value) ?? null;
28308
28783
  }
28309
28784
  function stringifyRecipeVariableValue(value) {
@@ -28441,7 +28916,6 @@ function buildMinimizedRequestPlan(input) {
28441
28916
  sourceId: input.record.recordId,
28442
28917
  ...input.record.source === "saved" && input.record.savedAt !== void 0 ? { capturedAt: input.record.savedAt } : {}
28443
28918
  },
28444
- lifecycle: "draft",
28445
28919
  payload: normalizeRequestPlanPayload({
28446
28920
  transport: {
28447
28921
  kind: input.transport
@@ -29101,12 +29575,12 @@ function extractReverseRuntimeValue(value, pointer) {
29101
29575
  }
29102
29576
  return readDotPath(value, pointer);
29103
29577
  }
29104
- function readDotPath(value, path11) {
29105
- if (path11.length === 0) {
29578
+ function readDotPath(value, path13) {
29579
+ if (path13.length === 0) {
29106
29580
  return value;
29107
29581
  }
29108
29582
  let current = value;
29109
- for (const segment of path11.split(".").filter((entry) => entry.length > 0)) {
29583
+ for (const segment of path13.split(".").filter((entry) => entry.length > 0)) {
29110
29584
  if (current === null || current === void 0) {
29111
29585
  return void 0;
29112
29586
  }
@@ -29579,7 +30053,7 @@ function parseSetCookieHeader(value, requestUrl) {
29579
30053
  }
29580
30054
  const url = new URL(requestUrl);
29581
30055
  let domain = url.hostname;
29582
- let path11 = defaultCookiePath(url.pathname);
30056
+ let path13 = defaultCookiePath(url.pathname);
29583
30057
  let secure = url.protocol === "https:";
29584
30058
  let expiresAt;
29585
30059
  const cookieValue = rawValueParts.join("=").trim();
@@ -29592,7 +30066,7 @@ function parseSetCookieHeader(value, requestUrl) {
29592
30066
  continue;
29593
30067
  }
29594
30068
  if (key === "path" && attributeValue.length > 0) {
29595
- path11 = attributeValue;
30069
+ path13 = attributeValue;
29596
30070
  continue;
29597
30071
  }
29598
30072
  if (key === "secure") {
@@ -29618,7 +30092,7 @@ function parseSetCookieHeader(value, requestUrl) {
29618
30092
  name,
29619
30093
  value: cookieValue,
29620
30094
  domain,
29621
- path: path11,
30095
+ path: path13,
29622
30096
  secure,
29623
30097
  ...expiresAt === void 0 ? {} : { expiresAt }
29624
30098
  }
@@ -30596,7 +31070,7 @@ function directionToDelta(direction, amount) {
30596
31070
  return { x: amount, y: 0 };
30597
31071
  }
30598
31072
  }
30599
- function normalizeNamespace3(value) {
31073
+ function normalizeNamespace2(value) {
30600
31074
  const normalized = String(value ?? "default").trim();
30601
31075
  return normalized.length === 0 ? "default" : normalized;
30602
31076
  }
@@ -30642,45 +31116,145 @@ function screenshotMediaType(format2) {
30642
31116
  }
30643
31117
  }
30644
31118
 
30645
- // src/mode/config.ts
30646
- var OPENSTEER_EXECUTION_MODES = ["local", "cloud"];
30647
- function assertExecutionModeSupportsEngine(mode, engine) {
31119
+ // src/sdk/runtime.ts
31120
+ var OpensteerRuntime = class extends OpensteerSessionRuntime {
31121
+ constructor(options = {}) {
31122
+ const publicWorkspace = normalizeWorkspace2(options.workspace);
31123
+ const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path6__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : resolveFilesystemWorkspacePath({
31124
+ rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
31125
+ workspace: publicWorkspace
31126
+ }));
31127
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? publicWorkspace === void 0;
31128
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31129
+ assertSupportedEngineOptions({
31130
+ engineName,
31131
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31132
+ ...options.context === void 0 ? {} : { context: options.context }
31133
+ });
31134
+ super(
31135
+ buildSharedRuntimeOptions({
31136
+ name: publicWorkspace ?? "default",
31137
+ rootPath,
31138
+ ...publicWorkspace === void 0 ? {} : { workspaceName: publicWorkspace },
31139
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31140
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31141
+ ...options.context === void 0 ? {} : { context: options.context },
31142
+ engineName,
31143
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31144
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31145
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31146
+ ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31147
+ cleanupRootOnClose
31148
+ })
31149
+ );
31150
+ }
31151
+ };
31152
+ var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31153
+ constructor(options) {
31154
+ const rootPath = options.rootPath ?? path6__default.default.resolve(options.rootDir ?? process.cwd());
31155
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? false;
31156
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31157
+ assertSupportedEngineOptions({
31158
+ engineName,
31159
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31160
+ ...options.context === void 0 ? {} : { context: options.context }
31161
+ });
31162
+ super(
31163
+ buildSharedRuntimeOptions({
31164
+ name: options.name,
31165
+ rootPath,
31166
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31167
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31168
+ ...options.context === void 0 ? {} : { context: options.context },
31169
+ engineName,
31170
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31171
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31172
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31173
+ ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31174
+ cleanupRootOnClose
31175
+ })
31176
+ );
31177
+ }
31178
+ };
31179
+ function buildSharedRuntimeOptions(input) {
31180
+ const ownership = resolveOwnership(input.browser);
31181
+ const engineFactory = input.engineFactory ?? ((factoryOptions) => new OpensteerBrowserManager({
31182
+ rootPath: input.rootPath,
31183
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31184
+ engineName: input.engineName,
31185
+ ...(factoryOptions.browser ?? input.browser) === void 0 ? {} : { browser: factoryOptions.browser ?? input.browser },
31186
+ ...(factoryOptions.launch ?? input.launch) === void 0 ? {} : { launch: factoryOptions.launch ?? input.launch },
31187
+ ...(factoryOptions.context ?? input.context) === void 0 ? {} : { context: factoryOptions.context ?? input.context }
31188
+ }).createEngine());
31189
+ return {
31190
+ name: input.name,
31191
+ ...input.workspaceName === void 0 ? {} : { workspaceName: input.workspaceName },
31192
+ rootPath: input.rootPath,
31193
+ ...input.engine === void 0 ? {} : { engine: input.engine },
31194
+ ...input.engine === void 0 ? { engineFactory } : {},
31195
+ ...input.policy === void 0 ? {} : { policy: input.policy },
31196
+ ...input.descriptorStore === void 0 ? {} : { descriptorStore: input.descriptorStore },
31197
+ cleanupRootOnClose: input.cleanupRootOnClose,
31198
+ sessionInfo: {
31199
+ provider: {
31200
+ kind: "local",
31201
+ ownership,
31202
+ engine: input.engineName
31203
+ },
31204
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31205
+ reconnectable: !input.cleanupRootOnClose
31206
+ }
31207
+ };
31208
+ }
31209
+ function normalizeWorkspace2(workspace) {
31210
+ if (workspace === void 0) {
31211
+ return void 0;
31212
+ }
31213
+ const trimmed = workspace.trim();
31214
+ return trimmed.length === 0 ? void 0 : trimmed;
31215
+ }
31216
+ function resolveOwnership(browser) {
31217
+ return typeof browser === "object" && browser.mode === "attach" ? "attached" : "owned";
31218
+ }
31219
+
31220
+ // src/provider/config.ts
31221
+ var OPENSTEER_PROVIDER_KINDS = ["local", "cloud"];
31222
+ function assertProviderSupportsEngine(provider, engine) {
30648
31223
  if (engine !== "abp") {
30649
31224
  return;
30650
31225
  }
30651
- if (mode === "cloud") {
31226
+ if (provider === "cloud") {
30652
31227
  throw new Error(
30653
- "ABP is not supported in cloud mode. Cloud mode currently requires Playwright."
31228
+ "ABP is not supported for provider=cloud. Cloud provider currently requires Playwright."
30654
31229
  );
30655
31230
  }
30656
31231
  }
30657
- function normalizeOpensteerExecutionMode(value, source = "OPENSTEER_MODE") {
31232
+ function normalizeOpensteerProviderKind(value, source = "OPENSTEER_PROVIDER") {
30658
31233
  const normalized = value.trim().toLowerCase();
30659
- if (normalized === OPENSTEER_EXECUTION_MODES[0] || normalized === OPENSTEER_EXECUTION_MODES[1]) {
31234
+ if (normalized === OPENSTEER_PROVIDER_KINDS[0] || normalized === OPENSTEER_PROVIDER_KINDS[1]) {
30660
31235
  return normalized;
30661
31236
  }
30662
31237
  throw new Error(
30663
- `${source} must be one of ${OPENSTEER_EXECUTION_MODES.join(", ")}; received "${value}".`
31238
+ `${source} must be one of ${OPENSTEER_PROVIDER_KINDS.join(", ")}; received "${value}".`
30664
31239
  );
30665
31240
  }
30666
- function resolveOpensteerExecutionMode(input = {}) {
30667
- const explicitFlags = [input.local, input.cloud].filter(Boolean).length;
30668
- if (explicitFlags > 1) {
30669
- throw new Error("Choose exactly one execution mode: local or cloud.");
30670
- }
30671
- if (input.explicit) {
30672
- return input.explicit;
30673
- }
30674
- if (input.local) {
30675
- return "local";
30676
- }
30677
- if (input.cloud) {
30678
- return "cloud";
31241
+ function resolveOpensteerProvider(input = {}) {
31242
+ if (input.provider) {
31243
+ return {
31244
+ kind: input.provider.kind,
31245
+ source: "explicit"
31246
+ };
30679
31247
  }
30680
- if (input.environment !== void 0 && input.environment.trim().length > 0) {
30681
- return normalizeOpensteerExecutionMode(input.environment);
31248
+ if (input.environmentProvider !== void 0 && input.environmentProvider.trim().length > 0) {
31249
+ return {
31250
+ kind: normalizeOpensteerProviderKind(input.environmentProvider),
31251
+ source: "env"
31252
+ };
30682
31253
  }
30683
- return "local";
31254
+ return {
31255
+ kind: "local",
31256
+ source: "default"
31257
+ };
30684
31258
  }
30685
31259
  var execFile2 = util.promisify(child_process.execFile);
30686
31260
  var DEFAULT_CAPTURE_TIMEOUT_MS = 3e4;
@@ -31077,14 +31651,14 @@ function toPortableBrowserProfileCookieRecord(cookie) {
31077
31651
  if (!name || !domain) {
31078
31652
  return null;
31079
31653
  }
31080
- const path11 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31654
+ const path13 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31081
31655
  const expiresAt = typeof cookie.expires === "number" && Number.isFinite(cookie.expires) && cookie.expires > 0 ? Math.floor(cookie.expires * 1e3) : null;
31082
31656
  const sameSite = normalizeSameSite(cookie.sameSite);
31083
31657
  return {
31084
31658
  name,
31085
31659
  value: cookie.value,
31086
31660
  domain,
31087
- path: path11,
31661
+ path: path13,
31088
31662
  secure: cookie.secure,
31089
31663
  httpOnly: cookie.httpOnly,
31090
31664
  ...sameSite === void 0 ? {} : { sameSite },
@@ -31261,6 +31835,15 @@ var OpensteerCloudClient = class {
31261
31835
  });
31262
31836
  return await response.json();
31263
31837
  }
31838
+ async issueAccess(sessionId, capabilities) {
31839
+ const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}/access`, {
31840
+ method: "POST",
31841
+ body: {
31842
+ capabilities
31843
+ }
31844
+ });
31845
+ return await response.json();
31846
+ }
31264
31847
  async closeSession(sessionId) {
31265
31848
  const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
31266
31849
  method: "DELETE"
@@ -31316,6 +31899,34 @@ var OpensteerCloudClient = class {
31316
31899
  async syncBrowserProfileCookies(input) {
31317
31900
  return syncBrowserProfileCookies(this, input);
31318
31901
  }
31902
+ async importSelectorCache(entries) {
31903
+ const response = await this.request("/selector-cache/import", {
31904
+ method: "POST",
31905
+ body: { entries }
31906
+ });
31907
+ return await response.json();
31908
+ }
31909
+ async importRequestPlans(entries) {
31910
+ const response = await this.request("/registry/request-plans/import", {
31911
+ method: "POST",
31912
+ body: { entries }
31913
+ });
31914
+ return await response.json();
31915
+ }
31916
+ async importRecipes(entries) {
31917
+ const response = await this.request("/registry/recipes/import", {
31918
+ method: "POST",
31919
+ body: { entries }
31920
+ });
31921
+ return await response.json();
31922
+ }
31923
+ async importAuthRecipes(entries) {
31924
+ const response = await this.request("/registry/auth-recipes/import", {
31925
+ method: "POST",
31926
+ body: { entries }
31927
+ });
31928
+ return await response.json();
31929
+ }
31319
31930
  buildAuthorizationHeader() {
31320
31931
  return `Bearer ${this.config.apiKey}`;
31321
31932
  }
@@ -31386,22 +31997,26 @@ function wrapCloudFetchError(error, input) {
31386
31997
 
31387
31998
  // src/cloud/config.ts
31388
31999
  function resolveCloudConfig(input = {}) {
31389
- const mode = resolveOpensteerExecutionMode({
31390
- ...input.mode === void 0 ? {} : { explicit: input.mode },
31391
- ...input.enabled === void 0 ? {} : { cloud: input.enabled },
31392
- ...process.env.OPENSTEER_MODE === void 0 ? {} : { environment: process.env.OPENSTEER_MODE }
32000
+ const provider = resolveOpensteerProvider({
32001
+ ...input.provider === void 0 ? {} : { provider: input.provider },
32002
+ ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
31393
32003
  });
31394
- if (mode !== "cloud") {
32004
+ if (provider.kind !== "cloud") {
31395
32005
  return void 0;
31396
32006
  }
31397
- const apiKey = input.apiKey ?? process.env.OPENSTEER_API_KEY;
32007
+ const cloudProvider = input.provider?.kind === "cloud" ? input.provider : void 0;
32008
+ const apiKey = cloudProvider?.apiKey ?? process.env.OPENSTEER_API_KEY;
31398
32009
  if (!apiKey || apiKey.trim().length === 0) {
31399
- throw new Error("Cloud mode requires OPENSTEER_API_KEY or cloud.apiKey.");
32010
+ throw new Error("provider=cloud requires OPENSTEER_API_KEY or provider.apiKey.");
32011
+ }
32012
+ const baseUrl = cloudProvider?.baseUrl ?? process.env.OPENSTEER_BASE_URL;
32013
+ if (!baseUrl || baseUrl.trim().length === 0) {
32014
+ throw new Error("provider=cloud requires OPENSTEER_BASE_URL or provider.baseUrl.");
31400
32015
  }
31401
32016
  return {
31402
32017
  apiKey: apiKey.trim(),
31403
- baseUrl: (input.baseUrl ?? process.env.OPENSTEER_BASE_URL ?? "https://api.opensteer.dev").trim().replace(/\/+$/, ""),
31404
- ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile }
32018
+ baseUrl: baseUrl.trim().replace(/\/+$/, ""),
32019
+ ...cloudProvider?.browserProfile === void 0 ? {} : { browserProfile: cloudProvider.browserProfile }
31405
32020
  };
31406
32021
  }
31407
32022
  var OpensteerSemanticRestError = class extends Error {
@@ -31466,58 +32081,475 @@ function isFetchFailure(error) {
31466
32081
  }
31467
32082
  return error.name === "TypeError" || /fetch failed/i.test(error.message);
31468
32083
  }
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");
32084
+ var OpensteerCloudAutomationError = class extends Error {
32085
+ opensteerError;
32086
+ constructor(error) {
32087
+ super(error.message);
32088
+ this.name = "OpensteerCloudAutomationError";
32089
+ this.opensteerError = error;
32090
+ }
32091
+ };
32092
+ var OpensteerCloudAutomationClient = class {
32093
+ constructor(cloud, sessionId) {
32094
+ this.cloud = cloud;
32095
+ this.sessionId = sessionId;
32096
+ }
32097
+ socket;
32098
+ connectPromise;
32099
+ pending = /* @__PURE__ */ new Map();
32100
+ routes = /* @__PURE__ */ new Map();
32101
+ grant;
32102
+ async invoke(operation, input) {
32103
+ await this.ensureConnected();
32104
+ const requestId = `automation:${crypto.randomUUID()}`;
32105
+ const message = {
32106
+ protocol: OPENSTEER_PROTOCOL_NAME,
32107
+ version: OPENSTEER_PROTOCOL_VERSION,
32108
+ kind: "invoke",
32109
+ requestId,
32110
+ operation,
32111
+ sentAt: Date.now(),
32112
+ ...input === void 0 ? {} : { input }
32113
+ };
32114
+ return new Promise((resolve5, reject) => {
32115
+ this.pending.set(requestId, {
32116
+ resolve: (value) => resolve5(value),
32117
+ reject
32118
+ });
32119
+ try {
32120
+ this.requireSocket().send(JSON.stringify(message));
32121
+ } catch (error) {
32122
+ this.pending.delete(requestId);
32123
+ reject(error);
32124
+ }
32125
+ });
32126
+ }
32127
+ async getSessionInfo() {
32128
+ const result = await this.invoke("session.info", {});
32129
+ const sessionInfo = result;
32130
+ assertCompatibleRuntimeCoreVersion(sessionInfo);
32131
+ return sessionInfo;
32132
+ }
32133
+ async route(input) {
32134
+ const routeId = `route:${crypto.randomUUID()}`;
32135
+ const registration = await this.invoke("route.register", {
32136
+ routeId,
32137
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32138
+ urlPattern: input.urlPattern,
32139
+ ...input.resourceTypes === void 0 ? {} : { resourceTypes: input.resourceTypes },
32140
+ ...input.times === void 0 ? {} : { times: input.times },
32141
+ includeOriginal: true
32142
+ });
32143
+ this.routes.set(routeId, {
32144
+ kind: "route",
32145
+ routeId,
32146
+ input
32147
+ });
32148
+ return registration;
32149
+ }
32150
+ async interceptScript(input) {
32151
+ const routeId = `route:${crypto.randomUUID()}`;
32152
+ const registration = await this.invoke("route.register", {
32153
+ routeId,
32154
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32155
+ urlPattern: input.urlPattern,
32156
+ resourceTypes: ["script"],
32157
+ ...input.times === void 0 ? {} : { times: input.times },
32158
+ includeOriginal: true
32159
+ });
32160
+ this.routes.set(routeId, {
32161
+ kind: "intercept-script",
32162
+ routeId,
32163
+ input
32164
+ });
32165
+ return registration;
32166
+ }
32167
+ async close() {
32168
+ this.connectPromise = void 0;
32169
+ this.grant = void 0;
32170
+ if (!this.socket) {
32171
+ return;
32172
+ }
32173
+ const socket = this.socket;
32174
+ this.socket = void 0;
32175
+ for (const [requestId, pending] of this.pending) {
32176
+ pending.reject(new Error(`automation connection closed before ${requestId} completed`));
32177
+ }
32178
+ this.pending.clear();
32179
+ await new Promise((resolve5) => {
32180
+ socket.once("close", () => resolve5());
32181
+ socket.close();
32182
+ }).catch(() => void 0);
32183
+ }
32184
+ async ensureConnected() {
32185
+ if (this.socket?.readyState === WebSocket2__default.default.OPEN) {
32186
+ return;
32187
+ }
32188
+ if (this.connectPromise) {
32189
+ await this.connectPromise;
32190
+ return;
32191
+ }
32192
+ this.connectPromise = this.connect();
32193
+ try {
32194
+ await this.connectPromise;
32195
+ } finally {
32196
+ this.connectPromise = void 0;
32197
+ }
32198
+ }
32199
+ async connect() {
32200
+ const grant = await this.issueGrant("automation");
32201
+ const wsUrl = new URL(grant.wsUrl);
32202
+ wsUrl.searchParams.set("token", grant.token);
32203
+ const socket = new WebSocket2__default.default(wsUrl);
32204
+ this.socket = socket;
32205
+ socket.on("message", (data, isBinary) => {
32206
+ if (isBinary) {
32207
+ return;
32208
+ }
32209
+ this.handleMessage(data.toString());
32210
+ });
32211
+ socket.on("close", () => {
32212
+ if (this.socket === socket) {
32213
+ this.socket = void 0;
32214
+ }
32215
+ });
32216
+ socket.on("error", (error) => {
32217
+ for (const pending of this.pending.values()) {
32218
+ pending.reject(error);
32219
+ }
32220
+ this.pending.clear();
32221
+ });
32222
+ await new Promise((resolve5, reject) => {
32223
+ socket.once("open", () => resolve5());
32224
+ socket.once("error", reject);
32225
+ });
32226
+ this.send({
32227
+ protocol: OPENSTEER_PROTOCOL_NAME,
32228
+ version: OPENSTEER_PROTOCOL_VERSION,
32229
+ kind: "hello",
32230
+ sessionId: this.sessionId,
32231
+ grantKind: grant.kind
32232
+ });
32233
+ await this.restoreRoutes();
32234
+ }
32235
+ async restoreRoutes() {
32236
+ const stored = [...this.routes.values()];
32237
+ this.routes.clear();
32238
+ for (const registration of stored) {
32239
+ if (registration.kind === "route") {
32240
+ await this.route(registration.input);
32241
+ } else {
32242
+ await this.interceptScript(registration.input);
32243
+ }
32244
+ }
32245
+ }
32246
+ handleMessage(json) {
32247
+ const message = JSON.parse(json);
32248
+ if (message.protocol !== OPENSTEER_PROTOCOL_NAME) {
32249
+ return;
32250
+ }
32251
+ switch (message.kind) {
32252
+ case "result": {
32253
+ const pending = this.pending.get(message.requestId);
32254
+ if (!pending) {
32255
+ return;
32256
+ }
32257
+ this.pending.delete(message.requestId);
32258
+ pending.resolve(message.data);
32259
+ return;
32260
+ }
32261
+ case "error": {
32262
+ if (!message.requestId) {
32263
+ return;
32264
+ }
32265
+ const pending = this.pending.get(message.requestId);
32266
+ if (!pending) {
32267
+ return;
32268
+ }
32269
+ this.pending.delete(message.requestId);
32270
+ pending.reject(new OpensteerCloudAutomationError(message.error));
32271
+ return;
32272
+ }
32273
+ case "event":
32274
+ void this.handleEvent(message.event, message.data);
32275
+ return;
32276
+ case "pong":
32277
+ return;
32278
+ }
32279
+ }
32280
+ async handleEvent(event, payload) {
32281
+ if (event !== "route.request") {
32282
+ return;
32283
+ }
32284
+ const data = asRecord(payload);
32285
+ const request = asRecord(data.request);
32286
+ const original = asRecord(data.original);
32287
+ const routeId = typeof data.routeId === "string" ? data.routeId : "";
32288
+ const routeRequestId = typeof data.routeRequestId === "string" ? data.routeRequestId : "";
32289
+ if (!routeId || !routeRequestId) {
32290
+ return;
32291
+ }
32292
+ const registration = this.routes.get(routeId);
32293
+ if (!registration) {
32294
+ await this.invoke("route.resolve", {
32295
+ routeRequestId,
32296
+ decision: { kind: "continue" }
32297
+ }).catch(() => void 0);
32298
+ return;
32299
+ }
32300
+ try {
32301
+ const decision = registration.kind === "route" ? await registration.input.handler({
32302
+ request: toRouteRequest(request),
32303
+ fetchOriginal: async () => toFetchedRouteResponse(original)
32304
+ }) : {
32305
+ kind: "fulfill",
32306
+ body: await registration.input.handler({
32307
+ url: typeof request.url === "string" ? request.url : "",
32308
+ content: typeof original.body === "string" ? original.body : "",
32309
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32310
+ status: typeof original.status === "number" ? original.status : 200
32311
+ }),
32312
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32313
+ status: typeof original.status === "number" ? original.status : 200,
32314
+ contentType: findHeaderValue(
32315
+ Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32316
+ "content-type"
32317
+ ) ?? "application/javascript; charset=utf-8"
32318
+ };
32319
+ await this.invoke("route.resolve", {
32320
+ routeRequestId,
32321
+ decision: serializeRouteDecision(decision)
32322
+ }).catch(() => void 0);
32323
+ } catch {
32324
+ await this.invoke("route.resolve", {
32325
+ routeRequestId,
32326
+ decision: { kind: "continue" }
32327
+ }).catch(() => void 0);
32328
+ }
32329
+ }
32330
+ async issueGrant(kind) {
32331
+ if (this.grant && this.grant.kind === kind && this.grant.expiresAt > Date.now() + 1e4) {
32332
+ return this.grant;
32333
+ }
32334
+ const issued = await this.cloud.issueAccess(this.sessionId, [kind]);
32335
+ const grant = issued.grants[kind];
32336
+ if (!grant) {
32337
+ throw new OpensteerCloudAutomationError(
32338
+ createOpensteerError(
32339
+ "permission-denied",
32340
+ `cloud did not issue an ${kind} automation grant`
32341
+ )
32342
+ );
32343
+ }
32344
+ this.grant = grant;
32345
+ return grant;
32346
+ }
32347
+ requireSocket() {
32348
+ if (!this.socket || this.socket.readyState !== WebSocket2__default.default.OPEN) {
32349
+ throw new Error("cloud automation socket is not connected");
32350
+ }
32351
+ return this.socket;
32352
+ }
32353
+ send(message) {
32354
+ this.requireSocket().send(JSON.stringify(message));
32355
+ }
32356
+ };
32357
+ function assertCompatibleRuntimeCoreVersion(sessionInfo) {
32358
+ const runtimeCoreVersion = sessionInfo.runtime?.runtimeCoreVersion;
32359
+ if (runtimeCoreVersion === void 0) {
32360
+ return;
32361
+ }
32362
+ const expectedMajor = parseMajorVersion(OPENSTEER_RUNTIME_CORE_VERSION);
32363
+ const actualMajor = parseMajorVersion(runtimeCoreVersion);
32364
+ if (expectedMajor === null || actualMajor === null || expectedMajor === actualMajor) {
32365
+ return;
32366
+ }
32367
+ throw new Error(
32368
+ `cloud runtime-core major version ${runtimeCoreVersion} is incompatible with local SDK runtime-core ${OPENSTEER_RUNTIME_CORE_VERSION}`
32369
+ );
31497
32370
  }
31498
- async function readPersistedCloudSessionRecord(rootPath) {
31499
- const sessionPath = resolveCloudSessionRecordPath(rootPath);
31500
- if (!await pathExists(sessionPath)) {
31501
- return void 0;
32371
+ function parseMajorVersion(version) {
32372
+ const major = Number.parseInt(version.split(".", 1)[0] ?? "", 10);
32373
+ return Number.isFinite(major) ? major : null;
32374
+ }
32375
+ function serializeRouteDecision(decision) {
32376
+ if (decision.kind === "continue") {
32377
+ return { kind: "continue" };
31502
32378
  }
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)) {
32379
+ if (decision.kind === "abort") {
32380
+ return {
32381
+ kind: "abort",
32382
+ ...decision.errorCode === void 0 ? {} : { errorCode: decision.errorCode }
32383
+ };
32384
+ }
32385
+ return {
32386
+ kind: "fulfill",
32387
+ ...decision.status === void 0 ? {} : { status: decision.status },
32388
+ ...decision.headers === void 0 ? {} : { headers: decision.headers },
32389
+ ...decision.body === void 0 ? {} : typeof decision.body === "string" ? { body: decision.body } : { bodyBase64: Buffer.from(decision.body).toString("base64") },
32390
+ ...decision.contentType === void 0 ? {} : { contentType: decision.contentType }
32391
+ };
32392
+ }
32393
+ function toRouteRequest(record) {
32394
+ const pageRef = typeof record.pageRef === "string" ? record.pageRef : void 0;
32395
+ return {
32396
+ url: typeof record.url === "string" ? record.url : "",
32397
+ method: typeof record.method === "string" ? record.method : "GET",
32398
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32399
+ resourceType: typeof record.resourceType === "string" ? record.resourceType : "other",
32400
+ ...pageRef === void 0 ? {} : { pageRef },
32401
+ ...typeof record.postData === "string" ? {
32402
+ postData: {
32403
+ bytes: Uint8Array.from(Buffer.from(record.postData)),
32404
+ encoding: "identity",
32405
+ truncated: false,
32406
+ capturedByteLength: Buffer.byteLength(record.postData)
32407
+ }
32408
+ } : {}
32409
+ };
32410
+ }
32411
+ function toFetchedRouteResponse(record) {
32412
+ return {
32413
+ url: typeof record.url === "string" ? record.url : "",
32414
+ status: typeof record.status === "number" ? record.status : 200,
32415
+ statusText: typeof record.statusText === "string" ? record.statusText : "OK",
32416
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32417
+ ...typeof record.body === "string" ? {
32418
+ body: {
32419
+ bytes: Uint8Array.from(Buffer.from(record.body)),
32420
+ encoding: "identity",
32421
+ truncated: false,
32422
+ capturedByteLength: Buffer.byteLength(record.body)
32423
+ }
32424
+ } : {},
32425
+ redirected: Boolean(record.redirected)
32426
+ };
32427
+ }
32428
+ function findHeaderValue(headers, name) {
32429
+ return headers.find((header) => header.name.toLowerCase() === name)?.value;
32430
+ }
32431
+ function isHeaderEntry(value) {
32432
+ return value !== null && typeof value === "object" && typeof value.name === "string" && typeof value.value === "string";
32433
+ }
32434
+ function asRecord(value) {
32435
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
32436
+ return {};
32437
+ }
32438
+ return value;
32439
+ }
32440
+
32441
+ // src/cloud/registry-sync.ts
32442
+ var REGISTRY_SYNC_MAX_PAYLOAD_BYTES = 15e5;
32443
+ var REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH = 100;
32444
+ async function syncLocalRegistryToCloud(client, workspace, store) {
32445
+ const [descriptors, requestPlans, recipes, authRecipes] = await Promise.all([
32446
+ store.registry.descriptors.list(),
32447
+ store.registry.requestPlans.list(),
32448
+ store.registry.recipes.list(),
32449
+ store.registry.authRecipes.list()
32450
+ ]);
32451
+ const selectorEntries = descriptors.flatMap((record) => {
32452
+ const entry = toSelectorCacheImportEntry(workspace, record);
32453
+ return entry === void 0 ? [] : [entry];
32454
+ });
32455
+ await Promise.all([
32456
+ importInBatches(selectorEntries, (entries) => client.importSelectorCache(entries)),
32457
+ importInBatches(
32458
+ requestPlans.map((record) => toRequestPlanImportEntry(workspace, record)),
32459
+ (entries) => client.importRequestPlans(entries)
32460
+ ),
32461
+ importInBatches(
32462
+ recipes.map((record) => toRegistryImportEntry(workspace, record)),
32463
+ (entries) => client.importRecipes(entries)
32464
+ ),
32465
+ importInBatches(
32466
+ authRecipes.map((record) => toRegistryImportEntry(workspace, record)),
32467
+ (entries) => client.importAuthRecipes(entries)
32468
+ )
32469
+ ]);
32470
+ }
32471
+ function toSelectorCacheImportEntry(workspace, record) {
32472
+ const descriptor = parseDomDescriptorRecord(record);
32473
+ if (descriptor === void 0) {
31505
32474
  return void 0;
31506
32475
  }
31507
32476
  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
32477
+ workspace,
32478
+ method: descriptor.payload.method,
32479
+ descriptionHash: hashDomDescriptorDescription(descriptor.payload.description),
32480
+ description: descriptor.payload.description,
32481
+ path: descriptor.payload.path,
32482
+ createdAt: descriptor.createdAt,
32483
+ updatedAt: descriptor.updatedAt
32484
+ };
32485
+ }
32486
+ function toRegistryImportEntry(workspace, record) {
32487
+ return {
32488
+ workspace,
32489
+ recordId: record.id,
32490
+ key: record.key,
32491
+ version: record.version,
32492
+ contentHash: record.contentHash,
32493
+ tags: record.tags,
32494
+ ...record.provenance === void 0 ? {} : { provenance: record.provenance },
32495
+ payload: record.payload,
32496
+ createdAt: record.createdAt,
32497
+ updatedAt: record.updatedAt
31516
32498
  };
31517
32499
  }
31518
- async function hasPersistedCloudSession(rootPath) {
31519
- return await readPersistedCloudSessionRecord(rootPath) !== void 0;
32500
+ function toRequestPlanImportEntry(workspace, record) {
32501
+ return {
32502
+ workspace,
32503
+ recordId: record.id,
32504
+ key: record.key,
32505
+ version: record.version,
32506
+ contentHash: record.contentHash,
32507
+ tags: record.tags,
32508
+ ...record.provenance === void 0 ? {} : { provenance: record.provenance },
32509
+ payload: record.payload,
32510
+ ...record.freshness === void 0 ? {} : { freshness: record.freshness },
32511
+ createdAt: record.createdAt,
32512
+ updatedAt: record.updatedAt
32513
+ };
32514
+ }
32515
+ async function importInBatches(entries, importBatch) {
32516
+ if (entries.length === 0) {
32517
+ return;
32518
+ }
32519
+ for (const batch of chunkEntries(entries)) {
32520
+ await importBatch(batch);
32521
+ }
32522
+ }
32523
+ function chunkEntries(entries) {
32524
+ const batches = [];
32525
+ let currentBatch = [];
32526
+ for (const entry of entries) {
32527
+ if (payloadByteLength([entry]) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
32528
+ continue;
32529
+ }
32530
+ if (currentBatch.length === 0) {
32531
+ currentBatch = [entry];
32532
+ continue;
32533
+ }
32534
+ const nextBatch = [...currentBatch, entry];
32535
+ if (nextBatch.length > REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH || payloadByteLength(nextBatch) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
32536
+ batches.push(currentBatch);
32537
+ currentBatch = [entry];
32538
+ continue;
32539
+ }
32540
+ currentBatch = nextBatch;
32541
+ }
32542
+ if (currentBatch.length > 0) {
32543
+ batches.push(currentBatch);
32544
+ }
32545
+ return batches;
31520
32546
  }
32547
+ function payloadByteLength(entries) {
32548
+ return Buffer.byteLength(JSON.stringify({ entries }), "utf8");
32549
+ }
32550
+
32551
+ // src/cloud/session-proxy.ts
32552
+ var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31521
32553
  var CloudSessionProxy = class {
31522
32554
  rootPath;
31523
32555
  workspace;
@@ -31526,6 +32558,7 @@ var CloudSessionProxy = class {
31526
32558
  sessionId;
31527
32559
  sessionBaseUrl;
31528
32560
  client;
32561
+ automation;
31529
32562
  workspaceStore;
31530
32563
  constructor(cloud, options = {}) {
31531
32564
  this.cloud = cloud;
@@ -31546,27 +32579,73 @@ var CloudSessionProxy = class {
31546
32579
  ...input.url === void 0 ? {} : { url: input.url }
31547
32580
  });
31548
32581
  }
32582
+ async info() {
32583
+ const persisted = this.client !== void 0 || this.sessionId !== void 0 ? void 0 : await this.loadPersistedSession();
32584
+ if (this.client === void 0 && this.sessionId === void 0 && persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
32585
+ this.bindClient(persisted);
32586
+ }
32587
+ if (this.automation) {
32588
+ try {
32589
+ const sessionInfo = await this.automation.getSessionInfo();
32590
+ return {
32591
+ ...sessionInfo,
32592
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace }
32593
+ };
32594
+ } catch {
32595
+ }
32596
+ }
32597
+ return {
32598
+ provider: {
32599
+ kind: "cloud",
32600
+ ownership: "managed",
32601
+ engine: "playwright",
32602
+ baseUrl: this.cloud.getConfig().baseUrl
32603
+ },
32604
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace },
32605
+ ...this.sessionId === void 0 ? persisted?.sessionId === void 0 ? {} : { sessionId: persisted.sessionId } : { sessionId: this.sessionId },
32606
+ reconnectable: this.workspace !== void 0 || this.sessionId !== void 0 || persisted !== void 0,
32607
+ capabilities: {
32608
+ semanticOperations: opensteerSemanticOperationNames,
32609
+ sessionGrants: ["automation", "view", "cdp"],
32610
+ instrumentation: {
32611
+ route: true,
32612
+ interceptScript: true,
32613
+ networkStream: true
32614
+ }
32615
+ },
32616
+ runtime: {
32617
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
32618
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
32619
+ }
32620
+ };
32621
+ }
31549
32622
  async listPages(input = {}) {
31550
- throw unsupportedCloudOperation("page.list");
32623
+ await this.ensureSession();
32624
+ return this.requireClient().invoke("page.list", input);
31551
32625
  }
31552
32626
  async newPage(input = {}) {
31553
- throw unsupportedCloudOperation("page.new");
32627
+ await this.ensureSession();
32628
+ return this.requireAutomation().invoke("page.new", input);
31554
32629
  }
31555
32630
  async activatePage(input) {
31556
- throw unsupportedCloudOperation("page.activate");
32631
+ await this.ensureSession();
32632
+ return this.requireClient().invoke("page.activate", input);
31557
32633
  }
31558
32634
  async closePage(input = {}) {
31559
- throw unsupportedCloudOperation("page.close");
32635
+ await this.ensureSession();
32636
+ return this.requireClient().invoke("page.close", input);
31560
32637
  }
31561
32638
  async goto(input) {
31562
32639
  await this.ensureSession();
31563
32640
  return this.requireClient().invoke("page.goto", input);
31564
32641
  }
31565
32642
  async evaluate(input) {
31566
- throw unsupportedCloudOperation("page.evaluate");
32643
+ await this.ensureSession();
32644
+ return this.requireAutomation().invoke("page.evaluate", input);
31567
32645
  }
31568
32646
  async addInitScript(input) {
31569
- throw unsupportedCloudOperation("page.add-init-script");
32647
+ await this.ensureSession();
32648
+ return this.requireClient().invoke("page.add-init-script", input);
31570
32649
  }
31571
32650
  async snapshot(input = {}) {
31572
32651
  await this.ensureSession();
@@ -31601,80 +32680,112 @@ var CloudSessionProxy = class {
31601
32680
  return this.requireClient().invoke("network.save", input);
31602
32681
  }
31603
32682
  async minimizeNetwork(input) {
31604
- throw unsupportedCloudOperation("network.minimize");
32683
+ await this.ensureSession();
32684
+ return this.requireClient().invoke("network.minimize", input);
31605
32685
  }
31606
32686
  async diffNetwork(input) {
31607
- throw unsupportedCloudOperation("network.diff");
32687
+ await this.ensureSession();
32688
+ return this.requireClient().invoke("network.diff", input);
31608
32689
  }
31609
32690
  async probeNetwork(input) {
31610
- throw unsupportedCloudOperation("network.probe");
32691
+ await this.ensureSession();
32692
+ return this.requireClient().invoke("network.probe", input);
31611
32693
  }
31612
32694
  async discoverReverse(input) {
31613
- throw unsupportedCloudOperation("reverse.discover");
32695
+ await this.ensureSession();
32696
+ return this.requireClient().invoke("reverse.discover", input);
31614
32697
  }
31615
32698
  async queryReverse(input) {
31616
- throw unsupportedCloudOperation("reverse.query");
32699
+ await this.ensureSession();
32700
+ return this.requireClient().invoke("reverse.query", input);
31617
32701
  }
31618
32702
  async createReversePackage(input) {
31619
- throw unsupportedCloudOperation("reverse.package.create");
32703
+ await this.ensureSession();
32704
+ return this.requireClient().invoke("reverse.package.create", input);
31620
32705
  }
31621
32706
  async runReversePackage(input) {
31622
- throw unsupportedCloudOperation("reverse.package.run");
32707
+ await this.ensureSession();
32708
+ return this.requireClient().invoke("reverse.package.run", input);
31623
32709
  }
31624
32710
  async exportReverse(input) {
31625
- throw unsupportedCloudOperation("reverse.export");
32711
+ await this.ensureSession();
32712
+ return this.requireClient().invoke("reverse.export", input);
31626
32713
  }
31627
32714
  async getReverseReport(input) {
31628
- throw unsupportedCloudOperation("reverse.report");
32715
+ await this.ensureSession();
32716
+ return this.requireClient().invoke("reverse.report", input);
31629
32717
  }
31630
32718
  async getReversePackage(input) {
31631
- throw unsupportedCloudOperation("reverse.package.get");
32719
+ await this.ensureSession();
32720
+ return this.requireClient().invoke("reverse.package.get", input);
31632
32721
  }
31633
32722
  async listReversePackages(input = {}) {
31634
- throw unsupportedCloudOperation("reverse.package.list");
32723
+ await this.ensureSession();
32724
+ return this.requireClient().invoke("reverse.package.list", input);
31635
32725
  }
31636
32726
  async patchReversePackage(input) {
31637
- throw unsupportedCloudOperation("reverse.package.patch");
32727
+ await this.ensureSession();
32728
+ return this.requireClient().invoke("reverse.package.patch", input);
31638
32729
  }
31639
32730
  async captureInteraction(input) {
31640
- throw unsupportedCloudOperation("interaction.capture");
32731
+ await this.ensureSession();
32732
+ return this.requireClient().invoke("interaction.capture", input);
31641
32733
  }
31642
32734
  async getInteraction(input) {
31643
- throw unsupportedCloudOperation("interaction.get");
32735
+ await this.ensureSession();
32736
+ return this.requireClient().invoke("interaction.get", input);
31644
32737
  }
31645
32738
  async diffInteraction(input) {
31646
- throw unsupportedCloudOperation("interaction.diff");
32739
+ await this.ensureSession();
32740
+ return this.requireClient().invoke("interaction.diff", input);
31647
32741
  }
31648
32742
  async replayInteraction(input) {
31649
- throw unsupportedCloudOperation("interaction.replay");
32743
+ await this.ensureSession();
32744
+ return this.requireClient().invoke("interaction.replay", input);
31650
32745
  }
31651
32746
  async clearNetwork(input = {}) {
31652
32747
  await this.ensureSession();
31653
32748
  return this.requireClient().invoke("network.clear", input);
31654
32749
  }
31655
32750
  async captureScripts(input = {}) {
31656
- throw unsupportedCloudOperation("scripts.capture");
32751
+ await this.ensureSession();
32752
+ return this.requireClient().invoke("scripts.capture", input);
31657
32753
  }
31658
32754
  async readArtifact(input) {
31659
- throw unsupportedCloudOperation("artifact.read");
32755
+ await this.ensureSession();
32756
+ return this.requireClient().invoke("artifact.read", input);
31660
32757
  }
31661
32758
  async beautifyScript(input) {
31662
- throw unsupportedCloudOperation("scripts.beautify");
32759
+ await this.ensureSession();
32760
+ return this.requireClient().invoke("scripts.beautify", input);
31663
32761
  }
31664
32762
  async deobfuscateScript(input) {
31665
- throw unsupportedCloudOperation("scripts.deobfuscate");
32763
+ await this.ensureSession();
32764
+ return this.requireClient().invoke("scripts.deobfuscate", input);
31666
32765
  }
31667
32766
  async sandboxScript(input) {
31668
- throw unsupportedCloudOperation("scripts.sandbox");
32767
+ await this.ensureSession();
32768
+ return this.requireClient().invoke("scripts.sandbox", input);
31669
32769
  }
31670
32770
  async solveCaptcha(input) {
31671
- throw unsupportedCloudOperation("captcha.solve");
32771
+ await this.ensureSession();
32772
+ return this.requireClient().invoke("captcha.solve", input);
31672
32773
  }
31673
32774
  async getCookies(input = {}) {
31674
- throw unsupportedCloudOperation("inspect.cookies");
32775
+ await this.ensureSession();
32776
+ return this.requireAutomation().invoke("inspect.cookies", input);
32777
+ }
32778
+ async route(input) {
32779
+ await this.ensureSession();
32780
+ return this.requireAutomation().route(input);
32781
+ }
32782
+ async interceptScript(input) {
32783
+ await this.ensureSession();
32784
+ return this.requireAutomation().interceptScript(input);
31675
32785
  }
31676
32786
  async getStorageSnapshot(input = {}) {
31677
- throw unsupportedCloudOperation("inspect.storage");
32787
+ await this.ensureSession();
32788
+ return this.requireClient().invoke("inspect.storage", input);
31678
32789
  }
31679
32790
  async rawRequest(input) {
31680
32791
  await this.ensureSession();
@@ -31697,28 +32808,36 @@ var CloudSessionProxy = class {
31697
32808
  return this.requireClient().invoke("request-plan.list", input);
31698
32809
  }
31699
32810
  async writeAuthRecipe(input) {
31700
- throw unsupportedCloudOperation("auth-recipe.write");
32811
+ await this.ensureSession();
32812
+ return this.requireClient().invoke("auth-recipe.write", input);
31701
32813
  }
31702
32814
  async writeRecipe(input) {
31703
- throw unsupportedCloudOperation("recipe.write");
32815
+ await this.ensureSession();
32816
+ return this.requireClient().invoke("recipe.write", input);
31704
32817
  }
31705
32818
  async getAuthRecipe(input) {
31706
- throw unsupportedCloudOperation("auth-recipe.get");
32819
+ await this.ensureSession();
32820
+ return this.requireClient().invoke("auth-recipe.get", input);
31707
32821
  }
31708
32822
  async getRecipe(input) {
31709
- throw unsupportedCloudOperation("recipe.get");
32823
+ await this.ensureSession();
32824
+ return this.requireClient().invoke("recipe.get", input);
31710
32825
  }
31711
32826
  async listAuthRecipes(input = {}) {
31712
- throw unsupportedCloudOperation("auth-recipe.list");
32827
+ await this.ensureSession();
32828
+ return this.requireClient().invoke("auth-recipe.list", input);
31713
32829
  }
31714
32830
  async listRecipes(input = {}) {
31715
- throw unsupportedCloudOperation("recipe.list");
32831
+ await this.ensureSession();
32832
+ return this.requireClient().invoke("recipe.list", input);
31716
32833
  }
31717
32834
  async runAuthRecipe(input) {
31718
- throw unsupportedCloudOperation("auth-recipe.run");
32835
+ await this.ensureSession();
32836
+ return this.requireClient().invoke("auth-recipe.run", input);
31719
32837
  }
31720
32838
  async runRecipe(input) {
31721
- throw unsupportedCloudOperation("recipe.run");
32839
+ await this.ensureSession();
32840
+ return this.requireClient().invoke("recipe.run", input);
31722
32841
  }
31723
32842
  async request(input) {
31724
32843
  await this.ensureSession();
@@ -31730,9 +32849,9 @@ var CloudSessionProxy = class {
31730
32849
  }
31731
32850
  async close() {
31732
32851
  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,
31735
- mode: "cloud",
32852
+ layout: "opensteer-session",
32853
+ version: 1,
32854
+ provider: "cloud",
31736
32855
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31737
32856
  sessionId: this.sessionId,
31738
32857
  baseUrl: this.sessionBaseUrl,
@@ -31749,7 +32868,9 @@ var CloudSessionProxy = class {
31749
32868
  });
31750
32869
  }
31751
32870
  } finally {
32871
+ await this.automation?.close().catch(() => void 0);
31752
32872
  await this.clearPersistedSession();
32873
+ this.automation = void 0;
31753
32874
  this.client = void 0;
31754
32875
  this.sessionId = void 0;
31755
32876
  this.sessionBaseUrl = void 0;
@@ -31765,6 +32886,8 @@ var CloudSessionProxy = class {
31765
32886
  return;
31766
32887
  }
31767
32888
  this.client = void 0;
32889
+ await this.automation?.close().catch(() => void 0);
32890
+ this.automation = void 0;
31768
32891
  this.sessionId = void 0;
31769
32892
  this.sessionBaseUrl = void 0;
31770
32893
  }
@@ -31775,9 +32898,11 @@ var CloudSessionProxy = class {
31775
32898
  assertSupportedCloudBrowserMode(input.browser);
31776
32899
  const persisted = await this.loadPersistedSession();
31777
32900
  if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
32901
+ await this.syncRegistryToCloud();
31778
32902
  this.bindClient(persisted);
31779
32903
  return;
31780
32904
  }
32905
+ await this.syncRegistryToCloud();
31781
32906
  const session = await this.cloud.createSession({
31782
32907
  ...this.workspace === void 0 ? {} : { name: this.workspace },
31783
32908
  ...input.launch === void 0 ? {} : { browser: input.launch },
@@ -31785,9 +32910,9 @@ var CloudSessionProxy = class {
31785
32910
  ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
31786
32911
  });
31787
32912
  const record = {
31788
- layout: CLOUD_SESSION_LAYOUT,
31789
- version: CLOUD_SESSION_VERSION,
31790
- mode: "cloud",
32913
+ layout: "opensteer-session",
32914
+ version: 1,
32915
+ provider: "cloud",
31791
32916
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31792
32917
  sessionId: session.sessionId,
31793
32918
  baseUrl: session.baseUrl,
@@ -31797,6 +32922,16 @@ var CloudSessionProxy = class {
31797
32922
  await this.writePersistedSession(record);
31798
32923
  this.bindClient(record);
31799
32924
  }
32925
+ async syncRegistryToCloud() {
32926
+ if (this.workspace === void 0) {
32927
+ return;
32928
+ }
32929
+ try {
32930
+ const workspaceStore = await this.ensureWorkspaceStore();
32931
+ await syncLocalRegistryToCloud(this.cloud, this.workspace, workspaceStore);
32932
+ } catch {
32933
+ }
32934
+ }
31800
32935
  bindClient(record) {
31801
32936
  this.sessionId = record.sessionId;
31802
32937
  this.sessionBaseUrl = record.baseUrl;
@@ -31804,6 +32939,7 @@ var CloudSessionProxy = class {
31804
32939
  baseUrl: record.baseUrl,
31805
32940
  getAuthorizationHeader: async () => this.cloud.buildAuthorizationHeader()
31806
32941
  });
32942
+ this.automation = new OpensteerCloudAutomationClient(this.cloud, record.sessionId);
31807
32943
  }
31808
32944
  async ensureWorkspaceStore() {
31809
32945
  if (this.workspaceStore !== void 0) {
@@ -31822,10 +32958,10 @@ var CloudSessionProxy = class {
31822
32958
  }
31823
32959
  async writePersistedSession(record) {
31824
32960
  const workspace = await this.ensureWorkspaceStore();
31825
- await writeJsonFileAtomic(resolveCloudSessionRecordPath(workspace.rootPath), record);
32961
+ await writePersistedSessionRecord(workspace.rootPath, record);
31826
32962
  }
31827
32963
  async clearPersistedSession() {
31828
- await promises.rm(resolveCloudSessionRecordPath(this.rootPath), { force: true }).catch(() => void 0);
32964
+ await clearPersistedSessionRecord(this.rootPath, "cloud").catch(() => void 0);
31829
32965
  }
31830
32966
  async isReusableCloudSession(sessionId) {
31831
32967
  try {
@@ -31844,6 +32980,12 @@ var CloudSessionProxy = class {
31844
32980
  }
31845
32981
  return this.client;
31846
32982
  }
32983
+ requireAutomation() {
32984
+ if (!this.automation) {
32985
+ throw new Error("Cloud automation session has not been initialized.");
32986
+ }
32987
+ return this.automation;
32988
+ }
31847
32989
  };
31848
32990
  function resolveCloudBrowserProfile(cloud, input) {
31849
32991
  return input.browserProfile ?? cloud.getConfig().browserProfile;
@@ -31859,49 +33001,33 @@ function assertSupportedCloudBrowserMode(browser) {
31859
33001
  function isMissingCloudSessionError(error) {
31860
33002
  return error instanceof Error && /\b404\b/.test(error.message);
31861
33003
  }
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
33004
 
31876
33005
  // src/sdk/runtime-resolution.ts
31877
33006
  function resolveOpensteerRuntimeConfig(input = {}) {
31878
- const mode = resolveOpensteerExecutionMode({
31879
- ...input.mode === void 0 ? {} : { explicit: input.mode },
31880
- cloud: input.cloud !== void 0 && input.cloud !== false,
31881
- ...input.environmentMode === void 0 ? {} : { environment: input.environmentMode }
33007
+ const provider = resolveOpensteerProvider({
33008
+ ...input.provider === void 0 ? {} : { provider: input.provider },
33009
+ ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
31882
33010
  });
31883
- if (mode === "cloud") {
33011
+ if (provider.kind === "cloud") {
31884
33012
  return {
31885
- mode,
33013
+ provider,
31886
33014
  cloud: resolveCloudConfig({
31887
- enabled: true,
31888
- ...typeof input.cloud === "object" ? input.cloud : {},
31889
- mode
33015
+ ...input.provider === void 0 ? {} : { provider: input.provider },
33016
+ ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
31890
33017
  })
31891
33018
  };
31892
33019
  }
31893
- return { mode };
33020
+ return { provider };
31894
33021
  }
31895
33022
  function createOpensteerSemanticRuntime(input = {}) {
31896
33023
  const runtimeOptions = input.runtimeOptions ?? {};
31897
33024
  const engine = input.engine ?? runtimeOptions.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31898
33025
  const config = resolveOpensteerRuntimeConfig({
31899
- ...input.cloud === void 0 ? {} : { cloud: input.cloud },
31900
- ...input.mode === void 0 ? {} : { mode: input.mode },
31901
- ...process.env.OPENSTEER_MODE === void 0 ? {} : { environmentMode: process.env.OPENSTEER_MODE }
33026
+ ...input.provider === void 0 ? {} : { provider: input.provider },
33027
+ ...process.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process.env.OPENSTEER_PROVIDER }
31902
33028
  });
31903
- assertExecutionModeSupportsEngine(config.mode, engine);
31904
- if (config.mode === "cloud") {
33029
+ assertProviderSupportsEngine(config.provider.kind, engine);
33030
+ if (config.provider.kind === "cloud") {
31905
33031
  return new CloudSessionProxy(new OpensteerCloudClient(config.cloud), {
31906
33032
  ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
31907
33033
  ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
@@ -31921,38 +33047,37 @@ var Opensteer = class {
31921
33047
  browserManager;
31922
33048
  browser;
31923
33049
  constructor(options = {}) {
33050
+ const { provider, engineName, ...runtimeOptions } = options;
31924
33051
  const runtimeConfig = resolveOpensteerRuntimeConfig({
31925
- ...options.cloud === void 0 ? {} : { cloud: options.cloud },
31926
- ...process.env.OPENSTEER_MODE === void 0 ? {} : { environmentMode: process.env.OPENSTEER_MODE }
33052
+ ...provider === void 0 ? {} : { provider },
33053
+ ...process.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process.env.OPENSTEER_PROVIDER }
31927
33054
  });
31928
- if (runtimeConfig.mode === "cloud") {
33055
+ if (runtimeConfig.provider.kind === "cloud") {
31929
33056
  this.browserManager = void 0;
31930
33057
  this.runtime = createOpensteerSemanticRuntime({
31931
- mode: runtimeConfig.mode,
31932
- ...options.cloud === void 0 ? {} : { cloud: options.cloud },
31933
- ...options.engineName === void 0 ? {} : { engine: options.engineName },
33058
+ ...provider === void 0 ? {} : { provider },
33059
+ ...engineName === void 0 ? {} : { engine: engineName },
31934
33060
  runtimeOptions: {
31935
- ...options
33061
+ ...runtimeOptions
31936
33062
  }
31937
33063
  });
31938
33064
  this.browser = createUnsupportedBrowserController();
31939
33065
  return;
31940
33066
  }
31941
33067
  this.browserManager = new OpensteerBrowserManager({
31942
- ...options.rootDir === void 0 ? {} : { rootDir: options.rootDir },
31943
- ...options.rootPath === void 0 ? {} : { rootPath: options.rootPath },
31944
- ...options.workspace === void 0 ? {} : { workspace: options.workspace },
31945
- ...options.engineName === void 0 ? {} : { engineName: options.engineName },
31946
- ...options.browser === void 0 ? {} : { browser: options.browser },
31947
- ...options.launch === void 0 ? {} : { launch: options.launch },
31948
- ...options.context === void 0 ? {} : { context: options.context }
33068
+ ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
33069
+ ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
33070
+ ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
33071
+ ...engineName === void 0 ? {} : { engineName },
33072
+ ...runtimeOptions.browser === void 0 ? {} : { browser: runtimeOptions.browser },
33073
+ ...runtimeOptions.launch === void 0 ? {} : { launch: runtimeOptions.launch },
33074
+ ...runtimeOptions.context === void 0 ? {} : { context: runtimeOptions.context }
31949
33075
  });
31950
33076
  this.runtime = createOpensteerSemanticRuntime({
31951
- mode: runtimeConfig.mode,
31952
- ...options.cloud === void 0 ? {} : { cloud: options.cloud },
31953
- ...options.engineName === void 0 ? {} : { engine: options.engineName },
33077
+ ...provider === void 0 ? {} : { provider },
33078
+ ...engineName === void 0 ? {} : { engine: engineName },
31954
33079
  runtimeOptions: {
31955
- ...options,
33080
+ ...runtimeOptions,
31956
33081
  rootPath: this.browserManager.rootPath,
31957
33082
  cleanupRootOnClose: this.browserManager.cleanupRootOnDisconnect
31958
33083
  }
@@ -31967,6 +33092,9 @@ var Opensteer = class {
31967
33092
  async open(input = {}) {
31968
33093
  return this.runtime.open(typeof input === "string" ? { url: input } : input);
31969
33094
  }
33095
+ async info() {
33096
+ return this.runtime.info();
33097
+ }
31970
33098
  async listPages(input = {}) {
31971
33099
  return this.runtime.listPages(input);
31972
33100
  }
@@ -31998,10 +33126,6 @@ var Opensteer = class {
31998
33126
  } : input;
31999
33127
  return this.runtime.addInitScript(normalized);
32000
33128
  }
32001
- async snapshot(input = {}) {
32002
- const mode = typeof input === "string" ? input : input.mode;
32003
- return this.runtime.snapshot(mode === void 0 ? {} : { mode });
32004
- }
32005
33129
  async click(input) {
32006
33130
  const normalized = normalizeTargetOptions(input);
32007
33131
  return this.runtime.click(normalized);
@@ -32081,6 +33205,9 @@ var Opensteer = class {
32081
33205
  await delay2(pollIntervalMs);
32082
33206
  }
32083
33207
  }
33208
+ async snapshot(input = {}) {
33209
+ return this.runtime.snapshot(typeof input === "string" ? { mode: input } : input);
33210
+ }
32084
33211
  async saveNetwork(input) {
32085
33212
  return this.runtime.saveNetwork(input);
32086
33213
  }
@@ -32225,12 +33352,15 @@ var Opensteer = class {
32225
33352
  await this.runtime.disconnect();
32226
33353
  }
32227
33354
  requireOwnedInstrumentationRuntime(method) {
32228
- if (this.runtime instanceof OpensteerRuntime) {
33355
+ if (isInstrumentableRuntime(this.runtime)) {
32229
33356
  return this.runtime;
32230
33357
  }
32231
- throw new Error(`${method}() is only available on owned local SDK sessions.`);
33358
+ throw new Error(`${method}() is not available for this session runtime.`);
32232
33359
  }
32233
33360
  };
33361
+ function isInstrumentableRuntime(runtime) {
33362
+ return typeof runtime.route === "function" && typeof runtime.interceptScript === "function";
33363
+ }
32234
33364
  function createUnsupportedBrowserController() {
32235
33365
  const fail = async () => {
32236
33366
  throw new Error("browser.* helpers are only available in local mode.");
@@ -32297,11 +33427,14 @@ exports.OpensteerAttachAmbiguousError = OpensteerAttachAmbiguousError;
32297
33427
  exports.OpensteerBrowserManager = OpensteerBrowserManager;
32298
33428
  exports.OpensteerCloudClient = OpensteerCloudClient;
32299
33429
  exports.OpensteerRuntime = OpensteerRuntime;
33430
+ exports.OpensteerSessionRuntime = OpensteerSessionRuntime2;
32300
33431
  exports.STABLE_PRIMARY_ATTR_KEYS = STABLE_PRIMARY_ATTR_KEYS;
33432
+ exports.assertProviderSupportsEngine = assertProviderSupportsEngine;
32301
33433
  exports.buildArrayFieldPathCandidates = buildArrayFieldPathCandidates;
32302
33434
  exports.buildPathCandidates = buildPathCandidates;
32303
33435
  exports.buildPathSelectorHint = buildPathSelectorHint;
32304
33436
  exports.buildSegmentSelector = buildSegmentSelector;
33437
+ exports.clearPersistedSessionRecord = clearPersistedSessionRecord;
32305
33438
  exports.cloneElementPath = cloneElementPath;
32306
33439
  exports.cloneReplayElementPath = cloneReplayElementPath;
32307
33440
  exports.cloneStructuralElementAnchor = cloneStructuralElementAnchor;
@@ -32316,23 +33449,26 @@ exports.defaultTimeoutPolicy = defaultTimeoutPolicy;
32316
33449
  exports.delayWithSignal = delayWithSignal;
32317
33450
  exports.discoverLocalCdpBrowsers = discoverLocalCdpBrowsers;
32318
33451
  exports.dispatchSemanticOperation = dispatchSemanticOperation;
32319
- exports.hasPersistedCloudSession = hasPersistedCloudSession;
32320
33452
  exports.inspectCdpEndpoint = inspectCdpEndpoint;
32321
33453
  exports.isCurrentUrlField = isCurrentUrlField;
32322
33454
  exports.isValidCssAttributeKey = isValidCssAttributeKey;
32323
33455
  exports.listLocalChromeProfiles = listLocalChromeProfiles;
32324
33456
  exports.normalizeExtractedValue = normalizeExtractedValue;
32325
33457
  exports.normalizeOpensteerEngineName = normalizeOpensteerEngineName;
32326
- exports.normalizeOpensteerExecutionMode = normalizeOpensteerExecutionMode;
33458
+ exports.normalizeOpensteerProviderKind = normalizeOpensteerProviderKind;
32327
33459
  exports.normalizeWorkspaceId = normalizeWorkspaceId;
32328
33460
  exports.readPersistedCloudSessionRecord = readPersistedCloudSessionRecord;
33461
+ exports.readPersistedLocalBrowserSessionRecord = readPersistedLocalBrowserSessionRecord;
33462
+ exports.readPersistedSessionRecord = readPersistedSessionRecord;
32329
33463
  exports.resolveCloudConfig = resolveCloudConfig;
32330
33464
  exports.resolveCloudSessionRecordPath = resolveCloudSessionRecordPath;
32331
33465
  exports.resolveDomActionBridge = resolveDomActionBridge;
32332
33466
  exports.resolveExtractedValueInContext = resolveExtractedValueInContext;
32333
33467
  exports.resolveFilesystemWorkspacePath = resolveFilesystemWorkspacePath;
33468
+ exports.resolveLiveSessionRecordPath = resolveLiveSessionRecordPath;
33469
+ exports.resolveLocalSessionRecordPath = resolveLocalSessionRecordPath;
32334
33470
  exports.resolveOpensteerEngineName = resolveOpensteerEngineName;
32335
- exports.resolveOpensteerExecutionMode = resolveOpensteerExecutionMode;
33471
+ exports.resolveOpensteerProvider = resolveOpensteerProvider;
32336
33472
  exports.resolveOpensteerRuntimeConfig = resolveOpensteerRuntimeConfig;
32337
33473
  exports.runWithPolicyTimeout = runWithPolicyTimeout;
32338
33474
  exports.sanitizeElementPath = sanitizeElementPath;
@@ -32340,5 +33476,6 @@ exports.sanitizeReplayElementPath = sanitizeReplayElementPath;
32340
33476
  exports.sanitizeStructuralElementAnchor = sanitizeStructuralElementAnchor;
32341
33477
  exports.settleWithPolicy = settleWithPolicy;
32342
33478
  exports.shouldKeepAttributeForPath = shouldKeepAttributeForPath;
33479
+ exports.writePersistedSessionRecord = writePersistedSessionRecord;
32343
33480
  //# sourceMappingURL=index.cjs.map
32344
33481
  //# sourceMappingURL=index.cjs.map