opensteer 0.8.8 → 0.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var path6 = require('path');
3
+ var path7 = require('path');
4
4
  var crypto = require('crypto');
5
5
  var promises = require('fs/promises');
6
6
  var url = require('url');
@@ -10,6 +10,7 @@ var os = require('os');
10
10
  var enginePlaywright = require('@opensteer/engine-playwright');
11
11
  var util = require('util');
12
12
  var fs = require('fs');
13
+ var async_hooks = require('async_hooks');
13
14
  var module$1 = require('module');
14
15
  var sharp = require('sharp');
15
16
  var cheerio = require('cheerio');
@@ -39,14 +40,19 @@ function _interopNamespace(e) {
39
40
  return Object.freeze(n);
40
41
  }
41
42
 
42
- var path6__default = /*#__PURE__*/_interopDefault(path6);
43
+ var path7__default = /*#__PURE__*/_interopDefault(path7);
43
44
  var sharp__default = /*#__PURE__*/_interopDefault(sharp);
44
45
  var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio);
45
46
  var prettier__namespace = /*#__PURE__*/_interopNamespace(prettier);
46
47
  var vm__default = /*#__PURE__*/_interopDefault(vm);
47
48
  var WebSocket2__default = /*#__PURE__*/_interopDefault(WebSocket2);
48
49
 
49
- // ../runtime-core/src/root.ts
50
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
51
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
52
+ }) : x)(function(x) {
53
+ if (typeof require !== "undefined") return require.apply(this, arguments);
54
+ throw Error('Dynamic require of "' + x + '" is not supported');
55
+ });
50
56
 
51
57
  // ../runtime-core/src/json.ts
