opensteer 0.8.7 → 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/cli/bin.cjs CHANGED
@@ -6,13 +6,14 @@ var child_process = require('child_process');
6
6
  var crypto = require('crypto');
7
7
  var promises = require('fs/promises');
8
8
  var os = require('os');
9
- var path6 = require('path');
9
+ var path7 = require('path');
10
10
  var enginePlaywright = require('@opensteer/engine-playwright');
11
11
  var util = require('util');
12
12
  var fs = require('fs');
13
13
  var url = require('url');
14
14
  var module$1 = require('module');
15
15
  var zlib = require('zlib');
16
+ var async_hooks = require('async_hooks');
16
17
  var cssSelect = require('css-select');
17
18
  var sharp = require('sharp');
18
19
  var cheerio = require('cheerio');
@@ -42,16 +43,23 @@ function _interopNamespace(e) {
42
43
  }
43
44
 
44
45
  var process2__default = /*#__PURE__*/_interopDefault(process2);
45
- var path6__default = /*#__PURE__*/_interopDefault(path6);
46
+ var path7__default = /*#__PURE__*/_interopDefault(path7);
46
47
  var sharp__default = /*#__PURE__*/_interopDefault(sharp);
47
48
  var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio);
48
49
  var prettier__namespace = /*#__PURE__*/_interopNamespace(prettier);
49
50
  var vm__default = /*#__PURE__*/_interopDefault(vm);
50
51
  var WebSocket2__default = /*#__PURE__*/_interopDefault(WebSocket2);
51
52
 
53
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
54
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
55
+ }) : x)(function(x) {
56
+ if (typeof require !== "undefined") return require.apply(this, arguments);
57
+ throw Error('Dynamic require of "' + x + '" is not supported');
58
+ });
59
+
52
60
  // package.json
53
61
  var package_default = {
54
- version: "0.8.6"};
62
+ version: "0.8.8"};
55
63
  util.promisify(child_process.execFile);
56
64
  Math.floor(Date.now() - process.uptime() * 1e3);
57
65
  ({ ...process.env});
