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.
@@ -1,6 +1,6 @@
1
1
  import path6, { join, resolve, basename, relative } from 'path';
2
2
  import { randomUUID, createHash } from 'crypto';
3
- import { rm, mkdtemp, mkdir, access, readFile, cp, readdir, writeFile, rename, stat, copyFile, open } from 'fs/promises';
3
+ import { access, rm, mkdtemp, mkdir, readFile, cp, readdir, writeFile, rename, stat, copyFile, open } from 'fs/promises';
4
4
  import { pathToFileURL } from 'url';
5
5
  import { selectAll } from 'css-select';
6
6
  import { execFileSync, execFile, spawn } from 'child_process';
@@ -14,6 +14,7 @@ import * as cheerio from 'cheerio';
14
14
  import * as prettier from 'prettier';
15
15
  import vm from 'vm';
16
16
  import { gzip as gzip$1 } from 'zlib';
17
+ import WebSocket2 from 'ws';
17
18
 
18
19
  // ../protocol/src/dom-action-bridge.ts
19
20
  var OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL = /* @__PURE__ */ Symbol.for("@opensteer/dom-action-bridge");
@@ -25,7 +26,7 @@ function resolveDomActionBridge(engine) {
25
26
  return isDomActionBridgeFactory(candidate) ? candidate.call(engine) : void 0;
26
27
  }
27
28
 