52
58
  function isPlainObject(value) {
@@ -56,30 +62,30 @@ function isPlainObject(value) {
56
62
  const prototype = Object.getPrototypeOf(value);
57
63
  return prototype === Object.prototype || prototype === null;
58
64
  }
59
- function canonicalizeJsonValue(value, path13) {
65
+ function canonicalizeJsonValue(value, path15) {
60
66
  if (value === null || typeof value === "string" || typeof value === "boolean") {
61
67
  return value;
62
68
  }
63
69
  if (typeof value === "number") {
64
70
  if (!Number.isFinite(value)) {
65
- throw new TypeError(`${path13} must be a finite JSON number`);
71
+ throw new TypeError(`${path15} must be a finite JSON number`);
66
72
  }
67
73
  return value;
68
74
  }
69
75
  if (Array.isArray(value)) {
70
- return value.map((entry, index) => canonicalizeJsonValue(entry, `${path13}[${index}]`));
76
+ return value.map((entry, index) => canonicalizeJsonValue(entry, `${path15}[${index}]`));
71
77
  }
72
78
  if (!isPlainObject(value)) {
73
- throw new TypeError(`${path13} must be a plain JSON object`);
79
+ throw new TypeError(`${path15} must be a plain JSON object`);
74
80
  }
75
81
  const sorted = Object.keys(value).sort((left, right) => left.localeCompare(right));
76
82
  const result = {};
77
83
  for (const key of sorted) {
78
84
  const entry = value[key];
79
85
  if (entry === void 0) {
80
- throw new TypeError(`${path13}.${key} must not be undefined`);
86
+ throw new TypeError(`${path15}.${key} must not be undefined`);
81
87
  }
82
- result[key] = canonicalizeJsonValue(entry, `${path13}.${key}`);
88
+ result[key] = canonicalizeJsonValue(entry, `${path15}.${key}`);
83
89
  }
84
90
  return result;
85
91
  }
@@ -116,7 +122,7 @@ function joinStoragePath(...segments) {
116
122
  return segments.join("/");
117
123
  }
118
124
  function resolveStoragePath(rootPath, relativePath) {
119
- if (path6__default.default.isAbsolute(relativePath)) {
125
+ if (path7__default.default.isAbsolute(relativePath)) {
120
126
  throw new TypeError(`storage path ${relativePath} must be relative`);
121
127
  }
122
128
  const segments = relativePath.split("/");
@@ -128,7 +134,7 @@ function resolveStoragePath(rootPath, relativePath) {
128
134
  throw new TypeError(`storage path ${relativePath} must not contain path traversal`);
129
135
  }
130
136
  }
131
- return path6__default.default.join(rootPath, ...segments);
137
+ return path7__default.default.join(rootPath, ...segments);
132
138
  }
133
139
  async function ensureDirectory(directoryPath) {
134
140
  await promises.mkdir(directoryPath, { recursive: true });
@@ -148,7 +154,7 @@ async function writeJsonFileAtomic(filePath, value) {
148
154
  await writeTextFileAtomic(filePath, stableJsonString(value));
149
155
  }
150
156
  async function writeTextFileAtomic(filePath, value) {
151
- await ensureDirectory(path6__default.default.dirname(filePath));
157
+ await ensureDirectory(path7__default.default.dirname(filePath));
152
158
  const temporaryPath = `${filePath}.${crypto.randomUUID()}.tmp`;
153
159
  await promises.writeFile(temporaryPath, value, "utf8");
154
160
  await promises.rename(temporaryPath, filePath);
@@ -157,7 +163,7 @@ async function writeJsonFileExclusive(filePath, value) {
157
163
  await writeTextFileExclusive(filePath, stableJsonString(value));
158
164
  }
159
165
  async function writeTextFileExclusive(filePath, value) {
160
- await ensureDirectory(path6__default.default.dirname(filePath));
166
+ await ensureDirectory(path7__default.default.dirname(filePath));
161
167
  const handle = await promises.open(filePath, "wx");
162
168
  try {
163
169
  await handle.writeFile(value, "utf8");
@@ -166,7 +172,7 @@ async function writeTextFileExclusive(filePath, value) {
166
172
  }
167
173
  }
168
174
  async function writeBufferIfMissing(filePath, value) {
169
- await ensureDirectory(path6__default.default.dirname(filePath));
175
+ await ensureDirectory(path7__default.default.dirname(filePath));
170
176
  try {
171
177
  const handle = await promises.open(filePath, "wx");
172
178
  try {
@@ -200,7 +206,7 @@ function isAlreadyExistsError(error) {
200
206
  return error?.code === "EEXIST";
201
207
  }
202
208
  async function withFilesystemLock(lockPath, task) {
203
- await ensureDirectory(path6__default.default.dirname(lockPath));
209
+ await ensureDirectory(path7__default.default.dirname(lockPath));
204
210
  let attempt = 0;
205
211
  while (true) {
206
212
  try {
@@ -212,7 +218,7 @@ async function withFilesystemLock(lockPath, task) {
212
218
  }
213
219
  const delayMs = LOCK_RETRY_DELAYS_MS[Math.min(attempt, LOCK_RETRY_DELAYS_MS.length - 1)];
214
220
  attempt += 1;
215
- await new Promise((resolve5) => setTimeout(resolve5, delayMs));
221
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
216
222
  }
217
223
  }
218
224
  try {
@@ -255,8 +261,8 @@ async function readStructuredPayload(objectPath) {
255
261
  var FilesystemArtifactStore = class {
256
262
  constructor(rootPath) {
257
263
  this.rootPath = rootPath;
258
- this.manifestsDirectory = path6__default.default.join(this.rootPath, "artifacts", "manifests");
259
- this.objectsDirectory = path6__default.default.join(this.rootPath, "artifacts", "objects", "sha256");
264
+ this.manifestsDirectory = path7__default.default.join(this.rootPath, "artifacts", "manifests");
265
+ this.objectsDirectory = path7__default.default.join(this.rootPath, "artifacts", "objects", "sha256");
260
266
  }
261
267
  manifestsDirectory;
262
268
  objectsDirectory;
@@ -481,7 +487,7 @@ var FilesystemArtifactStore = class {
481
487
  }
482
488
  }
483
489
  manifestPath(artifactId) {
484
- return path6__default.default.join(this.manifestsDirectory, `${encodePathSegment(artifactId)}.json`);
490
+ return path7__default.default.join(this.manifestsDirectory, `${encodePathSegment(artifactId)}.json`);
485
491
  }
486
492
  };
487
493
  function createArtifactStore(rootPath) {
@@ -576,31 +582,31 @@ function oneOfSchema(members, options = {}) {
576
582
  }
577
583
 
578
584
  // ../protocol/src/validation.ts
579
- function validateJsonSchema(schema, value, path13 = "$") {
580
- return validateSchemaNode(schema, value, path13);
585
+ function validateJsonSchema(schema, value, path15 = "$") {
586
+ return validateSchemaNode(schema, value, path15);
581
587
  }
582
- function validateSchemaNode(schema, value, path13) {
588
+ function validateSchemaNode(schema, value, path15) {
583
589
  const issues = [];
584
590
  if ("const" in schema && !isJsonValueEqual(schema.const, value)) {
585
591
  issues.push({
586
- path: path13,
592
+ path: path15,
587
593
  message: `must equal ${JSON.stringify(schema.const)}`
588
594
  });
589
595
  return issues;
590
596
  }
591
597
  if (schema.enum !== void 0 && !schema.enum.some((candidate) => isJsonValueEqual(candidate, value))) {
592
598
  issues.push({
593
- path: path13,
599
+ path: path15,
594
600
  message: `must be one of ${schema.enum.map((candidate) => JSON.stringify(candidate)).join(", ")}`
595
601
  });
596
602
  return issues;
597
603
  }
598
604
  if (schema.oneOf !== void 0) {
599
- const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path13));
605
+ const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path15));
600
606
  const validBranches = branchIssues.filter((current) => current.length === 0).length;
601
607
  if (validBranches !== 1) {
602
608
  issues.push({
603
- path: path13,
609
+ path: path15,
604
610
  message: validBranches === 0 ? "must match exactly one supported shape" : "matches multiple supported shapes"
605
611
  });
606
612
  return issues;
@@ -608,11 +614,11 @@ function validateSchemaNode(schema, value, path13) {
608
614
  }
609
615
  if (schema.anyOf !== void 0) {
610
616
  const hasMatch = schema.anyOf.some(
611
- (member) => validateSchemaNode(member, value, path13).length === 0
617
+ (member) => validateSchemaNode(member, value, path15).length === 0
612
618
  );
613
619
  if (!hasMatch) {
614
620
  issues.push({
615
- path: path13,
621
+ path: path15,
616
622
  message: "must match at least one supported shape"
617
623
  });
618
624
  return issues;
@@ -620,7 +626,7 @@ function validateSchemaNode(schema, value, path13) {
620
626
  }
621
627
  if (schema.allOf !== void 0) {
622
628
  for (const member of schema.allOf) {
623
- issues.push(...validateSchemaNode(member, value, path13));
629
+ issues.push(...validateSchemaNode(member, value, path15));
624
630
  }
625
631
  if (issues.length > 0) {
626
632
  return issues;
@@ -628,7 +634,7 @@ function validateSchemaNode(schema, value, path13) {
628
634
  }
629
635
  if (schema.type !== void 0 && !matchesSchemaType(schema.type, value)) {
630
636
  issues.push({
631
- path: path13,
637
+ path: path15,
632
638
  message: `must be ${describeSchemaType(schema.type)}`
633
639
  });
634
640
  return issues;
@@ -636,19 +642,19 @@ function validateSchemaNode(schema, value, path13) {
636
642
  if (typeof value === "string") {
637
643
  if (schema.minLength !== void 0 && value.length < schema.minLength) {
638
644
  issues.push({
639
- path: path13,
645
+ path: path15,
640
646
  message: `must have length >= ${String(schema.minLength)}`
641
647
  });
642
648
  }
643
649
  if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
644
650
  issues.push({
645
- path: path13,
651
+ path: path15,
646
652
  message: `must have length <= ${String(schema.maxLength)}`
647
653
  });
648
654
  }
649
655
  if (schema.pattern !== void 0 && !new RegExp(schema.pattern).test(value)) {
650
656
  issues.push({
651
- path: path13,
657
+ path: path15,
652
658
  message: `must match pattern ${schema.pattern}`
653
659
  });
654
660
  }
@@ -657,25 +663,25 @@ function validateSchemaNode(schema, value, path13) {
657
663
  if (typeof value === "number") {
658
664
  if (schema.minimum !== void 0 && value < schema.minimum) {
659
665
  issues.push({
660
- path: path13,
666
+ path: path15,
661
667
  message: `must be >= ${String(schema.minimum)}`
662
668
  });
663
669
  }
664
670
  if (schema.maximum !== void 0 && value > schema.maximum) {
665
671
  issues.push({
666
- path: path13,
672
+ path: path15,
667
673
  message: `must be <= ${String(schema.maximum)}`
668
674
  });
669
675
  }
670
676
  if (schema.exclusiveMinimum !== void 0 && value <= schema.exclusiveMinimum) {
671
677
  issues.push({
672
- path: path13,
678
+ path: path15,
673
679
  message: `must be > ${String(schema.exclusiveMinimum)}`
674
680
  });
675
681
  }
676
682
  if (schema.exclusiveMaximum !== void 0 && value >= schema.exclusiveMaximum) {
677
683
  issues.push({
678
- path: path13,
684
+ path: path15,
679
685
  message: `must be < ${String(schema.exclusiveMaximum)}`
680
686
  });
681
687
  }
@@ -684,13 +690,13 @@ function validateSchemaNode(schema, value, path13) {
684
690
  if (Array.isArray(value)) {
685
691
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
686
692
  issues.push({
687
- path: path13,
693
+ path: path15,
688
694
  message: `must have at least ${String(schema.minItems)} items`
689
695
  });
690
696
  }
691
697
  if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
692
698
  issues.push({
693
- path: path13,
699
+ path: path15,
694
700
  message: `must have at most ${String(schema.maxItems)} items`
695
701
  });
696
702
  }
@@ -700,7 +706,7 @@ function validateSchemaNode(schema, value, path13) {
700
706
  const key = JSON.stringify(item);
701
707
  if (seen.has(key)) {
702
708
  issues.push({
703
- path: path13,
709
+ path: path15,
704
710
  message: "must not contain duplicate items"
705
711
  });
706
712
  break;
@@ -710,7 +716,7 @@ function validateSchemaNode(schema, value, path13) {
710
716
  }
711
717
  if (schema.items !== void 0) {
712
718
  for (let index = 0; index < value.length; index += 1) {
713
- issues.push(...validateSchemaNode(schema.items, value[index], `${path13}[${String(index)}]`));
719
+ issues.push(...validateSchemaNode(schema.items, value[index], `${path15}[${String(index)}]`));
714
720
  }
715
721
  }
716
722
  return issues;
@@ -720,7 +726,7 @@ function validateSchemaNode(schema, value, path13) {
720
726
  for (const requiredKey of schema.required ?? []) {
721
727
  if (!(requiredKey in value)) {
722
728
  issues.push({
723
- path: joinObjectPath(path13, requiredKey),
729
+ path: joinObjectPath(path15, requiredKey),
724
730
  message: "is required"
725
731
  });
726
732
  }
@@ -729,13 +735,13 @@ function validateSchemaNode(schema, value, path13) {
729
735
  const propertySchema = properties[key];
730
736
  if (propertySchema !== void 0) {
731
737
  issues.push(
732
- ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path13, key))
738
+ ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path15, key))
733
739
  );
734
740
  continue;
735
741
  }
736
742
  if (schema.additionalProperties === false) {
737
743
  issues.push({
738
- path: joinObjectPath(path13, key),
744
+ path: joinObjectPath(path15, key),
739
745
  message: "is not allowed"
740
746
  });
741
747
  continue;
@@ -745,7 +751,7 @@ function validateSchemaNode(schema, value, path13) {
745
751
  ...validateSchemaNode(
746
752
  schema.additionalProperties,
747
753
  propertyValue,
748
- joinObjectPath(path13, key)
754
+ joinObjectPath(path15, key)
749
755
  )
750
756
  );
751
757
  }
@@ -989,8 +995,8 @@ function matchesNetworkRecordFilters(record, filters) {
989
995
  }
990
996
  }
991
997
  if (filters.path !== void 0) {
992
- const path13 = getParsedUrl().pathname;
993
- if (!includesCaseInsensitive(path13, filters.path)) {
998
+ const path15 = getParsedUrl().pathname;
999
+ if (!includesCaseInsensitive(path15, filters.path)) {
994
1000
  return false;
995
1001
  }
996
1002
  }
@@ -7080,9 +7086,9 @@ function compareByCreatedAtAndId(left, right) {
7080
7086
  var FilesystemRegistryStore = class {
7081
7087
  constructor(rootPath, registryRelativePath) {
7082
7088
  this.registryRelativePath = registryRelativePath;
7083
- const basePath = path6__default.default.join(rootPath, ...registryRelativePath);
7084
- this.recordsDirectory = path6__default.default.join(basePath, "records");
7085
- this.indexesDirectory = path6__default.default.join(basePath, "indexes", "by-key");
7089
+ const basePath = path7__default.default.join(rootPath, ...registryRelativePath);
7090
+ this.recordsDirectory = path7__default.default.join(basePath, "records");
7091
+ this.indexesDirectory = path7__default.default.join(basePath, "indexes", "by-key");
7086
7092
  }
7087
7093
  recordsDirectory;
7088
7094
  indexesDirectory;
@@ -7151,7 +7157,7 @@ var FilesystemRegistryStore = class {
7151
7157
  async readRecordsFromDirectory() {
7152
7158
  const files = await listJsonFiles(this.recordsDirectory);
7153
7159
  const records = await Promise.all(
7154
- files.map((fileName) => readJsonFile(path6__default.default.join(this.recordsDirectory, fileName)))
7160
+ files.map((fileName) => readJsonFile(path7__default.default.join(this.recordsDirectory, fileName)))
7155
7161
  );
7156
7162
  records.sort(compareByCreatedAtAndId);
7157
7163
  return records;
@@ -7183,17 +7189,17 @@ var FilesystemRegistryStore = class {
7183
7189
  return record;
7184
7190
  }
7185
7191
  recordPath(id) {
7186
- return path6__default.default.join(this.recordsDirectory, `${encodePathSegment(id)}.json`);
7192
+ return path7__default.default.join(this.recordsDirectory, `${encodePathSegment(id)}.json`);
7187
7193
  }
7188
7194
  indexPath(key, version) {
7189
- return path6__default.default.join(
7195
+ return path7__default.default.join(
7190
7196
  this.indexesDirectory,
7191
7197
  encodePathSegment(key),
7192
7198
  `${encodePathSegment(version)}.json`
7193
7199
  );
7194
7200
  }
7195
7201
  writeLockPath() {
7196
- return path6__default.default.join(path6__default.default.dirname(this.recordsDirectory), ".write.lock");
7202
+ return path7__default.default.join(path7__default.default.dirname(this.recordsDirectory), ".write.lock");
7197
7203
  }
7198
7204
  };
7199
7205
  var FilesystemDescriptorRegistry = class extends FilesystemRegistryStore {
@@ -7563,7 +7569,7 @@ var SqliteSavedNetworkStore = class {
7563
7569
  directoryInitialization;
7564
7570
  databaseInitialization;
7565
7571
  constructor(rootPath) {
7566
- this.databasePath = path6__default.default.join(rootPath, "registry", "saved-network.sqlite");
7572
+ this.databasePath = path7__default.default.join(rootPath, "registry", "saved-network.sqlite");
7567
7573
  }
7568
7574
  async initialize() {
7569
7575
  await this.ensureDatabaseDirectory();
@@ -7773,7 +7779,7 @@ var SqliteSavedNetworkStore = class {
7773
7779
  }
7774
7780
  }
7775
7781
  async ensureDatabaseDirectory() {
7776
- this.directoryInitialization ??= ensureDirectory(path6__default.default.dirname(this.databasePath)).catch(
7782
+ this.directoryInitialization ??= ensureDirectory(path7__default.default.dirname(this.databasePath)).catch(
7777
7783
  (error) => {
7778
7784
  this.directoryInitialization = void 0;
7779
7785
  throw error;
@@ -8163,6 +8169,546 @@ function withSqliteTransaction(database, task) {
8163
8169
  function createSavedNetworkStore(rootPath) {
8164
8170
  return new SqliteSavedNetworkStore(rootPath);
8165
8171
  }
8172
+
8173
+ // ../runtime-core/src/observation-utils.ts
8174
+ var REDACTED = "[REDACTED]";
8175
+ var SENSITIVE_KEY_PATTERN = /(authorization|proxy[_-]?authorization|cookie|set-cookie|api[_-]?key|access[_-]?token|refresh[_-]?token|auth[_-]?token|token|secret|password|passwd|private[_-]?key|database[_-]?url|db[_-]?url|session(?:id)?|csrf(?:token)?)/i;
8176
+ var SENSITIVE_VALUE_PATTERNS = [
8177
+ /\bsk-[A-Za-z0-9_-]{20,}\b/g,
8178
+ /\bAIza[0-9A-Za-z_-]{20,}\b/g,
8179
+ /\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/g,
8180
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g,
8181
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi
8182
+ ];
8183
+ function normalizeObservationContext(context) {
8184
+ if (context === void 0) {
8185
+ return void 0;
8186
+ }
8187
+ const normalized = {
8188
+ ...context.sessionRef === void 0 ? {} : { sessionRef: context.sessionRef },
8189
+ ...context.pageRef === void 0 ? {} : { pageRef: context.pageRef },
8190
+ ...context.frameRef === void 0 ? {} : { frameRef: context.frameRef },
8191
+ ...context.documentRef === void 0 ? {} : { documentRef: context.documentRef },
8192
+ ...context.documentEpoch === void 0 ? {} : { documentEpoch: context.documentEpoch }
8193
+ };
8194
+ return Object.keys(normalized).length === 0 ? void 0 : normalized;
8195
+ }
8196
+ function createObservationRedactor(config) {
8197
+ const state = createRedactionState(config);
8198
+ return {
8199
+ redactText(value) {
8200
+ return redactString(value, state);
8201
+ },
8202
+ redactJson(value) {
8203
+ return value === void 0 ? void 0 : redactUnknown(value, state, /* @__PURE__ */ new WeakSet());
8204
+ },
8205
+ redactError(error) {
8206
+ if (error === void 0) {
8207
+ return void 0;
8208
+ }
8209
+ return {
8210
+ ...error.code === void 0 ? {} : { code: redactString(error.code, state) },
8211
+ message: redactString(error.message, state),
8212
+ ...error.retriable === void 0 ? {} : { retriable: error.retriable },
8213
+ ...error.details === void 0 ? {} : { details: toCanonicalJsonValue(redactUnknown(error.details, state, /* @__PURE__ */ new WeakSet())) }
8214
+ };
8215
+ },
8216
+ redactLabels(labels) {
8217
+ if (labels === void 0) {
8218
+ return void 0;
8219
+ }
8220
+ const next = Object.entries(labels).reduce(
8221
+ (accumulator, [key, value]) => {
8222
+ accumulator[key] = isSensitiveKey(key, state) ? REDACTED : redactString(value, state);
8223
+ return accumulator;
8224
+ },
8225
+ {}
8226
+ );
8227
+ return Object.keys(next).length === 0 ? void 0 : next;
8228
+ },
8229
+ redactTraceContext(traceContext) {
8230
+ if (traceContext === void 0) {
8231
+ return void 0;
8232
+ }
8233
+ const next = {
8234
+ ...traceContext.traceparent === void 0 ? {} : { traceparent: redactString(traceContext.traceparent, state) },
8235
+ ...traceContext.baggage === void 0 ? {} : { baggage: redactString(traceContext.baggage, state) }
8236
+ };
8237
+ return Object.keys(next).length === 0 ? void 0 : next;
8238
+ }
8239
+ };
8240
+ }
8241
+ function createRedactionState(config) {
8242
+ return {
8243
+ sensitiveKeys: new Set(
8244
+ (config?.redaction?.sensitiveKeys ?? []).map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0)
8245
+ ),
8246
+ sensitiveValues: [
8247
+ ...new Set(
8248
+ (config?.redaction?.sensitiveValues ?? []).map((value) => value.trim()).filter((value) => value.length > 0)
8249
+ )
8250
+ ]
8251
+ };
8252
+ }
8253
+ function redactUnknown(value, state, seen) {
8254
+ if (value === null || value === void 0) {
8255
+ return value;
8256
+ }
8257
+ if (typeof value === "string") {
8258
+ return redactString(value, state);
8259
+ }
8260
+ if (typeof value !== "object") {
8261
+ return value;
8262
+ }
8263
+ if (seen.has(value)) {
8264
+ return REDACTED;
8265
+ }
8266
+ seen.add(value);
8267
+ if (Array.isArray(value)) {
8268
+ return value.map((entry) => redactUnknown(entry, state, seen));
8269
+ }
8270
+ const next = {};
8271
+ for (const [key, nestedValue] of Object.entries(value)) {
8272
+ next[key] = isSensitiveKey(key, state) ? REDACTED : redactUnknown(nestedValue, state, seen);
8273
+ }
8274
+ return next;
8275
+ }
8276
+ function redactString(value, state) {
8277
+ let next = value;
8278
+ for (const secret of state.sensitiveValues) {
8279
+ next = next.split(secret).join(REDACTED);
8280
+ }
8281
+ for (const pattern of SENSITIVE_VALUE_PATTERNS) {
8282
+ next = next.replace(pattern, REDACTED);
8283
+ }
8284
+ return redactUrlString(next, state);
8285
+ }
8286
+ function redactUrlString(value, state) {
8287
+ let parsed;
8288
+ try {
8289
+ parsed = new URL(value);
8290
+ } catch {
8291
+ return value;
8292
+ }
8293
+ let changed = false;
8294
+ if (parsed.username) {
8295
+ parsed.username = REDACTED;
8296
+ changed = true;
8297
+ }
8298
+ if (parsed.password) {
8299
+ parsed.password = REDACTED;
8300
+ changed = true;
8301
+ }
8302
+ for (const [key] of parsed.searchParams) {
8303
+ if (!isSensitiveKey(key, state)) {
8304
+ continue;
8305
+ }
8306
+ parsed.searchParams.set(key, REDACTED);
8307
+ changed = true;
8308
+ }
8309
+ return changed ? parsed.toString() : value;
8310
+ }
8311
+ function isSensitiveKey(key, state) {
8312
+ return state.sensitiveKeys.has(key.trim().toLowerCase()) || SENSITIVE_KEY_PATTERN.test(key);
8313
+ }
8314
+
8315
+ // ../runtime-core/src/observations.ts
8316
+ function normalizeObservabilityConfig(input) {
8317
+ const profile = input?.profile ?? "diagnostic";
8318
+ const labels = input?.labels === void 0 ? void 0 : Object.entries(input.labels).reduce((accumulator, [key, value]) => {
8319
+ const normalizedKey = key.trim();
8320
+ const normalizedValue = value.trim();
8321
+ if (normalizedKey.length === 0 || normalizedValue.length === 0) {
8322
+ return accumulator;
8323
+ }
8324
+ if (Object.keys(accumulator).length >= 20) {
8325
+ return accumulator;
8326
+ }
8327
+ accumulator[normalizedKey] = normalizedValue;
8328
+ return accumulator;
8329
+ }, {});
8330
+ const redaction = input?.redaction === void 0 ? void 0 : {
8331
+ ...input.redaction.sensitiveKeys === void 0 ? {} : {
8332
+ sensitiveKeys: input.redaction.sensitiveKeys.map((value) => value.trim()).filter((value) => value.length > 0)
8333
+ },
8334
+ ...input.redaction.sensitiveValues === void 0 ? {} : {
8335
+ sensitiveValues: input.redaction.sensitiveValues.map((value) => value.trim()).filter((value) => value.length > 0)
8336
+ }
8337
+ };
8338
+ return {
8339
+ profile,
8340
+ ...labels === void 0 || Object.keys(labels).length === 0 ? {} : { labels },
8341
+ ...input?.traceContext === void 0 ? {} : {
8342
+ traceContext: {
8343
+ ...input.traceContext.traceparent === void 0 ? {} : { traceparent: input.traceContext.traceparent.trim() },
8344
+ ...input.traceContext.baggage === void 0 ? {} : { baggage: input.traceContext.baggage.trim() }
8345
+ }
8346
+ },
8347
+ ...redaction === void 0 ? {} : { redaction }
8348
+ };
8349
+ }
8350
+ function eventFileName(sequence) {
8351
+ return `${String(sequence).padStart(12, "0")}.json`;
8352
+ }
8353
+ var FilesystemSessionSink = class {
8354
+ constructor(store, sessionId) {
8355
+ this.store = store;
8356
+ this.sessionId = sessionId;
8357
+ }
8358
+ append(input) {
8359
+ return this.store.appendEvent(this.sessionId, input);
8360
+ }
8361
+ appendBatch(input) {
8362
+ return this.store.appendEvents(this.sessionId, input);
8363
+ }
8364
+ writeArtifact(input) {
8365
+ return this.store.writeArtifact(this.sessionId, input);
8366
+ }
8367
+ async flush() {
8368
+ }
8369
+ close(reason) {
8370
+ return this.store.closeSession(this.sessionId, reason);
8371
+ }
8372
+ };
8373
+ var FilesystemObservationStoreImpl = class {
8374
+ constructor(rootPath, artifacts) {
8375
+ this.rootPath = rootPath;
8376
+ this.artifacts = artifacts;
8377
+ this.sessionsDirectory = path7__default.default.join(this.rootPath, "observations", "sessions");
8378
+ }
8379
+ sessionsDirectory;
8380
+ redactors = /* @__PURE__ */ new Map();
8381
+ async initialize() {
8382
+ await ensureDirectory(this.sessionsDirectory);
8383
+ }
8384
+ async openSession(input) {
8385
+ const sessionId = normalizeNonEmptyString("sessionId", input.sessionId);
8386
+ const openedAt = normalizeTimestamp("openedAt", input.openedAt ?? Date.now());
8387
+ const config = normalizeObservabilityConfig(input.config);
8388
+ const redactor = createObservationRedactor(config);
8389
+ this.redactors.set(sessionId, redactor);
8390
+ const redactedLabels = redactor.redactLabels(config.labels);
8391
+ const redactedTraceContext = redactor.redactTraceContext(config.traceContext);
8392
+ await withFilesystemLock(this.sessionLockPath(sessionId), async () => {
8393
+ const existing = await this.reconcileSessionManifest(sessionId);
8394
+ if (existing === void 0) {
8395
+ await ensureDirectory(this.sessionEventsDirectory(sessionId));
8396
+ await ensureDirectory(this.sessionArtifactsDirectory(sessionId));
8397
+ const session = {
8398
+ sessionId,
8399
+ profile: config.profile,
8400
+ ...redactedLabels === void 0 ? {} : { labels: redactedLabels },
8401
+ ...redactedTraceContext === void 0 ? {} : { traceContext: redactedTraceContext },
8402
+ openedAt,
8403
+ updatedAt: openedAt,
8404
+ currentSequence: 0,
8405
+ eventCount: 0,
8406
+ artifactCount: 0
8407
+ };
8408
+ await writeJsonFileExclusive(this.sessionManifestPath(sessionId), session);
8409
+ return;
8410
+ }
8411
+ const patched = {
8412
+ ...existing,
8413
+ profile: config.profile,
8414
+ ...redactedLabels === void 0 ? {} : { labels: redactedLabels },
8415
+ ...redactedTraceContext === void 0 ? {} : { traceContext: redactedTraceContext },
8416
+ updatedAt: Math.max(existing.updatedAt, openedAt)
8417
+ };
8418
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), patched);
8419
+ });
8420
+ return new FilesystemSessionSink(this, sessionId);
8421
+ }
8422
+ async getSession(sessionId) {
8423
+ const manifestPath = this.sessionManifestPath(sessionId);
8424
+ if (!await pathExists(manifestPath)) {
8425
+ return void 0;
8426
+ }
8427
+ return readJsonFile(manifestPath);
8428
+ }
8429
+ async appendEvent(sessionId, input) {
8430
+ const [event] = await this.appendEvents(sessionId, [input]);
8431
+ if (event === void 0) {
8432
+ throw new Error(`failed to append observation event for session ${sessionId}`);
8433
+ }
8434
+ return event;
8435
+ }
8436
+ async appendEvents(sessionId, input) {
8437
+ if (input.length === 0) {
8438
+ return [];
8439
+ }
8440
+ return withFilesystemLock(this.sessionLockPath(sessionId), async () => {
8441
+ const session = await this.reconcileSessionManifest(sessionId);
8442
+ if (session === void 0) {
8443
+ throw new Error(`observation session ${sessionId} was not found`);
8444
+ }
8445
+ const redactor = this.redactors.get(sessionId) ?? createObservationRedactor(void 0);
8446
+ const events = [];
8447
+ let sequence = session.currentSequence;
8448
+ let updatedAt = session.updatedAt;
8449
+ for (const raw of input) {
8450
+ sequence += 1;
8451
+ const createdAt = normalizeTimestamp("createdAt", raw.createdAt);
8452
+ const context = normalizeObservationContext(raw.context);
8453
+ const redactedData = raw.data === void 0 ? void 0 : redactor.redactJson(toCanonicalJsonValue(raw.data));
8454
+ const redactedError = redactor.redactError(raw.error);
8455
+ const event = {
8456
+ eventId: normalizeNonEmptyString(
8457
+ "eventId",
8458
+ raw.eventId ?? `observation:${sessionId}:${String(sequence).padStart(12, "0")}`
8459
+ ),
8460
+ sessionId,
8461
+ sequence,
8462
+ kind: raw.kind,
8463
+ phase: raw.phase,
8464
+ createdAt,
8465
+ correlationId: normalizeNonEmptyString("correlationId", raw.correlationId),
8466
+ ...raw.spanId === void 0 ? {} : { spanId: normalizeNonEmptyString("spanId", raw.spanId) },
8467
+ ...raw.parentSpanId === void 0 ? {} : { parentSpanId: normalizeNonEmptyString("parentSpanId", raw.parentSpanId) },
8468
+ ...context === void 0 ? {} : { context },
8469
+ ...redactedData === void 0 ? {} : { data: redactedData },
8470
+ ...redactedError === void 0 ? {} : { error: redactedError },
8471
+ ...raw.artifactIds === void 0 || raw.artifactIds.length === 0 ? {} : { artifactIds: [...raw.artifactIds] }
8472
+ };
8473
+ await writeJsonFileExclusive(
8474
+ path7__default.default.join(this.sessionEventsDirectory(sessionId), eventFileName(sequence)),
8475
+ event
8476
+ );
8477
+ updatedAt = Math.max(updatedAt, createdAt);
8478
+ events.push(event);
8479
+ }
8480
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), {
8481
+ ...session,
8482
+ currentSequence: sequence,
8483
+ eventCount: session.eventCount + events.length,
8484
+ updatedAt
8485
+ });
8486
+ return events;
8487
+ });
8488
+ }
8489
+ async writeArtifact(sessionId, input) {
8490
+ return withFilesystemLock(this.sessionLockPath(sessionId), async () => {
8491
+ const session = await this.reconcileSessionManifest(sessionId);
8492
+ if (session === void 0) {
8493
+ throw new Error(`observation session ${sessionId} was not found`);
8494
+ }
8495
+ const redactor = this.redactors.get(sessionId) ?? createObservationRedactor(void 0);
8496
+ const createdAt = normalizeTimestamp("createdAt", input.createdAt);
8497
+ const context = normalizeObservationContext(input.context);
8498
+ const redactedStorageKey = input.storageKey === void 0 ? void 0 : redactor.redactText(input.storageKey);
8499
+ const redactedMetadata = input.metadata === void 0 ? void 0 : redactor.redactJson(toCanonicalJsonValue(input.metadata));
8500
+ const artifact = {
8501
+ artifactId: normalizeNonEmptyString("artifactId", input.artifactId),
8502
+ sessionId,
8503
+ kind: input.kind,
8504
+ createdAt,
8505
+ ...context === void 0 ? {} : { context },
8506
+ ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
8507
+ ...input.byteLength === void 0 ? {} : { byteLength: input.byteLength },
8508
+ ...input.sha256 === void 0 ? {} : { sha256: input.sha256 },
8509
+ ...input.opensteerArtifactId === void 0 ? {} : { opensteerArtifactId: input.opensteerArtifactId },
8510
+ ...redactedStorageKey === void 0 ? {} : { storageKey: redactedStorageKey },
8511
+ ...redactedMetadata === void 0 ? {} : { metadata: redactedMetadata }
8512
+ };
8513
+ const artifactPath = this.sessionArtifactPath(sessionId, artifact.artifactId);
8514
+ if (!await pathExists(artifactPath)) {
8515
+ await writeJsonFileExclusive(artifactPath, artifact);
8516
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), {
8517
+ ...session,
8518
+ artifactCount: session.artifactCount + 1,
8519
+ updatedAt: Math.max(session.updatedAt, createdAt)
8520
+ });
8521
+ }
8522
+ return artifact;
8523
+ });
8524
+ }
8525
+ async listEvents(sessionId, input = {}) {
8526
+ const directoryPath = this.sessionEventsDirectory(sessionId);
8527
+ if (!await pathExists(directoryPath)) {
8528
+ return [];
8529
+ }
8530
+ const files = await listJsonFiles(directoryPath);
8531
+ const events = await Promise.all(
8532
+ files.map((fileName) => readJsonFile(path7__default.default.join(directoryPath, fileName)))
8533
+ );
8534
+ const filtered = events.filter((event) => {
8535
+ if (input.kind !== void 0 && event.kind !== input.kind) return false;
8536
+ if (input.phase !== void 0 && event.phase !== input.phase) return false;
8537
+ if (input.correlationId !== void 0 && event.correlationId !== input.correlationId) {
8538
+ return false;
8539
+ }
8540
+ if (input.pageRef !== void 0 && event.context?.pageRef !== input.pageRef) return false;
8541
+ if (input.afterSequence !== void 0 && event.sequence <= input.afterSequence) return false;
8542
+ if (input.from !== void 0 && event.createdAt < input.from) return false;
8543
+ if (input.to !== void 0 && event.createdAt > input.to) return false;
8544
+ return true;
8545
+ });
8546
+ if (input.limit === void 0 || filtered.length <= input.limit) {
8547
+ return filtered;
8548
+ }
8549
+ return filtered.slice(-input.limit);
8550
+ }
8551
+ async listArtifacts(sessionId, input = {}) {
8552
+ const directoryPath = this.sessionArtifactsDirectory(sessionId);
8553
+ if (!await pathExists(directoryPath)) {
8554
+ return [];
8555
+ }
8556
+ const files = await listJsonFiles(directoryPath);
8557
+ const artifacts = await Promise.all(
8558
+ files.map(
8559
+ (fileName) => readJsonFile(path7__default.default.join(directoryPath, fileName))
8560
+ )
8561
+ );
8562
+ const filtered = artifacts.filter((artifact) => {
8563
+ if (input.kind !== void 0 && artifact.kind !== input.kind) return false;
8564
+ if (input.pageRef !== void 0 && artifact.context?.pageRef !== input.pageRef) return false;
8565
+ return true;
8566
+ });
8567
+ if (input.limit === void 0 || filtered.length <= input.limit) {
8568
+ return filtered;
8569
+ }
8570
+ return filtered.slice(-input.limit);
8571
+ }
8572
+ async getArtifact(sessionId, artifactId) {
8573
+ const artifactPath = this.sessionArtifactPath(sessionId, artifactId);
8574
+ if (!await pathExists(artifactPath)) {
8575
+ return void 0;
8576
+ }
8577
+ return readJsonFile(artifactPath);
8578
+ }
8579
+ async closeSession(sessionId, _reason) {
8580
+ await withFilesystemLock(this.sessionLockPath(sessionId), async () => {
8581
+ const session = await this.reconcileSessionManifest(sessionId);
8582
+ if (session === void 0 || session.closedAt !== void 0) {
8583
+ return;
8584
+ }
8585
+ const now = Date.now();
8586
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), {
8587
+ ...session,
8588
+ updatedAt: Math.max(session.updatedAt, now),
8589
+ closedAt: now
8590
+ });
8591
+ });
8592
+ this.redactors.delete(sessionId);
8593
+ }
8594
+ async writeArtifactFromManifest(sessionId, manifest, kind, metadata) {
8595
+ return this.writeArtifact(sessionId, {
8596
+ artifactId: manifest.artifactId,
8597
+ kind,
8598
+ createdAt: manifest.createdAt,
8599
+ context: manifest.scope,
8600
+ mediaType: manifest.mediaType,
8601
+ byteLength: manifest.byteLength,
8602
+ sha256: manifest.sha256,
8603
+ opensteerArtifactId: manifest.artifactId,
8604
+ storageKey: manifestToExternalBinaryLocation(this.rootPath, manifest).uri,
8605
+ ...metadata === void 0 ? {} : { metadata }
8606
+ });
8607
+ }
8608
+ async ensureArtifactLinked(sessionId, manifest) {
8609
+ const existing = await this.getArtifact(sessionId, manifest.artifactId);
8610
+ if (existing !== void 0) {
8611
+ return existing;
8612
+ }
8613
+ const kind = toObservationArtifactKind(manifest.kind);
8614
+ return this.writeArtifactFromManifest(sessionId, manifest, kind);
8615
+ }
8616
+ async hydrateArtifactManifests(artifactIds) {
8617
+ return (await Promise.all(
8618
+ artifactIds.map(async (artifactId) => this.artifacts.getManifest(artifactId))
8619
+ )).filter((value) => value !== void 0);
8620
+ }
8621
+ sessionDirectory(sessionId) {
8622
+ return path7__default.default.join(this.sessionsDirectory, encodePathSegment(sessionId));
8623
+ }
8624
+ sessionManifestPath(sessionId) {
8625
+ return path7__default.default.join(this.sessionDirectory(sessionId), "session.json");
8626
+ }
8627
+ sessionEventsDirectory(sessionId) {
8628
+ return path7__default.default.join(this.sessionDirectory(sessionId), "events");
8629
+ }
8630
+ sessionArtifactsDirectory(sessionId) {
8631
+ return path7__default.default.join(this.sessionDirectory(sessionId), "artifacts");
8632
+ }
8633
+ sessionArtifactPath(sessionId, artifactId) {
8634
+ return path7__default.default.join(
8635
+ this.sessionArtifactsDirectory(sessionId),
8636
+ `${encodePathSegment(artifactId)}.json`
8637
+ );
8638
+ }
8639
+ sessionLockPath(sessionId) {
8640
+ return path7__default.default.join(this.sessionDirectory(sessionId), ".lock");
8641
+ }
8642
+ async reconcileSessionManifest(sessionId) {
8643
+ const session = await this.getSession(sessionId);
8644
+ if (session === void 0) {
8645
+ return void 0;
8646
+ }
8647
+ const [hasEventDirectory, hasArtifactDirectory] = await Promise.all([
8648
+ pathExists(this.sessionEventsDirectory(sessionId)),
8649
+ pathExists(this.sessionArtifactsDirectory(sessionId))
8650
+ ]);
8651
+ const [eventFiles, artifactFiles] = await Promise.all([
8652
+ hasEventDirectory ? listJsonFiles(this.sessionEventsDirectory(sessionId)) : Promise.resolve([]),
8653
+ hasArtifactDirectory ? listJsonFiles(this.sessionArtifactsDirectory(sessionId)) : Promise.resolve([])
8654
+ ]);
8655
+ const currentSequence = eventFiles.reduce((maxSequence, fileName) => {
8656
+ const parsed = Number.parseInt(fileName.replace(/\.json$/u, ""), 10);
8657
+ return Number.isFinite(parsed) ? Math.max(maxSequence, parsed) : maxSequence;
8658
+ }, 0);
8659
+ const eventCount = eventFiles.length;
8660
+ const artifactCount = artifactFiles.length;
8661
+ if (session.currentSequence === currentSequence && session.eventCount === eventCount && session.artifactCount === artifactCount) {
8662
+ return session;
8663
+ }
8664
+ const [events, artifacts] = await Promise.all([
8665
+ Promise.all(
8666
+ eventFiles.map(
8667
+ (fileName) => readJsonFile(
8668
+ path7__default.default.join(this.sessionEventsDirectory(sessionId), fileName)
8669
+ )
8670
+ )
8671
+ ),
8672
+ Promise.all(
8673
+ artifactFiles.map(
8674
+ (fileName) => readJsonFile(
8675
+ path7__default.default.join(this.sessionArtifactsDirectory(sessionId), fileName)
8676
+ )
8677
+ )
8678
+ )
8679
+ ]);
8680
+ const updatedAt = Math.max(
8681
+ session.openedAt,
8682
+ session.closedAt ?? 0,
8683
+ ...events.map((event) => event.createdAt),
8684
+ ...artifacts.map((artifact) => artifact.createdAt)
8685
+ );
8686
+ const reconciled = {
8687
+ ...session,
8688
+ currentSequence,
8689
+ eventCount,
8690
+ artifactCount,
8691
+ updatedAt
8692
+ };
8693
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), reconciled);
8694
+ return reconciled;
8695
+ }
8696
+ };
8697
+ function toObservationArtifactKind(kind) {
8698
+ switch (kind) {
8699
+ case "screenshot":
8700
+ return "screenshot";
8701
+ case "dom-snapshot":
8702
+ return "dom-snapshot";
8703
+ case "html-snapshot":
8704
+ return "html-snapshot";
8705
+ default:
8706
+ return "other";
8707
+ }
8708
+ }
8709
+ function createObservationStore(rootPath, artifacts) {
8710
+ return new FilesystemObservationStoreImpl(rootPath, artifacts);
8711
+ }
8166
8712
  function normalizeContext(context) {
8167
8713
  return {
8168
8714
  ...context?.sessionRef === void 0 ? {} : { sessionRef: context.sessionRef },
@@ -8179,7 +8725,7 @@ var FilesystemTraceStore = class {
8179
8725
  constructor(rootPath, artifacts) {
8180
8726
  this.rootPath = rootPath;
8181
8727
  this.artifacts = artifacts;
8182
- this.runsDirectory = path6__default.default.join(this.rootPath, "traces", "runs");
8728
+ this.runsDirectory = path7__default.default.join(this.rootPath, "traces", "runs");
8183
8729
  }
8184
8730
  runsDirectory;
8185
8731
  async initialize() {
@@ -8256,7 +8802,7 @@ var FilesystemTraceStore = class {
8256
8802
  ...input.error === void 0 ? {} : { error: input.error }
8257
8803
  };
8258
8804
  await writeJsonFileExclusive(
8259
- path6__default.default.join(this.runEntriesDirectory(runId), sequenceFileName(sequence)),
8805
+ path7__default.default.join(this.runEntriesDirectory(runId), sequenceFileName(sequence)),
8260
8806
  entry
8261
8807
  );
8262
8808
  await writeJsonFileAtomic(this.runManifestPath(runId), {
@@ -8275,7 +8821,7 @@ var FilesystemTraceStore = class {
8275
8821
  const files = await listJsonFiles(entriesDirectory);
8276
8822
  return Promise.all(
8277
8823
  files.map(
8278
- (fileName) => readJsonFile(path6__default.default.join(entriesDirectory, fileName))
8824
+ (fileName) => readJsonFile(path7__default.default.join(entriesDirectory, fileName))
8279
8825
  )
8280
8826
  );
8281
8827
  }
@@ -8321,16 +8867,16 @@ var FilesystemTraceStore = class {
8321
8867
  return { trace, artifacts };
8322
8868
  }
8323
8869
  runDirectory(runId) {
8324
- return path6__default.default.join(this.runsDirectory, encodeURIComponent(runId));
8870
+ return path7__default.default.join(this.runsDirectory, encodeURIComponent(runId));
8325
8871
  }
8326
8872
  runEntriesDirectory(runId) {
8327
- return path6__default.default.join(this.runDirectory(runId), "entries");
8873
+ return path7__default.default.join(this.runDirectory(runId), "entries");
8328
8874
  }
8329
8875
  runManifestPath(runId) {
8330
- return path6__default.default.join(this.runDirectory(runId), "manifest.json");
8876
+ return path7__default.default.join(this.runDirectory(runId), "manifest.json");
8331
8877
  }
8332
8878
  runWriteLockPath(runId) {
8333
- return path6__default.default.join(this.runDirectory(runId), ".append.lock");
8879
+ return path7__default.default.join(this.runDirectory(runId), ".append.lock");
8334
8880
  }
8335
8881
  };
8336
8882
  function createTraceStore(rootPath, artifacts) {
@@ -8344,7 +8890,7 @@ function normalizeWorkspaceId(workspace) {
8344
8890
  return encodePathSegment(workspace);
8345
8891
  }
8346
8892
  function resolveFilesystemWorkspacePath(input) {
8347
- return path6__default.default.join(
8893
+ return path7__default.default.join(
8348
8894
  input.rootDir,
8349
8895
  ".opensteer",
8350
8896
  "workspaces",
@@ -8353,17 +8899,18 @@ function resolveFilesystemWorkspacePath(input) {
8353
8899
  }
8354
8900
  async function createFilesystemOpensteerWorkspace(options) {
8355
8901
  await ensureDirectory(options.rootPath);
8356
- const manifestPath = path6__default.default.join(options.rootPath, "workspace.json");
8357
- const browserPath = path6__default.default.join(options.rootPath, "browser");
8358
- const browserManifestPath = path6__default.default.join(browserPath, "manifest.json");
8359
- const browserUserDataDir = path6__default.default.join(browserPath, "user-data");
8360
- const livePath = path6__default.default.join(options.rootPath, "live");
8361
- const liveLocalPath = path6__default.default.join(livePath, "local.json");
8362
- const liveCloudPath = path6__default.default.join(livePath, "cloud.json");
8363
- const artifactsPath = path6__default.default.join(options.rootPath, "artifacts");
8364
- const tracesPath = path6__default.default.join(options.rootPath, "traces");
8365
- const registryPath = path6__default.default.join(options.rootPath, "registry");
8366
- const lockPath = path6__default.default.join(options.rootPath, ".lock");
8902
+ const manifestPath = path7__default.default.join(options.rootPath, "workspace.json");
8903
+ const browserPath = path7__default.default.join(options.rootPath, "browser");
8904
+ const browserManifestPath = path7__default.default.join(browserPath, "manifest.json");
8905
+ const browserUserDataDir = path7__default.default.join(browserPath, "user-data");
8906
+ const livePath = path7__default.default.join(options.rootPath, "live");
8907
+ const liveLocalPath = path7__default.default.join(livePath, "local.json");
8908
+ const liveCloudPath = path7__default.default.join(livePath, "cloud.json");
8909
+ const artifactsPath = path7__default.default.join(options.rootPath, "artifacts");
8910
+ const tracesPath = path7__default.default.join(options.rootPath, "traces");
8911
+ const observationsPath = path7__default.default.join(options.rootPath, "observations");
8912
+ const registryPath = path7__default.default.join(options.rootPath, "registry");
8913
+ const lockPath = path7__default.default.join(options.rootPath, ".lock");
8367
8914
  let manifest;
8368
8915
  if (await pathExists(manifestPath)) {
8369
8916
  manifest = await readJsonFile(manifestPath);
@@ -8377,6 +8924,17 @@ async function createFilesystemOpensteerWorkspace(options) {
8377
8924
  `workspace ${options.rootPath} uses unsupported version ${String(manifest.version)}`
8378
8925
  );
8379
8926
  }
8927
+ if (manifest.paths.observations === void 0) {
8928
+ manifest = {
8929
+ ...manifest,
8930
+ updatedAt: Date.now(),
8931
+ paths: {
8932
+ ...manifest.paths,
8933
+ observations: "observations"
8934
+ }
8935
+ };
8936
+ await writeJsonFileAtomic(manifestPath, manifest);
8937
+ }
8380
8938
  } else {
8381
8939
  const createdAt = normalizeTimestamp("createdAt", options.createdAt ?? Date.now());
8382
8940
  manifest = {
@@ -8391,6 +8949,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8391
8949
  live: "live",
8392
8950
  artifacts: "artifacts",
8393
8951
  traces: "traces",
8952
+ observations: "observations",
8394
8953
  registry: "registry"
8395
8954
  }
8396
8955
  };
@@ -8402,6 +8961,7 @@ async function createFilesystemOpensteerWorkspace(options) {
8402
8961
  ensureDirectory(livePath),
8403
8962
  ensureDirectory(artifactsPath),
8404
8963
  ensureDirectory(tracesPath),
8964
+ ensureDirectory(observationsPath),
8405
8965
  ensureDirectory(registryPath)
8406
8966
  ]);
8407
8967
  const artifacts = createArtifactStore(options.rootPath);
@@ -8426,6 +8986,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8426
8986
  await reverseReports.initialize();
8427
8987
  const traces = createTraceStore(options.rootPath, artifacts);
8428
8988
  await traces.initialize();
8989
+ const observations = createObservationStore(options.rootPath, artifacts);
8990
+ await observations.initialize();
8429
8991
  return {
8430
8992
  rootPath: options.rootPath,
8431
8993
  manifestPath,
@@ -8438,10 +9000,12 @@ async function createFilesystemOpensteerWorkspace(options) {
8438
9000
  liveCloudPath,
8439
9001
  artifactsPath,
8440
9002
  tracesPath,
9003
+ observationsPath,
8441
9004
  registryPath,
8442
9005
  lockPath,
8443
9006
  artifacts,
8444
9007
  traces,
9008
+ observations,
8445
9009
  registry: {
8446
9010
  descriptors,
8447
9011
  requestPlans,
@@ -8628,10 +9192,10 @@ function delayWithSignal(delayMs, signal) {
8628
9192
  if (signal.aborted) {
8629
9193
  return Promise.reject(signal.reason ?? abortError());
8630
9194
  }
8631
- return new Promise((resolve5, reject) => {
9195
+ return new Promise((resolve4, reject) => {
8632
9196
  const timer = setTimeout(() => {
8633
9197
  signal.removeEventListener("abort", onAbort);
8634
- resolve5();
9198
+ resolve4();
8635
9199
  }, delayMs);
8636
9200
  const onAbort = () => {
8637
9201
  clearTimeout(timer);
@@ -9096,9 +9660,9 @@ var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
9096
9660
  "poster",
9097
9661
  "ping"
9098
9662
  ]);
9099
- function buildArrayFieldPathCandidates(path13) {
9100
- const strict = path13.nodes.length ? buildPathCandidates(path13.nodes) : [];
9101
- const relaxedNodes = stripPositionClauses(path13.nodes);
9663
+ function buildArrayFieldPathCandidates(path15) {
9664
+ const strict = path15.nodes.length ? buildPathCandidates(path15.nodes) : [];
9665
+ const relaxedNodes = stripPositionClauses(path15.nodes);
9102
9666
  const relaxed = relaxedNodes.length ? buildPathCandidates(relaxedNodes) : [];
9103
9667
  return dedupeSelectors([...strict, ...relaxed]);
9104
9668
  }
@@ -9628,18 +10192,18 @@ function cloneStructuralElementAnchor(anchor) {
9628
10192
  nodes: anchor.nodes.map(clonePathNode)
9629
10193
  };
9630
10194
  }
9631
- function cloneReplayElementPath(path13) {
10195
+ function cloneReplayElementPath(path15) {
9632
10196
  return {
9633
10197
  resolution: "deterministic",
9634
- context: cloneContext(path13.context),
9635
- nodes: path13.nodes.map(clonePathNode)
10198
+ context: cloneContext(path15.context),
10199
+ nodes: path15.nodes.map(clonePathNode)
9636
10200
  };
9637
10201
  }
9638
- function cloneElementPath(path13) {
9639
- return cloneReplayElementPath(path13);
10202
+ function cloneElementPath(path15) {
10203
+ return cloneReplayElementPath(path15);
9640
10204
  }
9641
- function buildPathSelectorHint(path13) {
9642
- const nodes = path13?.nodes || [];
10205
+ function buildPathSelectorHint(path15) {
10206
+ const nodes = path15?.nodes || [];
9643
10207
  const last = nodes[nodes.length - 1];
9644
10208
  if (!last) {
9645
10209
  return "*";
@@ -9688,15 +10252,15 @@ function sanitizeStructuralElementAnchor(anchor) {
9688
10252
  nodes: sanitizeNodes(anchor.nodes)
9689
10253
  };
9690
10254
  }
9691
- function sanitizeReplayElementPath(path13) {
10255
+ function sanitizeReplayElementPath(path15) {
9692
10256
  return {
9693
10257
  resolution: "deterministic",
9694
- context: sanitizeContext(path13.context),
9695
- nodes: sanitizeNodes(path13.nodes)
10258
+ context: sanitizeContext(path15.context),
10259
+ nodes: sanitizeNodes(path15.nodes)
9696
10260
  };
9697
10261
  }
9698
- function sanitizeElementPath(path13) {
9699
- return sanitizeReplayElementPath(path13);
10262
+ function sanitizeElementPath(path15) {
10263
+ return sanitizeReplayElementPath(path15);
9700
10264
  }
9701
10265
  function buildLocalStructuralElementAnchor(index, rawTargetNode) {
9702
10266
  const targetNode = requireElementNode(index, rawTargetNode);
@@ -9819,8 +10383,8 @@ function buildTargetNotFoundMessage(domPath, diagnostics) {
9819
10383
  }
9820
10384
  return `${base} Target depth ${String(depth)}. Candidate counts: ${sample}.`;
9821
10385
  }
9822
- function buildArrayFieldCandidates(path13) {
9823
- return buildArrayFieldPathCandidates(path13);
10386
+ function buildArrayFieldCandidates(path15) {
10387
+ return buildArrayFieldPathCandidates(path15);
9824
10388
  }
9825
10389
  function firstDefinedAttribute(node, keys) {
9826
10390
  for (const key of keys) {
@@ -10329,14 +10893,16 @@ var DomActionExecutor = class {
10329
10893
  ...input.timeout === void 0 ? {} : { timeout: input.timeout }
10330
10894
  },
10331
10895
  async (pointerTarget, point, timeout) => {
10332
- await timeout.runStep(
10896
+ const events = [];
10897
+ const moved = await timeout.runStep(
10333
10898
  () => this.options.engine.mouseMove({
10334
10899
  pageRef: pointerTarget.resolved.pageRef,
10335
10900
  point,
10336
10901
  coordinateSpace: "document-css"
10337
10902
  })
10338
10903
  );
10339
- await timeout.runStep(
10904
+ events.push(...moved.events);
10905
+ const clicked = await timeout.runStep(
10340
10906
  () => this.options.engine.mouseClick({
10341
10907
  pageRef: pointerTarget.resolved.pageRef,
10342
10908
  point,
@@ -10346,7 +10912,12 @@ var DomActionExecutor = class {
10346
10912
  ...input.modifiers === void 0 ? {} : { modifiers: input.modifiers }
10347
10913
  })
10348
10914
  );
10349
- return { resolved: pointerTarget.original, point };
10915
+ events.push(...clicked.events);
10916
+ return {
10917
+ resolved: pointerTarget.original,
10918
+ point,
10919
+ ...events.length === 0 ? {} : { events }
10920
+ };
10350
10921
  }
10351
10922
  );
10352
10923
  }
@@ -10360,14 +10931,18 @@ var DomActionExecutor = class {
10360
10931
  ...input.timeout === void 0 ? {} : { timeout: input.timeout }
10361
10932
  },
10362
10933
  async (pointerTarget, point, timeout) => {
10363
- await timeout.runStep(
10934
+ const moved = await timeout.runStep(
10364
10935
  () => this.options.engine.mouseMove({
10365
10936
  pageRef: pointerTarget.resolved.pageRef,
10366
10937
  point,
10367
10938
  coordinateSpace: "document-css"
10368
10939
  })
10369
10940
  );
10370
- return { resolved: pointerTarget.original, point };
10941
+ return {
10942
+ resolved: pointerTarget.original,
10943
+ point,
10944
+ ...moved.events.length === 0 ? {} : { events: moved.events }
10945
+ };
10371
10946
  }
10372
10947
  );
10373
10948
  }
@@ -10381,14 +10956,16 @@ var DomActionExecutor = class {
10381
10956
  ...input.timeout === void 0 ? {} : { timeout: input.timeout }
10382
10957
  },
10383
10958
  async (pointerTarget, point, timeout) => {
10384
- await timeout.runStep(
10959
+ const events = [];
10960
+ const moved = await timeout.runStep(
10385
10961
  () => this.options.engine.mouseMove({
10386
10962
  pageRef: pointerTarget.resolved.pageRef,
10387
10963
  point,
10388
10964
  coordinateSpace: "document-css"
10389
10965
  })
10390
10966
  );
10391
- await timeout.runStep(
10967
+ events.push(...moved.events);
10968
+ const scrolled = await timeout.runStep(
10392
10969
  () => this.options.engine.mouseScroll({
10393
10970
  pageRef: pointerTarget.resolved.pageRef,
10394
10971
  point,
@@ -10396,7 +10973,12 @@ var DomActionExecutor = class {
10396
10973
  delta: input.delta
10397
10974
  })
10398
10975
  );
10399
- return { resolved: pointerTarget.original, point };
10976
+ events.push(...scrolled.events);
10977
+ return {
10978
+ resolved: pointerTarget.original,
10979
+ point,
10980
+ ...events.length === 0 ? {} : { events }
10981
+ };
10400
10982
  }
10401
10983
  );
10402
10984
  }
@@ -11322,21 +11904,21 @@ var DefaultDomRuntime = class {
11322
11904
  return match;
11323
11905
  }
11324
11906
  async resolvePathTarget(session, pageRef, rawPath, source, description, descriptor) {
11325
- const path13 = sanitizeReplayElementPath(rawPath);
11326
- const context = await this.resolvePathContext(session, pageRef, path13.context);
11327
- const target = resolveDomPathInScope(context.index, path13.nodes, context.scope);
11907
+ const path15 = sanitizeReplayElementPath(rawPath);
11908
+ const context = await this.resolvePathContext(session, pageRef, path15.context);
11909
+ const target = resolveDomPathInScope(context.index, path15.nodes, context.scope);
11328
11910
  if (!target) {
11329
- throwTargetNotFound(context.index, path13.nodes, context.scope);
11911
+ throwTargetNotFound(context.index, path15.nodes, context.scope);
11330
11912
  }
11331
11913
  if (target.node.nodeRef === void 0) {
11332
11914
  throw new Error(
11333
- `resolved path "${buildPathSelectorHint(path13)}" does not point to a live element`
11915
+ `resolved path "${buildPathSelectorHint(path15)}" does not point to a live element`
11334
11916
  );
11335
11917
  }
11336
11918
  const anchor = await this.buildAnchorFromSnapshotNode(session, context.snapshot, target.node);
11337
11919
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
11338
11920
  ...description === void 0 ? {} : { description },
11339
- replayPath: path13,
11921
+ replayPath: path15,
11340
11922
  ...source === "path" || source === "descriptor" ? { selectorUsed: target.selector } : {},
11341
11923
  ...descriptor === void 0 ? {} : { descriptor }
11342
11924
  });
@@ -11357,9 +11939,9 @@ var DefaultDomRuntime = class {
11357
11939
  });
11358
11940
  }
11359
11941
  async queryAllByElementPath(session, pageRef, rawPath) {
11360
- const path13 = sanitizeReplayElementPath(rawPath);
11361
- const context = await this.resolvePathContext(session, pageRef, path13.context);
11362
- return queryAllDomPathInScope(context.index, path13.nodes, context.scope).filter(
11942
+ const path15 = sanitizeReplayElementPath(rawPath);
11943
+ const context = await this.resolvePathContext(session, pageRef, path15.context);
11944
+ return queryAllDomPathInScope(context.index, path15.nodes, context.scope).filter(
11363
11945
  (node) => node.nodeRef !== void 0
11364
11946
  ).map((node) => this.createSnapshotTarget(context.snapshot, node));
11365
11947
  }
@@ -11545,16 +12127,16 @@ var DefaultDomRuntime = class {
11545
12127
  const index = createSnapshotIndex(item.snapshot);
11546
12128
  return this.resolveFirstArrayFieldTargetInNode(index, item.node, field.path);
11547
12129
  }
11548
- resolveFirstArrayFieldTargetInNode(index, rootNode, path13) {
11549
- const normalizedPath = sanitizeElementPath(path13);
12130
+ resolveFirstArrayFieldTargetInNode(index, rootNode, path15) {
12131
+ const normalizedPath = sanitizeElementPath(path15);
11550
12132
  const selectors = buildArrayFieldCandidates(normalizedPath);
11551
12133
  if (!selectors.length) {
11552
12134
  return rootNode;
11553
12135
  }
11554
12136
  return resolveFirstWithinNodeBySelectors(index, rootNode, selectors);
11555
12137
  }
11556
- resolveUniqueArrayFieldTargetInNode(index, rootNode, path13) {
11557
- const normalizedPath = sanitizeElementPath(path13);
12138
+ resolveUniqueArrayFieldTargetInNode(index, rootNode, path15) {
12139
+ const normalizedPath = sanitizeElementPath(path15);
11558
12140
  const selectors = buildArrayFieldCandidates(normalizedPath);
11559
12141
  if (!selectors.length) {
11560
12142
  return rootNode;
@@ -11643,8 +12225,8 @@ function encodeDataPath(tokens) {
11643
12225
  }
11644
12226
  return out;
11645
12227
  }
11646
- function parseDataPath(path13) {
11647
- const input = path13.trim();
12228
+ function parseDataPath(path15) {
12229
+ const input = path15.trim();
11648
12230
  if (input.length === 0) {
11649
12231
  return [];
11650
12232
  }
@@ -11694,8 +12276,8 @@ function parseDataPath(path13) {
11694
12276
  function inflateDataPathObject(flat) {
11695
12277
  let root = {};
11696
12278
  let initialized = false;
11697
- for (const [path13, value] of Object.entries(flat)) {
11698
- const tokens = parseDataPath(path13);
12279
+ for (const [path15, value] of Object.entries(flat)) {
12280
+ const tokens = parseDataPath(path15);
11699
12281
  if (!tokens || tokens.length === 0) {
11700
12282
  continue;
11701
12283
  }
@@ -12027,8 +12609,8 @@ function buildVariantDescriptorFromCluster(descriptors) {
12027
12609
  fields: mergedFields
12028
12610
  };
12029
12611
  }
12030
- function minimizePathMatchClauses(path13, mode) {
12031
- const normalized = sanitizeElementPath(path13);
12612
+ function minimizePathMatchClauses(path15, mode) {
12613
+ const normalized = sanitizeElementPath(path15);
12032
12614
  const nodes = normalized.nodes.map((node, index) => {
12033
12615
  const isLast = index === normalized.nodes.length - 1;
12034
12616
  const attrs = node.attrs || {};
@@ -12132,8 +12714,8 @@ function seedMinimalAttrClause(attrs) {
12132
12714
  }
12133
12715
  return null;
12134
12716
  }
12135
- function relaxPathForSingleSample(path13, mode) {
12136
- const normalized = sanitizeElementPath(path13);
12717
+ function relaxPathForSingleSample(path15, mode) {
12718
+ const normalized = sanitizeElementPath(path15);
12137
12719
  const relaxedNodes = normalized.nodes.map((node, index) => {
12138
12720
  const isLast = index === normalized.nodes.length - 1;
12139
12721
  const attrs = normalizeAttrsForSingleSample(node.attrs || {});
@@ -12218,8 +12800,8 @@ function shouldKeepAttrForSingleSample(key) {
12218
12800
  }
12219
12801
  return true;
12220
12802
  }
12221
- function buildPathStructureKey(path13) {
12222
- const normalized = sanitizeElementPath(path13);
12803
+ function buildPathStructureKey(path15) {
12804
+ const normalized = sanitizeElementPath(path15);
12223
12805
  return canonicalJsonString({
12224
12806
  context: (normalized.context || []).map((hop) => ({
12225
12807
  kind: hop.kind,
@@ -12346,30 +12928,30 @@ function buildArrayItemNode(fields) {
12346
12928
  }
12347
12929
  return node;
12348
12930
  }
12349
- function insertNodeAtPath(root, path13, node) {
12350
- const tokens = parseDataPath(path13);
12931
+ function insertNodeAtPath(root, path15, node) {
12932
+ const tokens = parseDataPath(path15);
12351
12933
  if (!tokens || !tokens.length) {
12352
12934
  throw new Error(
12353
- `Invalid persisted extraction path "${path13}": expected a non-empty object path.`
12935
+ `Invalid persisted extraction path "${path15}": expected a non-empty object path.`
12354
12936
  );
12355
12937
  }
12356
12938
  if (tokens.some((token) => token.kind === "index")) {
12357
12939
  throw new Error(
12358
- `Invalid persisted extraction path "${path13}": nested array indices are not supported in cached descriptors.`
12940
+ `Invalid persisted extraction path "${path15}": nested array indices are not supported in cached descriptors.`
12359
12941
  );
12360
12942
  }
12361
12943
  let current = root;
12362
12944
  for (let index = 0; index < tokens.length; index += 1) {
12363
12945
  const token = tokens[index];
12364
12946
  if (!token || token.kind !== "prop") {
12365
- throw new Error(`Invalid persisted extraction path "${path13}": expected object segment.`);
12947
+ throw new Error(`Invalid persisted extraction path "${path15}": expected object segment.`);
12366
12948
  }
12367
12949
  const isLast = index === tokens.length - 1;
12368
12950
  if (isLast) {
12369
12951
  const existing = current[token.key];
12370
12952
  if (existing) {
12371
12953
  throw new Error(
12372
- `Conflicting persisted extraction path "${path13}" detected while building descriptor tree.`
12954
+ `Conflicting persisted extraction path "${path15}" detected while building descriptor tree.`
12373
12955
  );
12374
12956
  }
12375
12957
  current[token.key] = node;
@@ -12384,7 +12966,7 @@ function insertNodeAtPath(root, path13, node) {
12384
12966
  }
12385
12967
  if (!isPersistedObjectNode(next)) {
12386
12968
  throw new Error(
12387
- `Conflicting persisted extraction path "${path13}" detected at "${token.key}".`
12969
+ `Conflicting persisted extraction path "${path15}" detected at "${token.key}".`
12388
12970
  );
12389
12971
  }
12390
12972
  current = next;
@@ -12419,7 +13001,7 @@ function buildItemRootForArrayIndex(entries) {
12419
13001
  }
12420
13002
  const paths = entries.map(
12421
13003
  (entry) => isPersistablePathField(entry.source) ? sanitizeElementPath(entry.source.path) : null
12422
- ).filter((path13) => path13 !== null);
13004
+ ).filter((path15) => path15 !== null);
12423
13005
  if (!paths.length) {
12424
13006
  return null;
12425
13007
  }
@@ -12440,7 +13022,7 @@ function getCommonPathPrefixLength(paths) {
12440
13022
  if (!paths.length) {
12441
13023
  return 0;
12442
13024
  }
12443
- const nodeChains = paths.map((path13) => path13.nodes);
13025
+ const nodeChains = paths.map((path15) => path15.nodes);
12444
13026
  const minLength = Math.min(...nodeChains.map((nodes) => nodes.length));
12445
13027
  if (!Number.isFinite(minLength) || minLength <= 0) {
12446
13028
  return 0;
@@ -12509,30 +13091,30 @@ function mergeElementPathsByMajority(paths) {
12509
13091
  if (!paths.length) {
12510
13092
  return null;
12511
13093
  }
12512
- const normalized = paths.map((path13) => sanitizeElementPath(path13));
13094
+ const normalized = paths.map((path15) => sanitizeElementPath(path15));
12513
13095
  const contextKey = pickModeString(
12514
- normalized.map((path13) => canonicalJsonString(path13.context)),
13096
+ normalized.map((path15) => canonicalJsonString(path15.context)),
12515
13097
  1
12516
13098
  );
12517
13099
  if (!contextKey) {
12518
13100
  return null;
12519
13101
  }
12520
- const sameContext = normalized.filter((path13) => canonicalJsonString(path13.context) === contextKey);
13102
+ const sameContext = normalized.filter((path15) => canonicalJsonString(path15.context) === contextKey);
12521
13103
  if (!sameContext.length) {
12522
13104
  return null;
12523
13105
  }
12524
13106
  const targetLength = pickModeNumber(
12525
- sameContext.map((path13) => path13.nodes.length),
13107
+ sameContext.map((path15) => path15.nodes.length),
12526
13108
  1
12527
13109
  ) ?? sameContext[0]?.nodes.length ?? 0;
12528
- const aligned = sameContext.filter((path13) => path13.nodes.length === targetLength);
13110
+ const aligned = sameContext.filter((path15) => path15.nodes.length === targetLength);
12529
13111
  if (!aligned.length) {
12530
13112
  return null;
12531
13113
  }
12532
13114
  const threshold = majorityThreshold(aligned.length);
12533
13115
  const nodes = [];
12534
13116
  for (let index = 0; index < targetLength; index += 1) {
12535
- const nodesAtIndex = aligned.map((path13) => path13.nodes[index]).filter((node) => node !== void 0);
13117
+ const nodesAtIndex = aligned.map((path15) => path15.nodes[index]).filter((node) => node !== void 0);
12536
13118
  if (!nodesAtIndex.length) {
12537
13119
  return null;
12538
13120
  }
@@ -12778,8 +13360,8 @@ function clonePathContext(context) {
12778
13360
  function clonePathNodes(nodes) {
12779
13361
  return JSON.parse(JSON.stringify(nodes || []));
12780
13362
  }
12781
- function cloneElementPath2(path13) {
12782
- return JSON.parse(JSON.stringify(path13));
13363
+ function cloneElementPath2(path15) {
13364
+ return JSON.parse(JSON.stringify(path15));
12783
13365
  }
12784
13366
  function clonePersistedOpensteerExtractionNode(node) {
12785
13367
  return JSON.parse(JSON.stringify(node));
@@ -13097,8 +13679,8 @@ function collectPersistedValueNodeRefs(node) {
13097
13679
  return [
13098
13680
  {
13099
13681
  path: sanitizeElementPath(node.$path),
13100
- replacePath: (path13) => {
13101
- node.$path = sanitizeElementPath(path13);
13682
+ replacePath: (path15) => {
13683
+ node.$path = sanitizeElementPath(path15);
13102
13684
  }
13103
13685
  }
13104
13686
  ];
@@ -13112,13 +13694,13 @@ function collectPersistedValueNodeRefs(node) {
13112
13694
  }
13113
13695
  return refs;
13114
13696
  }
13115
- function hasPositionClause(path13) {
13116
- return path13.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
13697
+ function hasPositionClause(path15) {
13698
+ return path15.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
13117
13699
  }
13118
- function stripPositionClauses2(path13) {
13700
+ function stripPositionClauses2(path15) {
13119
13701
  return sanitizeElementPath({
13120
- context: path13.context,
13121
- nodes: path13.nodes.map((node) => ({
13702
+ context: path15.context,
13703
+ nodes: path15.nodes.map((node) => ({
13122
13704
  ...node,
13123
13705
  match: node.match.filter((clause) => clause.kind !== "position")
13124
13706
  }))
@@ -13528,8 +14110,8 @@ function normalizeNonEmptyString2(name, value) {
13528
14110
  function normalizeKey(value) {
13529
14111
  return String(value ?? "").trim();
13530
14112
  }
13531
- function labelForPath(path13) {
13532
- return path13.trim().length === 0 ? "$" : path13;
14113
+ function labelForPath(path15) {
14114
+ return path15.trim().length === 0 ? "$" : path15;
13533
14115
  }
13534
14116
  function sha256Hex3(value) {
13535
14117
  return crypto.createHash("sha256").update(value).digest("hex");
@@ -13558,7 +14140,7 @@ var CHROME_SINGLETON_ARTIFACTS = [
13558
14140
  async function clearChromeSingletonEntries(userDataDir) {
13559
14141
  await Promise.all(
13560
14142
  CHROME_SINGLETON_ARTIFACTS.map(
13561
- (entry) => promises.rm(path6.join(userDataDir, entry), {
14143
+ (entry) => promises.rm(path7.join(userDataDir, entry), {
13562
14144
  recursive: true,
13563
14145
  force: true
13564
14146
  }).catch(() => void 0)
@@ -13573,7 +14155,7 @@ async function sanitizeChromeProfile(userDataDir) {
13573
14155
  await Promise.all(profileDirs.map((dir) => sanitizeProfilePreferences(userDataDir, dir)));
13574
14156
  }
13575
14157
  async function sanitizeProfilePreferences(userDataDir, profileDir) {
13576
- const prefsPath = path6.join(userDataDir, profileDir, "Preferences");
14158
+ const prefsPath = path7.join(userDataDir, profileDir, "Preferences");
13577
14159
  try {
13578
14160
  const raw = await promises.readFile(prefsPath, "utf8");
13579
14161
  const prefs = JSON.parse(raw);
@@ -13585,14 +14167,13 @@ async function sanitizeProfilePreferences(userDataDir, profileDir) {
13585
14167
  profile.exited_cleanly = true;
13586
14168
  prefs.profile = profile;
13587
14169
  await promises.writeFile(prefsPath, JSON.stringify(prefs), "utf8");
13588
- await promises.rm(path6.join(userDataDir, profileDir, "Secure Preferences"), { force: true }).catch(
14170
+ await promises.rm(path7.join(userDataDir, profileDir, "Secure Preferences"), { force: true }).catch(
13589
14171
  () => void 0
13590
14172
  );
13591
14173
  } catch {
13592
14174
  }
13593
14175
  }
13594
- var PROCESS_LIST_MAX_BUFFER_BYTES2 = 16 * 1024 * 1024;
13595
- var PS_COMMAND_ENV2 = { ...process.env, LC_ALL: "C" };
14176
+ ({ ...process.env});
13596
14177
  var WINDOWS_PROGRAM_FILES = process.env.PROGRAMFILES ?? "C:\\Program Files";
13597
14178
  var WINDOWS_PROGRAM_FILES_X86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
13598
14179
  var BROWSER_BRANDS = [
@@ -13607,9 +14188,9 @@ var BROWSER_BRANDS = [
13607
14188
  },
13608
14189
  win32: {
13609
14190
  executableCandidates: [
13610
- path6.join(WINDOWS_PROGRAM_FILES, "Google", "Chrome", "Application", "chrome.exe"),
13611
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Google", "Chrome", "Application", "chrome.exe"),
13612
- path6.join("~", "AppData", "Local", "Google", "Chrome", "Application", "chrome.exe")
14191
+ path7.join(WINDOWS_PROGRAM_FILES, "Google", "Chrome", "Application", "chrome.exe"),
14192
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Google", "Chrome", "Application", "chrome.exe"),
14193
+ path7.join("~", "AppData", "Local", "Google", "Chrome", "Application", "chrome.exe")
13613
14194
  ],
13614
14195
  userDataDir: "~/AppData/Local/Google/Chrome/User Data",
13615
14196
  processNames: ["/google/chrome/application/chrome.exe"]
@@ -13639,7 +14220,7 @@ var BROWSER_BRANDS = [
13639
14220
  },
13640
14221
  win32: {
13641
14222
  executableCandidates: [
13642
- path6.join("~", "AppData", "Local", "Google", "Chrome SxS", "Application", "chrome.exe")
14223
+ path7.join("~", "AppData", "Local", "Google", "Chrome SxS", "Application", "chrome.exe")
13643
14224
  ],
13644
14225
  userDataDir: "~/AppData/Local/Google/Chrome SxS/User Data",
13645
14226
  processNames: ["/google/chrome sxs/application/chrome.exe"]
@@ -13656,9 +14237,9 @@ var BROWSER_BRANDS = [
13656
14237
  },
13657
14238
  win32: {
13658
14239
  executableCandidates: [
13659
- path6.join(WINDOWS_PROGRAM_FILES, "Chromium", "Application", "chrome.exe"),
13660
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Chromium", "Application", "chrome.exe"),
13661
- path6.join("~", "AppData", "Local", "Chromium", "Application", "chrome.exe")
14240
+ path7.join(WINDOWS_PROGRAM_FILES, "Chromium", "Application", "chrome.exe"),
14241
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Chromium", "Application", "chrome.exe"),
14242
+ path7.join("~", "AppData", "Local", "Chromium", "Application", "chrome.exe")
13662
14243
  ],
13663
14244
  userDataDir: "~/AppData/Local/Chromium/User Data",
13664
14245
  processNames: ["/chromium/application/chrome.exe"]
@@ -13685,15 +14266,15 @@ var BROWSER_BRANDS = [
13685
14266
  },
13686
14267
  win32: {
13687
14268
  executableCandidates: [
13688
- path6.join(WINDOWS_PROGRAM_FILES, "BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
13689
- path6.join(
14269
+ path7.join(WINDOWS_PROGRAM_FILES, "BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
14270
+ path7.join(
13690
14271
  WINDOWS_PROGRAM_FILES_X86,
13691
14272
  "BraveSoftware",
13692
14273
  "Brave-Browser",
13693
14274
  "Application",
13694
14275
  "brave.exe"
13695
14276
  ),
13696
- path6.join("~", "AppData", "Local", "BraveSoftware", "Brave-Browser", "Application", "brave.exe")
14277
+ path7.join("~", "AppData", "Local", "BraveSoftware", "Brave-Browser", "Application", "brave.exe")
13697
14278
  ],
13698
14279
  userDataDir: "~/AppData/Local/BraveSoftware/Brave-Browser/User Data",
13699
14280
  processNames: ["/bravesoftware/brave-browser/application/brave.exe"]
@@ -13719,9 +14300,9 @@ var BROWSER_BRANDS = [
13719
14300
  },
13720
14301
  win32: {
13721
14302
  executableCandidates: [
13722
- path6.join(WINDOWS_PROGRAM_FILES, "Microsoft", "Edge", "Application", "msedge.exe"),
13723
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Microsoft", "Edge", "Application", "msedge.exe"),
13724
- path6.join("~", "AppData", "Local", "Microsoft", "Edge", "Application", "msedge.exe")
14303
+ path7.join(WINDOWS_PROGRAM_FILES, "Microsoft", "Edge", "Application", "msedge.exe"),
14304
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Microsoft", "Edge", "Application", "msedge.exe"),
14305
+ path7.join("~", "AppData", "Local", "Microsoft", "Edge", "Application", "msedge.exe")
13725
14306
  ],
13726
14307
  userDataDir: "~/AppData/Local/Microsoft/Edge/User Data",
13727
14308
  processNames: ["/microsoft/edge/application/msedge.exe"]
@@ -13749,9 +14330,9 @@ var BROWSER_BRANDS = [
13749
14330
  },
13750
14331
  win32: {
13751
14332
  executableCandidates: [
13752
- path6.join(WINDOWS_PROGRAM_FILES, "Vivaldi", "Application", "vivaldi.exe"),
13753
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Vivaldi", "Application", "vivaldi.exe"),
13754
- path6.join("~", "AppData", "Local", "Vivaldi", "Application", "vivaldi.exe")
14333
+ path7.join(WINDOWS_PROGRAM_FILES, "Vivaldi", "Application", "vivaldi.exe"),
14334
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Vivaldi", "Application", "vivaldi.exe"),
14335
+ path7.join("~", "AppData", "Local", "Vivaldi", "Application", "vivaldi.exe")
13755
14336
  ],
13756
14337
  userDataDir: "~/AppData/Local/Vivaldi/User Data",
13757
14338
  processNames: ["/vivaldi/application/vivaldi.exe"]
@@ -13778,9 +14359,6 @@ var BROWSER_BRANDS = [
13778
14359
  }
13779
14360
  }
13780
14361
  ];
13781
- function getAllBrowserBrands() {
13782
- return BROWSER_BRANDS;
13783
- }
13784
14362
  function getBrowserBrand(id) {
13785
14363
  const brand2 = BROWSER_BRANDS.find((candidate) => candidate.id === id);
13786
14364
  if (!brand2) {
@@ -13818,177 +14396,35 @@ function detectInstalledBrowserBrands() {
13818
14396
  brandId: brand2.id,
13819
14397
  displayName: brand2.displayName,
13820
14398
  executablePath,
13821
- userDataDir: path6.resolve(expandHome(platformConfig.userDataDir))
14399
+ userDataDir: path7.resolve(expandHome(platformConfig.userDataDir))
13822
14400
  });
13823
14401
  }
13824
14402
  return installations;
13825
14403
  }
13826
- function resolveBrandExecutablePath(brand2, explicitPath) {
13827
- if (explicitPath !== void 0) {
13828
- const resolvedPath2 = path6.resolve(expandHome(explicitPath));
13829
- if (!fs.existsSync(resolvedPath2)) {
13830
- throw new Error(`${brand2.displayName} executable was not found at "${resolvedPath2}".`);
13831
- }
13832
- return resolvedPath2;
13833
- }
13834
- const platformConfig = resolveBrandPlatformConfig(brand2);
13835
- if (!platformConfig) {
13836
- throw new Error(`${brand2.displayName} is not supported on ${process.platform}.`);
13837
- }
13838
- const resolvedPath = firstExistingPath(
13839
- resolveExecutableCandidates(platformConfig.executableCandidates)
13840
- );
13841
- if (!resolvedPath) {
13842
- throw new Error(
13843
- `Could not find a ${brand2.displayName} executable. Pass --executable-path or browser.executablePath.`
13844
- );
13845
- }
13846
- return resolvedPath;
13847
- }
13848
14404
  function resolveBrandUserDataDir(brand2, explicitDir) {
13849
14405
  if (explicitDir !== void 0) {
13850
- return path6.resolve(expandHome(explicitDir));
14406
+ return path7.resolve(expandHome(explicitDir));
13851
14407
  }
13852
14408
  const platformConfig = resolveBrandPlatformConfig(brand2);
13853
14409
  if (!platformConfig) {
13854
14410
  throw new Error(`${brand2.displayName} is not supported on ${process.platform}.`);
13855
14411
  }
13856
- return path6.resolve(expandHome(platformConfig.userDataDir));
13857
- }
13858
- function isBrandProcess(brand2, commandLine) {
13859
- const normalizedCommand = normalizeCommand(commandLine);
13860
- if (!normalizedCommand) {
13861
- return false;
13862
- }
13863
- if (normalizedCommand.includes("crashpad_handler")) {
13864
- return false;
13865
- }
13866
- if (/\s--type=/.test(normalizedCommand)) {
13867
- return false;
13868
- }
13869
- return getBrandProcessMarkers(brand2).some((marker) => normalizedCommand.includes(marker));
13870
- }
13871
- function findBrandProcess(brand2) {
13872
- for (const processEntry of listProcesses()) {
13873
- if (isBrandProcess(brand2, processEntry.commandLine)) {
13874
- return { pid: processEntry.pid };
13875
- }
13876
- }
13877
- return null;
13878
- }
13879
- function getBrandProcessMarkers(brand2) {
13880
- const markers = /* @__PURE__ */ new Set();
13881
- for (const config of [brand2.darwin, brand2.win32, brand2.linux]) {
13882
- if (!config) {
13883
- continue;
13884
- }
13885
- for (const processName of config.processNames) {
13886
- const normalized = normalizeCommand(processName);
13887
- if (normalized) {
13888
- markers.add(normalized);
13889
- }
13890
- }
13891
- for (const candidate of config.executableCandidates) {
13892
- if (!candidate) {
13893
- continue;
13894
- }
13895
- const normalized = normalizeCommand(path6.resolve(expandHome(candidate)));
13896
- if (normalized) {
13897
- markers.add(normalized);
13898
- }
13899
- }
13900
- }
13901
- return [...markers];
14412
+ return path7.resolve(expandHome(platformConfig.userDataDir));
13902
14413
  }
13903
14414
  function resolveExecutableCandidates(candidates) {
13904
- return candidates.map((candidate) => candidate ? path6.resolve(expandHome(candidate)) : null);
13905
- }
13906
- function listProcesses() {
13907
- if (process.platform === "win32") {
13908
- return listWindowsProcesses();
13909
- }
13910
- return listUnixProcesses();
13911
- }
13912
- function listUnixProcesses() {
13913
- try {
13914
- const output = child_process.execFileSync("ps", ["-A", "-o", "pid=,command="], {
13915
- encoding: "utf8",
13916
- env: PS_COMMAND_ENV2,
13917
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2,
13918
- stdio: ["ignore", "pipe", "ignore"]
13919
- });
13920
- return output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
13921
- const match = /^(\d+)\s+(.*)$/.exec(line);
13922
- if (!match) {
13923
- return null;
13924
- }
13925
- const pid = Number.parseInt(match[1] ?? "", 10);
13926
- const commandLine = match[2]?.trim() ?? "";
13927
- if (!Number.isInteger(pid) || pid <= 0 || commandLine.length === 0) {
13928
- return null;
13929
- }
13930
- return {
13931
- pid,
13932
- commandLine
13933
- };
13934
- }).filter(
13935
- (entry) => entry !== null
13936
- ).sort((left, right) => left.pid - right.pid);
13937
- } catch {
13938
- return [];
13939
- }
13940
- }
13941
- function listWindowsProcesses() {
13942
- try {
13943
- const output = child_process.execFileSync(
13944
- "powershell.exe",
13945
- [
13946
- "-NoProfile",
13947
- "-Command",
13948
- "Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"
13949
- ],
13950
- {
13951
- encoding: "utf8",
13952
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2,
13953
- stdio: ["ignore", "pipe", "ignore"]
13954
- }
13955
- ).trim();
13956
- if (!output) {
13957
- return [];
13958
- }
13959
- const parsed = JSON.parse(output);
13960
- const records = Array.isArray(parsed) ? parsed : [parsed];
13961
- return records.map((record) => {
13962
- const pid = Number(record.ProcessId);
13963
- const commandLine = typeof record.CommandLine === "string" ? record.CommandLine.trim() : "";
13964
- if (!Number.isInteger(pid) || pid <= 0 || commandLine.length === 0) {
13965
- return null;
13966
- }
13967
- return {
13968
- pid,
13969
- commandLine
13970
- };
13971
- }).filter(
13972
- (entry) => entry !== null
13973
- ).sort((left, right) => left.pid - right.pid);
13974
- } catch {
13975
- return [];
13976
- }
13977
- }
13978
- function normalizeCommand(value) {
13979
- return value.trim().replaceAll("\\", "/").toLowerCase();
14415
+ return candidates.map((candidate) => candidate ? path7.resolve(expandHome(candidate)) : null);
13980
14416
  }
13981
14417
 
13982
14418
  // src/local-browser/chrome-discovery.ts
13983
14419
  function expandHome(value) {
13984
14420
  if (value === "~" || value.startsWith("~/")) {
13985
- return path6.join(os.homedir(), value.slice(1));
14421
+ return path7.join(os.homedir(), value.slice(1));
13986
14422
  }
13987
14423
  return value;
13988
14424
  }
13989
14425
  function resolveChromeUserDataDir(userDataDir) {
13990
14426
  const installation = detectLocalChromeInstallations().find(
13991
- (candidate) => fs.existsSync(path6.join(candidate.userDataDir, "Local State")) || candidate.executablePath !== null
14427
+ (candidate) => fs.existsSync(path7.join(candidate.userDataDir, "Local State")) || candidate.executablePath !== null
13992
14428
  );
13993
14429
  if (!installation) {
13994
14430
  throw new Error("Could not find a local Chrome or Chromium profile directory.");
@@ -13997,7 +14433,7 @@ function resolveChromeUserDataDir(userDataDir) {
13997
14433
  }
13998
14434
  function resolveChromeExecutablePath(executablePath) {
13999
14435
  if (executablePath !== void 0) {
14000
- const resolvedPath = path6.resolve(expandHome(executablePath));
14436
+ const resolvedPath = path7.resolve(expandHome(executablePath));
14001
14437
  if (!fs.existsSync(resolvedPath)) {
14002
14438
  throw new Error(`Chrome executable was not found at "${resolvedPath}".`);
14003
14439
  }
@@ -14021,37 +14457,37 @@ function detectLocalChromeInstallations() {
14021
14457
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
14022
14458
  "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
14023
14459
  ]),
14024
- userDataDir: path6.join(os.homedir(), "Library", "Application Support", "Google", "Chrome")
14460
+ userDataDir: path7.join(os.homedir(), "Library", "Application Support", "Google", "Chrome")
14025
14461
  },
14026
14462
  {
14027
14463
  brand: "chromium",
14028
14464
  executablePath: firstExistingPath(["/Applications/Chromium.app/Contents/MacOS/Chromium"]),
14029
- userDataDir: path6.join(os.homedir(), "Library", "Application Support", "Chromium")
14465
+ userDataDir: path7.join(os.homedir(), "Library", "Application Support", "Chromium")
14030
14466
  }
14031
14467
  ];
14032
14468
  }
14033
14469
  if (process.platform === "win32") {
14034
14470
  const programFiles = process.env.PROGRAMFILES ?? "C:\\Program Files";
14035
14471
  const programFilesX86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
14036
- const localAppData = process.env.LOCALAPPDATA ?? path6.join(os.homedir(), "AppData", "Local");
14472
+ const localAppData = process.env.LOCALAPPDATA ?? path7.join(os.homedir(), "AppData", "Local");
14037
14473
  return [
14038
14474
  {
14039
14475
  brand: "chrome",
14040
14476
  executablePath: firstExistingPath([
14041
- path6.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
14042
- path6.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
14043
- path6.join(localAppData, "Google", "Chrome", "Application", "chrome.exe")
14477
+ path7.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
14478
+ path7.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
14479
+ path7.join(localAppData, "Google", "Chrome", "Application", "chrome.exe")
14044
14480
  ]),
14045
- userDataDir: path6.join(localAppData, "Google", "Chrome", "User Data")
14481
+ userDataDir: path7.join(localAppData, "Google", "Chrome", "User Data")
14046
14482
  },
14047
14483
  {
14048
14484
  brand: "chromium",
14049
14485
  executablePath: firstExistingPath([
14050
- path6.join(programFiles, "Chromium", "Application", "chrome.exe"),
14051
- path6.join(programFilesX86, "Chromium", "Application", "chrome.exe"),
14052
- path6.join(localAppData, "Chromium", "Application", "chrome.exe")
14486
+ path7.join(programFiles, "Chromium", "Application", "chrome.exe"),
14487
+ path7.join(programFilesX86, "Chromium", "Application", "chrome.exe"),
14488
+ path7.join(localAppData, "Chromium", "Application", "chrome.exe")
14053
14489
  ]),
14054
- userDataDir: path6.join(localAppData, "Chromium", "User Data")
14490
+ userDataDir: path7.join(localAppData, "Chromium", "User Data")
14055
14491
  }
14056
14492
  ];
14057
14493
  }
@@ -14064,7 +14500,7 @@ function detectLocalChromeInstallations() {
14064
14500
  resolveBinaryFromPath("google-chrome"),
14065
14501
  resolveBinaryFromPath("google-chrome-stable")
14066
14502
  ]),
14067
- userDataDir: path6.join(os.homedir(), ".config", "google-chrome")
14503
+ userDataDir: path7.join(os.homedir(), ".config", "google-chrome")
14068
14504
  },
14069
14505
  {
14070
14506
  brand: "chromium",
@@ -14074,7 +14510,7 @@ function detectLocalChromeInstallations() {
14074
14510
  resolveBinaryFromPath("chromium"),
14075
14511
  resolveBinaryFromPath("chromium-browser")
14076
14512
  ]),
14077
- userDataDir: path6.join(os.homedir(), ".config", "chromium")
14513
+ userDataDir: path7.join(os.homedir(), ".config", "chromium")
14078
14514
  }
14079
14515
  ];
14080
14516
  }
@@ -14086,8 +14522,8 @@ function detectLocalBrowserInstallations() {
14086
14522
  }));
14087
14523
  }
14088
14524
  function listLocalChromeProfiles(userDataDir = resolveChromeUserDataDir()) {
14089
- const resolvedUserDataDir = path6.resolve(expandHome(userDataDir));
14090
- const localStatePath = path6.join(resolvedUserDataDir, "Local State");
14525
+ const resolvedUserDataDir = path7.resolve(expandHome(userDataDir));
14526
+ const localStatePath = path7.join(resolvedUserDataDir, "Local State");
14091
14527
  if (!fs.existsSync(localStatePath)) {
14092
14528
  return [];
14093
14529
  }
@@ -14099,7 +14535,7 @@ function listLocalChromeProfiles(userDataDir = resolveChromeUserDataDir()) {
14099
14535
  }
14100
14536
  return Object.entries(infoCache).map(([directory, info]) => {
14101
14537
  const record = info && typeof info === "object" && !Array.isArray(info) ? info : {};
14102
- const name = typeof record.name === "string" && record.name.trim().length > 0 ? record.name.trim() : directory || path6.basename(directory);
14538
+ const name = typeof record.name === "string" && record.name.trim().length > 0 ? record.name.trim() : directory || path7.basename(directory);
14103
14539
  return {
14104
14540
  directory,
14105
14541
  name,
@@ -14111,7 +14547,7 @@ function listLocalChromeProfiles(userDataDir = resolveChromeUserDataDir()) {
14111
14547
  }
14112
14548
  }
14113
14549
  function readDevToolsActivePort(userDataDir) {
14114
- const devToolsPath = path6.join(userDataDir, "DevToolsActivePort");
14550
+ const devToolsPath = path7.join(userDataDir, "DevToolsActivePort");
14115
14551
  if (!fs.existsSync(devToolsPath)) {
14116
14552
  return null;
14117
14553
  }
@@ -14344,8 +14780,8 @@ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
14344
14780
  const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
14345
14781
  return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
14346
14782
  }
14347
- function normalizeWebSocketPath(path13) {
14348
- return path13.startsWith("/") ? path13 : `/${path13}`;
14783
+ function normalizeWebSocketPath(path15) {
14784
+ return path15.startsWith("/") ? path15 : `/${path15}`;
14349
14785
  }
14350
14786
  function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
14351
14787
  try {
@@ -14391,20 +14827,20 @@ var SESSION_SKIPPED_PROFILE_DIRECTORIES = /* @__PURE__ */ new Set([
14391
14827
  "Network"
14392
14828
  ]);
14393
14829
  async function createBrowserProfileSnapshot(input) {
14394
- const sourceUserDataDir = path6.resolve(expandHome(input.sourceUserDataDir));
14395
- const targetUserDataDir = path6.resolve(expandHome(input.targetUserDataDir));
14830
+ const sourceUserDataDir = path7.resolve(expandHome(input.sourceUserDataDir));
14831
+ const targetUserDataDir = path7.resolve(expandHome(input.targetUserDataDir));
14396
14832
  const profileDirectory = input.profileDirectory?.trim();
14397
14833
  const copyMode = input.copyMode;
14398
14834
  await promises.mkdir(targetUserDataDir, { recursive: true });
14399
14835
  await clearChromeSingletonEntries(targetUserDataDir);
14400
14836
  if (profileDirectory) {
14401
- const sourceProfileDir = path6.join(sourceUserDataDir, profileDirectory);
14837
+ const sourceProfileDir = path7.join(sourceUserDataDir, profileDirectory);
14402
14838
  if (!fs.existsSync(sourceProfileDir)) {
14403
14839
  throw new Error(
14404
14840
  `Chrome profile "${profileDirectory}" was not found in "${sourceUserDataDir}".`
14405
14841
  );
14406
14842
  }
14407
- await promises.cp(sourceProfileDir, path6.join(targetUserDataDir, profileDirectory), {
14843
+ await promises.cp(sourceProfileDir, path7.join(targetUserDataDir, profileDirectory), {
14408
14844
  recursive: true,
14409
14845
  filter: (candidate) => shouldCopyEntry({
14410
14846
  candidatePath: candidate,
@@ -14428,8 +14864,8 @@ async function copyRootLevelEntries(input) {
14428
14864
  if (CHROME_SINGLETON_ENTRIES.has(entry) || entry === input.selectedProfileDirectory) {
14429
14865
  continue;
14430
14866
  }
14431
- const sourcePath = path6.join(input.sourceUserDataDir, entry);
14432
- const targetPath = path6.join(input.targetUserDataDir, entry);
14867
+ const sourcePath = path7.join(input.sourceUserDataDir, entry);
14868
+ const targetPath = path7.join(input.targetUserDataDir, entry);
14433
14869
  const entryStat = await promises.stat(sourcePath).catch(() => null);
14434
14870
  if (!entryStat) {
14435
14871
  continue;
@@ -14461,7 +14897,7 @@ async function copyRootLevelEntries(input) {
14461
14897
  }
14462
14898
  }
14463
14899
  function isProfileDirectory(userDataDir, entry) {
14464
- return fs.existsSync(path6.join(userDataDir, entry, "Preferences"));
14900
+ return fs.existsSync(path7.join(userDataDir, entry, "Preferences"));
14465
14901
  }
14466
14902
  function shouldCopyEntry(input) {
14467
14903
  const entryName = input.candidatePath.split("/").at(-1)?.split("\\").at(-1) ?? input.candidatePath;
@@ -14471,7 +14907,7 @@ function shouldCopyEntry(input) {
14471
14907
  if (input.copyMode !== "session") {
14472
14908
  return true;
14473
14909
  }
14474
- const relativePath = path6.relative(input.rootPath, input.candidatePath);
14910
+ const relativePath = path7.relative(input.rootPath, input.candidatePath);
14475
14911
  if (relativePath.length === 0) {
14476
14912
  return true;
14477
14913
  }
@@ -14953,7 +15389,7 @@ function pickStealthProfilePreset(overrides) {
14953
15389
  var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
14954
15390
  var OPENSTEER_LIVE_SESSION_VERSION = 1;
14955
15391
  function resolveLiveSessionRecordPath(rootPath, provider) {
14956
- return path6__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
15392
+ return path7__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
14957
15393
  }
14958
15394
  function resolveLocalSessionRecordPath(rootPath) {
14959
15395
  return resolveLiveSessionRecordPath(rootPath, "local");
@@ -15113,8 +15549,8 @@ var OpensteerBrowserManager = class {
15113
15549
  ...options.browser === void 0 ? {} : { browser: options.browser },
15114
15550
  ...this.contextOptions === void 0 ? {} : { context: this.contextOptions }
15115
15551
  });
15116
- this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path6__default.default.join(os.tmpdir(), `${TEMPORARY_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
15117
- rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
15552
+ this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path7__default.default.join(os.tmpdir(), `${TEMPORARY_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
15553
+ rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
15118
15554
  workspace: this.workspace
15119
15555
  }));
15120
15556
  this.cleanupRootOnDisconnect = this.workspace === void 0;
@@ -15184,7 +15620,7 @@ var OpensteerBrowserManager = class {
15184
15620
  userDataDir: "browser/user-data",
15185
15621
  bootstrap: {
15186
15622
  kind: "cloneLocalProfile",
15187
- sourceUserDataDir: path6__default.default.resolve(input.sourceUserDataDir),
15623
+ sourceUserDataDir: path7__default.default.resolve(input.sourceUserDataDir),
15188
15624
  ...input.sourceProfileDirectory === void 0 ? {} : { sourceProfileDirectory: input.sourceProfileDirectory }
15189
15625
  }
15190
15626
  };
@@ -15311,7 +15747,7 @@ var OpensteerBrowserManager = class {
15311
15747
  });
15312
15748
  }
15313
15749
  async createTemporaryEngine() {
15314
- const userDataDir = await promises.mkdtemp(path6__default.default.join(os.tmpdir(), "opensteer-temporary-browser-"));
15750
+ const userDataDir = await promises.mkdtemp(path7__default.default.join(os.tmpdir(), "opensteer-temporary-browser-"));
15315
15751
  await clearChromeSingletonEntries(userDataDir);
15316
15752
  const launched = await launchOwnedBrowser({
15317
15753
  userDataDir,
@@ -15758,7 +16194,7 @@ async function terminateProcess(pid) {
15758
16194
  }
15759
16195
  }
15760
16196
  async function requestBrowserClose(endpoint) {
15761
- await new Promise((resolve5, reject) => {
16197
+ await new Promise((resolve4, reject) => {
15762
16198
  const socket = new WebSocket(endpoint);
15763
16199
  const timeout = setTimeout(() => {
15764
16200
  socket.close();
@@ -15775,7 +16211,7 @@ async function requestBrowserClose(endpoint) {
15775
16211
  reject(error);
15776
16212
  return;
15777
16213
  }
15778
- resolve5();
16214
+ resolve4();
15779
16215
  };
15780
16216
  socket.addEventListener("open", () => {
15781
16217
  socket.send(JSON.stringify({ id: 1, method: "Browser.close" }));
@@ -15813,7 +16249,7 @@ async function waitForProcessExit(pid, timeoutMs) {
15813
16249
  return !isProcessRunning(pid);
15814
16250
  }
15815
16251
  function resolveAbpSessionDir(workspace) {
15816
- return path6__default.default.join(workspace.livePath, "abp-session");
16252
+ return path7__default.default.join(workspace.livePath, "abp-session");
15817
16253
  }
15818
16254
  async function allocateEphemeralPort() {
15819
16255
  const { allocatePort } = await loadAbpModule();
@@ -15871,7 +16307,103 @@ function isStealthProfile(input) {
15871
16307
  return input.id !== void 0 && input.platform !== void 0 && input.browserBrand !== void 0 && input.browserVersion !== void 0 && input.userAgent !== void 0 && input.viewport !== void 0 && input.screenResolution !== void 0 && input.devicePixelRatio !== void 0 && input.maxTouchPoints !== void 0 && input.webglVendor !== void 0 && input.webglRenderer !== void 0 && input.fonts !== void 0 && input.canvasNoiseSeed !== void 0 && input.audioNoiseSeed !== void 0 && input.locale !== void 0 && input.timezoneId !== void 0;
15872
16308
  }
15873
16309
  async function sleep(ms) {
15874
- await new Promise((resolve5) => setTimeout(resolve5, ms));
16310
+ await new Promise((resolve4) => setTimeout(resolve4, ms));
16311
+ }
16312
+ var ENV_FILENAMES = [".env", ".env.local"];
16313
+ var OPENSTEER_ENV_PREFIX = "OPENSTEER_";
16314
+ var opensteerEnvironmentCache = /* @__PURE__ */ new Map();
16315
+ function resolveOpensteerEnvironment(cwd = process.cwd(), baseEnv = process.env) {
16316
+ const resolvedCwd = path7__default.default.resolve(cwd);
16317
+ const signature = buildEnvironmentSignature(baseEnv, isOpensteerEnvironmentKey);
16318
+ const cached = opensteerEnvironmentCache.get(resolvedCwd);
16319
+ if (cached && cached.signature === signature) {
16320
+ return { ...cached.values };
16321
+ }
16322
+ const resolved = resolveEnvironmentFiles(resolvedCwd, baseEnv, isOpensteerEnvironmentKey);
16323
+ opensteerEnvironmentCache.set(resolvedCwd, {
16324
+ signature,
16325
+ values: { ...resolved }
16326
+ });
16327
+ return { ...resolved };
16328
+ }
16329
+ function collectDirectories(cwd) {
16330
+ const directories = [];
16331
+ let current = path7__default.default.resolve(cwd);
16332
+ for (; ; ) {
16333
+ directories.unshift(current);
16334
+ const parent = path7__default.default.dirname(current);
16335
+ if (parent === current) {
16336
+ return directories;
16337
+ }
16338
+ current = parent;
16339
+ }
16340
+ }
16341
+ function parseEnvFile(contents) {
16342
+ const parsed = {};
16343
+ for (const rawLine of contents.split(/\r?\n/u)) {
16344
+ const trimmed = rawLine.trim();
16345
+ if (!trimmed || trimmed.startsWith("#")) {
16346
+ continue;
16347
+ }
16348
+ const line = trimmed.startsWith("export ") ? trimmed.slice("export ".length) : trimmed;
16349
+ const separatorIndex = line.indexOf("=");
16350
+ if (separatorIndex <= 0) {
16351
+ continue;
16352
+ }
16353
+ const key = line.slice(0, separatorIndex).trim();
16354
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key)) {
16355
+ continue;
16356
+ }
16357
+ const rawValue = line.slice(separatorIndex + 1).trim();
16358
+ parsed[key] = parseEnvValue(rawValue);
16359
+ }
16360
+ return parsed;
16361
+ }
16362
+ function parseEnvValue(rawValue) {
16363
+ if (rawValue.length >= 2 && rawValue.startsWith('"') && rawValue.endsWith('"')) {
16364
+ return rawValue.slice(1, -1).replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"');
16365
+ }
16366
+ if (rawValue.length >= 2 && rawValue.startsWith("'") && rawValue.endsWith("'")) {
16367
+ return rawValue.slice(1, -1);
16368
+ }
16369
+ return rawValue.replace(/\s+#.*$/u, "").trimEnd();
16370
+ }
16371
+ function resolveEnvironmentFiles(cwd, baseEnv, predicate) {
16372
+ const resolved = collectEnvironment(baseEnv, predicate);
16373
+ const protectedKeys = new Set(Object.keys(resolved));
16374
+ const directories = collectDirectories(cwd);
16375
+ for (const directory of directories) {
16376
+ for (const filename of ENV_FILENAMES) {
16377
+ const filePath = path7__default.default.join(directory, filename);
16378
+ if (!fs.existsSync(filePath)) {
16379
+ continue;
16380
+ }
16381
+ const parsed = parseEnvFile(fs.readFileSync(filePath, "utf8"));
16382
+ for (const [key, value] of Object.entries(parsed)) {
16383
+ if (predicate && !predicate(key) || protectedKeys.has(key)) {
16384
+ continue;
16385
+ }
16386
+ resolved[key] = value;
16387
+ }
16388
+ }
16389
+ }
16390
+ return resolved;
16391
+ }
16392
+ function collectEnvironment(baseEnv, predicate) {
16393
+ const resolved = {};
16394
+ for (const [key, value] of Object.entries(baseEnv)) {
16395
+ if (predicate && !predicate(key) || value === void 0) {
16396
+ continue;
16397
+ }
16398
+ resolved[key] = value;
16399
+ }
16400
+ return resolved;
16401
+ }
16402
+ function buildEnvironmentSignature(baseEnv, predicate) {
16403
+ return Object.entries(baseEnv).filter(([key, value]) => predicate(key) && value !== void 0).sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)).map(([key, value]) => `${key}=${value}`).join("\n");
16404
+ }
16405
+ function isOpensteerEnvironmentKey(key) {
16406
+ return key.startsWith(OPENSTEER_ENV_PREFIX);
15875
16407
  }
15876
16408
 
15877
16409
  // ../runtime-core/package.json
@@ -17485,7 +18017,7 @@ function diffStringMap(prefix, left, right, includeUnchanged, output) {
17485
18017
  diffScalarField(`${prefix}.${key}`, left[key], right[key], includeUnchanged, output);
17486
18018
  }
17487
18019
  }
17488
- function diffScalarField(path13, left, right, includeUnchanged, output) {
18020
+ function diffScalarField(path15, left, right, includeUnchanged, output) {
17489
18021
  const leftValue = stringifyFieldValue(left);
17490
18022
  const rightValue = stringifyFieldValue(right);
17491
18023
  const kind = leftValue === void 0 ? rightValue === void 0 ? "unchanged" : "added" : rightValue === void 0 ? "removed" : leftValue === rightValue ? "unchanged" : "changed";
@@ -17493,7 +18025,7 @@ function diffScalarField(path13, left, right, includeUnchanged, output) {
17493
18025
  return;
17494
18026
  }
17495
18027
  output.push({
17496
- path: path13,
18028
+ path: path15,
17497
18029
  kind,
17498
18030
  ...leftValue === void 0 ? {} : { leftValue },
17499
18031
  ...rightValue === void 0 ? {} : { rightValue },
@@ -18499,9 +19031,9 @@ function matchReverseTargetHints(channel, codec, targetHints) {
18499
19031
  matches.add(`host:${host}`);
18500
19032
  }
18501
19033
  }
18502
- for (const path13 of targetHints.paths ?? []) {
18503
- if (url.pathname.includes(path13)) {
18504
- matches.add(`path:${path13}`);
19034
+ for (const path15 of targetHints.paths ?? []) {
19035
+ if (url.pathname.includes(path15)) {
19036
+ matches.add(`path:${path15}`);
18505
19037
  }
18506
19038
  }
18507
19039
  for (const operationName of targetHints.operationNames ?? []) {
@@ -19462,11 +19994,11 @@ function inferClusterRelationship(seed, record) {
19462
19994
  var MATCHED_TLS_BINARY_NAMES = ["curl-impersonate-chrome", "curl_chrome"];
19463
19995
  async function executeMatchedTlsTransportRequest(input) {
19464
19996
  const binary = await resolveMatchedTlsBinary();
19465
- const workingDirectory = await promises.mkdtemp(path6__default.default.join(os.tmpdir(), "opensteer-matched-tls-"));
19466
- const headersPath = path6__default.default.join(workingDirectory, "headers.txt");
19467
- const bodyPath = path6__default.default.join(workingDirectory, "body.bin");
19468
- const cookiesPath = path6__default.default.join(workingDirectory, "cookies.txt");
19469
- const requestBodyPath = path6__default.default.join(workingDirectory, "request-body.bin");
19997
+ const workingDirectory = await promises.mkdtemp(path7__default.default.join(os.tmpdir(), "opensteer-matched-tls-"));
19998
+ const headersPath = path7__default.default.join(workingDirectory, "headers.txt");
19999
+ const bodyPath = path7__default.default.join(workingDirectory, "body.bin");
20000
+ const cookiesPath = path7__default.default.join(workingDirectory, "cookies.txt");
20001
+ const requestBodyPath = path7__default.default.join(workingDirectory, "request-body.bin");
19470
20002
  try {
19471
20003
  await promises.writeFile(cookiesPath, toNetscapeCookieJar(input.cookies ?? []), "utf8");
19472
20004
  if (input.request.body !== void 0) {
@@ -19523,10 +20055,10 @@ async function executeMatchedTlsTransportRequest(input) {
19523
20055
  }
19524
20056
  }
19525
20057
  async function resolveMatchedTlsBinary() {
19526
- const pathEntries = (process.env.PATH ?? "").split(path6__default.default.delimiter).filter((entry) => entry.length > 0);
20058
+ const pathEntries = (process.env.PATH ?? "").split(path7__default.default.delimiter).filter((entry) => entry.length > 0);
19527
20059
  for (const directory of pathEntries) {
19528
20060
  for (const name of MATCHED_TLS_BINARY_NAMES) {
19529
- const candidate = path6__default.default.join(directory, name);
20061
+ const candidate = path7__default.default.join(directory, name);
19530
20062
  if (await isExecutable(candidate)) {
19531
20063
  return candidate;
19532
20064
  }
@@ -19534,7 +20066,7 @@ async function resolveMatchedTlsBinary() {
19534
20066
  const files = await readDirSafe(directory);
19535
20067
  const discovered = files.find((file) => file.startsWith("curl_chrome"));
19536
20068
  if (discovered !== void 0) {
19537
- const candidate = path6__default.default.join(directory, discovered);
20069
+ const candidate = path7__default.default.join(directory, discovered);
19538
20070
  if (await isExecutable(candidate)) {
19539
20071
  return candidate;
19540
20072
  }
@@ -19545,7 +20077,7 @@ async function resolveMatchedTlsBinary() {
19545
20077
  );
19546
20078
  }
19547
20079
  async function spawnAndCollect(command, args, signal) {
19548
- return await new Promise((resolve5, reject) => {
20080
+ return await new Promise((resolve4, reject) => {
19549
20081
  const child = child_process.spawn(command, args, {
19550
20082
  stdio: ["ignore", "pipe", "pipe"]
19551
20083
  });
@@ -19578,7 +20110,7 @@ async function spawnAndCollect(command, args, signal) {
19578
20110
  );
19579
20111
  return;
19580
20112
  }
19581
- resolve5({ stdout, stderr });
20113
+ resolve4({ stdout, stderr });
19582
20114
  });
19583
20115
  });
19584
20116
  }
@@ -22240,8 +22772,8 @@ function readString(value) {
22240
22772
  return typeof value === "string" && value.length > 0 ? value : void 0;
22241
22773
  }
22242
22774
  function sleep2(ms, signal) {
22243
- return new Promise((resolve5, reject) => {
22244
- const timeout = setTimeout(resolve5, ms);
22775
+ return new Promise((resolve4, reject) => {
22776
+ const timeout = setTimeout(resolve4, ms);
22245
22777
  const abort = () => {
22246
22778
  clearTimeout(timeout);
22247
22779
  reject(new Error("captcha solve aborted"));
@@ -22338,8 +22870,8 @@ function readString2(value) {
22338
22870
  return typeof value === "string" && value.length > 0 ? value : void 0;
22339
22871
  }
22340
22872
  function sleep3(ms, signal) {
22341
- return new Promise((resolve5, reject) => {
22342
- const timeout = setTimeout(resolve5, ms);
22873
+ return new Promise((resolve4, reject) => {
22874
+ const timeout = setTimeout(resolve4, ms);
22343
22875
  const abort = () => {
22344
22876
  clearTimeout(timeout);
22345
22877
  reject(new Error("captcha solve aborted"));
@@ -22538,6 +23070,8 @@ function diffInteractionTraces(left, right) {
22538
23070
  // ../runtime-core/src/sdk/runtime.ts
22539
23071
  var requireForAuthRecipeHook = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
22540
23072
  var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS = 5e3;
23073
+ var PENDING_OPERATION_EVENT_CAPTURE_LIMIT = 64;
23074
+ var PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS = 1e3;
22541
23075
  var OpensteerSessionRuntime = class {
22542
23076
  workspace;
22543
23077
  rootPath;
@@ -22550,6 +23084,9 @@ var OpensteerSessionRuntime = class {
22550
23084
  registryOverrides;
22551
23085
  cleanupRootOnClose;
22552
23086
  sessionInfoBase;
23087
+ observationConfig;
23088
+ observationSessionId;
23089
+ injectedObservationSink;
22553
23090
  root;
22554
23091
  engine;
22555
23092
  dom;
@@ -22559,6 +23096,9 @@ var OpensteerSessionRuntime = class {
22559
23096
  sessionRef;
22560
23097
  pageRef;
22561
23098
  runId;
23099
+ observations;
23100
+ operationEventStorage = new async_hooks.AsyncLocalStorage();
23101
+ pendingOperationEventCaptures = [];
22562
23102
  cookieJars = /* @__PURE__ */ new Map();
22563
23103
  recipeCache = /* @__PURE__ */ new Map();
22564
23104
  ownsEngine = false;
@@ -22566,7 +23106,7 @@ var OpensteerSessionRuntime = class {
22566
23106
  this.workspace = normalizeNamespace2(options.name);
22567
23107
  this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
22568
23108
  this.root = options.workspace;
22569
- this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6__default.default.resolve(process.cwd(), ".opensteer", "temporary", crypto.randomUUID());
23109
+ this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path7__default.default.resolve(process.cwd(), ".opensteer", "temporary", crypto.randomUUID());
22570
23110
  this.injectedEngine = options.engine;
22571
23111
  this.engineFactory = options.engineFactory;
22572
23112
  this.policy = options.policy ?? defaultPolicy();
@@ -22575,6 +23115,9 @@ var OpensteerSessionRuntime = class {
22575
23115
  this.registryOverrides = options.registryOverrides;
22576
23116
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
22577
23117
  this.sessionInfoBase = options.sessionInfo ?? {};
23118
+ this.observationConfig = normalizeObservabilityConfig(options.observability);
23119
+ this.observationSessionId = options.observationSessionId;
23120
+ this.injectedObservationSink = options.observationSink;
22578
23121
  if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
22579
23122
  throw new Error("OpensteerSessionRuntime requires an engine or engineFactory.");
22580
23123
  }
@@ -22606,6 +23149,20 @@ var OpensteerSessionRuntime = class {
22606
23149
  }
22607
23150
  };
22608
23151
  }
23152
+ async setObservabilityConfig(input) {
23153
+ this.observationConfig = normalizeObservabilityConfig(input);
23154
+ const observationSessionId = this.resolveObservationSessionId();
23155
+ if (observationSessionId === void 0) {
23156
+ return this.observationConfig;
23157
+ }
23158
+ const sink = this.injectedObservationSink ?? (await this.ensureRoot()).observations;
23159
+ this.observations = await sink.openSession({
23160
+ sessionId: observationSessionId,
23161
+ openedAt: Date.now(),
23162
+ config: this.observationConfig
23163
+ });
23164
+ return this.observationConfig;
23165
+ }
22609
23166
  async open(input = {}, options = {}) {
22610
23167
  assertValidSemanticOperationInput("session.open", input);
22611
23168
  if (input.workspace !== void 0 && normalizeNamespace2(input.workspace) !== this.workspace) {
@@ -22704,6 +23261,10 @@ var OpensteerSessionRuntime = class {
22704
23261
  return { pages: [] };
22705
23262
  }
22706
23263
  const startedAt = Date.now();
23264
+ const context = buildRuntimeTraceContext({
23265
+ sessionRef: this.sessionRef,
23266
+ pageRef: this.pageRef
23267
+ });
22707
23268
  try {
22708
23269
  const output = await this.runWithOperationTimeout(
22709
23270
  "page.list",
@@ -22718,19 +23279,18 @@ var OpensteerSessionRuntime = class {
22718
23279
  },
22719
23280
  options
22720
23281
  );
23282
+ const events = await this.drainPendingEngineEvents(context);
22721
23283
  await this.appendTrace({
22722
23284
  operation: "page.list",
22723
23285
  startedAt,
22724
23286
  completedAt: Date.now(),
22725
23287
  outcome: "ok",
23288
+ ...events === void 0 ? {} : { events },
22726
23289
  data: {
22727
23290
  count: output.pages.length,
22728
23291
  ...output.activePageRef === void 0 ? {} : { activePageRef: output.activePageRef }
22729
23292
  },
22730
- context: buildRuntimeTraceContext({
22731
- sessionRef: this.sessionRef,
22732
- pageRef: this.pageRef
22733
- })
23293
+ context
22734
23294
  });
22735
23295
  return output;
22736
23296
  } catch (error) {
@@ -22740,10 +23300,7 @@ var OpensteerSessionRuntime = class {
22740
23300
  completedAt: Date.now(),
22741
23301
  outcome: "error",
22742
23302
  error,
22743
- context: buildRuntimeTraceContext({
22744
- sessionRef: this.sessionRef,
22745
- pageRef: this.pageRef
22746
- })
23303
+ context
22747
23304
  });
22748
23305
  throw error;
22749
23306
  }
@@ -23131,22 +23688,25 @@ var OpensteerSessionRuntime = class {
23131
23688
  },
23132
23689
  options
23133
23690
  );
23691
+ const context = buildRuntimeTraceContext({
23692
+ sessionRef: this.sessionRef,
23693
+ pageRef
23694
+ });
23695
+ const events = await this.drainPendingEngineEvents(context);
23134
23696
  await this.appendTrace({
23135
23697
  operation: "page.snapshot",
23136
23698
  startedAt,
23137
23699
  completedAt: Date.now(),
23138
23700
  outcome: "ok",
23139
23701
  artifacts,
23702
+ ...events === void 0 ? {} : { events },
23140
23703
  data: {
23141
23704
  mode,
23142
23705
  url: output.url,
23143
23706
  title: output.title,
23144
23707
  counterCount: output.counters.length
23145
23708
  },
23146
- context: buildRuntimeTraceContext({
23147
- sessionRef: this.sessionRef,
23148
- pageRef
23149
- })
23709
+ context
23150
23710
  });
23151
23711
  return output;
23152
23712
  } catch (error) {
@@ -26571,11 +27131,13 @@ var OpensteerSessionRuntime = class {
26571
27131
  }
26572
27132
  );
26573
27133
  const output = toOpensteerActionResult(executed.result, preparedTarget.persistedDescription);
27134
+ const actionEvents = "events" in executed.result ? executed.result.events : void 0;
26574
27135
  await this.appendTrace({
26575
27136
  operation,
26576
27137
  startedAt,
26577
27138
  completedAt: Date.now(),
26578
27139
  outcome: "ok",
27140
+ ...actionEvents === void 0 ? {} : { events: actionEvents },
26579
27141
  data: {
26580
27142
  target: output.target,
26581
27143
  ...output.point === void 0 ? {} : { point: output.point },
@@ -28325,7 +28887,7 @@ var OpensteerSessionRuntime = class {
28325
28887
  }
28326
28888
  async executeAuthRecipeHook(step, variables) {
28327
28889
  const resolved = requireForAuthRecipeHook.resolve(step.hook.specifier, {
28328
- paths: [path6__default.default.dirname(this.rootPath)]
28890
+ paths: [path7__default.default.dirname(this.rootPath)]
28329
28891
  });
28330
28892
  const module = await import(url.pathToFileURL(resolved).href);
28331
28893
  const handler = module[step.hook.export];
@@ -28697,14 +29259,18 @@ var OpensteerSessionRuntime = class {
28697
29259
  return this.engine;
28698
29260
  }
28699
29261
  if (this.injectedEngine) {
28700
- this.engine = this.injectedEngine;
29262
+ this.engine = this.wrapEngineWithObservationCapture(
29263
+ this.injectedEngine
29264
+ );
28701
29265
  this.ownsEngine = false;
28702
29266
  return this.engine;
28703
29267
  }
28704
29268
  if (this.engineFactory === void 0) {
28705
29269
  throw new Error("Opensteer engine factory is not initialized");
28706
29270
  }
28707
- this.engine = await this.engineFactory(overrides);
29271
+ this.engine = this.wrapEngineWithObservationCapture(
29272
+ await this.engineFactory(overrides)
29273
+ );
28708
29274
  this.ownsEngine = true;
28709
29275
  return this.engine;
28710
29276
  }
@@ -28904,6 +29470,15 @@ var OpensteerSessionRuntime = class {
28904
29470
  return;
28905
29471
  }
28906
29472
  const root = await this.ensureRoot();
29473
+ const capturedStepEvents = input.events ?? this.consumePendingOperationEventCapture(
29474
+ input.operation,
29475
+ input.startedAt,
29476
+ input.completedAt
29477
+ );
29478
+ const drainedStepEvents = input.events === void 0 ? await this.drainPendingEngineEvents(input.context) : void 0;
29479
+ const stepEvents = mergeObservedStepEvents(capturedStepEvents, drainedStepEvents);
29480
+ const normalizedData = input.data === void 0 ? void 0 : toCanonicalJsonValue(input.data);
29481
+ const normalizedError = input.error === void 0 ? void 0 : normalizeOpensteerError(input.error);
28907
29482
  const artifacts = input.artifacts === void 0 ? void 0 : await Promise.all(
28908
29483
  input.artifacts.manifests.map(async (manifest) => {
28909
29484
  const reference = await root.artifacts.toProtocolArtifactReference(
@@ -28916,19 +29491,56 @@ var OpensteerSessionRuntime = class {
28916
29491
  return reference;
28917
29492
  })
28918
29493
  );
28919
- await root.traces.append(runId, {
29494
+ const traceEntry = await root.traces.append(runId, {
28920
29495
  operation: input.operation,
28921
29496
  outcome: input.outcome,
28922
29497
  startedAt: input.startedAt,
28923
29498
  completedAt: input.completedAt,
28924
29499
  ...input.context === void 0 ? {} : { context: input.context },
28925
- ...input.events === void 0 ? {} : { events: input.events },
29500
+ ...stepEvents === void 0 ? {} : { events: stepEvents },
28926
29501
  ...artifacts === void 0 ? {} : { artifacts },
28927
- ...input.data === void 0 ? {} : { data: toCanonicalJsonValue(input.data) },
28928
- ...input.error === void 0 ? {} : {
28929
- error: normalizeOpensteerError(input.error)
29502
+ ...normalizedData === void 0 ? {} : { data: normalizedData },
29503
+ ...normalizedError === void 0 ? {} : {
29504
+ error: normalizedError
28930
29505
  }
28931
29506
  });
29507
+ const observationSession = await this.ensureObservationSession().catch(() => void 0);
29508
+ if (observationSession === void 0 || this.observationConfig.profile === "off") {
29509
+ return;
29510
+ }
29511
+ const observationArtifactIds = input.artifacts === void 0 ? void 0 : (await Promise.allSettled(
29512
+ input.artifacts.manifests.map(async (manifest) => {
29513
+ const artifact = await observationSession.writeArtifact({
29514
+ artifactId: manifest.artifactId,
29515
+ kind: observationArtifactKindFromManifest(manifest.kind),
29516
+ createdAt: manifest.createdAt,
29517
+ context: manifest.scope,
29518
+ mediaType: manifest.mediaType,
29519
+ byteLength: manifest.byteLength,
29520
+ sha256: manifest.sha256,
29521
+ opensteerArtifactId: manifest.artifactId,
29522
+ storageKey: manifestToExternalBinaryLocation(root.rootPath, manifest).uri
29523
+ });
29524
+ return artifact.artifactId;
29525
+ })
29526
+ )).flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
29527
+ const observationEvents = buildObservationEventsFromTrace({
29528
+ traceId: traceEntry.traceId,
29529
+ stepId: traceEntry.stepId,
29530
+ operation: input.operation,
29531
+ outcome: input.outcome,
29532
+ startedAt: input.startedAt,
29533
+ completedAt: input.completedAt,
29534
+ ...input.context === void 0 ? {} : { context: input.context },
29535
+ ...stepEvents === void 0 ? {} : { events: stepEvents },
29536
+ ...normalizedData === void 0 ? {} : { data: normalizedData },
29537
+ ...normalizedError === void 0 ? {} : { error: normalizedError },
29538
+ ...observationArtifactIds === void 0 ? {} : { artifactIds: observationArtifactIds },
29539
+ profile: this.observationConfig.profile
29540
+ });
29541
+ if (observationEvents.length > 0) {
29542
+ await observationSession.appendBatch(observationEvents).catch(() => void 0);
29543
+ }
28932
29544
  }
28933
29545
  async cleanupSessionResources(engine, pageRef, sessionRef) {
28934
29546
  if (pageRef !== void 0) {
@@ -28940,6 +29552,7 @@ var OpensteerSessionRuntime = class {
28940
29552
  }
28941
29553
  async resetRuntimeState(options) {
28942
29554
  const engine = this.engine;
29555
+ const observations = this.observations;
28943
29556
  this.networkHistory.clear();
28944
29557
  this.sessionRef = void 0;
28945
29558
  this.pageRef = void 0;
@@ -28948,20 +29561,140 @@ var OpensteerSessionRuntime = class {
28948
29561
  this.computer = void 0;
28949
29562
  this.extractionDescriptors = void 0;
28950
29563
  this.engine = void 0;
29564
+ this.observations = void 0;
29565
+ this.pendingOperationEventCaptures.length = 0;
29566
+ await observations?.close("runtime_reset").catch(() => void 0);
28951
29567
  if (options.disposeEngine && this.ownsEngine && engine?.dispose) {
28952
29568
  await engine.dispose();
28953
29569
  }
28954
29570
  this.ownsEngine = false;
28955
29571
  }
29572
+ async ensureObservationSession() {
29573
+ if (this.observationConfig.profile === "off") {
29574
+ return void 0;
29575
+ }
29576
+ if (this.observations !== void 0) {
29577
+ return this.observations;
29578
+ }
29579
+ const observationSessionId = this.resolveObservationSessionId();
29580
+ if (observationSessionId === void 0) {
29581
+ return void 0;
29582
+ }
29583
+ const sink = this.injectedObservationSink ?? (await this.ensureRoot()).observations;
29584
+ this.observations = await sink.openSession({
29585
+ sessionId: observationSessionId,
29586
+ openedAt: Date.now(),
29587
+ config: this.observationConfig
29588
+ });
29589
+ return this.observations;
29590
+ }
29591
+ resolveObservationSessionId() {
29592
+ return this.observationSessionId ?? this.sessionRef;
29593
+ }
28956
29594
  runWithOperationTimeout(operation, callback, options = {}) {
28957
- return runWithPolicyTimeout(
28958
- this.policy.timeout,
28959
- {
28960
- operation,
28961
- ...options.signal === void 0 ? {} : { signal: options.signal }
28962
- },
28963
- callback
28964
- );
29595
+ const existingCollector = this.operationEventStorage.getStore();
29596
+ if (existingCollector !== void 0) {
29597
+ return runWithPolicyTimeout(
29598
+ this.policy.timeout,
29599
+ {
29600
+ operation,
29601
+ ...options.signal === void 0 ? {} : { signal: options.signal }
29602
+ },
29603
+ callback
29604
+ );
29605
+ }
29606
+ const collector = [];
29607
+ const startedAt = Date.now();
29608
+ return this.operationEventStorage.run(collector, async () => {
29609
+ try {
29610
+ return await runWithPolicyTimeout(
29611
+ this.policy.timeout,
29612
+ {
29613
+ operation,
29614
+ ...options.signal === void 0 ? {} : { signal: options.signal }
29615
+ },
29616
+ callback
29617
+ );
29618
+ } finally {
29619
+ this.recordPendingOperationEventCapture({
29620
+ operation,
29621
+ startedAt,
29622
+ completedAt: Date.now(),
29623
+ events: collector
29624
+ });
29625
+ }
29626
+ });
29627
+ }
29628
+ wrapEngineWithObservationCapture(engine) {
29629
+ return new Proxy(engine, {
29630
+ get: (target, property, receiver) => {
29631
+ const value = Reflect.get(target, property, receiver);
29632
+ if (typeof value !== "function") {
29633
+ return value;
29634
+ }
29635
+ return (...args) => {
29636
+ const result = Reflect.apply(value, target, args);
29637
+ if (!(result instanceof Promise)) {
29638
+ return result;
29639
+ }
29640
+ return result.then((resolved) => {
29641
+ this.captureObservedStepEvents(resolved);
29642
+ return resolved;
29643
+ });
29644
+ };
29645
+ }
29646
+ });
29647
+ }
29648
+ captureObservedStepEvents(value) {
29649
+ const collector = this.operationEventStorage.getStore();
29650
+ if (collector === void 0) {
29651
+ return;
29652
+ }
29653
+ const events = readStepResultEvents(value);
29654
+ if (events === void 0 || events.length === 0) {
29655
+ return;
29656
+ }
29657
+ collector.push(...events);
29658
+ }
29659
+ recordPendingOperationEventCapture(capture) {
29660
+ if (capture.events.length === 0) {
29661
+ return;
29662
+ }
29663
+ this.pendingOperationEventCaptures.push({
29664
+ ...capture,
29665
+ events: [...capture.events]
29666
+ });
29667
+ if (this.pendingOperationEventCaptures.length > PENDING_OPERATION_EVENT_CAPTURE_LIMIT) {
29668
+ this.pendingOperationEventCaptures.splice(
29669
+ 0,
29670
+ this.pendingOperationEventCaptures.length - PENDING_OPERATION_EVENT_CAPTURE_LIMIT
29671
+ );
29672
+ }
29673
+ }
29674
+ consumePendingOperationEventCapture(operation, startedAt, completedAt) {
29675
+ for (let index = this.pendingOperationEventCaptures.length - 1; index >= 0; index -= 1) {
29676
+ const capture = this.pendingOperationEventCaptures[index];
29677
+ if (capture === void 0) {
29678
+ continue;
29679
+ }
29680
+ if (capture.operation !== operation) {
29681
+ continue;
29682
+ }
29683
+ if (capture.startedAt < startedAt - PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS || capture.completedAt > completedAt + PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS) {
29684
+ continue;
29685
+ }
29686
+ this.pendingOperationEventCaptures.splice(index, 1);
29687
+ return capture.events;
29688
+ }
29689
+ return void 0;
29690
+ }
29691
+ async drainPendingEngineEvents(context) {
29692
+ const pageRef = context?.pageRef ?? this.pageRef;
29693
+ if (pageRef === void 0 || this.engine === void 0) {
29694
+ return void 0;
29695
+ }
29696
+ const events = await this.engine.drainEvents({ pageRef }).catch(() => []);
29697
+ return events.length > 0 ? events : void 0;
28965
29698
  }
28966
29699
  async navigatePage(input, timeout) {
28967
29700
  const remainingMs = timeout.remainingMs();
@@ -28997,6 +29730,34 @@ function buildRuntimeTraceContext(input) {
28997
29730
  function buildArtifactScope(input) {
28998
29731
  return buildRuntimeTraceContext(input);
28999
29732
  }
29733
+ function readStepResultEvents(value) {
29734
+ if (value === null || typeof value !== "object") {
29735
+ return void 0;
29736
+ }
29737
+ if (!("events" in value)) {
29738
+ return void 0;
29739
+ }
29740
+ const events = value.events;
29741
+ return Array.isArray(events) ? events : void 0;
29742
+ }
29743
+ function mergeObservedStepEvents(primary, secondary) {
29744
+ if (primary === void 0 || primary.length === 0) {
29745
+ return secondary === void 0 || secondary.length === 0 ? void 0 : secondary;
29746
+ }
29747
+ if (secondary === void 0 || secondary.length === 0) {
29748
+ return primary;
29749
+ }
29750
+ const merged = /* @__PURE__ */ new Map();
29751
+ for (const event of primary) {
29752
+ merged.set(event.eventId, event);
29753
+ }
29754
+ for (const event of secondary) {
29755
+ merged.set(event.eventId, event);
29756
+ }
29757
+ return [...merged.values()].sort(
29758
+ (left, right) => (left.timestamp ?? 0) - (right.timestamp ?? 0)
29759
+ );
29760
+ }
29000
29761
  function selectLiveQueryPageRef(input, currentPageRef) {
29001
29762
  if (input.pageRef !== void 0) {
29002
29763
  return input.pageRef;
@@ -29959,12 +30720,12 @@ function extractReverseRuntimeValue(value, pointer) {
29959
30720
  }
29960
30721
  return readDotPath(value, pointer);
29961
30722
  }
29962
- function readDotPath(value, path13) {
29963
- if (path13.length === 0) {
30723
+ function readDotPath(value, path15) {
30724
+ if (path15.length === 0) {
29964
30725
  return value;
29965
30726
  }
29966
30727
  let current = value;
29967
- for (const segment of path13.split(".").filter((entry) => entry.length > 0)) {
30728
+ for (const segment of path15.split(".").filter((entry) => entry.length > 0)) {
29968
30729
  if (current === null || current === void 0) {
29969
30730
  return void 0;
29970
30731
  }
@@ -30333,7 +31094,7 @@ function normalizeRuntimeErrorMessage(error) {
30333
31094
  return error instanceof Error ? error.message : String(error);
30334
31095
  }
30335
31096
  function runtimeDelay(ms) {
30336
- return new Promise((resolve5) => setTimeout(resolve5, ms));
31097
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
30337
31098
  }
30338
31099
  function applyBrowserCookiesToTransportRequest(request, cookies) {
30339
31100
  if (cookies.length === 0) {
@@ -30437,7 +31198,7 @@ function parseSetCookieHeader(value, requestUrl) {
30437
31198
  }
30438
31199
  const url = new URL(requestUrl);
30439
31200
  let domain = url.hostname;
30440
- let path13 = defaultCookiePath(url.pathname);
31201
+ let path15 = defaultCookiePath(url.pathname);
30441
31202
  let secure = url.protocol === "https:";
30442
31203
  let expiresAt;
30443
31204
  const cookieValue = rawValueParts.join("=").trim();
@@ -30450,7 +31211,7 @@ function parseSetCookieHeader(value, requestUrl) {
30450
31211
  continue;
30451
31212
  }
30452
31213
  if (key === "path" && attributeValue.length > 0) {
30453
- path13 = attributeValue;
31214
+ path15 = attributeValue;
30454
31215
  continue;
30455
31216
  }
30456
31217
  if (key === "secure") {
@@ -30476,7 +31237,7 @@ function parseSetCookieHeader(value, requestUrl) {
30476
31237
  name,
30477
31238
  value: cookieValue,
30478
31239
  domain,
30479
- path: path13,
31240
+ path: path15,
30480
31241
  secure,
30481
31242
  ...expiresAt === void 0 ? {} : { expiresAt }
30482
31243
  }
@@ -31428,7 +32189,7 @@ async function pollUntilResult(timeout, producer) {
31428
32189
  if (produced !== void 0) {
31429
32190
  return produced;
31430
32191
  }
31431
- await new Promise((resolve5) => setTimeout(resolve5, 100));
32192
+ await new Promise((resolve4) => setTimeout(resolve4, 100));
31432
32193
  }
31433
32194
  }
31434
32195
  async function getMainFrame(engine, pageRef) {
@@ -31486,6 +32247,133 @@ function toOpensteerResolvedTarget2(target) {
31486
32247
  function normalizeOpensteerError(error) {
31487
32248
  return normalizeThrownOpensteerError(error, "Unknown Opensteer runtime failure");
31488
32249
  }
32250
+ function observationArtifactKindFromManifest(kind) {
32251
+ switch (kind) {
32252
+ case "screenshot":
32253
+ return "screenshot";
32254
+ case "dom-snapshot":
32255
+ return "dom-snapshot";
32256
+ case "html-snapshot":
32257
+ return "html-snapshot";
32258
+ default:
32259
+ return "other";
32260
+ }
32261
+ }
32262
+ function buildObservationEventsFromTrace(input) {
32263
+ const context = normalizeObservationContext(input.context);
32264
+ const baseCorrelationId = input.traceId;
32265
+ const startedEvent = {
32266
+ kind: input.operation === "session.open" || input.operation === "session.close" ? "session" : "operation",
32267
+ phase: "started",
32268
+ createdAt: input.startedAt,
32269
+ correlationId: baseCorrelationId,
32270
+ spanId: input.stepId,
32271
+ ...context === void 0 ? {} : { context },
32272
+ data: {
32273
+ operation: input.operation
32274
+ }
32275
+ };
32276
+ const stepEvents = (input.events ?? []).filter((event) => shouldCaptureObservationStepEvent(event, input.profile)).map((event) => {
32277
+ const eventContext = buildObservationContextFromEvent(event);
32278
+ return {
32279
+ kind: observationKindForStepEvent(event),
32280
+ phase: "occurred",
32281
+ createdAt: event.timestamp,
32282
+ correlationId: baseCorrelationId,
32283
+ parentSpanId: input.stepId,
32284
+ ...eventContext === void 0 ? {} : { context: eventContext },
32285
+ data: stripObservationStepEvent(event),
32286
+ ...event.kind === "page-error" ? {
32287
+ error: {
32288
+ message: event.message,
32289
+ ...event.stack === void 0 ? {} : { details: { stack: event.stack } }
32290
+ }
32291
+ } : {}
32292
+ };
32293
+ });
32294
+ const completedEvent = {
32295
+ kind: input.operation === "session.open" || input.operation === "session.close" ? "session" : "operation",
32296
+ phase: input.outcome === "ok" ? "completed" : "failed",
32297
+ createdAt: input.completedAt,
32298
+ correlationId: baseCorrelationId,
32299
+ spanId: input.stepId,
32300
+ ...context === void 0 ? {} : { context },
32301
+ data: {
32302
+ operation: input.operation,
32303
+ startedAt: input.startedAt,
32304
+ completedAt: input.completedAt,
32305
+ durationMs: input.completedAt - input.startedAt,
32306
+ ...input.data === void 0 ? {} : { output: input.data }
32307
+ },
32308
+ ...input.error === void 0 ? {} : {
32309
+ error: {
32310
+ ...input.error.code === void 0 ? {} : { code: input.error.code },
32311
+ message: input.error.message,
32312
+ ...input.error.retriable === void 0 ? {} : { retriable: input.error.retriable },
32313
+ ...input.error.details === void 0 ? {} : { details: toCanonicalJsonValue(input.error.details) }
32314
+ }
32315
+ },
32316
+ ...input.artifactIds === void 0 || input.artifactIds.length === 0 ? {} : { artifactIds: input.artifactIds }
32317
+ };
32318
+ return [startedEvent, ...stepEvents, completedEvent];
32319
+ }
32320
+ function buildObservationContextFromEvent(event) {
32321
+ return normalizeObservationContext({
32322
+ sessionRef: event.sessionRef,
32323
+ ...event.pageRef === void 0 ? {} : { pageRef: event.pageRef },
32324
+ ...event.frameRef === void 0 ? {} : { frameRef: event.frameRef },
32325
+ ...event.documentRef === void 0 ? {} : { documentRef: event.documentRef },
32326
+ ...event.documentEpoch === void 0 ? {} : { documentEpoch: event.documentEpoch }
32327
+ });
32328
+ }
32329
+ function shouldCaptureObservationStepEvent(event, profile) {
32330
+ if (profile === "diagnostic") {
32331
+ return true;
32332
+ }
32333
+ switch (event.kind) {
32334
+ case "page-created":
32335
+ case "popup-opened":
32336
+ case "page-closed":
32337
+ case "page-error":
32338
+ return true;
32339
+ case "console":
32340
+ return event.level === "warn" || event.level === "error";
32341
+ default:
32342
+ return false;
32343
+ }
32344
+ }
32345
+ function observationKindForStepEvent(event) {
32346
+ switch (event.kind) {
32347
+ case "console":
32348
+ return "console";
32349
+ case "page-error":
32350
+ return "error";
32351
+ case "paused":
32352
+ case "resumed":
32353
+ case "frozen":
32354
+ return "runtime";
32355
+ default:
32356
+ return "page";
32357
+ }
32358
+ }
32359
+ function stripObservationStepEvent(event) {
32360
+ const {
32361
+ eventId: _eventId,
32362
+ kind,
32363
+ timestamp,
32364
+ sessionRef: _sessionRef,
32365
+ pageRef: _pageRef,
32366
+ frameRef: _frameRef,
32367
+ documentRef: _documentRef,
32368
+ documentEpoch: _documentEpoch,
32369
+ ...rest
32370
+ } = event;
32371
+ return toCanonicalJsonValue({
32372
+ eventKind: kind,
32373
+ timestamp,
32374
+ ...rest
32375
+ });
32376
+ }
31489
32377
  function buildMutationCaptureTraceData(diagnostics) {
31490
32378
  if (diagnostics?.finalizeError === void 0) {
31491
32379
  return {};
@@ -31535,8 +32423,8 @@ function screenshotMediaType(format2) {
31535
32423
  var OpensteerRuntime = class extends OpensteerSessionRuntime {
31536
32424
  constructor(options = {}) {
31537
32425
  const publicWorkspace = normalizeWorkspace2(options.workspace);
31538
- const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path6__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : resolveFilesystemWorkspacePath({
31539
- rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
32426
+ const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path7__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : resolveFilesystemWorkspacePath({
32427
+ rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
31540
32428
  workspace: publicWorkspace
31541
32429
  }));
31542
32430
  const cleanupRootOnClose = options.cleanupRootOnClose ?? publicWorkspace === void 0;
@@ -31561,14 +32449,17 @@ var OpensteerRuntime = class extends OpensteerSessionRuntime {
31561
32449
  ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31562
32450
  ...options.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: options.extractionDescriptorStore },
31563
32451
  ...options.registryOverrides === void 0 ? {} : { registryOverrides: options.registryOverrides },
31564
- cleanupRootOnClose
32452
+ cleanupRootOnClose,
32453
+ ...options.observability === void 0 ? {} : { observability: options.observability },
32454
+ ...options.observationSessionId === void 0 ? {} : { observationSessionId: options.observationSessionId },
32455
+ ...options.observationSink === void 0 ? {} : { observationSink: options.observationSink }
31565
32456
  })
31566
32457
  );
31567
32458
  }
31568
32459
  };
31569
32460
  var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31570
32461
  constructor(options) {
31571
- const rootPath = options.rootPath ?? path6__default.default.resolve(options.rootDir ?? process.cwd());
32462
+ const rootPath = options.rootPath ?? path7__default.default.resolve(options.rootDir ?? process.cwd());
31572
32463
  const cleanupRootOnClose = options.cleanupRootOnClose ?? false;
31573
32464
  const engineName = options.engineName ?? DEFAULT_OPENSTEER_ENGINE;
31574
32465
  assertSupportedEngineOptions({
@@ -31590,7 +32481,10 @@ var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31590
32481
  ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31591
32482
  ...options.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: options.extractionDescriptorStore },
31592
32483
  ...options.registryOverrides === void 0 ? {} : { registryOverrides: options.registryOverrides },
31593
- cleanupRootOnClose
32484
+ cleanupRootOnClose,
32485
+ ...options.observability === void 0 ? {} : { observability: options.observability },
32486
+ ...options.observationSessionId === void 0 ? {} : { observationSessionId: options.observationSessionId },
32487
+ ...options.observationSink === void 0 ? {} : { observationSink: options.observationSink }
31594
32488
  })
31595
32489
  );
31596
32490
  }
@@ -31616,6 +32510,9 @@ function buildSharedRuntimeOptions(input) {
31616
32510
  ...input.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: input.extractionDescriptorStore },
31617
32511
  ...input.registryOverrides === void 0 ? {} : { registryOverrides: input.registryOverrides },
31618
32512
  cleanupRootOnClose: input.cleanupRootOnClose,
32513
+ ...input.observability === void 0 ? {} : { observability: input.observability },
32514
+ ...input.observationSessionId === void 0 ? {} : { observationSessionId: input.observationSessionId },
32515
+ ...input.observationSink === void 0 ? {} : { observationSink: input.observationSink },
31619
32516
  sessionInfo: {
31620
32517
  provider: {
31621
32518
  mode: "local",
@@ -31678,345 +32575,267 @@ function resolveOpensteerProvider(input = {}) {
31678
32575
  };
31679
32576
  }
31680
32577
  var execFile2 = util.promisify(child_process.execFile);
31681
- var DEFAULT_CAPTURE_TIMEOUT_MS = 3e4;
31682
- var DEFAULT_STOP_TIMEOUT_MS = 15e3;
31683
- var DEVTOOLS_POLL_INTERVAL_MS2 = 50;
31684
- var PROCESS_LIST_MAX_BUFFER_BYTES3 = 16 * 1024 * 1024;
31685
- async function resolveCookieCaptureStrategy(input = {}) {
31686
- const timeoutMs = input.timeoutMs ?? DEFAULT_CAPTURE_TIMEOUT_MS;
31687
- if (input.attachEndpoint !== void 0) {
31688
- if (input.strategy !== void 0 && input.strategy !== "attach") {
31689
- throw new Error(
31690
- `Strategy "${input.strategy}" is incompatible with an explicit attach endpoint.`
31691
- );
31692
- }
31693
- return {
31694
- strategy: "attach",
31695
- attachEndpoint: input.attachEndpoint,
31696
- ...input.profileDirectory === void 0 ? {} : { profileDirectory: input.profileDirectory },
31697
- timeoutMs
31698
- };
31699
- }
32578
+ var NODE_SQLITE_SPECIFIER2 = `node:${"sqlite"}`;
32579
+ var CHROME_EPOCH_OFFSET = 11644473600000000n;
32580
+ var CHROME_HMAC_PREFIX_LENGTH = 32;
32581
+ async function readBrowserCookies(input = {}) {
31700
32582
  const brand2 = resolveRequestedBrand(input);
31701
- const executablePath = resolveBrandExecutablePath(brand2, input.executablePath);
31702
32583
  const userDataDir = resolveBrandUserDataDir(brand2, input.userDataDir);
31703
- const profileDirectory = input.profileDirectory;
31704
- const attachEndpoint = await resolveReachableAttachEndpoint(userDataDir, timeoutMs);
31705
- const runningProcess = findBrandProcess(brand2);
31706
- const autoStrategy = attachEndpoint !== void 0 ? "attach" : runningProcess !== null ? "managed-relaunch" : "headless";
31707
- const strategy = input.strategy ?? autoStrategy;
31708
- validateRequestedStrategy({
31709
- strategy,
31710
- brand: brand2,
31711
- ...attachEndpoint === void 0 ? {} : { attachEndpoint },
31712
- ...runningProcess?.pid === void 0 ? {} : { runningPid: runningProcess.pid }
31713
- });
31714
- return {
31715
- strategy,
31716
- brandId: brand2.id,
31717
- brandDisplayName: brand2.displayName,
31718
- executablePath,
31719
- userDataDir,
31720
- ...profileDirectory === void 0 ? {} : { profileDirectory },
31721
- ...attachEndpoint === void 0 ? {} : { attachEndpoint },
31722
- ...runningProcess === null ? {} : { runningPid: runningProcess.pid },
31723
- timeoutMs
31724
- };
31725
- }
31726
- async function acquireCdpEndpoint(resolved) {
31727
- if (resolved.strategy === "attach") {
31728
- if (!resolved.attachEndpoint) {
31729
- throw new Error("Attach capture requires a debuggable browser endpoint.");
31730
- }
31731
- const inspected = await inspectCdpEndpoint({
31732
- endpoint: resolved.attachEndpoint,
31733
- timeoutMs: Math.min(2e3, resolved.timeoutMs)
31734
- });
31735
- return {
31736
- strategy: "attach",
31737
- cdpEndpoint: inspected.endpoint,
31738
- ...resolved.brandId === void 0 ? {} : { brandId: resolved.brandId },
31739
- ...resolved.brandDisplayName === void 0 ? {} : { brandDisplayName: resolved.brandDisplayName },
31740
- ...resolved.userDataDir === void 0 ? {} : { userDataDir: resolved.userDataDir },
31741
- ...resolved.profileDirectory === void 0 ? {} : { profileDirectory: resolved.profileDirectory },
31742
- cleanup: async () => void 0
31743
- };
31744
- }
31745
- if (!resolved.brandId || !resolved.brandDisplayName || !resolved.executablePath || !resolved.userDataDir) {
32584
+ const profileDirectory = input.profileDirectory ?? "Default";
32585
+ const cookiesPath = path7.join(userDataDir, profileDirectory, "Cookies");
32586
+ if (!fs.existsSync(cookiesPath)) {
31746
32587
  throw new Error(
31747
- "Headless cookie capture requires a resolved browser brand, executable, and user-data-dir."
31748
- );
31749
- }
31750
- const userDataDir = resolved.userDataDir;
31751
- if (resolved.strategy === "managed-relaunch") {
31752
- if (resolved.runningPid === void 0) {
31753
- throw new Error("Managed relaunch requires a running browser process.");
31754
- }
31755
- await gracefullyStopBrowser(
31756
- getBrowserBrand(resolved.brandId),
31757
- resolved.runningPid,
31758
- resolved.timeoutMs
32588
+ `Cookies database not found at "${cookiesPath}". Verify the browser brand, user-data-dir, and profile-directory are correct.`
31759
32589
  );
31760
32590
  }
31761
- await clearChromeSingletonEntries(userDataDir);
31762
- try {
31763
- const capture = await launchCaptureChrome({
31764
- brandDisplayName: resolved.brandDisplayName,
31765
- executablePath: resolved.executablePath,
31766
- userDataDir,
31767
- ...resolved.profileDirectory === void 0 ? {} : { profileDirectory: resolved.profileDirectory },
31768
- timeoutMs: resolved.timeoutMs
31769
- });
31770
- return {
31771
- strategy: resolved.strategy,
31772
- cdpEndpoint: capture.endpoint,
31773
- brandId: resolved.brandId,
31774
- brandDisplayName: resolved.brandDisplayName,
31775
- userDataDir: resolved.userDataDir,
31776
- ...resolved.profileDirectory === void 0 ? {} : { profileDirectory: resolved.profileDirectory },
31777
- cleanup: async () => {
31778
- await capture.kill().catch(() => void 0);
31779
- await clearChromeSingletonEntries(userDataDir).catch(() => void 0);
31780
- }
31781
- };
31782
- } catch (error) {
31783
- await clearChromeSingletonEntries(userDataDir).catch(() => void 0);
31784
- throw error;
31785
- }
31786
- }
31787
- async function gracefullyStopBrowser(brand2, pid, timeoutMs = DEFAULT_STOP_TIMEOUT_MS) {
31788
- if (pid <= 0) {
31789
- return;
31790
- }
31791
- const platformConfig = resolveBrandPlatformConfig(brand2);
31792
- if (process.platform === "darwin" && platformConfig?.bundleId) {
31793
- await execFile2(
31794
- "osascript",
31795
- ["-e", `tell application id "${platformConfig.bundleId}" to quit`],
31796
- {
31797
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES3
31798
- }
31799
- ).catch(() => void 0);
31800
- } else if (process.platform === "win32") {
31801
- await execFile2("taskkill", ["/PID", String(pid)], {
31802
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES3
31803
- }).catch(() => void 0);
31804
- } else {
31805
- try {
31806
- process.kill(pid, "SIGTERM");
31807
- } catch {
31808
- }
31809
- }
31810
- if (await waitForProcessExit2(pid, timeoutMs)) {
31811
- return;
31812
- }
31813
- if (process.platform === "win32") {
31814
- await execFile2("taskkill", ["/F", "/PID", String(pid)], {
31815
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES3
31816
- }).catch(() => void 0);
31817
- } else {
31818
- try {
31819
- process.kill(pid, "SIGKILL");
31820
- } catch {
31821
- }
31822
- }
31823
- await waitForProcessExit2(pid, Math.min(5e3, timeoutMs));
31824
- }
31825
- async function launchCaptureChrome(input) {
31826
- const stderrLines = [];
31827
- const child = child_process.spawn(input.executablePath, buildCaptureChromeArgs(input), {
31828
- detached: process.platform !== "win32",
31829
- stdio: ["ignore", "ignore", "pipe"]
31830
- });
31831
- child.unref();
31832
- child.stderr?.setEncoding("utf8");
31833
- child.stderr?.on("data", (chunk) => {
31834
- stderrLines.push(String(chunk));
31835
- });
32591
+ const tempDir = await promises.mkdtemp(path7.join(os.tmpdir(), "opensteer-cookies-"));
31836
32592
  try {
31837
- const endpoint = await waitForCaptureEndpoint({
31838
- brandDisplayName: input.brandDisplayName,
31839
- child,
31840
- stderrLines,
31841
- timeoutMs: input.timeoutMs,
31842
- userDataDir: input.userDataDir
31843
- });
32593
+ await copyCookiesDatabase(cookiesPath, tempDir);
32594
+ const decryptionKey = await resolveDecryptionKey(brand2.id, userDataDir);
32595
+ const rows = queryAllCookies(path7.join(tempDir, "Cookies"));
32596
+ const cookies = decryptCookieRows(rows, decryptionKey);
31844
32597
  return {
31845
- endpoint,
31846
- kill: async () => {
31847
- await terminateChild(child);
31848
- }
32598
+ cookies,
32599
+ brandId: brand2.id,
32600
+ brandDisplayName: brand2.displayName,
32601
+ userDataDir,
32602
+ profileDirectory
31849
32603
  };
31850
- } catch (error) {
31851
- await terminateChild(child).catch(() => void 0);
31852
- throw error;
32604
+ } finally {
32605
+ await promises.rm(tempDir, { recursive: true, force: true }).catch(() => void 0);
31853
32606
  }
31854
32607
  }
31855
- function relaunchBrowserNormally(executablePath) {
31856
- const child = child_process.spawn(executablePath, [], {
31857
- detached: true,
31858
- stdio: "ignore"
31859
- });
31860
- child.unref();
31861
- }
31862
32608
  function resolveRequestedBrand(input) {
31863
32609
  if (input.brandId !== void 0) {
31864
32610
  return getBrowserBrand(input.brandId);
31865
32611
  }
31866
- if (input.userDataDir !== void 0) {
31867
- const inferred = inferBrandFromUserDataDir(input.userDataDir);
31868
- if (!inferred) {
31869
- throw new Error(
31870
- `Could not infer a browser brand from user-data-dir "${input.userDataDir}". Pass --browser explicitly.`
31871
- );
31872
- }
31873
- return inferred;
31874
- }
31875
- if (input.executablePath !== void 0) {
31876
- const inferred = inferBrandFromExecutablePath(input.executablePath);
31877
- if (!inferred) {
31878
- throw new Error(
31879
- `Could not infer a browser brand from executable path "${input.executablePath}". Pass --browser explicitly.`
31880
- );
31881
- }
31882
- return inferred;
31883
- }
31884
32612
  const installed = detectInstalledBrowserBrands()[0];
31885
32613
  if (!installed) {
31886
32614
  throw new Error(
31887
- "No Chromium browser found. Install a supported browser or pass --browser explicitly."
32615
+ "No Chromium browser found. Install a supported browser or pass brandId explicitly."
31888
32616
  );
31889
32617
  }
31890
32618
  return installed.brand;
31891
32619
  }
31892
- async function resolveReachableAttachEndpoint(userDataDir, timeoutMs) {
31893
- const activePort = readDevToolsActivePort(userDataDir);
31894
- if (!activePort) {
31895
- return void 0;
32620
+ async function copyCookiesDatabase(cookiesPath, destDir) {
32621
+ await promises.copyFile(cookiesPath, path7.join(destDir, "Cookies"));
32622
+ for (const suffix of ["-wal", "-journal", "-shm"]) {
32623
+ const src = cookiesPath + suffix;
32624
+ if (fs.existsSync(src)) {
32625
+ await promises.copyFile(src, path7.join(destDir, "Cookies" + suffix)).catch(() => void 0);
32626
+ }
31896
32627
  }
32628
+ }
32629
+ function queryAllCookies(dbPath) {
32630
+ let DatabaseSync;
31897
32631
  try {
31898
- return (await inspectCdpEndpoint({
31899
- endpoint: `http://127.0.0.1:${String(activePort.port)}`,
31900
- timeoutMs: Math.min(2e3, timeoutMs)
31901
- })).endpoint;
32632
+ ({ DatabaseSync } = __require(NODE_SQLITE_SPECIFIER2));
31902
32633
  } catch {
31903
- return void 0;
32634
+ throw new Error(
32635
+ "Reading browser cookies requires Node's built-in SQLite support. Use Node 22.5+ or a build with node:sqlite enabled."
32636
+ );
32637
+ }
32638
+ const database = new DatabaseSync(dbPath, { readOnly: true });
32639
+ try {
32640
+ const stmt = database.prepare(
32641
+ `SELECT host_key, name, value, encrypted_value, path,
32642
+ expires_utc, is_secure, is_httponly, samesite, is_persistent
32643
+ FROM cookies`
32644
+ );
32645
+ stmt.setReadBigInts(true);
32646
+ return stmt.all();
32647
+ } finally {
32648
+ database.close();
31904
32649
  }
31905
32650
  }
31906
- function validateRequestedStrategy(input) {
31907
- if (input.strategy === "attach" && input.attachEndpoint === void 0) {
32651
+ async function resolveDecryptionKey(brandId, userDataDir) {
32652
+ if (process.platform === "darwin") {
32653
+ const password = await resolveKeychainPassword(brandId);
32654
+ const key = crypto.pbkdf2Sync(password, "saltysalt", 1003, 16, "sha1");
32655
+ return { platform: "darwin", key, algorithm: "aes-128-cbc" };
32656
+ }
32657
+ if (process.platform === "linux") {
32658
+ const key = crypto.pbkdf2Sync("peanuts", "saltysalt", 1, 16, "sha1");
32659
+ return { platform: "linux", key, algorithm: "aes-128-cbc" };
32660
+ }
32661
+ if (process.platform === "win32") {
32662
+ const key = await resolveWindowsMasterKey(userDataDir);
32663
+ return { platform: "win32", key, algorithm: "aes-256-gcm" };
32664
+ }
32665
+ throw new Error(`Unsupported platform "${process.platform}" for cookie decryption.`);
32666
+ }
32667
+ var BRAND_KEYCHAIN_SERVICE = {
32668
+ chrome: "Chrome Safe Storage",
32669
+ "chrome-canary": "Chrome Safe Storage",
32670
+ chromium: "Chromium Safe Storage",
32671
+ brave: "Brave Safe Storage",
32672
+ edge: "Microsoft Edge Safe Storage",
32673
+ vivaldi: "Chrome Safe Storage",
32674
+ helium: "Chrome Safe Storage"
32675
+ };
32676
+ async function resolveKeychainPassword(brandId) {
32677
+ const service = BRAND_KEYCHAIN_SERVICE[brandId];
32678
+ try {
32679
+ const { stdout } = await execFile2("security", [
32680
+ "find-generic-password",
32681
+ "-s",
32682
+ service,
32683
+ "-w"
32684
+ ]);
32685
+ return stdout.trim();
32686
+ } catch {
31908
32687
  throw new Error(
31909
- `${input.brand.displayName} is not currently exposing a debuggable CDP endpoint for attach mode.`
32688
+ `Failed to retrieve "${service}" from macOS Keychain. Ensure the browser has been opened at least once and Keychain access is allowed.`
31910
32689
  );
31911
32690
  }
31912
- if (input.strategy === "headless" && input.runningPid !== void 0) {
32691
+ }
32692
+ async function resolveWindowsMasterKey(userDataDir) {
32693
+ const localStatePath = path7.join(userDataDir, "Local State");
32694
+ let localState;
32695
+ try {
32696
+ localState = JSON.parse(await promises.readFile(localStatePath, "utf8"));
32697
+ } catch {
31913
32698
  throw new Error(
31914
- `${input.brand.displayName} is already running. Close it first or use managed-relaunch.`
32699
+ `Failed to read "${localStatePath}". Ensure the browser has been opened at least once.`
31915
32700
  );
31916
32701
  }
31917
- if (input.strategy === "managed-relaunch" && input.runningPid === void 0) {
32702
+ const encodedKey = localState.os_crypt?.encrypted_key;
32703
+ if (!encodedKey) {
32704
+ throw new Error(`No encrypted key found in "${localStatePath}".`);
32705
+ }
32706
+ const rawKey = Buffer.from(encodedKey, "base64").subarray(5);
32707
+ const psScript = `
32708
+ Add-Type -AssemblyName System.Security
32709
+ $bytes = [byte[]]@(${Array.from(rawKey).join(",")})
32710
+ $decrypted = [System.Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, 'CurrentUser')
32711
+ [Convert]::ToBase64String($decrypted)
32712
+ `;
32713
+ try {
32714
+ const { stdout } = await execFile2("powershell", [
32715
+ "-NoProfile",
32716
+ "-NonInteractive",
32717
+ "-Command",
32718
+ psScript
32719
+ ]);
32720
+ return Buffer.from(stdout.trim(), "base64");
32721
+ } catch {
31918
32722
  throw new Error(
31919
- `${input.brand.displayName} is not currently running, so managed-relaunch is not available.`
32723
+ "Failed to decrypt browser master key via Windows DPAPI. Ensure you are running as the same user who owns the browser profile."
31920
32724
  );
31921
32725
  }
31922
32726
  }
31923
- function inferBrandFromUserDataDir(userDataDir) {
31924
- const normalized = normalizePath(userDataDir);
31925
- return getAllBrowserBrands().find((brand2) => {
31926
- const config = resolveBrandPlatformConfig(brand2);
31927
- if (!config) {
31928
- return false;
32727
+ function decryptCookieRows(rows, decryptionKey) {
32728
+ const cookies = [];
32729
+ const nowSeconds = Math.floor(Date.now() / 1e3);
32730
+ for (const row of rows) {
32731
+ const name = row.name.trim();
32732
+ const domain = row.host_key.trim();
32733
+ if (!name || !domain) {
32734
+ continue;
31929
32735
  }
31930
- const defaultDir = normalizePath(config.userDataDir);
31931
- return normalized === defaultDir || normalized.startsWith(`${defaultDir}/`);
31932
- });
31933
- }
31934
- function inferBrandFromExecutablePath(executablePath) {
31935
- const normalized = normalizePath(executablePath);
31936
- return getAllBrowserBrands().find((brand2) => {
31937
- const config = resolveBrandPlatformConfig(brand2);
31938
- if (!config) {
31939
- return false;
32736
+ const value = decryptCookieValue(row, decryptionKey);
32737
+ if (value === null) {
32738
+ continue;
31940
32739
  }
31941
- return config.executableCandidates.some(
31942
- (candidate) => candidate !== null && normalizePath(candidate) === normalized
31943
- );
31944
- });
31945
- }
31946
- function buildCaptureChromeArgs(input) {
31947
- const args = [
31948
- "--remote-debugging-port=0",
31949
- "--headless=new",
31950
- "--no-first-run",
31951
- "--no-default-browser-check",
31952
- "--disable-background-networking",
31953
- "--disable-sync",
31954
- "--disable-component-update",
31955
- `--user-data-dir=${input.userDataDir}`
31956
- ];
31957
- if (input.profileDirectory !== void 0) {
31958
- args.push(`--profile-directory=${input.profileDirectory}`);
31959
- }
31960
- return args;
31961
- }
31962
- async function waitForCaptureEndpoint(input) {
31963
- const deadline = Date.now() + input.timeoutMs;
31964
- while (Date.now() < deadline) {
31965
- const activePort = readDevToolsActivePort(input.userDataDir);
31966
- if (activePort) {
31967
- try {
31968
- return (await inspectCdpEndpoint({
31969
- endpoint: `http://127.0.0.1:${String(activePort.port)}`,
31970
- timeoutMs: Math.min(2e3, input.timeoutMs)
31971
- })).endpoint;
31972
- } catch {
31973
- return `ws://127.0.0.1:${String(activePort.port)}${activePort.webSocketPath}`;
31974
- }
32740
+ const expiresSeconds = chromeDateToUnixSeconds(row.expires_utc);
32741
+ const isSession = expiresSeconds <= 0;
32742
+ if (!isSession && expiresSeconds < nowSeconds) {
32743
+ continue;
31975
32744
  }
31976
- if (input.child.exitCode !== null) {
31977
- break;
32745
+ const sameSite = chromeSameSiteToString(row.samesite);
32746
+ let secure = Number(row.is_secure) === 1;
32747
+ if (sameSite === "None") {
32748
+ secure = true;
31978
32749
  }
31979
- await sleep4(DEVTOOLS_POLL_INTERVAL_MS2);
32750
+ cookies.push({
32751
+ name,
32752
+ value,
32753
+ domain,
32754
+ path: row.path || "/",
32755
+ secure,
32756
+ httpOnly: Number(row.is_httponly) === 1,
32757
+ ...isSession ? {} : { expires: expiresSeconds },
32758
+ ...sameSite !== void 0 ? { sameSite } : {}
32759
+ });
31980
32760
  }
31981
- throw new Error(formatCaptureLaunchError(input.brandDisplayName, input.stderrLines));
32761
+ return cookies;
31982
32762
  }
31983
- function formatCaptureLaunchError(brandDisplayName, stderrLines) {
31984
- const relevantLines = stderrLines.join("").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
31985
- if (relevantLines.length === 0) {
31986
- return `${brandDisplayName} failed to launch before exposing a DevTools endpoint.`;
32763
+ function decryptCookieValue(row, decryptionKey) {
32764
+ if (row.value && row.value.length > 0) {
32765
+ return row.value;
31987
32766
  }
31988
- const focusedLines = relevantLines.filter(
31989
- (line) => /(error|fatal|sandbox|namespace|permission|cannot|failed|abort)/i.test(line)
31990
- );
31991
- return `${brandDisplayName} failed to launch before exposing a DevTools endpoint.
31992
- ${(focusedLines.length > 0 ? focusedLines : relevantLines).slice(-5).join("\n")}`;
32767
+ const encrypted = Buffer.isBuffer(row.encrypted_value) ? row.encrypted_value : Buffer.from(row.encrypted_value);
32768
+ if (encrypted.length === 0) {
32769
+ return "";
32770
+ }
32771
+ const prefix = encrypted.subarray(0, 3).toString("ascii");
32772
+ if (prefix !== "v10" && prefix !== "v11") {
32773
+ return encrypted.toString("utf8");
32774
+ }
32775
+ const ciphertext = encrypted.subarray(3);
32776
+ if (decryptionKey.algorithm === "aes-128-cbc") {
32777
+ return decryptAes128Cbc(ciphertext, decryptionKey.key);
32778
+ }
32779
+ if (decryptionKey.algorithm === "aes-256-gcm") {
32780
+ return decryptAes256Gcm(ciphertext, decryptionKey.key);
32781
+ }
32782
+ return null;
31993
32783
  }
31994
- async function terminateChild(child) {
31995
- if (child.exitCode !== null) {
31996
- return;
32784
+ function decryptAes128Cbc(ciphertext, key) {
32785
+ try {
32786
+ const iv = Buffer.alloc(16, 32);
32787
+ const decipher = crypto.createDecipheriv("aes-128-cbc", key, iv);
32788
+ let decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
32789
+ if (decrypted.length > CHROME_HMAC_PREFIX_LENGTH && containsNonPrintableAscii(decrypted, CHROME_HMAC_PREFIX_LENGTH)) {
32790
+ decrypted = decrypted.subarray(CHROME_HMAC_PREFIX_LENGTH);
32791
+ }
32792
+ if (containsNonPrintableAscii(decrypted, decrypted.length)) {
32793
+ return null;
32794
+ }
32795
+ return decrypted.toString("utf8");
32796
+ } catch {
32797
+ return null;
31997
32798
  }
32799
+ }
32800
+ function decryptAes256Gcm(ciphertext, key) {
31998
32801
  try {
31999
- child.kill("SIGKILL");
32802
+ const nonce = ciphertext.subarray(0, 12);
32803
+ const authTag = ciphertext.subarray(ciphertext.length - 16);
32804
+ const encrypted = ciphertext.subarray(12, ciphertext.length - 16);
32805
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, nonce);
32806
+ decipher.setAuthTag(authTag);
32807
+ const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
32808
+ if (containsNonPrintableAscii(decrypted, decrypted.length)) {
32809
+ return null;
32810
+ }
32811
+ return decrypted.toString("utf8");
32000
32812
  } catch {
32001
- return;
32813
+ return null;
32002
32814
  }
32003
- await sleep4(50);
32004
32815
  }
32005
- async function waitForProcessExit2(pid, timeoutMs) {
32006
- const deadline = Date.now() + timeoutMs;
32007
- while (Date.now() < deadline) {
32008
- if (!isProcessRunning(pid)) {
32816
+ function containsNonPrintableAscii(buffer, length) {
32817
+ const end = Math.min(length, buffer.length);
32818
+ for (let i = 0; i < end; i++) {
32819
+ const byte = buffer[i];
32820
+ if (byte < 32 || byte > 126) {
32009
32821
  return true;
32010
32822
  }
32011
- await sleep4(50);
32012
32823
  }
32013
- return !isProcessRunning(pid);
32824
+ return false;
32014
32825
  }
32015
- function normalizePath(value) {
32016
- return path6.resolve(expandHome(value)).replaceAll("\\", "/").toLowerCase();
32826
+ function chromeDateToUnixSeconds(chromeTimestamp) {
32827
+ const ts = BigInt(chromeTimestamp);
32828
+ if (ts <= 0n) {
32829
+ return -1;
32830
+ }
32831
+ return Number((ts - CHROME_EPOCH_OFFSET) / 1000000n);
32017
32832
  }
32018
- async function sleep4(ms) {
32019
- await new Promise((resolve5) => setTimeout(resolve5, ms));
32833
+ function chromeSameSiteToString(value) {
32834
+ const v = Number(value);
32835
+ if (v === 0) return "None";
32836
+ if (v === 1) return "Lax";
32837
+ if (v === 2) return "Strict";
32838
+ return void 0;
32020
32839
  }
32021
32840
 
32022
32841
  // src/cloud/cookie-sync.ts
@@ -32072,14 +32891,14 @@ function toPortableBrowserProfileCookieRecord(cookie) {
32072
32891
  if (!name || !domain) {
32073
32892
  return null;
32074
32893
  }
32075
- const path13 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
32894
+ const path15 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
32076
32895
  const expiresAt = typeof cookie.expires === "number" && Number.isFinite(cookie.expires) && cookie.expires > 0 ? Math.floor(cookie.expires * 1e3) : null;
32077
32896
  const sameSite = normalizeSameSite(cookie.sameSite);
32078
32897
  return {
32079
32898
  name,
32080
32899
  value: cookie.value,
32081
32900
  domain,
32082
- path: path13,
32901
+ path: path15,
32083
32902
  secure: cookie.secure,
32084
32903
  httpOnly: cookie.httpOnly,
32085
32904
  ...sameSite === void 0 ? {} : { sameSite },
@@ -32095,114 +32914,48 @@ function normalizeSameSite(value) {
32095
32914
  return void 0;
32096
32915
  }
32097
32916
 
32098
- // src/cloud/portable-cookie-snapshot.ts
32099
- var gzip = util.promisify(zlib.gzip);
32100
- async function capturePortableBrowserProfileSnapshot(input = {}) {
32101
- const attached = input.attachEndpoint ? await inspectCdpEndpoint({
32102
- endpoint: input.attachEndpoint,
32103
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
32104
- }) : await selectAttachBrowserCandidate({
32105
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
32106
- });
32107
- const browser = await enginePlaywright.connectPlaywrightChromiumBrowser({
32108
- url: attached.endpoint
32109
- });
32110
- try {
32111
- const context = browser.contexts()[0];
32112
- if (!context) {
32113
- throw new Error("Attached browser did not expose a default browser context.");
32114
- }
32115
- const prepared = prepareBrowserProfileSyncCookies({
32116
- cookies: await context.cookies(),
32117
- ...input.domains === void 0 ? {} : { domains: input.domains }
32118
- });
32119
- if (prepared.cookies.length === 0) {
32120
- throw new Error("No syncable cookies found for the selected browser and scope.");
32121
- }
32122
- const browserVersion = browser.version();
32123
- const source = parseSnapshotSource(attached.browser ?? browserVersion);
32124
- return {
32125
- version: "portable-cookies-v1",
32126
- source: {
32127
- browserFamily: "chromium",
32128
- ...source.browserName === void 0 ? {} : { browserName: source.browserName },
32129
- ...source.browserMajor === void 0 ? {} : { browserMajor: source.browserMajor },
32130
- ...input.browserBrand === void 0 ? {} : { browserBrand: input.browserBrand },
32131
- ...input.captureMethod === void 0 ? {} : { captureMethod: input.captureMethod },
32132
- platform: normalizePlatform(process.platform),
32133
- capturedAt: Date.now()
32134
- },
32135
- cookies: prepared.cookies
32136
- };
32137
- } finally {
32138
- await browser.close().catch(() => void 0);
32139
- }
32140
- }
32141
- async function encodePortableBrowserProfileSnapshot(snapshot) {
32142
- return gzip(Buffer.from(JSON.stringify(snapshot), "utf8"));
32143
- }
32144
- function parseSnapshotSource(value) {
32145
- if (!value) {
32146
- return {};
32147
- }
32148
- const trimmed = value.trim();
32149
- const browserName = trimmed.split("/")[0]?.trim() || void 0;
32150
- const majorMatch = trimmed.match(/(\d+)/);
32151
- return {
32152
- ...browserName === void 0 ? {} : { browserName },
32153
- ...majorMatch?.[1] === void 0 ? {} : { browserMajor: majorMatch[1] }
32154
- };
32155
- }
32156
- function normalizePlatform(platform) {
32157
- if (platform === "darwin") return "macos";
32158
- if (platform === "win32") return "windows";
32159
- return platform;
32160
- }
32161
-
32162
32917
  // src/cloud/profile-sync.ts
32918
+ var gzip = util.promisify(zlib.gzip);
32163
32919
  var DEFAULT_POLL_INTERVAL_MS = 1e3;
32164
32920
  var DEFAULT_POLL_TIMEOUT_MS = 5 * 6e4;
32165
32921
  async function syncBrowserProfileCookies(client, input) {
32166
- const resolved = await resolveCookieCaptureStrategy({
32167
- ...input.attachEndpoint === void 0 ? {} : { attachEndpoint: input.attachEndpoint },
32922
+ const result = await readBrowserCookies({
32168
32923
  ...input.brandId === void 0 ? {} : { brandId: input.brandId },
32169
32924
  ...input.userDataDir === void 0 ? {} : { userDataDir: input.userDataDir },
32170
- ...input.profileDirectory === void 0 ? {} : { profileDirectory: input.profileDirectory },
32171
- ...input.executablePath === void 0 ? {} : { executablePath: input.executablePath },
32172
- ...input.strategy === void 0 ? {} : { strategy: input.strategy },
32173
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
32925
+ ...input.profileDirectory === void 0 ? {} : { profileDirectory: input.profileDirectory }
32174
32926
  });
32175
- const shouldRestoreBrowser = (input.restoreBrowser ?? true) && resolved.strategy === "managed-relaunch";
32176
- let captureSource;
32177
- try {
32178
- captureSource = await acquireCdpEndpoint(resolved);
32179
- const snapshot = await capturePortableBrowserProfileSnapshot({
32180
- attachEndpoint: captureSource.cdpEndpoint,
32181
- ...captureSource.brandId === void 0 ? {} : { browserBrand: captureSource.brandId },
32182
- captureMethod: captureSource.strategy,
32183
- ...input.domains === void 0 ? {} : { domains: input.domains },
32184
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
32185
- });
32186
- const payload = await encodePortableBrowserProfileSnapshot(snapshot);
32187
- const created = await client.createBrowserProfileImport({
32188
- profileId: input.profileId
32189
- });
32190
- if (payload.length > created.maxUploadBytes) {
32191
- throw new Error(
32192
- `Compressed cookie snapshot is ${String(payload.length)} bytes, exceeding the ${String(created.maxUploadBytes)} byte upload limit.`
32193
- );
32194
- }
32195
- const uploaded = await client.uploadBrowserProfileImportPayload({
32196
- uploadUrl: created.uploadUrl,
32197
- payload
32198
- });
32199
- return uploaded.status === "ready" ? uploaded : waitForBrowserProfileImport(client, created.importId);
32200
- } finally {
32201
- await captureSource?.cleanup().catch(() => void 0);
32202
- if (shouldRestoreBrowser && resolved.executablePath !== void 0) {
32203
- relaunchBrowserNormally(resolved.executablePath);
32204
- }
32927
+ const prepared = prepareBrowserProfileSyncCookies({
32928
+ cookies: result.cookies,
32929
+ ...input.domains === void 0 ? {} : { domains: input.domains }
32930
+ });
32931
+ if (prepared.cookies.length === 0) {
32932
+ throw new Error("No syncable cookies found for the selected browser and scope.");
32933
+ }
32934
+ const snapshot = {
32935
+ version: "portable-cookies-v1",
32936
+ source: {
32937
+ browserFamily: "chromium",
32938
+ browserBrand: result.brandId,
32939
+ captureMethod: "sqlite",
32940
+ platform: normalizePlatform(process.platform),
32941
+ capturedAt: Date.now()
32942
+ },
32943
+ cookies: prepared.cookies
32944
+ };
32945
+ const payload = await gzip(Buffer.from(JSON.stringify(snapshot), "utf8"));
32946
+ const created = await client.createBrowserProfileImport({
32947
+ profileId: input.profileId
32948
+ });
32949
+ if (payload.length > created.maxUploadBytes) {
32950
+ throw new Error(
32951
+ `Compressed cookie snapshot is ${String(payload.length)} bytes, exceeding the ${String(created.maxUploadBytes)} byte upload limit.`
32952
+ );
32205
32953
  }
32954
+ const uploaded = await client.uploadBrowserProfileImportPayload({
32955
+ uploadUrl: created.uploadUrl,
32956
+ payload
32957
+ });
32958
+ return uploaded.status === "ready" ? uploaded : waitForBrowserProfileImport(client, created.importId);
32206
32959
  }
32207
32960
  async function waitForBrowserProfileImport(client, importId) {
32208
32961
  const deadline = Date.now() + DEFAULT_POLL_TIMEOUT_MS;
@@ -32214,12 +32967,17 @@ async function waitForBrowserProfileImport(client, importId) {
32214
32967
  if (current.status === "failed") {
32215
32968
  throw new Error(current.error ?? "Browser profile sync failed.");
32216
32969
  }
32217
- await sleep5(DEFAULT_POLL_INTERVAL_MS);
32970
+ await sleep4(DEFAULT_POLL_INTERVAL_MS);
32218
32971
  }
32219
32972
  throw new Error(`Timed out waiting for browser profile sync "${importId}" to finish.`);
32220
32973
  }
32221
- async function sleep5(ms) {
32222
- await new Promise((resolve5) => setTimeout(resolve5, ms));
32974
+ function normalizePlatform(platform) {
32975
+ if (platform === "darwin") return "macos";
32976
+ if (platform === "win32") return "windows";
32977
+ return platform;
32978
+ }
32979
+ async function sleep4(ms) {
32980
+ await new Promise((resolve4) => setTimeout(resolve4, ms));
32223
32981
  }
32224
32982
 
32225
32983
  // src/cloud/client.ts
@@ -32239,7 +32997,8 @@ var OpensteerCloudClient = class {
32239
32997
  ...input.name === void 0 ? {} : { name: input.name },
32240
32998
  ...input.browser === void 0 ? {} : { browser: input.browser },
32241
32999
  ...input.context === void 0 ? {} : { context: input.context },
32242
- ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile }
33000
+ ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
33001
+ ...input.observability === void 0 ? {} : { observability: input.observability }
32243
33002
  }
32244
33003
  });
32245
33004
  return await response.json();
@@ -32417,8 +33176,8 @@ var OpensteerCloudClient = class {
32417
33176
  }
32418
33177
  };
32419
33178
  function delay(ms) {
32420
- return new Promise((resolve5) => {
32421
- setTimeout(resolve5, ms);
33179
+ return new Promise((resolve4) => {
33180
+ setTimeout(resolve4, ms);
32422
33181
  });
32423
33182
  }
32424
33183
  function wrapCloudFetchError(error, input) {
@@ -32441,17 +33200,17 @@ function wrapCloudFetchError(error, input) {
32441
33200
  function resolveCloudConfig(input = {}) {
32442
33201
  const provider = resolveOpensteerProvider({
32443
33202
  ...input.provider === void 0 ? {} : { provider: input.provider },
32444
- ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
33203
+ ...input.environment?.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: input.environment.OPENSTEER_PROVIDER }
32445
33204
  });
32446
33205
  if (provider.mode !== "cloud") {
32447
33206
  return void 0;
32448
33207
  }
32449
33208
  const cloudProvider = input.provider?.mode === "cloud" ? input.provider : void 0;
32450
- const apiKey = cloudProvider?.apiKey ?? process.env.OPENSTEER_API_KEY;
33209
+ const apiKey = cloudProvider?.apiKey ?? input.environment?.OPENSTEER_API_KEY;
32451
33210
  if (!apiKey || apiKey.trim().length === 0) {
32452
33211
  throw new Error("provider=cloud requires OPENSTEER_API_KEY or provider.apiKey.");
32453
33212
  }
32454
- const baseUrl = cloudProvider?.baseUrl ?? process.env.OPENSTEER_BASE_URL;
33213
+ const baseUrl = cloudProvider?.baseUrl ?? input.environment?.OPENSTEER_BASE_URL;
32455
33214
  if (!baseUrl || baseUrl.trim().length === 0) {
32456
33215
  throw new Error("provider=cloud requires OPENSTEER_BASE_URL or provider.baseUrl.");
32457
33216
  }
@@ -32553,9 +33312,9 @@ var OpensteerCloudAutomationClient = class {
32553
33312
  sentAt: Date.now(),
32554
33313
  ...input === void 0 ? {} : { input }
32555
33314
  };
32556
- return new Promise((resolve5, reject) => {
33315
+ return new Promise((resolve4, reject) => {
32557
33316
  this.pending.set(requestId, {
32558
- resolve: (value) => resolve5(value),
33317
+ resolve: (value) => resolve4(value),
32559
33318
  reject
32560
33319
  });
32561
33320
  try {
@@ -32618,8 +33377,8 @@ var OpensteerCloudAutomationClient = class {
32618
33377
  pending.reject(new Error(`automation connection closed before ${requestId} completed`));
32619
33378
  }
32620
33379
  this.pending.clear();
32621
- await new Promise((resolve5) => {
32622
- socket.once("close", () => resolve5());
33380
+ await new Promise((resolve4) => {
33381
+ socket.once("close", () => resolve4());
32623
33382
  socket.close();
32624
33383
  }).catch(() => void 0);
32625
33384
  }
@@ -32661,8 +33420,8 @@ var OpensteerCloudAutomationClient = class {
32661
33420
  }
32662
33421
  this.pending.clear();
32663
33422
  });
32664
- await new Promise((resolve5, reject) => {
32665
- socket.once("open", () => resolve5());
33423
+ await new Promise((resolve4, reject) => {
33424
+ socket.once("open", () => resolve4());
32666
33425
  socket.once("error", reject);
32667
33426
  });
32668
33427
  this.send({
@@ -33003,6 +33762,7 @@ var CloudSessionProxy = class {
33003
33762
  workspace;
33004
33763
  cleanupRootOnClose;
33005
33764
  cloud;
33765
+ observability;
33006
33766
  sessionId;
33007
33767
  sessionBaseUrl;
33008
33768
  client;
@@ -33011,8 +33771,9 @@ var CloudSessionProxy = class {
33011
33771
  constructor(cloud, options = {}) {
33012
33772
  this.cloud = cloud;
33013
33773
  this.workspace = options.workspace;
33014
- this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path6__default.default.join(os.tmpdir(), `${TEMPORARY_CLOUD_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
33015
- rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
33774
+ this.observability = options.observability;
33775
+ this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path7__default.default.join(os.tmpdir(), `${TEMPORARY_CLOUD_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
33776
+ rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
33016
33777
  workspace: this.workspace
33017
33778
  }));
33018
33779
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.workspace === void 0;
@@ -33355,6 +34116,7 @@ var CloudSessionProxy = class {
33355
34116
  ...this.workspace === void 0 ? {} : { name: this.workspace },
33356
34117
  ...input.launch === void 0 ? {} : { browser: input.launch },
33357
34118
  ...input.context === void 0 ? {} : { context: input.context },
34119
+ ...this.observability === void 0 ? {} : { observability: this.observability },
33358
34120
  ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
33359
34121
  });
33360
34122
  const record = {
@@ -33452,16 +34214,17 @@ function isMissingCloudSessionError(error) {
33452
34214
 
33453
34215
  // src/sdk/runtime-resolution.ts
33454
34216
  function resolveOpensteerRuntimeConfig(input = {}) {
34217
+ const environment = input.environment ?? process.env;
33455
34218
  const provider = resolveOpensteerProvider({
33456
34219
  ...input.provider === void 0 ? {} : { provider: input.provider },
33457
- ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
34220
+ ...environment.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: environment.OPENSTEER_PROVIDER }
33458
34221
  });
33459
34222
  if (provider.mode === "cloud") {
33460
34223
  return {
33461
34224
  provider,
33462
34225
  cloud: resolveCloudConfig({
33463
34226
  ...input.provider === void 0 ? {} : { provider: input.provider },
33464
- ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
34227
+ environment
33465
34228
  })
33466
34229
  };
33467
34230
  }
@@ -33472,7 +34235,7 @@ function createOpensteerSemanticRuntime(input = {}) {
33472
34235
  const engine = input.engine ?? runtimeOptions.engineName ?? DEFAULT_OPENSTEER_ENGINE;
33473
34236
  const config = resolveOpensteerRuntimeConfig({
33474
34237
  ...input.provider === void 0 ? {} : { provider: input.provider },
33475
- ...process.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process.env.OPENSTEER_PROVIDER }
34238
+ ...input.environment === void 0 ? {} : { environment: input.environment }
33476
34239
  });
33477
34240
  assertProviderSupportsEngine(config.provider.mode, engine);
33478
34241
  if (config.provider.mode === "cloud") {
@@ -33480,7 +34243,8 @@ function createOpensteerSemanticRuntime(input = {}) {
33480
34243
  ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
33481
34244
  ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
33482
34245
  ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
33483
- ...runtimeOptions.cleanupRootOnClose === void 0 ? {} : { cleanupRootOnClose: runtimeOptions.cleanupRootOnClose }
34246
+ ...runtimeOptions.cleanupRootOnClose === void 0 ? {} : { cleanupRootOnClose: runtimeOptions.cleanupRootOnClose },
34247
+ ...runtimeOptions.observability === void 0 ? {} : { observability: runtimeOptions.observability }
33484
34248
  });
33485
34249
  }
33486
34250
  return new OpensteerRuntime({
@@ -33495,16 +34259,18 @@ var Opensteer = class {
33495
34259
  browserManager;
33496
34260
  browser;
33497
34261
  constructor(options = {}) {
34262
+ const environment = resolveOpensteerEnvironment(options.rootDir);
33498
34263
  const { provider, engineName, ...runtimeOptions } = options;
33499
34264
  const runtimeConfig = resolveOpensteerRuntimeConfig({
33500
34265
  ...provider === void 0 ? {} : { provider },
33501
- ...process.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process.env.OPENSTEER_PROVIDER }
34266
+ environment
33502
34267
  });
33503
34268
  if (runtimeConfig.provider.mode === "cloud") {
33504
34269
  this.browserManager = void 0;
33505
34270
  this.runtime = createOpensteerSemanticRuntime({
33506
34271
  ...provider === void 0 ? {} : { provider },
33507
34272
  ...engineName === void 0 ? {} : { engine: engineName },
34273
+ environment,
33508
34274
  runtimeOptions: {
33509
34275
  ...runtimeOptions
33510
34276
  }
@@ -33524,6 +34290,7 @@ var Opensteer = class {
33524
34290
  this.runtime = createOpensteerSemanticRuntime({
33525
34291
  ...provider === void 0 ? {} : { provider },
33526
34292
  ...engineName === void 0 ? {} : { engine: engineName },
34293
+ environment,
33527
34294
  runtimeOptions: {
33528
34295
  ...runtimeOptions,
33529
34296
  rootPath: this.browserManager.rootPath,
@@ -33865,7 +34632,7 @@ function normalizeTargetOptions(input) {
33865
34632
  };
33866
34633
  }
33867
34634
  function delay2(ms) {
33868
- return new Promise((resolve5) => setTimeout(resolve5, ms));
34635
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
33869
34636
  }
33870
34637
 
33871
34638
  exports.CloudSessionProxy = CloudSessionProxy;
@@ -33896,8 +34663,10 @@ exports.clearPersistedSessionRecord = clearPersistedSessionRecord;
33896
34663
  exports.cloneElementPath = cloneElementPath;
33897
34664
  exports.cloneReplayElementPath = cloneReplayElementPath;
33898
34665
  exports.cloneStructuralElementAnchor = cloneStructuralElementAnchor;
34666
+ exports.createArtifactStore = createArtifactStore;
33899
34667
  exports.createDomRuntime = createDomRuntime;
33900
34668
  exports.createFilesystemOpensteerWorkspace = createFilesystemOpensteerWorkspace;
34669
+ exports.createObservationStore = createObservationStore;
33901
34670
  exports.createOpensteerExtractionDescriptorStore = createOpensteerExtractionDescriptorStore;
33902
34671
  exports.createOpensteerSemanticRuntime = createOpensteerSemanticRuntime;
33903
34672
  exports.defaultFallbackPolicy = defaultFallbackPolicy;
@@ -33913,7 +34682,9 @@ exports.inspectCdpEndpoint = inspectCdpEndpoint;
33913
34682
  exports.isCurrentUrlField = isCurrentUrlField;
33914
34683
  exports.isValidCssAttributeKey = isValidCssAttributeKey;
33915
34684
  exports.listLocalChromeProfiles = listLocalChromeProfiles;
34685
+ exports.manifestToExternalBinaryLocation = manifestToExternalBinaryLocation;
33916
34686
  exports.normalizeExtractedValue = normalizeExtractedValue;
34687
+ exports.normalizeObservabilityConfig = normalizeObservabilityConfig;
33917
34688
  exports.normalizeOpensteerEngineName = normalizeOpensteerEngineName;
33918
34689
  exports.normalizeOpensteerProviderMode = normalizeOpensteerProviderMode;
33919
34690
  exports.normalizeWorkspaceId = normalizeWorkspaceId;