@@ -76,7 +84,7 @@ var CHROME_SINGLETON_ARTIFACTS = [
76
84
  async function clearChromeSingletonEntries(userDataDir) {
77
85
  await Promise.all(
78
86
  CHROME_SINGLETON_ARTIFACTS.map(
79
- (entry) => promises.rm(path6.join(userDataDir, entry), {
87
+ (entry) => promises.rm(path7.join(userDataDir, entry), {
80
88
  recursive: true,
81
89
  force: true
82
90
  }).catch(() => void 0)
@@ -91,7 +99,7 @@ async function sanitizeChromeProfile(userDataDir) {
91
99
  await Promise.all(profileDirs.map((dir) => sanitizeProfilePreferences(userDataDir, dir)));
92
100
  }
93
101
  async function sanitizeProfilePreferences(userDataDir, profileDir) {
94
- const prefsPath = path6.join(userDataDir, profileDir, "Preferences");
102
+ const prefsPath = path7.join(userDataDir, profileDir, "Preferences");
95
103
  try {
96
104
  const raw = await promises.readFile(prefsPath, "utf8");
97
105
  const prefs = JSON.parse(raw);
@@ -103,14 +111,13 @@ async function sanitizeProfilePreferences(userDataDir, profileDir) {
103
111
  profile.exited_cleanly = true;
104
112
  prefs.profile = profile;
105
113
  await promises.writeFile(prefsPath, JSON.stringify(prefs), "utf8");
106
- await promises.rm(path6.join(userDataDir, profileDir, "Secure Preferences"), { force: true }).catch(
114
+ await promises.rm(path7.join(userDataDir, profileDir, "Secure Preferences"), { force: true }).catch(
107
115
  () => void 0
108
116
  );
109
117
  } catch {
110
118
  }
111
119
  }
112
- var PROCESS_LIST_MAX_BUFFER_BYTES2 = 16 * 1024 * 1024;
113
- var PS_COMMAND_ENV2 = { ...process.env, LC_ALL: "C" };
120
+ ({ ...process.env});
114
121
  var WINDOWS_PROGRAM_FILES = process.env.PROGRAMFILES ?? "C:\\Program Files";
115
122
  var WINDOWS_PROGRAM_FILES_X86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
116
123
  var BROWSER_BRANDS = [
@@ -125,9 +132,9 @@ var BROWSER_BRANDS = [
125
132
  },
126
133
  win32: {
127
134
  executableCandidates: [
128
- path6.join(WINDOWS_PROGRAM_FILES, "Google", "Chrome", "Application", "chrome.exe"),
129
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Google", "Chrome", "Application", "chrome.exe"),
130
- path6.join("~", "AppData", "Local", "Google", "Chrome", "Application", "chrome.exe")
135
+ path7.join(WINDOWS_PROGRAM_FILES, "Google", "Chrome", "Application", "chrome.exe"),
136
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Google", "Chrome", "Application", "chrome.exe"),
137
+ path7.join("~", "AppData", "Local", "Google", "Chrome", "Application", "chrome.exe")
131
138
  ],
132
139
  userDataDir: "~/AppData/Local/Google/Chrome/User Data",
133
140
  processNames: ["/google/chrome/application/chrome.exe"]
@@ -157,7 +164,7 @@ var BROWSER_BRANDS = [
157
164
  },
158
165
  win32: {
159
166
  executableCandidates: [
160
- path6.join("~", "AppData", "Local", "Google", "Chrome SxS", "Application", "chrome.exe")
167
+ path7.join("~", "AppData", "Local", "Google", "Chrome SxS", "Application", "chrome.exe")
161
168
  ],
162
169
  userDataDir: "~/AppData/Local/Google/Chrome SxS/User Data",
163
170
  processNames: ["/google/chrome sxs/application/chrome.exe"]
@@ -174,9 +181,9 @@ var BROWSER_BRANDS = [
174
181
  },
175
182
  win32: {
176
183
  executableCandidates: [
177
- path6.join(WINDOWS_PROGRAM_FILES, "Chromium", "Application", "chrome.exe"),
178
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Chromium", "Application", "chrome.exe"),
179
- path6.join("~", "AppData", "Local", "Chromium", "Application", "chrome.exe")
184
+ path7.join(WINDOWS_PROGRAM_FILES, "Chromium", "Application", "chrome.exe"),
185
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Chromium", "Application", "chrome.exe"),
186
+ path7.join("~", "AppData", "Local", "Chromium", "Application", "chrome.exe")
180
187
  ],
181
188
  userDataDir: "~/AppData/Local/Chromium/User Data",
182
189
  processNames: ["/chromium/application/chrome.exe"]
@@ -203,15 +210,15 @@ var BROWSER_BRANDS = [
203
210
  },
204
211
  win32: {
205
212
  executableCandidates: [
206
- path6.join(WINDOWS_PROGRAM_FILES, "BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
207
- path6.join(
213
+ path7.join(WINDOWS_PROGRAM_FILES, "BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
214
+ path7.join(
208
215
  WINDOWS_PROGRAM_FILES_X86,
209
216
  "BraveSoftware",
210
217
  "Brave-Browser",
211
218
  "Application",
212
219
  "brave.exe"
213
220
  ),
214
- path6.join("~", "AppData", "Local", "BraveSoftware", "Brave-Browser", "Application", "brave.exe")
221
+ path7.join("~", "AppData", "Local", "BraveSoftware", "Brave-Browser", "Application", "brave.exe")
215
222
  ],
216
223
  userDataDir: "~/AppData/Local/BraveSoftware/Brave-Browser/User Data",
217
224
  processNames: ["/bravesoftware/brave-browser/application/brave.exe"]
@@ -237,9 +244,9 @@ var BROWSER_BRANDS = [
237
244
  },
238
245
  win32: {
239
246
  executableCandidates: [
240
- path6.join(WINDOWS_PROGRAM_FILES, "Microsoft", "Edge", "Application", "msedge.exe"),
241
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Microsoft", "Edge", "Application", "msedge.exe"),
242
- path6.join("~", "AppData", "Local", "Microsoft", "Edge", "Application", "msedge.exe")
247
+ path7.join(WINDOWS_PROGRAM_FILES, "Microsoft", "Edge", "Application", "msedge.exe"),
248
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Microsoft", "Edge", "Application", "msedge.exe"),
249
+ path7.join("~", "AppData", "Local", "Microsoft", "Edge", "Application", "msedge.exe")
243
250
  ],
244
251
  userDataDir: "~/AppData/Local/Microsoft/Edge/User Data",
245
252
  processNames: ["/microsoft/edge/application/msedge.exe"]
@@ -267,9 +274,9 @@ var BROWSER_BRANDS = [
267
274
  },
268
275
  win32: {
269
276
  executableCandidates: [
270
- path6.join(WINDOWS_PROGRAM_FILES, "Vivaldi", "Application", "vivaldi.exe"),
271
- path6.join(WINDOWS_PROGRAM_FILES_X86, "Vivaldi", "Application", "vivaldi.exe"),
272
- path6.join("~", "AppData", "Local", "Vivaldi", "Application", "vivaldi.exe")
277
+ path7.join(WINDOWS_PROGRAM_FILES, "Vivaldi", "Application", "vivaldi.exe"),
278
+ path7.join(WINDOWS_PROGRAM_FILES_X86, "Vivaldi", "Application", "vivaldi.exe"),
279
+ path7.join("~", "AppData", "Local", "Vivaldi", "Application", "vivaldi.exe")
273
280
  ],
274
281
  userDataDir: "~/AppData/Local/Vivaldi/User Data",
275
282
  processNames: ["/vivaldi/application/vivaldi.exe"]
@@ -296,9 +303,6 @@ var BROWSER_BRANDS = [
296
303
  }
297
304
  }
298
305
  ];
299
- function getAllBrowserBrands() {
300
- return BROWSER_BRANDS;
301
- }
302
306
  function getBrowserBrand(id) {
303
307
  const brand2 = BROWSER_BRANDS.find((candidate) => candidate.id === id);
304
308
  if (!brand2) {
@@ -336,177 +340,35 @@ function detectInstalledBrowserBrands() {
336
340
  brandId: brand2.id,
337
341
  displayName: brand2.displayName,
338
342
  executablePath,
339
- userDataDir: path6.resolve(expandHome(platformConfig.userDataDir))
343
+ userDataDir: path7.resolve(expandHome(platformConfig.userDataDir))
340
344
  });
341
345
  }
342
346
  return installations;
343
347
  }
344
- function resolveBrandExecutablePath(brand2, explicitPath) {
345
- if (explicitPath !== void 0) {
346
- const resolvedPath2 = path6.resolve(expandHome(explicitPath));
347
- if (!fs.existsSync(resolvedPath2)) {
348
- throw new Error(`${brand2.displayName} executable was not found at "${resolvedPath2}".`);
349
- }
350
- return resolvedPath2;
351
- }
352
- const platformConfig = resolveBrandPlatformConfig(brand2);
353
- if (!platformConfig) {
354
- throw new Error(`${brand2.displayName} is not supported on ${process.platform}.`);
355
- }
356
- const resolvedPath = firstExistingPath(
357
- resolveExecutableCandidates(platformConfig.executableCandidates)
358
- );
359
- if (!resolvedPath) {
360
- throw new Error(
361
- `Could not find a ${brand2.displayName} executable. Pass --executable-path or browser.executablePath.`
362
- );
363
- }
364
- return resolvedPath;
365
- }
366
348
  function resolveBrandUserDataDir(brand2, explicitDir) {
367
349
  if (explicitDir !== void 0) {
368
- return path6.resolve(expandHome(explicitDir));
350
+ return path7.resolve(expandHome(explicitDir));
369
351
  }
370
352
  const platformConfig = resolveBrandPlatformConfig(brand2);
371
353
  if (!platformConfig) {
372
354
  throw new Error(`${brand2.displayName} is not supported on ${process.platform}.`);
373
355
  }
374
- return path6.resolve(expandHome(platformConfig.userDataDir));
375
- }
376
- function isBrandProcess(brand2, commandLine) {
377
- const normalizedCommand = normalizeCommand(commandLine);
378
- if (!normalizedCommand) {
379
- return false;
380
- }
381
- if (normalizedCommand.includes("crashpad_handler")) {
382
- return false;
383
- }
384
- if (/\s--type=/.test(normalizedCommand)) {
385
- return false;
386
- }
387
- return getBrandProcessMarkers(brand2).some((marker) => normalizedCommand.includes(marker));
388
- }
389
- function findBrandProcess(brand2) {
390
- for (const processEntry of listProcesses()) {
391
- if (isBrandProcess(brand2, processEntry.commandLine)) {
392
- return { pid: processEntry.pid };
393
- }
394
- }
395
- return null;
396
- }
397
- function getBrandProcessMarkers(brand2) {
398
- const markers = /* @__PURE__ */ new Set();
399
- for (const config of [brand2.darwin, brand2.win32, brand2.linux]) {
400
- if (!config) {
401
- continue;
402
- }
403
- for (const processName of config.processNames) {
404
- const normalized = normalizeCommand(processName);
405
- if (normalized) {
406
- markers.add(normalized);
407
- }
408
- }
409
- for (const candidate of config.executableCandidates) {
410
- if (!candidate) {
411
- continue;
412
- }
413
- const normalized = normalizeCommand(path6.resolve(expandHome(candidate)));
414
- if (normalized) {
415
- markers.add(normalized);
416
- }
417
- }
418
- }
419
- return [...markers];
356
+ return path7.resolve(expandHome(platformConfig.userDataDir));
420
357
  }
421
358
  function resolveExecutableCandidates(candidates) {
422
- return candidates.map((candidate) => candidate ? path6.resolve(expandHome(candidate)) : null);
423
- }
424
- function listProcesses() {
425
- if (process.platform === "win32") {
426
- return listWindowsProcesses();
427
- }
428
- return listUnixProcesses();
429
- }
430
- function listUnixProcesses() {
431
- try {
432
- const output = child_process.execFileSync("ps", ["-A", "-o", "pid=,command="], {
433
- encoding: "utf8",
434
- env: PS_COMMAND_ENV2,
435
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2,
436
- stdio: ["ignore", "pipe", "ignore"]
437
- });
438
- return output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
439
- const match = /^(\d+)\s+(.*)$/.exec(line);
440
- if (!match) {
441
- return null;
442
- }
443
- const pid = Number.parseInt(match[1] ?? "", 10);
444
- const commandLine = match[2]?.trim() ?? "";
445
- if (!Number.isInteger(pid) || pid <= 0 || commandLine.length === 0) {
446
- return null;
447
- }
448
- return {
449
- pid,
450
- commandLine
451
- };
452
- }).filter(
453
- (entry) => entry !== null
454
- ).sort((left, right) => left.pid - right.pid);
455
- } catch {
456
- return [];
457
- }
458
- }
459
- function listWindowsProcesses() {
460
- try {
461
- const output = child_process.execFileSync(
462
- "powershell.exe",
463
- [
464
- "-NoProfile",
465
- "-Command",
466
- "Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"
467
- ],
468
- {
469
- encoding: "utf8",
470
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2,
471
- stdio: ["ignore", "pipe", "ignore"]
472
- }
473
- ).trim();
474
- if (!output) {
475
- return [];
476
- }
477
- const parsed = JSON.parse(output);
478
- const records = Array.isArray(parsed) ? parsed : [parsed];
479
- return records.map((record) => {
480
- const pid = Number(record.ProcessId);
481
- const commandLine = typeof record.CommandLine === "string" ? record.CommandLine.trim() : "";
482
- if (!Number.isInteger(pid) || pid <= 0 || commandLine.length === 0) {
483
- return null;
484
- }
485
- return {
486
- pid,
487
- commandLine
488
- };
489
- }).filter(
490
- (entry) => entry !== null
491
- ).sort((left, right) => left.pid - right.pid);
492
- } catch {
493
- return [];
494
- }
495
- }
496
- function normalizeCommand(value) {
497
- return value.trim().replaceAll("\\", "/").toLowerCase();
359
+ return candidates.map((candidate) => candidate ? path7.resolve(expandHome(candidate)) : null);
498
360
  }
499
361
 
500
362
  // src/local-browser/chrome-discovery.ts
501
363
  function expandHome(value) {
502
364
  if (value === "~" || value.startsWith("~/")) {
503
- return path6.join(os.homedir(), value.slice(1));
365
+ return path7.join(os.homedir(), value.slice(1));
504
366
  }
505
367
  return value;
506
368
  }
507
369
  function resolveChromeExecutablePath(executablePath) {
508
370
  if (executablePath !== void 0) {
509
- const resolvedPath = path6.resolve(expandHome(executablePath));
371
+ const resolvedPath = path7.resolve(expandHome(executablePath));
510
372
  if (!fs.existsSync(resolvedPath)) {
511
373
  throw new Error(`Chrome executable was not found at "${resolvedPath}".`);
512
374
  }
@@ -530,37 +392,37 @@ function detectLocalChromeInstallations() {
530
392
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
531
393
  "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
532
394
  ]),
533
- userDataDir: path6.join(os.homedir(), "Library", "Application Support", "Google", "Chrome")
395
+ userDataDir: path7.join(os.homedir(), "Library", "Application Support", "Google", "Chrome")
534
396
  },
535
397
  {
536
398
  brand: "chromium",
537
399
  executablePath: firstExistingPath(["/Applications/Chromium.app/Contents/MacOS/Chromium"]),
538
- userDataDir: path6.join(os.homedir(), "Library", "Application Support", "Chromium")
400
+ userDataDir: path7.join(os.homedir(), "Library", "Application Support", "Chromium")
539
401
  }
540
402
  ];
541
403
  }
542
404
  if (process.platform === "win32") {
543
405
  const programFiles = process.env.PROGRAMFILES ?? "C:\\Program Files";
544
406
  const programFilesX86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
545
- const localAppData = process.env.LOCALAPPDATA ?? path6.join(os.homedir(), "AppData", "Local");
407
+ const localAppData = process.env.LOCALAPPDATA ?? path7.join(os.homedir(), "AppData", "Local");
546
408
  return [
547
409
  {
548
410
  brand: "chrome",
549
411
  executablePath: firstExistingPath([
550
- path6.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
551
- path6.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
552
- path6.join(localAppData, "Google", "Chrome", "Application", "chrome.exe")
412
+ path7.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
413
+ path7.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
414
+ path7.join(localAppData, "Google", "Chrome", "Application", "chrome.exe")
553
415
  ]),
554
- userDataDir: path6.join(localAppData, "Google", "Chrome", "User Data")
416
+ userDataDir: path7.join(localAppData, "Google", "Chrome", "User Data")
555
417
  },
556
418
  {
557
419
  brand: "chromium",
558
420
  executablePath: firstExistingPath([
559
- path6.join(programFiles, "Chromium", "Application", "chrome.exe"),
560
- path6.join(programFilesX86, "Chromium", "Application", "chrome.exe"),
561
- path6.join(localAppData, "Chromium", "Application", "chrome.exe")
421
+ path7.join(programFiles, "Chromium", "Application", "chrome.exe"),
422
+ path7.join(programFilesX86, "Chromium", "Application", "chrome.exe"),
423
+ path7.join(localAppData, "Chromium", "Application", "chrome.exe")
562
424
  ]),
563
- userDataDir: path6.join(localAppData, "Chromium", "User Data")
425
+ userDataDir: path7.join(localAppData, "Chromium", "User Data")
564
426
  }
565
427
  ];
566
428
  }
@@ -573,7 +435,7 @@ function detectLocalChromeInstallations() {
573
435
  resolveBinaryFromPath("google-chrome"),
574
436
  resolveBinaryFromPath("google-chrome-stable")
575
437
  ]),
576
- userDataDir: path6.join(os.homedir(), ".config", "google-chrome")
438
+ userDataDir: path7.join(os.homedir(), ".config", "google-chrome")
577
439
  },
578
440
  {
579
441
  brand: "chromium",
@@ -583,7 +445,7 @@ function detectLocalChromeInstallations() {
583
445
  resolveBinaryFromPath("chromium"),
584
446
  resolveBinaryFromPath("chromium-browser")
585
447
  ]),
586
- userDataDir: path6.join(os.homedir(), ".config", "chromium")
448
+ userDataDir: path7.join(os.homedir(), ".config", "chromium")
587
449
  }
588
450
  ];
589
451
  }
@@ -595,7 +457,7 @@ function detectLocalBrowserInstallations() {
595
457
  }));
596
458
  }
597
459
  function readDevToolsActivePort(userDataDir) {
598
- const devToolsPath = path6.join(userDataDir, "DevToolsActivePort");
460
+ const devToolsPath = path7.join(userDataDir, "DevToolsActivePort");
599
461
  if (!fs.existsSync(devToolsPath)) {
600
462
  return null;
601
463
  }
@@ -828,8 +690,8 @@ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
828
690
  const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
829
691
  return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
830
692
  }
831
- function normalizeWebSocketPath(path16) {
832
- return path16.startsWith("/") ? path16 : `/${path16}`;
693
+ function normalizeWebSocketPath(path17) {
694
+ return path17.startsWith("/") ? path17 : `/${path17}`;
833
695
  }
834
696
  function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
835
697
  try {
@@ -875,20 +737,20 @@ var SESSION_SKIPPED_PROFILE_DIRECTORIES = /* @__PURE__ */ new Set([
875
737
  "Network"
876
738
  ]);
877
739
  async function createBrowserProfileSnapshot(input) {
878
- const sourceUserDataDir = path6.resolve(expandHome(input.sourceUserDataDir));
879
- const targetUserDataDir = path6.resolve(expandHome(input.targetUserDataDir));
740
+ const sourceUserDataDir = path7.resolve(expandHome(input.sourceUserDataDir));
741
+ const targetUserDataDir = path7.resolve(expandHome(input.targetUserDataDir));
880
742
  const profileDirectory = input.profileDirectory?.trim();
881
743
  const copyMode = input.copyMode;
882
744
  await promises.mkdir(targetUserDataDir, { recursive: true });
883
745
  await clearChromeSingletonEntries(targetUserDataDir);
884
746
  if (profileDirectory) {
885
- const sourceProfileDir = path6.join(sourceUserDataDir, profileDirectory);
747
+ const sourceProfileDir = path7.join(sourceUserDataDir, profileDirectory);
886
748
  if (!fs.existsSync(sourceProfileDir)) {
887
749
  throw new Error(
888
750
  `Chrome profile "${profileDirectory}" was not found in "${sourceUserDataDir}".`
889
751
  );
890
752
  }
891
- await promises.cp(sourceProfileDir, path6.join(targetUserDataDir, profileDirectory), {
753
+ await promises.cp(sourceProfileDir, path7.join(targetUserDataDir, profileDirectory), {
892
754
  recursive: true,
893
755
  filter: (candidate) => shouldCopyEntry({
894
756
  candidatePath: candidate,
@@ -912,8 +774,8 @@ async function copyRootLevelEntries(input) {
912
774
  if (CHROME_SINGLETON_ENTRIES.has(entry) || entry === input.selectedProfileDirectory) {
913
775
  continue;
914
776
  }
915
- const sourcePath = path6.join(input.sourceUserDataDir, entry);
916
- const targetPath = path6.join(input.targetUserDataDir, entry);
777
+ const sourcePath = path7.join(input.sourceUserDataDir, entry);
778
+ const targetPath = path7.join(input.targetUserDataDir, entry);
917
779
  const entryStat = await promises.stat(sourcePath).catch(() => null);
918
780
  if (!entryStat) {
919
781
  continue;
@@ -945,7 +807,7 @@ async function copyRootLevelEntries(input) {
945
807
  }
946
808
  }
947
809
  function isProfileDirectory(userDataDir, entry) {
948
- return fs.existsSync(path6.join(userDataDir, entry, "Preferences"));
810
+ return fs.existsSync(path7.join(userDataDir, entry, "Preferences"));
949
811
  }
950
812
  function shouldCopyEntry(input) {
951
813
  const entryName = input.candidatePath.split("/").at(-1)?.split("\\").at(-1) ?? input.candidatePath;
@@ -955,7 +817,7 @@ function shouldCopyEntry(input) {
955
817
  if (input.copyMode !== "session") {
956
818
  return true;
957
819
  }
958
- const relativePath = path6.relative(input.rootPath, input.candidatePath);
820
+ const relativePath = path7.relative(input.rootPath, input.candidatePath);
959
821
  if (relativePath.length === 0) {
960
822
  return true;
961
823
  }
@@ -1443,30 +1305,30 @@ function isPlainObject(value) {
1443
1305
  const prototype = Object.getPrototypeOf(value);
1444
1306
  return prototype === Object.prototype || prototype === null;
1445
1307
  }
1446
- function canonicalizeJsonValue(value, path16) {
1308
+ function canonicalizeJsonValue(value, path17) {
1447
1309
  if (value === null || typeof value === "string" || typeof value === "boolean") {
1448
1310
  return value;
1449
1311
  }
1450
1312
  if (typeof value === "number") {
1451
1313
  if (!Number.isFinite(value)) {
1452
- throw new TypeError(`${path16} must be a finite JSON number`);
1314
+ throw new TypeError(`${path17} must be a finite JSON number`);
1453
1315
  }
1454
1316
  return value;
1455
1317
  }
1456
1318
  if (Array.isArray(value)) {
1457
- return value.map((entry, index) => canonicalizeJsonValue(entry, `${path16}[${index}]`));
1319
+ return value.map((entry, index) => canonicalizeJsonValue(entry, `${path17}[${index}]`));
1458
1320
  }
1459
1321
  if (!isPlainObject(value)) {
1460
- throw new TypeError(`${path16} must be a plain JSON object`);
1322
+ throw new TypeError(`${path17} must be a plain JSON object`);
1461
1323
  }
1462
1324
  const sorted = Object.keys(value).sort((left, right) => left.localeCompare(right));
1463
1325
  const result = {};
1464
1326
  for (const key of sorted) {
1465
1327
  const entry = value[key];
1466
1328
  if (entry === void 0) {
1467
- throw new TypeError(`${path16}.${key} must not be undefined`);
1329
+ throw new TypeError(`${path17}.${key} must not be undefined`);
1468
1330
  }
1469
- result[key] = canonicalizeJsonValue(entry, `${path16}.${key}`);
1331
+ result[key] = canonicalizeJsonValue(entry, `${path17}.${key}`);
1470
1332
  }
1471
1333
  return result;
1472
1334
  }
@@ -1503,7 +1365,7 @@ function joinStoragePath(...segments) {
1503
1365
  return segments.join("/");
1504
1366
  }
1505
1367
  function resolveStoragePath(rootPath, relativePath) {
1506
- if (path6__default.default.isAbsolute(relativePath)) {
1368
+ if (path7__default.default.isAbsolute(relativePath)) {
1507
1369
  throw new TypeError(`storage path ${relativePath} must be relative`);
1508
1370
  }
1509
1371
  const segments = relativePath.split("/");
@@ -1515,7 +1377,7 @@ function resolveStoragePath(rootPath, relativePath) {
1515
1377
  throw new TypeError(`storage path ${relativePath} must not contain path traversal`);
1516
1378
  }
1517
1379
  }
1518
- return path6__default.default.join(rootPath, ...segments);
1380
+ return path7__default.default.join(rootPath, ...segments);
1519
1381
  }
1520
1382
  async function ensureDirectory(directoryPath) {
1521
1383
  await promises.mkdir(directoryPath, { recursive: true });
@@ -1535,7 +1397,7 @@ async function writeJsonFileAtomic(filePath, value) {
1535
1397
  await writeTextFileAtomic(filePath, stableJsonString(value));
1536
1398
  }
1537
1399
  async function writeTextFileAtomic(filePath, value) {
1538
- await ensureDirectory(path6__default.default.dirname(filePath));
1400
+ await ensureDirectory(path7__default.default.dirname(filePath));
1539
1401
  const temporaryPath = `${filePath}.${crypto.randomUUID()}.tmp`;
1540
1402
  await promises.writeFile(temporaryPath, value, "utf8");
1541
1403
  await promises.rename(temporaryPath, filePath);
@@ -1544,7 +1406,7 @@ async function writeJsonFileExclusive(filePath, value) {
1544
1406
  await writeTextFileExclusive(filePath, stableJsonString(value));
1545
1407
  }
1546
1408
  async function writeTextFileExclusive(filePath, value) {
1547
- await ensureDirectory(path6__default.default.dirname(filePath));
1409
+ await ensureDirectory(path7__default.default.dirname(filePath));
1548
1410
  const handle = await promises.open(filePath, "wx");
1549
1411
  try {
1550
1412
  await handle.writeFile(value, "utf8");
@@ -1553,7 +1415,7 @@ async function writeTextFileExclusive(filePath, value) {
1553
1415
  }
1554
1416
  }
1555
1417
  async function writeBufferIfMissing(filePath, value) {
1556
- await ensureDirectory(path6__default.default.dirname(filePath));
1418
+ await ensureDirectory(path7__default.default.dirname(filePath));
1557
1419
  try {
1558
1420
  const handle = await promises.open(filePath, "wx");
1559
1421
  try {
@@ -1587,7 +1449,7 @@ function isAlreadyExistsError(error) {
1587
1449
  return error?.code === "EEXIST";
1588
1450
  }
1589
1451
  async function withFilesystemLock(lockPath, task) {
1590
- await ensureDirectory(path6__default.default.dirname(lockPath));
1452
+ await ensureDirectory(path7__default.default.dirname(lockPath));
1591
1453
  let attempt = 0;
1592
1454
  while (true) {
1593
1455
  try {
@@ -1599,7 +1461,7 @@ async function withFilesystemLock(lockPath, task) {
1599
1461
  }
1600
1462
  const delayMs = LOCK_RETRY_DELAYS_MS[Math.min(attempt, LOCK_RETRY_DELAYS_MS.length - 1)];
1601
1463
  attempt += 1;
1602
- await new Promise((resolve5) => setTimeout(resolve5, delayMs));
1464
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
1603
1465
  }
1604
1466
  }
1605
1467
  try {
@@ -1642,8 +1504,8 @@ async function readStructuredPayload(objectPath) {
1642
1504
  var FilesystemArtifactStore = class {
1643
1505
  constructor(rootPath) {
1644
1506
  this.rootPath = rootPath;
1645
- this.manifestsDirectory = path6__default.default.join(this.rootPath, "artifacts", "manifests");
1646
- this.objectsDirectory = path6__default.default.join(this.rootPath, "artifacts", "objects", "sha256");
1507
+ this.manifestsDirectory = path7__default.default.join(this.rootPath, "artifacts", "manifests");
1508
+ this.objectsDirectory = path7__default.default.join(this.rootPath, "artifacts", "objects", "sha256");
1647
1509
  }
1648
1510
  manifestsDirectory;
1649
1511
  objectsDirectory;
@@ -1868,7 +1730,7 @@ var FilesystemArtifactStore = class {
1868
1730
  }
1869
1731
  }
1870
1732
  manifestPath(artifactId) {
1871
- return path6__default.default.join(this.manifestsDirectory, `${encodePathSegment(artifactId)}.json`);
1733
+ return path7__default.default.join(this.manifestsDirectory, `${encodePathSegment(artifactId)}.json`);
1872
1734
  }
1873
1735
  };
1874
1736
  function createArtifactStore(rootPath) {
@@ -1963,31 +1825,31 @@ function oneOfSchema(members, options = {}) {
1963
1825
  }
1964
1826
 
1965
1827
  // ../protocol/src/validation.ts
1966
- function validateJsonSchema(schema, value, path16 = "$") {
1967
- return validateSchemaNode(schema, value, path16);
1828
+ function validateJsonSchema(schema, value, path17 = "$") {
1829
+ return validateSchemaNode(schema, value, path17);
1968
1830
  }
1969
- function validateSchemaNode(schema, value, path16) {
1831
+ function validateSchemaNode(schema, value, path17) {
1970
1832
  const issues = [];
1971
1833
  if ("const" in schema && !isJsonValueEqual(schema.const, value)) {
1972
1834
  issues.push({
1973
- path: path16,
1835
+ path: path17,
1974
1836
  message: `must equal ${JSON.stringify(schema.const)}`
1975
1837
  });
1976
1838
  return issues;
1977
1839
  }
1978
1840
  if (schema.enum !== void 0 && !schema.enum.some((candidate) => isJsonValueEqual(candidate, value))) {
1979
1841
  issues.push({
1980
- path: path16,
1842
+ path: path17,
1981
1843
  message: `must be one of ${schema.enum.map((candidate) => JSON.stringify(candidate)).join(", ")}`
1982
1844
  });
1983
1845
  return issues;
1984
1846
  }
1985
1847
  if (schema.oneOf !== void 0) {
1986
- const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path16));
1848
+ const branchIssues = schema.oneOf.map((member) => validateSchemaNode(member, value, path17));
1987
1849
  const validBranches = branchIssues.filter((current) => current.length === 0).length;
1988
1850
  if (validBranches !== 1) {
1989
1851
  issues.push({
1990
- path: path16,
1852
+ path: path17,
1991
1853
  message: validBranches === 0 ? "must match exactly one supported shape" : "matches multiple supported shapes"
1992
1854
  });
1993
1855
  return issues;
@@ -1995,11 +1857,11 @@ function validateSchemaNode(schema, value, path16) {
1995
1857
  }
1996
1858
  if (schema.anyOf !== void 0) {
1997
1859
  const hasMatch = schema.anyOf.some(
1998
- (member) => validateSchemaNode(member, value, path16).length === 0
1860
+ (member) => validateSchemaNode(member, value, path17).length === 0
1999
1861
  );
2000
1862
  if (!hasMatch) {
2001
1863
  issues.push({
2002
- path: path16,
1864
+ path: path17,
2003
1865
  message: "must match at least one supported shape"
2004
1866
  });
2005
1867
  return issues;
@@ -2007,7 +1869,7 @@ function validateSchemaNode(schema, value, path16) {
2007
1869
  }
2008
1870
  if (schema.allOf !== void 0) {
2009
1871
  for (const member of schema.allOf) {
2010
- issues.push(...validateSchemaNode(member, value, path16));
1872
+ issues.push(...validateSchemaNode(member, value, path17));
2011
1873
  }
2012
1874
  if (issues.length > 0) {
2013
1875
  return issues;
@@ -2015,7 +1877,7 @@ function validateSchemaNode(schema, value, path16) {
2015
1877
  }
2016
1878
  if (schema.type !== void 0 && !matchesSchemaType(schema.type, value)) {
2017
1879
  issues.push({
2018
- path: path16,
1880
+ path: path17,
2019
1881
  message: `must be ${describeSchemaType(schema.type)}`
2020
1882
  });
2021
1883
  return issues;
@@ -2023,19 +1885,19 @@ function validateSchemaNode(schema, value, path16) {
2023
1885
  if (typeof value === "string") {
2024
1886
  if (schema.minLength !== void 0 && value.length < schema.minLength) {
2025
1887
  issues.push({
2026
- path: path16,
1888
+ path: path17,
2027
1889
  message: `must have length >= ${String(schema.minLength)}`
2028
1890
  });
2029
1891
  }
2030
1892
  if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
2031
1893
  issues.push({
2032
- path: path16,
1894
+ path: path17,
2033
1895
  message: `must have length <= ${String(schema.maxLength)}`
2034
1896
  });
2035
1897
  }
2036
1898
  if (schema.pattern !== void 0 && !new RegExp(schema.pattern).test(value)) {
2037
1899
  issues.push({
2038
- path: path16,
1900
+ path: path17,
2039
1901
  message: `must match pattern ${schema.pattern}`
2040
1902
  });
2041
1903
  }
@@ -2044,25 +1906,25 @@ function validateSchemaNode(schema, value, path16) {
2044
1906
  if (typeof value === "number") {
2045
1907
  if (schema.minimum !== void 0 && value < schema.minimum) {
2046
1908
  issues.push({
2047
- path: path16,
1909
+ path: path17,
2048
1910
  message: `must be >= ${String(schema.minimum)}`
2049
1911
  });
2050
1912
  }
2051
1913
  if (schema.maximum !== void 0 && value > schema.maximum) {
2052
1914
  issues.push({
2053
- path: path16,
1915
+ path: path17,
2054
1916
  message: `must be <= ${String(schema.maximum)}`
2055
1917
  });
2056
1918
  }
2057
1919
  if (schema.exclusiveMinimum !== void 0 && value <= schema.exclusiveMinimum) {
2058
1920
  issues.push({
2059
- path: path16,
1921
+ path: path17,
2060
1922
  message: `must be > ${String(schema.exclusiveMinimum)}`
2061
1923
  });
2062
1924
  }
2063
1925
  if (schema.exclusiveMaximum !== void 0 && value >= schema.exclusiveMaximum) {
2064
1926
  issues.push({
2065
- path: path16,
1927
+ path: path17,
2066
1928
  message: `must be < ${String(schema.exclusiveMaximum)}`
2067
1929
  });
2068
1930
  }
@@ -2071,13 +1933,13 @@ function validateSchemaNode(schema, value, path16) {
2071
1933
  if (Array.isArray(value)) {
2072
1934
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
2073
1935
  issues.push({
2074
- path: path16,
1936
+ path: path17,
2075
1937
  message: `must have at least ${String(schema.minItems)} items`
2076
1938
  });
2077
1939
  }
2078
1940
  if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
2079
1941
  issues.push({
2080
- path: path16,
1942
+ path: path17,
2081
1943
  message: `must have at most ${String(schema.maxItems)} items`
2082
1944
  });
2083
1945
  }
@@ -2087,7 +1949,7 @@ function validateSchemaNode(schema, value, path16) {
2087
1949
  const key = JSON.stringify(item);
2088
1950
  if (seen.has(key)) {
2089
1951
  issues.push({
2090
- path: path16,
1952
+ path: path17,
2091
1953
  message: "must not contain duplicate items"
2092
1954
  });
2093
1955
  break;
@@ -2097,7 +1959,7 @@ function validateSchemaNode(schema, value, path16) {
2097
1959
  }
2098
1960
  if (schema.items !== void 0) {
2099
1961
  for (let index = 0; index < value.length; index += 1) {
2100
- issues.push(...validateSchemaNode(schema.items, value[index], `${path16}[${String(index)}]`));
1962
+ issues.push(...validateSchemaNode(schema.items, value[index], `${path17}[${String(index)}]`));
2101
1963
  }
2102
1964
  }
2103
1965
  return issues;
@@ -2107,7 +1969,7 @@ function validateSchemaNode(schema, value, path16) {
2107
1969
  for (const requiredKey of schema.required ?? []) {
2108
1970
  if (!(requiredKey in value)) {
2109
1971
  issues.push({
2110
- path: joinObjectPath(path16, requiredKey),
1972
+ path: joinObjectPath(path17, requiredKey),
2111
1973
  message: "is required"
2112
1974
  });
2113
1975
  }
@@ -2116,13 +1978,13 @@ function validateSchemaNode(schema, value, path16) {
2116
1978
  const propertySchema = properties[key];
2117
1979
  if (propertySchema !== void 0) {
2118
1980
  issues.push(
2119
- ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path16, key))
1981
+ ...validateSchemaNode(propertySchema, propertyValue, joinObjectPath(path17, key))
2120
1982
  );
2121
1983
  continue;
2122
1984
  }
2123
1985
  if (schema.additionalProperties === false) {
2124
1986
  issues.push({
2125
- path: joinObjectPath(path16, key),
1987
+ path: joinObjectPath(path17, key),
2126
1988
  message: "is not allowed"
2127
1989
  });
2128
1990
  continue;
@@ -2132,7 +1994,7 @@ function validateSchemaNode(schema, value, path16) {
2132
1994
  ...validateSchemaNode(
2133
1995
  schema.additionalProperties,
2134
1996
  propertyValue,
2135
- joinObjectPath(path16, key)
1997
+ joinObjectPath(path17, key)
2136
1998
  )
2137
1999
  );
2138
2000
  }
@@ -2376,8 +2238,8 @@ function matchesNetworkRecordFilters(record, filters) {
2376
2238
  }
2377
2239
  }
2378
2240
  if (filters.path !== void 0) {
2379
- const path16 = getParsedUrl().pathname;
2380
- if (!includesCaseInsensitive(path16, filters.path)) {
2241
+ const path17 = getParsedUrl().pathname;
2242
+ if (!includesCaseInsensitive(path17, filters.path)) {
2381
2243
  return false;
2382
2244
  }
2383
2245
  }
@@ -2851,7 +2713,7 @@ var networkRecordSchema = objectSchema(
2851
2713
  var networkQueryRecordSchema = objectSchema(
2852
2714
  {
2853
2715
  recordId: stringSchema({ minLength: 1 }),
2854
- actionId: stringSchema({ minLength: 1 }),
2716
+ capture: stringSchema({ minLength: 1 }),
2855
2717
  tags: arraySchema(stringSchema({ minLength: 1 }), {
2856
2718
  uniqueItems: true
2857
2719
  }),
@@ -3331,8 +3193,7 @@ var opensteerRecipeStepSchema = oneOfSchema(
3331
3193
  objectSchema(
3332
3194
  {
3333
3195
  kind: enumSchema(["goto"]),
3334
- url: stringSchema({ minLength: 1 }),
3335
- networkTag: stringSchema({ minLength: 1 })
3196
+ url: stringSchema({ minLength: 1 })
3336
3197
  },
3337
3198
  {
3338
3199
  title: "OpensteerAuthRecipeGotoStep",
@@ -3341,8 +3202,7 @@ var opensteerRecipeStepSchema = oneOfSchema(
3341
3202
  ),
3342
3203
  objectSchema(
3343
3204
  {
3344
- kind: enumSchema(["reload"]),
3345
- networkTag: stringSchema({ minLength: 1 })
3205
+ kind: enumSchema(["reload"])
3346
3206
  },
3347
3207
  {
3348
3208
  title: "OpensteerAuthRecipeReloadStep",
@@ -3559,7 +3419,7 @@ var opensteerNetworkQueryInputSchema = objectSchema(
3559
3419
  pageRef: pageRefSchema,
3560
3420
  recordId: stringSchema({ minLength: 1 }),
3561
3421
  requestId: stringSchema({ minLength: 1 }),
3562
- actionId: stringSchema({ minLength: 1 }),
3422
+ capture: stringSchema({ minLength: 1 }),
3563
3423
  tag: stringSchema({ minLength: 1 }),
3564
3424
  url: stringSchema({ minLength: 1 }),
3565
3425
  hostname: stringSchema({ minLength: 1 }),
@@ -3588,7 +3448,7 @@ var opensteerNetworkTagInputSchema = objectSchema(
3588
3448
  pageRef: pageRefSchema,
3589
3449
  recordId: stringSchema({ minLength: 1 }),
3590
3450
  requestId: stringSchema({ minLength: 1 }),
3591
- actionId: stringSchema({ minLength: 1 }),
3451
+ capture: stringSchema({ minLength: 1 }),
3592
3452
  tag: stringSchema({ minLength: 1 }),
3593
3453
  url: stringSchema({ minLength: 1 }),
3594
3454
  hostname: stringSchema({ minLength: 1 }),
@@ -3613,6 +3473,7 @@ var opensteerNetworkTagOutputSchema = objectSchema(
3613
3473
  );
3614
3474
  var opensteerNetworkClearInputSchema = objectSchema(
3615
3475
  {
3476
+ capture: stringSchema({ minLength: 1 }),
3616
3477
  tag: stringSchema({ minLength: 1 })
3617
3478
  },
3618
3479
  {
@@ -7464,7 +7325,7 @@ var opensteerPageCloseOutputSchema = objectSchema(
7464
7325
  var opensteerPageGotoInputSchema = objectSchema(
7465
7326
  {
7466
7327
  url: stringSchema(),
7467
- networkTag: stringSchema({ minLength: 1 })
7328
+ captureNetwork: stringSchema({ minLength: 1 })
7468
7329
  },
7469
7330
  {
7470
7331
  title: "OpensteerPageGotoInput",
@@ -7615,7 +7476,7 @@ var opensteerDomClickInputSchema = objectSchema(
7615
7476
  {
7616
7477
  target: opensteerTargetInputSchema,
7617
7478
  persistAsDescription: stringSchema(),
7618
- networkTag: stringSchema({ minLength: 1 })
7479
+ captureNetwork: stringSchema({ minLength: 1 })
7619
7480
  },
7620
7481
  {
7621
7482
  title: "OpensteerDomClickInput",
@@ -7626,7 +7487,7 @@ var opensteerDomHoverInputSchema = objectSchema(
7626
7487
  {
7627
7488
  target: opensteerTargetInputSchema,
7628
7489
  persistAsDescription: stringSchema(),
7629
- networkTag: stringSchema({ minLength: 1 })
7490
+ captureNetwork: stringSchema({ minLength: 1 })
7630
7491
  },
7631
7492
  {
7632
7493
  title: "OpensteerDomHoverInput",
@@ -7639,7 +7500,7 @@ var opensteerDomInputInputSchema = objectSchema(
7639
7500
  text: stringSchema(),
7640
7501
  pressEnter: { type: "boolean" },
7641
7502
  persistAsDescription: stringSchema(),
7642
- networkTag: stringSchema({ minLength: 1 })
7503
+ captureNetwork: stringSchema({ minLength: 1 })
7643
7504
  },
7644
7505
  {
7645
7506
  title: "OpensteerDomInputInput",
@@ -7652,7 +7513,7 @@ var opensteerDomScrollInputSchema = objectSchema(
7652
7513
  direction: enumSchema(["up", "down", "left", "right"]),
7653
7514
  amount: integerSchema({ minimum: 1 }),
7654
7515
  persistAsDescription: stringSchema(),
7655
- networkTag: stringSchema({ minLength: 1 })
7516
+ captureNetwork: stringSchema({ minLength: 1 })
7656
7517
  },
7657
7518
  {
7658
7519
  title: "OpensteerDomScrollInput",
@@ -7853,7 +7714,7 @@ var opensteerComputerExecuteInputSchema = objectSchema(
7853
7714
  {
7854
7715
  action: opensteerComputerActionSchema,
7855
7716
  screenshot: opensteerComputerScreenshotOptionsSchema,
7856
- networkTag: stringSchema({ minLength: 1 })
7717
+ captureNetwork: stringSchema({ minLength: 1 })
7857
7718
  },
7858
7719
  {
7859
7720
  title: "OpensteerComputerExecuteInput",
@@ -8468,9 +8329,9 @@ function compareByCreatedAtAndId(left, right) {
8468
8329
  var FilesystemRegistryStore = class {
8469
8330
  constructor(rootPath, registryRelativePath) {
8470
8331
  this.registryRelativePath = registryRelativePath;
8471
- const basePath = path6__default.default.join(rootPath, ...registryRelativePath);
8472
- this.recordsDirectory = path6__default.default.join(basePath, "records");
8473
- this.indexesDirectory = path6__default.default.join(basePath, "indexes", "by-key");
8332
+ const basePath = path7__default.default.join(rootPath, ...registryRelativePath);
8333
+ this.recordsDirectory = path7__default.default.join(basePath, "records");
8334
+ this.indexesDirectory = path7__default.default.join(basePath, "indexes", "by-key");
8474
8335
  }
8475
8336
  recordsDirectory;
8476
8337
  indexesDirectory;
@@ -8539,7 +8400,7 @@ var FilesystemRegistryStore = class {
8539
8400
  async readRecordsFromDirectory() {
8540
8401
  const files = await listJsonFiles(this.recordsDirectory);
8541
8402
  const records = await Promise.all(
8542
- files.map((fileName) => readJsonFile(path6__default.default.join(this.recordsDirectory, fileName)))
8403
+ files.map((fileName) => readJsonFile(path7__default.default.join(this.recordsDirectory, fileName)))
8543
8404
  );
8544
8405
  records.sort(compareByCreatedAtAndId);
8545
8406
  return records;
@@ -8571,17 +8432,17 @@ var FilesystemRegistryStore = class {
8571
8432
  return record;
8572
8433
  }
8573
8434
  recordPath(id) {
8574
- return path6__default.default.join(this.recordsDirectory, `${encodePathSegment(id)}.json`);
8435
+ return path7__default.default.join(this.recordsDirectory, `${encodePathSegment(id)}.json`);
8575
8436
  }
8576
8437
  indexPath(key, version) {
8577
- return path6__default.default.join(
8438
+ return path7__default.default.join(
8578
8439
  this.indexesDirectory,
8579
8440
  encodePathSegment(key),
8580
8441
  `${encodePathSegment(version)}.json`
8581
8442
  );
8582
8443
  }
8583
8444
  writeLockPath() {
8584
- return path6__default.default.join(path6__default.default.dirname(this.recordsDirectory), ".write.lock");
8445
+ return path7__default.default.join(path7__default.default.dirname(this.recordsDirectory), ".write.lock");
8585
8446
  }
8586
8447
  };
8587
8448
  var FilesystemDescriptorRegistry = class extends FilesystemRegistryStore {
@@ -8951,7 +8812,7 @@ var SqliteSavedNetworkStore = class {
8951
8812
  directoryInitialization;
8952
8813
  databaseInitialization;
8953
8814
  constructor(rootPath) {
8954
- this.databasePath = path6__default.default.join(rootPath, "registry", "saved-network.sqlite");
8815
+ this.databasePath = path7__default.default.join(rootPath, "registry", "saved-network.sqlite");
8955
8816
  }
8956
8817
  async initialize() {
8957
8818
  await this.ensureDatabaseDirectory();
@@ -8989,7 +8850,7 @@ var SqliteSavedNetworkStore = class {
8989
8850
  page_ref_key: pageRefKey,
8990
8851
  frame_ref: entry.record.frameRef ?? null,
8991
8852
  document_ref: entry.record.documentRef ?? null,
8992
- action_id: entry.actionId ?? null,
8853
+ capture: entry.capture ?? null,
8993
8854
  method: entry.record.method,
8994
8855
  method_lc: entry.record.method.toLowerCase(),
8995
8856
  url: entry.record.url,
@@ -9102,39 +8963,31 @@ var SqliteSavedNetworkStore = class {
9102
8963
  }
9103
8964
  async clear(input = {}) {
9104
8965
  const database = await this.requireDatabase();
9105
- const countAll = database.prepare(`
9106
- SELECT COUNT(*) AS cleared
9107
- FROM saved_network_records
9108
- `);
9109
- const countByTag = database.prepare(`
9110
- SELECT COUNT(DISTINCT record_id) AS cleared
9111
- FROM saved_network_tags
9112
- WHERE tag = @tag
9113
- `);
9114
- const deleteAllTags = database.prepare(`DELETE FROM saved_network_tags`);
8966
+ const countAll = database.prepare(`SELECT COUNT(*) AS cleared FROM saved_network_records`);
9115
8967
  const deleteAllRecords = database.prepare(`DELETE FROM saved_network_records`);
9116
- const deleteTag = database.prepare(`
9117
- DELETE FROM saved_network_tags
9118
- WHERE tag = @tag
8968
+ const { whereSql, parameters } = buildSavedNetworkWhere(input);
8969
+ const countFiltered = database.prepare(`
8970
+ SELECT COUNT(*) AS cleared
8971
+ FROM saved_network_records r
8972
+ ${whereSql}
9119
8973
  `);
9120
- const deleteOrphans = database.prepare(`
8974
+ const deleteFiltered = database.prepare(`
9121
8975
  DELETE FROM saved_network_records
9122
- WHERE NOT EXISTS (
9123
- SELECT 1
9124
- FROM saved_network_tags t
9125
- WHERE t.record_id = saved_network_records.record_id
8976
+ WHERE record_id IN (
8977
+ SELECT r.record_id
8978
+ FROM saved_network_records r
8979
+ ${whereSql}
9126
8980
  )
9127
8981
  `);
9128
8982
  return withSqliteTransaction(database, () => {
9129
- const tag = input.tag;
9130
- const cleared = tag === void 0 ? countAll.get().cleared : countByTag.get({ tag }).cleared;
9131
- if (tag === void 0) {
9132
- deleteAllTags.run();
8983
+ if (input.capture === void 0 && input.tag === void 0) {
8984
+ const cleared2 = countAll.get().cleared;
9133
8985
  deleteAllRecords.run();
9134
- return cleared;
8986
+ return cleared2;
9135
8987
  }
9136
- deleteTag.run({ tag });
9137
- deleteOrphans.run();
8988
+ const args = parameters;
8989
+ const cleared = countFiltered.get(...args).cleared;
8990
+ deleteFiltered.run(...args);
9138
8991
  return cleared;
9139
8992
  });
9140
8993
  }
@@ -9169,7 +9022,7 @@ var SqliteSavedNetworkStore = class {
9169
9022
  }
9170
9023
  }
9171
9024
  async ensureDatabaseDirectory() {
9172
- this.directoryInitialization ??= ensureDirectory(path6__default.default.dirname(this.databasePath)).catch(
9025
+ this.directoryInitialization ??= ensureDirectory(path7__default.default.dirname(this.databasePath)).catch(
9173
9026
  (error) => {
9174
9027
  this.directoryInitialization = void 0;
9175
9028
  throw error;
@@ -9189,7 +9042,7 @@ var SqliteSavedNetworkStore = class {
9189
9042
  page_ref_key TEXT NOT NULL,
9190
9043
  frame_ref TEXT,
9191
9044
  document_ref TEXT,
9192
- action_id TEXT,
9045
+ capture TEXT,
9193
9046
  method TEXT NOT NULL,
9194
9047
  method_lc TEXT NOT NULL,
9195
9048
  url TEXT NOT NULL,
@@ -9228,6 +9081,9 @@ var SqliteSavedNetworkStore = class {
9228
9081
  CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
9229
9082
  ON saved_network_records (saved_at DESC);
9230
9083
 
9084
+ CREATE INDEX IF NOT EXISTS saved_network_records_capture
9085
+ ON saved_network_records (capture);
9086
+
9231
9087
  CREATE TABLE IF NOT EXISTS saved_network_tags (
9232
9088
  record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
9233
9089
  tag TEXT NOT NULL,
@@ -9243,6 +9099,7 @@ var SqliteSavedNetworkStore = class {
9243
9099
  "capture_state",
9244
9100
  "TEXT NOT NULL DEFAULT 'complete'"
9245
9101
  );
9102
+ this.ensureColumn(database, "saved_network_records", "capture", "TEXT");
9246
9103
  this.ensureColumn(
9247
9104
  database,
9248
9105
  "saved_network_records",
@@ -9283,9 +9140,9 @@ function buildSavedNetworkWhere(input) {
9283
9140
  clauses.push("r.request_id = ?");
9284
9141
  parameters.push(input.requestId);
9285
9142
  }
9286
- if (input.actionId !== void 0) {
9287
- clauses.push("r.action_id = ?");
9288
- parameters.push(input.actionId);
9143
+ if (input.capture !== void 0) {
9144
+ clauses.push("r.capture = ?");
9145
+ parameters.push(input.capture);
9289
9146
  }
9290
9147
  if (input.tag !== void 0) {
9291
9148
  clauses.push(`
@@ -9347,7 +9204,7 @@ function buildSavedNetworkUpsertSql(bodyWriteMode) {
9347
9204
  page_ref_key,
9348
9205
  frame_ref,
9349
9206
  document_ref,
9350
- action_id,
9207
+ capture,
9351
9208
  method,
9352
9209
  method_lc,
9353
9210
  url,
@@ -9386,7 +9243,7 @@ function buildSavedNetworkUpsertSql(bodyWriteMode) {
9386
9243
  @page_ref_key,
9387
9244
  @frame_ref,
9388
9245
  @document_ref,
9389
- @action_id,
9246
+ @capture,
9390
9247
  @method,
9391
9248
  @method_lc,
9392
9249
  @url,
@@ -9423,7 +9280,7 @@ function buildSavedNetworkUpsertSql(bodyWriteMode) {
9423
9280
  page_ref_key = excluded.page_ref_key,
9424
9281
  frame_ref = excluded.frame_ref,
9425
9282
  document_ref = excluded.document_ref,
9426
- action_id = excluded.action_id,
9283
+ capture = excluded.capture,
9427
9284
  method = excluded.method,
9428
9285
  method_lc = excluded.method_lc,
9429
9286
  url = excluded.url,
@@ -9518,7 +9375,7 @@ function inflateSavedNetworkRow(row, includeBodies) {
9518
9375
  }
9519
9376
  return {
9520
9377
  recordId: row.record_id,
9521
- ...row.action_id === null ? {} : { actionId: row.action_id },
9378
+ ...row.capture === null ? {} : { capture: row.capture },
9522
9379
  ...row.tags === null || row.tags.length === 0 ? {} : { tags: row.tags.split(TAG_DELIMITER).filter((tag) => tag.length > 0) },
9523
9380
  savedAt: row.saved_at,
9524
9381
  record
@@ -9555,6 +9412,546 @@ function withSqliteTransaction(database, task) {
9555
9412
  function createSavedNetworkStore(rootPath) {
9556
9413
  return new SqliteSavedNetworkStore(rootPath);
9557
9414
  }
9415
+
9416
+ // ../runtime-core/src/observation-utils.ts
9417
+ var REDACTED = "[REDACTED]";
9418
+ 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;
9419
+ var SENSITIVE_VALUE_PATTERNS = [
9420
+ /\bsk-[A-Za-z0-9_-]{20,}\b/g,
9421
+ /\bAIza[0-9A-Za-z_-]{20,}\b/g,
9422
+ /\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/g,
9423
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g,
9424
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi
9425
+ ];
9426
+ function normalizeObservationContext(context) {
9427
+ if (context === void 0) {
9428
+ return void 0;
9429
+ }
9430
+ const normalized = {
9431
+ ...context.sessionRef === void 0 ? {} : { sessionRef: context.sessionRef },
9432
+ ...context.pageRef === void 0 ? {} : { pageRef: context.pageRef },
9433
+ ...context.frameRef === void 0 ? {} : { frameRef: context.frameRef },
9434
+ ...context.documentRef === void 0 ? {} : { documentRef: context.documentRef },
9435
+ ...context.documentEpoch === void 0 ? {} : { documentEpoch: context.documentEpoch }
9436
+ };
9437
+ return Object.keys(normalized).length === 0 ? void 0 : normalized;
9438
+ }
9439
+ function createObservationRedactor(config) {
9440
+ const state = createRedactionState(config);
9441
+ return {
9442
+ redactText(value) {
9443
+ return redactString(value, state);
9444
+ },
9445
+ redactJson(value) {
9446
+ return value === void 0 ? void 0 : redactUnknown(value, state, /* @__PURE__ */ new WeakSet());
9447
+ },
9448
+ redactError(error) {
9449
+ if (error === void 0) {
9450
+ return void 0;
9451
+ }
9452
+ return {
9453
+ ...error.code === void 0 ? {} : { code: redactString(error.code, state) },
9454
+ message: redactString(error.message, state),
9455
+ ...error.retriable === void 0 ? {} : { retriable: error.retriable },
9456
+ ...error.details === void 0 ? {} : { details: toCanonicalJsonValue(redactUnknown(error.details, state, /* @__PURE__ */ new WeakSet())) }
9457
+ };
9458
+ },
9459
+ redactLabels(labels) {
9460
+ if (labels === void 0) {
9461
+ return void 0;
9462
+ }
9463
+ const next = Object.entries(labels).reduce(
9464
+ (accumulator, [key, value]) => {
9465
+ accumulator[key] = isSensitiveKey(key, state) ? REDACTED : redactString(value, state);
9466
+ return accumulator;
9467
+ },
9468
+ {}
9469
+ );
9470
+ return Object.keys(next).length === 0 ? void 0 : next;
9471
+ },
9472
+ redactTraceContext(traceContext) {
9473
+ if (traceContext === void 0) {
9474
+ return void 0;
9475
+ }
9476
+ const next = {
9477
+ ...traceContext.traceparent === void 0 ? {} : { traceparent: redactString(traceContext.traceparent, state) },
9478
+ ...traceContext.baggage === void 0 ? {} : { baggage: redactString(traceContext.baggage, state) }
9479
+ };
9480
+ return Object.keys(next).length === 0 ? void 0 : next;
9481
+ }
9482
+ };
9483
+ }
9484
+ function createRedactionState(config) {
9485
+ return {
9486
+ sensitiveKeys: new Set(
9487
+ (config?.redaction?.sensitiveKeys ?? []).map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0)
9488
+ ),
9489
+ sensitiveValues: [
9490
+ ...new Set(
9491
+ (config?.redaction?.sensitiveValues ?? []).map((value) => value.trim()).filter((value) => value.length > 0)
9492
+ )
9493
+ ]
9494
+ };
9495
+ }
9496
+ function redactUnknown(value, state, seen) {
9497
+ if (value === null || value === void 0) {
9498
+ return value;
9499
+ }
9500
+ if (typeof value === "string") {
9501
+ return redactString(value, state);
9502
+ }
9503
+ if (typeof value !== "object") {
9504
+ return value;
9505
+ }
9506
+ if (seen.has(value)) {
9507
+ return REDACTED;
9508
+ }
9509
+ seen.add(value);
9510
+ if (Array.isArray(value)) {
9511
+ return value.map((entry) => redactUnknown(entry, state, seen));
9512
+ }
9513
+ const next = {};
9514
+ for (const [key, nestedValue] of Object.entries(value)) {
9515
+ next[key] = isSensitiveKey(key, state) ? REDACTED : redactUnknown(nestedValue, state, seen);
9516
+ }
9517
+ return next;
9518
+ }
9519
+ function redactString(value, state) {
9520
+ let next = value;
9521
+ for (const secret of state.sensitiveValues) {
9522
+ next = next.split(secret).join(REDACTED);
9523
+ }
9524
+ for (const pattern of SENSITIVE_VALUE_PATTERNS) {
9525
+ next = next.replace(pattern, REDACTED);
9526
+ }
9527
+ return redactUrlString(next, state);
9528
+ }
9529
+ function redactUrlString(value, state) {
9530
+ let parsed;
9531
+ try {
9532
+ parsed = new URL(value);
9533
+ } catch {
9534
+ return value;
9535
+ }
9536
+ let changed = false;
9537
+ if (parsed.username) {
9538
+ parsed.username = REDACTED;
9539
+ changed = true;
9540
+ }
9541
+ if (parsed.password) {
9542
+ parsed.password = REDACTED;
9543
+ changed = true;
9544
+ }
9545
+ for (const [key] of parsed.searchParams) {
9546
+ if (!isSensitiveKey(key, state)) {
9547
+ continue;
9548
+ }
9549
+ parsed.searchParams.set(key, REDACTED);
9550
+ changed = true;
9551
+ }
9552
+ return changed ? parsed.toString() : value;
9553
+ }
9554
+ function isSensitiveKey(key, state) {
9555
+ return state.sensitiveKeys.has(key.trim().toLowerCase()) || SENSITIVE_KEY_PATTERN.test(key);
9556
+ }
9557
+
9558
+ // ../runtime-core/src/observations.ts
9559
+ function normalizeObservabilityConfig(input) {
9560
+ const profile = input?.profile ?? "diagnostic";
9561
+ const labels = input?.labels === void 0 ? void 0 : Object.entries(input.labels).reduce((accumulator, [key, value]) => {
9562
+ const normalizedKey = key.trim();
9563
+ const normalizedValue = value.trim();
9564
+ if (normalizedKey.length === 0 || normalizedValue.length === 0) {
9565
+ return accumulator;
9566
+ }
9567
+ if (Object.keys(accumulator).length >= 20) {
9568
+ return accumulator;
9569
+ }
9570
+ accumulator[normalizedKey] = normalizedValue;
9571
+ return accumulator;
9572
+ }, {});
9573
+ const redaction = input?.redaction === void 0 ? void 0 : {
9574
+ ...input.redaction.sensitiveKeys === void 0 ? {} : {
9575
+ sensitiveKeys: input.redaction.sensitiveKeys.map((value) => value.trim()).filter((value) => value.length > 0)
9576
+ },
9577
+ ...input.redaction.sensitiveValues === void 0 ? {} : {
9578
+ sensitiveValues: input.redaction.sensitiveValues.map((value) => value.trim()).filter((value) => value.length > 0)
9579
+ }
9580
+ };
9581
+ return {
9582
+ profile,
9583
+ ...labels === void 0 || Object.keys(labels).length === 0 ? {} : { labels },
9584
+ ...input?.traceContext === void 0 ? {} : {
9585
+ traceContext: {
9586
+ ...input.traceContext.traceparent === void 0 ? {} : { traceparent: input.traceContext.traceparent.trim() },
9587
+ ...input.traceContext.baggage === void 0 ? {} : { baggage: input.traceContext.baggage.trim() }
9588
+ }
9589
+ },
9590
+ ...redaction === void 0 ? {} : { redaction }
9591
+ };
9592
+ }
9593
+ function eventFileName(sequence) {
9594
+ return `${String(sequence).padStart(12, "0")}.json`;
9595
+ }
9596
+ var FilesystemSessionSink = class {
9597
+ constructor(store, sessionId) {
9598
+ this.store = store;
9599
+ this.sessionId = sessionId;
9600
+ }
9601
+ append(input) {
9602
+ return this.store.appendEvent(this.sessionId, input);
9603
+ }
9604
+ appendBatch(input) {
9605
+ return this.store.appendEvents(this.sessionId, input);
9606
+ }
9607
+ writeArtifact(input) {
9608
+ return this.store.writeArtifact(this.sessionId, input);
9609
+ }
9610
+ async flush() {
9611
+ }
9612
+ close(reason) {
9613
+ return this.store.closeSession(this.sessionId, reason);
9614
+ }
9615
+ };
9616
+ var FilesystemObservationStoreImpl = class {
9617
+ constructor(rootPath, artifacts) {
9618
+ this.rootPath = rootPath;
9619
+ this.artifacts = artifacts;
9620
+ this.sessionsDirectory = path7__default.default.join(this.rootPath, "observations", "sessions");
9621
+ }
9622
+ sessionsDirectory;
9623
+ redactors = /* @__PURE__ */ new Map();
9624
+ async initialize() {
9625
+ await ensureDirectory(this.sessionsDirectory);
9626
+ }
9627
+ async openSession(input) {
9628
+ const sessionId = normalizeNonEmptyString("sessionId", input.sessionId);
9629
+ const openedAt = normalizeTimestamp("openedAt", input.openedAt ?? Date.now());
9630
+ const config = normalizeObservabilityConfig(input.config);
9631
+ const redactor = createObservationRedactor(config);
9632
+ this.redactors.set(sessionId, redactor);
9633
+ const redactedLabels = redactor.redactLabels(config.labels);
9634
+ const redactedTraceContext = redactor.redactTraceContext(config.traceContext);
9635
+ await withFilesystemLock(this.sessionLockPath(sessionId), async () => {
9636
+ const existing = await this.reconcileSessionManifest(sessionId);
9637
+ if (existing === void 0) {
9638
+ await ensureDirectory(this.sessionEventsDirectory(sessionId));
9639
+ await ensureDirectory(this.sessionArtifactsDirectory(sessionId));
9640
+ const session = {
9641
+ sessionId,
9642
+ profile: config.profile,
9643
+ ...redactedLabels === void 0 ? {} : { labels: redactedLabels },
9644
+ ...redactedTraceContext === void 0 ? {} : { traceContext: redactedTraceContext },
9645
+ openedAt,
9646
+ updatedAt: openedAt,
9647
+ currentSequence: 0,
9648
+ eventCount: 0,
9649
+ artifactCount: 0
9650
+ };
9651
+ await writeJsonFileExclusive(this.sessionManifestPath(sessionId), session);
9652
+ return;
9653
+ }
9654
+ const patched = {
9655
+ ...existing,
9656
+ profile: config.profile,
9657
+ ...redactedLabels === void 0 ? {} : { labels: redactedLabels },
9658
+ ...redactedTraceContext === void 0 ? {} : { traceContext: redactedTraceContext },
9659
+ updatedAt: Math.max(existing.updatedAt, openedAt)
9660
+ };
9661
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), patched);
9662
+ });
9663
+ return new FilesystemSessionSink(this, sessionId);
9664
+ }
9665
+ async getSession(sessionId) {
9666
+ const manifestPath = this.sessionManifestPath(sessionId);
9667
+ if (!await pathExists(manifestPath)) {
9668
+ return void 0;
9669
+ }
9670
+ return readJsonFile(manifestPath);
9671
+ }
9672
+ async appendEvent(sessionId, input) {
9673
+ const [event] = await this.appendEvents(sessionId, [input]);
9674
+ if (event === void 0) {
9675
+ throw new Error(`failed to append observation event for session ${sessionId}`);
9676
+ }
9677
+ return event;
9678
+ }
9679
+ async appendEvents(sessionId, input) {
9680
+ if (input.length === 0) {
9681
+ return [];
9682
+ }
9683
+ return withFilesystemLock(this.sessionLockPath(sessionId), async () => {
9684
+ const session = await this.reconcileSessionManifest(sessionId);
9685
+ if (session === void 0) {
9686
+ throw new Error(`observation session ${sessionId} was not found`);
9687
+ }
9688
+ const redactor = this.redactors.get(sessionId) ?? createObservationRedactor(void 0);
9689
+ const events = [];
9690
+ let sequence = session.currentSequence;
9691
+ let updatedAt = session.updatedAt;
9692
+ for (const raw of input) {
9693
+ sequence += 1;
9694
+ const createdAt = normalizeTimestamp("createdAt", raw.createdAt);
9695
+ const context = normalizeObservationContext(raw.context);
9696
+ const redactedData = raw.data === void 0 ? void 0 : redactor.redactJson(toCanonicalJsonValue(raw.data));
9697
+ const redactedError = redactor.redactError(raw.error);
9698
+ const event = {
9699
+ eventId: normalizeNonEmptyString(
9700
+ "eventId",
9701
+ raw.eventId ?? `observation:${sessionId}:${String(sequence).padStart(12, "0")}`
9702
+ ),
9703
+ sessionId,
9704
+ sequence,
9705
+ kind: raw.kind,
9706
+ phase: raw.phase,
9707
+ createdAt,
9708
+ correlationId: normalizeNonEmptyString("correlationId", raw.correlationId),
9709
+ ...raw.spanId === void 0 ? {} : { spanId: normalizeNonEmptyString("spanId", raw.spanId) },
9710
+ ...raw.parentSpanId === void 0 ? {} : { parentSpanId: normalizeNonEmptyString("parentSpanId", raw.parentSpanId) },
9711
+ ...context === void 0 ? {} : { context },
9712
+ ...redactedData === void 0 ? {} : { data: redactedData },
9713
+ ...redactedError === void 0 ? {} : { error: redactedError },
9714
+ ...raw.artifactIds === void 0 || raw.artifactIds.length === 0 ? {} : { artifactIds: [...raw.artifactIds] }
9715
+ };
9716
+ await writeJsonFileExclusive(
9717
+ path7__default.default.join(this.sessionEventsDirectory(sessionId), eventFileName(sequence)),
9718
+ event
9719
+ );
9720
+ updatedAt = Math.max(updatedAt, createdAt);
9721
+ events.push(event);
9722
+ }
9723
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), {
9724
+ ...session,
9725
+ currentSequence: sequence,
9726
+ eventCount: session.eventCount + events.length,
9727
+ updatedAt
9728
+ });
9729
+ return events;
9730
+ });
9731
+ }
9732
+ async writeArtifact(sessionId, input) {
9733
+ return withFilesystemLock(this.sessionLockPath(sessionId), async () => {
9734
+ const session = await this.reconcileSessionManifest(sessionId);
9735
+ if (session === void 0) {
9736
+ throw new Error(`observation session ${sessionId} was not found`);
9737
+ }
9738
+ const redactor = this.redactors.get(sessionId) ?? createObservationRedactor(void 0);
9739
+ const createdAt = normalizeTimestamp("createdAt", input.createdAt);
9740
+ const context = normalizeObservationContext(input.context);
9741
+ const redactedStorageKey = input.storageKey === void 0 ? void 0 : redactor.redactText(input.storageKey);
9742
+ const redactedMetadata = input.metadata === void 0 ? void 0 : redactor.redactJson(toCanonicalJsonValue(input.metadata));
9743
+ const artifact = {
9744
+ artifactId: normalizeNonEmptyString("artifactId", input.artifactId),
9745
+ sessionId,
9746
+ kind: input.kind,
9747
+ createdAt,
9748
+ ...context === void 0 ? {} : { context },
9749
+ ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
9750
+ ...input.byteLength === void 0 ? {} : { byteLength: input.byteLength },
9751
+ ...input.sha256 === void 0 ? {} : { sha256: input.sha256 },
9752
+ ...input.opensteerArtifactId === void 0 ? {} : { opensteerArtifactId: input.opensteerArtifactId },
9753
+ ...redactedStorageKey === void 0 ? {} : { storageKey: redactedStorageKey },
9754
+ ...redactedMetadata === void 0 ? {} : { metadata: redactedMetadata }
9755
+ };
9756
+ const artifactPath = this.sessionArtifactPath(sessionId, artifact.artifactId);
9757
+ if (!await pathExists(artifactPath)) {
9758
+ await writeJsonFileExclusive(artifactPath, artifact);
9759
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), {
9760
+ ...session,
9761
+ artifactCount: session.artifactCount + 1,
9762
+ updatedAt: Math.max(session.updatedAt, createdAt)
9763
+ });
9764
+ }
9765
+ return artifact;
9766
+ });
9767
+ }
9768
+ async listEvents(sessionId, input = {}) {
9769
+ const directoryPath = this.sessionEventsDirectory(sessionId);
9770
+ if (!await pathExists(directoryPath)) {
9771
+ return [];
9772
+ }
9773
+ const files = await listJsonFiles(directoryPath);
9774
+ const events = await Promise.all(
9775
+ files.map((fileName) => readJsonFile(path7__default.default.join(directoryPath, fileName)))
9776
+ );
9777
+ const filtered = events.filter((event) => {
9778
+ if (input.kind !== void 0 && event.kind !== input.kind) return false;
9779
+ if (input.phase !== void 0 && event.phase !== input.phase) return false;
9780
+ if (input.correlationId !== void 0 && event.correlationId !== input.correlationId) {
9781
+ return false;
9782
+ }
9783
+ if (input.pageRef !== void 0 && event.context?.pageRef !== input.pageRef) return false;
9784
+ if (input.afterSequence !== void 0 && event.sequence <= input.afterSequence) return false;
9785
+ if (input.from !== void 0 && event.createdAt < input.from) return false;
9786
+ if (input.to !== void 0 && event.createdAt > input.to) return false;
9787
+ return true;
9788
+ });
9789
+ if (input.limit === void 0 || filtered.length <= input.limit) {
9790
+ return filtered;
9791
+ }
9792
+ return filtered.slice(-input.limit);
9793
+ }
9794
+ async listArtifacts(sessionId, input = {}) {
9795
+ const directoryPath = this.sessionArtifactsDirectory(sessionId);
9796
+ if (!await pathExists(directoryPath)) {
9797
+ return [];
9798
+ }
9799
+ const files = await listJsonFiles(directoryPath);
9800
+ const artifacts = await Promise.all(
9801
+ files.map(
9802
+ (fileName) => readJsonFile(path7__default.default.join(directoryPath, fileName))
9803
+ )
9804
+ );
9805
+ const filtered = artifacts.filter((artifact) => {
9806
+ if (input.kind !== void 0 && artifact.kind !== input.kind) return false;
9807
+ if (input.pageRef !== void 0 && artifact.context?.pageRef !== input.pageRef) return false;
9808
+ return true;
9809
+ });
9810
+ if (input.limit === void 0 || filtered.length <= input.limit) {
9811
+ return filtered;
9812
+ }
9813
+ return filtered.slice(-input.limit);
9814
+ }
9815
+ async getArtifact(sessionId, artifactId) {
9816
+ const artifactPath = this.sessionArtifactPath(sessionId, artifactId);
9817
+ if (!await pathExists(artifactPath)) {
9818
+ return void 0;
9819
+ }
9820
+ return readJsonFile(artifactPath);
9821
+ }
9822
+ async closeSession(sessionId, _reason) {
9823
+ await withFilesystemLock(this.sessionLockPath(sessionId), async () => {
9824
+ const session = await this.reconcileSessionManifest(sessionId);
9825
+ if (session === void 0 || session.closedAt !== void 0) {
9826
+ return;
9827
+ }
9828
+ const now = Date.now();
9829
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), {
9830
+ ...session,
9831
+ updatedAt: Math.max(session.updatedAt, now),
9832
+ closedAt: now
9833
+ });
9834
+ });
9835
+ this.redactors.delete(sessionId);
9836
+ }
9837
+ async writeArtifactFromManifest(sessionId, manifest, kind, metadata) {
9838
+ return this.writeArtifact(sessionId, {
9839
+ artifactId: manifest.artifactId,
9840
+ kind,
9841
+ createdAt: manifest.createdAt,
9842
+ context: manifest.scope,
9843
+ mediaType: manifest.mediaType,
9844
+ byteLength: manifest.byteLength,
9845
+ sha256: manifest.sha256,
9846
+ opensteerArtifactId: manifest.artifactId,
9847
+ storageKey: manifestToExternalBinaryLocation(this.rootPath, manifest).uri,
9848
+ ...metadata === void 0 ? {} : { metadata }
9849
+ });
9850
+ }
9851
+ async ensureArtifactLinked(sessionId, manifest) {
9852
+ const existing = await this.getArtifact(sessionId, manifest.artifactId);
9853
+ if (existing !== void 0) {
9854
+ return existing;
9855
+ }
9856
+ const kind = toObservationArtifactKind(manifest.kind);
9857
+ return this.writeArtifactFromManifest(sessionId, manifest, kind);
9858
+ }
9859
+ async hydrateArtifactManifests(artifactIds) {
9860
+ return (await Promise.all(
9861
+ artifactIds.map(async (artifactId) => this.artifacts.getManifest(artifactId))
9862
+ )).filter((value) => value !== void 0);
9863
+ }
9864
+ sessionDirectory(sessionId) {
9865
+ return path7__default.default.join(this.sessionsDirectory, encodePathSegment(sessionId));
9866
+ }
9867
+ sessionManifestPath(sessionId) {
9868
+ return path7__default.default.join(this.sessionDirectory(sessionId), "session.json");
9869
+ }
9870
+ sessionEventsDirectory(sessionId) {
9871
+ return path7__default.default.join(this.sessionDirectory(sessionId), "events");
9872
+ }
9873
+ sessionArtifactsDirectory(sessionId) {
9874
+ return path7__default.default.join(this.sessionDirectory(sessionId), "artifacts");
9875
+ }
9876
+ sessionArtifactPath(sessionId, artifactId) {
9877
+ return path7__default.default.join(
9878
+ this.sessionArtifactsDirectory(sessionId),
9879
+ `${encodePathSegment(artifactId)}.json`
9880
+ );
9881
+ }
9882
+ sessionLockPath(sessionId) {
9883
+ return path7__default.default.join(this.sessionDirectory(sessionId), ".lock");
9884
+ }
9885
+ async reconcileSessionManifest(sessionId) {
9886
+ const session = await this.getSession(sessionId);
9887
+ if (session === void 0) {
9888
+ return void 0;
9889
+ }
9890
+ const [hasEventDirectory, hasArtifactDirectory] = await Promise.all([
9891
+ pathExists(this.sessionEventsDirectory(sessionId)),
9892
+ pathExists(this.sessionArtifactsDirectory(sessionId))
9893
+ ]);
9894
+ const [eventFiles, artifactFiles] = await Promise.all([
9895
+ hasEventDirectory ? listJsonFiles(this.sessionEventsDirectory(sessionId)) : Promise.resolve([]),
9896
+ hasArtifactDirectory ? listJsonFiles(this.sessionArtifactsDirectory(sessionId)) : Promise.resolve([])
9897
+ ]);
9898
+ const currentSequence = eventFiles.reduce((maxSequence, fileName) => {
9899
+ const parsed = Number.parseInt(fileName.replace(/\.json$/u, ""), 10);
9900
+ return Number.isFinite(parsed) ? Math.max(maxSequence, parsed) : maxSequence;
9901
+ }, 0);
9902
+ const eventCount = eventFiles.length;
9903
+ const artifactCount = artifactFiles.length;
9904
+ if (session.currentSequence === currentSequence && session.eventCount === eventCount && session.artifactCount === artifactCount) {
9905
+ return session;
9906
+ }
9907
+ const [events, artifacts] = await Promise.all([
9908
+ Promise.all(
9909
+ eventFiles.map(
9910
+ (fileName) => readJsonFile(
9911
+ path7__default.default.join(this.sessionEventsDirectory(sessionId), fileName)
9912
+ )
9913
+ )
9914
+ ),
9915
+ Promise.all(
9916
+ artifactFiles.map(
9917
+ (fileName) => readJsonFile(
9918
+ path7__default.default.join(this.sessionArtifactsDirectory(sessionId), fileName)
9919
+ )
9920
+ )
9921
+ )
9922
+ ]);
9923
+ const updatedAt = Math.max(
9924
+ session.openedAt,
9925
+ session.closedAt ?? 0,
9926
+ ...events.map((event) => event.createdAt),
9927
+ ...artifacts.map((artifact) => artifact.createdAt)
9928
+ );
9929
+ const reconciled = {
9930
+ ...session,
9931
+ currentSequence,
9932
+ eventCount,
9933
+ artifactCount,
9934
+ updatedAt
9935
+ };
9936
+ await writeJsonFileAtomic(this.sessionManifestPath(sessionId), reconciled);
9937
+ return reconciled;
9938
+ }
9939
+ };
9940
+ function toObservationArtifactKind(kind) {
9941
+ switch (kind) {
9942
+ case "screenshot":
9943
+ return "screenshot";
9944
+ case "dom-snapshot":
9945
+ return "dom-snapshot";
9946
+ case "html-snapshot":
9947
+ return "html-snapshot";
9948
+ default:
9949
+ return "other";
9950
+ }
9951
+ }
9952
+ function createObservationStore(rootPath, artifacts) {
9953
+ return new FilesystemObservationStoreImpl(rootPath, artifacts);
9954
+ }
9558
9955
  function normalizeContext(context) {
9559
9956
  return {
9560
9957
  ...context?.sessionRef === void 0 ? {} : { sessionRef: context.sessionRef },
@@ -9571,7 +9968,7 @@ var FilesystemTraceStore = class {
9571
9968
  constructor(rootPath, artifacts) {
9572
9969
  this.rootPath = rootPath;
9573
9970
  this.artifacts = artifacts;
9574
- this.runsDirectory = path6__default.default.join(this.rootPath, "traces", "runs");
9971
+ this.runsDirectory = path7__default.default.join(this.rootPath, "traces", "runs");
9575
9972
  }
9576
9973
  runsDirectory;
9577
9974
  async initialize() {
@@ -9648,7 +10045,7 @@ var FilesystemTraceStore = class {
9648
10045
  ...input.error === void 0 ? {} : { error: input.error }
9649
10046
  };
9650
10047
  await writeJsonFileExclusive(
9651
- path6__default.default.join(this.runEntriesDirectory(runId), sequenceFileName(sequence)),
10048
+ path7__default.default.join(this.runEntriesDirectory(runId), sequenceFileName(sequence)),
9652
10049
  entry
9653
10050
  );
9654
10051
  await writeJsonFileAtomic(this.runManifestPath(runId), {
@@ -9667,7 +10064,7 @@ var FilesystemTraceStore = class {
9667
10064
  const files = await listJsonFiles(entriesDirectory);
9668
10065
  return Promise.all(
9669
10066
  files.map(
9670
- (fileName) => readJsonFile(path6__default.default.join(entriesDirectory, fileName))
10067
+ (fileName) => readJsonFile(path7__default.default.join(entriesDirectory, fileName))
9671
10068
  )
9672
10069
  );
9673
10070
  }
@@ -9713,16 +10110,16 @@ var FilesystemTraceStore = class {
9713
10110
  return { trace, artifacts };
9714
10111
  }
9715
10112
  runDirectory(runId) {
9716
- return path6__default.default.join(this.runsDirectory, encodeURIComponent(runId));
10113
+ return path7__default.default.join(this.runsDirectory, encodeURIComponent(runId));
9717
10114
  }
9718
10115
  runEntriesDirectory(runId) {
9719
- return path6__default.default.join(this.runDirectory(runId), "entries");
10116
+ return path7__default.default.join(this.runDirectory(runId), "entries");
9720
10117
  }
9721
10118
  runManifestPath(runId) {
9722
- return path6__default.default.join(this.runDirectory(runId), "manifest.json");
10119
+ return path7__default.default.join(this.runDirectory(runId), "manifest.json");
9723
10120
  }
9724
10121
  runWriteLockPath(runId) {
9725
- return path6__default.default.join(this.runDirectory(runId), ".append.lock");
10122
+ return path7__default.default.join(this.runDirectory(runId), ".append.lock");
9726
10123
  }
9727
10124
  };
9728
10125
  function createTraceStore(rootPath, artifacts) {
@@ -9736,7 +10133,7 @@ function normalizeWorkspaceId(workspace) {
9736
10133
  return encodePathSegment(workspace);
9737
10134
  }
9738
10135
  function resolveFilesystemWorkspacePath(input) {
9739
- return path6__default.default.join(
10136
+ return path7__default.default.join(
9740
10137
  input.rootDir,
9741
10138
  ".opensteer",
9742
10139
  "workspaces",
@@ -9745,17 +10142,18 @@ function resolveFilesystemWorkspacePath(input) {
9745
10142
  }
9746
10143
  async function createFilesystemOpensteerWorkspace(options) {
9747
10144
  await ensureDirectory(options.rootPath);
9748
- const manifestPath = path6__default.default.join(options.rootPath, "workspace.json");
9749
- const browserPath = path6__default.default.join(options.rootPath, "browser");
9750
- const browserManifestPath = path6__default.default.join(browserPath, "manifest.json");
9751
- const browserUserDataDir = path6__default.default.join(browserPath, "user-data");
9752
- const livePath = path6__default.default.join(options.rootPath, "live");
9753
- const liveLocalPath = path6__default.default.join(livePath, "local.json");
9754
- const liveCloudPath = path6__default.default.join(livePath, "cloud.json");
9755
- const artifactsPath = path6__default.default.join(options.rootPath, "artifacts");
9756
- const tracesPath = path6__default.default.join(options.rootPath, "traces");
9757
- const registryPath = path6__default.default.join(options.rootPath, "registry");
9758
- const lockPath = path6__default.default.join(options.rootPath, ".lock");
10145
+ const manifestPath = path7__default.default.join(options.rootPath, "workspace.json");
10146
+ const browserPath = path7__default.default.join(options.rootPath, "browser");
10147
+ const browserManifestPath = path7__default.default.join(browserPath, "manifest.json");
10148
+ const browserUserDataDir = path7__default.default.join(browserPath, "user-data");
10149
+ const livePath = path7__default.default.join(options.rootPath, "live");
10150
+ const liveLocalPath = path7__default.default.join(livePath, "local.json");
10151
+ const liveCloudPath = path7__default.default.join(livePath, "cloud.json");
10152
+ const artifactsPath = path7__default.default.join(options.rootPath, "artifacts");
10153
+ const tracesPath = path7__default.default.join(options.rootPath, "traces");
10154
+ const observationsPath = path7__default.default.join(options.rootPath, "observations");
10155
+ const registryPath = path7__default.default.join(options.rootPath, "registry");
10156
+ const lockPath = path7__default.default.join(options.rootPath, ".lock");
9759
10157
  let manifest;
9760
10158
  if (await pathExists(manifestPath)) {
9761
10159
  manifest = await readJsonFile(manifestPath);
@@ -9769,6 +10167,17 @@ async function createFilesystemOpensteerWorkspace(options) {
9769
10167
  `workspace ${options.rootPath} uses unsupported version ${String(manifest.version)}`
9770
10168
  );
9771
10169
  }
10170
+ if (manifest.paths.observations === void 0) {
10171
+ manifest = {
10172
+ ...manifest,
10173
+ updatedAt: Date.now(),
10174
+ paths: {
10175
+ ...manifest.paths,
10176
+ observations: "observations"
10177
+ }
10178
+ };
10179
+ await writeJsonFileAtomic(manifestPath, manifest);
10180
+ }
9772
10181
  } else {
9773
10182
  const createdAt = normalizeTimestamp("createdAt", options.createdAt ?? Date.now());
9774
10183
  manifest = {
@@ -9783,6 +10192,7 @@ async function createFilesystemOpensteerWorkspace(options) {
9783
10192
  live: "live",
9784
10193
  artifacts: "artifacts",
9785
10194
  traces: "traces",
10195
+ observations: "observations",
9786
10196
  registry: "registry"
9787
10197
  }
9788
10198
  };
@@ -9794,6 +10204,7 @@ async function createFilesystemOpensteerWorkspace(options) {
9794
10204
  ensureDirectory(livePath),
9795
10205
  ensureDirectory(artifactsPath),
9796
10206
  ensureDirectory(tracesPath),
10207
+ ensureDirectory(observationsPath),
9797
10208
  ensureDirectory(registryPath)
9798
10209
  ]);
9799
10210
  const artifacts = createArtifactStore(options.rootPath);
@@ -9818,6 +10229,8 @@ async function createFilesystemOpensteerWorkspace(options) {
9818
10229
  await reverseReports.initialize();
9819
10230
  const traces = createTraceStore(options.rootPath, artifacts);
9820
10231
  await traces.initialize();
10232
+ const observations = createObservationStore(options.rootPath, artifacts);
10233
+ await observations.initialize();
9821
10234
  return {
9822
10235
  rootPath: options.rootPath,
9823
10236
  manifestPath,
@@ -9830,10 +10243,12 @@ async function createFilesystemOpensteerWorkspace(options) {
9830
10243
  liveCloudPath,
9831
10244
  artifactsPath,
9832
10245
  tracesPath,
10246
+ observationsPath,
9833
10247
  registryPath,
9834
10248
  lockPath,
9835
10249
  artifacts,
9836
10250
  traces,
10251
+ observations,
9837
10252
  registry: {
9838
10253
  descriptors,
9839
10254
  requestPlans,
@@ -9853,7 +10268,7 @@ async function createFilesystemOpensteerWorkspace(options) {
9853
10268
  var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
9854
10269
  var OPENSTEER_LIVE_SESSION_VERSION = 1;
9855
10270
  function resolveLiveSessionRecordPath(rootPath, provider) {
9856
- return path6__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
10271
+ return path7__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
9857
10272
  }
9858
10273
  async function readPersistedSessionRecord(rootPath, provider) {
9859
10274
  const sessionPath = resolveLiveSessionRecordPath(rootPath, provider);
@@ -10007,8 +10422,8 @@ var OpensteerBrowserManager = class {
10007
10422
  ...options.browser === void 0 ? {} : { browser: options.browser },
10008
10423
  ...this.contextOptions === void 0 ? {} : { context: this.contextOptions }
10009
10424
  });
10010
- this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path6__default.default.join(os.tmpdir(), `${TEMPORARY_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
10011
- rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
10425
+ this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path7__default.default.join(os.tmpdir(), `${TEMPORARY_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
10426
+ rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
10012
10427
  workspace: this.workspace
10013
10428
  }));
10014
10429
  this.cleanupRootOnDisconnect = this.workspace === void 0;
@@ -10078,7 +10493,7 @@ var OpensteerBrowserManager = class {
10078
10493
  userDataDir: "browser/user-data",
10079
10494
  bootstrap: {
10080
10495
  kind: "cloneLocalProfile",
10081
- sourceUserDataDir: path6__default.default.resolve(input.sourceUserDataDir),
10496
+ sourceUserDataDir: path7__default.default.resolve(input.sourceUserDataDir),
10082
10497
  ...input.sourceProfileDirectory === void 0 ? {} : { sourceProfileDirectory: input.sourceProfileDirectory }
10083
10498
  }
10084
10499
  };
@@ -10205,7 +10620,7 @@ var OpensteerBrowserManager = class {
10205
10620
  });
10206
10621
  }
10207
10622
  async createTemporaryEngine() {
10208
- const userDataDir = await promises.mkdtemp(path6__default.default.join(os.tmpdir(), "opensteer-temporary-browser-"));
10623
+ const userDataDir = await promises.mkdtemp(path7__default.default.join(os.tmpdir(), "opensteer-temporary-browser-"));
10209
10624
  await clearChromeSingletonEntries(userDataDir);
10210
10625
  const launched = await launchOwnedBrowser({
10211
10626
  userDataDir,
@@ -10652,7 +11067,7 @@ async function terminateProcess(pid) {
10652
11067
  }
10653
11068
  }
10654
11069
  async function requestBrowserClose(endpoint) {
10655
- await new Promise((resolve5, reject) => {
11070
+ await new Promise((resolve4, reject) => {
10656
11071
  const socket = new WebSocket(endpoint);
10657
11072
  const timeout = setTimeout(() => {
10658
11073
  socket.close();
@@ -10669,7 +11084,7 @@ async function requestBrowserClose(endpoint) {
10669
11084
  reject(error);
10670
11085
  return;
10671
11086
  }
10672
- resolve5();
11087
+ resolve4();
10673
11088
  };
10674
11089
  socket.addEventListener("open", () => {
10675
11090
  socket.send(JSON.stringify({ id: 1, method: "Browser.close" }));
@@ -10707,7 +11122,7 @@ async function waitForProcessExit(pid, timeoutMs) {
10707
11122
  return !isProcessRunning(pid);
10708
11123
  }
10709
11124
  function resolveAbpSessionDir(workspace) {
10710
- return path6__default.default.join(workspace.livePath, "abp-session");
11125
+ return path7__default.default.join(workspace.livePath, "abp-session");
10711
11126
  }
10712
11127
  async function allocateEphemeralPort() {
10713
11128
  const { allocatePort } = await loadAbpModule();
@@ -10765,7 +11180,7 @@ function isStealthProfile(input) {
10765
11180
  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;
10766
11181
  }
10767
11182
  async function sleep(ms) {
10768
- await new Promise((resolve5) => setTimeout(resolve5, ms));
11183
+ await new Promise((resolve4) => setTimeout(resolve4, ms));
10769
11184
  }
10770
11185
 
10771
11186
  // ../runtime-core/src/sdk/semantic-dispatch.ts
@@ -11029,31 +11444,18 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
11029
11444
  }
11030
11445
  }
11031
11446
  var ENV_FILENAMES = [".env", ".env.local"];
11032
- async function loadCliEnvironment(cwd) {
11033
- const protectedKeys = new Set(Object.keys(process.env));
11034
- const directories = collectDirectories(cwd);
11035
- for (const directory of directories) {
11036
- for (const filename of ENV_FILENAMES) {
11037
- const filePath = path6__default.default.join(directory, filename);
11038
- if (!await pathExists(filePath)) {
11039
- continue;
11040
- }
11041
- const parsed = parseEnvFile(await promises.readFile(filePath, "utf8"));
11042
- for (const [key, value] of Object.entries(parsed)) {
11043
- if (protectedKeys.has(key)) {
11044
- continue;
11045
- }
11046
- process.env[key] = value;
11047
- }
11048
- }
11447
+ function loadEnvironment(cwd = process.cwd()) {
11448
+ const resolved = resolveEnvironmentFiles(path7__default.default.resolve(cwd), process.env);
11449
+ for (const [key, value] of Object.entries(resolved)) {
11450
+ process.env[key] = value;
11049
11451
  }
11050
11452
  }
11051
11453
  function collectDirectories(cwd) {
11052
11454
  const directories = [];
11053
- let current = path6__default.default.resolve(cwd);
11455
+ let current = path7__default.default.resolve(cwd);
11054
11456
  for (; ; ) {
11055
11457
  directories.unshift(current);
11056
- const parent = path6__default.default.dirname(current);
11458
+ const parent = path7__default.default.dirname(current);
11057
11459
  if (parent === current) {
11058
11460
  return directories;
11059
11461
  }
@@ -11090,6 +11492,42 @@ function parseEnvValue(rawValue) {
11090
11492
  }
11091
11493
  return rawValue.replace(/\s+#.*$/u, "").trimEnd();
11092
11494
  }
11495
+ function resolveEnvironmentFiles(cwd, baseEnv, predicate) {
11496
+ const resolved = collectEnvironment(baseEnv);
11497
+ const protectedKeys = new Set(Object.keys(resolved));
11498
+ const directories = collectDirectories(cwd);
11499
+ for (const directory of directories) {
11500
+ for (const filename of ENV_FILENAMES) {
11501
+ const filePath = path7__default.default.join(directory, filename);
11502
+ if (!fs.existsSync(filePath)) {
11503
+ continue;
11504
+ }
11505
+ const parsed = parseEnvFile(fs.readFileSync(filePath, "utf8"));
11506
+ for (const [key, value] of Object.entries(parsed)) {
11507
+ if (protectedKeys.has(key)) {
11508
+ continue;
11509
+ }
11510
+ resolved[key] = value;
11511
+ }
11512
+ }
11513
+ }
11514
+ return resolved;
11515
+ }
11516
+ function collectEnvironment(baseEnv, predicate) {
11517
+ const resolved = {};
11518
+ for (const [key, value] of Object.entries(baseEnv)) {
11519
+ if (value === void 0) {
11520
+ continue;
11521
+ }
11522
+ resolved[key] = value;
11523
+ }
11524
+ return resolved;
11525
+ }
11526
+
11527
+ // src/cli/env-loader.ts
11528
+ async function loadCliEnvironment(cwd) {
11529
+ loadEnvironment(cwd);
11530
+ }
11093
11531
  function createOpensteerSkillsInvocation(input) {
11094
11532
  const cliArgs = ["add", input.skillSourcePath];
11095
11533
  if (input.options.all === true) {
@@ -11123,22 +11561,22 @@ function createOpensteerSkillsInvocation(input) {
11123
11561
  function resolveOpensteerSkillsCliPath() {
11124
11562
  const require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bin.cjs', document.baseURI).href)));
11125
11563
  const skillsPackagePath = require2.resolve("skills/package.json");
11126
- const skillsPackageDir = path6__default.default.dirname(skillsPackagePath);
11127
- const cliPath = path6__default.default.join(skillsPackageDir, "bin", "cli.mjs");
11564
+ const skillsPackageDir = path7__default.default.dirname(skillsPackagePath);
11565
+ const cliPath = path7__default.default.join(skillsPackageDir, "bin", "cli.mjs");
11128
11566
  if (!fs.existsSync(cliPath)) {
11129
11567
  throw new Error(`skills CLI entrypoint was not found at "${cliPath}".`);
11130
11568
  }
11131
11569
  return cliPath;
11132
11570
  }
11133
11571
  function resolveOpensteerSkillSourcePath() {
11134
- let ancestor = path6__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bin.cjs', document.baseURI).href))));
11572
+ let ancestor = path7__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bin.cjs', document.baseURI).href))));
11135
11573
  for (let index = 0; index < 6; index += 1) {
11136
- const candidate = path6__default.default.join(ancestor, "skills");
11137
- const skillManifest = path6__default.default.join(candidate, "opensteer", "SKILL.md");
11574
+ const candidate = path7__default.default.join(ancestor, "skills");
11575
+ const skillManifest = path7__default.default.join(candidate, "opensteer", "SKILL.md");
11138
11576
  if (fs.existsSync(skillManifest)) {
11139
11577
  return candidate;
11140
11578
  }
11141
- ancestor = path6__default.default.resolve(ancestor, "..");
11579
+ ancestor = path7__default.default.resolve(ancestor, "..");
11142
11580
  }
11143
11581
  throw new Error("Unable to find the packaged Opensteer skill source directory.");
11144
11582
  }
@@ -11221,345 +11659,267 @@ function resolveOpensteerProvider(input = {}) {
11221
11659
  };
11222
11660
  }
11223
11661
  var execFile2 = util.promisify(child_process.execFile);
11224
- var DEFAULT_CAPTURE_TIMEOUT_MS = 3e4;
11225
- var DEFAULT_STOP_TIMEOUT_MS = 15e3;
11226
- var DEVTOOLS_POLL_INTERVAL_MS2 = 50;
11227
- var PROCESS_LIST_MAX_BUFFER_BYTES3 = 16 * 1024 * 1024;
11228
- async function resolveCookieCaptureStrategy(input = {}) {
11229
- const timeoutMs = input.timeoutMs ?? DEFAULT_CAPTURE_TIMEOUT_MS;
11230
- if (input.attachEndpoint !== void 0) {
11231
- if (input.strategy !== void 0 && input.strategy !== "attach") {
11232
- throw new Error(
11233
- `Strategy "${input.strategy}" is incompatible with an explicit attach endpoint.`
11234
- );
11235
- }
11236
- return {
11237
- strategy: "attach",
11238
- attachEndpoint: input.attachEndpoint,
11239
- ...input.profileDirectory === void 0 ? {} : { profileDirectory: input.profileDirectory },
11240
- timeoutMs
11241
- };
11242
- }
11662
+ var NODE_SQLITE_SPECIFIER2 = `node:${"sqlite"}`;
11663
+ var CHROME_EPOCH_OFFSET = 11644473600000000n;
11664
+ var CHROME_HMAC_PREFIX_LENGTH = 32;
11665
+ async function readBrowserCookies(input = {}) {
11243
11666
  const brand2 = resolveRequestedBrand(input);
11244
- const executablePath = resolveBrandExecutablePath(brand2, input.executablePath);
11245
11667
  const userDataDir = resolveBrandUserDataDir(brand2, input.userDataDir);
11246
- const profileDirectory = input.profileDirectory;
11247
- const attachEndpoint = await resolveReachableAttachEndpoint(userDataDir, timeoutMs);
11248
- const runningProcess = findBrandProcess(brand2);
11249
- const autoStrategy = attachEndpoint !== void 0 ? "attach" : runningProcess !== null ? "managed-relaunch" : "headless";
11250
- const strategy = input.strategy ?? autoStrategy;
11251
- validateRequestedStrategy({
11252
- strategy,
11253
- brand: brand2,
11254
- ...attachEndpoint === void 0 ? {} : { attachEndpoint },
11255
- ...runningProcess?.pid === void 0 ? {} : { runningPid: runningProcess.pid }
11256
- });
11257
- return {
11258
- strategy,
11259
- brandId: brand2.id,
11260
- brandDisplayName: brand2.displayName,
11261
- executablePath,
11262
- userDataDir,
11263
- ...profileDirectory === void 0 ? {} : { profileDirectory },
11264
- ...attachEndpoint === void 0 ? {} : { attachEndpoint },
11265
- ...runningProcess === null ? {} : { runningPid: runningProcess.pid },
11266
- timeoutMs
11267
- };
11268
- }
11269
- async function acquireCdpEndpoint(resolved) {
11270
- if (resolved.strategy === "attach") {
11271
- if (!resolved.attachEndpoint) {
11272
- throw new Error("Attach capture requires a debuggable browser endpoint.");
11273
- }
11274
- const inspected = await inspectCdpEndpoint({
11275
- endpoint: resolved.attachEndpoint,
11276
- timeoutMs: Math.min(2e3, resolved.timeoutMs)
11277
- });
11278
- return {
11279
- strategy: "attach",
11280
- cdpEndpoint: inspected.endpoint,
11281
- ...resolved.brandId === void 0 ? {} : { brandId: resolved.brandId },
11282
- ...resolved.brandDisplayName === void 0 ? {} : { brandDisplayName: resolved.brandDisplayName },
11283
- ...resolved.userDataDir === void 0 ? {} : { userDataDir: resolved.userDataDir },
11284
- ...resolved.profileDirectory === void 0 ? {} : { profileDirectory: resolved.profileDirectory },
11285
- cleanup: async () => void 0
11286
- };
11287
- }
11288
- if (!resolved.brandId || !resolved.brandDisplayName || !resolved.executablePath || !resolved.userDataDir) {
11668
+ const profileDirectory = input.profileDirectory ?? "Default";
11669
+ const cookiesPath = path7.join(userDataDir, profileDirectory, "Cookies");
11670
+ if (!fs.existsSync(cookiesPath)) {
11289
11671
  throw new Error(
11290
- "Headless cookie capture requires a resolved browser brand, executable, and user-data-dir."
11672
+ `Cookies database not found at "${cookiesPath}". Verify the browser brand, user-data-dir, and profile-directory are correct.`
11291
11673
  );
11292
11674
  }
11293
- const userDataDir = resolved.userDataDir;
11294
- if (resolved.strategy === "managed-relaunch") {
11295
- if (resolved.runningPid === void 0) {
11296
- throw new Error("Managed relaunch requires a running browser process.");
11297
- }
11298
- await gracefullyStopBrowser(
11299
- getBrowserBrand(resolved.brandId),
11300
- resolved.runningPid,
11301
- resolved.timeoutMs
11302
- );
11303
- }
11304
- await clearChromeSingletonEntries(userDataDir);
11305
- try {
11306
- const capture = await launchCaptureChrome({
11307
- brandDisplayName: resolved.brandDisplayName,
11308
- executablePath: resolved.executablePath,
11309
- userDataDir,
11310
- ...resolved.profileDirectory === void 0 ? {} : { profileDirectory: resolved.profileDirectory },
11311
- timeoutMs: resolved.timeoutMs
11312
- });
11313
- return {
11314
- strategy: resolved.strategy,
11315
- cdpEndpoint: capture.endpoint,
11316
- brandId: resolved.brandId,
11317
- brandDisplayName: resolved.brandDisplayName,
11318
- userDataDir: resolved.userDataDir,
11319
- ...resolved.profileDirectory === void 0 ? {} : { profileDirectory: resolved.profileDirectory },
11320
- cleanup: async () => {
11321
- await capture.kill().catch(() => void 0);
11322
- await clearChromeSingletonEntries(userDataDir).catch(() => void 0);
11323
- }
11324
- };
11325
- } catch (error) {
11326
- await clearChromeSingletonEntries(userDataDir).catch(() => void 0);
11327
- throw error;
11328
- }
11329
- }
11330
- async function gracefullyStopBrowser(brand2, pid, timeoutMs = DEFAULT_STOP_TIMEOUT_MS) {
11331
- if (pid <= 0) {
11332
- return;
11333
- }
11334
- const platformConfig = resolveBrandPlatformConfig(brand2);
11335
- if (process.platform === "darwin" && platformConfig?.bundleId) {
11336
- await execFile2(
11337
- "osascript",
11338
- ["-e", `tell application id "${platformConfig.bundleId}" to quit`],
11339
- {
11340
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES3
11341
- }
11342
- ).catch(() => void 0);
11343
- } else if (process.platform === "win32") {
11344
- await execFile2("taskkill", ["/PID", String(pid)], {
11345
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES3
11346
- }).catch(() => void 0);
11347
- } else {
11348
- try {
11349
- process.kill(pid, "SIGTERM");
11350
- } catch {
11351
- }
11352
- }
11353
- if (await waitForProcessExit2(pid, timeoutMs)) {
11354
- return;
11355
- }
11356
- if (process.platform === "win32") {
11357
- await execFile2("taskkill", ["/F", "/PID", String(pid)], {
11358
- maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES3
11359
- }).catch(() => void 0);
11360
- } else {
11361
- try {
11362
- process.kill(pid, "SIGKILL");
11363
- } catch {
11364
- }
11365
- }
11366
- await waitForProcessExit2(pid, Math.min(5e3, timeoutMs));
11367
- }
11368
- async function launchCaptureChrome(input) {
11369
- const stderrLines = [];
11370
- const child = child_process.spawn(input.executablePath, buildCaptureChromeArgs(input), {
11371
- detached: process.platform !== "win32",
11372
- stdio: ["ignore", "ignore", "pipe"]
11373
- });
11374
- child.unref();
11375
- child.stderr?.setEncoding("utf8");
11376
- child.stderr?.on("data", (chunk) => {
11377
- stderrLines.push(String(chunk));
11378
- });
11675
+ const tempDir = await promises.mkdtemp(path7.join(os.tmpdir(), "opensteer-cookies-"));
11379
11676
  try {
11380
- const endpoint = await waitForCaptureEndpoint({
11381
- brandDisplayName: input.brandDisplayName,
11382
- child,
11383
- stderrLines,
11384
- timeoutMs: input.timeoutMs,
11385
- userDataDir: input.userDataDir
11386
- });
11677
+ await copyCookiesDatabase(cookiesPath, tempDir);
11678
+ const decryptionKey = await resolveDecryptionKey(brand2.id, userDataDir);
11679
+ const rows = queryAllCookies(path7.join(tempDir, "Cookies"));
11680
+ const cookies = decryptCookieRows(rows, decryptionKey);
11387
11681
  return {
11388
- endpoint,
11389
- kill: async () => {
11390
- await terminateChild(child);
11391
- }
11682
+ cookies,
11683
+ brandId: brand2.id,
11684
+ brandDisplayName: brand2.displayName,
11685
+ userDataDir,
11686
+ profileDirectory
11392
11687
  };
11393
- } catch (error) {
11394
- await terminateChild(child).catch(() => void 0);
11395
- throw error;
11688
+ } finally {
11689
+ await promises.rm(tempDir, { recursive: true, force: true }).catch(() => void 0);
11396
11690
  }
11397
11691
  }
11398
- function relaunchBrowserNormally(executablePath) {
11399
- const child = child_process.spawn(executablePath, [], {
11400
- detached: true,
11401
- stdio: "ignore"
11402
- });
11403
- child.unref();
11404
- }
11405
11692
  function resolveRequestedBrand(input) {
11406
11693
  if (input.brandId !== void 0) {
11407
11694
  return getBrowserBrand(input.brandId);
11408
11695
  }
11409
- if (input.userDataDir !== void 0) {
11410
- const inferred = inferBrandFromUserDataDir(input.userDataDir);
11411
- if (!inferred) {
11412
- throw new Error(
11413
- `Could not infer a browser brand from user-data-dir "${input.userDataDir}". Pass --browser explicitly.`
11414
- );
11415
- }
11416
- return inferred;
11417
- }
11418
- if (input.executablePath !== void 0) {
11419
- const inferred = inferBrandFromExecutablePath(input.executablePath);
11420
- if (!inferred) {
11421
- throw new Error(
11422
- `Could not infer a browser brand from executable path "${input.executablePath}". Pass --browser explicitly.`
11423
- );
11424
- }
11425
- return inferred;
11426
- }
11427
11696
  const installed = detectInstalledBrowserBrands()[0];
11428
11697
  if (!installed) {
11429
11698
  throw new Error(
11430
- "No Chromium browser found. Install a supported browser or pass --browser explicitly."
11699
+ "No Chromium browser found. Install a supported browser or pass brandId explicitly."
11431
11700
  );
11432
11701
  }
11433
11702
  return installed.brand;
11434
11703
  }
11435
- async function resolveReachableAttachEndpoint(userDataDir, timeoutMs) {
11436
- const activePort = readDevToolsActivePort(userDataDir);
11437
- if (!activePort) {
11438
- return void 0;
11704
+ async function copyCookiesDatabase(cookiesPath, destDir) {
11705
+ await promises.copyFile(cookiesPath, path7.join(destDir, "Cookies"));
11706
+ for (const suffix of ["-wal", "-journal", "-shm"]) {
11707
+ const src = cookiesPath + suffix;
11708
+ if (fs.existsSync(src)) {
11709
+ await promises.copyFile(src, path7.join(destDir, "Cookies" + suffix)).catch(() => void 0);
11710
+ }
11439
11711
  }
11712
+ }
11713
+ function queryAllCookies(dbPath) {
11714
+ let DatabaseSync;
11440
11715
  try {
11441
- return (await inspectCdpEndpoint({
11442
- endpoint: `http://127.0.0.1:${String(activePort.port)}`,
11443
- timeoutMs: Math.min(2e3, timeoutMs)
11444
- })).endpoint;
11716
+ ({ DatabaseSync } = __require(NODE_SQLITE_SPECIFIER2));
11445
11717
  } catch {
11446
- return void 0;
11718
+ throw new Error(
11719
+ "Reading browser cookies requires Node's built-in SQLite support. Use Node 22.5+ or a build with node:sqlite enabled."
11720
+ );
11721
+ }
11722
+ const database = new DatabaseSync(dbPath, { readOnly: true });
11723
+ try {
11724
+ const stmt = database.prepare(
11725
+ `SELECT host_key, name, value, encrypted_value, path,
11726
+ expires_utc, is_secure, is_httponly, samesite, is_persistent
11727
+ FROM cookies`
11728
+ );
11729
+ stmt.setReadBigInts(true);
11730
+ return stmt.all();
11731
+ } finally {
11732
+ database.close();
11447
11733
  }
11448
11734
  }
11449
- function validateRequestedStrategy(input) {
11450
- if (input.strategy === "attach" && input.attachEndpoint === void 0) {
11735
+ async function resolveDecryptionKey(brandId, userDataDir) {
11736
+ if (process.platform === "darwin") {
11737
+ const password = await resolveKeychainPassword(brandId);
11738
+ const key = crypto.pbkdf2Sync(password, "saltysalt", 1003, 16, "sha1");
11739
+ return { platform: "darwin", key, algorithm: "aes-128-cbc" };
11740
+ }
11741
+ if (process.platform === "linux") {
11742
+ const key = crypto.pbkdf2Sync("peanuts", "saltysalt", 1, 16, "sha1");
11743
+ return { platform: "linux", key, algorithm: "aes-128-cbc" };
11744
+ }
11745
+ if (process.platform === "win32") {
11746
+ const key = await resolveWindowsMasterKey(userDataDir);
11747
+ return { platform: "win32", key, algorithm: "aes-256-gcm" };
11748
+ }
11749
+ throw new Error(`Unsupported platform "${process.platform}" for cookie decryption.`);
11750
+ }
11751
+ var BRAND_KEYCHAIN_SERVICE = {
11752
+ chrome: "Chrome Safe Storage",
11753
+ "chrome-canary": "Chrome Safe Storage",
11754
+ chromium: "Chromium Safe Storage",
11755
+ brave: "Brave Safe Storage",
11756
+ edge: "Microsoft Edge Safe Storage",
11757
+ vivaldi: "Chrome Safe Storage",
11758
+ helium: "Chrome Safe Storage"
11759
+ };
11760
+ async function resolveKeychainPassword(brandId) {
11761
+ const service = BRAND_KEYCHAIN_SERVICE[brandId];
11762
+ try {
11763
+ const { stdout } = await execFile2("security", [
11764
+ "find-generic-password",
11765
+ "-s",
11766
+ service,
11767
+ "-w"
11768
+ ]);
11769
+ return stdout.trim();
11770
+ } catch {
11451
11771
  throw new Error(
11452
- `${input.brand.displayName} is not currently exposing a debuggable CDP endpoint for attach mode.`
11772
+ `Failed to retrieve "${service}" from macOS Keychain. Ensure the browser has been opened at least once and Keychain access is allowed.`
11453
11773
  );
11454
11774
  }
11455
- if (input.strategy === "headless" && input.runningPid !== void 0) {
11775
+ }
11776
+ async function resolveWindowsMasterKey(userDataDir) {
11777
+ const localStatePath = path7.join(userDataDir, "Local State");
11778
+ let localState;
11779
+ try {
11780
+ localState = JSON.parse(await promises.readFile(localStatePath, "utf8"));
11781
+ } catch {
11456
11782
  throw new Error(
11457
- `${input.brand.displayName} is already running. Close it first or use managed-relaunch.`
11783
+ `Failed to read "${localStatePath}". Ensure the browser has been opened at least once.`
11458
11784
  );
11459
11785
  }
11460
- if (input.strategy === "managed-relaunch" && input.runningPid === void 0) {
11786
+ const encodedKey = localState.os_crypt?.encrypted_key;
11787
+ if (!encodedKey) {
11788
+ throw new Error(`No encrypted key found in "${localStatePath}".`);
11789
+ }
11790
+ const rawKey = Buffer.from(encodedKey, "base64").subarray(5);
11791
+ const psScript = `
11792
+ Add-Type -AssemblyName System.Security
11793
+ $bytes = [byte[]]@(${Array.from(rawKey).join(",")})
11794
+ $decrypted = [System.Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, 'CurrentUser')
11795
+ [Convert]::ToBase64String($decrypted)
11796
+ `;
11797
+ try {
11798
+ const { stdout } = await execFile2("powershell", [
11799
+ "-NoProfile",
11800
+ "-NonInteractive",
11801
+ "-Command",
11802
+ psScript
11803
+ ]);
11804
+ return Buffer.from(stdout.trim(), "base64");
11805
+ } catch {
11461
11806
  throw new Error(
11462
- `${input.brand.displayName} is not currently running, so managed-relaunch is not available.`
11807
+ "Failed to decrypt browser master key via Windows DPAPI. Ensure you are running as the same user who owns the browser profile."
11463
11808
  );
11464
11809
  }
11465
11810
  }
11466
- function inferBrandFromUserDataDir(userDataDir) {
11467
- const normalized = normalizePath(userDataDir);
11468
- return getAllBrowserBrands().find((brand2) => {
11469
- const config = resolveBrandPlatformConfig(brand2);
11470
- if (!config) {
11471
- return false;
11811
+ function decryptCookieRows(rows, decryptionKey) {
11812
+ const cookies = [];
11813
+ const nowSeconds = Math.floor(Date.now() / 1e3);
11814
+ for (const row of rows) {
11815
+ const name = row.name.trim();
11816
+ const domain = row.host_key.trim();
11817
+ if (!name || !domain) {
11818
+ continue;
11472
11819
  }
11473
- const defaultDir = normalizePath(config.userDataDir);
11474
- return normalized === defaultDir || normalized.startsWith(`${defaultDir}/`);
11475
- });
11476
- }
11477
- function inferBrandFromExecutablePath(executablePath) {
11478
- const normalized = normalizePath(executablePath);
11479
- return getAllBrowserBrands().find((brand2) => {
11480
- const config = resolveBrandPlatformConfig(brand2);
11481
- if (!config) {
11482
- return false;
11820
+ const value = decryptCookieValue(row, decryptionKey);
11821
+ if (value === null) {
11822
+ continue;
11483
11823
  }
11484
- return config.executableCandidates.some(
11485
- (candidate) => candidate !== null && normalizePath(candidate) === normalized
11486
- );
11487
- });
11488
- }
11489
- function buildCaptureChromeArgs(input) {
11490
- const args = [
11491
- "--remote-debugging-port=0",
11492
- "--headless=new",
11493
- "--no-first-run",
11494
- "--no-default-browser-check",
11495
- "--disable-background-networking",
11496
- "--disable-sync",
11497
- "--disable-component-update",
11498
- `--user-data-dir=${input.userDataDir}`
11499
- ];
11500
- if (input.profileDirectory !== void 0) {
11501
- args.push(`--profile-directory=${input.profileDirectory}`);
11502
- }
11503
- return args;
11504
- }
11505
- async function waitForCaptureEndpoint(input) {
11506
- const deadline = Date.now() + input.timeoutMs;
11507
- while (Date.now() < deadline) {
11508
- const activePort = readDevToolsActivePort(input.userDataDir);
11509
- if (activePort) {
11510
- try {
11511
- return (await inspectCdpEndpoint({
11512
- endpoint: `http://127.0.0.1:${String(activePort.port)}`,
11513
- timeoutMs: Math.min(2e3, input.timeoutMs)
11514
- })).endpoint;
11515
- } catch {
11516
- return `ws://127.0.0.1:${String(activePort.port)}${activePort.webSocketPath}`;
11517
- }
11824
+ const expiresSeconds = chromeDateToUnixSeconds(row.expires_utc);
11825
+ const isSession = expiresSeconds <= 0;
11826
+ if (!isSession && expiresSeconds < nowSeconds) {
11827
+ continue;
11518
11828
  }
11519
- if (input.child.exitCode !== null) {
11520
- break;
11829
+ const sameSite = chromeSameSiteToString(row.samesite);
11830
+ let secure = Number(row.is_secure) === 1;
11831
+ if (sameSite === "None") {
11832
+ secure = true;
11521
11833
  }
11522
- await sleep2(DEVTOOLS_POLL_INTERVAL_MS2);
11834
+ cookies.push({
11835
+ name,
11836
+ value,
11837
+ domain,
11838
+ path: row.path || "/",
11839
+ secure,
11840
+ httpOnly: Number(row.is_httponly) === 1,
11841
+ ...isSession ? {} : { expires: expiresSeconds },
11842
+ ...sameSite !== void 0 ? { sameSite } : {}
11843
+ });
11523
11844
  }
11524
- throw new Error(formatCaptureLaunchError(input.brandDisplayName, input.stderrLines));
11845
+ return cookies;
11525
11846
  }
11526
- function formatCaptureLaunchError(brandDisplayName, stderrLines) {
11527
- const relevantLines = stderrLines.join("").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
11528
- if (relevantLines.length === 0) {
11529
- return `${brandDisplayName} failed to launch before exposing a DevTools endpoint.`;
11847
+ function decryptCookieValue(row, decryptionKey) {
11848
+ if (row.value && row.value.length > 0) {
11849
+ return row.value;
11530
11850
  }
11531
- const focusedLines = relevantLines.filter(
11532
- (line) => /(error|fatal|sandbox|namespace|permission|cannot|failed|abort)/i.test(line)
11533
- );
11534
- return `${brandDisplayName} failed to launch before exposing a DevTools endpoint.
11535
- ${(focusedLines.length > 0 ? focusedLines : relevantLines).slice(-5).join("\n")}`;
11851
+ const encrypted = Buffer.isBuffer(row.encrypted_value) ? row.encrypted_value : Buffer.from(row.encrypted_value);
11852
+ if (encrypted.length === 0) {
11853
+ return "";
11854
+ }
11855
+ const prefix = encrypted.subarray(0, 3).toString("ascii");
11856
+ if (prefix !== "v10" && prefix !== "v11") {
11857
+ return encrypted.toString("utf8");
11858
+ }
11859
+ const ciphertext = encrypted.subarray(3);
11860
+ if (decryptionKey.algorithm === "aes-128-cbc") {
11861
+ return decryptAes128Cbc(ciphertext, decryptionKey.key);
11862
+ }
11863
+ if (decryptionKey.algorithm === "aes-256-gcm") {
11864
+ return decryptAes256Gcm(ciphertext, decryptionKey.key);
11865
+ }
11866
+ return null;
11536
11867
  }
11537
- async function terminateChild(child) {
11538
- if (child.exitCode !== null) {
11539
- return;
11868
+ function decryptAes128Cbc(ciphertext, key) {
11869
+ try {
11870
+ const iv = Buffer.alloc(16, 32);
11871
+ const decipher = crypto.createDecipheriv("aes-128-cbc", key, iv);
11872
+ let decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
11873
+ if (decrypted.length > CHROME_HMAC_PREFIX_LENGTH && containsNonPrintableAscii(decrypted, CHROME_HMAC_PREFIX_LENGTH)) {
11874
+ decrypted = decrypted.subarray(CHROME_HMAC_PREFIX_LENGTH);
11875
+ }
11876
+ if (containsNonPrintableAscii(decrypted, decrypted.length)) {
11877
+ return null;
11878
+ }
11879
+ return decrypted.toString("utf8");
11880
+ } catch {
11881
+ return null;
11540
11882
  }
11883
+ }
11884
+ function decryptAes256Gcm(ciphertext, key) {
11541
11885
  try {
11542
- child.kill("SIGKILL");
11886
+ const nonce = ciphertext.subarray(0, 12);
11887
+ const authTag = ciphertext.subarray(ciphertext.length - 16);
11888
+ const encrypted = ciphertext.subarray(12, ciphertext.length - 16);
11889
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, nonce);
11890
+ decipher.setAuthTag(authTag);
11891
+ const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
11892
+ if (containsNonPrintableAscii(decrypted, decrypted.length)) {
11893
+ return null;
11894
+ }
11895
+ return decrypted.toString("utf8");
11543
11896
  } catch {
11544
- return;
11897
+ return null;
11545
11898
  }
11546
- await sleep2(50);
11547
11899
  }
11548
- async function waitForProcessExit2(pid, timeoutMs) {
11549
- const deadline = Date.now() + timeoutMs;
11550
- while (Date.now() < deadline) {
11551
- if (!isProcessRunning(pid)) {
11900
+ function containsNonPrintableAscii(buffer, length) {
11901
+ const end = Math.min(length, buffer.length);
11902
+ for (let i = 0; i < end; i++) {
11903
+ const byte = buffer[i];
11904
+ if (byte < 32 || byte > 126) {
11552
11905
  return true;
11553
11906
  }
11554
- await sleep2(50);
11555
11907
  }
11556
- return !isProcessRunning(pid);
11908
+ return false;
11557
11909
  }
11558
- function normalizePath(value) {
11559
- return path6.resolve(expandHome(value)).replaceAll("\\", "/").toLowerCase();
11910
+ function chromeDateToUnixSeconds(chromeTimestamp) {
11911
+ const ts = BigInt(chromeTimestamp);
11912
+ if (ts <= 0n) {
11913
+ return -1;
11914
+ }
11915
+ return Number((ts - CHROME_EPOCH_OFFSET) / 1000000n);
11560
11916
  }
11561
- async function sleep2(ms) {
11562
- await new Promise((resolve5) => setTimeout(resolve5, ms));
11917
+ function chromeSameSiteToString(value) {
11918
+ const v = Number(value);
11919
+ if (v === 0) return "None";
11920
+ if (v === 1) return "Lax";
11921
+ if (v === 2) return "Strict";
11922
+ return void 0;
11563
11923
  }
11564
11924
 
11565
11925
  // src/cloud/cookie-sync.ts
@@ -11615,14 +11975,14 @@ function toPortableBrowserProfileCookieRecord(cookie) {
11615
11975
  if (!name || !domain) {
11616
11976
  return null;
11617
11977
  }
11618
- const path16 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
11978
+ const path17 = typeof cookie.path === "string" && cookie.path.trim().length > 0 ? cookie.path : "/";
11619
11979
  const expiresAt = typeof cookie.expires === "number" && Number.isFinite(cookie.expires) && cookie.expires > 0 ? Math.floor(cookie.expires * 1e3) : null;
11620
11980
  const sameSite = normalizeSameSite(cookie.sameSite);
11621
11981
  return {
11622
11982
  name,
11623
11983
  value: cookie.value,
11624
11984
  domain,
11625
- path: path16,
11985
+ path: path17,
11626
11986
  secure: cookie.secure,
11627
11987
  httpOnly: cookie.httpOnly,
11628
11988
  ...sameSite === void 0 ? {} : { sameSite },
@@ -11638,114 +11998,48 @@ function normalizeSameSite(value) {
11638
11998
  return void 0;
11639
11999
  }
11640
12000
 
11641
- // src/cloud/portable-cookie-snapshot.ts
11642
- var gzip = util.promisify(zlib.gzip);
11643
- async function capturePortableBrowserProfileSnapshot(input = {}) {
11644
- const attached = input.attachEndpoint ? await inspectCdpEndpoint({
11645
- endpoint: input.attachEndpoint,
11646
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
11647
- }) : await selectAttachBrowserCandidate({
11648
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
11649
- });
11650
- const browser = await enginePlaywright.connectPlaywrightChromiumBrowser({
11651
- url: attached.endpoint
11652
- });
11653
- try {
11654
- const context = browser.contexts()[0];
11655
- if (!context) {
11656
- throw new Error("Attached browser did not expose a default browser context.");
11657
- }
11658
- const prepared = prepareBrowserProfileSyncCookies({
11659
- cookies: await context.cookies(),
11660
- ...input.domains === void 0 ? {} : { domains: input.domains }
11661
- });
11662
- if (prepared.cookies.length === 0) {
11663
- throw new Error("No syncable cookies found for the selected browser and scope.");
11664
- }
11665
- const browserVersion = browser.version();
11666
- const source = parseSnapshotSource(attached.browser ?? browserVersion);
11667
- return {
11668
- version: "portable-cookies-v1",
11669
- source: {
11670
- browserFamily: "chromium",
11671
- ...source.browserName === void 0 ? {} : { browserName: source.browserName },
11672
- ...source.browserMajor === void 0 ? {} : { browserMajor: source.browserMajor },
11673
- ...input.browserBrand === void 0 ? {} : { browserBrand: input.browserBrand },
11674
- ...input.captureMethod === void 0 ? {} : { captureMethod: input.captureMethod },
11675
- platform: normalizePlatform(process.platform),
11676
- capturedAt: Date.now()
11677
- },
11678
- cookies: prepared.cookies
11679
- };
11680
- } finally {
11681
- await browser.close().catch(() => void 0);
11682
- }
11683
- }
11684
- async function encodePortableBrowserProfileSnapshot(snapshot) {
11685
- return gzip(Buffer.from(JSON.stringify(snapshot), "utf8"));
11686
- }
11687
- function parseSnapshotSource(value) {
11688
- if (!value) {
11689
- return {};
11690
- }
11691
- const trimmed = value.trim();
11692
- const browserName = trimmed.split("/")[0]?.trim() || void 0;
11693
- const majorMatch = trimmed.match(/(\d+)/);
11694
- return {
11695
- ...browserName === void 0 ? {} : { browserName },
11696
- ...majorMatch?.[1] === void 0 ? {} : { browserMajor: majorMatch[1] }
11697
- };
11698
- }
11699
- function normalizePlatform(platform) {
11700
- if (platform === "darwin") return "macos";
11701
- if (platform === "win32") return "windows";
11702
- return platform;
11703
- }
11704
-
11705
12001
  // src/cloud/profile-sync.ts
12002
+ var gzip = util.promisify(zlib.gzip);
11706
12003
  var DEFAULT_POLL_INTERVAL_MS = 1e3;
11707
12004
  var DEFAULT_POLL_TIMEOUT_MS = 5 * 6e4;
11708
12005
  async function syncBrowserProfileCookies(client, input) {
11709
- const resolved = await resolveCookieCaptureStrategy({
11710
- ...input.attachEndpoint === void 0 ? {} : { attachEndpoint: input.attachEndpoint },
12006
+ const result = await readBrowserCookies({
11711
12007
  ...input.brandId === void 0 ? {} : { brandId: input.brandId },
11712
12008
  ...input.userDataDir === void 0 ? {} : { userDataDir: input.userDataDir },
11713
- ...input.profileDirectory === void 0 ? {} : { profileDirectory: input.profileDirectory },
11714
- ...input.executablePath === void 0 ? {} : { executablePath: input.executablePath },
11715
- ...input.strategy === void 0 ? {} : { strategy: input.strategy },
11716
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
12009
+ ...input.profileDirectory === void 0 ? {} : { profileDirectory: input.profileDirectory }
11717
12010
  });
11718
- const shouldRestoreBrowser = (input.restoreBrowser ?? true) && resolved.strategy === "managed-relaunch";
11719
- let captureSource;
11720
- try {
11721
- captureSource = await acquireCdpEndpoint(resolved);
11722
- const snapshot = await capturePortableBrowserProfileSnapshot({
11723
- attachEndpoint: captureSource.cdpEndpoint,
11724
- ...captureSource.brandId === void 0 ? {} : { browserBrand: captureSource.brandId },
11725
- captureMethod: captureSource.strategy,
11726
- ...input.domains === void 0 ? {} : { domains: input.domains },
11727
- ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs }
11728
- });
11729
- const payload = await encodePortableBrowserProfileSnapshot(snapshot);
11730
- const created = await client.createBrowserProfileImport({
11731
- profileId: input.profileId
11732
- });
11733
- if (payload.length > created.maxUploadBytes) {
11734
- throw new Error(
11735
- `Compressed cookie snapshot is ${String(payload.length)} bytes, exceeding the ${String(created.maxUploadBytes)} byte upload limit.`
11736
- );
11737
- }
11738
- const uploaded = await client.uploadBrowserProfileImportPayload({
11739
- uploadUrl: created.uploadUrl,
11740
- payload
11741
- });
11742
- return uploaded.status === "ready" ? uploaded : waitForBrowserProfileImport(client, created.importId);
11743
- } finally {
11744
- await captureSource?.cleanup().catch(() => void 0);
11745
- if (shouldRestoreBrowser && resolved.executablePath !== void 0) {
11746
- relaunchBrowserNormally(resolved.executablePath);
11747
- }
12011
+ const prepared = prepareBrowserProfileSyncCookies({
12012
+ cookies: result.cookies,
12013
+ ...input.domains === void 0 ? {} : { domains: input.domains }
12014
+ });
12015
+ if (prepared.cookies.length === 0) {
12016
+ throw new Error("No syncable cookies found for the selected browser and scope.");
12017
+ }
12018
+ const snapshot = {
12019
+ version: "portable-cookies-v1",
12020
+ source: {
12021
+ browserFamily: "chromium",
12022
+ browserBrand: result.brandId,
12023
+ captureMethod: "sqlite",
12024
+ platform: normalizePlatform(process.platform),
12025
+ capturedAt: Date.now()
12026
+ },
12027
+ cookies: prepared.cookies
12028
+ };
12029
+ const payload = await gzip(Buffer.from(JSON.stringify(snapshot), "utf8"));
12030
+ const created = await client.createBrowserProfileImport({
12031
+ profileId: input.profileId
12032
+ });
12033
+ if (payload.length > created.maxUploadBytes) {
12034
+ throw new Error(
12035
+ `Compressed cookie snapshot is ${String(payload.length)} bytes, exceeding the ${String(created.maxUploadBytes)} byte upload limit.`
12036
+ );
11748
12037
  }
12038
+ const uploaded = await client.uploadBrowserProfileImportPayload({
12039
+ uploadUrl: created.uploadUrl,
12040
+ payload
12041
+ });
12042
+ return uploaded.status === "ready" ? uploaded : waitForBrowserProfileImport(client, created.importId);
11749
12043
  }
11750
12044
  async function waitForBrowserProfileImport(client, importId) {
11751
12045
  const deadline = Date.now() + DEFAULT_POLL_TIMEOUT_MS;
@@ -11757,12 +12051,17 @@ async function waitForBrowserProfileImport(client, importId) {
11757
12051
  if (current.status === "failed") {
11758
12052
  throw new Error(current.error ?? "Browser profile sync failed.");
11759
12053
  }
11760
- await sleep3(DEFAULT_POLL_INTERVAL_MS);
12054
+ await sleep2(DEFAULT_POLL_INTERVAL_MS);
11761
12055
  }
11762
12056
  throw new Error(`Timed out waiting for browser profile sync "${importId}" to finish.`);
11763
12057
  }
11764
- async function sleep3(ms) {
11765
- await new Promise((resolve5) => setTimeout(resolve5, ms));
12058
+ function normalizePlatform(platform) {
12059
+ if (platform === "darwin") return "macos";
12060
+ if (platform === "win32") return "windows";
12061
+ return platform;
12062
+ }
12063
+ async function sleep2(ms) {
12064
+ await new Promise((resolve4) => setTimeout(resolve4, ms));
11766
12065
  }
11767
12066
 
11768
12067
  // src/cloud/client.ts
@@ -11782,7 +12081,8 @@ var OpensteerCloudClient = class {
11782
12081
  ...input.name === void 0 ? {} : { name: input.name },
11783
12082
  ...input.browser === void 0 ? {} : { browser: input.browser },
11784
12083
  ...input.context === void 0 ? {} : { context: input.context },
11785
- ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile }
12084
+ ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
12085
+ ...input.observability === void 0 ? {} : { observability: input.observability }
11786
12086
  }
11787
12087
  });
11788
12088
  return await response.json();
@@ -11960,8 +12260,8 @@ var OpensteerCloudClient = class {
11960
12260
  }
11961
12261
  };
11962
12262
  function delay(ms) {
11963
- return new Promise((resolve5) => {
11964
- setTimeout(resolve5, ms);
12263
+ return new Promise((resolve4) => {
12264
+ setTimeout(resolve4, ms);
11965
12265
  });
11966
12266
  }
11967
12267
  function wrapCloudFetchError(error, input) {
@@ -11984,17 +12284,17 @@ function wrapCloudFetchError(error, input) {
11984
12284
  function resolveCloudConfig(input = {}) {
11985
12285
  const provider = resolveOpensteerProvider({
11986
12286
  ...input.provider === void 0 ? {} : { provider: input.provider },
11987
- ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
12287
+ ...input.environment?.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: input.environment.OPENSTEER_PROVIDER }
11988
12288
  });
11989
12289
  if (provider.mode !== "cloud") {
11990
12290
  return void 0;
11991
12291
  }
11992
12292
  const cloudProvider = input.provider?.mode === "cloud" ? input.provider : void 0;
11993
- const apiKey = cloudProvider?.apiKey ?? process.env.OPENSTEER_API_KEY;
12293
+ const apiKey = cloudProvider?.apiKey ?? input.environment?.OPENSTEER_API_KEY;
11994
12294
  if (!apiKey || apiKey.trim().length === 0) {
11995
12295
  throw new Error("provider=cloud requires OPENSTEER_API_KEY or provider.apiKey.");
11996
12296
  }
11997
- const baseUrl = cloudProvider?.baseUrl ?? process.env.OPENSTEER_BASE_URL;
12297
+ const baseUrl = cloudProvider?.baseUrl ?? input.environment?.OPENSTEER_BASE_URL;
11998
12298
  if (!baseUrl || baseUrl.trim().length === 0) {
11999
12299
  throw new Error("provider=cloud requires OPENSTEER_BASE_URL or provider.baseUrl.");
12000
12300
  }
@@ -12007,11 +12307,54 @@ function resolveCloudConfig(input = {}) {
12007
12307
 
12008
12308
  // ../runtime-core/package.json
12009
12309
  var package_default2 = {
12010
- version: "0.1.1"};
12310
+ version: "0.1.2"};
12011
12311
 
12012
12312
  // ../runtime-core/src/version.ts
12013
12313
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default2.version;
12014
12314
 
12315
+ // ../runtime-core/src/action-boundary.ts
12316
+ var actionBoundaryDiagnosticsBySignal = /* @__PURE__ */ new WeakMap();
12317
+ async function captureActionBoundarySnapshot(engine, pageRef) {
12318
+ const frames = await engine.listFrames({ pageRef });
12319
+ const mainFrame = frames.find((frame) => frame.isMainFrame);
12320
+ if (!mainFrame) {
12321
+ throw new Error(`page ${pageRef} does not expose a main frame`);
12322
+ }
12323
+ return {
12324
+ pageRef,
12325
+ documentRef: mainFrame.documentRef
12326
+ };
12327
+ }
12328
+ function createActionBoundaryDiagnostics(input) {
12329
+ return {
12330
+ trigger: input.boundary.trigger,
12331
+ crossDocument: input.boundary.crossDocument,
12332
+ bootstrapSettled: input.boundary.bootstrapSettled,
12333
+ visualSettled: input.visualSettled,
12334
+ ...input.boundary.timedOutPhase !== void 0 ? { timedOutPhase: input.boundary.timedOutPhase } : !input.visualSettled ? { timedOutPhase: "visual" } : {}
12335
+ };
12336
+ }
12337
+ function recordActionBoundaryDiagnostics(signal, diagnostics) {
12338
+ actionBoundaryDiagnosticsBySignal.set(signal, diagnostics);
12339
+ }
12340
+ function takeActionBoundaryDiagnostics(signal) {
12341
+ const diagnostics = actionBoundaryDiagnosticsBySignal.get(signal);
12342
+ actionBoundaryDiagnosticsBySignal.delete(signal);
12343
+ return diagnostics;
12344
+ }
12345
+ function isSoftSettleTimeoutError(error, signal) {
12346
+ if (isTimeoutError(error)) {
12347
+ return true;
12348
+ }
12349
+ return signal?.aborted === true && isTimeoutError(signal.reason) && (error === signal.reason || isAbortError(error));
12350
+ }
12351
+ function isAbortError(error) {
12352
+ return error instanceof Error && error.name === "AbortError";
12353
+ }
12354
+ function isTimeoutError(error) {
12355
+ return isOpensteerProtocolError(error) && error.code === "timeout";
12356
+ }
12357
+
12015
12358
  // ../runtime-core/src/internal/errors.ts
12016
12359
  function normalizeThrownOpensteerError(error, fallbackMessage) {
12017
12360
  if (isOpensteerProtocolError(error)) {
@@ -12044,9 +12387,9 @@ var DEFAULT_TIMEOUTS = {
12044
12387
  "page.add-init-script": 1e4,
12045
12388
  "page.snapshot": 15e3,
12046
12389
  "computer.execute": 3e4,
12047
- "dom.click": 1e4,
12390
+ "dom.click": 3e4,
12048
12391
  "dom.hover": 1e4,
12049
- "dom.input": 1e4,
12392
+ "dom.input": 3e4,
12050
12393
  "dom.scroll": 1e4,
12051
12394
  "dom.extract": 15e3,
12052
12395
  "network.query": 15e3,
@@ -12206,10 +12549,10 @@ function delayWithSignal(delayMs, signal) {
12206
12549
  if (signal.aborted) {
12207
12550
  return Promise.reject(signal.reason ?? abortError());
12208
12551
  }
12209
- return new Promise((resolve5, reject) => {
12552
+ return new Promise((resolve4, reject) => {
12210
12553
  const timer = setTimeout(() => {
12211
12554
  signal.removeEventListener("abort", onAbort);
12212
- resolve5();
12555
+ resolve4();
12213
12556
  }, delayMs);
12214
12557
  const onAbort = () => {
12215
12558
  clearTimeout(timer);
@@ -12674,9 +13017,9 @@ var IFRAME_URL_ATTRIBUTES = /* @__PURE__ */ new Set([
12674
13017
  "poster",
12675
13018
  "ping"
12676
13019
  ]);
12677
- function buildArrayFieldPathCandidates(path16) {
12678
- const strict = path16.nodes.length ? buildPathCandidates(path16.nodes) : [];
12679
- const relaxedNodes = stripPositionClauses(path16.nodes);
13020
+ function buildArrayFieldPathCandidates(path17) {
13021
+ const strict = path17.nodes.length ? buildPathCandidates(path17.nodes) : [];
13022
+ const relaxedNodes = stripPositionClauses(path17.nodes);
12680
13023
  const relaxed = relaxedNodes.length ? buildPathCandidates(relaxedNodes) : [];
12681
13024
  return dedupeSelectors([...strict, ...relaxed]);
12682
13025
  }
@@ -13203,8 +13546,8 @@ function cloneStructuralElementAnchor(anchor) {
13203
13546
  nodes: anchor.nodes.map(clonePathNode)
13204
13547
  };
13205
13548
  }
13206
- function buildPathSelectorHint(path16) {
13207
- const nodes = path16?.nodes || [];
13549
+ function buildPathSelectorHint(path17) {
13550
+ const nodes = path17?.nodes || [];
13208
13551
  const last = nodes[nodes.length - 1];
13209
13552
  if (!last) {
13210
13553
  return "*";
@@ -13253,15 +13596,15 @@ function sanitizeStructuralElementAnchor(anchor) {
13253
13596
  nodes: sanitizeNodes(anchor.nodes)
13254
13597
  };
13255
13598
  }
13256
- function sanitizeReplayElementPath(path16) {
13599
+ function sanitizeReplayElementPath(path17) {
13257
13600
  return {
13258
13601
  resolution: "deterministic",
13259
- context: sanitizeContext(path16.context),
13260
- nodes: sanitizeNodes(path16.nodes)
13602
+ context: sanitizeContext(path17.context),
13603
+ nodes: sanitizeNodes(path17.nodes)
13261
13604
  };
13262
13605
  }
13263
- function sanitizeElementPath(path16) {
13264
- return sanitizeReplayElementPath(path16);
13606
+ function sanitizeElementPath(path17) {
13607
+ return sanitizeReplayElementPath(path17);
13265
13608
  }
13266
13609
  function buildLocalStructuralElementAnchor(index, rawTargetNode) {
13267
13610
  const targetNode = requireElementNode(index, rawTargetNode);
@@ -13384,8 +13727,8 @@ function buildTargetNotFoundMessage(domPath, diagnostics) {
13384
13727
  }
13385
13728
  return `${base} Target depth ${String(depth)}. Candidate counts: ${sample}.`;
13386
13729
  }
13387
- function buildArrayFieldCandidates(path16) {
13388
- return buildArrayFieldPathCandidates(path16);
13730
+ function buildArrayFieldCandidates(path17) {
13731
+ return buildArrayFieldPathCandidates(path17);
13389
13732
  }
13390
13733
  function firstDefinedAttribute(node, keys) {
13391
13734
  for (const key of keys) {
@@ -13829,19 +14172,6 @@ var MemoryDomDescriptorStore = class {
13829
14172
  }
13830
14173
  };
13831
14174
 
13832
- // ../runtime-core/src/action-boundary.ts
13833
- async function captureActionBoundarySnapshot(engine, pageRef) {
13834
- const frames = await engine.listFrames({ pageRef });
13835
- const mainFrame = frames.find((frame) => frame.isMainFrame);
13836
- if (!mainFrame) {
13837
- throw new Error(`page ${pageRef} does not expose a main frame`);
13838
- }
13839
- return {
13840
- pageRef,
13841
- documentRef: mainFrame.documentRef
13842
- };
13843
- }
13844
-
13845
14175
  // ../runtime-core/src/runtimes/dom/executor.ts
13846
14176
  var MAX_DOM_ACTION_ATTEMPTS = 3;
13847
14177
  var DEFAULT_SCROLL_OPTIONS = {
@@ -13864,14 +14194,16 @@ var DomActionExecutor = class {
13864
14194
  ...input.timeout === void 0 ? {} : { timeout: input.timeout }
13865
14195
  },
13866
14196
  async (pointerTarget, point, timeout) => {
13867
- await timeout.runStep(
14197
+ const events = [];
14198
+ const moved = await timeout.runStep(
13868
14199
  () => this.options.engine.mouseMove({
13869
14200
  pageRef: pointerTarget.resolved.pageRef,
13870
14201
  point,
13871
14202
  coordinateSpace: "document-css"
13872
14203
  })
13873
14204
  );
13874
- await timeout.runStep(
14205
+ events.push(...moved.events);
14206
+ const clicked = await timeout.runStep(
13875
14207
  () => this.options.engine.mouseClick({
13876
14208
  pageRef: pointerTarget.resolved.pageRef,
13877
14209
  point,
@@ -13881,7 +14213,12 @@ var DomActionExecutor = class {
13881
14213
  ...input.modifiers === void 0 ? {} : { modifiers: input.modifiers }
13882
14214
  })
13883
14215
  );
13884
- return { resolved: pointerTarget.original, point };
14216
+ events.push(...clicked.events);
14217
+ return {
14218
+ resolved: pointerTarget.original,
14219
+ point,
14220
+ ...events.length === 0 ? {} : { events }
14221
+ };
13885
14222
  }
13886
14223
  );
13887
14224
  }
@@ -13895,14 +14232,18 @@ var DomActionExecutor = class {
13895
14232
  ...input.timeout === void 0 ? {} : { timeout: input.timeout }
13896
14233
  },
13897
14234
  async (pointerTarget, point, timeout) => {
13898
- await timeout.runStep(
14235
+ const moved = await timeout.runStep(
13899
14236
  () => this.options.engine.mouseMove({
13900
14237
  pageRef: pointerTarget.resolved.pageRef,
13901
14238
  point,
13902
14239
  coordinateSpace: "document-css"
13903
14240
  })
13904
14241
  );
13905
- return { resolved: pointerTarget.original, point };
14242
+ return {
14243
+ resolved: pointerTarget.original,
14244
+ point,
14245
+ ...moved.events.length === 0 ? {} : { events: moved.events }
14246
+ };
13906
14247
  }
13907
14248
  );
13908
14249
  }
@@ -13916,14 +14257,16 @@ var DomActionExecutor = class {
13916
14257
  ...input.timeout === void 0 ? {} : { timeout: input.timeout }
13917
14258
  },
13918
14259
  async (pointerTarget, point, timeout) => {
13919
- await timeout.runStep(
14260
+ const events = [];
14261
+ const moved = await timeout.runStep(
13920
14262
  () => this.options.engine.mouseMove({
13921
14263
  pageRef: pointerTarget.resolved.pageRef,
13922
14264
  point,
13923
14265
  coordinateSpace: "document-css"
13924
14266
  })
13925
14267
  );
13926
- await timeout.runStep(
14268
+ events.push(...moved.events);
14269
+ const scrolled = await timeout.runStep(
13927
14270
  () => this.options.engine.mouseScroll({
13928
14271
  pageRef: pointerTarget.resolved.pageRef,
13929
14272
  point,
@@ -13931,7 +14274,12 @@ var DomActionExecutor = class {
13931
14274
  delta: input.delta
13932
14275
  })
13933
14276
  );
13934
- return { resolved: pointerTarget.original, point };
14277
+ events.push(...scrolled.events);
14278
+ return {
14279
+ resolved: pointerTarget.original,
14280
+ point,
14281
+ ...events.length === 0 ? {} : { events }
14282
+ };
13935
14283
  }
13936
14284
  );
13937
14285
  }
@@ -13973,7 +14321,7 @@ var DomActionExecutor = class {
13973
14321
  let finalResolved = resolved;
13974
14322
  let finalSnapshot;
13975
14323
  if (input.pressEnter) {
13976
- await this.settle(resolved.pageRef, "dom.input", timeout);
14324
+ await this.waitForPressEnterReaction(timeout);
13977
14325
  const enterSession = this.options.createResolutionSession();
13978
14326
  const enterResolved = await timeout.runStep(
13979
14327
  () => this.options.resolveTarget(enterSession, {
@@ -13997,7 +14345,15 @@ var DomActionExecutor = class {
13997
14345
  );
13998
14346
  finalResolved = enterResolved;
13999
14347
  }
14000
- await this.settle(finalResolved.pageRef, "dom.input", timeout, finalSnapshot);
14348
+ const settleDiagnostics = await this.settle(
14349
+ finalResolved.pageRef,
14350
+ "dom.input",
14351
+ timeout,
14352
+ finalSnapshot
14353
+ );
14354
+ if (finalSnapshot !== void 0) {
14355
+ recordActionBoundaryDiagnostics(timeout.signal, settleDiagnostics);
14356
+ }
14001
14357
  return finalResolved;
14002
14358
  } catch (error) {
14003
14359
  lastError = error;
@@ -14074,12 +14430,13 @@ var DomActionExecutor = class {
14074
14430
  () => captureActionBoundarySnapshot(this.options.engine, pointerTarget.resolved.pageRef)
14075
14431
  );
14076
14432
  const outcome = await dispatch(pointerTarget, point, timeout);
14077
- await this.settle(
14433
+ const settleDiagnostics = await this.settle(
14078
14434
  pointerTarget.resolved.pageRef,
14079
14435
  input.operation,
14080
14436
  timeout,
14081
14437
  actionBoundarySnapshot
14082
14438
  );
14439
+ recordActionBoundaryDiagnostics(timeout.signal, settleDiagnostics);
14083
14440
  return outcome;
14084
14441
  } catch (error) {
14085
14442
  lastError = error;
@@ -14099,22 +14456,47 @@ var DomActionExecutor = class {
14099
14456
  }
14100
14457
  async settle(pageRef, operation, timeout, snapshot) {
14101
14458
  const bridge = this.requireBridge();
14102
- await timeout.runStep(
14459
+ let visualSettled = true;
14460
+ const boundary = await timeout.runStep(
14103
14461
  () => bridge.finalizeDomAction(pageRef, {
14104
14462
  operation,
14105
14463
  ...snapshot === void 0 ? {} : { snapshot },
14106
14464
  signal: timeout.signal,
14107
14465
  remainingMs: () => timeout.remainingMs(),
14108
- policySettle: (targetPageRef, trigger) => settleWithPolicy(this.options.policy.settle, {
14109
- operation,
14110
- trigger,
14111
- engine: this.options.engine,
14112
- pageRef: targetPageRef,
14113
- signal: timeout.signal,
14114
- remainingMs: timeout.remainingMs()
14115
- })
14466
+ policySettle: async (targetPageRef, trigger) => {
14467
+ try {
14468
+ await settleWithPolicy(this.options.policy.settle, {
14469
+ operation,
14470
+ trigger,
14471
+ engine: this.options.engine,
14472
+ pageRef: targetPageRef,
14473
+ signal: timeout.signal,
14474
+ remainingMs: timeout.remainingMs()
14475
+ });
14476
+ } catch (error) {
14477
+ if (snapshot !== void 0 && isSoftSettleTimeoutError(error, timeout.signal)) {
14478
+ visualSettled = false;
14479
+ return;
14480
+ }
14481
+ throw error;
14482
+ }
14483
+ }
14116
14484
  })
14117
14485
  );
14486
+ return createActionBoundaryDiagnostics({
14487
+ boundary,
14488
+ visualSettled
14489
+ });
14490
+ }
14491
+ async waitForPressEnterReaction(timeout) {
14492
+ const delayMs = this.options.policy.settle.resolveDelayMs({
14493
+ operation: "dom.input",
14494
+ trigger: "dom-action"
14495
+ });
14496
+ if (delayMs <= 0) {
14497
+ return;
14498
+ }
14499
+ await delayWithSignal(delayMs, timeout.signal);
14118
14500
  }
14119
14501
  requireBridge() {
14120
14502
  if (this.bridge !== void 0) {
@@ -14823,21 +15205,21 @@ var DefaultDomRuntime = class {
14823
15205
  return match;
14824
15206
  }
14825
15207
  async resolvePathTarget(session, pageRef, rawPath, source, description, descriptor) {
14826
- const path16 = sanitizeReplayElementPath(rawPath);
14827
- const context = await this.resolvePathContext(session, pageRef, path16.context);
14828
- const target = resolveDomPathInScope(context.index, path16.nodes, context.scope);
15208
+ const path17 = sanitizeReplayElementPath(rawPath);
15209
+ const context = await this.resolvePathContext(session, pageRef, path17.context);
15210
+ const target = resolveDomPathInScope(context.index, path17.nodes, context.scope);
14829
15211
  if (!target) {
14830
- throwTargetNotFound(context.index, path16.nodes, context.scope);
15212
+ throwTargetNotFound(context.index, path17.nodes, context.scope);
14831
15213
  }
14832
15214
  if (target.node.nodeRef === void 0) {
14833
15215
  throw new Error(
14834
- `resolved path "${buildPathSelectorHint(path16)}" does not point to a live element`
15216
+ `resolved path "${buildPathSelectorHint(path17)}" does not point to a live element`
14835
15217
  );
14836
15218
  }
14837
15219
  const anchor = await this.buildAnchorFromSnapshotNode(session, context.snapshot, target.node);
14838
15220
  return this.createResolvedTarget(source, context.snapshot, target.node, anchor, {
14839
15221
  ...description === void 0 ? {} : { description },
14840
- replayPath: path16,
15222
+ replayPath: path17,
14841
15223
  ...source === "path" || source === "descriptor" ? { selectorUsed: target.selector } : {},
14842
15224
  ...descriptor === void 0 ? {} : { descriptor }
14843
15225
  });
@@ -14858,9 +15240,9 @@ var DefaultDomRuntime = class {
14858
15240
  });
14859
15241
  }
14860
15242
  async queryAllByElementPath(session, pageRef, rawPath) {
14861
- const path16 = sanitizeReplayElementPath(rawPath);
14862
- const context = await this.resolvePathContext(session, pageRef, path16.context);
14863
- return queryAllDomPathInScope(context.index, path16.nodes, context.scope).filter(
15243
+ const path17 = sanitizeReplayElementPath(rawPath);
15244
+ const context = await this.resolvePathContext(session, pageRef, path17.context);
15245
+ return queryAllDomPathInScope(context.index, path17.nodes, context.scope).filter(
14864
15246
  (node) => node.nodeRef !== void 0
14865
15247
  ).map((node) => this.createSnapshotTarget(context.snapshot, node));
14866
15248
  }
@@ -15046,16 +15428,16 @@ var DefaultDomRuntime = class {
15046
15428
  const index = createSnapshotIndex(item.snapshot);
15047
15429
  return this.resolveFirstArrayFieldTargetInNode(index, item.node, field.path);
15048
15430
  }
15049
- resolveFirstArrayFieldTargetInNode(index, rootNode, path16) {
15050
- const normalizedPath = sanitizeElementPath(path16);
15431
+ resolveFirstArrayFieldTargetInNode(index, rootNode, path17) {
15432
+ const normalizedPath = sanitizeElementPath(path17);
15051
15433
  const selectors = buildArrayFieldCandidates(normalizedPath);
15052
15434
  if (!selectors.length) {
15053
15435
  return rootNode;
15054
15436
  }
15055
15437
  return resolveFirstWithinNodeBySelectors(index, rootNode, selectors);
15056
15438
  }
15057
- resolveUniqueArrayFieldTargetInNode(index, rootNode, path16) {
15058
- const normalizedPath = sanitizeElementPath(path16);
15439
+ resolveUniqueArrayFieldTargetInNode(index, rootNode, path17) {
15440
+ const normalizedPath = sanitizeElementPath(path17);
15059
15441
  const selectors = buildArrayFieldCandidates(normalizedPath);
15060
15442
  if (!selectors.length) {
15061
15443
  return rootNode;
@@ -15384,6 +15766,7 @@ var DefaultComputerUseRuntime = class {
15384
15766
  const snapshot = await input.timeout.runStep(
15385
15767
  () => captureActionBoundarySnapshot(this.options.engine, input.pageRef)
15386
15768
  );
15769
+ let visualSettled = true;
15387
15770
  const executed = await input.timeout.runStep(
15388
15771
  () => bridge.execute({
15389
15772
  pageRef: input.pageRef,
@@ -15392,16 +15775,35 @@ var DefaultComputerUseRuntime = class {
15392
15775
  screenshot,
15393
15776
  signal: input.timeout.signal,
15394
15777
  remainingMs: () => input.timeout.remainingMs(),
15395
- policySettle: async (pageRef, trigger) => settleWithPolicy(this.options.policy.settle, {
15396
- operation: "computer.execute",
15397
- trigger,
15398
- engine: this.options.engine,
15399
- pageRef,
15400
- signal: input.timeout.signal,
15401
- remainingMs: input.timeout.remainingMs()
15402
- })
15778
+ policySettle: async (pageRef, trigger) => {
15779
+ try {
15780
+ await settleWithPolicy(this.options.policy.settle, {
15781
+ operation: "computer.execute",
15782
+ trigger,
15783
+ engine: this.options.engine,
15784
+ pageRef,
15785
+ signal: input.timeout.signal,
15786
+ remainingMs: input.timeout.remainingMs()
15787
+ });
15788
+ } catch (error) {
15789
+ if (pageRef === input.pageRef && isSoftSettleTimeoutError(error, input.timeout.signal)) {
15790
+ visualSettled = false;
15791
+ return;
15792
+ }
15793
+ throw error;
15794
+ }
15795
+ }
15403
15796
  })
15404
15797
  );
15798
+ if (executed.boundary !== void 0 && executed.pageRef === input.pageRef) {
15799
+ recordActionBoundaryDiagnostics(
15800
+ input.timeout.signal,
15801
+ createActionBoundaryDiagnostics({
15802
+ boundary: executed.boundary,
15803
+ visualSettled
15804
+ })
15805
+ );
15806
+ }
15405
15807
  let trace = void 0;
15406
15808
  if (!input.timeout.signal.aborted) {
15407
15809
  try {
@@ -16411,7 +16813,7 @@ function diffStringMap(prefix, left, right, includeUnchanged, output) {
16411
16813
  diffScalarField(`${prefix}.${key}`, left[key], right[key], includeUnchanged, output);
16412
16814
  }
16413
16815
  }
16414
- function diffScalarField(path16, left, right, includeUnchanged, output) {
16816
+ function diffScalarField(path17, left, right, includeUnchanged, output) {
16415
16817
  const leftValue = stringifyFieldValue(left);
16416
16818
  const rightValue = stringifyFieldValue(right);
16417
16819
  const kind = leftValue === void 0 ? rightValue === void 0 ? "unchanged" : "added" : rightValue === void 0 ? "removed" : leftValue === rightValue ? "unchanged" : "changed";
@@ -16419,7 +16821,7 @@ function diffScalarField(path16, left, right, includeUnchanged, output) {
16419
16821
  return;
16420
16822
  }
16421
16823
  output.push({
16422
- path: path16,
16824
+ path: path17,
16423
16825
  kind,
16424
16826
  ...leftValue === void 0 ? {} : { leftValue },
16425
16827
  ...rightValue === void 0 ? {} : { rightValue },
@@ -16513,7 +16915,7 @@ function resolveBodyEncoding(charset) {
16513
16915
  var NetworkHistory = class {
16514
16916
  metadataByRequestId = /* @__PURE__ */ new Map();
16515
16917
  requestIdByRecordId = /* @__PURE__ */ new Map();
16516
- requestIdsByActionId = /* @__PURE__ */ new Map();
16918
+ requestIdsByCapture = /* @__PURE__ */ new Map();
16517
16919
  requestIdsByTag = /* @__PURE__ */ new Map();
16518
16920
  tombstonedRequestIds = /* @__PURE__ */ new Set();
16519
16921
  materialize(records, options = {}) {
@@ -16560,17 +16962,17 @@ var NetworkHistory = class {
16560
16962
  }
16561
16963
  return persisted;
16562
16964
  }
16563
- assignActionId(records, actionId) {
16965
+ assignCapture(records, capture) {
16564
16966
  for (const record of records) {
16565
16967
  const metadata = this.metadataByRequestId.get(record.record.requestId);
16566
- if (!metadata || metadata.actionId === actionId) {
16968
+ if (!metadata || metadata.capture === capture) {
16567
16969
  continue;
16568
16970
  }
16569
- if (metadata.actionId !== void 0) {
16570
- this.requestIdsByActionId.get(metadata.actionId)?.delete(record.record.requestId);
16971
+ if (metadata.capture !== void 0) {
16972
+ this.requestIdsByCapture.get(metadata.capture)?.delete(record.record.requestId);
16571
16973
  }
16572
- metadata.actionId = actionId;
16573
- this.addIndexedRequestId(this.requestIdsByActionId, actionId, record.record.requestId);
16974
+ metadata.capture = capture;
16975
+ this.addIndexedRequestId(this.requestIdsByCapture, capture, record.record.requestId);
16574
16976
  }
16575
16977
  }
16576
16978
  addTag(records, tag) {
@@ -16590,8 +16992,8 @@ var NetworkHistory = class {
16590
16992
  getRequestId(recordId) {
16591
16993
  return this.requestIdByRecordId.get(recordId);
16592
16994
  }
16593
- getRequestIdsForActionId(actionId) {
16594
- return new Set(this.requestIdsByActionId.get(actionId) ?? []);
16995
+ getRequestIdsForCapture(capture) {
16996
+ return new Set(this.requestIdsByCapture.get(capture) ?? []);
16595
16997
  }
16596
16998
  getRequestIdsForTag(tag) {
16597
16999
  return new Set(this.requestIdsByTag.get(tag) ?? []);
@@ -16602,20 +17004,6 @@ var NetworkHistory = class {
16602
17004
  getKnownRequestIds() {
16603
17005
  return new Set(this.metadataByRequestId.keys());
16604
17006
  }
16605
- clearTag(tag) {
16606
- const requestIds = [...this.requestIdsByTag.get(tag) ?? []];
16607
- this.requestIdsByTag.delete(tag);
16608
- for (const requestId of requestIds) {
16609
- const metadata = this.metadataByRequestId.get(requestId);
16610
- if (!metadata) {
16611
- continue;
16612
- }
16613
- metadata.tags.delete(tag);
16614
- if (metadata.tags.size === 0) {
16615
- this.tombstoneRequestIds([requestId]);
16616
- }
16617
- }
16618
- }
16619
17007
  tombstoneRequestIds(requestIds) {
16620
17008
  for (const requestId of requestIds) {
16621
17009
  this.tombstonedRequestIds.add(requestId);
@@ -16625,8 +17013,8 @@ var NetworkHistory = class {
16625
17013
  }
16626
17014
  this.metadataByRequestId.delete(requestId);
16627
17015
  this.requestIdByRecordId.delete(metadata.recordId);
16628
- if (metadata.actionId !== void 0) {
16629
- this.requestIdsByActionId.get(metadata.actionId)?.delete(requestId);
17016
+ if (metadata.capture !== void 0) {
17017
+ this.requestIdsByCapture.get(metadata.capture)?.delete(requestId);
16630
17018
  }
16631
17019
  for (const tag of metadata.tags) {
16632
17020
  this.requestIdsByTag.get(tag)?.delete(requestId);
@@ -16636,7 +17024,7 @@ var NetworkHistory = class {
16636
17024
  clear() {
16637
17025
  this.metadataByRequestId.clear();
16638
17026
  this.requestIdByRecordId.clear();
16639
- this.requestIdsByActionId.clear();
17027
+ this.requestIdsByCapture.clear();
16640
17028
  this.requestIdsByTag.clear();
16641
17029
  this.tombstonedRequestIds.clear();
16642
17030
  }
@@ -16659,7 +17047,7 @@ var NetworkHistory = class {
16659
17047
  }
16660
17048
  return {
16661
17049
  recordId: metadata.recordId,
16662
- ...metadata.actionId === void 0 ? {} : { actionId: metadata.actionId },
17050
+ ...metadata.capture === void 0 ? {} : { capture: metadata.capture },
16663
17051
  ...metadata.tags.size === 0 ? {} : { tags: [...metadata.tags].sort() },
16664
17052
  ...metadata.savedAt === void 0 ? {} : { savedAt: metadata.savedAt },
16665
17053
  record: toProtocolNetworkRecord(record, {
@@ -17439,9 +17827,9 @@ function matchReverseTargetHints(channel, codec, targetHints) {
17439
17827
  matches.add(`host:${host}`);
17440
17828
  }
17441
17829
  }
17442
- for (const path16 of targetHints.paths ?? []) {
17443
- if (url.pathname.includes(path16)) {
17444
- matches.add(`path:${path16}`);
17830
+ for (const path17 of targetHints.paths ?? []) {
17831
+ if (url.pathname.includes(path17)) {
17832
+ matches.add(`path:${path17}`);
17445
17833
  }
17446
17834
  }
17447
17835
  for (const operationName of targetHints.operationNames ?? []) {
@@ -18402,11 +18790,11 @@ function inferClusterRelationship(seed, record) {
18402
18790
  var MATCHED_TLS_BINARY_NAMES = ["curl-impersonate-chrome", "curl_chrome"];
18403
18791
  async function executeMatchedTlsTransportRequest(input) {
18404
18792
  const binary = await resolveMatchedTlsBinary();
18405
- const workingDirectory = await promises.mkdtemp(path6__default.default.join(os.tmpdir(), "opensteer-matched-tls-"));
18406
- const headersPath = path6__default.default.join(workingDirectory, "headers.txt");
18407
- const bodyPath = path6__default.default.join(workingDirectory, "body.bin");
18408
- const cookiesPath = path6__default.default.join(workingDirectory, "cookies.txt");
18409
- const requestBodyPath = path6__default.default.join(workingDirectory, "request-body.bin");
18793
+ const workingDirectory = await promises.mkdtemp(path7__default.default.join(os.tmpdir(), "opensteer-matched-tls-"));
18794
+ const headersPath = path7__default.default.join(workingDirectory, "headers.txt");
18795
+ const bodyPath = path7__default.default.join(workingDirectory, "body.bin");
18796
+ const cookiesPath = path7__default.default.join(workingDirectory, "cookies.txt");
18797
+ const requestBodyPath = path7__default.default.join(workingDirectory, "request-body.bin");
18410
18798
  try {
18411
18799
  await promises.writeFile(cookiesPath, toNetscapeCookieJar(input.cookies ?? []), "utf8");
18412
18800
  if (input.request.body !== void 0) {
@@ -18463,10 +18851,10 @@ async function executeMatchedTlsTransportRequest(input) {
18463
18851
  }
18464
18852
  }
18465
18853
  async function resolveMatchedTlsBinary() {
18466
- const pathEntries = (process.env.PATH ?? "").split(path6__default.default.delimiter).filter((entry) => entry.length > 0);
18854
+ const pathEntries = (process.env.PATH ?? "").split(path7__default.default.delimiter).filter((entry) => entry.length > 0);
18467
18855
  for (const directory of pathEntries) {
18468
18856
  for (const name of MATCHED_TLS_BINARY_NAMES) {
18469
- const candidate = path6__default.default.join(directory, name);
18857
+ const candidate = path7__default.default.join(directory, name);
18470
18858
  if (await isExecutable(candidate)) {
18471
18859
  return candidate;
18472
18860
  }
@@ -18474,7 +18862,7 @@ async function resolveMatchedTlsBinary() {
18474
18862
  const files = await readDirSafe(directory);
18475
18863
  const discovered = files.find((file) => file.startsWith("curl_chrome"));
18476
18864
  if (discovered !== void 0) {
18477
- const candidate = path6__default.default.join(directory, discovered);
18865
+ const candidate = path7__default.default.join(directory, discovered);
18478
18866
  if (await isExecutable(candidate)) {
18479
18867
  return candidate;
18480
18868
  }
@@ -18485,7 +18873,7 @@ async function resolveMatchedTlsBinary() {
18485
18873
  );
18486
18874
  }
18487
18875
  async function spawnAndCollect(command, args, signal) {
18488
- return await new Promise((resolve5, reject) => {
18876
+ return await new Promise((resolve4, reject) => {
18489
18877
  const child = child_process.spawn(command, args, {
18490
18878
  stdio: ["ignore", "pipe", "pipe"]
18491
18879
  });
@@ -18518,7 +18906,7 @@ async function spawnAndCollect(command, args, signal) {
18518
18906
  );
18519
18907
  return;
18520
18908
  }
18521
- resolve5({ stdout, stderr });
18909
+ resolve4({ stdout, stderr });
18522
18910
  });
18523
18911
  });
18524
18912
  }
@@ -19277,8 +19665,8 @@ function encodeDataPath(tokens) {
19277
19665
  }
19278
19666
  return out;
19279
19667
  }
19280
- function parseDataPath(path16) {
19281
- const input = path16.trim();
19668
+ function parseDataPath(path17) {
19669
+ const input = path17.trim();
19282
19670
  if (input.length === 0) {
19283
19671
  return [];
19284
19672
  }
@@ -19328,8 +19716,8 @@ function parseDataPath(path16) {
19328
19716
  function inflateDataPathObject(flat) {
19329
19717
  let root = {};
19330
19718
  let initialized = false;
19331
- for (const [path16, value] of Object.entries(flat)) {
19332
- const tokens = parseDataPath(path16);
19719
+ for (const [path17, value] of Object.entries(flat)) {
19720
+ const tokens = parseDataPath(path17);
19333
19721
  if (!tokens || tokens.length === 0) {
19334
19722
  continue;
19335
19723
  }
@@ -19661,8 +20049,8 @@ function buildVariantDescriptorFromCluster(descriptors) {
19661
20049
  fields: mergedFields
19662
20050
  };
19663
20051
  }
19664
- function minimizePathMatchClauses(path16, mode) {
19665
- const normalized = sanitizeElementPath(path16);
20052
+ function minimizePathMatchClauses(path17, mode) {
20053
+ const normalized = sanitizeElementPath(path17);
19666
20054
  const nodes = normalized.nodes.map((node, index) => {
19667
20055
  const isLast = index === normalized.nodes.length - 1;
19668
20056
  const attrs = node.attrs || {};
@@ -19766,8 +20154,8 @@ function seedMinimalAttrClause(attrs) {
19766
20154
  }
19767
20155
  return null;
19768
20156
  }
19769
- function relaxPathForSingleSample(path16, mode) {
19770
- const normalized = sanitizeElementPath(path16);
20157
+ function relaxPathForSingleSample(path17, mode) {
20158
+ const normalized = sanitizeElementPath(path17);
19771
20159
  const relaxedNodes = normalized.nodes.map((node, index) => {
19772
20160
  const isLast = index === normalized.nodes.length - 1;
19773
20161
  const attrs = normalizeAttrsForSingleSample(node.attrs || {});
@@ -19852,8 +20240,8 @@ function shouldKeepAttrForSingleSample(key) {
19852
20240
  }
19853
20241
  return true;
19854
20242
  }
19855
- function buildPathStructureKey(path16) {
19856
- const normalized = sanitizeElementPath(path16);
20243
+ function buildPathStructureKey(path17) {
20244
+ const normalized = sanitizeElementPath(path17);
19857
20245
  return canonicalJsonString({
19858
20246
  context: (normalized.context || []).map((hop) => ({
19859
20247
  kind: hop.kind,
@@ -19980,30 +20368,30 @@ function buildArrayItemNode(fields) {
19980
20368
  }
19981
20369
  return node;
19982
20370
  }
19983
- function insertNodeAtPath(root, path16, node) {
19984
- const tokens = parseDataPath(path16);
20371
+ function insertNodeAtPath(root, path17, node) {
20372
+ const tokens = parseDataPath(path17);
19985
20373
  if (!tokens || !tokens.length) {
19986
20374
  throw new Error(
19987
- `Invalid persisted extraction path "${path16}": expected a non-empty object path.`
20375
+ `Invalid persisted extraction path "${path17}": expected a non-empty object path.`
19988
20376
  );
19989
20377
  }
19990
20378
  if (tokens.some((token) => token.kind === "index")) {
19991
20379
  throw new Error(
19992
- `Invalid persisted extraction path "${path16}": nested array indices are not supported in cached descriptors.`
20380
+ `Invalid persisted extraction path "${path17}": nested array indices are not supported in cached descriptors.`
19993
20381
  );
19994
20382
  }
19995
20383
  let current = root;
19996
20384
  for (let index = 0; index < tokens.length; index += 1) {
19997
20385
  const token = tokens[index];
19998
20386
  if (!token || token.kind !== "prop") {
19999
- throw new Error(`Invalid persisted extraction path "${path16}": expected object segment.`);
20387
+ throw new Error(`Invalid persisted extraction path "${path17}": expected object segment.`);
20000
20388
  }
20001
20389
  const isLast = index === tokens.length - 1;
20002
20390
  if (isLast) {
20003
20391
  const existing = current[token.key];
20004
20392
  if (existing) {
20005
20393
  throw new Error(
20006
- `Conflicting persisted extraction path "${path16}" detected while building descriptor tree.`
20394
+ `Conflicting persisted extraction path "${path17}" detected while building descriptor tree.`
20007
20395
  );
20008
20396
  }
20009
20397
  current[token.key] = node;
@@ -20018,7 +20406,7 @@ function insertNodeAtPath(root, path16, node) {
20018
20406
  }
20019
20407
  if (!isPersistedObjectNode(next)) {
20020
20408
  throw new Error(
20021
- `Conflicting persisted extraction path "${path16}" detected at "${token.key}".`
20409
+ `Conflicting persisted extraction path "${path17}" detected at "${token.key}".`
20022
20410
  );
20023
20411
  }
20024
20412
  current = next;
@@ -20053,7 +20441,7 @@ function buildItemRootForArrayIndex(entries) {
20053
20441
  }
20054
20442
  const paths = entries.map(
20055
20443
  (entry) => isPersistablePathField(entry.source) ? sanitizeElementPath(entry.source.path) : null
20056
- ).filter((path16) => path16 !== null);
20444
+ ).filter((path17) => path17 !== null);
20057
20445
  if (!paths.length) {
20058
20446
  return null;
20059
20447
  }
@@ -20074,7 +20462,7 @@ function getCommonPathPrefixLength(paths) {
20074
20462
  if (!paths.length) {
20075
20463
  return 0;
20076
20464
  }
20077
- const nodeChains = paths.map((path16) => path16.nodes);
20465
+ const nodeChains = paths.map((path17) => path17.nodes);
20078
20466
  const minLength = Math.min(...nodeChains.map((nodes) => nodes.length));
20079
20467
  if (!Number.isFinite(minLength) || minLength <= 0) {
20080
20468
  return 0;
@@ -20143,30 +20531,30 @@ function mergeElementPathsByMajority(paths) {
20143
20531
  if (!paths.length) {
20144
20532
  return null;
20145
20533
  }
20146
- const normalized = paths.map((path16) => sanitizeElementPath(path16));
20534
+ const normalized = paths.map((path17) => sanitizeElementPath(path17));
20147
20535
  const contextKey = pickModeString(
20148
- normalized.map((path16) => canonicalJsonString(path16.context)),
20536
+ normalized.map((path17) => canonicalJsonString(path17.context)),
20149
20537
  1
20150
20538
  );
20151
20539
  if (!contextKey) {
20152
20540
  return null;
20153
20541
  }
20154
- const sameContext = normalized.filter((path16) => canonicalJsonString(path16.context) === contextKey);
20542
+ const sameContext = normalized.filter((path17) => canonicalJsonString(path17.context) === contextKey);
20155
20543
  if (!sameContext.length) {
20156
20544
  return null;
20157
20545
  }
20158
20546
  const targetLength = pickModeNumber(
20159
- sameContext.map((path16) => path16.nodes.length),
20547
+ sameContext.map((path17) => path17.nodes.length),
20160
20548
  1
20161
20549
  ) ?? sameContext[0]?.nodes.length ?? 0;
20162
- const aligned = sameContext.filter((path16) => path16.nodes.length === targetLength);
20550
+ const aligned = sameContext.filter((path17) => path17.nodes.length === targetLength);
20163
20551
  if (!aligned.length) {
20164
20552
  return null;
20165
20553
  }
20166
20554
  const threshold = majorityThreshold(aligned.length);
20167
20555
  const nodes = [];
20168
20556
  for (let index = 0; index < targetLength; index += 1) {
20169
- const nodesAtIndex = aligned.map((path16) => path16.nodes[index]).filter((node) => node !== void 0);
20557
+ const nodesAtIndex = aligned.map((path17) => path17.nodes[index]).filter((node) => node !== void 0);
20170
20558
  if (!nodesAtIndex.length) {
20171
20559
  return null;
20172
20560
  }
@@ -20412,8 +20800,8 @@ function clonePathContext(context) {
20412
20800
  function clonePathNodes(nodes) {
20413
20801
  return JSON.parse(JSON.stringify(nodes || []));
20414
20802
  }
20415
- function cloneElementPath2(path16) {
20416
- return JSON.parse(JSON.stringify(path16));
20803
+ function cloneElementPath2(path17) {
20804
+ return JSON.parse(JSON.stringify(path17));
20417
20805
  }
20418
20806
  function clonePersistedOpensteerExtractionNode(node) {
20419
20807
  return JSON.parse(JSON.stringify(node));
@@ -20731,8 +21119,8 @@ function collectPersistedValueNodeRefs(node) {
20731
21119
  return [
20732
21120
  {
20733
21121
  path: sanitizeElementPath(node.$path),
20734
- replacePath: (path16) => {
20735
- node.$path = sanitizeElementPath(path16);
21122
+ replacePath: (path17) => {
21123
+ node.$path = sanitizeElementPath(path17);
20736
21124
  }
20737
21125
  }
20738
21126
  ];
@@ -20746,13 +21134,13 @@ function collectPersistedValueNodeRefs(node) {
20746
21134
  }
20747
21135
  return refs;
20748
21136
  }
20749
- function hasPositionClause(path16) {
20750
- return path16.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
21137
+ function hasPositionClause(path17) {
21138
+ return path17.nodes.some((node) => node.match.some((clause) => clause.kind === "position"));
20751
21139
  }
20752
- function stripPositionClauses2(path16) {
21140
+ function stripPositionClauses2(path17) {
20753
21141
  return sanitizeElementPath({
20754
- context: path16.context,
20755
- nodes: path16.nodes.map((node) => ({
21142
+ context: path17.context,
21143
+ nodes: path17.nodes.map((node) => ({
20756
21144
  ...node,
20757
21145
  match: node.match.filter((clause) => clause.kind !== "position")
20758
21146
  }))
@@ -21162,8 +21550,8 @@ function normalizeNonEmptyString2(name, value) {
21162
21550
  function normalizeKey(value) {
21163
21551
  return String(value ?? "").trim();
21164
21552
  }
21165
- function labelForPath(path16) {
21166
- return path16.trim().length === 0 ? "$" : path16;
21553
+ function labelForPath(path17) {
21554
+ return path17.trim().length === 0 ? "$" : path17;
21167
21555
  }
21168
21556
  function sha256Hex3(value) {
21169
21557
  return crypto.createHash("sha256").update(value).digest("hex");
@@ -23058,7 +23446,7 @@ async function pollTask(apiKey, taskId, signal) {
23058
23446
  const deadline = Date.now() + 12e4;
23059
23447
  while (Date.now() < deadline) {
23060
23448
  signal?.throwIfAborted?.();
23061
- await sleep4(3e3, signal);
23449
+ await sleep3(3e3, signal);
23062
23450
  const response = await fetch(CAPSOLVER_GET_TASK_RESULT_URL, {
23063
23451
  method: "POST",
23064
23452
  headers: {
@@ -23102,9 +23490,9 @@ function extractCaptchaToken(solution) {
23102
23490
  function readString(value) {
23103
23491
  return typeof value === "string" && value.length > 0 ? value : void 0;
23104
23492
  }
23105
- function sleep4(ms, signal) {
23106
- return new Promise((resolve5, reject) => {
23107
- const timeout = setTimeout(resolve5, ms);
23493
+ function sleep3(ms, signal) {
23494
+ return new Promise((resolve4, reject) => {
23495
+ const timeout = setTimeout(resolve4, ms);
23108
23496
  const abort = () => {
23109
23497
  clearTimeout(timeout);
23110
23498
  reject(new Error("captcha solve aborted"));
@@ -23156,7 +23544,7 @@ async function pollTask2(apiKey, taskId, signal) {
23156
23544
  const deadline = Date.now() + 12e4;
23157
23545
  while (Date.now() < deadline) {
23158
23546
  signal?.throwIfAborted?.();
23159
- await sleep5(5e3, signal);
23547
+ await sleep4(5e3, signal);
23160
23548
  const response = await fetch(TWO_CAPTCHA_GET_TASK_RESULT_URL, {
23161
23549
  method: "POST",
23162
23550
  headers: {
@@ -23200,9 +23588,9 @@ function extractCaptchaToken2(solution) {
23200
23588
  function readString2(value) {
23201
23589
  return typeof value === "string" && value.length > 0 ? value : void 0;
23202
23590
  }
23203
- function sleep5(ms, signal) {
23204
- return new Promise((resolve5, reject) => {
23205
- const timeout = setTimeout(resolve5, ms);
23591
+ function sleep4(ms, signal) {
23592
+ return new Promise((resolve4, reject) => {
23593
+ const timeout = setTimeout(resolve4, ms);
23206
23594
  const abort = () => {
23207
23595
  clearTimeout(timeout);
23208
23596
  reject(new Error("captcha solve aborted"));
@@ -23400,6 +23788,9 @@ function diffInteractionTraces(left, right) {
23400
23788
 
23401
23789
  // ../runtime-core/src/sdk/runtime.ts
23402
23790
  var requireForAuthRecipeHook = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bin.cjs', document.baseURI).href)));
23791
+ var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS = 5e3;
23792
+ var PENDING_OPERATION_EVENT_CAPTURE_LIMIT = 64;
23793
+ var PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS = 1e3;
23403
23794
  var OpensteerSessionRuntime = class {
23404
23795
  workspace;
23405
23796
  rootPath;
@@ -23412,6 +23803,9 @@ var OpensteerSessionRuntime = class {
23412
23803
  registryOverrides;
23413
23804
  cleanupRootOnClose;
23414
23805
  sessionInfoBase;
23806
+ observationConfig;
23807
+ observationSessionId;
23808
+ injectedObservationSink;
23415
23809
  root;
23416
23810
  engine;
23417
23811
  dom;
@@ -23421,6 +23815,9 @@ var OpensteerSessionRuntime = class {
23421
23815
  sessionRef;
23422
23816
  pageRef;
23423
23817
  runId;
23818
+ observations;
23819
+ operationEventStorage = new async_hooks.AsyncLocalStorage();
23820
+ pendingOperationEventCaptures = [];
23424
23821
  cookieJars = /* @__PURE__ */ new Map();
23425
23822
  recipeCache = /* @__PURE__ */ new Map();
23426
23823
  ownsEngine = false;
@@ -23428,7 +23825,7 @@ var OpensteerSessionRuntime = class {
23428
23825
  this.workspace = normalizeNamespace2(options.name);
23429
23826
  this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
23430
23827
  this.root = options.workspace;
23431
- this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6__default.default.resolve(process.cwd(), ".opensteer", "temporary", crypto.randomUUID());
23828
+ this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path7__default.default.resolve(process.cwd(), ".opensteer", "temporary", crypto.randomUUID());
23432
23829
  this.injectedEngine = options.engine;
23433
23830
  this.engineFactory = options.engineFactory;
23434
23831
  this.policy = options.policy ?? defaultPolicy();
@@ -23437,6 +23834,9 @@ var OpensteerSessionRuntime = class {
23437
23834
  this.registryOverrides = options.registryOverrides;
23438
23835
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
23439
23836
  this.sessionInfoBase = options.sessionInfo ?? {};
23837
+ this.observationConfig = normalizeObservabilityConfig(options.observability);
23838
+ this.observationSessionId = options.observationSessionId;
23839
+ this.injectedObservationSink = options.observationSink;
23440
23840
  if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
23441
23841
  throw new Error("OpensteerSessionRuntime requires an engine or engineFactory.");
23442
23842
  }
@@ -23468,6 +23868,20 @@ var OpensteerSessionRuntime = class {
23468
23868
  }
23469
23869
  };
23470
23870
  }
23871
+ async setObservabilityConfig(input) {
23872
+ this.observationConfig = normalizeObservabilityConfig(input);
23873
+ const observationSessionId = this.resolveObservationSessionId();
23874
+ if (observationSessionId === void 0) {
23875
+ return this.observationConfig;
23876
+ }
23877
+ const sink = this.injectedObservationSink ?? (await this.ensureRoot()).observations;
23878
+ this.observations = await sink.openSession({
23879
+ sessionId: observationSessionId,
23880
+ openedAt: Date.now(),
23881
+ config: this.observationConfig
23882
+ });
23883
+ return this.observationConfig;
23884
+ }
23471
23885
  async open(input = {}, options = {}) {
23472
23886
  assertValidSemanticOperationInput("session.open", input);
23473
23887
  if (input.workspace !== void 0 && normalizeNamespace2(input.workspace) !== this.workspace) {
@@ -23566,6 +23980,10 @@ var OpensteerSessionRuntime = class {
23566
23980
  return { pages: [] };
23567
23981
  }
23568
23982
  const startedAt = Date.now();
23983
+ const context = buildRuntimeTraceContext({
23984
+ sessionRef: this.sessionRef,
23985
+ pageRef: this.pageRef
23986
+ });
23569
23987
  try {
23570
23988
  const output = await this.runWithOperationTimeout(
23571
23989
  "page.list",
@@ -23580,19 +23998,18 @@ var OpensteerSessionRuntime = class {
23580
23998
  },
23581
23999
  options
23582
24000
  );
24001
+ const events = await this.drainPendingEngineEvents(context);
23583
24002
  await this.appendTrace({
23584
24003
  operation: "page.list",
23585
24004
  startedAt,
23586
24005
  completedAt: Date.now(),
23587
24006
  outcome: "ok",
24007
+ ...events === void 0 ? {} : { events },
23588
24008
  data: {
23589
24009
  count: output.pages.length,
23590
24010
  ...output.activePageRef === void 0 ? {} : { activePageRef: output.activePageRef }
23591
24011
  },
23592
- context: buildRuntimeTraceContext({
23593
- sessionRef: this.sessionRef,
23594
- pageRef: this.pageRef
23595
- })
24012
+ context
23596
24013
  });
23597
24014
  return output;
23598
24015
  } catch (error) {
@@ -23602,10 +24019,7 @@ var OpensteerSessionRuntime = class {
23602
24019
  completedAt: Date.now(),
23603
24020
  outcome: "error",
23604
24021
  error,
23605
- context: buildRuntimeTraceContext({
23606
- sessionRef: this.sessionRef,
23607
- pageRef: this.pageRef
23608
- })
24022
+ context
23609
24023
  });
23610
24024
  throw error;
23611
24025
  }
@@ -23782,34 +24196,32 @@ var OpensteerSessionRuntime = class {
23782
24196
  assertValidSemanticOperationInput("page.goto", input);
23783
24197
  const pageRef = await this.ensurePageRef();
23784
24198
  const startedAt = Date.now();
24199
+ let mutationCaptureDiagnostics;
23785
24200
  try {
23786
- const { navigation, state } = await this.runWithOperationTimeout(
24201
+ const { navigation, state } = await this.runMutationCapturedOperation(
23787
24202
  "page.goto",
24203
+ {
24204
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
24205
+ options
24206
+ },
23788
24207
  async (timeout) => {
23789
- const baselineRequestIds = await this.beginMutationCapture(timeout);
23790
- try {
23791
- const navigation2 = await this.navigatePage(
23792
- {
23793
- operation: "page.goto",
23794
- pageRef,
23795
- url: input.url
23796
- },
23797
- timeout
23798
- );
23799
- timeout.throwIfAborted();
23800
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
23801
- return {
23802
- navigation: navigation2,
23803
- state: await timeout.runStep(() => this.readSessionState())
23804
- };
23805
- } catch (error) {
23806
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
23807
- () => void 0
23808
- );
23809
- throw error;
23810
- }
24208
+ const navigation2 = await this.navigatePage(
24209
+ {
24210
+ operation: "page.goto",
24211
+ pageRef,
24212
+ url: input.url
24213
+ },
24214
+ timeout
24215
+ );
24216
+ timeout.throwIfAborted();
24217
+ return {
24218
+ navigation: navigation2,
24219
+ state: await timeout.runStep(() => this.readSessionState())
24220
+ };
23811
24221
  },
23812
- options
24222
+ (diagnostics) => {
24223
+ mutationCaptureDiagnostics = diagnostics;
24224
+ }
23813
24225
  );
23814
24226
  await this.appendTrace({
23815
24227
  operation: "page.goto",
@@ -23818,7 +24230,8 @@ var OpensteerSessionRuntime = class {
23818
24230
  outcome: "ok",
23819
24231
  data: {
23820
24232
  url: input.url,
23821
- state
24233
+ state,
24234
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
23822
24235
  },
23823
24236
  context: buildRuntimeTraceContext({
23824
24237
  sessionRef: this.sessionRef,
@@ -23834,6 +24247,7 @@ var OpensteerSessionRuntime = class {
23834
24247
  completedAt: Date.now(),
23835
24248
  outcome: "error",
23836
24249
  error,
24250
+ data: buildMutationCaptureTraceData(mutationCaptureDiagnostics),
23837
24251
  context: buildRuntimeTraceContext({
23838
24252
  sessionRef: this.sessionRef,
23839
24253
  pageRef
@@ -23846,34 +24260,29 @@ var OpensteerSessionRuntime = class {
23846
24260
  assertValidSemanticOperationInput("page.evaluate", input);
23847
24261
  const pageRef = input.pageRef ?? await this.ensurePageRef();
23848
24262
  const startedAt = Date.now();
24263
+ let mutationCaptureDiagnostics;
23849
24264
  try {
23850
- const output = await this.runWithOperationTimeout(
24265
+ const output = await this.runMutationCapturedOperation(
23851
24266
  "page.evaluate",
24267
+ { options },
23852
24268
  async (timeout) => {
23853
- const baselineRequestIds = await this.beginMutationCapture(timeout);
23854
- try {
23855
- const remainingMs = timeout.remainingMs();
23856
- const evaluated = await timeout.runStep(
23857
- () => this.requireEngine().evaluatePage({
23858
- pageRef,
23859
- script: input.script,
23860
- ...input.args === void 0 ? {} : { args: input.args },
23861
- ...remainingMs === void 0 ? {} : { timeoutMs: remainingMs }
23862
- })
23863
- );
23864
- await this.completeMutationCapture(timeout, baselineRequestIds, void 0);
23865
- return {
24269
+ const remainingMs = timeout.remainingMs();
24270
+ const evaluated = await timeout.runStep(
24271
+ () => this.requireEngine().evaluatePage({
23866
24272
  pageRef,
23867
- value: toJsonValueOrNull(evaluated.data)
23868
- };
23869
- } catch (error) {
23870
- await this.completeMutationCapture(timeout, baselineRequestIds, void 0).catch(
23871
- () => void 0
23872
- );
23873
- throw error;
23874
- }
24273
+ script: input.script,
24274
+ ...input.args === void 0 ? {} : { args: input.args },
24275
+ ...remainingMs === void 0 ? {} : { timeoutMs: remainingMs }
24276
+ })
24277
+ );
24278
+ return {
24279
+ pageRef,
24280
+ value: toJsonValueOrNull(evaluated.data)
24281
+ };
23875
24282
  },
23876
- options
24283
+ (diagnostics) => {
24284
+ mutationCaptureDiagnostics = diagnostics;
24285
+ }
23877
24286
  );
23878
24287
  await this.appendTrace({
23879
24288
  operation: "page.evaluate",
@@ -23882,7 +24291,8 @@ var OpensteerSessionRuntime = class {
23882
24291
  outcome: "ok",
23883
24292
  data: {
23884
24293
  pageRef: output.pageRef,
23885
- value: output.value
24294
+ value: output.value,
24295
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
23886
24296
  },
23887
24297
  context: buildRuntimeTraceContext({
23888
24298
  sessionRef: this.sessionRef,
@@ -23897,6 +24307,7 @@ var OpensteerSessionRuntime = class {
23897
24307
  completedAt: Date.now(),
23898
24308
  outcome: "error",
23899
24309
  error,
24310
+ data: buildMutationCaptureTraceData(mutationCaptureDiagnostics),
23900
24311
  context: buildRuntimeTraceContext({
23901
24312
  sessionRef: this.sessionRef,
23902
24313
  pageRef
@@ -23996,22 +24407,25 @@ var OpensteerSessionRuntime = class {
23996
24407
  },
23997
24408
  options
23998
24409
  );
24410
+ const context = buildRuntimeTraceContext({
24411
+ sessionRef: this.sessionRef,
24412
+ pageRef
24413
+ });
24414
+ const events = await this.drainPendingEngineEvents(context);
23999
24415
  await this.appendTrace({
24000
24416
  operation: "page.snapshot",
24001
24417
  startedAt,
24002
24418
  completedAt: Date.now(),
24003
24419
  outcome: "ok",
24004
24420
  artifacts,
24421
+ ...events === void 0 ? {} : { events },
24005
24422
  data: {
24006
24423
  mode,
24007
24424
  url: output.url,
24008
24425
  title: output.title,
24009
24426
  counterCount: output.counters.length
24010
24427
  },
24011
- context: buildRuntimeTraceContext({
24012
- sessionRef: this.sessionRef,
24013
- pageRef
24014
- })
24428
+ context
24015
24429
  });
24016
24430
  return output;
24017
24431
  } catch (error) {
@@ -24336,17 +24750,29 @@ var OpensteerSessionRuntime = class {
24336
24750
  "network.clear",
24337
24751
  async (timeout) => {
24338
24752
  if (this.sessionRef !== void 0) {
24339
- const liveRequestIds = await this.readLiveRequestIds(timeout, {
24340
- includeCurrentPageOnly: false
24341
- });
24342
- if (input.tag === void 0) {
24753
+ if (input.capture !== void 0 || input.tag !== void 0) {
24754
+ const records = await this.queryLiveNetwork(
24755
+ {
24756
+ ...input.capture === void 0 ? {} : { capture: input.capture },
24757
+ ...input.tag === void 0 ? {} : { tag: input.tag }
24758
+ },
24759
+ timeout,
24760
+ {
24761
+ ignoreLimit: true
24762
+ }
24763
+ );
24764
+ this.networkHistory.tombstoneRequestIds(
24765
+ records.map((record) => record.record.requestId)
24766
+ );
24767
+ } else {
24768
+ const liveRequestIds = await this.readLiveRequestIds(timeout, {
24769
+ includeCurrentPageOnly: false
24770
+ });
24343
24771
  this.networkHistory.tombstoneRequestIds(liveRequestIds);
24344
24772
  }
24345
24773
  }
24346
- if (input.tag === void 0) {
24774
+ if (input.capture === void 0 && input.tag === void 0) {
24347
24775
  this.networkHistory.tombstoneRequestIds(this.networkHistory.getKnownRequestIds());
24348
- } else {
24349
- this.networkHistory.clearTag(input.tag);
24350
24776
  }
24351
24777
  return {
24352
24778
  clearedCount: await timeout.runStep(() => root.registry.savedNetwork.clear(input))
@@ -24360,6 +24786,7 @@ var OpensteerSessionRuntime = class {
24360
24786
  completedAt: Date.now(),
24361
24787
  outcome: "ok",
24362
24788
  data: {
24789
+ ...input.capture === void 0 ? {} : { capture: input.capture },
24363
24790
  ...input.tag === void 0 ? {} : { tag: input.tag },
24364
24791
  clearedCount: output.clearedCount
24365
24792
  }
@@ -25541,7 +25968,9 @@ var OpensteerSessionRuntime = class {
25541
25968
  };
25542
25969
  }
25543
25970
  const bindings = /* @__PURE__ */ new Map();
25544
- const baselineRequestIds = await this.beginMutationCapture(timeout);
25971
+ const baselineRequestIds = await this.readLiveRequestIds(timeout, {
25972
+ includeCurrentPageOnly: true
25973
+ });
25545
25974
  const pageRef = explicitPageRef ?? await this.ensurePageRef();
25546
25975
  const validatorMap = new Map(
25547
25976
  packageRecord.payload.validators.map((validator) => [validator.id, validator])
@@ -27213,33 +27642,38 @@ var OpensteerSessionRuntime = class {
27213
27642
  assertValidSemanticOperationInput("computer.execute", input);
27214
27643
  const pageRef = await this.ensurePageRef();
27215
27644
  const startedAt = Date.now();
27645
+ let mutationCaptureDiagnostics;
27646
+ let boundaryDiagnostics;
27216
27647
  try {
27217
- const { artifacts, output } = await this.runWithOperationTimeout(
27648
+ const { artifacts, output } = await this.runMutationCapturedOperation(
27218
27649
  "computer.execute",
27650
+ {
27651
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
27652
+ options
27653
+ },
27219
27654
  async (timeout) => {
27220
- const baselineRequestIds = await this.beginMutationCapture(timeout);
27221
27655
  try {
27222
27656
  const output2 = await this.requireComputer().execute({
27223
27657
  pageRef,
27224
27658
  input,
27225
27659
  timeout
27226
27660
  });
27661
+ boundaryDiagnostics = takeActionBoundaryDiagnostics(timeout.signal);
27227
27662
  timeout.throwIfAborted();
27228
27663
  this.pageRef = output2.pageRef;
27229
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
27230
27664
  const artifacts2 = await this.persistComputerArtifacts(output2, timeout);
27231
27665
  return {
27232
27666
  artifacts: { manifests: artifacts2.manifests },
27233
27667
  output: artifacts2.output
27234
27668
  };
27235
27669
  } catch (error) {
27236
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
27237
- () => void 0
27238
- );
27670
+ boundaryDiagnostics ??= takeActionBoundaryDiagnostics(timeout.signal);
27239
27671
  throw error;
27240
27672
  }
27241
27673
  },
27242
- options
27674
+ (diagnostics) => {
27675
+ mutationCaptureDiagnostics = diagnostics;
27676
+ }
27243
27677
  );
27244
27678
  await this.appendTrace({
27245
27679
  operation: "computer.execute",
@@ -27255,6 +27689,8 @@ var OpensteerSessionRuntime = class {
27255
27689
  nativeViewport: output.nativeViewport,
27256
27690
  displayScale: output.displayScale,
27257
27691
  timing: output.timing,
27692
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
27693
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics),
27258
27694
  ...output.trace === void 0 ? {} : { trace: output.trace }
27259
27695
  },
27260
27696
  context: buildRuntimeTraceContext({
@@ -27273,6 +27709,10 @@ var OpensteerSessionRuntime = class {
27273
27709
  completedAt: Date.now(),
27274
27710
  outcome: "error",
27275
27711
  error,
27712
+ data: {
27713
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
27714
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
27715
+ },
27276
27716
  context: buildRuntimeTraceContext({
27277
27717
  sessionRef: this.sessionRef,
27278
27718
  pageRef: this.pageRef
@@ -27376,44 +27816,53 @@ var OpensteerSessionRuntime = class {
27376
27816
  async runDomAction(operation, input, executor, options = {}) {
27377
27817
  const pageRef = await this.ensurePageRef();
27378
27818
  const startedAt = Date.now();
27819
+ let mutationCaptureDiagnostics;
27820
+ let boundaryDiagnostics;
27379
27821
  try {
27380
- const { executed, preparedTarget } = await this.runWithOperationTimeout(
27822
+ const { executed, preparedTarget } = await this.runMutationCapturedOperation(
27381
27823
  operation,
27824
+ {
27825
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
27826
+ options
27827
+ },
27382
27828
  async (timeout) => {
27383
- const baselineRequestIds = await this.beginMutationCapture(timeout);
27829
+ const preparedTarget2 = await this.prepareDomTarget(
27830
+ pageRef,
27831
+ operation,
27832
+ input.target,
27833
+ input.persistAsDescription,
27834
+ timeout
27835
+ );
27384
27836
  try {
27385
- const preparedTarget2 = await this.prepareDomTarget(
27386
- pageRef,
27387
- operation,
27388
- input.target,
27389
- input.persistAsDescription,
27390
- timeout
27391
- );
27392
27837
  const executed2 = await executor(pageRef, preparedTarget2.target, timeout);
27393
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
27838
+ boundaryDiagnostics = takeActionBoundaryDiagnostics(timeout.signal);
27394
27839
  return {
27395
27840
  executed: executed2,
27396
27841
  preparedTarget: preparedTarget2
27397
27842
  };
27398
27843
  } catch (error) {
27399
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
27400
- () => void 0
27401
- );
27844
+ boundaryDiagnostics ??= takeActionBoundaryDiagnostics(timeout.signal);
27402
27845
  throw error;
27403
27846
  }
27404
27847
  },
27405
- options
27848
+ (diagnostics) => {
27849
+ mutationCaptureDiagnostics = diagnostics;
27850
+ }
27406
27851
  );
27407
27852
  const output = toOpensteerActionResult(executed.result, preparedTarget.persistedDescription);
27853
+ const actionEvents = "events" in executed.result ? executed.result.events : void 0;
27408
27854
  await this.appendTrace({
27409
27855
  operation,
27410
27856
  startedAt,
27411
27857
  completedAt: Date.now(),
27412
27858
  outcome: "ok",
27859
+ ...actionEvents === void 0 ? {} : { events: actionEvents },
27413
27860
  data: {
27414
27861
  target: output.target,
27415
27862
  ...output.point === void 0 ? {} : { point: output.point },
27416
- ...output.persistedDescription === void 0 ? {} : { persistedDescription: output.persistedDescription }
27863
+ ...output.persistedDescription === void 0 ? {} : { persistedDescription: output.persistedDescription },
27864
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
27865
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
27417
27866
  },
27418
27867
  context: buildRuntimeTraceContext({
27419
27868
  sessionRef: this.sessionRef,
@@ -27431,6 +27880,10 @@ var OpensteerSessionRuntime = class {
27431
27880
  completedAt: Date.now(),
27432
27881
  outcome: "error",
27433
27882
  error,
27883
+ data: {
27884
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
27885
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
27886
+ },
27434
27887
  context: buildRuntimeTraceContext({
27435
27888
  sessionRef: this.sessionRef,
27436
27889
  pageRef
@@ -27540,7 +27993,7 @@ var OpensteerSessionRuntime = class {
27540
27993
  const filtered = filterNetworkQueryRecords(metadataRecords, {
27541
27994
  ...input.recordId === void 0 ? {} : { recordId: input.recordId },
27542
27995
  ...input.requestId === void 0 ? {} : { requestId: input.requestId },
27543
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
27996
+ ...input.capture === void 0 ? {} : { capture: input.capture },
27544
27997
  ...input.tag === void 0 ? {} : { tag: input.tag },
27545
27998
  ...input.url === void 0 ? {} : { url: input.url },
27546
27999
  ...input.hostname === void 0 ? {} : { hostname: input.hostname },
@@ -27746,32 +28199,68 @@ var OpensteerSessionRuntime = class {
27746
28199
  artifactId: manifest.artifactId
27747
28200
  };
27748
28201
  }
27749
- beginMutationCapture(timeout) {
27750
- return this.readLiveRequestIds(timeout, {
27751
- includeCurrentPageOnly: true
27752
- });
27753
- }
27754
- async completeMutationCapture(timeout, baselineRequestIds, networkTag) {
27755
- const records = await timeout.runStep(
27756
- () => this.readLiveNetworkRecords(
27757
- {
27758
- includeBodies: false,
27759
- includeCurrentPageOnly: true
28202
+ async runMutationCapturedOperation(operation, input, execute, onFinalized) {
28203
+ let plan;
28204
+ try {
28205
+ const result = await this.runWithOperationTimeout(
28206
+ operation,
28207
+ async (timeout) => {
28208
+ plan = await this.beginMutationCapture(timeout, input.captureNetwork);
28209
+ return execute(timeout);
27760
28210
  },
27761
- timeout.signal
27762
- )
28211
+ input.options
28212
+ );
28213
+ const diagnostics = await this.finalizeMutationCaptureBestEffort(plan);
28214
+ onFinalized?.(diagnostics);
28215
+ return result;
28216
+ } catch (error) {
28217
+ const diagnostics = await this.finalizeMutationCaptureBestEffort(plan);
28218
+ onFinalized?.(diagnostics);
28219
+ throw error;
28220
+ }
28221
+ }
28222
+ async beginMutationCapture(timeout, capture) {
28223
+ if (capture === void 0) {
28224
+ return void 0;
28225
+ }
28226
+ return {
28227
+ baselineRequestIds: await this.readLiveRequestIds(timeout, {
28228
+ includeCurrentPageOnly: true
28229
+ }),
28230
+ capture
28231
+ };
28232
+ }
28233
+ async finalizeMutationCaptureBestEffort(plan) {
28234
+ if (plan === void 0) {
28235
+ return {};
28236
+ }
28237
+ try {
28238
+ await withDetachedTimeoutSignal(MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS, async (signal) => {
28239
+ await this.completeMutationCaptureWithSignal(signal, plan);
28240
+ });
28241
+ return {};
28242
+ } catch (error) {
28243
+ return {
28244
+ finalizeError: normalizeOpensteerError(error)
28245
+ };
28246
+ }
28247
+ }
28248
+ async completeMutationCaptureWithSignal(signal, plan) {
28249
+ const records = await this.readLiveNetworkRecords(
28250
+ {
28251
+ includeBodies: false,
28252
+ includeCurrentPageOnly: true
28253
+ },
28254
+ signal
27763
28255
  );
27764
- const delta = records.filter((record) => !baselineRequestIds.has(record.record.requestId));
28256
+ const delta = records.filter((record) => !plan.baselineRequestIds.has(record.record.requestId));
27765
28257
  if (delta.length === 0) {
27766
28258
  return;
27767
28259
  }
27768
- this.networkHistory.assignActionId(delta, `action:${crypto.randomUUID()}`);
27769
- if (networkTag !== void 0) {
27770
- this.networkHistory.addTag(delta, networkTag);
27771
- }
27772
- await this.persistLiveRequestIds(
28260
+ this.networkHistory.assignCapture(delta, plan.capture);
28261
+ await this.persistLiveRequestIdsWithSignal(
27773
28262
  delta.map((record) => record.record.requestId),
27774
- timeout,
28263
+ signal,
27775
28264
  {
27776
28265
  includeCurrentPageOnly: true
27777
28266
  }
@@ -28178,27 +28667,28 @@ var OpensteerSessionRuntime = class {
28178
28667
  });
28179
28668
  }
28180
28669
  async persistLiveRequestIds(requestIds, timeout, options) {
28670
+ return timeout.runStep(
28671
+ () => this.persistLiveRequestIdsWithSignal(requestIds, timeout.signal, options)
28672
+ );
28673
+ }
28674
+ async persistLiveRequestIdsWithSignal(requestIds, signal, options) {
28181
28675
  if (requestIds.length === 0) {
28182
28676
  return [];
28183
28677
  }
28184
28678
  const root = await this.ensureRoot();
28185
- const browserRecords = await timeout.runStep(
28186
- () => this.readBrowserNetworkRecords(
28187
- {
28188
- includeBodies: true,
28189
- includeCurrentPageOnly: options.includeCurrentPageOnly,
28190
- ...options.pageRef === void 0 ? {} : { pageRef: options.pageRef },
28191
- requestIds
28192
- },
28193
- timeout.signal
28194
- )
28195
- );
28196
- return timeout.runStep(
28197
- () => this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
28198
- bodyWriteMode: "authoritative",
28199
- redactSecretHeaders: false
28200
- })
28679
+ const browserRecords = await this.readBrowserNetworkRecords(
28680
+ {
28681
+ includeBodies: true,
28682
+ includeCurrentPageOnly: options.includeCurrentPageOnly,
28683
+ ...options.pageRef === void 0 ? {} : { pageRef: options.pageRef },
28684
+ requestIds
28685
+ },
28686
+ signal
28201
28687
  );
28688
+ return this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
28689
+ bodyWriteMode: "authoritative",
28690
+ redactSecretHeaders: false
28691
+ });
28202
28692
  }
28203
28693
  async syncPersistedNetworkSelection(timeout, input, options) {
28204
28694
  if (this.sessionRef === void 0) {
@@ -28240,7 +28730,7 @@ var OpensteerSessionRuntime = class {
28240
28730
  ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
28241
28731
  ...input.recordId === void 0 ? {} : { recordId: input.recordId },
28242
28732
  ...input.requestId === void 0 ? {} : { requestId: input.requestId },
28243
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
28733
+ ...input.capture === void 0 ? {} : { capture: input.capture },
28244
28734
  ...input.tag === void 0 ? {} : { tag: input.tag },
28245
28735
  ...input.url === void 0 ? {} : { url: input.url },
28246
28736
  ...input.hostname === void 0 ? {} : { hostname: input.hostname },
@@ -28257,7 +28747,7 @@ var OpensteerSessionRuntime = class {
28257
28747
  ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
28258
28748
  ...input.recordId === void 0 ? {} : { recordId: input.recordId },
28259
28749
  ...input.requestId === void 0 ? {} : { requestId: input.requestId },
28260
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
28750
+ ...input.capture === void 0 ? {} : { capture: input.capture },
28261
28751
  ...input.url === void 0 ? {} : { url: input.url },
28262
28752
  ...input.hostname === void 0 ? {} : { hostname: input.hostname },
28263
28753
  ...input.path === void 0 ? {} : { path: input.path },
@@ -29116,7 +29606,7 @@ var OpensteerSessionRuntime = class {
29116
29606
  }
29117
29607
  async executeAuthRecipeHook(step, variables) {
29118
29608
  const resolved = requireForAuthRecipeHook.resolve(step.hook.specifier, {
29119
- paths: [path6__default.default.dirname(this.rootPath)]
29609
+ paths: [path7__default.default.dirname(this.rootPath)]
29120
29610
  });
29121
29611
  const module = await import(url.pathToFileURL(resolved).href);
29122
29612
  const handler = module[step.hook.export];
@@ -29488,14 +29978,18 @@ var OpensteerSessionRuntime = class {
29488
29978
  return this.engine;
29489
29979
  }
29490
29980
  if (this.injectedEngine) {
29491
- this.engine = this.injectedEngine;
29981
+ this.engine = this.wrapEngineWithObservationCapture(
29982
+ this.injectedEngine
29983
+ );
29492
29984
  this.ownsEngine = false;
29493
29985
  return this.engine;
29494
29986
  }
29495
29987
  if (this.engineFactory === void 0) {
29496
29988
  throw new Error("Opensteer engine factory is not initialized");
29497
29989
  }
29498
- this.engine = await this.engineFactory(overrides);
29990
+ this.engine = this.wrapEngineWithObservationCapture(
29991
+ await this.engineFactory(overrides)
29992
+ );
29499
29993
  this.ownsEngine = true;
29500
29994
  return this.engine;
29501
29995
  }
@@ -29695,6 +30189,15 @@ var OpensteerSessionRuntime = class {
29695
30189
  return;
29696
30190
  }
29697
30191
  const root = await this.ensureRoot();
30192
+ const capturedStepEvents = input.events ?? this.consumePendingOperationEventCapture(
30193
+ input.operation,
30194
+ input.startedAt,
30195
+ input.completedAt
30196
+ );
30197
+ const drainedStepEvents = input.events === void 0 ? await this.drainPendingEngineEvents(input.context) : void 0;
30198
+ const stepEvents = mergeObservedStepEvents(capturedStepEvents, drainedStepEvents);
30199
+ const normalizedData = input.data === void 0 ? void 0 : toCanonicalJsonValue(input.data);
30200
+ const normalizedError = input.error === void 0 ? void 0 : normalizeOpensteerError(input.error);
29698
30201
  const artifacts = input.artifacts === void 0 ? void 0 : await Promise.all(
29699
30202
  input.artifacts.manifests.map(async (manifest) => {
29700
30203
  const reference = await root.artifacts.toProtocolArtifactReference(
@@ -29707,19 +30210,56 @@ var OpensteerSessionRuntime = class {
29707
30210
  return reference;
29708
30211
  })
29709
30212
  );
29710
- await root.traces.append(runId, {
30213
+ const traceEntry = await root.traces.append(runId, {
29711
30214
  operation: input.operation,
29712
30215
  outcome: input.outcome,
29713
30216
  startedAt: input.startedAt,
29714
30217
  completedAt: input.completedAt,
29715
30218
  ...input.context === void 0 ? {} : { context: input.context },
29716
- ...input.events === void 0 ? {} : { events: input.events },
30219
+ ...stepEvents === void 0 ? {} : { events: stepEvents },
29717
30220
  ...artifacts === void 0 ? {} : { artifacts },
29718
- ...input.data === void 0 ? {} : { data: toCanonicalJsonValue(input.data) },
29719
- ...input.error === void 0 ? {} : {
29720
- error: normalizeOpensteerError(input.error)
30221
+ ...normalizedData === void 0 ? {} : { data: normalizedData },
30222
+ ...normalizedError === void 0 ? {} : {
30223
+ error: normalizedError
29721
30224
  }
29722
30225
  });
30226
+ const observationSession = await this.ensureObservationSession().catch(() => void 0);
30227
+ if (observationSession === void 0 || this.observationConfig.profile === "off") {
30228
+ return;
30229
+ }
30230
+ const observationArtifactIds = input.artifacts === void 0 ? void 0 : (await Promise.allSettled(
30231
+ input.artifacts.manifests.map(async (manifest) => {
30232
+ const artifact = await observationSession.writeArtifact({
30233
+ artifactId: manifest.artifactId,
30234
+ kind: observationArtifactKindFromManifest(manifest.kind),
30235
+ createdAt: manifest.createdAt,
30236
+ context: manifest.scope,
30237
+ mediaType: manifest.mediaType,
30238
+ byteLength: manifest.byteLength,
30239
+ sha256: manifest.sha256,
30240
+ opensteerArtifactId: manifest.artifactId,
30241
+ storageKey: manifestToExternalBinaryLocation(root.rootPath, manifest).uri
30242
+ });
30243
+ return artifact.artifactId;
30244
+ })
30245
+ )).flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
30246
+ const observationEvents = buildObservationEventsFromTrace({
30247
+ traceId: traceEntry.traceId,
30248
+ stepId: traceEntry.stepId,
30249
+ operation: input.operation,
30250
+ outcome: input.outcome,
30251
+ startedAt: input.startedAt,
30252
+ completedAt: input.completedAt,
30253
+ ...input.context === void 0 ? {} : { context: input.context },
30254
+ ...stepEvents === void 0 ? {} : { events: stepEvents },
30255
+ ...normalizedData === void 0 ? {} : { data: normalizedData },
30256
+ ...normalizedError === void 0 ? {} : { error: normalizedError },
30257
+ ...observationArtifactIds === void 0 ? {} : { artifactIds: observationArtifactIds },
30258
+ profile: this.observationConfig.profile
30259
+ });
30260
+ if (observationEvents.length > 0) {
30261
+ await observationSession.appendBatch(observationEvents).catch(() => void 0);
30262
+ }
29723
30263
  }
29724
30264
  async cleanupSessionResources(engine, pageRef, sessionRef) {
29725
30265
  if (pageRef !== void 0) {
@@ -29731,6 +30271,7 @@ var OpensteerSessionRuntime = class {
29731
30271
  }
29732
30272
  async resetRuntimeState(options) {
29733
30273
  const engine = this.engine;
30274
+ const observations = this.observations;
29734
30275
  this.networkHistory.clear();
29735
30276
  this.sessionRef = void 0;
29736
30277
  this.pageRef = void 0;
@@ -29739,20 +30280,140 @@ var OpensteerSessionRuntime = class {
29739
30280
  this.computer = void 0;
29740
30281
  this.extractionDescriptors = void 0;
29741
30282
  this.engine = void 0;
30283
+ this.observations = void 0;
30284
+ this.pendingOperationEventCaptures.length = 0;
30285
+ await observations?.close("runtime_reset").catch(() => void 0);
29742
30286
  if (options.disposeEngine && this.ownsEngine && engine?.dispose) {
29743
30287
  await engine.dispose();
29744
30288
  }
29745
30289
  this.ownsEngine = false;
29746
30290
  }
30291
+ async ensureObservationSession() {
30292
+ if (this.observationConfig.profile === "off") {
30293
+ return void 0;
30294
+ }
30295
+ if (this.observations !== void 0) {
30296
+ return this.observations;
30297
+ }
30298
+ const observationSessionId = this.resolveObservationSessionId();
30299
+ if (observationSessionId === void 0) {
30300
+ return void 0;
30301
+ }
30302
+ const sink = this.injectedObservationSink ?? (await this.ensureRoot()).observations;
30303
+ this.observations = await sink.openSession({
30304
+ sessionId: observationSessionId,
30305
+ openedAt: Date.now(),
30306
+ config: this.observationConfig
30307
+ });
30308
+ return this.observations;
30309
+ }
30310
+ resolveObservationSessionId() {
30311
+ return this.observationSessionId ?? this.sessionRef;
30312
+ }
29747
30313
  runWithOperationTimeout(operation, callback, options = {}) {
29748
- return runWithPolicyTimeout(
29749
- this.policy.timeout,
29750
- {
29751
- operation,
29752
- ...options.signal === void 0 ? {} : { signal: options.signal }
29753
- },
29754
- callback
29755
- );
30314
+ const existingCollector = this.operationEventStorage.getStore();
30315
+ if (existingCollector !== void 0) {
30316
+ return runWithPolicyTimeout(
30317
+ this.policy.timeout,
30318
+ {
30319
+ operation,
30320
+ ...options.signal === void 0 ? {} : { signal: options.signal }
30321
+ },
30322
+ callback
30323
+ );
30324
+ }
30325
+ const collector = [];
30326
+ const startedAt = Date.now();
30327
+ return this.operationEventStorage.run(collector, async () => {
30328
+ try {
30329
+ return await runWithPolicyTimeout(
30330
+ this.policy.timeout,
30331
+ {
30332
+ operation,
30333
+ ...options.signal === void 0 ? {} : { signal: options.signal }
30334
+ },
30335
+ callback
30336
+ );
30337
+ } finally {
30338
+ this.recordPendingOperationEventCapture({
30339
+ operation,
30340
+ startedAt,
30341
+ completedAt: Date.now(),
30342
+ events: collector
30343
+ });
30344
+ }
30345
+ });
30346
+ }
30347
+ wrapEngineWithObservationCapture(engine) {
30348
+ return new Proxy(engine, {
30349
+ get: (target, property, receiver) => {
30350
+ const value = Reflect.get(target, property, receiver);
30351
+ if (typeof value !== "function") {
30352
+ return value;
30353
+ }
30354
+ return (...args) => {
30355
+ const result = Reflect.apply(value, target, args);
30356
+ if (!(result instanceof Promise)) {
30357
+ return result;
30358
+ }
30359
+ return result.then((resolved) => {
30360
+ this.captureObservedStepEvents(resolved);
30361
+ return resolved;
30362
+ });
30363
+ };
30364
+ }
30365
+ });
30366
+ }
30367
+ captureObservedStepEvents(value) {
30368
+ const collector = this.operationEventStorage.getStore();
30369
+ if (collector === void 0) {
30370
+ return;
30371
+ }
30372
+ const events = readStepResultEvents(value);
30373
+ if (events === void 0 || events.length === 0) {
30374
+ return;
30375
+ }
30376
+ collector.push(...events);
30377
+ }
30378
+ recordPendingOperationEventCapture(capture) {
30379
+ if (capture.events.length === 0) {
30380
+ return;
30381
+ }
30382
+ this.pendingOperationEventCaptures.push({
30383
+ ...capture,
30384
+ events: [...capture.events]
30385
+ });
30386
+ if (this.pendingOperationEventCaptures.length > PENDING_OPERATION_EVENT_CAPTURE_LIMIT) {
30387
+ this.pendingOperationEventCaptures.splice(
30388
+ 0,
30389
+ this.pendingOperationEventCaptures.length - PENDING_OPERATION_EVENT_CAPTURE_LIMIT
30390
+ );
30391
+ }
30392
+ }
30393
+ consumePendingOperationEventCapture(operation, startedAt, completedAt) {
30394
+ for (let index = this.pendingOperationEventCaptures.length - 1; index >= 0; index -= 1) {
30395
+ const capture = this.pendingOperationEventCaptures[index];
30396
+ if (capture === void 0) {
30397
+ continue;
30398
+ }
30399
+ if (capture.operation !== operation) {
30400
+ continue;
30401
+ }
30402
+ if (capture.startedAt < startedAt - PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS || capture.completedAt > completedAt + PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS) {
30403
+ continue;
30404
+ }
30405
+ this.pendingOperationEventCaptures.splice(index, 1);
30406
+ return capture.events;
30407
+ }
30408
+ return void 0;
30409
+ }
30410
+ async drainPendingEngineEvents(context) {
30411
+ const pageRef = context?.pageRef ?? this.pageRef;
30412
+ if (pageRef === void 0 || this.engine === void 0) {
30413
+ return void 0;
30414
+ }
30415
+ const events = await this.engine.drainEvents({ pageRef }).catch(() => []);
30416
+ return events.length > 0 ? events : void 0;
29756
30417
  }
29757
30418
  async navigatePage(input, timeout) {
29758
30419
  const remainingMs = timeout.remainingMs();
@@ -29788,6 +30449,34 @@ function buildRuntimeTraceContext(input) {
29788
30449
  function buildArtifactScope(input) {
29789
30450
  return buildRuntimeTraceContext(input);
29790
30451
  }
30452
+ function readStepResultEvents(value) {
30453
+ if (value === null || typeof value !== "object") {
30454
+ return void 0;
30455
+ }
30456
+ if (!("events" in value)) {
30457
+ return void 0;
30458
+ }
30459
+ const events = value.events;
30460
+ return Array.isArray(events) ? events : void 0;
30461
+ }
30462
+ function mergeObservedStepEvents(primary, secondary) {
30463
+ if (primary === void 0 || primary.length === 0) {
30464
+ return secondary === void 0 || secondary.length === 0 ? void 0 : secondary;
30465
+ }
30466
+ if (secondary === void 0 || secondary.length === 0) {
30467
+ return primary;
30468
+ }
30469
+ const merged = /* @__PURE__ */ new Map();
30470
+ for (const event of primary) {
30471
+ merged.set(event.eventId, event);
30472
+ }
30473
+ for (const event of secondary) {
30474
+ merged.set(event.eventId, event);
30475
+ }
30476
+ return [...merged.values()].sort(
30477
+ (left, right) => (left.timestamp ?? 0) - (right.timestamp ?? 0)
30478
+ );
30479
+ }
29791
30480
  function selectLiveQueryPageRef(input, currentPageRef) {
29792
30481
  if (input.pageRef !== void 0) {
29793
30482
  return input.pageRef;
@@ -29819,8 +30508,8 @@ function resolveLiveQueryRequestIds(input, history) {
29819
30508
  if (input.requestId !== void 0) {
29820
30509
  requestIdCandidates.push(/* @__PURE__ */ new Set([input.requestId]));
29821
30510
  }
29822
- if (input.actionId !== void 0) {
29823
- requestIdCandidates.push(history.getRequestIdsForActionId(input.actionId));
30511
+ if (input.capture !== void 0) {
30512
+ requestIdCandidates.push(history.getRequestIdsForCapture(input.capture));
29824
30513
  }
29825
30514
  if (input.tag !== void 0) {
29826
30515
  requestIdCandidates.push(history.getRequestIdsForTag(input.tag));
@@ -29867,7 +30556,7 @@ function filterNetworkQueryRecords(records, input) {
29867
30556
  if (input.requestId !== void 0 && record.record.requestId !== input.requestId) {
29868
30557
  return false;
29869
30558
  }
29870
- if (input.actionId !== void 0 && record.actionId !== input.actionId) {
30559
+ if (input.capture !== void 0 && record.capture !== input.capture) {
29871
30560
  return false;
29872
30561
  }
29873
30562
  if (input.tag !== void 0 && !(record.tags ?? []).includes(input.tag)) {
@@ -30750,12 +31439,12 @@ function extractReverseRuntimeValue(value, pointer) {
30750
31439
  }
30751
31440
  return readDotPath(value, pointer);
30752
31441
  }
30753
- function readDotPath(value, path16) {
30754
- if (path16.length === 0) {
31442
+ function readDotPath(value, path17) {
31443
+ if (path17.length === 0) {
30755
31444
  return value;
30756
31445
  }
30757
31446
  let current = value;
30758
- for (const segment of path16.split(".").filter((entry) => entry.length > 0)) {
31447
+ for (const segment of path17.split(".").filter((entry) => entry.length > 0)) {
30759
31448
  if (current === null || current === void 0) {
30760
31449
  return void 0;
30761
31450
  }
@@ -31124,7 +31813,7 @@ function normalizeRuntimeErrorMessage(error) {
31124
31813
  return error instanceof Error ? error.message : String(error);
31125
31814
  }
31126
31815
  function runtimeDelay(ms) {
31127
- return new Promise((resolve5) => setTimeout(resolve5, ms));
31816
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
31128
31817
  }
31129
31818
  function applyBrowserCookiesToTransportRequest(request, cookies) {
31130
31819
  if (cookies.length === 0) {
@@ -31228,7 +31917,7 @@ function parseSetCookieHeader(value, requestUrl) {
31228
31917
  }
31229
31918
  const url = new URL(requestUrl);
31230
31919
  let domain = url.hostname;
31231
- let path16 = defaultCookiePath(url.pathname);
31920
+ let path17 = defaultCookiePath(url.pathname);
31232
31921
  let secure = url.protocol === "https:";
31233
31922
  let expiresAt;
31234
31923
  const cookieValue = rawValueParts.join("=").trim();
@@ -31241,7 +31930,7 @@ function parseSetCookieHeader(value, requestUrl) {
31241
31930
  continue;
31242
31931
  }
31243
31932
  if (key === "path" && attributeValue.length > 0) {
31244
- path16 = attributeValue;
31933
+ path17 = attributeValue;
31245
31934
  continue;
31246
31935
  }
31247
31936
  if (key === "secure") {
@@ -31267,7 +31956,7 @@ function parseSetCookieHeader(value, requestUrl) {
31267
31956
  name,
31268
31957
  value: cookieValue,
31269
31958
  domain,
31270
- path: path16,
31959
+ path: path17,
31271
31960
  secure,
31272
31961
  ...expiresAt === void 0 ? {} : { expiresAt }
31273
31962
  }
@@ -32219,7 +32908,7 @@ async function pollUntilResult(timeout, producer) {
32219
32908
  if (produced !== void 0) {
32220
32909
  return produced;
32221
32910
  }
32222
- await new Promise((resolve5) => setTimeout(resolve5, 100));
32911
+ await new Promise((resolve4) => setTimeout(resolve4, 100));
32223
32912
  }
32224
32913
  }
32225
32914
  async function getMainFrame(engine, pageRef) {
@@ -32277,9 +32966,167 @@ function toOpensteerResolvedTarget2(target) {
32277
32966
  function normalizeOpensteerError(error) {
32278
32967
  return normalizeThrownOpensteerError(error, "Unknown Opensteer runtime failure");
32279
32968
  }
32969
+ function observationArtifactKindFromManifest(kind) {
32970
+ switch (kind) {
32971
+ case "screenshot":
32972
+ return "screenshot";
32973
+ case "dom-snapshot":
32974
+ return "dom-snapshot";
32975
+ case "html-snapshot":
32976
+ return "html-snapshot";
32977
+ default:
32978
+ return "other";
32979
+ }
32980
+ }
32981
+ function buildObservationEventsFromTrace(input) {
32982
+ const context = normalizeObservationContext(input.context);
32983
+ const baseCorrelationId = input.traceId;
32984
+ const startedEvent = {
32985
+ kind: input.operation === "session.open" || input.operation === "session.close" ? "session" : "operation",
32986
+ phase: "started",
32987
+ createdAt: input.startedAt,
32988
+ correlationId: baseCorrelationId,
32989
+ spanId: input.stepId,
32990
+ ...context === void 0 ? {} : { context },
32991
+ data: {
32992
+ operation: input.operation
32993
+ }
32994
+ };
32995
+ const stepEvents = (input.events ?? []).filter((event) => shouldCaptureObservationStepEvent(event, input.profile)).map((event) => {
32996
+ const eventContext = buildObservationContextFromEvent(event);
32997
+ return {
32998
+ kind: observationKindForStepEvent(event),
32999
+ phase: "occurred",
33000
+ createdAt: event.timestamp,
33001
+ correlationId: baseCorrelationId,
33002
+ parentSpanId: input.stepId,
33003
+ ...eventContext === void 0 ? {} : { context: eventContext },
33004
+ data: stripObservationStepEvent(event),
33005
+ ...event.kind === "page-error" ? {
33006
+ error: {
33007
+ message: event.message,
33008
+ ...event.stack === void 0 ? {} : { details: { stack: event.stack } }
33009
+ }
33010
+ } : {}
33011
+ };
33012
+ });
33013
+ const completedEvent = {
33014
+ kind: input.operation === "session.open" || input.operation === "session.close" ? "session" : "operation",
33015
+ phase: input.outcome === "ok" ? "completed" : "failed",
33016
+ createdAt: input.completedAt,
33017
+ correlationId: baseCorrelationId,
33018
+ spanId: input.stepId,
33019
+ ...context === void 0 ? {} : { context },
33020
+ data: {
33021
+ operation: input.operation,
33022
+ startedAt: input.startedAt,
33023
+ completedAt: input.completedAt,
33024
+ durationMs: input.completedAt - input.startedAt,
33025
+ ...input.data === void 0 ? {} : { output: input.data }
33026
+ },
33027
+ ...input.error === void 0 ? {} : {
33028
+ error: {
33029
+ ...input.error.code === void 0 ? {} : { code: input.error.code },
33030
+ message: input.error.message,
33031
+ ...input.error.retriable === void 0 ? {} : { retriable: input.error.retriable },
33032
+ ...input.error.details === void 0 ? {} : { details: toCanonicalJsonValue(input.error.details) }
33033
+ }
33034
+ },
33035
+ ...input.artifactIds === void 0 || input.artifactIds.length === 0 ? {} : { artifactIds: input.artifactIds }
33036
+ };
33037
+ return [startedEvent, ...stepEvents, completedEvent];
33038
+ }
33039
+ function buildObservationContextFromEvent(event) {
33040
+ return normalizeObservationContext({
33041
+ sessionRef: event.sessionRef,
33042
+ ...event.pageRef === void 0 ? {} : { pageRef: event.pageRef },
33043
+ ...event.frameRef === void 0 ? {} : { frameRef: event.frameRef },
33044
+ ...event.documentRef === void 0 ? {} : { documentRef: event.documentRef },
33045
+ ...event.documentEpoch === void 0 ? {} : { documentEpoch: event.documentEpoch }
33046
+ });
33047
+ }
33048
+ function shouldCaptureObservationStepEvent(event, profile) {
33049
+ if (profile === "diagnostic") {
33050
+ return true;
33051
+ }
33052
+ switch (event.kind) {
33053
+ case "page-created":
33054
+ case "popup-opened":
33055
+ case "page-closed":
33056
+ case "page-error":
33057
+ return true;
33058
+ case "console":
33059
+ return event.level === "warn" || event.level === "error";
33060
+ default:
33061
+ return false;
33062
+ }
33063
+ }
33064
+ function observationKindForStepEvent(event) {
33065
+ switch (event.kind) {
33066
+ case "console":
33067
+ return "console";
33068
+ case "page-error":
33069
+ return "error";
33070
+ case "paused":
33071
+ case "resumed":
33072
+ case "frozen":
33073
+ return "runtime";
33074
+ default:
33075
+ return "page";
33076
+ }
33077
+ }
33078
+ function stripObservationStepEvent(event) {
33079
+ const {
33080
+ eventId: _eventId,
33081
+ kind,
33082
+ timestamp,
33083
+ sessionRef: _sessionRef,
33084
+ pageRef: _pageRef,
33085
+ frameRef: _frameRef,
33086
+ documentRef: _documentRef,
33087
+ documentEpoch: _documentEpoch,
33088
+ ...rest
33089
+ } = event;
33090
+ return toCanonicalJsonValue({
33091
+ eventKind: kind,
33092
+ timestamp,
33093
+ ...rest
33094
+ });
33095
+ }
33096
+ function buildMutationCaptureTraceData(diagnostics) {
33097
+ if (diagnostics?.finalizeError === void 0) {
33098
+ return {};
33099
+ }
33100
+ return {
33101
+ networkCapture: {
33102
+ finalizeError: diagnostics.finalizeError
33103
+ }
33104
+ };
33105
+ }
32280
33106
  function isIgnorableRuntimeBindingError(error) {
32281
33107
  return isBrowserCoreError(error) && (error.code === "not-found" || error.code === "page-closed" || error.code === "session-closed");
32282
33108
  }
33109
+ async function withDetachedTimeoutSignal(timeoutMs, operation) {
33110
+ const controller = new AbortController();
33111
+ const timeoutError = new OpensteerProtocolError(
33112
+ "timeout",
33113
+ `mutation capture finalization exceeded ${String(timeoutMs)}ms timeout`,
33114
+ {
33115
+ details: {
33116
+ policy: "mutation-capture-finalize",
33117
+ budgetMs: timeoutMs
33118
+ }
33119
+ }
33120
+ );
33121
+ const timer = setTimeout(() => {
33122
+ controller.abort(timeoutError);
33123
+ }, timeoutMs);
33124
+ try {
33125
+ return await operation(controller.signal);
33126
+ } finally {
33127
+ clearTimeout(timer);
33128
+ }
33129
+ }
32283
33130
  function screenshotMediaType(format2) {
32284
33131
  switch (format2) {
32285
33132
  case "png":
@@ -32382,9 +33229,9 @@ var OpensteerCloudAutomationClient = class {
32382
33229
  sentAt: Date.now(),
32383
33230
  ...input === void 0 ? {} : { input }
32384
33231
  };
32385
- return new Promise((resolve5, reject) => {
33232
+ return new Promise((resolve4, reject) => {
32386
33233
  this.pending.set(requestId, {
32387
- resolve: (value) => resolve5(value),
33234
+ resolve: (value) => resolve4(value),
32388
33235
  reject
32389
33236
  });
32390
33237
  try {
@@ -32447,8 +33294,8 @@ var OpensteerCloudAutomationClient = class {
32447
33294
  pending.reject(new Error(`automation connection closed before ${requestId} completed`));
32448
33295
  }
32449
33296
  this.pending.clear();
32450
- await new Promise((resolve5) => {
32451
- socket.once("close", () => resolve5());
33297
+ await new Promise((resolve4) => {
33298
+ socket.once("close", () => resolve4());
32452
33299
  socket.close();
32453
33300
  }).catch(() => void 0);
32454
33301
  }
@@ -32490,8 +33337,8 @@ var OpensteerCloudAutomationClient = class {
32490
33337
  }
32491
33338
  this.pending.clear();
32492
33339
  });
32493
- await new Promise((resolve5, reject) => {
32494
- socket.once("open", () => resolve5());
33340
+ await new Promise((resolve4, reject) => {
33341
+ socket.once("open", () => resolve4());
32495
33342
  socket.once("error", reject);
32496
33343
  });
32497
33344
  this.send({
@@ -32832,6 +33679,7 @@ var CloudSessionProxy = class {
32832
33679
  workspace;
32833
33680
  cleanupRootOnClose;
32834
33681
  cloud;
33682
+ observability;
32835
33683
  sessionId;
32836
33684
  sessionBaseUrl;
32837
33685
  client;
@@ -32840,8 +33688,9 @@ var CloudSessionProxy = class {
32840
33688
  constructor(cloud, options = {}) {
32841
33689
  this.cloud = cloud;
32842
33690
  this.workspace = options.workspace;
32843
- this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path6__default.default.join(os.tmpdir(), `${TEMPORARY_CLOUD_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
32844
- rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
33691
+ this.observability = options.observability;
33692
+ this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path7__default.default.join(os.tmpdir(), `${TEMPORARY_CLOUD_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
33693
+ rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
32845
33694
  workspace: this.workspace
32846
33695
  }));
32847
33696
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.workspace === void 0;
@@ -33184,6 +34033,7 @@ var CloudSessionProxy = class {
33184
34033
  ...this.workspace === void 0 ? {} : { name: this.workspace },
33185
34034
  ...input.launch === void 0 ? {} : { browser: input.launch },
33186
34035
  ...input.context === void 0 ? {} : { context: input.context },
34036
+ ...this.observability === void 0 ? {} : { observability: this.observability },
33187
34037
  ...resolveCloudBrowserProfile(this.cloud, input) === void 0 ? {} : { browserProfile: resolveCloudBrowserProfile(this.cloud, input) }
33188
34038
  });
33189
34039
  const record = {
@@ -33281,8 +34131,8 @@ function isMissingCloudSessionError(error) {
33281
34131
  var OpensteerRuntime = class extends OpensteerSessionRuntime {
33282
34132
  constructor(options = {}) {
33283
34133
  const publicWorkspace = normalizeWorkspace2(options.workspace);
33284
- const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path6__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : resolveFilesystemWorkspacePath({
33285
- rootDir: path6__default.default.resolve(options.rootDir ?? process.cwd()),
34134
+ const rootPath = options.rootPath ?? (publicWorkspace === void 0 ? path7__default.default.resolve(options.rootDir ?? process.cwd(), ".opensteer", "temporary", crypto.randomUUID()) : resolveFilesystemWorkspacePath({
34135
+ rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
33286
34136
  workspace: publicWorkspace
33287
34137
  }));
33288
34138
  const cleanupRootOnClose = options.cleanupRootOnClose ?? publicWorkspace === void 0;
@@ -33307,7 +34157,10 @@ var OpensteerRuntime = class extends OpensteerSessionRuntime {
33307
34157
  ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
33308
34158
  ...options.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: options.extractionDescriptorStore },
33309
34159
  ...options.registryOverrides === void 0 ? {} : { registryOverrides: options.registryOverrides },
33310
- cleanupRootOnClose
34160
+ cleanupRootOnClose,
34161
+ ...options.observability === void 0 ? {} : { observability: options.observability },
34162
+ ...options.observationSessionId === void 0 ? {} : { observationSessionId: options.observationSessionId },
34163
+ ...options.observationSink === void 0 ? {} : { observationSink: options.observationSink }
33311
34164
  })
33312
34165
  );
33313
34166
  }
@@ -33333,6 +34186,9 @@ function buildSharedRuntimeOptions(input) {
33333
34186
  ...input.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: input.extractionDescriptorStore },
33334
34187
  ...input.registryOverrides === void 0 ? {} : { registryOverrides: input.registryOverrides },
33335
34188
  cleanupRootOnClose: input.cleanupRootOnClose,
34189
+ ...input.observability === void 0 ? {} : { observability: input.observability },
34190
+ ...input.observationSessionId === void 0 ? {} : { observationSessionId: input.observationSessionId },
34191
+ ...input.observationSink === void 0 ? {} : { observationSink: input.observationSink },
33336
34192
  sessionInfo: {
33337
34193
  provider: {
33338
34194
  mode: "local",
@@ -33357,16 +34213,17 @@ function resolveOwnership(browser) {
33357
34213
 
33358
34214
  // src/sdk/runtime-resolution.ts
33359
34215
  function resolveOpensteerRuntimeConfig(input = {}) {
34216
+ const environment = input.environment ?? process.env;
33360
34217
  const provider = resolveOpensteerProvider({
33361
34218
  ...input.provider === void 0 ? {} : { provider: input.provider },
33362
- ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
34219
+ ...environment.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: environment.OPENSTEER_PROVIDER }
33363
34220
  });
33364
34221
  if (provider.mode === "cloud") {
33365
34222
  return {
33366
34223
  provider,
33367
34224
  cloud: resolveCloudConfig({
33368
34225
  ...input.provider === void 0 ? {} : { provider: input.provider },
33369
- ...input.environmentProvider === void 0 ? {} : { environmentProvider: input.environmentProvider }
34226
+ environment
33370
34227
  })
33371
34228
  };
33372
34229
  }
@@ -33377,7 +34234,7 @@ function createOpensteerSemanticRuntime(input = {}) {
33377
34234
  const engine = input.engine ?? runtimeOptions.engineName ?? DEFAULT_OPENSTEER_ENGINE;
33378
34235
  const config = resolveOpensteerRuntimeConfig({
33379
34236
  ...input.provider === void 0 ? {} : { provider: input.provider },
33380
- ...process.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process.env.OPENSTEER_PROVIDER }
34237
+ ...input.environment === void 0 ? {} : { environment: input.environment }
33381
34238
  });
33382
34239
  assertProviderSupportsEngine(config.provider.mode, engine);
33383
34240
  if (config.provider.mode === "cloud") {
@@ -33385,7 +34242,8 @@ function createOpensteerSemanticRuntime(input = {}) {
33385
34242
  ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
33386
34243
  ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
33387
34244
  ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
33388
- ...runtimeOptions.cleanupRootOnClose === void 0 ? {} : { cleanupRootOnClose: runtimeOptions.cleanupRootOnClose }
34245
+ ...runtimeOptions.cleanupRootOnClose === void 0 ? {} : { cleanupRootOnClose: runtimeOptions.cleanupRootOnClose },
34246
+ ...runtimeOptions.observability === void 0 ? {} : { observability: runtimeOptions.observability }
33389
34247
  });
33390
34248
  }
33391
34249
  return new OpensteerRuntime({
@@ -33476,7 +34334,7 @@ function describeLocalLane(record, current) {
33476
34334
  summary: "none"
33477
34335
  };
33478
34336
  }
33479
- const browser = record.executablePath ? path6__default.default.basename(record.executablePath).replace(/\.[A-Za-z0-9]+$/u, "") : void 0;
34337
+ const browser = record.executablePath ? path7__default.default.basename(record.executablePath).replace(/\.[A-Za-z0-9]+$/u, "") : void 0;
33480
34338
  return {
33481
34339
  provider: "local",
33482
34340
  status: "active",
@@ -34061,7 +34919,7 @@ async function handleStatusCommand(parsed) {
34061
34919
  const runtimeProvider = buildCliRuntimeProvider(parsed, provider.mode);
34062
34920
  const runtimeConfig = resolveOpensteerRuntimeConfig({
34063
34921
  ...runtimeProvider === void 0 ? {} : { provider: runtimeProvider },
34064
- ...process2__default.default.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process2__default.default.env.OPENSTEER_PROVIDER }
34922
+ environment: process2__default.default.env
34065
34923
  });
34066
34924
  const status = await collectOpensteerStatus({
34067
34925
  rootDir: process2__default.default.cwd(),