28
- // src/json.ts
29
+ // ../runtime-core/src/json.ts
29
30
  function isPlainObject(value) {
30
31
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
31
32
  return false;
@@ -33,30 +34,30 @@ function isPlainObject(value) {
33
34
  const prototype = Object.getPrototypeOf(value);
34
35
  return prototype === Object.prototype || prototype === null;
35
36
  }
36
- function canonicalizeJsonValue(value, path11) {
37
+ function canonicalizeJsonValue(value, path13) {
37
38
  if (value === null || typeof value === "string" || typeof value === "boolean") {
38
39
  return value;
39
40
  }
40
41
  if (typeof value === "number") {
41
42
  if (!Number.isFinite(value)) {
42
- throw new TypeError(`${path11} must be a finite JSON number`);
43
+ throw new TypeError(`${path13} must be a finite JSON number`);
43
44
  }
44
45
  return value;
45
46
  }
46
47
  if (Array.isArray(value)) {
47
- return value.map((entry, index) => canonicalizeJsonValue(entry, `${path11}[${index}]`));
48
+ return value.map((entry, index) => canonicalizeJsonValue(entry, `${path13}[${index}]`));
48
49
  }
49
50
  if (!isPlainObject(value)) {
50
- throw new TypeError(`${path11} must be a plain JSON object`);
51
+ throw new TypeError(`${path13} must be a plain JSON object`);
51
52
  }
52
53
  const sorted = Object.keys(value).sort((left, right) => left.localeCompare(right));
53
54
  const result = {};
54
55
  for (const key of sorted) {
55
56
  const entry = value[key];
56
57
  if (entry === void 0) {
57
- throw new TypeError(`${path11}.${key} must not be undefined`);
58
+ throw new TypeError(`${path13}.${key} must not be undefined`);
58
59
  }
59
- result[key] = canonicalizeJsonValue(entry, `${path11}.${key}`);
60
+ result[key] = canonicalizeJsonValue(entry, `${path13}.${key}`);
60
61
  }
61
62
  return result;
62
63
  }
@@ -71,7 +72,7 @@ function stableJsonString(value) {
71
72
  `;
72
73
  }
73
74
 
74
- // src/internal/filesystem.ts
75
+ // ../runtime-core/src/internal/filesystem.ts
75
76
  var LOCK_RETRY_DELAYS_MS = [1, 2, 5, 10, 20, 50];
76
77
  function normalizeNonEmptyString(name, value) {
77
78
  const normalized = value.trim();
@@ -199,7 +200,7 @@ async function withFilesystemLock(lockPath, task) {
199
200
  }
200
201
  }
201
202
 
202
- // src/artifacts.ts
203
+ // ../runtime-core/src/artifacts.ts
203
204
  function normalizeScope(scope) {
204
205
  if (scope === void 0) {
205
206
  return {};
@@ -553,31 +554,31 @@ function oneOfSchema(members, options = {}) {
553
554
  }
554
555
 
555
556
  // ../protocol/src/validation.ts
556
- function validateJsonSchema(schema, value, path11 = "$") {
557
- return validateSchemaNode(schema, value, path11);
557
+ function validateJsonSchema(schema, value, path13 = "$") {
558
+ return validateSchemaNode(schema, value, path13);
558
559
  }
559
- function validateSchemaNode(schema, value, path11) {
560
+ function validateSchemaNode(schema, value, path13) {
560
561
  const issues = [];
561
562
  if ("const" in schema && !isJsonValueEqual(schema.const, value)) {
562
563
  issues.push({
563
- path: path11,
564
+ path: path13,
564
565
  message: `must equal ${JSON.stringify(schema.const)}`
565
566
  });
566
567
  return issues;
567
568
  }
568
569
  if (schema.enum !== void 0 && !schema.enum.some((candidate) => isJsonValueEqual(candidate, value))) {
569
570
  issues.push({
570
- path: path11,
571
+ path: path13,
571
572
  message: `must be one of ${schema.enum.map((candidate) => JSON.stringify(candidate)).join(", ")}`
572
573
  });
573
574
  return issues;
574
575
  }
575
576
  if (schema.oneOf !== void 0) {
576
- const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path11));
577
+ const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path13));
577
578
  const validBranches = branchIssues.filter((current) => current.length === 0).length;
578
579
  if (validBranches !== 1) {
579
580
  issues.push({
580
- path: path11,
581
+ path: path13,
581
582
  message: validBranches === 0 ? "must match exactly one supported shape" : "matches multiple supported shapes"
582
583
  });
583
584
  return issues;
@@ -585,11 +586,11 @@ function validateSchemaNode(schema, value, path11) {
585
586
  }
586
587
  if (schema.anyOf !== void 0) {
587
588
  const hasMatch = schema.anyOf.some(
588
- (member) => validateSchemaNode(member, value, path11).length === 0
589
+ (member) => validateSchemaNode(member, value, path13).length === 0
589
590
  );
590
591
  if (!hasMatch) {
591
592
  issues.push({
592
- path: path11,
593
+ path: path13,
593
594
  message: "must match at least one supported shape"
594
595
  });
595
596
  return issues;
@@ -597,7 +598,7 @@ function validateSchemaNode(schema, value, path11) {
597
598
  }
598
599
  if (schema.allOf !== void 0) {
599
600
  for (const member of schema.allOf) {
600
- issues.push(...validateSchemaNode(member, value, path11));
601
+ issues.push(...validateSchemaNode(member, value, path13));
601
602
  }
602
603
  if (issues.length > 0) {
603
604
  return issues;
@@ -605,7 +606,7 @@ function validateSchemaNode(schema, value, path11) {
605
606
  }
606
607
  if (schema.type !== void 0 && !matchesSchemaType(schema.type, value)) {
607
608
  issues.push({
608
- path: path11,
609
+ path: path13,
609
610
  message: `must be ${describeSchemaType(schema.type)}`
610
611
  });
611
612
  return issues;
@@ -613,19 +614,19 @@ function validateSchemaNode(schema, value, path11) {
613
614
  if (typeof value === "string") {
614
615
  if (schema.minLength !== void 0 && value.length < schema.minLength) {
615
616
  issues.push({
616
- path: path11,
617
+ path: path13,
617
618
  message: `must have length >= ${String(schema.minLength)}`
618
619
  });
619
620
  }
620
621
  if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
621
622
  issues.push({
622
- path: path11,
623
+ path: path13,
623
624
  message: `must have length <= ${String(schema.maxLength)}`
624
625
  });
625
626
  }
626
627
  if (schema.pattern !== void 0 && !new RegExp(schema.pattern).test(value)) {
627
628
  issues.push({
628
- path: path11,
629
+ path: path13,
629
630
  message: `must match pattern ${schema.pattern}`
630
631
  });
631
632
  }
@@ -634,25 +635,25 @@ function validateSchemaNode(schema, value, path11) {
634
635
  if (typeof value === "number") {
635
636
  if (schema.minimum !== void 0 && value < schema.minimum) {
636
637
  issues.push({
637
- path: path11,
638
+ path: path13,
638
639
  message: `must be >= ${String(schema.minimum)}`
639
640
  });
640
641
  }
641
642
  if (schema.maximum !== void 0 && value > schema.maximum) {
642
643
  issues.push({
643
- path: path11,
644
+ path: path13,
644
645
  message: `must be <= ${String(schema.maximum)}`
645
646
  });
646
647
  }
647
648
  if (schema.exclusiveMinimum !== void 0 && value <= schema.exclusiveMinimum) {
648
649
  issues.push({
649
- path: path11,
650
+ path: path13,
650
651
  message: `must be > ${String(schema.exclusiveMinimum)}`
651
652
  });
652
653
  }
653
654
  if (schema.exclusiveMaximum !== void 0 && value >= schema.exclusiveMaximum) {
654
655
  issues.push({
655
- path: path11,
656
+ path: path13,
656
657
  message: `must be < ${String(schema.exclusiveMaximum)}`
657
658
  });
658
659
  }
@@ -661,13 +662,13 @@ function validateSchemaNode(schema, value, path11) {
661
662
  if (Array.isArray(value)) {
662
663
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
663
664
  issues.push({
664
- path: path11,
665
+ path: path13,
665
666
  message: `must have at least ${String(schema.minItems)} items`
666
667
  });
667
668
  }
668
669
  if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
669
670
  issues.push({
670
- path: path11,
671
+ path: path13,
671
672
  message: `must have at most ${String(schema.maxItems)} items`
672
673
  });
673
674
  }
@@ -677,7 +678,7 @@ function validateSchemaNode(schema, value, path11) {
677
678
  const key = JSON.stringify(item);
678
679
  if (seen.has(key)) {
679
680
  issues.push({
680
- path: path11,
681
+ path: path13,
681
682
  message: "must not contain duplicate items"
682
683
  });
683
684
  break;
@@ -687,7 +688,7 @@ function validateSchemaNode(schema, value, path11) {
687
688
  }
688
689
  if (schema.items !== void 0) {
689
690
  for (let index = 0; index < value.length; index += 1) {
690
- issues.push(...validateSchemaNode(schema.items, value[index], `${path11}[${String(index)}]`));
691
+ issues.push(...validateSchemaNode(schema.items, value[index], `${path13}[${String(index)}]`));
691
692
  }
692
693
  }
693
694
  return issues;
@@ -697,7 +698,7 @@ function validateSchemaNode(schema, value, path11) {
697
698
  for (const requiredKey of schema.required ?? []) {
698
699
  if (!(requiredKey in value)) {
699
700
  issues.push({
700
- path: joinObjectPath(path11, requiredKey),
701
+ path: joinObjectPath(path13, requiredKey),
701
702
  message: "is required"
702
703
  });
703
704
  }
@@ -706,13 +707,13 @@ function validateSchemaNode(schema, value, path11) {
706
707
  const propertySchema = properties[key];
707
708
  if (propertySchema !== void 0) {
708
709
  issues.push(
709
- ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path11, key))
710
+ ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path13, key))
710
711
  );
711
712
  continue;
712
713
  }
713
714
  if (schema.additionalProperties === false) {
714
715
  issues.push({
715
- path: joinObjectPath(path11, key),
716
+ path: joinObjectPath(path13, key),
716
717
  message: "is not allowed"
717
718
  });
718
719
  continue;
@@ -722,7 +723,7 @@ function validateSchemaNode(schema, value, path11) {
722
723
  ...validateSchemaNode(
723
724
  schema.additionalProperties,
724
725
  propertyValue,
725
- joinObjectPath(path11, key)
726
+ joinObjectPath(path13, key)
726
727
  )
727
728
  );
728
729
  }
@@ -966,8 +967,8 @@ function matchesNetworkRecordFilters(record, filters) {
966
967
  }
967
968
  }
968
969
  if (filters.path !== void 0) {
969
- const path11 = getParsedUrl().pathname;
970
- if (!includesCaseInsensitive(path11, filters.path)) {
970
+ const path13 = getParsedUrl().pathname;
971
+ if (!includesCaseInsensitive(path13, filters.path)) {
971
972
  return false;
972
973
  }
973
974
  }
@@ -1764,12 +1765,6 @@ var opensteerRegistryProvenanceSchema = objectSchema(
1764
1765
  required: ["source"]
1765
1766
  }
1766
1767
  );
1767
- var opensteerRequestPlanLifecycleSchema = enumSchema(
1768
- ["draft", "active", "deprecated", "retired"],
1769
- {
1770
- title: "OpensteerRequestPlanLifecycle"
1771
- }
1772
- );
1773
1768
  var opensteerRequestPlanFreshnessSchema = objectSchema(
1774
1769
  {
1775
1770
  lastValidatedAt: integerSchema({ minimum: 0 }),
@@ -1792,23 +1787,12 @@ var opensteerRequestPlanRecordSchema = objectSchema(
1792
1787
  uniqueItems: true
1793
1788
  }),
1794
1789
  provenance: opensteerRegistryProvenanceSchema,
1795
- lifecycle: opensteerRequestPlanLifecycleSchema,
1796
1790
  freshness: opensteerRequestPlanFreshnessSchema,
1797
1791
  payload: opensteerRequestPlanPayloadSchema
1798
1792
  },
1799
1793
  {
1800
1794
  title: "OpensteerRequestPlanRecord",
1801
- required: [
1802
- "id",
1803
- "key",
1804
- "version",
1805
- "createdAt",
1806
- "updatedAt",
1807
- "contentHash",
1808
- "tags",
1809
- "lifecycle",
1810
- "payload"
1811
- ]
1795
+ required: ["id", "key", "version", "createdAt", "updatedAt", "contentHash", "tags", "payload"]
1812
1796
  }
1813
1797
  );
1814
1798
  var jsonValueSchema = defineSchema({
@@ -2251,7 +2235,6 @@ var opensteerWriteRequestPlanInputSchema = objectSchema(
2251
2235
  uniqueItems: true
2252
2236
  }),
2253
2237
  provenance: opensteerRegistryProvenanceSchema,
2254
- lifecycle: opensteerRequestPlanLifecycleSchema,
2255
2238
  freshness: opensteerRequestPlanFreshnessSchema,
2256
2239
  payload: opensteerRequestPlanPayloadSchema
2257
2240
  },
@@ -2492,7 +2475,7 @@ var opensteerInferRequestPlanInputSchema = objectSchema(
2492
2475
  recordId: stringSchema({ minLength: 1 }),
2493
2476
  key: stringSchema({ minLength: 1 }),
2494
2477
  version: stringSchema({ minLength: 1 }),
2495
- lifecycle: opensteerRequestPlanLifecycleSchema
2478
+ transport: transportKindSchema
2496
2479
  },
2497
2480
  {
2498
2481
  title: "OpensteerInferRequestPlanInput",
@@ -5682,6 +5665,65 @@ var opensteerComputerAnnotationNames = [
5682
5665
  "grid",
5683
5666
  "selected"
5684
5667
  ];
5668
+ var opensteerSemanticOperationNames = [
5669
+ "session.open",
5670
+ "page.list",
5671
+ "page.new",
5672
+ "page.activate",
5673
+ "page.close",
5674
+ "page.goto",
5675
+ "page.evaluate",
5676
+ "page.add-init-script",
5677
+ "page.snapshot",
5678
+ "dom.click",
5679
+ "dom.hover",
5680
+ "dom.input",
5681
+ "dom.scroll",
5682
+ "dom.extract",
5683
+ "network.query",
5684
+ "network.save",
5685
+ "network.clear",
5686
+ "network.minimize",
5687
+ "network.diff",
5688
+ "network.probe",
5689
+ "reverse.discover",
5690
+ "reverse.query",
5691
+ "reverse.package.create",
5692
+ "reverse.package.run",
5693
+ "reverse.export",
5694
+ "reverse.report",
5695
+ "reverse.package.get",
5696
+ "reverse.package.list",
5697
+ "reverse.package.patch",
5698
+ "interaction.capture",
5699
+ "interaction.get",
5700
+ "interaction.diff",
5701
+ "interaction.replay",
5702
+ "artifact.read",
5703
+ "inspect.cookies",
5704
+ "inspect.storage",
5705
+ "scripts.capture",
5706
+ "scripts.beautify",
5707
+ "scripts.deobfuscate",
5708
+ "scripts.sandbox",
5709
+ "captcha.solve",
5710
+ "request.raw",
5711
+ "request-plan.infer",
5712
+ "request-plan.write",
5713
+ "request-plan.get",
5714
+ "request-plan.list",
5715
+ "recipe.write",
5716
+ "recipe.get",
5717
+ "recipe.list",
5718
+ "recipe.run",
5719
+ "auth-recipe.write",
5720
+ "auth-recipe.get",
5721
+ "auth-recipe.list",
5722
+ "auth-recipe.run",
5723
+ "request.execute",
5724
+ "computer.execute",
5725
+ "session.close"
5726
+ ];
5685
5727
  function defineSemanticOperationSpec(spec) {
5686
5728
  return spec;
5687
5729
  }
@@ -6971,7 +7013,7 @@ function resolveComputerUseBridge(engine) {
6971
7013
  return isComputerUseBridgeFactory(candidate) ? candidate.call(engine) : void 0;
6972
7014
  }
6973
7015
 
6974
- // src/registry.ts
7016
+ // ../runtime-core/src/registry.ts
6975
7017
  function normalizeTags(tags) {
6976
7018
  if (tags === void 0) {
6977
7019
  return [];
@@ -7037,9 +7079,7 @@ var FilesystemRegistryStore = class {
7037
7079
  if (input.version !== void 0) {
7038
7080
  return this.resolveIndexedRecord(key, normalizeNonEmptyString("version", input.version));
7039
7081
  }
7040
- const matches = (await this.readAllRecords()).filter(
7041
- (record) => this.isActive(record) && record.key === key
7042
- );
7082
+ const matches = (await this.readAllRecords()).filter((record) => record.key === key);
7043
7083
  matches.sort(compareByCreatedAtAndId);
7044
7084
  return matches[0];
7045
7085
  }
@@ -7162,8 +7202,10 @@ var FilesystemDescriptorRegistry = class extends FilesystemRegistryStore {
7162
7202
  };
7163
7203
  return this.writeRecord(record);
7164
7204
  }
7165
- isActive(_record) {
7166
- return true;
7205
+ async list(input = {}) {
7206
+ const key = input.key === void 0 ? void 0 : normalizeNonEmptyString("key", input.key);
7207
+ const records = await this.readAllRecords();
7208
+ return key === void 0 ? records : records.filter((record) => record.key === key);
7167
7209
  }
7168
7210
  };
7169
7211
  var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
@@ -7193,7 +7235,6 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7193
7235
  tags: normalizeTags(input.tags),
7194
7236
  ...provenance === void 0 ? {} : { provenance },
7195
7237
  payload,
7196
- lifecycle: input.lifecycle ?? "active",
7197
7238
  ...freshness === void 0 ? {} : { freshness }
7198
7239
  };
7199
7240
  return this.writeRecord(record);
@@ -7203,7 +7244,7 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7203
7244
  const records = await this.readAllRecords();
7204
7245
  return key === void 0 ? records : records.filter((record) => record.key === key);
7205
7246
  }
7206
- async updateMetadata(input) {
7247
+ async updateFreshness(input) {
7207
7248
  const id = normalizeNonEmptyString("id", input.id);
7208
7249
  return withFilesystemLock(this.writeLockPath(), async () => {
7209
7250
  const existing = await this.getById(id);
@@ -7221,16 +7262,12 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7221
7262
  const nextRecord = {
7222
7263
  ...existing,
7223
7264
  updatedAt: nextUpdatedAt,
7224
- lifecycle: input.lifecycle ?? existing.lifecycle,
7225
7265
  ...nextFreshness === void 0 ? {} : { freshness: nextFreshness }
7226
7266
  };
7227
7267
  await writeJsonFileAtomic(this.recordPath(id), nextRecord);
7228
7268
  return nextRecord;
7229
7269
  });
7230
7270
  }
7231
- isActive(record) {
7232
- return record.lifecycle === "active";
7233
- }
7234
7271
  };
7235
7272
  var FilesystemAuthRecipeRegistry = class extends FilesystemRegistryStore {
7236
7273
  constructor(rootPath) {
@@ -7266,9 +7303,6 @@ var FilesystemAuthRecipeRegistry = class extends FilesystemRegistryStore {
7266
7303
  const records = await this.readAllRecords();
7267
7304
  return key === void 0 ? records : records.filter((record) => record.key === key);
7268
7305
  }
7269
- isActive(_record) {
7270
- return true;
7271
- }
7272
7306
  };
7273
7307
  var FilesystemRecipeRegistry = class extends FilesystemRegistryStore {
7274
7308
  constructor(rootPath) {
@@ -7304,9 +7338,6 @@ var FilesystemRecipeRegistry = class extends FilesystemRegistryStore {
7304
7338
  const records = await this.readAllRecords();
7305
7339
  return key === void 0 ? records : records.filter((record) => record.key === key);
7306
7340
  }
7307
- isActive(_record) {
7308
- return true;
7309
- }
7310
7341
  };
7311
7342
  var FilesystemInteractionTraceRegistry = class extends FilesystemRegistryStore {
7312
7343
  constructor(rootPath) {
@@ -7342,9 +7373,6 @@ var FilesystemInteractionTraceRegistry = class extends FilesystemRegistryStore {
7342
7373
  const records = await this.readAllRecords();
7343
7374
  return key === void 0 ? records : records.filter((record) => record.key === key);
7344
7375
  }
7345
- isActive(_record) {
7346
- return true;
7347
- }
7348
7376
  };
7349
7377
  var FilesystemReverseCaseRegistry = class extends FilesystemRegistryStore {
7350
7378
  constructor(rootPath) {
@@ -7408,9 +7436,6 @@ var FilesystemReverseCaseRegistry = class extends FilesystemRegistryStore {
7408
7436
  return nextRecord;
7409
7437
  });
7410
7438
  }
7411
- isActive(_record) {
7412
- return true;
7413
- }
7414
7439
  };
7415
7440
  var FilesystemReversePackageRegistry = class extends FilesystemRegistryStore {
7416
7441
  constructor(rootPath) {
@@ -7446,9 +7471,6 @@ var FilesystemReversePackageRegistry = class extends FilesystemRegistryStore {
7446
7471
  const records = await this.readAllRecords();
7447
7472
  return key === void 0 ? records : records.filter((record) => record.key === key);
7448
7473
  }
7449
- isActive(_record) {
7450
- return true;
7451
- }
7452
7474
  };
7453
7475
  var FilesystemReverseReportRegistry = class extends FilesystemRegistryStore {
7454
7476
  constructor(rootPath) {
@@ -7484,9 +7506,6 @@ var FilesystemReverseReportRegistry = class extends FilesystemRegistryStore {
7484
7506
  const records = await this.readAllRecords();
7485
7507
  return key === void 0 ? records : records.filter((record) => record.key === key);
7486
7508
  }
7487
- isActive(_record) {
7488
- return true;
7489
- }
7490
7509
  };
7491
7510
  function createDescriptorRegistry(rootPath) {
7492
7511
  return new FilesystemDescriptorRegistry(rootPath);
@@ -8205,7 +8224,7 @@ function createTraceStore(rootPath, artifacts) {
8205
8224
  return new FilesystemTraceStore(rootPath, artifacts);
8206
8225
  }
8207
8226
 
8208
- // src/root.ts
8227
+ // ../runtime-core/src/root.ts
8209
8228
  var OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT = "opensteer-workspace";
8210
8229
  var OPENSTEER_FILESYSTEM_WORKSPACE_VERSION = 2;
8211
8230
  function normalizeWorkspaceId(workspace) {
@@ -8226,7 +8245,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8226
8245
  const browserManifestPath = path6.join(browserPath, "manifest.json");
8227
8246
  const browserUserDataDir = path6.join(browserPath, "user-data");
8228
8247
  const livePath = path6.join(options.rootPath, "live");
8229
- const liveBrowserPath = path6.join(livePath, "browser.json");
8248
+ const liveLocalPath = path6.join(livePath, "local.json");
8249
+ const liveCloudPath = path6.join(livePath, "cloud.json");
8230
8250
  const artifactsPath = path6.join(options.rootPath, "artifacts");
8231
8251
  const tracesPath = path6.join(options.rootPath, "traces");
8232
8252
  const registryPath = path6.join(options.rootPath, "registry");
@@ -8301,7 +8321,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8301
8321
  browserManifestPath,
8302
8322
  browserUserDataDir,
8303
8323
  livePath,
8304
- liveBrowserPath,
8324
+ liveLocalPath,
8325
+ liveCloudPath,
8305
8326
  artifactsPath,
8306
8327
  tracesPath,
8307
8328
  registryPath,
@@ -8325,7 +8346,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8325
8346
  };
8326
8347
  }
8327
8348
 
8328
- // src/policy/defaults.ts
8349
+ // ../runtime-core/src/policy/defaults.ts
8329
8350
  var DEFAULT_TIMEOUTS = {
8330
8351
  "session.open": 3e4,
8331
8352
  "page.goto": 3e4,
@@ -8408,7 +8429,7 @@ function defaultPolicy() {
8408
8429
  return DEFAULT_POLICY;
8409
8430
  }
8410
8431
 
8411
- // src/policy/settle.ts
8432
+ // ../runtime-core/src/policy/settle.ts
8412
8433
  async function settleWithPolicy(policy, input) {
8413
8434
  for (const observer of policy.observers ?? []) {
8414
8435
  if (await observer.settle(input)) {
@@ -8447,7 +8468,7 @@ function abortError() {
8447
8468
  return error;
8448
8469
  }
8449
8470
 
8450
- // src/policy/timeout.ts
8471
+ // ../runtime-core/src/policy/timeout.ts
8451
8472
  var PolicyTimeoutController = class {
8452
8473
  constructor(input, budgetMs) {
8453
8474
  this.input = input;
@@ -8557,7 +8578,17 @@ function abortError2() {
8557
8578
  return error;
8558
8579
  }
8559
8580
 
8560
- // src/runtimes/dom/match-policy.ts
8581
+ // ../runtime-core/src/runtimes/dom/errors.ts
8582
+ var ElementPathError = class extends Error {
8583
+ code;
8584
+ constructor(code, message) {
8585
+ super(message);
8586
+ this.name = "ElementPathError";
8587
+ this.code = code;
8588
+ }
8589
+ };
8590
+
8591
+ // ../runtime-core/src/runtimes/dom/match-policy.ts
8561
8592
  var ATTRIBUTE_DENY_KEYS = /* @__PURE__ */ new Set([
8562
8593
  "style",
8563
8594
  "nonce",
@@ -8789,7 +8820,7 @@ function getClauseAttributeValue(node, clause) {
8789
8820
  return String(raw);
8790
8821
  }
8791
8822
 
8792
- // src/runtimes/dom/match-selectors.ts
8823
+ // ../runtime-core/src/runtimes/dom/match-selectors.ts
8793
8824
  function buildPathCandidates(domPath) {
8794
8825
  const nodes = Array.isArray(domPath) ? domPath : [];
8795
8826
  if (!nodes.length) {
@@ -8874,7 +8905,7 @@ function buildSuffixCandidates(segments) {
8874
8905
  return out;
8875
8906
  }
8876
8907
 
8877
- // src/runtimes/dom/extraction.ts
8908
+ // ../runtime-core/src/runtimes/dom/extraction.ts
8878
8909
  var URL_LIST_ATTRIBUTES = /* @__PURE__ */ new Set(["srcset", "imagesrcset", "ping"]);
8879
8910
  var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8880
8911
  "href",
@@ -8886,9 +8917,9 @@ var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
8886
8917
  "poster",
8887
8918
  "ping"
8888
8919
  ]);
8889
- function buildArrayFieldPathCandidates(path11) {
8890
- const strict = path11.nodes.length ? buildPathCandidates(path11.nodes) : [];
8891
- const relaxedNodes = stripPositionClauses(path11.nodes);
8920
+ function buildArrayFieldPathCandidates(path13) {
8921
+ const strict = path13.nodes.length ? buildPathCandidates(path13.nodes) : [];
8922
+ const relaxedNodes = stripPositionClauses(path13.nodes);
8892
8923
  const relaxed = relaxedNodes.length ? buildPathCandidates(relaxedNodes) : [];
8893
8924
  return dedupeSelectors([...strict, ...relaxed]);
8894
8925
  }
@@ -9120,16 +9151,6 @@ function readDescriptorToken(value, index) {
9120
9151
  nextIndex: cursor
9121
9152
  };
9122
9153
  }
9123
-
9124
- // src/runtimes/dom/errors.ts
9125
- var ElementPathError = class extends Error {
9126
- code;
9127
- constructor(code, message) {
9128
- super(message);
9129
- this.name = "ElementPathError";
9130
- this.code = code;
9131
- }
9132
- };
9133
9154
  var selectorAdapter = {
9134
9155
  isTag(node) {
9135
9156
  return node.kind === "element" && node.source.nodeType === 1;
@@ -9197,6 +9218,45 @@ var selectorAdapter = {
9197
9218
  },
9198
9219
  equals(left, right) {
9199
9220
  return left === right;
9221
+ },
9222
+ existsOne(test, nodes) {
9223
+ return selectorAdapter.findOne(test, nodes) !== null;
9224
+ },
9225
+ findAll(test, nodes) {
9226
+ const matches = [];
9227
+ const visit = (node) => {
9228
+ if (selectorAdapter.isTag(node) && test(node)) {
9229
+ matches.push(node);
9230
+ }
9231
+ for (const child of selectorAdapter.getChildren(node)) {
9232
+ visit(child);
9233
+ }
9234
+ };
9235
+ for (const node of nodes) {
9236
+ visit(node);
9237
+ }
9238
+ return matches;
9239
+ },
9240
+ findOne(test, nodes) {
9241
+ const visit = (node) => {
9242
+ if (selectorAdapter.isTag(node) && test(node)) {
9243
+ return node;
9244
+ }
9245
+ for (const child of selectorAdapter.getChildren(node)) {
9246
+ const match = visit(child);
9247
+ if (match !== null) {
9248
+ return match;
9249
+ }
9250
+ }
9251
+ return null;
9252
+ };
9253
+ for (const node of nodes) {
9254
+ const match = visit(node);
9255
+ if (match !== null) {
9256
+ return match;
9257
+ }
9258
+ }
9259
+ return null;
9200
9260
  }
9201
9261
  };
9202
9262
  function createDomSnapshotIndex(snapshot) {
@@ -9380,7 +9440,7 @@ function sortNodes(nodes) {
9380
9440
  return [...nodes].sort((left, right) => left.snapshotNodeId - right.snapshotNodeId);
9381
9441
  }
9382
9442
 
9383
- // src/runtimes/dom/path.ts
9443
+ // ../runtime-core/src/runtimes/dom/path.ts
9384
9444
  var MAX_ATTRIBUTE_VALUE_LENGTH = 300;
9385
9445
  function cloneStructuralElementAnchor(anchor) {
9386
9446
  return {
@@ -9389,18 +9449,18 @@ function cloneStructuralElementAnchor(anchor) {
9389
9449
  nodes: anchor.nodes.map(clonePathNode)
9390
9450
  };
9391
9451
  }
9392
- function cloneReplayElementPath(path11) {
9452
+ function cloneReplayElementPath(path13) {
9393
9453
  return {
9394
9454
  resolution: "deterministic",
9395
- context: cloneContext(path11.context),
9396
- nodes: path11.nodes.map(clonePathNode)
9455
+ context: cloneContext(path13.context),
9456
+ nodes: path13.nodes.map(clonePathNode)
9397
9457
  };
9398
9458
  }
9399
- function cloneElementPath(path11) {
9400
- return cloneReplayElementPath(path11);
9459
+ function cloneElementPath(path13) {
9460
+ return cloneReplayElementPath(path13);
9401
9461
  }
9402
- function buildPathSelectorHint(path11) {
9403
- const nodes = path11?.nodes || [];
9462
+ function buildPathSelectorHint(path13) {
9463
+ const nodes = path13?.nodes || [];
9404
9464
  const last = nodes[nodes.length - 1];
9405
9465
  if (!last) {
9406
9466
  return "*";
@@ -9449,15 +9509,15 @@ function sanitizeStructuralElementAnchor(anchor) {
9449
9509
  nodes: sanitizeNodes(anchor.nodes)
9450
9510
  };
9451
9511
  }
9452
- function sanitizeReplayElementPath(path11) {
9512
+ function sanitizeReplayElementPath(path13) {
9453
9513
  return {
9454
9514
  resolution: "deterministic",
9455
- context: sanitizeContext(path11.context),
9456
- nodes: sanitizeNodes(path11.nodes)
9515
+ context: sanitizeContext(path13.context),
9516
+ nodes: sanitizeNodes(path13.nodes)
9457
9517
  };
9458
9518
  }
9459
- function sanitizeElementPath(path11) {
9460
- return sanitizeReplayElementPath(path11);
9519
+ function sanitizeElementPath(path13) {
9520
+ return sanitizeReplayElementPath(path13);
9461
9521
  }
9462
9522
  function buildLocalStructuralElementAnchor(index, rawTargetNode) {
9463
9523
  const targetNode = requireElementNode(index, rawTargetNode);
@@ -9580,8 +9640,8 @@ function buildTargetNotFoundMessage(domPath, diagnostics) {
9580
9640
  }
9581
9641
  return `${base} Target depth ${String(depth)}. Candidate counts: ${sample}.`;
9582
9642
  }
9583
- function buildArrayFieldCandidates(path11) {
9584
- return buildArrayFieldPathCandidates(path11);
9643
+ function buildArrayFieldCandidates(path13) {
9644
+ return buildArrayFieldPathCandidates(path13);
9585
9645
  }
9586
9646
  function firstDefinedAttribute(node, keys) {
9587
9647
  for (const key of keys) {
@@ -9856,23 +9916,28 @@ function getShadowScopeNodeRef(index, node) {
9856
9916
  return findContainingShadowHostNode(index, node)?.nodeRef;
9857
9917
  }
9858
9918
  function createDomDescriptorStore(options) {
9859
- const namespace = normalizeNamespace(options.namespace);
9919
+ const namespace = normalizeDomDescriptorNamespace(options.namespace);
9860
9920
  if (options.root) {
9861
9921
  return new FilesystemDomDescriptorStore(options.root.registry.descriptors, namespace);
9862
9922
  }
9863
9923
  return new MemoryDomDescriptorStore(namespace);
9864
9924
  }
9865
- function descriptionKey(namespace, method, description) {
9866
- return `dom:${namespace}:${method}:${sha256Hex2(description.trim())}`;
9925
+ function hashDomDescriptorDescription(description) {
9926
+ return sha256Hex2(description.trim());
9867
9927
  }
9868
- function normalizeNamespace(namespace) {
9928
+ function buildDomDescriptorKey(options) {
9929
+ return `dom:${normalizeDomDescriptorNamespace(options.namespace)}:${options.method}:${hashDomDescriptorDescription(
9930
+ options.description
9931
+ )}`;
9932
+ }
9933
+ function normalizeDomDescriptorNamespace(namespace) {
9869
9934
  const normalized = String(namespace || "default").trim();
9870
9935
  return normalized.length === 0 ? "default" : normalized;
9871
9936
  }
9872
9937
  function sha256Hex2(value) {
9873
9938
  return createHash("sha256").update(value).digest("hex");
9874
9939
  }
9875
- function buildPayload(input) {
9940
+ function buildDomDescriptorPayload(input) {
9876
9941
  return {
9877
9942
  kind: "dom-target",
9878
9943
  method: input.method,
@@ -9881,6 +9946,9 @@ function buildPayload(input) {
9881
9946
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
9882
9947
  };
9883
9948
  }
9949
+ function buildDomDescriptorVersion(payload) {
9950
+ return sha256Hex2(canonicalJsonString(payload));
9951
+ }
9884
9952
  function parseDomDescriptorRecord(record) {
9885
9953
  const payload = record.payload;
9886
9954
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
@@ -9922,7 +9990,11 @@ var FilesystemDomDescriptorStore = class {
9922
9990
  }
9923
9991
  async read(input) {
9924
9992
  const record = await this.registry.resolve({
9925
- key: descriptionKey(this.namespace, input.method, input.description)
9993
+ key: buildDomDescriptorKey({
9994
+ namespace: this.namespace,
9995
+ method: input.method,
9996
+ description: input.description
9997
+ })
9926
9998
  });
9927
9999
  if (!record) {
9928
10000
  return void 0;
@@ -9930,9 +10002,13 @@ var FilesystemDomDescriptorStore = class {
9930
10002
  return parseDomDescriptorRecord(record);
9931
10003
  }
9932
10004
  async write(input) {
9933
- const payload = buildPayload(input);
9934
- const key = descriptionKey(this.namespace, input.method, input.description);
9935
- const version = sha256Hex2(canonicalJsonString(payload));
10005
+ const payload = buildDomDescriptorPayload(input);
10006
+ const key = buildDomDescriptorKey({
10007
+ namespace: this.namespace,
10008
+ method: input.method,
10009
+ description: input.description
10010
+ });
10011
+ const version = buildDomDescriptorVersion(payload);
9936
10012
  const existing = await this.registry.resolve({ key, version });
9937
10013
  if (existing) {
9938
10014
  const parsed2 = parseDomDescriptorRecord(existing);
@@ -9970,12 +10046,22 @@ var MemoryDomDescriptorStore = class {
9970
10046
  latestByKey = /* @__PURE__ */ new Map();
9971
10047
  recordsByKey = /* @__PURE__ */ new Map();
9972
10048
  async read(input) {
9973
- return this.latestByKey.get(descriptionKey(this.namespace, input.method, input.description));
10049
+ return this.latestByKey.get(
10050
+ buildDomDescriptorKey({
10051
+ namespace: this.namespace,
10052
+ method: input.method,
10053
+ description: input.description
10054
+ })
10055
+ );
9974
10056
  }
9975
10057
  async write(input) {
9976
- const payload = buildPayload(input);
9977
- const key = descriptionKey(this.namespace, input.method, input.description);
9978
- const version = sha256Hex2(canonicalJsonString(payload));
10058
+ const payload = buildDomDescriptorPayload(input);
10059
+ const key = buildDomDescriptorKey({
10060
+ namespace: this.namespace,
10061
+ method: input.method,
10062
+ description: input.description
10063
+ });
10064
+ const version = buildDomDescriptorVersion(payload);
9979
10065
  const existing = this.recordsByKey.get(key)?.get(version);
9980
10066
  if (existing) {
9981
10067
  return existing;
@@ -9997,7 +10083,7 @@ var MemoryDomDescriptorStore = class {
9997
10083
  }
9998
10084
  };
9999
10085
 
10000
- // src/runtimes/dom/executor.ts
10086
+ // ../runtime-core/src/runtimes/dom/executor.ts
10001
10087
  var MAX_DOM_ACTION_ATTEMPTS = 3;
10002
10088
  var DEFAULT_SCROLL_OPTIONS = {
10003
10089
  block: "center",
@@ -10561,7 +10647,7 @@ function pointFallsWithinQuads(point, quads) {
10561
10647
  return quads.some((quad) => rectContainsPoint(quadBounds(quad), point));
10562
10648
  }
10563
10649
 
10564
- // src/runtimes/dom/runtime.ts
10650
+ // ../runtime-core/src/runtimes/dom/runtime.ts
10565
10651
  var SnapshotSession = class {
10566
10652
  constructor(engine) {
10567
10653
  this.engine = engine;
@@ -10618,7 +10704,7 @@ var DefaultDomRuntime = class {
10618
10704
  bridge;
10619
10705
  constructor(options) {
10620
10706
  this.engine = options.engine;
10621
- this.descriptors = createDomDescriptorStore({
10707
+ this.descriptors = options.descriptorStore ?? createDomDescriptorStore({
10622
10708
  ...options.root === void 0 ? {} : { root: options.root },
10623
10709
  ...options.namespace === void 0 ? {} : { namespace: options.namespace }
10624
10710
  });
@@ -10965,21 +11051,21 @@ var DefaultDomRuntime = class {
10965
11051
  return match;
10966
11052
  }
10967
11053
  async resolvePathTarget(session, pageRef, rawPath, source, description, descriptor) {
10968
- const path11 = sanitizeReplayElementPath(rawPath);
10969
- const context = await this.resolvePathContext(session, pageRef, path11.context);
10970
- const target = resolveDomPathInScope(context.index, path11.nodes, context.scope);
11054
+ const path13 = sanitizeReplayElementPath(rawPath);
11055
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11056
+ const target = resolveDomPathInScope(context.index, path13.nodes, context.scope);
10971
11057
  if (!target) {
10972
- throwTargetNotFound(context.index, path11.nodes, context.scope);
11058
+ throwTargetNotFound(context.index, path13.nodes, context.scope);
10973
11059
  }
10974
11060
  if (target.node.nodeRef === void 0) {
10975
11061
  throw new Error(
10976
- `resolved path "${buildPathSelectorHint(path11)}" does not point to a live element`
11062
+ `resolved path "${buildPathSelectorHint(path13)}" does not point to a live element`
10977
11063
  );
10978
11064
  }
10979
11065
  const anchor = await this.buildAnchorFromSnapshotNode(session, context.snapshot, target.node);
10980
11066
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
10981
11067
  ...description === void 0 ? {} : { description },
10982
- replayPath: path11,
11068
+ replayPath: path13,
10983
11069
  ...source === "path" || source === "descriptor" ? { selectorUsed: target.selector } : {},
10984
11070
  ...descriptor === void 0 ? {} : { descriptor }
10985
11071
  });
@@ -11000,9 +11086,9 @@ var DefaultDomRuntime = class {
11000
11086
  });
11001
11087
  }
11002
11088
  async queryAllByElementPath(session, pageRef, rawPath) {
11003
- const path11 = sanitizeReplayElementPath(rawPath);
11004
- const context = await this.resolvePathContext(session, pageRef, path11.context);
11005
- return queryAllDomPathInScope(context.index, path11.nodes, context.scope).filter(
11089
+ const path13 = sanitizeReplayElementPath(rawPath);
11090
+ const context = await this.resolvePathContext(session, pageRef, path13.context);
11091
+ return queryAllDomPathInScope(context.index, path13.nodes, context.scope).filter(
11006
11092
  (node) => node.nodeRef !== void 0
11007
11093
  ).map((node) => this.createSnapshotTarget(context.snapshot, node));
11008
11094
  }
@@ -11188,16 +11274,16 @@ var DefaultDomRuntime = class {
11188
11274
  const index = createSnapshotIndex(item.snapshot);
11189
11275
  return this.resolveFirstArrayFieldTargetInNode(index, item.node, field.path);
11190
11276
  }
11191
- resolveFirstArrayFieldTargetInNode(index, rootNode, path11) {
11192
- const normalizedPath = sanitizeElementPath(path11);
11277
+ resolveFirstArrayFieldTargetInNode(index, rootNode, path13) {
11278
+ const normalizedPath = sanitizeElementPath(path13);
11193
11279
  const selectors = buildArrayFieldCandidates(normalizedPath);
11194
11280
  if (!selectors.length) {
11195
11281
  return rootNode;
11196
11282
  }
11197
11283
  return resolveFirstWithinNodeBySelectors(index, rootNode, selectors);
11198
11284
  }
11199
- resolveUniqueArrayFieldTargetInNode(index, rootNode, path11) {
11200
- const normalizedPath = sanitizeElementPath(path11);
11285
+ resolveUniqueArrayFieldTargetInNode(index, rootNode, path13) {
11286
+ const normalizedPath = sanitizeElementPath(path13);
11201
11287
  const selectors = buildArrayFieldCandidates(normalizedPath);
11202
11288
  if (!selectors.length) {
11203
11289
  return rootNode;
@@ -12007,8 +12093,8 @@ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
12007
12093
  const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
12008
12094
  return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
12009
12095
  }
12010
- function normalizeWebSocketPath(path11) {
12011
- return path11.startsWith("/") ? path11 : `/${path11}`;
12096
+ function normalizeWebSocketPath(path13) {
12097
+ return path13.startsWith("/") ? path13 : `/${path13}`;
12012
12098
  }
12013
12099
  function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
12014
12100
  try {
@@ -12025,8 +12111,53 @@ function readPort(url) {
12025
12111
  const port = Number.parseInt(url.port, 10);
12026
12112
  return Number.isInteger(port) && port > 0 ? port : void 0;
12027
12113
  }
12114
+ var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
12115
+ var OPENSTEER_LIVE_SESSION_VERSION = 1;
12116
+ function resolveLiveSessionRecordPath(rootPath, provider) {
12117
+ return path6.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
12118
+ }
12119
+ function resolveLocalSessionRecordPath(rootPath) {
12120
+ return resolveLiveSessionRecordPath(rootPath, "local");
12121
+ }
12122
+ function resolveCloudSessionRecordPath(rootPath) {
12123
+ return resolveLiveSessionRecordPath(rootPath, "cloud");
12124
+ }
12125
+ async function readPersistedSessionRecord(rootPath, provider) {
12126
+ const sessionPath = resolveLiveSessionRecordPath(rootPath, provider);
12127
+ if (!await pathExists(sessionPath)) {
12128
+ return void 0;
12129
+ }
12130
+ const parsed = await readJsonFile(sessionPath);
12131
+ if (provider === "local" && isPersistedLocalBrowserSessionRecord(parsed)) {
12132
+ return parsed;
12133
+ }
12134
+ if (provider === "cloud" && isPersistedCloudSessionRecord(parsed)) {
12135
+ return parsed;
12136
+ }
12137
+ return void 0;
12138
+ }
12139
+ async function readPersistedCloudSessionRecord(rootPath) {
12140
+ const record = await readPersistedSessionRecord(rootPath, "cloud");
12141
+ return record?.provider === "cloud" ? record : void 0;
12142
+ }
12143
+ async function readPersistedLocalBrowserSessionRecord(rootPath) {
12144
+ const record = await readPersistedSessionRecord(rootPath, "local");
12145
+ return record?.provider === "local" ? record : void 0;
12146
+ }
12147
+ async function writePersistedSessionRecord(rootPath, record) {
12148
+ await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath, record.provider), record);
12149
+ }
12150
+ async function clearPersistedSessionRecord(rootPath, provider) {
12151
+ await rm(resolveLiveSessionRecordPath(rootPath, provider), { force: true });
12152
+ }
12153
+ function isPersistedCloudSessionRecord(value) {
12154
+ 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);
12155
+ }
12156
+ function isPersistedLocalBrowserSessionRecord(value) {
12157
+ 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;
12158
+ }
12028
12159
 
12029
- // src/internal/engine-selection.ts
12160
+ // ../runtime-core/src/internal/engine-selection.ts
12030
12161
  var OPENSTEER_ENGINE_NAMES = ["playwright", "abp"];
12031
12162
  var DEFAULT_OPENSTEER_ENGINE = "playwright";
12032
12163
  function resolveOpensteerEngineName(input = {}) {
@@ -12147,9 +12278,6 @@ async function clearChromeSingletonEntries(userDataDir) {
12147
12278
  );
12148
12279
  }
12149
12280
  async function sanitizeChromeProfile(userDataDir) {
12150
- if (!existsSync(userDataDir)) {
12151
- return;
12152
- }
12153
12281
  const entries = await readdir(userDataDir).catch(() => []);
12154
12282
  const profileDirs = entries.filter(
12155
12283
  (entry) => entry === "Default" || /^Profile \d+$/i.test(entry)
@@ -12158,9 +12286,6 @@ async function sanitizeChromeProfile(userDataDir) {
12158
12286
  }
12159
12287
  async function sanitizeProfilePreferences(userDataDir, profileDir) {
12160
12288
  const prefsPath = join(userDataDir, profileDir, "Preferences");
12161
- if (!existsSync(prefsPath)) {
12162
- return;
12163
- }
12164
12289
  try {
12165
12290
  const raw = await readFile(prefsPath, "utf8");
12166
12291
  const prefs = JSON.parse(raw);
@@ -12297,20 +12422,121 @@ function shouldCopyEntry(input) {
12297
12422
 
12298
12423
  // src/local-browser/stealth-init-script.ts
12299
12424
  function generateStealthInitScript(profile) {
12300
- const encodedProfile = JSON.stringify(profile);
12425
+ const encodedProfile = JSON.stringify({
12426
+ ...profile,
12427
+ platformString: getPlatformString(profile.platform),
12428
+ userAgentData: buildUserAgentData(profile)
12429
+ });
12301
12430
  return `(() => {
12302
12431
  const profile = ${encodedProfile};
12432
+ var define = function(target, key, value) {
12433
+ Object.defineProperty(target, key, {
12434
+ configurable: true,
12435
+ get: typeof value === 'function' ? value : function() { return value; },
12436
+ });
12437
+ };
12303
12438
 
12304
- // --- navigator.webdriver safety net ---
12305
- // --disable-blink-features=AutomationControlled handles this at the flag level
12306
- // and CDP handles it at the protocol level, but some Chrome builds still leak
12307
- // webdriver=true when --remote-debugging-port is active.
12439
+ // --- navigator / screen mirrors for future pages ---
12308
12440
  if (navigator.webdriver === true) {
12309
12441
  Object.defineProperty(Navigator.prototype, 'webdriver', {
12310
12442
  configurable: true,
12311
12443
  get: function() { return false; },
12312
12444
  });
12313
12445
  }
12446
+ define(Navigator.prototype, 'platform', profile.platformString);
12447
+ define(Navigator.prototype, 'userAgent', profile.userAgent);
12448
+ define(Navigator.prototype, 'language', profile.locale);
12449
+ define(Navigator.prototype, 'languages', [profile.locale, 'en']);
12450
+ define(Navigator.prototype, 'maxTouchPoints', profile.maxTouchPoints);
12451
+ define(window, 'devicePixelRatio', profile.devicePixelRatio);
12452
+ define(window.screen, 'width', profile.screenResolution.width);
12453
+ define(window.screen, 'height', profile.screenResolution.height);
12454
+ define(window.screen, 'availWidth', profile.screenResolution.width);
12455
+ define(window.screen, 'availHeight', profile.screenResolution.height - 40);
12456
+ define(window.screen, 'colorDepth', 24);
12457
+ define(window.screen, 'pixelDepth', 24);
12458
+ define(Navigator.prototype, 'userAgentData', {
12459
+ brands: profile.userAgentData.brands,
12460
+ mobile: false,
12461
+ platform: profile.userAgentData.platform,
12462
+ toJSON: function() {
12463
+ return {
12464
+ brands: this.brands,
12465
+ mobile: this.mobile,
12466
+ platform: this.platform,
12467
+ };
12468
+ },
12469
+ getHighEntropyValues: async function(hints) {
12470
+ var source = {
12471
+ architecture: profile.userAgentData.architecture,
12472
+ bitness: profile.userAgentData.bitness,
12473
+ brands: profile.userAgentData.brands,
12474
+ fullVersionList: profile.userAgentData.fullVersionList,
12475
+ mobile: false,
12476
+ model: '',
12477
+ platform: profile.userAgentData.platform,
12478
+ platformVersion: profile.userAgentData.platformVersion,
12479
+ uaFullVersion: profile.browserVersion,
12480
+ wow64: false,
12481
+ };
12482
+ var values = {};
12483
+ for (var i = 0; i < hints.length; i++) {
12484
+ var hint = hints[i];
12485
+ if (Object.prototype.hasOwnProperty.call(source, hint)) {
12486
+ values[hint] = source[hint];
12487
+ }
12488
+ }
12489
+ return values;
12490
+ },
12491
+ });
12492
+
12493
+ if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
12494
+ var originalResolvedOptions = Intl.DateTimeFormat.prototype.resolvedOptions;
12495
+ Intl.DateTimeFormat.prototype.resolvedOptions = function() {
12496
+ var options = originalResolvedOptions.call(this);
12497
+ options.timeZone = profile.timezoneId;
12498
+ return options;
12499
+ };
12500
+ }
12501
+
12502
+ if (Date.prototype.getTimezoneOffset) {
12503
+ var originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
12504
+ var calculateTimezoneOffset = function(date) {
12505
+ try {
12506
+ var formatter = new Intl.DateTimeFormat('en-US', {
12507
+ timeZone: profile.timezoneId,
12508
+ hour12: false,
12509
+ year: 'numeric',
12510
+ month: '2-digit',
12511
+ day: '2-digit',
12512
+ hour: '2-digit',
12513
+ minute: '2-digit',
12514
+ second: '2-digit',
12515
+ });
12516
+ var parts = formatter.formatToParts(date);
12517
+ var values = {};
12518
+ for (var i = 0; i < parts.length; i++) {
12519
+ if (parts[i].type !== 'literal') {
12520
+ values[parts[i].type] = Number(parts[i].value);
12521
+ }
12522
+ }
12523
+ var utcTime = Date.UTC(
12524
+ values.year,
12525
+ values.month - 1,
12526
+ values.day,
12527
+ values.hour,
12528
+ values.minute,
12529
+ values.second,
12530
+ );
12531
+ return Math.round((date.getTime() - utcTime) / 60000);
12532
+ } catch {
12533
+ return originalGetTimezoneOffset.call(date);
12534
+ }
12535
+ };
12536
+ Date.prototype.getTimezoneOffset = function() {
12537
+ return calculateTimezoneOffset(this);
12538
+ };
12539
+ }
12314
12540
 
12315
12541
  // --- CDP Runtime.enable leak defense ---
12316
12542
  var _wrap = function(name) {
@@ -12384,6 +12610,34 @@ function generateStealthInitScript(profile) {
12384
12610
  }
12385
12611
  })();`;
12386
12612
  }
12613
+ function buildUserAgentData(profile) {
12614
+ const majorVersion = profile.browserVersion.split(".")[0] ?? "136";
12615
+ const platformData = {
12616
+ macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12617
+ windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12618
+ linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12619
+ };
12620
+ const platformInfo = platformData[profile.platform];
12621
+ return {
12622
+ architecture: platformInfo.architecture,
12623
+ bitness: "64",
12624
+ brands: [
12625
+ { brand: "Chromium", version: majorVersion },
12626
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: majorVersion }] : [{ brand: "Google Chrome", version: majorVersion }],
12627
+ { brand: "Not-A.Brand", version: "99" }
12628
+ ],
12629
+ fullVersionList: [
12630
+ { brand: "Chromium", version: profile.browserVersion },
12631
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: profile.browserVersion }] : [{ brand: "Google Chrome", version: profile.browserVersion }],
12632
+ { brand: "Not-A.Brand", version: "99.0.0.0" }
12633
+ ],
12634
+ platform: platformInfo.platform,
12635
+ platformVersion: platformInfo.platformVersion
12636
+ };
12637
+ }
12638
+ function getPlatformString(platform) {
12639
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12640
+ }
12387
12641
 
12388
12642
  // src/local-browser/stealth.ts
12389
12643
  var STEALTH_INIT_SCRIPT = `(() => {
@@ -12427,8 +12681,9 @@ var STEALTH_INIT_SCRIPT = `(() => {
12427
12681
  ['debug', 'log', 'info', 'error', 'warn', 'trace', 'dir'].forEach(_wrap);
12428
12682
  })();`;
12429
12683
  async function injectBrowserStealthScripts(context, input = {}) {
12430
- if (input.profile !== void 0 && input.page !== void 0) {
12431
- await applyCdpStealthOverrides(context, input.page, input.profile);
12684
+ if (input.profile !== void 0) {
12685
+ await installContextNetworkHeaders(context, input.profile);
12686
+ await installCdpStealthOverrides(context, input.profile, input.page);
12432
12687
  }
12433
12688
  if (typeof context.addInitScript === "function") {
12434
12689
  await context.addInitScript({
@@ -12449,11 +12704,12 @@ function buildUserAgentMetadata(profile) {
12449
12704
  { brand: "Not-A.Brand", version: "99.0.0.0" }
12450
12705
  ];
12451
12706
  const platformMap = {
12707
+ // Chromium keeps the reduced macOS UA token frozen to Intel even on Apple Silicon.
12452
12708
  macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12453
12709
  windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12454
12710
  linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12455
12711
  };
12456
- const platformInfo = platformMap[profile.platform] ?? platformMap.linux;
12712
+ const platformInfo = platformMap[profile.platform];
12457
12713
  return {
12458
12714
  brands,
12459
12715
  fullVersionList,
@@ -12466,7 +12722,28 @@ function buildUserAgentMetadata(profile) {
12466
12722
  wow64: false
12467
12723
  };
12468
12724
  }
12469
- async function applyCdpStealthOverrides(context, page, profile) {
12725
+ async function installCdpStealthOverrides(context, profile, initialPage) {
12726
+ const pages = initialPage === void 0 ? context.pages() : Array.from(/* @__PURE__ */ new Set([initialPage, ...context.pages()]));
12727
+ await Promise.all(pages.map((page) => applyPageOverrides(context, page, profile)));
12728
+ const appliedPages = /* @__PURE__ */ new WeakSet();
12729
+ const applyFuturePageOverrides = async (page) => {
12730
+ if (appliedPages.has(page)) {
12731
+ return;
12732
+ }
12733
+ appliedPages.add(page);
12734
+ await applyPageOverrides(context, page, profile);
12735
+ };
12736
+ if (typeof context.on === "function") {
12737
+ context.on("page", applyFuturePageOverrides);
12738
+ }
12739
+ }
12740
+ async function installContextNetworkHeaders(context, profile) {
12741
+ if (typeof context.setExtraHTTPHeaders !== "function") {
12742
+ return;
12743
+ }
12744
+ await context.setExtraHTTPHeaders(buildStealthRequestHeaders(profile)).catch(() => void 0);
12745
+ }
12746
+ async function applyPageOverrides(context, page, profile) {
12470
12747
  const contextWithCdp = context;
12471
12748
  if (typeof contextWithCdp.newCDPSession !== "function") {
12472
12749
  return;
@@ -12478,31 +12755,50 @@ async function applyCdpStealthOverrides(context, page, profile) {
12478
12755
  return;
12479
12756
  }
12480
12757
  try {
12481
- const platformString = profile.platform === "macos" ? "MacIntel" : profile.platform === "windows" ? "Win32" : "Linux x86_64";
12482
- await cdp.send("Network.setUserAgentOverride", {
12483
- userAgent: profile.userAgent,
12484
- acceptLanguage: `${profile.locale},en;q=0.9`,
12485
- platform: platformString,
12486
- userAgentMetadata: buildUserAgentMetadata(profile)
12487
- });
12488
- await cdp.send("Emulation.setDeviceMetricsOverride", {
12489
- width: profile.viewport.width,
12490
- height: profile.viewport.height,
12491
- deviceScaleFactor: profile.devicePixelRatio,
12492
- mobile: false,
12493
- screenWidth: profile.screenResolution.width,
12494
- screenHeight: profile.screenResolution.height
12495
- });
12496
- await cdp.send("Emulation.setLocaleOverride", {
12497
- locale: profile.locale
12498
- }).catch(() => void 0);
12499
- await cdp.send("Emulation.setTimezoneOverride", {
12500
- timezoneId: profile.timezoneId
12501
- }).catch(() => void 0);
12502
- await cdp.detach();
12758
+ await applyCdpStealthCommands((method, params) => cdp.send(method, params), profile);
12503
12759
  } catch {
12760
+ } finally {
12761
+ await cdp.detach().catch(() => void 0);
12504
12762
  }
12505
12763
  }
12764
+ async function applyCdpStealthCommands(send, profile) {
12765
+ await send("Network.setUserAgentOverride", {
12766
+ userAgent: profile.userAgent,
12767
+ acceptLanguage: `${profile.locale},en;q=0.9`,
12768
+ platform: getPlatformString2(profile.platform),
12769
+ userAgentMetadata: buildUserAgentMetadata(profile)
12770
+ });
12771
+ await send("Emulation.setDeviceMetricsOverride", {
12772
+ width: profile.viewport.width,
12773
+ height: profile.viewport.height,
12774
+ deviceScaleFactor: profile.devicePixelRatio,
12775
+ mobile: false,
12776
+ screenWidth: profile.screenResolution.width,
12777
+ screenHeight: profile.screenResolution.height
12778
+ });
12779
+ await send("Emulation.setLocaleOverride", {
12780
+ locale: profile.locale
12781
+ }).catch(() => void 0);
12782
+ await send("Emulation.setTimezoneOverride", {
12783
+ timezoneId: profile.timezoneId
12784
+ }).catch(() => void 0);
12785
+ }
12786
+ function buildStealthRequestHeaders(profile) {
12787
+ const metadata = buildUserAgentMetadata(profile);
12788
+ return {
12789
+ "Accept-Language": `${profile.locale},en;q=0.9`,
12790
+ "Sec-CH-UA": metadata.brands.map(formatClientHintBrand).join(", "),
12791
+ "Sec-CH-UA-Mobile": "?0",
12792
+ "Sec-CH-UA-Platform": `"${metadata.platform}"`,
12793
+ "User-Agent": profile.userAgent
12794
+ };
12795
+ }
12796
+ function formatClientHintBrand(brand2) {
12797
+ return `"${brand2.brand}";v="${brand2.version}"`;
12798
+ }
12799
+ function getPlatformString2(platform) {
12800
+ return platform === "macos" ? "MacIntel" : platform === "windows" ? "Win32" : "Linux x86_64";
12801
+ }
12506
12802
 
12507
12803
  // src/local-browser/stealth-profiles.ts
12508
12804
  var PROFILE_PRESETS = [
@@ -12709,7 +13005,7 @@ var OpensteerBrowserManager = class {
12709
13005
  await this.closePersistentBrowser(workspace);
12710
13006
  await rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12711
13007
  await rm(workspace.browserPath, { recursive: true, force: true });
12712
- await rm(workspace.liveBrowserPath, { force: true });
13008
+ await clearPersistedSessionRecord(workspace.rootPath, "local");
12713
13009
  await ensureDirectory(workspace.browserUserDataDir);
12714
13010
  });
12715
13011
  }
@@ -12720,7 +13016,7 @@ var OpensteerBrowserManager = class {
12720
13016
  await this.closePersistentBrowser(workspace);
12721
13017
  await rm(resolveAbpSessionDir(workspace), { recursive: true, force: true });
12722
13018
  await rm(workspace.browserPath, { recursive: true, force: true });
12723
- await rm(workspace.liveBrowserPath, { force: true });
13019
+ await clearPersistedSessionRecord(workspace.rootPath, "local");
12724
13020
  });
12725
13021
  }
12726
13022
  async close() {
@@ -12798,12 +13094,12 @@ var OpensteerBrowserManager = class {
12798
13094
  sessionDir: resolveAbpSessionDir(workspace),
12799
13095
  ...launch?.browserExecutablePath === void 0 ? {} : { executablePath: launch.browserExecutablePath }
12800
13096
  };
12801
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13097
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12802
13098
  try {
12803
13099
  return await this.createAdoptedAbpEngine(liveRecord);
12804
13100
  } catch (error) {
12805
13101
  await terminateProcess(launched.process.pid ?? 0).catch(() => void 0);
12806
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13102
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
12807
13103
  throw error;
12808
13104
  }
12809
13105
  });
@@ -12886,7 +13182,7 @@ var OpensteerBrowserManager = class {
12886
13182
  executablePath: launched.executablePath,
12887
13183
  userDataDir: workspace.browserUserDataDir
12888
13184
  };
12889
- await writeJsonFileAtomic(workspace.liveBrowserPath, liveRecord);
13185
+ await this.writeLivePersistentBrowser(workspace, liveRecord);
12890
13186
  try {
12891
13187
  return await this.createAttachedEngine({
12892
13188
  endpoint: launched.endpoint,
@@ -12895,7 +13191,7 @@ var OpensteerBrowserManager = class {
12895
13191
  });
12896
13192
  } catch (error) {
12897
13193
  await terminateProcess(launched.pid).catch(() => void 0);
12898
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13194
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
12899
13195
  throw error;
12900
13196
  }
12901
13197
  });
@@ -12915,7 +13211,10 @@ var OpensteerBrowserManager = class {
12915
13211
  const stealthProfile = resolveStealthProfile(this.contextOptions?.stealthProfile);
12916
13212
  await injectBrowserStealthScripts(
12917
13213
  context,
12918
- stealthProfile === void 0 ? {} : { profile: stealthProfile, page }
13214
+ stealthProfile === void 0 ? {} : {
13215
+ profile: stealthProfile,
13216
+ page
13217
+ }
12919
13218
  );
12920
13219
  const engine = await createPlaywrightBrowserCoreEngine({
12921
13220
  browser,
@@ -12998,7 +13297,7 @@ var OpensteerBrowserManager = class {
12998
13297
  return void 0;
12999
13298
  }
13000
13299
  if (!isProcessRunning(live.pid)) {
13001
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13300
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13002
13301
  return void 0;
13003
13302
  }
13004
13303
  if (live.engine === "playwright") {
@@ -13017,19 +13316,8 @@ var OpensteerBrowserManager = class {
13017
13316
  return live;
13018
13317
  }
13019
13318
  async readStoredLiveBrowser(workspace) {
13020
- if (!await pathExists(workspace.liveBrowserPath)) {
13021
- return void 0;
13022
- }
13023
- const live = await readJsonFile(
13024
- workspace.liveBrowserPath
13025
- );
13026
- if (live.engine === "abp") {
13027
- return live;
13028
- }
13029
- return {
13030
- ...live,
13031
- engine: "playwright"
13032
- };
13319
+ const live = await readPersistedLocalBrowserSessionRecord(workspace.rootPath);
13320
+ return live === void 0 ? void 0 : toWorkspaceLiveBrowserRecord(live);
13033
13321
  }
13034
13322
  async resolveLivePersistentEngineName() {
13035
13323
  if (this.mode !== "persistent") {
@@ -13049,7 +13337,7 @@ var OpensteerBrowserManager = class {
13049
13337
  async closePersistentBrowser(workspace) {
13050
13338
  const live = await this.readStoredLiveBrowser(workspace);
13051
13339
  if (!live) {
13052
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13340
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13053
13341
  return;
13054
13342
  }
13055
13343
  if (live.engine === "playwright") {
@@ -13057,15 +13345,21 @@ var OpensteerBrowserManager = class {
13057
13345
  await requestBrowserClose(live.endpoint).catch(() => void 0);
13058
13346
  }
13059
13347
  if (await waitForProcessExit(live.pid, BROWSER_CLOSE_TIMEOUT_MS)) {
13060
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13348
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13061
13349
  return;
13062
13350
  }
13063
13351
  await terminateProcess(live.pid).catch(() => void 0);
13064
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13352
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13065
13353
  return;
13066
13354
  }
13067
13355
  await terminateProcess(live.pid).catch(() => void 0);
13068
- await rm(workspace.liveBrowserPath, { force: true }).catch(() => void 0);
13356
+ await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
13357
+ }
13358
+ async writeLivePersistentBrowser(workspace, live) {
13359
+ await writePersistedSessionRecord(
13360
+ workspace.rootPath,
13361
+ toPersistedLocalBrowserSessionRecord(this.workspace, live)
13362
+ );
13069
13363
  }
13070
13364
  requirePersistentMode(method) {
13071
13365
  if (this.mode !== "persistent" || this.workspace === void 0) {
@@ -13077,6 +13371,38 @@ function normalizeWorkspace(workspace) {
13077
13371
  const normalized = workspace?.trim();
13078
13372
  return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
13079
13373
  }
13374
+ function toPersistedLocalBrowserSessionRecord(workspace, live) {
13375
+ return {
13376
+ layout: "opensteer-session",
13377
+ version: 1,
13378
+ provider: "local",
13379
+ ...workspace === void 0 ? {} : { workspace },
13380
+ engine: live.engine,
13381
+ ...live.endpoint === void 0 ? {} : { endpoint: live.endpoint },
13382
+ ...live.baseUrl === void 0 ? {} : { baseUrl: live.baseUrl },
13383
+ ...live.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: live.remoteDebuggingUrl },
13384
+ ...live.sessionDir === void 0 ? {} : { sessionDir: live.sessionDir },
13385
+ pid: live.pid,
13386
+ startedAt: live.startedAt,
13387
+ updatedAt: Date.now(),
13388
+ ...live.executablePath === void 0 ? {} : { executablePath: live.executablePath },
13389
+ userDataDir: live.userDataDir
13390
+ };
13391
+ }
13392
+ function toWorkspaceLiveBrowserRecord(record) {
13393
+ return {
13394
+ mode: "persistent",
13395
+ engine: record.engine,
13396
+ ...record.endpoint === void 0 ? {} : { endpoint: record.endpoint },
13397
+ ...record.baseUrl === void 0 ? {} : { baseUrl: record.baseUrl },
13398
+ ...record.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: record.remoteDebuggingUrl },
13399
+ ...record.sessionDir === void 0 ? {} : { sessionDir: record.sessionDir },
13400
+ pid: record.pid,
13401
+ startedAt: record.startedAt,
13402
+ ...record.executablePath === void 0 ? {} : { executablePath: record.executablePath },
13403
+ userDataDir: record.userDataDir
13404
+ };
13405
+ }
13080
13406
  function resolveBrowserMode(workspace, browser) {
13081
13407
  if (browser === void 0) {
13082
13408
  return workspace === void 0 ? "temporary" : "persistent";
@@ -13156,9 +13482,7 @@ function buildChromeArgs(userDataDir, launch, viewport) {
13156
13482
  if (isHeadless) {
13157
13483
  args.push("--headless=new");
13158
13484
  }
13159
- const hasUserWindowSize = (launch?.args ?? []).some(
13160
- (entry) => entry.startsWith("--window-size")
13161
- );
13485
+ const hasUserWindowSize = (launch?.args ?? []).some((entry) => entry.startsWith("--window-size"));
13162
13486
  if (!hasUserWindowSize) {
13163
13487
  const width = viewport?.width ?? 1440;
13164
13488
  const height = viewport?.height ?? 900;
@@ -13356,7 +13680,7 @@ async function sleep(ms) {
13356
13680
  await new Promise((resolve5) => setTimeout(resolve5, ms));
13357
13681
  }
13358
13682
 
13359
- // src/sdk/semantic-dispatch.ts
13683
+ // ../runtime-core/src/sdk/semantic-dispatch.ts
13360
13684
  async function dispatchSemanticOperation(runtime, operation, input, options = {}) {
13361
13685
  switch (operation) {
13362
13686
  case "session.open":
@@ -13617,7 +13941,14 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
13617
13941
  }
13618
13942
  }
13619
13943
 
13620
- // src/internal/errors.ts
13944
+ // ../runtime-core/package.json
13945
+ var package_default = {
13946
+ version: "0.1.0"};
13947
+
13948
+ // ../runtime-core/src/version.ts
13949
+ var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
13950
+
13951
+ // ../runtime-core/src/internal/errors.ts
13621
13952
  function normalizeThrownOpensteerError(error, fallbackMessage) {
13622
13953
  if (isOpensteerProtocolError(error)) {
13623
13954
  return toOpensteerError(error);
@@ -13628,15 +13959,6 @@ function normalizeThrownOpensteerError(error, fallbackMessage) {
13628
13959
  ...error.details === void 0 ? {} : { details: error.details }
13629
13960
  });
13630
13961
  }
13631
- if (error instanceof OpensteerAttachAmbiguousError) {
13632
- return createOpensteerError("conflict", error.message, {
13633
- details: {
13634
- candidates: error.candidates,
13635
- code: error.code,
13636
- name: error.name
13637
- }
13638
- });
13639
- }
13640
13962
  if (error instanceof Error) {
13641
13963
  return createOpensteerError("operation-failed", error.message, {
13642
13964
  details: {
@@ -13806,7 +14128,7 @@ function roundScale(value) {
13806
14128
  return Number(value.toFixed(6));
13807
14129
  }
13808
14130
 
13809
- // src/runtimes/computer-use/trace-enrichment.ts
14131
+ // ../runtime-core/src/runtimes/computer-use/trace-enrichment.ts
13810
14132
  async function enrichComputerUseTrace(input) {
13811
14133
  const tracePoints = toTracePoints(input.action);
13812
14134
  if (tracePoints.length === 0) {
@@ -13899,7 +14221,7 @@ function toOpensteerResolvedTarget(target) {
13899
14221
  };
13900
14222
  }
13901
14223
 
13902
- // src/runtimes/computer-use/runtime.ts
14224
+ // ../runtime-core/src/runtimes/computer-use/runtime.ts
13903
14225
  function createComputerUseRuntime(options) {
13904
14226
  return new DefaultComputerUseRuntime(options);
13905
14227
  }
@@ -13994,7 +14316,7 @@ function normalizeScreenshotOptions(input) {
13994
14316
  };
13995
14317
  }
13996
14318
 
13997
- // src/requests/shared.ts
14319
+ // ../runtime-core/src/requests/shared.ts
13998
14320
  var REDACTED_HEADER_VALUE = "[redacted]";
13999
14321
  var HTTP_HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
14000
14322
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
@@ -14210,14 +14532,14 @@ function resolveTextEncoding(charset) {
14210
14532
  }
14211
14533
  }
14212
14534
 
14213
- // src/requests/errors.ts
14535
+ // ../runtime-core/src/requests/errors.ts
14214
14536
  function invalidRequestPlanError(message, details = {}) {
14215
14537
  return new OpensteerProtocolError("invalid-request", message, {
14216
14538
  details
14217
14539
  });
14218
14540
  }
14219
14541
 
14220
- // src/requests/plans/index.ts
14542
+ // ../runtime-core/src/requests/plans/index.ts
14221
14543
  var HTTP_METHOD_PATTERN = /^[A-Za-z]+$/;
14222
14544
  var URL_TEMPLATE_PLACEHOLDER_PATTERN = /\{([A-Za-z][A-Za-z0-9_-]*)\}/g;
14223
14545
  function assertValidRequestPlanPayload(payload) {
@@ -14625,7 +14947,7 @@ function normalizeTrimmedString(field, value) {
14625
14947
  return normalized;
14626
14948
  }
14627
14949
 
14628
- // src/requests/inference.ts
14950
+ // ../runtime-core/src/requests/inference.ts
14629
14951
  function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14630
14952
  const url = new URL(record.record.url);
14631
14953
  const defaultQuery = Array.from(url.searchParams.entries()).map(
@@ -14638,9 +14960,10 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14638
14960
  const responseContentType = headerValue(record.record.responseHeaders, "content-type") ?? record.record.responseBody?.mimeType;
14639
14961
  const defaultHeaders = inferDefaultHeaders(record);
14640
14962
  const auth = inferAuth(record.record.requestHeaders);
14963
+ const body = inferRequestPlanBody(record.record.requestBody, requestContentType);
14641
14964
  const payload = normalizeRequestPlanPayload({
14642
14965
  transport: {
14643
- kind: "context-http"
14966
+ kind: input.transport ?? "context-http"
14644
14967
  },
14645
14968
  endpoint: {
14646
14969
  method: record.record.method,
@@ -14648,12 +14971,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14648
14971
  ...defaultQuery.length === 0 ? {} : { defaultQuery },
14649
14972
  ...defaultHeaders.length === 0 ? {} : { defaultHeaders }
14650
14973
  },
14651
- ...requestContentType === void 0 && record.record.requestBody === void 0 ? {} : {
14652
- body: {
14653
- ...requestContentType === void 0 ? {} : { contentType: requestContentType },
14654
- required: true
14655
- }
14656
- },
14974
+ ...body === void 0 ? {} : { body },
14657
14975
  ...record.record.status === void 0 ? {} : {
14658
14976
  response: {
14659
14977
  status: record.record.status,
@@ -14665,7 +14983,6 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
14665
14983
  return {
14666
14984
  key: input.key,
14667
14985
  version: input.version,
14668
- lifecycle: input.lifecycle ?? "draft",
14669
14986
  provenance: {
14670
14987
  source: record.source === "saved" ? "saved-network-record" : "live-network-record",
14671
14988
  sourceId: record.recordId,
@@ -14709,22 +15026,66 @@ function inferAuth(headers) {
14709
15026
  }
14710
15027
  return void 0;
14711
15028
  }
14712
-
14713
- // src/reverse/materialization.ts
14714
- var ALWAYS_OMIT_HEADER_NAMES = /* @__PURE__ */ new Set(["content-length", "host", "priority"]);
14715
- var BROWSER_OWNED_HEADER_PREFIXES = ["sec-"];
14716
- function isManagedRequestHeaderName(name, transport) {
14717
- const normalized = normalizeHeaderName(name);
14718
- if (!isValidHttpHeaderName(name)) {
14719
- return true;
15029
+ function inferRequestPlanBody(body, contentType) {
15030
+ if (body === void 0) {
15031
+ return void 0;
14720
15032
  }
14721
- if (normalized.startsWith(":")) {
14722
- return true;
15033
+ const text = Buffer.from(body.data, "base64").toString("utf8");
15034
+ const normalizedContentType = contentType?.toLowerCase();
15035
+ const trimmedText = text.trim();
15036
+ const parsedJson = parseJsonBody(trimmedText);
15037
+ if (normalizedContentType?.includes("application/json") === true || normalizedContentType?.includes("+json") === true || parsedJson !== void 0) {
15038
+ return {
15039
+ kind: "json",
15040
+ required: true,
15041
+ ...contentType === void 0 ? {} : { contentType },
15042
+ template: parsedJson ?? text
15043
+ };
14723
15044
  }
14724
- if (ALWAYS_OMIT_HEADER_NAMES.has(normalized)) {
14725
- return true;
15045
+ if (normalizedContentType?.includes("application/x-www-form-urlencoded") === true) {
15046
+ return {
15047
+ kind: "form",
15048
+ required: true,
15049
+ ...contentType === void 0 ? {} : { contentType },
15050
+ fields: Array.from(new URLSearchParams(text).entries()).map(([name, value]) => ({
15051
+ name,
15052
+ value
15053
+ }))
15054
+ };
14726
15055
  }
14727
- if (transport !== void 0 && (transport === "page-http" || transport === "session-http")) {
15056
+ return {
15057
+ kind: "text",
15058
+ required: true,
15059
+ ...contentType === void 0 ? {} : { contentType },
15060
+ template: text
15061
+ };
15062
+ }
15063
+ function parseJsonBody(value) {
15064
+ if (value.length === 0 || !value.startsWith("{") && !value.startsWith("[")) {
15065
+ return void 0;
15066
+ }
15067
+ try {
15068
+ return JSON.parse(value);
15069
+ } catch {
15070
+ return void 0;
15071
+ }
15072
+ }
15073
+
15074
+ // ../runtime-core/src/reverse/materialization.ts
15075
+ var ALWAYS_OMIT_HEADER_NAMES = /* @__PURE__ */ new Set(["content-length", "host", "priority"]);
15076
+ var BROWSER_OWNED_HEADER_PREFIXES = ["sec-"];
15077
+ function isManagedRequestHeaderName(name, transport) {
15078
+ const normalized = normalizeHeaderName(name);
15079
+ if (!isValidHttpHeaderName(name)) {
15080
+ return true;
15081
+ }
15082
+ if (normalized.startsWith(":")) {
15083
+ return true;
15084
+ }
15085
+ if (ALWAYS_OMIT_HEADER_NAMES.has(normalized)) {
15086
+ return true;
15087
+ }
15088
+ if (transport !== void 0 && (transport === "page-http" || transport === "session-http")) {
14728
15089
  if (BROWSER_OWNED_HEADER_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
14729
15090
  return true;
14730
15091
  }
@@ -14746,7 +15107,7 @@ function finalizeMaterializedTransportRequest(request, transport) {
14746
15107
  };
14747
15108
  }
14748
15109
 
14749
- // src/network/diff.ts
15110
+ // ../runtime-core/src/network/diff.ts
14750
15111
  function diffNetworkRecords(left, right, input) {
14751
15112
  const requestDiffs = [];
14752
15113
  const responseDiffs = [];
@@ -14906,7 +15267,7 @@ function diffStringMap(prefix, left, right, includeUnchanged, output) {
14906
15267
  diffScalarField(`${prefix}.${key}`, left[key], right[key], includeUnchanged, output);
14907
15268
  }
14908
15269
  }
14909
- function diffScalarField(path11, left, right, includeUnchanged, output) {
15270
+ function diffScalarField(path13, left, right, includeUnchanged, output) {
14910
15271
  const leftValue = stringifyFieldValue(left);
14911
15272
  const rightValue = stringifyFieldValue(right);
14912
15273
  const kind = leftValue === void 0 ? rightValue === void 0 ? "unchanged" : "added" : rightValue === void 0 ? "removed" : leftValue === rightValue ? "unchanged" : "changed";
@@ -14914,7 +15275,7 @@ function diffScalarField(path11, left, right, includeUnchanged, output) {
14914
15275
  return;
14915
15276
  }
14916
15277
  output.push({
14917
- path: path11,
15278
+ path: path13,
14918
15279
  kind,
14919
15280
  ...leftValue === void 0 ? {} : { leftValue },
14920
15281
  ...rightValue === void 0 ? {} : { rightValue },
@@ -15103,7 +15464,7 @@ var NetworkJournal = class {
15103
15464
  }
15104
15465
  };
15105
15466
 
15106
- // src/network/minimize.ts
15467
+ // ../runtime-core/src/network/minimize.ts
15107
15468
  function prepareMinimizationRequest(record, preserve = []) {
15108
15469
  const requestUrl = new URL(record.record.url);
15109
15470
  const preservedNames = new Set(
@@ -15516,7 +15877,7 @@ function resolveBodyEncoding2(charset) {
15516
15877
  }
15517
15878
  }
15518
15879
 
15519
- // src/network/probe.ts
15880
+ // ../runtime-core/src/network/probe.ts
15520
15881
  var TRANSPORT_PROBE_LADDER = [
15521
15882
  "direct-http",
15522
15883
  "matched-tls",
@@ -15528,7 +15889,7 @@ function selectTransportProbeRecommendation(results) {
15528
15889
  return results.find((entry) => entry.success)?.transport ?? results.at(-1)?.transport ?? "session-http";
15529
15890
  }
15530
15891
 
15531
- // src/reverse/analysis.ts
15892
+ // ../runtime-core/src/reverse/analysis.ts
15532
15893
  var TELEMETRY_HOST_PATTERNS = [
15533
15894
  "google-analytics",
15534
15895
  "doubleclick",
@@ -15868,9 +16229,9 @@ function matchReverseTargetHints(channel, codec, targetHints) {
15868
16229
  matches.add(`host:${host}`);
15869
16230
  }
15870
16231
  }
15871
- for (const path11 of targetHints.paths ?? []) {
15872
- if (url.pathname.includes(path11)) {
15873
- matches.add(`path:${path11}`);
16232
+ for (const path13 of targetHints.paths ?? []) {
16233
+ if (url.pathname.includes(path13)) {
16234
+ matches.add(`path:${path13}`);
15874
16235
  }
15875
16236
  }
15876
16237
  for (const operationName of targetHints.operationNames ?? []) {
@@ -16722,7 +17083,7 @@ function looksHighEntropy(value) {
16722
17083
  return uniqueCharacters >= Math.min(20, Math.floor(trimmed.length * 0.6));
16723
17084
  }
16724
17085
 
16725
- // src/reverse/discovery.ts
17086
+ // ../runtime-core/src/reverse/discovery.ts
16726
17087
  function clusterReverseObservationRecords(input) {
16727
17088
  const groups = /* @__PURE__ */ new Map();
16728
17089
  for (const item of sortClusterableRecords(input.records)) {
@@ -17029,7 +17390,7 @@ async function readDirSafe(directory) {
17029
17390
  }
17030
17391
  }
17031
17392
 
17032
- // src/reverse/validation.ts
17393
+ // ../runtime-core/src/reverse/validation.ts
17033
17394
  function buildReverseValidationRules(input) {
17034
17395
  switch (input.channel.kind) {
17035
17396
  case "http":
@@ -17306,7 +17667,7 @@ function jsonStructureShape(value) {
17306
17667
  return typeof value;
17307
17668
  }
17308
17669
 
17309
- // src/reverse/workflows.ts
17670
+ // ../runtime-core/src/reverse/workflows.ts
17310
17671
  function buildReversePackageWorkflow(input) {
17311
17672
  if (input.template === void 0 && input.executeStepInput === void 0) {
17312
17673
  return [];
@@ -17675,7 +18036,7 @@ function dedupeSuggestedEdits(suggestions) {
17675
18036
  return [...new Map(suggestions.map((suggestion) => [suggestion.id, suggestion])).values()];
17676
18037
  }
17677
18038
 
17678
- // src/sdk/extraction-data-path.ts
18039
+ // ../runtime-core/src/sdk/extraction-data-path.ts
17679
18040
  function joinDataPath(base, key) {
17680
18041
  const normalizedBase = base.trim();
17681
18042
  const normalizedKey = key.trim();
@@ -17706,8 +18067,8 @@ function encodeDataPath(tokens) {
17706
18067
  }
17707
18068
  return out;
17708
18069
  }
17709
- function parseDataPath(path11) {
17710
- const input = path11.trim();
18070
+ function parseDataPath(path13) {
18071
+ const input = path13.trim();
17711
18072
  if (input.length === 0) {
17712
18073
  return [];
17713
18074
  }
@@ -17757,8 +18118,8 @@ function parseDataPath(path11) {
17757
18118
  function inflateDataPathObject(flat) {
17758
18119
  let root = {};
17759
18120
  let initialized = false;
17760
- for (const [path11, value] of Object.entries(flat)) {
17761
- const tokens = parseDataPath(path11);
18121
+ for (const [path13, value] of Object.entries(flat)) {
18122
+ const tokens = parseDataPath(path13);
17762
18123
  if (!tokens || tokens.length === 0) {
17763
18124
  continue;
17764
18125
  }
@@ -17816,7 +18177,7 @@ function assignDataPathValue(root, tokens, value) {
17816
18177
  }
17817
18178
  }
17818
18179
 
17819
- // src/sdk/extraction-consolidation.ts
18180
+ // ../runtime-core/src/sdk/extraction-consolidation.ts
17820
18181
  var STRUCTURAL_ATTR_KEYS = /* @__PURE__ */ new Set([
17821
18182
  "class",
17822
18183
  "role",
@@ -18090,8 +18451,8 @@ function buildVariantDescriptorFromCluster(descriptors) {
18090
18451
  fields: mergedFields
18091
18452
  };
18092
18453
  }
18093
- function minimizePathMatchClauses(path11, mode) {
18094
- const normalized = sanitizeElementPath(path11);
18454
+ function minimizePathMatchClauses(path13, mode) {
18455
+ const normalized = sanitizeElementPath(path13);
18095
18456
  const nodes = normalized.nodes.map((node, index) => {
18096
18457
  const isLast = index === normalized.nodes.length - 1;
18097
18458
  const attrs = node.attrs || {};
@@ -18195,8 +18556,8 @@ function seedMinimalAttrClause(attrs) {
18195
18556
  }
18196
18557
  return null;
18197
18558
  }
18198
- function relaxPathForSingleSample(path11, mode) {
18199
- const normalized = sanitizeElementPath(path11);
18559
+ function relaxPathForSingleSample(path13, mode) {
18560
+ const normalized = sanitizeElementPath(path13);
18200
18561
  const relaxedNodes = normalized.nodes.map((node, index) => {
18201
18562
  const isLast = index === normalized.nodes.length - 1;
18202
18563
  const attrs = normalizeAttrsForSingleSample(node.attrs || {});
@@ -18281,8 +18642,8 @@ function shouldKeepAttrForSingleSample(key) {
18281
18642
  }
18282
18643
  return true;
18283
18644
  }
18284
- function buildPathStructureKey(path11) {
18285
- const normalized = sanitizeElementPath(path11);
18645
+ function buildPathStructureKey(path13) {
18646
+ const normalized = sanitizeElementPath(path13);
18286
18647
  return canonicalJsonString({
18287
18648
  context: (normalized.context || []).map((hop) => ({
18288
18649
  kind: hop.kind,
@@ -18409,30 +18770,30 @@ function buildArrayItemNode(fields) {
18409
18770
  }
18410
18771
  return node;
18411
18772
  }
18412
- function insertNodeAtPath(root, path11, node) {
18413
- const tokens = parseDataPath(path11);
18773
+ function insertNodeAtPath(root, path13, node) {
18774
+ const tokens = parseDataPath(path13);
18414
18775
  if (!tokens || !tokens.length) {
18415
18776
  throw new Error(
18416
- `Invalid persisted extraction path "${path11}": expected a non-empty object path.`
18777
+ `Invalid persisted extraction path "${path13}": expected a non-empty object path.`
18417
18778
  );
18418
18779
  }
18419
18780
  if (tokens.some((token) => token.kind === "index")) {
18420
18781
  throw new Error(
18421
- `Invalid persisted extraction path "${path11}": nested array indices are not supported in cached descriptors.`
18782
+ `Invalid persisted extraction path "${path13}": nested array indices are not supported in cached descriptors.`
18422
18783
  );
18423
18784
  }
18424
18785
  let current = root;
18425
18786
  for (let index = 0; index < tokens.length; index += 1) {
18426
18787
  const token = tokens[index];
18427
18788
  if (!token || token.kind !== "prop") {
18428
- throw new Error(`Invalid persisted extraction path "${path11}": expected object segment.`);
18789
+ throw new Error(`Invalid persisted extraction path "${path13}": expected object segment.`);
18429
18790
  }
18430
18791
  const isLast = index === tokens.length - 1;
18431
18792
  if (isLast) {
18432
18793
  const existing = current[token.key];
18433
18794
  if (existing) {
18434
18795
  throw new Error(
18435
- `Conflicting persisted extraction path "${path11}" detected while building descriptor tree.`
18796
+ `Conflicting persisted extraction path "${path13}" detected while building descriptor tree.`
18436
18797
  );
18437
18798
  }
18438
18799
  current[token.key] = node;
@@ -18447,7 +18808,7 @@ function insertNodeAtPath(root, path11, node) {
18447
18808
  }
18448
18809
  if (!isPersistedObjectNode(next)) {
18449
18810
  throw new Error(
18450
- `Conflicting persisted extraction path "${path11}" detected at "${token.key}".`
18811
+ `Conflicting persisted extraction path "${path13}" detected at "${token.key}".`
18451
18812
  );
18452
18813
  }
18453
18814
  current = next;
@@ -18482,7 +18843,7 @@ function buildItemRootForArrayIndex(entries) {
18482
18843
  }
18483
18844
  const paths = entries.map(
18484
18845
  (entry) => isPersistablePathField(entry.source) ? sanitizeElementPath(entry.source.path) : null
18485
- ).filter((path11) => path11 !== null);
18846
+ ).filter((path13) => path13 !== null);
18486
18847
  if (!paths.length) {
18487
18848
  return null;
18488
18849
  }
@@ -18503,7 +18864,7 @@ function getCommonPathPrefixLength(paths) {
18503
18864
  if (!paths.length) {
18504
18865
  return 0;
18505
18866
  }
18506
- const nodeChains = paths.map((path11) => path11.nodes);
18867
+ const nodeChains = paths.map((path13) => path13.nodes);
18507
18868
  const minLength = Math.min(...nodeChains.map((nodes) => nodes.length));
18508
18869
  if (!Number.isFinite(minLength) || minLength <= 0) {
18509
18870
  return 0;
@@ -18572,30 +18933,30 @@ function mergeElementPathsByMajority(paths) {
18572
18933
  if (!paths.length) {
18573
18934
  return null;
18574
18935
  }
18575
- const normalized = paths.map((path11) => sanitizeElementPath(path11));
18936
+ const normalized = paths.map((path13) => sanitizeElementPath(path13));
18576
18937
  const contextKey = pickModeString(
18577
- normalized.map((path11) => canonicalJsonString(path11.context)),
18938
+ normalized.map((path13) => canonicalJsonString(path13.context)),
18578
18939
  1
18579
18940
  );
18580
18941
  if (!contextKey) {
18581
18942
  return null;
18582
18943
  }
18583
- const sameContext = normalized.filter((path11) => canonicalJsonString(path11.context) === contextKey);
18944
+ const sameContext = normalized.filter((path13) => canonicalJsonString(path13.context) === contextKey);
18584
18945
  if (!sameContext.length) {
18585
18946
  return null;
18586
18947
  }
18587
18948
  const targetLength = pickModeNumber(
18588
- sameContext.map((path11) => path11.nodes.length),
18949
+ sameContext.map((path13) => path13.nodes.length),
18589
18950
  1
18590
18951
  ) ?? sameContext[0]?.nodes.length ?? 0;
18591
- const aligned = sameContext.filter((path11) => path11.nodes.length === targetLength);
18952
+ const aligned = sameContext.filter((path13) => path13.nodes.length === targetLength);
18592
18953
  if (!aligned.length) {
18593
18954
  return null;
18594
18955
  }
18595
18956
  const threshold = majorityThreshold(aligned.length);
18596
18957
  const nodes = [];
18597
18958
  for (let index = 0; index < targetLength; index += 1) {
18598
- const nodesAtIndex = aligned.map((path11) => path11.nodes[index]).filter((node) => node !== void 0);
18959
+ const nodesAtIndex = aligned.map((path13) => path13.nodes[index]).filter((node) => node !== void 0);
18599
18960
  if (!nodesAtIndex.length) {
18600
18961
  return null;
18601
18962
  }
@@ -18841,8 +19202,8 @@ function clonePathContext(context) {
18841
19202
  function clonePathNodes(nodes) {
18842
19203
  return JSON.parse(JSON.stringify(nodes || []));
18843
19204
  }
18844
- function cloneElementPath2(path11) {
18845
- return JSON.parse(JSON.stringify(path11));
19205
+ function cloneElementPath2(path13) {
19206
+ return JSON.parse(JSON.stringify(path13));
18846
19207
  }
18847
19208
  function clonePersistedOpensteerExtractionNode(node) {
18848
19209
  return JSON.parse(JSON.stringify(node));
@@ -18863,7 +19224,7 @@ function isPersistedObjectNode(node) {
18863
19224
  return !!node && typeof node === "object" && !Array.isArray(node) && !isPersistedOpensteerExtractionValueNode(node) && !isPersistedOpensteerExtractionSourceNode(node) && !isPersistedOpensteerExtractionArrayNode(node);
18864
19225
  }
18865
19226
 
18866
- // src/sdk/extraction.ts
19227
+ // ../runtime-core/src/sdk/extraction.ts
18867
19228
  function assertValidOpensteerExtractionSchemaRoot(schema) {
18868
19229
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
18869
19230
  throw new Error("Invalid extraction schema: expected a JSON object at the top level.");
@@ -18950,7 +19311,7 @@ async function replayOpensteerExtractionPayload(options) {
18950
19311
  return extractPersistedObjectNode(options.pageRef, options.dom, options.payload);
18951
19312
  }
18952
19313
  function createOpensteerExtractionDescriptorStore(options) {
18953
- const namespace = normalizeNamespace2(options.namespace);
19314
+ const namespace = normalizeNamespace(options.namespace);
18954
19315
  if (options.root) {
18955
19316
  return new FilesystemOpensteerExtractionDescriptorStore(
18956
19317
  options.root.registry.descriptors,
@@ -19128,12 +19489,12 @@ async function resolvePersistableFieldTargets(options) {
19128
19489
  anchor: field.anchor
19129
19490
  }
19130
19491
  });
19131
- const path11 = resolved.replayPath ?? await options.dom.buildPath({
19492
+ const path13 = resolved.replayPath ?? await options.dom.buildPath({
19132
19493
  locator: resolved.locator
19133
19494
  });
19134
19495
  fields.push({
19135
19496
  key: field.key,
19136
- path: sanitizeElementPath(path11),
19497
+ path: sanitizeElementPath(path13),
19137
19498
  ...field.attribute === void 0 ? {} : { attribute: field.attribute }
19138
19499
  });
19139
19500
  }
@@ -19216,8 +19577,8 @@ function collectPersistedValueNodeRefs(node) {
19216
19577
  return [
19217
19578
  {
19218
19579
  path: sanitizeElementPath(node.$path),
19219
- replacePath: (path11) => {
19220
- node.$path = sanitizeElementPath(path11);
19580
+ replacePath: (path13) => {
19581
+ node.$path = sanitizeElementPath(path13);
19221
19582
  }
19222
19583
  }
19223
19584
  ];
@@ -19231,13 +19592,13 @@ function collectPersistedValueNodeRefs(node) {
19231
19592
  }
19232
19593
  return refs;
19233
19594
  }
19234
- function hasPositionClause(path11) {
19235
- return path11.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19595
+ function hasPositionClause(path13) {
19596
+ return path13.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
19236
19597
  }
19237
- function stripPositionClauses2(path11) {
19598
+ function stripPositionClauses2(path13) {
19238
19599
  return sanitizeElementPath({
19239
- context: path11.context,
19240
- nodes: path11.nodes.map((node) => ({
19600
+ context: path13.context,
19601
+ nodes: path13.nodes.map((node) => ({
19241
19602
  ...node,
19242
19603
  match: node.match.filter((clause) => clause.kind !== "position")
19243
19604
  }))
@@ -19447,11 +19808,11 @@ function normalizeSchemaField(value) {
19447
19808
  ...attribute === void 0 ? {} : { attribute }
19448
19809
  };
19449
19810
  }
19450
- function normalizeNamespace2(namespace) {
19811
+ function normalizeNamespace(namespace) {
19451
19812
  const normalized = String(namespace ?? "default").trim();
19452
19813
  return normalized.length === 0 ? "default" : normalized;
19453
19814
  }
19454
- function descriptionKey2(namespace, description) {
19815
+ function descriptionKey(namespace, description) {
19455
19816
  return `extract:${namespace}:${sha256Hex3(description.trim())}`;
19456
19817
  }
19457
19818
  function parseExtractionDescriptorRecord(record) {
@@ -19554,7 +19915,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
19554
19915
  }
19555
19916
  async read(input) {
19556
19917
  const record = await this.registry.resolve({
19557
- key: descriptionKey2(this.namespace, input.description)
19918
+ key: descriptionKey(this.namespace, input.description)
19558
19919
  });
19559
19920
  return record === void 0 ? void 0 : parseExtractionDescriptorRecord(record);
19560
19921
  }
@@ -19566,7 +19927,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
19566
19927
  ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
19567
19928
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
19568
19929
  };
19569
- const key = descriptionKey2(this.namespace, input.description);
19930
+ const key = descriptionKey(this.namespace, input.description);
19570
19931
  const version = sha256Hex3(canonicalJsonString(payload));
19571
19932
  const existing = await this.registry.resolve({ key, version });
19572
19933
  if (existing) {
@@ -19605,7 +19966,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
19605
19966
  latestByKey = /* @__PURE__ */ new Map();
19606
19967
  recordsByKey = /* @__PURE__ */ new Map();
19607
19968
  async read(input) {
19608
- return this.latestByKey.get(descriptionKey2(this.namespace, input.description));
19969
+ return this.latestByKey.get(descriptionKey(this.namespace, input.description));
19609
19970
  }
19610
19971
  async write(input) {
19611
19972
  const payload = {
@@ -19615,7 +19976,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
19615
19976
  ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
19616
19977
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
19617
19978
  };
19618
- const key = descriptionKey2(this.namespace, input.description);
19979
+ const key = descriptionKey(this.namespace, input.description);
19619
19980
  const version = sha256Hex3(canonicalJsonString(payload));
19620
19981
  const existing = this.recordsByKey.get(key)?.get(version);
19621
19982
  if (existing) {
@@ -19647,18 +20008,19 @@ function normalizeNonEmptyString2(name, value) {
19647
20008
  function normalizeKey(value) {
19648
20009
  return String(value ?? "").trim();
19649
20010
  }
19650
- function labelForPath(path11) {
19651
- return path11.trim().length === 0 ? "$" : path11;
20011
+ function labelForPath(path13) {
20012
+ return path13.trim().length === 0 ? "$" : path13;
19652
20013
  }
19653
20014
  function sha256Hex3(value) {
19654
20015
  return createHash("sha256").update(value).digest("hex");
19655
20016
  }
19656
20017
 
19657
- // src/sdk/snapshot/constants.ts
20018
+ // ../runtime-core/src/sdk/snapshot/constants.ts
19658
20019
  var OPENSTEER_INTERACTIVE_ATTR = "data-opensteer-interactive";
19659
20020
  var OPENSTEER_HIDDEN_ATTR = "data-opensteer-hidden";
19660
20021
  var OPENSTEER_SCROLLABLE_ATTR = "data-opensteer-scrollable";
19661
20022
  var OPENSTEER_NODE_ID_ATTR = "data-os-node-id";
20023
+ var OPENSTEER_SPARSE_COUNTER_ATTR = "data-os-c";
19662
20024
  var OPENSTEER_BOUNDARY_ATTR = "data-os-boundary";
19663
20025
  var OPENSTEER_UNAVAILABLE_ATTR = "data-os-unavailable";
19664
20026
  var OPENSTEER_IFRAME_BOUNDARY_TAG = "os-iframe-root";
@@ -19722,7 +20084,7 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
19722
20084
  "wbr"
19723
20085
  ]);
19724
20086
 
19725
- // src/sdk/snapshot/cleaner.ts
20087
+ // ../runtime-core/src/sdk/snapshot/cleaner.ts
19726
20088
  var STRIP_TAGS = /* @__PURE__ */ new Set(["script", "style", "noscript", "meta", "link", "template"]);
19727
20089
  var TEXT_ATTR_MAX = 150;
19728
20090
  var URL_ATTR_MAX = 500;
@@ -20162,8 +20524,83 @@ var VOID_TAGS2 = /* @__PURE__ */ new Set([
20162
20524
  "wbr"
20163
20525
  ]);
20164
20526
 
20165
- // src/sdk/snapshot/compiler.ts
20527
+ // ../runtime-core/src/sdk/snapshot/compiler.ts
20528
+ async function assignSparseCountersToLiveDom(engine, pageRef) {
20529
+ try {
20530
+ await engine.evaluatePage({
20531
+ pageRef,
20532
+ script: `(() => {
20533
+ let counter = 1;
20534
+ const walk = (root) => {
20535
+ for (const child of root.children) {
20536
+ child.setAttribute('data-os-c', String(counter++));
20537
+ walk(child);
20538
+ if (child.shadowRoot) walk(child.shadowRoot);
20539
+ }
20540
+ };
20541
+ walk(document);
20542
+ })()`
20543
+ });
20544
+ return true;
20545
+ } catch {
20546
+ return false;
20547
+ }
20548
+ }
20549
+ async function syncDenseCountersToLiveDom(engine, pageRef, sparseToDirectMapping) {
20550
+ const mappingObj = Object.fromEntries(sparseToDirectMapping);
20551
+ await engine.evaluatePage({
20552
+ pageRef,
20553
+ script: `((mapping) => {
20554
+ const walk = (root) => {
20555
+ for (const child of root.children) {
20556
+ child.removeAttribute('c');
20557
+ const sparse = child.getAttribute('data-os-c');
20558
+ if (sparse !== null) {
20559
+ const dense = mapping[sparse];
20560
+ if (dense !== undefined) {
20561
+ child.setAttribute('c', String(dense));
20562
+ }
20563
+ child.removeAttribute('data-os-c');
20564
+ }
20565
+ walk(child);
20566
+ if (child.shadowRoot) walk(child.shadowRoot);
20567
+ }
20568
+ };
20569
+ walk(document);
20570
+ })`,
20571
+ args: [mappingObj]
20572
+ });
20573
+ }
20574
+ function renumberCountersDensely(cleanedHtml, counterRecords) {
20575
+ const $ = cheerio.load(cleanedHtml, { xmlMode: false });
20576
+ const newRecords = /* @__PURE__ */ new Map();
20577
+ const sparseToDirectMapping = /* @__PURE__ */ new Map();
20578
+ let nextDense = 1;
20579
+ $("[c]").each(function renumberElement() {
20580
+ const el = $(this);
20581
+ const oldC = Number.parseInt(String(el.attr("c") || ""), 10);
20582
+ if (!Number.isFinite(oldC)) {
20583
+ return;
20584
+ }
20585
+ const record = counterRecords.get(oldC);
20586
+ if (!record) {
20587
+ return;
20588
+ }
20589
+ const denseC = nextDense++;
20590
+ el.attr("c", String(denseC));
20591
+ newRecords.set(denseC, { ...record, element: denseC });
20592
+ if (record.sparseCounter !== void 0) {
20593
+ sparseToDirectMapping.set(record.sparseCounter, denseC);
20594
+ }
20595
+ });
20596
+ return {
20597
+ html: $.html(),
20598
+ counterRecords: newRecords,
20599
+ sparseToDirectMapping
20600
+ };
20601
+ }
20166
20602
  async function compileOpensteerSnapshot(options) {
20603
+ const liveCountersEnabled = await assignSparseCountersToLiveDom(options.engine, options.pageRef);
20167
20604
  const pageInfo = await options.engine.getPageInfo({ pageRef: options.pageRef });
20168
20605
  const mainSnapshot = await getMainDocumentSnapshot(options.engine, options.pageRef);
20169
20606
  const snapshotsByDocumentRef = await collectDocumentSnapshots(options.engine, mainSnapshot);
@@ -20182,13 +20619,24 @@ async function compileOpensteerSnapshot(options) {
20182
20619
  const compiledHtml = assignCounters(rawHtml, renderedNodes);
20183
20620
  const cleanedHtml = options.mode === "extraction" ? cleanForExtraction(compiledHtml.html) : cleanForAction(compiledHtml.html);
20184
20621
  const filtered = retainVisibleCounterRecords(cleanedHtml, compiledHtml.counterRecords);
20622
+ const dense = renumberCountersDensely(cleanedHtml, filtered);
20623
+ if (liveCountersEnabled && dense.sparseToDirectMapping.size > 0) {
20624
+ try {
20625
+ await syncDenseCountersToLiveDom(
20626
+ options.engine,
20627
+ options.pageRef,
20628
+ dense.sparseToDirectMapping
20629
+ );
20630
+ } catch {
20631
+ }
20632
+ }
20185
20633
  return {
20186
20634
  url: pageInfo.url,
20187
20635
  title: pageInfo.title,
20188
20636
  mode: options.mode,
20189
- html: cleanedHtml,
20190
- counters: [...filtered.values()].map(toPublicCounterRecord),
20191
- counterRecords: filtered
20637
+ html: dense.html,
20638
+ counters: [...dense.counterRecords.values()].map(toPublicCounterRecord),
20639
+ counterRecords: dense.counterRecords
20192
20640
  };
20193
20641
  }
20194
20642
  async function getMainDocumentSnapshot(engine, pageRef) {
@@ -20417,6 +20865,9 @@ function assignCounters(rawHtml, renderedNodes) {
20417
20865
  if (!rendered) {
20418
20866
  return;
20419
20867
  }
20868
+ const rawSparseCounter = el.attr(OPENSTEER_SPARSE_COUNTER_ATTR);
20869
+ el.removeAttr(OPENSTEER_SPARSE_COUNTER_ATTR);
20870
+ const sparseCounter = rawSparseCounter ? Number.parseInt(rawSparseCounter, 10) : void 0;
20420
20871
  const counter = nextCounter++;
20421
20872
  el.attr("c", String(counter));
20422
20873
  counterRecords.set(counter, {
@@ -20434,7 +20885,8 @@ function assignCounters(rawHtml, renderedNodes) {
20434
20885
  shadowDepth: rendered.shadowDepth,
20435
20886
  interactive: rendered.interactive,
20436
20887
  locator: rendered.locator,
20437
- anchor: rendered.anchor
20888
+ anchor: rendered.anchor,
20889
+ ...sparseCounter !== void 0 && Number.isFinite(sparseCounter) ? { sparseCounter } : {}
20438
20890
  });
20439
20891
  });
20440
20892
  return {
@@ -20713,7 +21165,7 @@ async function beautifyScriptContent(content) {
20713
21165
  });
20714
21166
  }
20715
21167
 
20716
- // src/scripts/deobfuscate.ts
21168
+ // ../runtime-core/src/scripts/deobfuscate.ts
20717
21169
  async function deobfuscateScriptContent(input) {
20718
21170
  const webcrack = await loadWebcrack();
20719
21171
  const result = await webcrack(input.content, {
@@ -20771,7 +21223,7 @@ function inferTransforms(original, deobfuscated) {
20771
21223
  return [...inferred];
20772
21224
  }
20773
21225
 
20774
- // src/scripts/sandbox-shims/minimal.ts
21226
+ // ../runtime-core/src/scripts/sandbox-shims/minimal.ts
20775
21227
  function createMinimalSandboxGlobals(options) {
20776
21228
  return {
20777
21229
  console: options.console,
@@ -20795,7 +21247,7 @@ function createMinimalSandboxGlobals(options) {
20795
21247
  };
20796
21248
  }
20797
21249
 
20798
- // src/scripts/sandbox-shims/standard.ts
21250
+ // ../runtime-core/src/scripts/sandbox-shims/standard.ts
20799
21251
  function createStandardSandboxGlobals(options) {
20800
21252
  const globals = createMinimalSandboxGlobals(options);
20801
21253
  const eventApi = createEventTargetApi();
@@ -21066,7 +21518,7 @@ function normalizeErrorMessage(error) {
21066
21518
  return error instanceof Error ? error.message : String(error);
21067
21519
  }
21068
21520
 
21069
- // src/scripts/sandbox-shims/full.ts
21521
+ // ../runtime-core/src/scripts/sandbox-shims/full.ts
21070
21522
  function createFullSandboxGlobals(options) {
21071
21523
  const globals = createStandardSandboxGlobals(options);
21072
21524
  const eventListeners = /* @__PURE__ */ new WeakMap();
@@ -21186,7 +21638,7 @@ function createFullSandboxGlobals(options) {
21186
21638
  };
21187
21639
  }
21188
21640
 
21189
- // src/scripts/sandbox.ts
21641
+ // ../runtime-core/src/scripts/sandbox.ts
21190
21642
  async function runScriptSandbox(input) {
21191
21643
  const startedAt = Date.now();
21192
21644
  const errors = [];
@@ -21410,7 +21862,7 @@ function normalizeErrorMessage2(error) {
21410
21862
  return error instanceof Error ? error.message : String(error);
21411
21863
  }
21412
21864
 
21413
- // src/captcha/solver-capsolver.ts
21865
+ // ../runtime-core/src/captcha/solver-capsolver.ts
21414
21866
  var CAPSOLVER_CREATE_TASK_URL = "https://api.capsolver.com/createTask";
21415
21867
  var CAPSOLVER_GET_TASK_RESULT_URL = "https://api.capsolver.com/getTaskResult";
21416
21868
  function createCapSolver(apiKey) {
@@ -21508,7 +21960,7 @@ function sleep2(ms, signal) {
21508
21960
  });
21509
21961
  }
21510
21962
 
21511
- // src/captcha/solver-2captcha.ts
21963
+ // ../runtime-core/src/captcha/solver-2captcha.ts
21512
21964
  var TWO_CAPTCHA_CREATE_TASK_URL = "https://api.2captcha.com/createTask";
21513
21965
  var TWO_CAPTCHA_GET_TASK_RESULT_URL = "https://api.2captcha.com/getTaskResult";
21514
21966
  function createTwoCaptchaSolver(apiKey) {
@@ -21606,7 +22058,7 @@ function sleep3(ms, signal) {
21606
22058
  });
21607
22059
  }
21608
22060
 
21609
- // src/captcha/detect.ts
22061
+ // ../runtime-core/src/captcha/detect.ts
21610
22062
  var CAPTCHA_DETECTION_SCRIPT = `(() => {
21611
22063
  const pageUrl = location.href;
21612
22064
  const findSiteKey = (selectors) => {
@@ -21668,7 +22120,7 @@ async function detectCaptchaOnPage(engine, pageRef) {
21668
22120
  return candidate;
21669
22121
  }
21670
22122
 
21671
- // src/captcha/inject.ts
22123
+ // ../runtime-core/src/captcha/inject.ts
21672
22124
  async function injectCaptchaToken(input) {
21673
22125
  const result = await input.engine.evaluatePage({
21674
22126
  pageRef: input.pageRef,
@@ -21724,7 +22176,7 @@ var CAPTCHA_INJECTION_SCRIPT = `(({ type, token }) => {
21724
22176
  return true;
21725
22177
  })`;
21726
22178
 
21727
- // src/interaction/diff.ts
22179
+ // ../runtime-core/src/interaction/diff.ts
21728
22180
  function diffInteractionTraces(left, right) {
21729
22181
  const eventSequenceMismatches = [];
21730
22182
  const eventPropertyMismatches = [];
@@ -21793,20 +22245,19 @@ function diffInteractionTraces(left, right) {
21793
22245
  };
21794
22246
  }
21795
22247
 
21796
- // src/sdk/runtime.ts
22248
+ // ../runtime-core/src/sdk/runtime.ts
21797
22249
  var requireForAuthRecipeHook = createRequire(import.meta.url);
21798
- var OpensteerRuntime = class {
22250
+ var OpensteerSessionRuntime = class {
21799
22251
  workspace;
21800
22252
  rootPath;
21801
- publicWorkspace;
21802
- configuredBrowser;
21803
- configuredLaunch;
21804
- configuredContext;
21805
- configuredEngineName;
22253
+ workspaceName;
21806
22254
  injectedEngine;
21807
22255
  engineFactory;
21808
22256
  policy;
22257
+ injectedDescriptorStore;
22258
+ registryOverrides;
21809
22259
  cleanupRootOnClose;
22260
+ sessionInfoBase;
21810
22261
  root;
21811
22262
  engine;
21812
22263
  dom;
@@ -21821,39 +22272,52 @@ var OpensteerRuntime = class {
21821
22272
  cookieJars = /* @__PURE__ */ new Map();
21822
22273
  recipeCache = /* @__PURE__ */ new Map();
21823
22274
  ownsEngine = false;
21824
- constructor(options = {}) {
21825
- this.publicWorkspace = options.workspace?.trim() === void 0 || options.workspace?.trim().length === 0 ? void 0 : options.workspace.trim();
21826
- this.workspace = normalizeNamespace3(options.workspace);
21827
- this.rootPath = options.rootPath ?? (this.publicWorkspace === void 0 ? path6.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", randomUUID()) : path6.resolve(
21828
- options.rootDir ?? process.cwd(),
21829
- ".opensteer",
21830
- "workspaces",
21831
- encodeURIComponent(this.publicWorkspace)
21832
- ));
21833
- this.configuredBrowser = options.browser;
21834
- this.configuredLaunch = options.launch;
21835
- this.configuredContext = options.context;
21836
- this.configuredEngineName = options.engineName;
22275
+ constructor(options) {
22276
+ this.workspace = normalizeNamespace2(options.name);
22277
+ this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
22278
+ this.root = options.workspace;
22279
+ this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6.resolve(process.cwd(), ".opensteer", "temporary", randomUUID());
21837
22280
  this.injectedEngine = options.engine;
21838
- this.engineFactory = options.engineFactory ?? ((factoryOptions) => {
21839
- const browser = factoryOptions.browser ?? this.configuredBrowser;
21840
- const launch = factoryOptions.launch ?? this.configuredLaunch;
21841
- const context = factoryOptions.context ?? this.configuredContext;
21842
- return new OpensteerBrowserManager({
21843
- rootPath: this.rootPath,
21844
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
21845
- ...this.configuredEngineName === void 0 ? {} : { engineName: this.configuredEngineName },
21846
- ...browser === void 0 ? {} : { browser },
21847
- ...launch === void 0 ? {} : { launch },
21848
- ...context === void 0 ? {} : { context }
21849
- }).createEngine();
21850
- });
22281
+ this.engineFactory = options.engineFactory;
21851
22282
  this.policy = options.policy ?? defaultPolicy();
21852
- this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.publicWorkspace === void 0;
22283
+ this.injectedDescriptorStore = options.descriptorStore;
22284
+ this.registryOverrides = options.registryOverrides;
22285
+ this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
22286
+ this.sessionInfoBase = options.sessionInfo ?? {};
22287
+ if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
22288
+ throw new Error("OpensteerSessionRuntime requires an engine or engineFactory.");
22289
+ }
22290
+ }
22291
+ async info() {
22292
+ const base = this.sessionInfoBase;
22293
+ return {
22294
+ provider: base.provider ?? {
22295
+ kind: "local",
22296
+ ownership: "owned",
22297
+ engine: "playwright"
22298
+ },
22299
+ ...base.workspace === void 0 ? {} : { workspace: base.workspace },
22300
+ ...this.sessionRef === void 0 ? {} : { sessionId: this.sessionRef },
22301
+ ...this.pageRef === void 0 ? {} : { activePageRef: this.pageRef },
22302
+ reconnectable: base.reconnectable ?? !this.cleanupRootOnClose,
22303
+ capabilities: base.capabilities ?? {
22304
+ semanticOperations: opensteerSemanticOperationNames,
22305
+ instrumentation: {
22306
+ route: true,
22307
+ interceptScript: true,
22308
+ networkStream: false
22309
+ }
22310
+ },
22311
+ ...base.grants === void 0 ? {} : { grants: base.grants },
22312
+ runtime: base.runtime ?? {
22313
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
22314
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
22315
+ }
22316
+ };
21853
22317
  }
21854
22318
  async open(input = {}, options = {}) {
21855
22319
  assertValidSemanticOperationInput("session.open", input);
21856
- if (input.workspace !== void 0 && normalizeNamespace3(input.workspace) !== this.workspace) {
22320
+ if (input.workspace !== void 0 && normalizeNamespace2(input.workspace) !== this.workspace) {
21857
22321
  throw new Error(
21858
22322
  `session.open requested workspace "${input.workspace}" but runtime is bound to "${this.workspace}"`
21859
22323
  );
@@ -24269,8 +24733,7 @@ var OpensteerRuntime = class {
24269
24733
  const inferred = inferRequestPlanFromNetworkRecord(record, {
24270
24734
  recordId: candidate.recordId,
24271
24735
  key: input.key,
24272
- version: input.version,
24273
- lifecycle: "draft"
24736
+ version: input.version
24274
24737
  });
24275
24738
  const defaultHeaders = inferred.payload.endpoint.defaultHeaders === void 0 ? void 0 : stripManagedRequestHeaders(
24276
24739
  inferred.payload.endpoint.defaultHeaders,
@@ -24898,8 +25361,7 @@ var OpensteerRuntime = class {
24898
25361
  recordId: input.recordId,
24899
25362
  id: record.id,
24900
25363
  key: record.key,
24901
- version: record.version,
24902
- lifecycle: record.lifecycle
25364
+ version: record.version
24903
25365
  }
24904
25366
  });
24905
25367
  return record;
@@ -24940,8 +25402,7 @@ var OpensteerRuntime = class {
24940
25402
  data: {
24941
25403
  id: record.id,
24942
25404
  key: record.key,
24943
- version: record.version,
24944
- lifecycle: record.lifecycle
25405
+ version: record.version
24945
25406
  }
24946
25407
  });
24947
25408
  return record;
@@ -24987,8 +25448,7 @@ var OpensteerRuntime = class {
24987
25448
  data: {
24988
25449
  id: record.id,
24989
25450
  key: record.key,
24990
- version: record.version,
24991
- lifecycle: record.lifecycle
25451
+ version: record.version
24992
25452
  }
24993
25453
  });
24994
25454
  return record;
@@ -25859,18 +26319,12 @@ var OpensteerRuntime = class {
25859
26319
  }
25860
26320
  if (target.kind === "element") {
25861
26321
  const counter = this.latestSnapshot?.counterRecords.get(target.element);
25862
- if (!counter) {
25863
- throw new Error(`no counter ${String(target.element)} is available in the latest snapshot`);
25864
- }
26322
+ const elementTarget = counter ? { kind: "live", locator: counter.locator, anchor: counter.anchor } : { kind: "selector", selector: `[c="${String(target.element)}"]` };
25865
26323
  const resolved2 = await timeout.runStep(
25866
26324
  () => this.requireDom().resolveTarget({
25867
26325
  pageRef,
25868
26326
  method,
25869
- target: {
25870
- kind: "live",
25871
- locator: counter.locator,
25872
- anchor: counter.anchor
25873
- }
26327
+ target: elementTarget
25874
26328
  })
25875
26329
  );
25876
26330
  const stablePath2 = resolved2.replayPath ?? await timeout.runStep(
@@ -26220,14 +26674,14 @@ var OpensteerRuntime = class {
26220
26674
  return saved;
26221
26675
  }
26222
26676
  resolveCurrentStateSource() {
26223
- const browser = this.configuredBrowser;
26224
- if (browser === void 0 || browser === "temporary") {
26225
- return "temporary";
26677
+ const ownership = this.sessionInfoBase.provider?.ownership;
26678
+ if (ownership === "attached") {
26679
+ return "attach";
26226
26680
  }
26227
- if (browser === "persistent") {
26681
+ if (this.workspaceName !== void 0 || this.cleanupRootOnClose === false) {
26228
26682
  return "persistent";
26229
26683
  }
26230
- return "attach";
26684
+ return "temporary";
26231
26685
  }
26232
26686
  async resolveReverseCaseById(caseId) {
26233
26687
  const record = await (await this.ensureRoot()).registry.reverseCases.getById(caseId);
@@ -27113,7 +27567,7 @@ var OpensteerRuntime = class {
27113
27567
  }
27114
27568
  async touchRequestPlanFreshness(plan) {
27115
27569
  const freshness = touchFreshness(plan.freshness);
27116
- await this.requireRoot().registry.requestPlans.updateMetadata({
27570
+ await this.requireRoot().registry.requestPlans.updateFreshness({
27117
27571
  id: plan.id,
27118
27572
  ...freshness === void 0 ? {} : { freshness }
27119
27573
  });
@@ -27782,21 +28236,40 @@ var OpensteerRuntime = class {
27782
28236
  };
27783
28237
  }
27784
28238
  const counter = this.latestSnapshot?.counterRecords.get(target.element);
27785
- if (!counter) {
27786
- throw new Error(`no counter ${String(target.element)} is available in the latest snapshot`);
28239
+ if (counter) {
28240
+ return {
28241
+ kind: "live",
28242
+ locator: counter.locator,
28243
+ anchor: counter.anchor
28244
+ };
27787
28245
  }
27788
28246
  return {
27789
- kind: "live",
27790
- locator: counter.locator,
27791
- anchor: counter.anchor
28247
+ kind: "selector",
28248
+ selector: `[c="${String(target.element)}"]`
27792
28249
  };
27793
28250
  }
27794
28251
  async ensureRoot() {
27795
- this.root ??= await createFilesystemOpensteerWorkspace({
27796
- rootPath: this.rootPath,
27797
- ...this.publicWorkspace === void 0 ? {} : { workspace: this.publicWorkspace },
27798
- scope: this.publicWorkspace === void 0 ? "temporary" : "workspace"
27799
- });
28252
+ if (!this.root) {
28253
+ const workspace = await createFilesystemOpensteerWorkspace({
28254
+ rootPath: this.rootPath,
28255
+ ...this.workspaceName === void 0 ? {} : { workspace: this.workspaceName },
28256
+ scope: this.workspaceName === void 0 ? "temporary" : "workspace"
28257
+ });
28258
+ if (this.registryOverrides) {
28259
+ const overrides = this.registryOverrides;
28260
+ this.root = {
28261
+ ...workspace,
28262
+ registry: {
28263
+ ...workspace.registry,
28264
+ ...overrides.requestPlans === void 0 ? {} : { requestPlans: overrides.requestPlans },
28265
+ ...overrides.authRecipes === void 0 ? {} : { authRecipes: overrides.authRecipes },
28266
+ ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes }
28267
+ }
28268
+ };
28269
+ } else {
28270
+ this.root = workspace;
28271
+ }
28272
+ }
27800
28273
  return this.root;
27801
28274
  }
27802
28275
  async ensureEngine(overrides = {}) {
@@ -27808,15 +28281,10 @@ var OpensteerRuntime = class {
27808
28281
  this.ownsEngine = false;
27809
28282
  return this.engine;
27810
28283
  }
27811
- const browser = overrides.browser ?? this.configuredBrowser;
27812
- const launch = overrides.launch ?? this.configuredLaunch;
27813
- const context = overrides.context ?? this.configuredContext;
27814
- const factoryOptions = {
27815
- ...browser === void 0 ? {} : { browser },
27816
- ...launch === void 0 ? {} : { launch },
27817
- ...context === void 0 ? {} : { context }
27818
- };
27819
- this.engine = await this.engineFactory(factoryOptions);
28284
+ if (this.engineFactory === void 0) {
28285
+ throw new Error("Opensteer engine factory is not initialized");
28286
+ }
28287
+ this.engine = await this.engineFactory(overrides);
27820
28288
  this.ownsEngine = true;
27821
28289
  return this.engine;
27822
28290
  }
@@ -27827,6 +28295,7 @@ var OpensteerRuntime = class {
27827
28295
  engine,
27828
28296
  root,
27829
28297
  namespace: this.workspace,
28298
+ ...this.injectedDescriptorStore === void 0 ? {} : { descriptorStore: this.injectedDescriptorStore },
27830
28299
  policy: this.policy
27831
28300
  });
27832
28301
  this.computer = createComputerUseRuntime({
@@ -28273,6 +28742,9 @@ function parseContentType2(contentType) {
28273
28742
  };
28274
28743
  }
28275
28744
  function toJsonValueOrNull(value) {
28745
+ if (value === void 0) {
28746
+ return null;
28747
+ }
28276
28748
  return toCanonicalJsonValue(value) ?? null;
28277
28749
  }
28278
28750
  function stringifyRecipeVariableValue(value) {
@@ -28410,7 +28882,6 @@ function buildMinimizedRequestPlan(input) {
28410
28882
  sourceId: input.record.recordId,
28411
28883
  ...input.record.source === "saved" && input.record.savedAt !== void 0 ? { capturedAt: input.record.savedAt } : {}
28412
28884
  },
28413
- lifecycle: "draft",
28414
28885
  payload: normalizeRequestPlanPayload({
28415
28886
  transport: {
28416
28887
  kind: input.transport
@@ -29070,12 +29541,12 @@ function extractReverseRuntimeValue(value, pointer) {
29070
29541
  }
29071
29542
  return readDotPath(value, pointer);
29072
29543
  }
29073
- function readDotPath(value, path11) {
29074
- if (path11.length === 0) {
29544
+ function readDotPath(value, path13) {
29545
+ if (path13.length === 0) {
29075
29546
  return value;
29076
29547
  }
29077
29548
  let current = value;
29078
- for (const segment of path11.split(".").filter((entry) => entry.length > 0)) {
29549
+ for (const segment of path13.split(".").filter((entry) => entry.length > 0)) {
29079
29550
  if (current === null || current === void 0) {
29080
29551
  return void 0;
29081
29552
  }
@@ -29548,7 +30019,7 @@ function parseSetCookieHeader(value, requestUrl) {
29548
30019
  }
29549
30020
  const url = new URL(requestUrl);
29550
30021
  let domain = url.hostname;
29551
- let path11 = defaultCookiePath(url.pathname);
30022
+ let path13 = defaultCookiePath(url.pathname);
29552
30023
  let secure = url.protocol === "https:";
29553
30024
  let expiresAt;
29554
30025
  const cookieValue = rawValueParts.join("=").trim();
@@ -29561,7 +30032,7 @@ function parseSetCookieHeader(value, requestUrl) {
29561
30032
  continue;
29562
30033
  }
29563
30034
  if (key === "path" && attributeValue.length > 0) {
29564
- path11 = attributeValue;
30035
+ path13 = attributeValue;
29565
30036
  continue;
29566
30037
  }
29567
30038
  if (key === "secure") {
@@ -29587,7 +30058,7 @@ function parseSetCookieHeader(value, requestUrl) {
29587
30058
  name,
29588
30059
  value: cookieValue,
29589
30060
  domain,
29590
- path: path11,
30061
+ path: path13,
29591
30062
  secure,
29592
30063
  ...expiresAt === void 0 ? {} : { expiresAt }
29593
30064
  }
@@ -30565,7 +31036,7 @@ function directionToDelta(direction, amount) {
30565
31036
  return { x: amount, y: 0 };
30566
31037
  }
30567
31038
  }
30568
- function normalizeNamespace3(value) {
31039
+ function normalizeNamespace2(value) {
30569
31040
  const normalized = String(value ?? "default").trim();
30570
31041
  return normalized.length === 0 ? "default" : normalized;
30571
31042
  }
@@ -30611,45 +31082,145 @@ function screenshotMediaType(format2) {
30611
31082
  }
30612
31083
  }
30613
31084
 
30614
- // src/mode/config.ts
30615
- var OPENSTEER_EXECUTION_MODES = ["local", "cloud"];
30616
- function assertExecutionModeSupportsEngine(mode, engine) {
31085
+ // src/sdk/runtime.ts
31086
+ var OpensteerRuntime = class extends OpensteerSessionRuntime {
31087
+ constructor(options = {}) {
31088
+ const publicWorkspace = normalizeWorkspace2(options.workspace);
31089
+ const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path6.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", randomUUID()) : resolveFilesystemWorkspacePath({
31090
+ rootDir: path6.resolve(options.rootDir ?? process.cwd()),
31091
+ workspace: publicWorkspace
31092
+ }));
31093
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? publicWorkspace === void 0;
31094
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31095
+ assertSupportedEngineOptions({
31096
+ engineName,
31097
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31098
+ ...options.context === void 0 ? {} : { context: options.context }
31099
+ });
31100
+ super(
31101
+ buildSharedRuntimeOptions({
31102
+ name: publicWorkspace ?? "default",
31103
+ rootPath,
31104
+ ...publicWorkspace === void 0 ? {} : { workspaceName: publicWorkspace },
31105
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31106
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31107
+ ...options.context === void 0 ? {} : { context: options.context },
31108
+ engineName,
31109
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31110
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31111
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31112
+ ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31113
+ cleanupRootOnClose
31114
+ })
31115
+ );
31116
+ }
31117
+ };
31118
+ var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31119
+ constructor(options) {
31120
+ const rootPath = options.rootPath ?? path6.resolve(options.rootDir ?? process.cwd());
31121
+ const cleanupRootOnClose = options.cleanupRootOnClose ?? false;
31122
+ const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31123
+ assertSupportedEngineOptions({
31124
+ engineName,
31125
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31126
+ ...options.context === void 0 ? {} : { context: options.context }
31127
+ });
31128
+ super(
31129
+ buildSharedRuntimeOptions({
31130
+ name: options.name,
31131
+ rootPath,
31132
+ ...options.browser === void 0 ? {} : { browser: options.browser },
31133
+ ...options.launch === void 0 ? {} : { launch: options.launch },
31134
+ ...options.context === void 0 ? {} : { context: options.context },
31135
+ engineName,
31136
+ ...options.engine === void 0 ? {} : { engine: options.engine },
31137
+ ...options.engineFactory === void 0 ? {} : { engineFactory: options.engineFactory },
31138
+ ...options.policy === void 0 ? {} : { policy: options.policy },
31139
+ ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31140
+ cleanupRootOnClose
31141
+ })
31142
+ );
31143
+ }
31144
+ };
31145
+ function buildSharedRuntimeOptions(input) {
31146
+ const ownership = resolveOwnership(input.browser);
31147
+ const engineFactory = input.engineFactory ?? ((factoryOptions) => new OpensteerBrowserManager({
31148
+ rootPath: input.rootPath,
31149
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31150
+ engineName: input.engineName,
31151
+ ...(factoryOptions.browser ?? input.browser) === void 0 ? {} : { browser: factoryOptions.browser ?? input.browser },
31152
+ ...(factoryOptions.launch ?? input.launch) === void 0 ? {} : { launch: factoryOptions.launch ?? input.launch },
31153
+ ...(factoryOptions.context ?? input.context) === void 0 ? {} : { context: factoryOptions.context ?? input.context }
31154
+ }).createEngine());
31155
+ return {
31156
+ name: input.name,
31157
+ ...input.workspaceName === void 0 ? {} : { workspaceName: input.workspaceName },
31158
+ rootPath: input.rootPath,
31159
+ ...input.engine === void 0 ? {} : { engine: input.engine },
31160
+ ...input.engine === void 0 ? { engineFactory } : {},
31161
+ ...input.policy === void 0 ? {} : { policy: input.policy },
31162
+ ...input.descriptorStore === void 0 ? {} : { descriptorStore: input.descriptorStore },
31163
+ cleanupRootOnClose: input.cleanupRootOnClose,
31164
+ sessionInfo: {
31165
+ provider: {
31166
+ kind: "local",
31167
+ ownership,
31168
+ engine: input.engineName
31169
+ },
31170
+ ...input.workspaceName === void 0 ? {} : { workspace: input.workspaceName },
31171
+ reconnectable: !input.cleanupRootOnClose
31172
+ }
31173
+ };
31174
+ }
31175
+ function normalizeWorkspace2(workspace) {
31176
+ if (workspace === void 0) {
31177
+ return void 0;
31178
+ }
31179
+ const trimmed = workspace.trim();
31180
+ return trimmed.length === 0 ? void 0 : trimmed;
31181
+ }
31182
+ function resolveOwnership(browser) {
31183
+ return typeof browser === "object" && browser.mode === "attach" ? "attached" : "owned";
31184
+ }
31185
+
31186
+ // src/provider/config.ts
31187
+ var OPENSTEER_PROVIDER_KINDS = ["local", "cloud"];
31188
+ function assertProviderSupportsEngine(provider, engine) {
30617
31189
  if (engine !== "abp") {
30618
31190
  return;
30619
31191
  }
30620
- if (mode === "cloud") {
31192
+ if (provider === "cloud") {
30621
31193
  throw new Error(
30622
- "ABP is not supported in cloud mode. Cloud mode currently requires Playwright."
31194
+ "ABP is not supported for provider=cloud. Cloud provider currently requires Playwright."
30623
31195
  );
30624
31196
  }
30625
31197
  }
30626
- function normalizeOpensteerExecutionMode(value, source = "OPENSTEER_MODE") {
31198
+ function normalizeOpensteerProviderKind(value, source = "OPENSTEER_PROVIDER") {
30627
31199
  const normalized = value.trim().toLowerCase();
30628
- if (normalized === OPENSTEER_EXECUTION_MODES[0] || normalized === OPENSTEER_EXECUTION_MODES[1]) {
31200
+ if (normalized === OPENSTEER_PROVIDER_KINDS[0] || normalized === OPENSTEER_PROVIDER_KINDS[1]) {
30629
31201
  return normalized;
30630
31202
  }
30631
31203
  throw new Error(
30632
- `${source} must be one of ${OPENSTEER_EXECUTION_MODES.join(", ")}; received "${value}".`
31204
+ `${source} must be one of ${OPENSTEER_PROVIDER_KINDS.join(", ")}; received "${value}".`
30633
31205
  );
30634
31206
  }
30635
- function resolveOpensteerExecutionMode(input = {}) {
30636
- const explicitFlags = [input.local, input.cloud].filter(Boolean).length;
30637
- if (explicitFlags > 1) {
30638
- throw new Error("Choose exactly one execution mode: local or cloud.");
30639
- }
30640
- if (input.explicit) {
30641
- return input.explicit;
30642
- }
30643
- if (input.local) {
30644
- return "local";
30645
- }
30646
- if (input.cloud) {
30647
- return "cloud";
31207
+ function resolveOpensteerProvider(input = {}) {
31208
+ if (input.provider) {
31209
+ return {
31210
+ kind: input.provider.kind,
31211
+ source: "explicit"
31212
+ };
30648
31213
  }
30649
- if (input.environment !== void 0 && input.environment.trim().length > 0) {
30650
- return normalizeOpensteerExecutionMode(input.environment);
31214
+ if (input.environmentProvider !== void 0 && input.environmentProvider.trim().length > 0) {
31215
+ return {
31216
+ kind: normalizeOpensteerProviderKind(input.environmentProvider),
31217
+ source: "env"
31218
+ };
30651
31219
  }
30652
- return "local";
31220
+ return {
31221
+ kind: "local",
31222
+ source: "default"
31223
+ };
30653
31224
  }
30654
31225
  var execFile2 = promisify(execFile);
30655
31226
  var DEFAULT_CAPTURE_TIMEOUT_MS = 3e4;
@@ -31046,14 +31617,14 @@ function toPortableBrowserProfileCookieRecord(cookie) {
31046
31617
  if (!name || !domain) {
31047
31618
  return null;
31048
31619
  }
31049
- const path11 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31620
+ const path13 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
31050
31621
  const expiresAt = typeof cookie.expires === "number" && Number.isFinite(cookie.expires) && cookie.expires > 0 ? Math.floor(cookie.expires * 1e3) : null;
31051
31622
  const sameSite = normalizeSameSite(cookie.sameSite);
31052
31623
  return {
31053
31624
  name,
31054
31625
  value: cookie.value,
31055
31626
  domain,
31056
- path: path11,
31627
+ path: path13,
31057
31628
  secure: cookie.secure,
31058
31629
  httpOnly: cookie.httpOnly,
31059
31630
  ...sameSite === void 0 ? {} : { sameSite },
@@ -31230,6 +31801,15 @@ var OpensteerCloudClient = class {
31230
31801
  });
31231
31802
  return await response.json();
31232
31803
  }
31804
+ async issueAccess(sessionId, capabilities) {
31805
+ const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}/access`, {
31806
+ method: "POST",
31807
+ body: {
31808
+ capabilities
31809
+ }
31810
+ });
31811
+ return await response.json();
31812
+ }
31233
31813
  async closeSession(sessionId) {
31234
31814
  const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
31235
31815
  method: "DELETE"
@@ -31285,6 +31865,34 @@ var OpensteerCloudClient = class {
31285
31865
  async syncBrowserProfileCookies(input) {
31286
31866
  return syncBrowserProfileCookies(this, input);
31287
31867
  }
31868
+ async importSelectorCache(entries) {
31869
+ const response = await this.request("/selector-cache/import", {
31870
+ method: "POST",
31871
+ body: { entries }
31872
+ });
31873
+ return await response.json();
31874
+ }
31875
+ async importRequestPlans(entries) {
31876
+ const response = await this.request("/registry/request-plans/import", {
31877
+ method: "POST",
31878
+ body: { entries }
31879
+ });
31880
+ return await response.json();
31881
+ }
31882
+ async importRecipes(entries) {
31883
+ const response = await this.request("/registry/recipes/import", {
31884
+ method: "POST",
31885
+ body: { entries }
31886
+ });
31887
+ return await response.json();
31888
+ }
31889
+ async importAuthRecipes(entries) {
31890
+ const response = await this.request("/registry/auth-recipes/import", {
31891
+ method: "POST",
31892
+ body: { entries }
31893
+ });
31894
+ return await response.json();
31895
+ }
31288
31896
  buildAuthorizationHeader() {
31289
31897
  return `Bearer ${this.config.apiKey}`;
31290
31898
  }
@@ -31355,22 +31963,26 @@ function wrapCloudFetchError(error, input) {
31355
31963
 
31356
31964
  // src/cloud/config.ts
31357
31965
  function resolveCloudConfig(input = {}) {
31358
- const mode = resolveOpensteerExecutionMode({
31359
- ...input.mode === void 0 ? {} : { explicit: input.mode },
31360
- ...input.enabled === void 0 ? {} : { cloud: input.enabled },
31361
- ...process.env.OPENSTEER_MODE === void 0 ? {} : { environment: process.env.OPENSTEER_MODE }
31966
+ const provider = resolveOpensteerProvider({
31967
+ ...input.provider === void 0 ? {} : { provider: input.provider },
31968
+ ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
31362
31969
  });
31363
- if (mode !== "cloud") {
31970
+ if (provider.kind !== "cloud") {
31364
31971
  return void 0;
31365
31972
  }
31366
- const apiKey = input.apiKey ?? process.env.OPENSTEER_API_KEY;
31973
+ const cloudProvider = input.provider?.kind === "cloud" ? input.provider : void 0;
31974
+ const apiKey = cloudProvider?.apiKey ?? process.env.OPENSTEER_API_KEY;
31367
31975
  if (!apiKey || apiKey.trim().length === 0) {
31368
- throw new Error("Cloud mode requires OPENSTEER_API_KEY or cloud.apiKey.");
31976
+ throw new Error("provider=cloud requires OPENSTEER_API_KEY or provider.apiKey.");
31977
+ }
31978
+ const baseUrl = cloudProvider?.baseUrl ?? process.env.OPENSTEER_BASE_URL;
31979
+ if (!baseUrl || baseUrl.trim().length === 0) {
31980
+ throw new Error("provider=cloud requires OPENSTEER_BASE_URL or provider.baseUrl.");
31369
31981
  }
31370
31982
  return {
31371
31983
  apiKey: apiKey.trim(),
31372
- baseUrl: (input.baseUrl ?? process.env.OPENSTEER_BASE_URL ?? "https://api.opensteer.dev").trim().replace(/\/+$/, ""),
31373
- ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile }
31984
+ baseUrl: baseUrl.trim().replace(/\/+$/, ""),
31985
+ ...cloudProvider?.browserProfile === void 0 ? {} : { browserProfile: cloudProvider.browserProfile }
31374
31986
  };
31375
31987
  }
31376
31988
  var OpensteerSemanticRestError = class extends Error {
@@ -31435,58 +32047,475 @@ function isFetchFailure(error) {
31435
32047
  }
31436
32048
  return error.name === "TypeError" || /fetch failed/i.test(error.message);
31437
32049
  }
31438
-
31439
- // src/cloud/session-proxy.ts
31440
- var CLOUD_SESSION_LAYOUT = "opensteer-cloud-session";
31441
- var CLOUD_SESSION_VERSION = 1;
31442
- var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31443
- var SUPPORTED_CLOUD_OPERATIONS = /* @__PURE__ */ new Set([
31444
- "session.open",
31445
- "page.goto",
31446
- "page.snapshot",
31447
- "dom.click",
31448
- "dom.hover",
31449
- "dom.input",
31450
- "dom.scroll",
31451
- "dom.extract",
31452
- "network.query",
31453
- "network.save",
31454
- "network.clear",
31455
- "request.raw",
31456
- "request-plan.infer",
31457
- "request-plan.write",
31458
- "request-plan.get",
31459
- "request-plan.list",
31460
- "request.execute",
31461
- "computer.execute",
31462
- "session.close"
31463
- ]);
31464
- function resolveCloudSessionRecordPath(rootPath) {
31465
- return path6.join(rootPath, "live", "cloud-session.json");
32050
+ var OpensteerCloudAutomationError = class extends Error {
32051
+ opensteerError;
32052
+ constructor(error) {
32053
+ super(error.message);
32054
+ this.name = "OpensteerCloudAutomationError";
32055
+ this.opensteerError = error;
32056
+ }
32057
+ };
32058
+ var OpensteerCloudAutomationClient = class {
32059
+ constructor(cloud, sessionId) {
32060
+ this.cloud = cloud;
32061
+ this.sessionId = sessionId;
32062
+ }
32063
+ socket;
32064
+ connectPromise;
32065
+ pending = /* @__PURE__ */ new Map();
32066
+ routes = /* @__PURE__ */ new Map();
32067
+ grant;
32068
+ async invoke(operation, input) {
32069
+ await this.ensureConnected();
32070
+ const requestId = `automation:${randomUUID()}`;
32071
+ const message = {
32072
+ protocol: OPENSTEER_PROTOCOL_NAME,
32073
+ version: OPENSTEER_PROTOCOL_VERSION,
32074
+ kind: "invoke",
32075
+ requestId,
32076
+ operation,
32077
+ sentAt: Date.now(),
32078
+ ...input === void 0 ? {} : { input }
32079
+ };
32080
+ return new Promise((resolve5, reject) => {
32081
+ this.pending.set(requestId, {
32082
+ resolve: (value) => resolve5(value),
32083
+ reject
32084
+ });
32085
+ try {
32086
+ this.requireSocket().send(JSON.stringify(message));
32087
+ } catch (error) {
32088
+ this.pending.delete(requestId);
32089
+ reject(error);
32090
+ }
32091
+ });
32092
+ }
32093
+ async getSessionInfo() {
32094
+ const result = await this.invoke("session.info", {});
32095
+ const sessionInfo = result;
32096
+ assertCompatibleRuntimeCoreVersion(sessionInfo);
32097
+ return sessionInfo;
32098
+ }
32099
+ async route(input) {
32100
+ const routeId = `route:${randomUUID()}`;
32101
+ const registration = await this.invoke("route.register", {
32102
+ routeId,
32103
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32104
+ urlPattern: input.urlPattern,
32105
+ ...input.resourceTypes === void 0 ? {} : { resourceTypes: input.resourceTypes },
32106
+ ...input.times === void 0 ? {} : { times: input.times },
32107
+ includeOriginal: true
32108
+ });
32109
+ this.routes.set(routeId, {
32110
+ kind: "route",
32111
+ routeId,
32112
+ input
32113
+ });
32114
+ return registration;
32115
+ }
32116
+ async interceptScript(input) {
32117
+ const routeId = `route:${randomUUID()}`;
32118
+ const registration = await this.invoke("route.register", {
32119
+ routeId,
32120
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
32121
+ urlPattern: input.urlPattern,
32122
+ resourceTypes: ["script"],
32123
+ ...input.times === void 0 ? {} : { times: input.times },
32124
+ includeOriginal: true
32125
+ });
32126
+ this.routes.set(routeId, {
32127
+ kind: "intercept-script",
32128
+ routeId,
32129
+ input
32130
+ });
32131
+ return registration;
32132
+ }
32133
+ async close() {
32134
+ this.connectPromise = void 0;
32135
+ this.grant = void 0;
32136
+ if (!this.socket) {
32137
+ return;
32138
+ }
32139
+ const socket = this.socket;
32140
+ this.socket = void 0;
32141
+ for (const [requestId, pending] of this.pending) {
32142
+ pending.reject(new Error(`automation connection closed before ${requestId} completed`));
32143
+ }
32144
+ this.pending.clear();
32145
+ await new Promise((resolve5) => {
32146
+ socket.once("close", () => resolve5());
32147
+ socket.close();
32148
+ }).catch(() => void 0);
32149
+ }
32150
+ async ensureConnected() {
32151
+ if (this.socket?.readyState === WebSocket2.OPEN) {
32152
+ return;
32153
+ }
32154
+ if (this.connectPromise) {
32155
+ await this.connectPromise;
32156
+ return;
32157
+ }
32158
+ this.connectPromise = this.connect();
32159
+ try {
32160
+ await this.connectPromise;
32161
+ } finally {
32162
+ this.connectPromise = void 0;
32163
+ }
32164
+ }
32165
+ async connect() {
32166
+ const grant = await this.issueGrant("automation");
32167
+ const wsUrl = new URL(grant.wsUrl);
32168
+ wsUrl.searchParams.set("token", grant.token);
32169
+ const socket = new WebSocket2(wsUrl);
32170
+ this.socket = socket;
32171
+ socket.on("message", (data, isBinary) => {
32172
+ if (isBinary) {
32173
+ return;
32174
+ }
32175
+ this.handleMessage(data.toString());
32176
+ });
32177
+ socket.on("close", () => {
32178
+ if (this.socket === socket) {
32179
+ this.socket = void 0;
32180
+ }
32181
+ });
32182
+ socket.on("error", (error) => {
32183
+ for (const pending of this.pending.values()) {
32184
+ pending.reject(error);
32185
+ }
32186
+ this.pending.clear();
32187
+ });
32188
+ await new Promise((resolve5, reject) => {
32189
+ socket.once("open", () => resolve5());
32190
+ socket.once("error", reject);
32191
+ });
32192
+ this.send({
32193
+ protocol: OPENSTEER_PROTOCOL_NAME,
32194
+ version: OPENSTEER_PROTOCOL_VERSION,
32195
+ kind: "hello",
32196
+ sessionId: this.sessionId,
32197
+ grantKind: grant.kind
32198
+ });
32199
+ await this.restoreRoutes();
32200
+ }
32201
+ async restoreRoutes() {
32202
+ const stored = [...this.routes.values()];
32203
+ this.routes.clear();
32204
+ for (const registration of stored) {
32205
+ if (registration.kind === "route") {
32206
+ await this.route(registration.input);
32207
+ } else {
32208
+ await this.interceptScript(registration.input);
32209
+ }
32210
+ }
32211
+ }
32212
+ handleMessage(json) {
32213
+ const message = JSON.parse(json);
32214
+ if (message.protocol !== OPENSTEER_PROTOCOL_NAME) {
32215
+ return;
32216
+ }
32217
+ switch (message.kind) {
32218
+ case "result": {
32219
+ const pending = this.pending.get(message.requestId);
32220
+ if (!pending) {
32221
+ return;
32222
+ }
32223
+ this.pending.delete(message.requestId);
32224
+ pending.resolve(message.data);
32225
+ return;
32226
+ }
32227
+ case "error": {
32228
+ if (!message.requestId) {
32229
+ return;
32230
+ }
32231
+ const pending = this.pending.get(message.requestId);
32232
+ if (!pending) {
32233
+ return;
32234
+ }
32235
+ this.pending.delete(message.requestId);
32236
+ pending.reject(new OpensteerCloudAutomationError(message.error));
32237
+ return;
32238
+ }
32239
+ case "event":
32240
+ void this.handleEvent(message.event, message.data);
32241
+ return;
32242
+ case "pong":
32243
+ return;
32244
+ }
32245
+ }
32246
+ async handleEvent(event, payload) {
32247
+ if (event !== "route.request") {
32248
+ return;
32249
+ }
32250
+ const data = asRecord(payload);
32251
+ const request = asRecord(data.request);
32252
+ const original = asRecord(data.original);
32253
+ const routeId = typeof data.routeId === "string" ? data.routeId : "";
32254
+ const routeRequestId = typeof data.routeRequestId === "string" ? data.routeRequestId : "";
32255
+ if (!routeId || !routeRequestId) {
32256
+ return;
32257
+ }
32258
+ const registration = this.routes.get(routeId);
32259
+ if (!registration) {
32260
+ await this.invoke("route.resolve", {
32261
+ routeRequestId,
32262
+ decision: { kind: "continue" }
32263
+ }).catch(() => void 0);
32264
+ return;
32265
+ }
32266
+ try {
32267
+ const decision = registration.kind === "route" ? await registration.input.handler({
32268
+ request: toRouteRequest(request),
32269
+ fetchOriginal: async () => toFetchedRouteResponse(original)
32270
+ }) : {
32271
+ kind: "fulfill",
32272
+ body: await registration.input.handler({
32273
+ url: typeof request.url === "string" ? request.url : "",
32274
+ content: typeof original.body === "string" ? original.body : "",
32275
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32276
+ status: typeof original.status === "number" ? original.status : 200
32277
+ }),
32278
+ headers: Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32279
+ status: typeof original.status === "number" ? original.status : 200,
32280
+ contentType: findHeaderValue(
32281
+ Array.isArray(original.headers) ? original.headers.filter(isHeaderEntry) : [],
32282
+ "content-type"
32283
+ ) ?? "application/javascript; charset=utf-8"
32284
+ };
32285
+ await this.invoke("route.resolve", {
32286
+ routeRequestId,
32287
+ decision: serializeRouteDecision(decision)
32288
+ }).catch(() => void 0);
32289
+ } catch {
32290
+ await this.invoke("route.resolve", {
32291
+ routeRequestId,
32292
+ decision: { kind: "continue" }
32293
+ }).catch(() => void 0);
32294
+ }
32295
+ }
32296
+ async issueGrant(kind) {
32297
+ if (this.grant && this.grant.kind === kind && this.grant.expiresAt > Date.now() + 1e4) {
32298
+ return this.grant;
32299
+ }
32300
+ const issued = await this.cloud.issueAccess(this.sessionId, [kind]);
32301
+ const grant = issued.grants[kind];
32302
+ if (!grant) {
32303
+ throw new OpensteerCloudAutomationError(
32304
+ createOpensteerError(
32305
+ "permission-denied",
32306
+ `cloud did not issue an ${kind} automation grant`
32307
+ )
32308
+ );
32309
+ }
32310
+ this.grant = grant;
32311
+ return grant;
32312
+ }
32313
+ requireSocket() {
32314
+ if (!this.socket || this.socket.readyState !== WebSocket2.OPEN) {
32315
+ throw new Error("cloud automation socket is not connected");
32316
+ }
32317
+ return this.socket;
32318
+ }
32319
+ send(message) {
32320
+ this.requireSocket().send(JSON.stringify(message));
32321
+ }
32322
+ };
32323
+ function assertCompatibleRuntimeCoreVersion(sessionInfo) {
32324
+ const runtimeCoreVersion = sessionInfo.runtime?.runtimeCoreVersion;
32325
+ if (runtimeCoreVersion === void 0) {
32326
+ return;
32327
+ }
32328
+ const expectedMajor = parseMajorVersion(OPENSTEER_RUNTIME_CORE_VERSION);
32329
+ const actualMajor = parseMajorVersion(runtimeCoreVersion);
32330
+ if (expectedMajor === null || actualMajor === null || expectedMajor === actualMajor) {
32331
+ return;
32332
+ }
32333
+ throw new Error(
32334
+ `cloud runtime-core major version ${runtimeCoreVersion} is incompatible with local SDK runtime-core ${OPENSTEER_RUNTIME_CORE_VERSION}`
32335
+ );
31466
32336
  }
31467
- async function readPersistedCloudSessionRecord(rootPath) {
31468
- const sessionPath = resolveCloudSessionRecordPath(rootPath);
31469
- if (!await pathExists(sessionPath)) {
31470
- return void 0;
32337
+ function parseMajorVersion(version) {
32338
+ const major = Number.parseInt(version.split(".", 1)[0] ?? "", 10);
32339
+ return Number.isFinite(major) ? major : null;
32340
+ }
32341
+ function serializeRouteDecision(decision) {
32342
+ if (decision.kind === "continue") {
32343
+ return { kind: "continue" };
31471
32344
  }
31472
- const parsed = await readJsonFile(sessionPath);
31473
- if (parsed.layout !== CLOUD_SESSION_LAYOUT || parsed.version !== CLOUD_SESSION_VERSION || parsed.mode !== "cloud" || typeof parsed.sessionId !== "string" || parsed.sessionId.length === 0 || typeof parsed.baseUrl !== "string" || parsed.baseUrl.length === 0 || typeof parsed.startedAt !== "number" || !Number.isFinite(parsed.startedAt) || typeof parsed.updatedAt !== "number" || !Number.isFinite(parsed.updatedAt)) {
32345
+ if (decision.kind === "abort") {
32346
+ return {
32347
+ kind: "abort",
32348
+ ...decision.errorCode === void 0 ? {} : { errorCode: decision.errorCode }
32349
+ };
32350
+ }
32351
+ return {
32352
+ kind: "fulfill",
32353
+ ...decision.status === void 0 ? {} : { status: decision.status },
32354
+ ...decision.headers === void 0 ? {} : { headers: decision.headers },
32355
+ ...decision.body === void 0 ? {} : typeof decision.body === "string" ? { body: decision.body } : { bodyBase64: Buffer.from(decision.body).toString("base64") },
32356
+ ...decision.contentType === void 0 ? {} : { contentType: decision.contentType }
32357
+ };
32358
+ }
32359
+ function toRouteRequest(record) {
32360
+ const pageRef = typeof record.pageRef === "string" ? record.pageRef : void 0;
32361
+ return {
32362
+ url: typeof record.url === "string" ? record.url : "",
32363
+ method: typeof record.method === "string" ? record.method : "GET",
32364
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32365
+ resourceType: typeof record.resourceType === "string" ? record.resourceType : "other",
32366
+ ...pageRef === void 0 ? {} : { pageRef },
32367
+ ...typeof record.postData === "string" ? {
32368
+ postData: {
32369
+ bytes: Uint8Array.from(Buffer.from(record.postData)),
32370
+ encoding: "identity",
32371
+ truncated: false,
32372
+ capturedByteLength: Buffer.byteLength(record.postData)
32373
+ }
32374
+ } : {}
32375
+ };
32376
+ }
32377
+ function toFetchedRouteResponse(record) {
32378
+ return {
32379
+ url: typeof record.url === "string" ? record.url : "",
32380
+ status: typeof record.status === "number" ? record.status : 200,
32381
+ statusText: typeof record.statusText === "string" ? record.statusText : "OK",
32382
+ headers: Array.isArray(record.headers) ? record.headers.filter(isHeaderEntry) : [],
32383
+ ...typeof record.body === "string" ? {
32384
+ body: {
32385
+ bytes: Uint8Array.from(Buffer.from(record.body)),
32386
+ encoding: "identity",
32387
+ truncated: false,
32388
+ capturedByteLength: Buffer.byteLength(record.body)
32389
+ }
32390
+ } : {},
32391
+ redirected: Boolean(record.redirected)
32392
+ };
32393
+ }
32394
+ function findHeaderValue(headers, name) {
32395
+ return headers.find((header) => header.name.toLowerCase() === name)?.value;
32396
+ }
32397
+ function isHeaderEntry(value) {
32398
+ return value !== null && typeof value === "object" && typeof value.name === "string" && typeof value.value === "string";
32399
+ }
32400
+ function asRecord(value) {
32401
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
32402
+ return {};
32403
+ }
32404
+ return value;
32405
+ }
32406
+
32407
+ // src/cloud/registry-sync.ts
32408
+ var REGISTRY_SYNC_MAX_PAYLOAD_BYTES = 15e5;
32409
+ var REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH = 100;
32410
+ async function syncLocalRegistryToCloud(client, workspace, store) {
32411
+ const [descriptors, requestPlans, recipes, authRecipes] = await Promise.all([
32412
+ store.registry.descriptors.list(),
32413
+ store.registry.requestPlans.list(),
32414
+ store.registry.recipes.list(),
32415
+ store.registry.authRecipes.list()
32416
+ ]);
32417
+ const selectorEntries = descriptors.flatMap((record) => {
32418
+ const entry = toSelectorCacheImportEntry(workspace, record);
32419
+ return entry === void 0 ? [] : [entry];
32420
+ });
32421
+ await Promise.all([
32422
+ importInBatches(selectorEntries, (entries) => client.importSelectorCache(entries)),
32423
+ importInBatches(
32424
+ requestPlans.map((record) => toRequestPlanImportEntry(workspace, record)),
32425
+ (entries) => client.importRequestPlans(entries)
32426
+ ),
32427
+ importInBatches(
32428
+ recipes.map((record) => toRegistryImportEntry(workspace, record)),
32429
+ (entries) => client.importRecipes(entries)
32430
+ ),
32431
+ importInBatches(
32432
+ authRecipes.map((record) => toRegistryImportEntry(workspace, record)),
32433
+ (entries) => client.importAuthRecipes(entries)
32434
+ )
32435
+ ]);
32436
+ }
32437
+ function toSelectorCacheImportEntry(workspace, record) {
32438
+ const descriptor = parseDomDescriptorRecord(record);
32439
+ if (descriptor === void 0) {
31474
32440
  return void 0;
31475
32441
  }
31476
32442
  return {
31477
- layout: CLOUD_SESSION_LAYOUT,
31478
- version: CLOUD_SESSION_VERSION,
31479
- mode: "cloud",
31480
- ...parsed.workspace === void 0 ? {} : { workspace: parsed.workspace },
31481
- sessionId: parsed.sessionId,
31482
- baseUrl: parsed.baseUrl,
31483
- startedAt: parsed.startedAt,
31484
- updatedAt: parsed.updatedAt
32443
+ workspace,
32444
+ method: descriptor.payload.method,
32445
+ descriptionHash: hashDomDescriptorDescription(descriptor.payload.description),
32446
+ description: descriptor.payload.description,
32447
+ path: descriptor.payload.path,
32448
+ createdAt: descriptor.createdAt,
32449
+ updatedAt: descriptor.updatedAt
32450
+ };
32451
+ }
32452
+ function toRegistryImportEntry(workspace, record) {
32453
+ return {
32454
+ workspace,
32455
+ recordId: record.id,
32456
+ key: record.key,
32457
+ version: record.version,
32458
+ contentHash: record.contentHash,
32459
+ tags: record.tags,
32460
+ ...record.provenance === void 0 ? {} : { provenance: record.provenance },
32461
+ payload: record.payload,
32462
+ createdAt: record.createdAt,
32463
+ updatedAt: record.updatedAt
32464
+ };
32465
+ }
32466
+ function toRequestPlanImportEntry(workspace, record) {
32467
+ return {
32468
+ workspace,
32469
+ recordId: record.id,
32470
+ key: record.key,
32471
+ version: record.version,
32472
+ contentHash: record.contentHash,
32473
+ tags: record.tags,
32474
+ ...record.provenance === void 0 ? {} : { provenance: record.provenance },
32475
+ payload: record.payload,
32476
+ ...record.freshness === void 0 ? {} : { freshness: record.freshness },
32477
+ createdAt: record.createdAt,
32478
+ updatedAt: record.updatedAt
31485
32479
  };
31486
32480
  }
31487
- async function hasPersistedCloudSession(rootPath) {
31488
- return await readPersistedCloudSessionRecord(rootPath) !== void 0;
32481
+ async function importInBatches(entries, importBatch) {
32482
+ if (entries.length === 0) {
32483
+ return;
32484
+ }
32485
+ for (const batch of chunkEntries(entries)) {
32486
+ await importBatch(batch);
32487
+ }
31489
32488
  }
32489
+ function chunkEntries(entries) {
32490
+ const batches = [];
32491
+ let currentBatch = [];
32492
+ for (const entry of entries) {
32493
+ if (payloadByteLength([entry]) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
32494
+ continue;
32495
+ }
32496
+ if (currentBatch.length === 0) {
32497
+ currentBatch = [entry];
32498
+ continue;
32499
+ }
32500
+ const nextBatch = [...currentBatch, entry];
32501
+ if (nextBatch.length > REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH || payloadByteLength(nextBatch) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
32502
+ batches.push(currentBatch);
32503
+ currentBatch = [entry];
32504
+ continue;
32505
+ }
32506
+ currentBatch = nextBatch;
32507
+ }
32508
+ if (currentBatch.length > 0) {
32509
+ batches.push(currentBatch);
32510
+ }
32511
+ return batches;
32512
+ }
32513
+ function payloadByteLength(entries) {
32514
+ return Buffer.byteLength(JSON.stringify({ entries }), "utf8");
32515
+ }
32516
+
32517
+ // src/cloud/session-proxy.ts
32518
+ var TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
31490
32519
  var CloudSessionProxy = class {
31491
32520
  rootPath;
31492
32521
  workspace;
@@ -31495,6 +32524,7 @@ var CloudSessionProxy = class {
31495
32524
  sessionId;
31496
32525
  sessionBaseUrl;
31497
32526
  client;
32527
+ automation;
31498
32528
  workspaceStore;
31499
32529
  constructor(cloud, options = {}) {
31500
32530
  this.cloud = cloud;
@@ -31515,27 +32545,73 @@ var CloudSessionProxy = class {
31515
32545
  ...input.url === void 0 ? {} : { url: input.url }
31516
32546
  });
31517
32547
  }
32548
+ async info() {
32549
+ const persisted = this.client !== void 0 || this.sessionId !== void 0 ? void 0 : await this.loadPersistedSession();
32550
+ if (this.client === void 0 && this.sessionId === void 0 && persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
32551
+ this.bindClient(persisted);
32552
+ }
32553
+ if (this.automation) {
32554
+ try {
32555
+ const sessionInfo = await this.automation.getSessionInfo();
32556
+ return {
32557
+ ...sessionInfo,
32558
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace }
32559
+ };
32560
+ } catch {
32561
+ }
32562
+ }
32563
+ return {
32564
+ provider: {
32565
+ kind: "cloud",
32566
+ ownership: "managed",
32567
+ engine: "playwright",
32568
+ baseUrl: this.cloud.getConfig().baseUrl
32569
+ },
32570
+ ...this.workspace === void 0 ? {} : { workspace: this.workspace },
32571
+ ...this.sessionId === void 0 ? persisted?.sessionId === void 0 ? {} : { sessionId: persisted.sessionId } : { sessionId: this.sessionId },
32572
+ reconnectable: this.workspace !== void 0 || this.sessionId !== void 0 || persisted !== void 0,
32573
+ capabilities: {
32574
+ semanticOperations: opensteerSemanticOperationNames,
32575
+ sessionGrants: ["automation", "view", "cdp"],
32576
+ instrumentation: {
32577
+ route: true,
32578
+ interceptScript: true,
32579
+ networkStream: true
32580
+ }
32581
+ },
32582
+ runtime: {
32583
+ protocolVersion: OPENSTEER_PROTOCOL_VERSION,
32584
+ runtimeCoreVersion: OPENSTEER_RUNTIME_CORE_VERSION
32585
+ }
32586
+ };
32587
+ }
31518
32588
  async listPages(input = {}) {
31519
- throw unsupportedCloudOperation("page.list");
32589
+ await this.ensureSession();
32590
+ return this.requireClient().invoke("page.list", input);
31520
32591
  }
31521
32592
  async newPage(input = {}) {
31522
- throw unsupportedCloudOperation("page.new");
32593
+ await this.ensureSession();
32594
+ return this.requireAutomation().invoke("page.new", input);
31523
32595
  }
31524
32596
  async activatePage(input) {
31525
- throw unsupportedCloudOperation("page.activate");
32597
+ await this.ensureSession();
32598
+ return this.requireClient().invoke("page.activate", input);
31526
32599
  }
31527
32600
  async closePage(input = {}) {
31528
- throw unsupportedCloudOperation("page.close");
32601
+ await this.ensureSession();
32602
+ return this.requireClient().invoke("page.close", input);
31529
32603
  }
31530
32604
  async goto(input) {
31531
32605
  await this.ensureSession();
31532
32606
  return this.requireClient().invoke("page.goto", input);
31533
32607
  }
31534
32608
  async evaluate(input) {
31535
- throw unsupportedCloudOperation("page.evaluate");
32609
+ await this.ensureSession();
32610
+ return this.requireAutomation().invoke("page.evaluate", input);
31536
32611
  }
31537
32612
  async addInitScript(input) {
31538
- throw unsupportedCloudOperation("page.add-init-script");
32613
+ await this.ensureSession();
32614
+ return this.requireClient().invoke("page.add-init-script", input);
31539
32615
  }
31540
32616
  async snapshot(input = {}) {
31541
32617
  await this.ensureSession();
@@ -31570,80 +32646,112 @@ var CloudSessionProxy = class {
31570
32646
  return this.requireClient().invoke("network.save", input);
31571
32647
  }
31572
32648
  async minimizeNetwork(input) {
31573
- throw unsupportedCloudOperation("network.minimize");
32649
+ await this.ensureSession();
32650
+ return this.requireClient().invoke("network.minimize", input);
31574
32651
  }
31575
32652
  async diffNetwork(input) {
31576
- throw unsupportedCloudOperation("network.diff");
32653
+ await this.ensureSession();
32654
+ return this.requireClient().invoke("network.diff", input);
31577
32655
  }
31578
32656
  async probeNetwork(input) {
31579
- throw unsupportedCloudOperation("network.probe");
32657
+ await this.ensureSession();
32658
+ return this.requireClient().invoke("network.probe", input);
31580
32659
  }
31581
32660
  async discoverReverse(input) {
31582
- throw unsupportedCloudOperation("reverse.discover");
32661
+ await this.ensureSession();
32662
+ return this.requireClient().invoke("reverse.discover", input);
31583
32663
  }
31584
32664
  async queryReverse(input) {
31585
- throw unsupportedCloudOperation("reverse.query");
32665
+ await this.ensureSession();
32666
+ return this.requireClient().invoke("reverse.query", input);
31586
32667
  }
31587
32668
  async createReversePackage(input) {
31588
- throw unsupportedCloudOperation("reverse.package.create");
32669
+ await this.ensureSession();
32670
+ return this.requireClient().invoke("reverse.package.create", input);
31589
32671
  }
31590
32672
  async runReversePackage(input) {
31591
- throw unsupportedCloudOperation("reverse.package.run");
32673
+ await this.ensureSession();
32674
+ return this.requireClient().invoke("reverse.package.run", input);
31592
32675
  }
31593
32676
  async exportReverse(input) {
31594
- throw unsupportedCloudOperation("reverse.export");
32677
+ await this.ensureSession();
32678
+ return this.requireClient().invoke("reverse.export", input);
31595
32679
  }
31596
32680
  async getReverseReport(input) {
31597
- throw unsupportedCloudOperation("reverse.report");
32681
+ await this.ensureSession();
32682
+ return this.requireClient().invoke("reverse.report", input);
31598
32683
  }
31599
32684
  async getReversePackage(input) {
31600
- throw unsupportedCloudOperation("reverse.package.get");
32685
+ await this.ensureSession();
32686
+ return this.requireClient().invoke("reverse.package.get", input);
31601
32687
  }
31602
32688
  async listReversePackages(input = {}) {
31603
- throw unsupportedCloudOperation("reverse.package.list");
32689
+ await this.ensureSession();
32690
+ return this.requireClient().invoke("reverse.package.list", input);
31604
32691
  }
31605
32692
  async patchReversePackage(input) {
31606
- throw unsupportedCloudOperation("reverse.package.patch");
32693
+ await this.ensureSession();
32694
+ return this.requireClient().invoke("reverse.package.patch", input);
31607
32695
  }
31608
32696
  async captureInteraction(input) {
31609
- throw unsupportedCloudOperation("interaction.capture");
32697
+ await this.ensureSession();
32698
+ return this.requireClient().invoke("interaction.capture", input);
31610
32699
  }
31611
32700
  async getInteraction(input) {
31612
- throw unsupportedCloudOperation("interaction.get");
32701
+ await this.ensureSession();
32702
+ return this.requireClient().invoke("interaction.get", input);
31613
32703
  }
31614
32704
  async diffInteraction(input) {
31615
- throw unsupportedCloudOperation("interaction.diff");
32705
+ await this.ensureSession();
32706
+ return this.requireClient().invoke("interaction.diff", input);
31616
32707
  }
31617
32708
  async replayInteraction(input) {
31618
- throw unsupportedCloudOperation("interaction.replay");
32709
+ await this.ensureSession();
32710
+ return this.requireClient().invoke("interaction.replay", input);
31619
32711
  }
31620
32712
  async clearNetwork(input = {}) {
31621
32713
  await this.ensureSession();
31622
32714
  return this.requireClient().invoke("network.clear", input);
31623
32715
  }
31624
32716
  async captureScripts(input = {}) {
31625
- throw unsupportedCloudOperation("scripts.capture");
32717
+ await this.ensureSession();
32718
+ return this.requireClient().invoke("scripts.capture", input);
31626
32719
  }
31627
32720
  async readArtifact(input) {
31628
- throw unsupportedCloudOperation("artifact.read");
32721
+ await this.ensureSession();
32722
+ return this.requireClient().invoke("artifact.read", input);
31629
32723
  }
31630
32724
  async beautifyScript(input) {
31631
- throw unsupportedCloudOperation("scripts.beautify");
32725
+ await this.ensureSession();
32726
+ return this.requireClient().invoke("scripts.beautify", input);
31632
32727
  }
31633
32728
  async deobfuscateScript(input) {
31634
- throw unsupportedCloudOperation("scripts.deobfuscate");
32729
+ await this.ensureSession();
32730
+ return this.requireClient().invoke("scripts.deobfuscate", input);
31635
32731
  }
31636
32732
  async sandboxScript(input) {
31637
- throw unsupportedCloudOperation("scripts.sandbox");
32733
+ await this.ensureSession();
32734
+ return this.requireClient().invoke("scripts.sandbox", input);
31638
32735
  }
31639
32736
  async solveCaptcha(input) {
31640
- throw unsupportedCloudOperation("captcha.solve");
32737
+ await this.ensureSession();
32738
+ return this.requireClient().invoke("captcha.solve", input);
31641
32739
  }
31642
32740
  async getCookies(input = {}) {
31643
- throw unsupportedCloudOperation("inspect.cookies");
32741
+ await this.ensureSession();
32742
+ return this.requireAutomation().invoke("inspect.cookies", input);
32743
+ }
32744
+ async route(input) {
32745
+ await this.ensureSession();
32746
+ return this.requireAutomation().route(input);
32747
+ }
32748
+ async interceptScript(input) {
32749
+ await this.ensureSession();
32750
+ return this.requireAutomation().interceptScript(input);
31644
32751
  }
31645
32752
  async getStorageSnapshot(input = {}) {
31646
- throw unsupportedCloudOperation("inspect.storage");
32753
+ await this.ensureSession();
32754
+ return this.requireClient().invoke("inspect.storage", input);
31647
32755
  }
31648
32756
  async rawRequest(input) {
31649
32757
  await this.ensureSession();
@@ -31666,28 +32774,36 @@ var CloudSessionProxy = class {
31666
32774
  return this.requireClient().invoke("request-plan.list", input);
31667
32775
  }
31668
32776
  async writeAuthRecipe(input) {
31669
- throw unsupportedCloudOperation("auth-recipe.write");
32777
+ await this.ensureSession();
32778
+ return this.requireClient().invoke("auth-recipe.write", input);
31670
32779
  }
31671
32780
  async writeRecipe(input) {
31672
- throw unsupportedCloudOperation("recipe.write");
32781
+ await this.ensureSession();
32782
+ return this.requireClient().invoke("recipe.write", input);
31673
32783
  }
31674
32784
  async getAuthRecipe(input) {
31675
- throw unsupportedCloudOperation("auth-recipe.get");
32785
+ await this.ensureSession();
32786
+ return this.requireClient().invoke("auth-recipe.get", input);
31676
32787
  }
31677
32788
  async getRecipe(input) {
31678
- throw unsupportedCloudOperation("recipe.get");
32789
+ await this.ensureSession();
32790
+ return this.requireClient().invoke("recipe.get", input);
31679
32791
  }
31680
32792
  async listAuthRecipes(input = {}) {
31681
- throw unsupportedCloudOperation("auth-recipe.list");
32793
+ await this.ensureSession();
32794
+ return this.requireClient().invoke("auth-recipe.list", input);
31682
32795
  }
31683
32796
  async listRecipes(input = {}) {
31684
- throw unsupportedCloudOperation("recipe.list");
32797
+ await this.ensureSession();
32798
+ return this.requireClient().invoke("recipe.list", input);
31685
32799
  }
31686
32800
  async runAuthRecipe(input) {
31687
- throw unsupportedCloudOperation("auth-recipe.run");
32801
+ await this.ensureSession();
32802
+ return this.requireClient().invoke("auth-recipe.run", input);
31688
32803
  }
31689
32804
  async runRecipe(input) {
31690
- throw unsupportedCloudOperation("recipe.run");
32805
+ await this.ensureSession();
32806
+ return this.requireClient().invoke("recipe.run", input);
31691
32807
  }
31692
32808
  async request(input) {
31693
32809
  await this.ensureSession();
@@ -31699,9 +32815,9 @@ var CloudSessionProxy = class {
31699
32815
  }
31700
32816
  async close() {
31701
32817
  const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 || this.sessionBaseUrl === void 0 ? void 0 : {
31702
- layout: CLOUD_SESSION_LAYOUT,
31703
- version: CLOUD_SESSION_VERSION,
31704
- mode: "cloud",
32818
+ layout: "opensteer-session",
32819
+ version: 1,
32820
+ provider: "cloud",
31705
32821
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31706
32822
  sessionId: this.sessionId,
31707
32823
  baseUrl: this.sessionBaseUrl,
@@ -31718,7 +32834,9 @@ var CloudSessionProxy = class {
31718
32834
  });
31719
32835
  }
31720
32836
  } finally {
32837
+ await this.automation?.close().catch(() => void 0);
31721
32838
  await this.clearPersistedSession();
32839
+ this.automation = void 0;
31722
32840
  this.client = void 0;
31723
32841
  this.sessionId = void 0;
31724
32842
  this.sessionBaseUrl = void 0;
@@ -31734,6 +32852,8 @@ var CloudSessionProxy = class {
31734
32852
  return;
31735
32853
  }
31736
32854
  this.client = void 0;
32855
+ await this.automation?.close().catch(() => void 0);
32856
+ this.automation = void 0;
31737
32857
  this.sessionId = void 0;
31738
32858
  this.sessionBaseUrl = void 0;
31739
32859
  }
@@ -31744,9 +32864,11 @@ var CloudSessionProxy = class {
31744
32864
  assertSupportedCloudBrowserMode(input.browser);
31745
32865
  const persisted = await this.loadPersistedSession();
31746
32866
  if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
32867
+ await this.syncRegistryToCloud();
31747
32868
  this.bindClient(persisted);
31748
32869
  return;
31749
32870
  }
32871
+ await this.syncRegistryToCloud();
31750
32872
  const session = await this.cloud.createSession({
31751
32873
  ...this.workspace === void 0 ? {} : { name: this.workspace },
31752
32874
  ...input.launch === void 0 ? {} : { browser: input.launch },
@@ -31754,9 +32876,9 @@ var CloudSessionProxy = class {
31754
32876
  ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
31755
32877
  });
31756
32878
  const record = {
31757
- layout: CLOUD_SESSION_LAYOUT,
31758
- version: CLOUD_SESSION_VERSION,
31759
- mode: "cloud",
32879
+ layout: "opensteer-session",
32880
+ version: 1,
32881
+ provider: "cloud",
31760
32882
  ...this.workspace === void 0 ? {} : { workspace: this.workspace },
31761
32883
  sessionId: session.sessionId,
31762
32884
  baseUrl: session.baseUrl,
@@ -31766,6 +32888,16 @@ var CloudSessionProxy = class {
31766
32888
  await this.writePersistedSession(record);
31767
32889
  this.bindClient(record);
31768
32890
  }
32891
+ async syncRegistryToCloud() {
32892
+ if (this.workspace === void 0) {
32893
+ return;
32894
+ }
32895
+ try {
32896
+ const workspaceStore = await this.ensureWorkspaceStore();
32897
+ await syncLocalRegistryToCloud(this.cloud, this.workspace, workspaceStore);
32898
+ } catch {
32899
+ }
32900
+ }
31769
32901
  bindClient(record) {
31770
32902
  this.sessionId = record.sessionId;
31771
32903
  this.sessionBaseUrl = record.baseUrl;
@@ -31773,6 +32905,7 @@ var CloudSessionProxy = class {
31773
32905
  baseUrl: record.baseUrl,
31774
32906
  getAuthorizationHeader: async () => this.cloud.buildAuthorizationHeader()
31775
32907
  });
32908
+ this.automation = new OpensteerCloudAutomationClient(this.cloud, record.sessionId);
31776
32909
  }
31777
32910
  async ensureWorkspaceStore() {
31778
32911
  if (this.workspaceStore !== void 0) {
@@ -31791,10 +32924,10 @@ var CloudSessionProxy = class {
31791
32924
  }
31792
32925
  async writePersistedSession(record) {
31793
32926
  const workspace = await this.ensureWorkspaceStore();
31794
- await writeJsonFileAtomic(resolveCloudSessionRecordPath(workspace.rootPath), record);
32927
+ await writePersistedSessionRecord(workspace.rootPath, record);
31795
32928
  }
31796
32929
  async clearPersistedSession() {
31797
- await rm(resolveCloudSessionRecordPath(this.rootPath), { force: true }).catch(() => void 0);
32930
+ await clearPersistedSessionRecord(this.rootPath, "cloud").catch(() => void 0);
31798
32931
  }
31799
32932
  async isReusableCloudSession(sessionId) {
31800
32933
  try {
@@ -31813,6 +32946,12 @@ var CloudSessionProxy = class {
31813
32946
  }
31814
32947
  return this.client;
31815
32948
  }
32949
+ requireAutomation() {
32950
+ if (!this.automation) {
32951
+ throw new Error("Cloud automation session has not been initialized.");
32952
+ }
32953
+ return this.automation;
32954
+ }
31816
32955
  };
31817
32956
  function resolveCloudBrowserProfile(cloud, input) {
31818
32957
  return input.browserProfile ?? cloud.getConfig().browserProfile;
@@ -31828,49 +32967,33 @@ function assertSupportedCloudBrowserMode(browser) {
31828
32967
  function isMissingCloudSessionError(error) {
31829
32968
  return error instanceof Error && /\b404\b/.test(error.message);
31830
32969
  }
31831
- function unsupportedCloudOperation(operation) {
31832
- return new OpensteerProtocolError(
31833
- "unsupported-operation",
31834
- `Cloud mode does not currently support ${operation}.`,
31835
- {
31836
- details: {
31837
- mode: "cloud",
31838
- operation,
31839
- supportedOperations: [...SUPPORTED_CLOUD_OPERATIONS]
31840
- }
31841
- }
31842
- );
31843
- }
31844
32970
 
31845
32971
  // src/sdk/runtime-resolution.ts
31846
32972
  function resolveOpensteerRuntimeConfig(input = {}) {
31847
- const mode = resolveOpensteerExecutionMode({
31848
- ...input.mode === void 0 ? {} : { explicit: input.mode },
31849
- cloud: input.cloud !== void 0 && input.cloud !== false,
31850
- ...input.environmentMode === void 0 ? {} : { environment: input.environmentMode }
32973
+ const provider = resolveOpensteerProvider({
32974
+ ...input.provider === void 0 ? {} : { provider: input.provider },
32975
+ ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
31851
32976
  });
31852
- if (mode === "cloud") {
32977
+ if (provider.kind === "cloud") {
31853
32978
  return {
31854
- mode,
32979
+ provider,
31855
32980
  cloud: resolveCloudConfig({
31856
- enabled: true,
31857
- ...typeof input.cloud === "object" ? input.cloud : {},
31858
- mode
32981
+ ...input.provider === void 0 ? {} : { provider: input.provider },
32982
+ ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
31859
32983
  })
31860
32984
  };
31861
32985
  }
31862
- return { mode };
32986
+ return { provider };
31863
32987
  }
31864
32988
  function createOpensteerSemanticRuntime(input = {}) {
31865
32989
  const runtimeOptions = input.runtimeOptions ?? {};
31866
32990
  const engine = input.engine ?? runtimeOptions.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31867
32991
  const config = resolveOpensteerRuntimeConfig({
31868
- ...input.cloud === void 0 ? {} : { cloud: input.cloud },
31869
- ...input.mode === void 0 ? {} : { mode: input.mode },
31870
- ...process.env.OPENSTEER_MODE === void 0 ? {} : { environmentMode: process.env.OPENSTEER_MODE }
32992
+ ...input.provider === void 0 ? {} : { provider: input.provider },
32993
+ ...process.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process.env.OPENSTEER_PROVIDER }
31871
32994
  });
31872
- assertExecutionModeSupportsEngine(config.mode, engine);
31873
- if (config.mode === "cloud") {
32995
+ assertProviderSupportsEngine(config.provider.kind, engine);
32996
+ if (config.provider.kind === "cloud") {
31874
32997
  return new CloudSessionProxy(new OpensteerCloudClient(config.cloud), {
31875
32998
  ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
31876
32999
  ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
@@ -31884,6 +33007,6 @@ function createOpensteerSemanticRuntime(input = {}) {
31884
33007
  });
31885
33008
  }
31886
33009
 
31887
- export { CloudSessionProxy, DEFAULT_OPENSTEER_ENGINE, DEFERRED_MATCH_ATTR_KEYS, ElementPathError, MATCH_ATTRIBUTE_PRIORITY, OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL, OPENSTEER_ENGINE_NAMES, OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OpensteerAttachAmbiguousError, OpensteerBrowserManager, OpensteerCloudClient, OpensteerRuntime, STABLE_PRIMARY_ATTR_KEYS, assertExecutionModeSupportsEngine, buildArrayFieldPathCandidates, buildPathCandidates, buildPathSelectorHint, buildSegmentSelector, cloneElementPath, cloneReplayElementPath, cloneStructuralElementAnchor, createDomRuntime, createFilesystemOpensteerWorkspace, createOpensteerSemanticRuntime, defaultFallbackPolicy, defaultPolicy, defaultRetryPolicy, defaultSettlePolicy, defaultTimeoutPolicy, delayWithSignal, discoverLocalCdpBrowsers, dispatchSemanticOperation, hasPersistedCloudSession, inspectCdpEndpoint, isCurrentUrlField, isValidCssAttributeKey, listLocalChromeProfiles, normalizeExtractedValue, normalizeOpensteerEngineName, normalizeOpensteerExecutionMode, normalizeWorkspaceId, readPersistedCloudSessionRecord, resolveCloudConfig, resolveCloudSessionRecordPath, resolveDomActionBridge, resolveExtractedValueInContext, resolveFilesystemWorkspacePath, resolveOpensteerEngineName, resolveOpensteerExecutionMode, resolveOpensteerRuntimeConfig, runWithPolicyTimeout, sanitizeElementPath, sanitizeReplayElementPath, sanitizeStructuralElementAnchor, settleWithPolicy, shouldKeepAttributeForPath };
31888
- //# sourceMappingURL=chunk-X3G6QSCF.js.map
31889
- //# sourceMappingURL=chunk-X3G6QSCF.js.map
33010
+ export { CloudSessionProxy, DEFAULT_OPENSTEER_ENGINE, DEFERRED_MATCH_ATTR_KEYS, ElementPathError, MATCH_ATTRIBUTE_PRIORITY, OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL, OPENSTEER_ENGINE_NAMES, OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OpensteerAttachAmbiguousError, OpensteerBrowserManager, OpensteerCloudClient, OpensteerRuntime, OpensteerSessionRuntime2 as OpensteerSessionRuntime, STABLE_PRIMARY_ATTR_KEYS, assertProviderSupportsEngine, buildArrayFieldPathCandidates, buildPathCandidates, buildPathSelectorHint, buildSegmentSelector, clearPersistedSessionRecord, cloneElementPath, cloneReplayElementPath, cloneStructuralElementAnchor, createDomRuntime, createFilesystemOpensteerWorkspace, createOpensteerSemanticRuntime, defaultFallbackPolicy, defaultPolicy, defaultRetryPolicy, defaultSettlePolicy, defaultTimeoutPolicy, delayWithSignal, discoverLocalCdpBrowsers, dispatchSemanticOperation, inspectCdpEndpoint, isCurrentUrlField, isProcessRunning, isValidCssAttributeKey, listLocalChromeProfiles, normalizeExtractedValue, normalizeOpensteerEngineName, normalizeOpensteerProviderKind, normalizeWorkspaceId, pathExists, readPersistedCloudSessionRecord, readPersistedLocalBrowserSessionRecord, readPersistedSessionRecord, resolveCloudConfig, resolveCloudSessionRecordPath, resolveDomActionBridge, resolveExtractedValueInContext, resolveFilesystemWorkspacePath, resolveLiveSessionRecordPath, resolveLocalSessionRecordPath, resolveOpensteerEngineName, resolveOpensteerProvider, resolveOpensteerRuntimeConfig, runWithPolicyTimeout, sanitizeElementPath, sanitizeReplayElementPath, sanitizeStructuralElementAnchor, settleWithPolicy, shouldKeepAttributeForPath, writePersistedSessionRecord };
33011
+ //# sourceMappingURL=chunk-C7GWMSTV.js.map
33012
+ //# sourceMappingURL=chunk-C7GWMSTV.js.map