opensteer 0.8.17 → 0.9.0

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
@@ -3162,7 +3162,7 @@ var init_storage2 = __esm({
3162
3162
  });
3163
3163
 
3164
3164
  // ../protocol/src/requests.ts
3165
- var opensteerRequestScalarSchema, opensteerRequestScalarMapSchema, opensteerRequestEntrySchema, opensteerRequestPlanParameterLocationSchema, opensteerRequestPlanParameterSchema, opensteerRequestPlanTransportSchema, opensteerRequestPlanEndpointSchema, opensteerRequestPlanBodySchema, transportKindSchema, opensteerRequestPlanStatusSchema, opensteerRequestPlanResponseExpectationSchema, opensteerRecipeRefSchema, opensteerRequestFailurePolicyHeaderMatchSchema, opensteerRequestFailurePolicySchema, opensteerRequestRetryBackoffPolicySchema, opensteerRequestRetryPolicySchema, opensteerRecipeCachePolicySchema, opensteerRequestPlanRecipeBindingSchema, opensteerRequestPlanRecoverBindingSchema, opensteerRequestPlanRecipesSchema, opensteerRequestPlanAuthSchema, opensteerRequestPlanPayloadSchema, opensteerRegistryProvenanceSchema, opensteerRequestPlanFreshnessSchema, opensteerRequestPlanRecordSchema, jsonValueSchema, opensteerRequestBodyInputSchema, opensteerRecipeRetryOverridesSchema, opensteerRecipeStepResponseCaptureSchema, opensteerRecipeRequestStepInputSchema, opensteerRecipeHookRefSchema, opensteerRecipeStepSchema, opensteerRecipePayloadSchema, opensteerRecipeRecordSchema, opensteerNetworkQueryInputSchema, opensteerGraphqlSummarySchema, opensteerNetworkBodySummarySchema, opensteerNetworkSummaryRecordSchema, opensteerNetworkQueryOutputSchema, opensteerParsedCookieSchema, opensteerStructuredBodyPreviewSchema, opensteerNetworkRedirectHopSchema, opensteerReplayAttemptSchema, opensteerNetworkDetailOutputSchema, opensteerSessionFetchTransportSchema, opensteerSessionFetchInputSchema, opensteerSessionFetchOutputSchema, opensteerCookieQueryInputSchema, opensteerCookieQueryOutputSchema, opensteerStorageDomainSnapshotSchema, opensteerStorageQueryInputSchema, opensteerStorageQueryOutputSchema, opensteerHiddenFieldSchema, opensteerStateDomainSnapshotSchema, opensteerStateQueryInputSchema, opensteerStateQueryOutputSchema, opensteerRequestTransportResultSchema, opensteerRequestResponseResultSchema;
3165
+ var opensteerRequestScalarSchema, opensteerRequestScalarMapSchema, opensteerRequestEntrySchema, opensteerRequestPlanParameterLocationSchema, opensteerRequestPlanParameterSchema, opensteerRequestPlanTransportSchema, opensteerRequestPlanEndpointSchema, opensteerRequestPlanBodySchema, transportKindSchema, opensteerRequestPlanStatusSchema, opensteerRequestPlanResponseExpectationSchema, opensteerRecipeRefSchema, opensteerRequestFailurePolicyHeaderMatchSchema, opensteerRequestFailurePolicySchema, opensteerRequestRetryBackoffPolicySchema, opensteerRequestRetryPolicySchema, opensteerRecipeCachePolicySchema, opensteerRequestPlanRecipeBindingSchema, opensteerRequestPlanRecoverBindingSchema, opensteerRequestPlanRecipesSchema, opensteerRequestPlanAuthSchema, opensteerRequestPlanPayloadSchema, opensteerRegistryProvenanceSchema, opensteerRequestPlanFreshnessSchema, opensteerRequestPlanRecordSchema, jsonValueSchema, opensteerRequestBodyInputSchema, opensteerRecipeRetryOverridesSchema, opensteerRecipeStepResponseCaptureSchema, opensteerRecipeRequestStepInputSchema, opensteerRecipeHookRefSchema, opensteerRecipeStepSchema, opensteerRecipePayloadSchema, opensteerRecipeRecordSchema, opensteerNetworkQueryInputSchema, opensteerGraphqlSummarySchema, opensteerNetworkBodySummarySchema, opensteerNetworkSummaryRecordSchema, opensteerNetworkQueryOutputSchema, opensteerNetworkDetailInputSchema, opensteerParsedCookieSchema, opensteerStructuredBodyPreviewSchema, opensteerNetworkRedirectHopSchema, opensteerReplayAttemptSchema, opensteerNetworkDetailOutputSchema, opensteerSessionFetchTransportSchema, opensteerSessionFetchInputSchema, opensteerSessionFetchOutputSchema, opensteerCookieQueryInputSchema, opensteerCookieQueryOutputSchema, opensteerStorageDomainSnapshotSchema, opensteerStorageQueryInputSchema, opensteerStorageQueryOutputSchema, opensteerHiddenFieldSchema, opensteerStateDomainSnapshotSchema, opensteerStateQueryInputSchema, opensteerStateQueryOutputSchema, opensteerRequestTransportResultSchema, opensteerRequestResponseResultSchema;
3166
3166
  var init_requests = __esm({
3167
3167
  "../protocol/src/requests.ts"() {
3168
3168
  init_network2();
@@ -3886,6 +3886,16 @@ var init_requests = __esm({
3886
3886
  required: ["records"]
3887
3887
  }
3888
3888
  );
3889
+ opensteerNetworkDetailInputSchema = objectSchema(
3890
+ {
3891
+ recordId: stringSchema({ minLength: 1 }),
3892
+ probe: { type: "boolean" }
3893
+ },
3894
+ {
3895
+ title: "OpensteerNetworkDetailInput",
3896
+ required: ["recordId"]
3897
+ }
3898
+ );
3889
3899
  opensteerParsedCookieSchema = objectSchema(
3890
3900
  {
3891
3901
  name: stringSchema({ minLength: 1 }),
@@ -3991,7 +4001,7 @@ var init_requests = __esm({
3991
4001
  }
3992
4002
  );
3993
4003
  opensteerSessionFetchTransportSchema = enumSchema(
3994
- ["auto", "direct", "matched-tls", "page"],
4004
+ ["auto", "direct", "matched-tls", "context", "page"],
3995
4005
  {
3996
4006
  title: "OpensteerSessionFetchTransport"
3997
4007
  }
@@ -8437,7 +8447,7 @@ function assertValidSemanticOperationInput(name, input) {
8437
8447
  }
8438
8448
  );
8439
8449
  }
8440
- var opensteerComputerAnnotationNames, opensteerExposedSemanticOperationNames, opensteerPackageRunnableSemanticOperationNames, snapshotModeSchema, viewportSchema, opensteerBrowserLaunchOptionsSchema, attachBrowserOptionsSchema, opensteerBrowserOptionsSchema, opensteerBrowserContextOptionsSchema, targetByElementSchema2, targetByPersistSchema2, targetBySelectorSchema2, opensteerTargetInputSchema, opensteerResolvedTargetSchema, opensteerActionResultSchema, opensteerSnapshotCounterSchema, opensteerSessionStateSchema, opensteerOpenInputSchema, opensteerPageListInputSchema, opensteerPageListOutputSchema, opensteerPageNewInputSchema, opensteerPageActivateInputSchema, opensteerPageCloseInputSchema, opensteerPageCloseOutputSchema, opensteerPageGotoInputSchema, opensteerPageEvaluateInputSchema, opensteerPageEvaluateOutputSchema, opensteerAddInitScriptInputSchema, opensteerAddInitScriptOutputSchema, opensteerCapturedScriptSchema, opensteerCaptureScriptsInputSchema, opensteerCaptureScriptsOutputSchema, opensteerPageSnapshotInputSchema, opensteerPageSnapshotOutputSchema, opensteerNetworkDetailInputSchema, opensteerComputerMouseButtonSchema, opensteerComputerKeyModifierSchema, opensteerDomClickInputSchema, opensteerDomHoverInputSchema, opensteerDomInputInputSchema, opensteerDomScrollInputSchema, opensteerExtractSchemaSchema, opensteerDomExtractInputSchema, jsonValueSchema3, opensteerDomExtractOutputSchema, opensteerSessionCloseInputSchema, opensteerSessionCloseOutputSchema, opensteerComputerAnnotationSchema, opensteerComputerClickActionSchema, opensteerComputerMoveActionSchema, opensteerComputerScrollActionSchema, opensteerComputerTypeActionSchema, opensteerComputerKeyActionSchema, opensteerComputerDragActionSchema, opensteerComputerScreenshotActionSchema, opensteerComputerWaitActionSchema, opensteerComputerActionSchema, opensteerComputerScreenshotOptionsSchema, opensteerComputerExecuteInputSchema, opensteerComputerTracePointSchema, opensteerComputerTraceEnrichmentSchema, opensteerComputerExecuteTimingSchema, opensteerComputerDisplayScaleSchema, opensteerComputerExecuteOutputSchema, opensteerSemanticOperationSpecificationsBase, exposedSemanticOperationNameSet, opensteerSemanticOperationSpecificationsInternal, opensteerSemanticOperationSpecifications, opensteerSemanticOperationSpecificationMap, semanticRestBasePath, opensteerSemanticRestEndpoints;
8450
+ var opensteerComputerAnnotationNames, opensteerExposedSemanticOperationNames, opensteerPackageRunnableSemanticOperationNames, snapshotModeSchema, viewportSchema, opensteerBrowserLaunchOptionsSchema, attachBrowserOptionsSchema, opensteerBrowserOptionsSchema, opensteerBrowserContextOptionsSchema, targetByElementSchema2, targetByPersistSchema2, targetBySelectorSchema2, opensteerTargetInputSchema, opensteerResolvedTargetSchema, opensteerActionResultSchema, opensteerSnapshotCounterSchema, opensteerSessionStateSchema, opensteerOpenInputSchema, opensteerPageListInputSchema, opensteerPageListOutputSchema, opensteerPageNewInputSchema, opensteerPageActivateInputSchema, opensteerPageCloseInputSchema, opensteerPageCloseOutputSchema, opensteerPageGotoInputSchema, opensteerPageEvaluateInputSchema, opensteerPageEvaluateOutputSchema, opensteerAddInitScriptInputSchema, opensteerAddInitScriptOutputSchema, opensteerCapturedScriptSchema, opensteerCaptureScriptsInputSchema, opensteerCaptureScriptsOutputSchema, opensteerPageSnapshotInputSchema, opensteerPageSnapshotOutputSchema, opensteerComputerMouseButtonSchema, opensteerComputerKeyModifierSchema, opensteerDomClickInputSchema, opensteerDomHoverInputSchema, opensteerDomInputInputSchema, opensteerDomScrollInputSchema, opensteerExtractSchemaSchema, opensteerDomExtractInputSchema, jsonValueSchema3, opensteerDomExtractOutputSchema, opensteerSessionCloseInputSchema, opensteerSessionCloseOutputSchema, opensteerComputerAnnotationSchema, opensteerComputerClickActionSchema, opensteerComputerMoveActionSchema, opensteerComputerScrollActionSchema, opensteerComputerTypeActionSchema, opensteerComputerKeyActionSchema, opensteerComputerDragActionSchema, opensteerComputerScreenshotActionSchema, opensteerComputerWaitActionSchema, opensteerComputerActionSchema, opensteerComputerScreenshotOptionsSchema, opensteerComputerExecuteInputSchema, opensteerComputerTracePointSchema, opensteerComputerTraceEnrichmentSchema, opensteerComputerExecuteTimingSchema, opensteerComputerDisplayScaleSchema, opensteerComputerExecuteOutputSchema, opensteerSemanticOperationSpecificationsBase, exposedSemanticOperationNameSet, opensteerSemanticOperationSpecificationsInternal, opensteerSemanticOperationSpecifications, opensteerSemanticOperationSpecificationMap, semanticRestBasePath, opensteerSemanticRestEndpoints;
8441
8451
  var init_semantic = __esm({
8442
8452
  "../protocol/src/semantic.ts"() {
8443
8453
  init_json2();
@@ -8940,15 +8950,6 @@ var init_semantic = __esm({
8940
8950
  required: ["url", "title", "mode", "html", "counters"]
8941
8951
  }
8942
8952
  );
8943
- opensteerNetworkDetailInputSchema = objectSchema(
8944
- {
8945
- recordId: stringSchema({ minLength: 1 })
8946
- },
8947
- {
8948
- title: "OpensteerNetworkDetailInput",
8949
- required: ["recordId"]
8950
- }
8951
- );
8952
8953
  opensteerComputerMouseButtonSchema = enumSchema(
8953
8954
  ["left", "middle", "right"],
8954
8955
  {
@@ -9500,6 +9501,7 @@ var init_semantic = __esm({
9500
9501
  case "direct":
9501
9502
  return [];
9502
9503
  case "matched-tls":
9504
+ case "context":
9503
9505
  return ["inspect.cookies"];
9504
9506
  case "page":
9505
9507
  return ["pages.manage"];
@@ -10520,13 +10522,6 @@ var init_saved_store = __esm({
10520
10522
  }
10521
10523
  async save(records, options) {
10522
10524
  const database = await this.requireDatabase();
10523
- const readExisting = database.prepare(`
10524
- SELECT record_id
10525
- FROM saved_network_records
10526
- WHERE session_ref = @session_ref
10527
- AND page_ref_key = @page_ref_key
10528
- AND request_id = @request_id
10529
- `);
10530
10525
  const upsertRecord = database.prepare(buildSavedNetworkUpsertSql(options.bodyWriteMode));
10531
10526
  const insertTag = database.prepare(`
10532
10527
  INSERT OR IGNORE INTO saved_network_tags (record_id, tag)
@@ -10537,14 +10532,8 @@ var init_saved_store = __esm({
10537
10532
  for (const entry of records) {
10538
10533
  const url = new URL(entry.record.url);
10539
10534
  const pageRefKey = entry.record.pageRef ?? "";
10540
- const existing = readExisting.get({
10541
- session_ref: entry.record.sessionRef,
10542
- page_ref_key: pageRefKey,
10543
- request_id: entry.record.requestId
10544
- }) ?? void 0;
10545
- const recordId = existing?.record_id ?? entry.recordId;
10546
10535
  upsertRecord.run({
10547
- record_id: recordId,
10536
+ record_id: entry.recordId,
10548
10537
  request_id: entry.record.requestId,
10549
10538
  session_ref: entry.record.sessionRef,
10550
10539
  page_ref: entry.record.pageRef ?? null,
@@ -10589,7 +10578,7 @@ var init_saved_store = __esm({
10589
10578
  }
10590
10579
  for (const currentTag of tags) {
10591
10580
  const result = insertTag.run({
10592
- record_id: recordId,
10581
+ record_id: entry.recordId,
10593
10582
  tag: currentTag
10594
10583
  });
10595
10584
  savedCount += result.changes ?? 0;
@@ -10692,6 +10681,49 @@ var init_saved_store = __esm({
10692
10681
  return cleared;
10693
10682
  });
10694
10683
  }
10684
+ async *iterateBatches(options = {}) {
10685
+ const database = await this.requireDatabase();
10686
+ const batchSize = Math.max(1, Math.min(options.batchSize ?? 500, 1e3));
10687
+ let cursor;
10688
+ while (true) {
10689
+ const rows = database.prepare(
10690
+ `
10691
+ SELECT
10692
+ r.*,
10693
+ GROUP_CONCAT(t.tag, '${TAG_DELIMITER}') AS tags
10694
+ FROM saved_network_records r
10695
+ LEFT JOIN saved_network_tags t
10696
+ ON t.record_id = r.record_id
10697
+ ${cursor === void 0 ? "" : "WHERE r.saved_at > ? OR (r.saved_at = ? AND r.record_id > ?)"}
10698
+ GROUP BY r.record_id
10699
+ ORDER BY r.saved_at ASC, r.record_id ASC
10700
+ LIMIT ?
10701
+ `
10702
+ ).all(
10703
+ ...cursor === void 0 ? [] : [cursor.savedAt, cursor.savedAt, cursor.recordId],
10704
+ batchSize
10705
+ );
10706
+ if (rows.length === 0) {
10707
+ return;
10708
+ }
10709
+ yield rows.map((row) => inflateSavedNetworkRow(row, options.includeBodies ?? true));
10710
+ const lastRow = rows.at(-1);
10711
+ if (lastRow === void 0) {
10712
+ return;
10713
+ }
10714
+ cursor = {
10715
+ savedAt: lastRow.saved_at,
10716
+ recordId: lastRow.record_id
10717
+ };
10718
+ }
10719
+ }
10720
+ close() {
10721
+ if (this.database !== void 0) {
10722
+ closeSqliteDatabase(this.database);
10723
+ this.database = void 0;
10724
+ this.databaseInitialization = void 0;
10725
+ }
10726
+ }
10695
10727
  async requireDatabase() {
10696
10728
  if (this.database) {
10697
10729
  return this.database;
@@ -10776,15 +10808,6 @@ var init_saved_store = __esm({
10776
10808
  saved_at INTEGER NOT NULL
10777
10809
  );
10778
10810
 
10779
- CREATE UNIQUE INDEX IF NOT EXISTS saved_network_records_scope_request
10780
- ON saved_network_records (session_ref, page_ref_key, request_id);
10781
-
10782
- CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
10783
- ON saved_network_records (saved_at DESC);
10784
-
10785
- CREATE INDEX IF NOT EXISTS saved_network_records_capture
10786
- ON saved_network_records (capture);
10787
-
10788
10811
  CREATE TABLE IF NOT EXISTS saved_network_tags (
10789
10812
  record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
10790
10813
  tag TEXT NOT NULL,
@@ -10793,6 +10816,19 @@ var init_saved_store = __esm({
10793
10816
 
10794
10817
  CREATE INDEX IF NOT EXISTS saved_network_tags_tag
10795
10818
  ON saved_network_tags (tag);
10819
+ `);
10820
+ database.exec(`DROP INDEX IF EXISTS saved_network_records_scope_request`);
10821
+ database.exec(`
10822
+ CREATE INDEX IF NOT EXISTS saved_network_records_scope_request
10823
+ ON saved_network_records (session_ref, page_ref_key, request_id)
10824
+ `);
10825
+ database.exec(`
10826
+ CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
10827
+ ON saved_network_records (saved_at DESC)
10828
+ `);
10829
+ database.exec(`
10830
+ CREATE INDEX IF NOT EXISTS saved_network_records_capture
10831
+ ON saved_network_records (capture)
10796
10832
  `);
10797
10833
  this.ensureColumn(
10798
10834
  database,
@@ -11932,8 +11968,14 @@ async function launchOwnedBrowser(input) {
11932
11968
  await ensureDirectory(input.userDataDir);
11933
11969
  await clearChromeSingletonEntries(input.userDataDir);
11934
11970
  await sanitizeChromeProfile(input.userDataDir);
11971
+ const requestedRemoteDebuggingPort = readRequestedRemoteDebuggingPort(input.launch?.args);
11935
11972
  const executablePath = resolveChromeExecutablePath(input.launch?.executablePath);
11936
- const args = buildChromeArgs(input.userDataDir, input.launch, input.viewport);
11973
+ const args = buildChromeArgs(
11974
+ input.userDataDir,
11975
+ input.launch,
11976
+ input.viewport,
11977
+ requestedRemoteDebuggingPort
11978
+ );
11937
11979
  const child = child_process.spawn(executablePath, args, {
11938
11980
  stdio: ["ignore", "ignore", "pipe"],
11939
11981
  detached: process.platform !== "win32"
@@ -11949,7 +11991,8 @@ async function launchOwnedBrowser(input) {
11949
11991
  userDataDir: input.userDataDir,
11950
11992
  timeoutMs: input.launch?.timeoutMs ?? DEFAULT_TIMEOUT_MS,
11951
11993
  childExited: async () => child.exitCode,
11952
- stderrLines
11994
+ stderrLines,
11995
+ ...requestedRemoteDebuggingPort !== void 0 && requestedRemoteDebuggingPort > 0 ? { requestedRemoteDebuggingPort } : {}
11953
11996
  }).catch(async (error) => {
11954
11997
  child.kill("SIGKILL");
11955
11998
  throw error;
@@ -11960,10 +12003,10 @@ async function launchOwnedBrowser(input) {
11960
12003
  executablePath
11961
12004
  };
11962
12005
  }
11963
- function buildChromeArgs(userDataDir, launch, viewport) {
12006
+ function buildChromeArgs(userDataDir, launch, viewport, requestedRemoteDebuggingPort) {
11964
12007
  const isHeadless = launch?.headless ?? true;
11965
12008
  const args = [
11966
- "--remote-debugging-port=0",
12009
+ ...requestedRemoteDebuggingPort === void 0 ? ["--remote-debugging-port=0"] : [],
11967
12010
  "--no-first-run",
11968
12011
  "--no-default-browser-check",
11969
12012
  "--disable-blink-features=AutomationControlled",
@@ -12014,6 +12057,15 @@ async function waitForDevToolsEndpoint(input) {
12014
12057
  return `ws://127.0.0.1:${String(activePort.port)}${activePort.webSocketPath}`;
12015
12058
  }
12016
12059
  }
12060
+ if (input.requestedRemoteDebuggingPort !== void 0) {
12061
+ const endpoint = await tryInspectRemoteDebuggingPort(
12062
+ input.requestedRemoteDebuggingPort,
12063
+ input.timeoutMs
12064
+ );
12065
+ if (endpoint !== void 0) {
12066
+ return endpoint;
12067
+ }
12068
+ }
12017
12069
  const exitCode = await input.childExited();
12018
12070
  if (exitCode !== null) {
12019
12071
  throw new Error(formatChromeLaunchError(input.stderrLines));
@@ -12022,6 +12074,52 @@ async function waitForDevToolsEndpoint(input) {
12022
12074
  }
12023
12075
  throw new Error(formatChromeLaunchError(input.stderrLines));
12024
12076
  }
12077
+ function readRequestedRemoteDebuggingPort(args) {
12078
+ if (args === void 0 || args.length === 0) {
12079
+ return void 0;
12080
+ }
12081
+ let explicitFlagFound = false;
12082
+ let port;
12083
+ for (let index = 0; index < args.length; index += 1) {
12084
+ const entry = args[index];
12085
+ if (entry === "--remote-debugging-port") {
12086
+ explicitFlagFound = true;
12087
+ const next = args[index + 1];
12088
+ if (next !== void 0) {
12089
+ port = parseRemoteDebuggingPort(next);
12090
+ index += 1;
12091
+ }
12092
+ continue;
12093
+ }
12094
+ if (entry.startsWith("--remote-debugging-port=")) {
12095
+ explicitFlagFound = true;
12096
+ port = parseRemoteDebuggingPort(entry.slice("--remote-debugging-port=".length));
12097
+ }
12098
+ }
12099
+ return explicitFlagFound ? port : void 0;
12100
+ }
12101
+ function parseRemoteDebuggingPort(value) {
12102
+ const trimmed = value.trim();
12103
+ if (!/^\d+$/.test(trimmed)) {
12104
+ return void 0;
12105
+ }
12106
+ const parsed = Number.parseInt(trimmed, 10);
12107
+ if (!Number.isInteger(parsed) || parsed < 0) {
12108
+ return void 0;
12109
+ }
12110
+ return parsed;
12111
+ }
12112
+ async function tryInspectRemoteDebuggingPort(port, timeoutMs) {
12113
+ try {
12114
+ const inspected = await inspectCdpEndpoint({
12115
+ endpoint: `http://127.0.0.1:${String(port)}`,
12116
+ timeoutMs: Math.min(2e3, timeoutMs)
12117
+ });
12118
+ return inspected.endpoint;
12119
+ } catch {
12120
+ return void 0;
12121
+ }
12122
+ }
12025
12123
  function formatChromeLaunchError(stderrLines) {
12026
12124
  const collapsed = stderrLines.join("").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
12027
12125
  if (collapsed.length === 0) {
@@ -13142,6 +13240,13 @@ var init_profile_sync = __esm({
13142
13240
  });
13143
13241
 
13144
13242
  // src/cloud/client.ts
13243
+ function createRequestSignal(options) {
13244
+ const timeoutSignal = AbortSignal.timeout(options.timeoutMs ?? 3e4);
13245
+ if (options.signal === void 0) {
13246
+ return timeoutSignal;
13247
+ }
13248
+ return AbortSignal.any([options.signal, timeoutSignal]);
13249
+ }
13145
13250
  function delay(ms) {
13146
13251
  return new Promise((resolve4) => {
13147
13252
  setTimeout(resolve4, ms);
@@ -13175,21 +13280,24 @@ var init_client = __esm({
13175
13280
  getConfig() {
13176
13281
  return this.config;
13177
13282
  }
13178
- async createSession(input = {}) {
13179
- const response = await this.request("/v1/sessions", {
13180
- method: "POST",
13181
- body: {
13182
- ...input.name === void 0 ? {} : { name: input.name },
13183
- ...input.browser === void 0 ? {} : { browser: input.browser },
13184
- ...input.context === void 0 ? {} : { context: input.context },
13185
- ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
13186
- ...input.observability === void 0 ? {} : { observability: input.observability },
13187
- ...input.sourceType === void 0 ? {} : { sourceType: input.sourceType },
13188
- ...input.sourceRef === void 0 ? {} : { sourceRef: input.sourceRef },
13189
- ...input.localWorkspaceRootPath === void 0 ? {} : { localWorkspaceRootPath: input.localWorkspaceRootPath },
13190
- ...input.locality === void 0 ? {} : { locality: input.locality }
13191
- }
13192
- });
13283
+ async createSession(input = {}, options = {}) {
13284
+ const response = await this.request(
13285
+ "/v1/sessions",
13286
+ {
13287
+ method: "POST",
13288
+ body: {
13289
+ ...input.name === void 0 ? {} : { name: input.name },
13290
+ ...input.browser === void 0 ? {} : { browser: input.browser },
13291
+ ...input.context === void 0 ? {} : { context: input.context },
13292
+ ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
13293
+ ...input.observability === void 0 ? {} : { observability: input.observability },
13294
+ ...input.sourceType === void 0 ? {} : { sourceType: input.sourceType },
13295
+ ...input.sourceRef === void 0 ? {} : { sourceRef: input.sourceRef },
13296
+ ...input.localWorkspaceRootPath === void 0 ? {} : { localWorkspaceRootPath: input.localWorkspaceRootPath }
13297
+ }
13298
+ },
13299
+ options
13300
+ );
13193
13301
  return await response.json();
13194
13302
  }
13195
13303
  async listSessions() {
@@ -13198,19 +13306,27 @@ var init_client = __esm({
13198
13306
  });
13199
13307
  return response.json();
13200
13308
  }
13201
- async getSession(sessionId) {
13202
- const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
13203
- method: "GET"
13204
- });
13309
+ async getSession(sessionId, options = {}) {
13310
+ const response = await this.request(
13311
+ `/v1/sessions/${encodeURIComponent(sessionId)}`,
13312
+ {
13313
+ method: "GET"
13314
+ },
13315
+ options
13316
+ );
13205
13317
  return await response.json();
13206
13318
  }
13207
- async issueAccess(sessionId, capabilities) {
13208
- const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}/access`, {
13209
- method: "POST",
13210
- body: {
13211
- capabilities
13212
- }
13213
- });
13319
+ async issueAccess(sessionId, capabilities, options = {}) {
13320
+ const response = await this.request(
13321
+ `/v1/sessions/${encodeURIComponent(sessionId)}/access`,
13322
+ {
13323
+ method: "POST",
13324
+ body: {
13325
+ capabilities
13326
+ }
13327
+ },
13328
+ options
13329
+ );
13214
13330
  return await response.json();
13215
13331
  }
13216
13332
  async getSessionRecording(sessionId) {
@@ -13292,28 +13408,17 @@ var init_client = __esm({
13292
13408
  async syncBrowserProfileCookies(input) {
13293
13409
  return syncBrowserProfileCookies(this, input);
13294
13410
  }
13295
- async importSelectorCache(entries) {
13296
- const response = await this.request("/selector-cache/import", {
13411
+ async importDescriptors(entries) {
13412
+ const response = await this.request("/registry/descriptors/import", {
13297
13413
  method: "POST",
13298
- body: {
13299
- entries: entries.map((entry) => ({
13300
- workspace: entry.workspace,
13301
- method: entry.method,
13302
- persistHash: entry.persistHash,
13303
- ...entry.persist === void 0 ? {} : { persist: entry.persist },
13304
- path: entry.path,
13305
- ...entry.schemaHash === void 0 ? {} : { schemaHash: entry.schemaHash },
13306
- createdAt: entry.createdAt,
13307
- updatedAt: entry.updatedAt
13308
- }))
13309
- }
13414
+ body: { entries }
13310
13415
  });
13311
13416
  return await response.json();
13312
13417
  }
13313
- async importDescriptors(entries) {
13314
- const response = await this.request("/registry/descriptors/import", {
13418
+ async importRequestPlans(input) {
13419
+ const response = await this.request("/registry/request-plans/import", {
13315
13420
  method: "POST",
13316
- body: { entries }
13421
+ body: input
13317
13422
  });
13318
13423
  return await response.json();
13319
13424
  }
@@ -13326,7 +13431,7 @@ var init_client = __esm({
13326
13431
  "content-type": "application/json; charset=utf-8"
13327
13432
  };
13328
13433
  }
13329
- async request(pathname, init) {
13434
+ async request(pathname, init, options = {}) {
13330
13435
  const url = `${this.config.baseUrl}${pathname}`;
13331
13436
  let response;
13332
13437
  try {
@@ -13334,7 +13439,7 @@ var init_client = __esm({
13334
13439
  method: init.method,
13335
13440
  headers: this.buildHeaders(),
13336
13441
  ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) },
13337
- signal: AbortSignal.timeout(3e4)
13442
+ signal: createRequestSignal(options)
13338
13443
  });
13339
13444
  } catch (error) {
13340
13445
  throw wrapCloudFetchError(error, {
@@ -13414,11 +13519,26 @@ var init_package = __esm({
13414
13519
  "../runtime-core/package.json"() {
13415
13520
  package_default2 = {
13416
13521
  name: "@opensteer/runtime-core",
13417
- version: "0.1.7",
13522
+ version: "0.2.0",
13418
13523
  description: "Shared semantic runtime for Opensteer local and cloud execution.",
13419
13524
  license: "MIT",
13420
13525
  type: "module",
13421
13526
  sideEffects: false,
13527
+ repository: {
13528
+ type: "git",
13529
+ url: "git+https://github.com/steerlabs/opensteer.git",
13530
+ directory: "packages/runtime-core"
13531
+ },
13532
+ bugs: {
13533
+ url: "https://github.com/steerlabs/opensteer/issues"
13534
+ },
13535
+ homepage: "https://github.com/steerlabs/opensteer/tree/main/packages/runtime-core#readme",
13536
+ keywords: [
13537
+ "opensteer",
13538
+ "runtime",
13539
+ "agents",
13540
+ "browser-automation"
13541
+ ],
13422
13542
  engines: {
13423
13543
  node: ">=22"
13424
13544
  },
@@ -13568,7 +13688,6 @@ var init_defaults = __esm({
13568
13688
  "dom.extract": 15e3,
13569
13689
  "network.query": 15e3,
13570
13690
  "network.detail": 15e3,
13571
- "network.replay": 3e4,
13572
13691
  "scripts.capture": 15e3,
13573
13692
  "session.cookies": 1e4,
13574
13693
  "session.storage": 1e4,
@@ -22728,6 +22847,21 @@ function buildEngineNetworkRecordFilters(input) {
22728
22847
  function normalizeNetworkStatusFilter(status) {
22729
22848
  return String(status);
22730
22849
  }
22850
+ function normalizeNetworkQueryInput(input) {
22851
+ return {
22852
+ ...input,
22853
+ ...input.recordId === void 0 ? {} : { recordId: normalizeNetworkRecordId(input.recordId) },
22854
+ ...input.before === void 0 ? {} : { before: normalizeNetworkRecordId(input.before) },
22855
+ ...input.after === void 0 ? {} : { after: normalizeNetworkRecordId(input.after) }
22856
+ };
22857
+ }
22858
+ function normalizeNetworkRecordId(recordId) {
22859
+ const trimmed = recordId.trim();
22860
+ if (trimmed.length === 0 || trimmed.startsWith("record:")) {
22861
+ return trimmed;
22862
+ }
22863
+ return `record:${trimmed}`;
22864
+ }
22731
22865
  function resolveLiveQueryRequestIds(input, history) {
22732
22866
  const requestIdCandidates = [];
22733
22867
  if (input.recordId !== void 0) {
@@ -22925,6 +23059,20 @@ function jsonStructureShape(value) {
22925
23059
  }
22926
23060
  return typeof value;
22927
23061
  }
23062
+ function resolveReplayProbeAttemptTimeoutMs(input) {
23063
+ const attemptCapMs = input.recommendedFound ? REPLAY_PROBE_POST_SUCCESS_ATTEMPT_TIMEOUT_MS : REPLAY_PROBE_MAX_ATTEMPT_TIMEOUT_MS;
23064
+ const clampedRemaining = input.remainingMs === void 0 ? void 0 : Math.max(0, input.remainingMs);
23065
+ if (clampedRemaining === 0) {
23066
+ return 0;
23067
+ }
23068
+ if (clampedRemaining === void 0) {
23069
+ return attemptCapMs;
23070
+ }
23071
+ const sliceMs = Math.floor(clampedRemaining / Math.max(1, input.transportsRemaining));
23072
+ const minimumBudgetAffordable = clampedRemaining >= REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS * input.transportsRemaining;
23073
+ const attemptBudgetMs = minimumBudgetAffordable ? Math.max(REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS, sliceMs) : sliceMs;
23074
+ return Math.min(clampedRemaining, attemptCapMs, Math.max(1, attemptBudgetMs));
23075
+ }
22928
23076
  function filterNetworkSummaryRecords(records, input) {
22929
23077
  return records.filter((record) => {
22930
23078
  if (record.record.resourceType === "preflight" || record.record.method === "OPTIONS") {
@@ -23097,10 +23245,10 @@ function extractGraphqlOperationName(queryText) {
23097
23245
  function shouldShowRequestBody(method) {
23098
23246
  return !["GET", "HEAD", "DELETE", "OPTIONS"].includes(method.trim().toUpperCase());
23099
23247
  }
23100
- function buildStructuredBodyPreview(body, headers) {
23248
+ function buildStructuredBodyPreview(body, headers, options = {}) {
23101
23249
  const contentType = headerValue(headers, "content-type") ?? body?.mimeType;
23102
23250
  const parsed = parseStructuredPayload(body, contentType);
23103
- const data = parsed === void 0 ? void 0 : typeof parsed === "string" ? truncateInlineText(parsed) : truncateStructuredValue(parsed);
23251
+ const data = parsed === void 0 ? void 0 : options.truncateData === false ? parsed : typeof parsed === "string" ? truncateInlineText(parsed) : truncateStructuredValue(parsed);
23104
23252
  return {
23105
23253
  bytes: body?.originalByteLength ?? body?.capturedByteLength ?? 0,
23106
23254
  ...contentType === void 0 ? {} : { contentType },
@@ -23313,10 +23461,12 @@ function resolveSessionFetchTransportLadder(transport) {
23313
23461
  return ["direct-http"];
23314
23462
  case "matched-tls":
23315
23463
  return ["matched-tls"];
23464
+ case "context":
23465
+ return ["context-http"];
23316
23466
  case "page":
23317
23467
  return ["page-http"];
23318
23468
  case "auto":
23319
- return ["direct-http", "matched-tls", "page-http"];
23469
+ return ["direct-http", "matched-tls", "context-http", "page-http"];
23320
23470
  }
23321
23471
  }
23322
23472
  function detectChallengeNoteFromRecord(record) {
@@ -23461,6 +23611,12 @@ function diffStorageSnapshot(left, right) {
23461
23611
  function normalizeRuntimeErrorMessage(error) {
23462
23612
  return error instanceof Error ? error.message : String(error);
23463
23613
  }
23614
+ function normalizeProbeTransportAttemptError(transport, error, attemptTimeoutMs) {
23615
+ if (attemptTimeoutMs !== void 0 && error instanceof OpensteerProtocolError && error.code === "timeout") {
23616
+ return `${transport} probe exceeded ${String(attemptTimeoutMs)}ms`;
23617
+ }
23618
+ return normalizeRuntimeErrorMessage(error);
23619
+ }
23464
23620
  function applyBrowserCookiesToTransportRequest(request, cookies) {
23465
23621
  if (cookies.length === 0) {
23466
23622
  return request;
@@ -23835,7 +23991,7 @@ function screenshotMediaType(format2) {
23835
23991
  return "image/webp";
23836
23992
  }
23837
23993
  }
23838
- var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS, PERSISTED_NETWORK_FLUSH_TIMEOUT_MS, PENDING_OPERATION_EVENT_CAPTURE_LIMIT, PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS, OpensteerSessionRuntime, DEFAULT_STATE_GLOBAL_NAMES, REPLAY_TRANSPORT_LADDER, CAPTURE_PAGE_STATE_SCRIPT, INTERACTION_RECORDER_INSTALL_SCRIPT, INTERACTION_RECORDER_READ_SCRIPT, INTERACTION_REPLAY_SCRIPT, PAGE_HTTP_REQUEST_SCRIPT;
23994
+ var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS, PERSISTED_NETWORK_FLUSH_TIMEOUT_MS, PENDING_OPERATION_EVENT_CAPTURE_LIMIT, PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS, REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS, REPLAY_PROBE_MAX_ATTEMPT_TIMEOUT_MS, REPLAY_PROBE_POST_SUCCESS_ATTEMPT_TIMEOUT_MS, OpensteerSessionRuntime, DEFAULT_STATE_GLOBAL_NAMES, REPLAY_TRANSPORT_LADDER, CAPTURE_PAGE_STATE_SCRIPT, INTERACTION_RECORDER_INSTALL_SCRIPT, INTERACTION_RECORDER_READ_SCRIPT, INTERACTION_REPLAY_SCRIPT, PAGE_HTTP_REQUEST_SCRIPT;
23839
23995
  var init_runtime3 = __esm({
23840
23996
  "../runtime-core/src/sdk/runtime.ts"() {
23841
23997
  init_src();
@@ -23871,6 +24027,9 @@ var init_runtime3 = __esm({
23871
24027
  PERSISTED_NETWORK_FLUSH_TIMEOUT_MS = 5e3;
23872
24028
  PENDING_OPERATION_EVENT_CAPTURE_LIMIT = 64;
23873
24029
  PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS = 1e3;
24030
+ REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS = 3e3;
24031
+ REPLAY_PROBE_MAX_ATTEMPT_TIMEOUT_MS = 15e3;
24032
+ REPLAY_PROBE_POST_SUCCESS_ATTEMPT_TIMEOUT_MS = 5e3;
23874
24033
  OpensteerSessionRuntime = class {
23875
24034
  workspace;
23876
24035
  rootPath;
@@ -24732,26 +24891,27 @@ var init_runtime3 = __esm({
24732
24891
  }
24733
24892
  }
24734
24893
  async queryNetwork(input = {}, options = {}) {
24735
- assertValidSemanticOperationInput("network.query", input);
24894
+ const normalizedInput = normalizeNetworkQueryInput(input);
24895
+ assertValidSemanticOperationInput("network.query", normalizedInput);
24736
24896
  const root = await this.ensureRoot();
24737
24897
  const startedAt = Date.now();
24738
24898
  try {
24739
24899
  const output = await this.runWithOperationTimeout(
24740
24900
  "network.query",
24741
24901
  async (timeout) => {
24742
- await this.syncPersistedNetworkSelection(timeout, input, {
24902
+ await this.syncPersistedNetworkSelection(timeout, normalizedInput, {
24743
24903
  includeBodies: false
24744
24904
  });
24745
24905
  const rawRecords = await timeout.runStep(
24746
24906
  () => root.registry.savedNetwork.query({
24747
- ...this.toSavedNetworkQueryInput(input),
24748
- limit: Math.max(input.limit ?? 50, 1e3)
24907
+ ...this.toSavedNetworkQueryInput(normalizedInput),
24908
+ limit: Math.max(normalizedInput.limit ?? 50, 1e3)
24749
24909
  })
24750
24910
  );
24751
- const filtered = filterNetworkSummaryRecords(rawRecords, input);
24911
+ const filtered = filterNetworkSummaryRecords(rawRecords, normalizedInput);
24752
24912
  const sorted = sortPersistedNetworkRecordsChronologically(filtered);
24753
- const sliced = sliceNetworkSummaryWindow(sorted, input);
24754
- const limited = sliced.slice(0, Math.max(1, Math.min(input.limit ?? 50, 200)));
24913
+ const sliced = sliceNetworkSummaryWindow(sorted, normalizedInput);
24914
+ const limited = sliced.slice(0, Math.max(1, Math.min(normalizedInput.limit ?? 50, 200)));
24755
24915
  const summaries = await this.buildNetworkSummaryRecords(limited, timeout);
24756
24916
  return {
24757
24917
  records: summaries
@@ -24765,9 +24925,9 @@ var init_runtime3 = __esm({
24765
24925
  completedAt: Date.now(),
24766
24926
  outcome: "ok",
24767
24927
  data: {
24768
- limit: input.limit ?? 50,
24769
- ...input.capture === void 0 ? {} : { capture: input.capture },
24770
- ...input.json === true ? { json: true } : {},
24928
+ limit: normalizedInput.limit ?? 50,
24929
+ ...normalizedInput.capture === void 0 ? {} : { capture: normalizedInput.capture },
24930
+ ...normalizedInput.json === true ? { json: true } : {},
24771
24931
  count: output.records.length
24772
24932
  },
24773
24933
  context: buildRuntimeTraceContext({
@@ -24792,12 +24952,13 @@ var init_runtime3 = __esm({
24792
24952
  }
24793
24953
  }
24794
24954
  async getNetworkDetail(input, options = {}) {
24955
+ const normalizedRecordId = normalizeNetworkRecordId(input.recordId);
24795
24956
  const startedAt = Date.now();
24796
24957
  try {
24797
24958
  const output = await this.runWithOperationTimeout(
24798
24959
  "network.detail",
24799
24960
  async (timeout) => {
24800
- const record = await this.resolveNetworkRecordByRecordId(input.recordId, timeout, {
24961
+ const record = await this.resolveNetworkRecordByRecordId(normalizedRecordId, timeout, {
24801
24962
  includeBodies: true,
24802
24963
  redactSecretHeaders: false
24803
24964
  });
@@ -24816,8 +24977,8 @@ var init_runtime3 = __esm({
24816
24977
  completedAt: Date.now(),
24817
24978
  outcome: "ok",
24818
24979
  data: {
24819
- recordId: input.recordId,
24820
- status: output.summary.status,
24980
+ recordId: normalizedRecordId,
24981
+ ...output.summary.status === void 0 ? {} : { status: output.summary.status },
24821
24982
  url: output.summary.url
24822
24983
  },
24823
24984
  context: buildRuntimeTraceContext({
@@ -26221,7 +26382,9 @@ var init_runtime3 = __esm({
26221
26382
  ...graphql.persisted === void 0 ? {} : { persisted: graphql.persisted },
26222
26383
  ...graphqlVariables === void 0 ? {} : { variables: graphqlVariables }
26223
26384
  };
26224
- const requestBody = shouldShowRequestBody(record.record.method) && record.record.requestBody !== void 0 ? buildStructuredBodyPreview(record.record.requestBody, record.record.requestHeaders) : void 0;
26385
+ const requestBody = shouldShowRequestBody(record.record.method) && record.record.requestBody !== void 0 ? buildStructuredBodyPreview(record.record.requestBody, record.record.requestHeaders, {
26386
+ truncateData: false
26387
+ }) : void 0;
26225
26388
  const responseBody = record.record.responseBody === void 0 ? void 0 : buildStructuredBodyPreview(record.record.responseBody, record.record.responseHeaders);
26226
26389
  const notes = detectNetworkRecordNotes(record);
26227
26390
  return {
@@ -26251,8 +26414,18 @@ var init_runtime3 = __esm({
26251
26414
  let recommended;
26252
26415
  for (const transport of REPLAY_TRANSPORT_LADDER) {
26253
26416
  const attemptStartedAt = Date.now();
26417
+ const attemptTimeoutMs = resolveReplayProbeAttemptTimeoutMs({
26418
+ remainingMs: timeout.remainingMs(),
26419
+ transportsRemaining: REPLAY_TRANSPORT_LADDER.length - attempts.length,
26420
+ recommendedFound: recommended !== void 0
26421
+ });
26254
26422
  try {
26255
- const output = await this.executeReplayTransportAttempt(transport, request, timeout);
26423
+ const output = await this.executeReplayTransportAttemptWithinBudget(
26424
+ transport,
26425
+ request,
26426
+ timeout,
26427
+ attemptTimeoutMs
26428
+ );
26256
26429
  const ok = matchesSuccessFingerprintFromProtocolResponse(output.response, fingerprint);
26257
26430
  attempts.push({
26258
26431
  transport,
@@ -26268,7 +26441,7 @@ var init_runtime3 = __esm({
26268
26441
  transport,
26269
26442
  ok: false,
26270
26443
  durationMs: Date.now() - attemptStartedAt,
26271
- error: normalizeRuntimeErrorMessage(error)
26444
+ error: normalizeProbeTransportAttemptError(transport, error, attemptTimeoutMs)
26272
26445
  });
26273
26446
  }
26274
26447
  }
@@ -26472,6 +26645,23 @@ var init_runtime3 = __esm({
26472
26645
  }
26473
26646
  }
26474
26647
  }
26648
+ async executeReplayTransportAttemptWithinBudget(transport, request, timeout, attemptTimeoutMs) {
26649
+ if (attemptTimeoutMs === void 0) {
26650
+ return this.executeReplayTransportAttempt(transport, request, timeout);
26651
+ }
26652
+ return runWithPolicyTimeout(
26653
+ {
26654
+ resolveTimeoutMs() {
26655
+ return attemptTimeoutMs;
26656
+ }
26657
+ },
26658
+ {
26659
+ operation: timeout.operation,
26660
+ signal: timeout.signal
26661
+ },
26662
+ (attemptTimeout) => this.executeReplayTransportAttempt(transport, request, attemptTimeout)
26663
+ );
26664
+ }
26475
26665
  async executeFetchTransportAttempt(transport, request, timeout, input) {
26476
26666
  let prepared = finalizeMaterializedTransportRequest(request, transport);
26477
26667
  if (input.cookies !== false && transport === "direct-http" && this.currentBinding() !== void 0) {
@@ -27386,10 +27576,15 @@ var init_runtime3 = __esm({
27386
27576
  return this.observationSessionId ?? this.sessionRef;
27387
27577
  }
27388
27578
  runWithOperationTimeout(operation, callback, options = {}) {
27579
+ const timeoutPolicy = options.timeoutMs === void 0 ? this.policy.timeout : {
27580
+ resolveTimeoutMs() {
27581
+ return options.timeoutMs;
27582
+ }
27583
+ };
27389
27584
  const existingCollector = this.operationEventStorage.getStore();
27390
27585
  if (existingCollector !== void 0) {
27391
27586
  return runWithPolicyTimeout(
27392
- this.policy.timeout,
27587
+ timeoutPolicy,
27393
27588
  {
27394
27589
  operation,
27395
27590
  ...options.signal === void 0 ? {} : { signal: options.signal }
@@ -27402,7 +27597,7 @@ var init_runtime3 = __esm({
27402
27597
  return this.operationEventStorage.run(collector, async () => {
27403
27598
  try {
27404
27599
  return await runWithPolicyTimeout(
27405
- this.policy.timeout,
27600
+ timeoutPolicy,
27406
27601
  {
27407
27602
  operation,
27408
27603
  ...options.signal === void 0 ? {} : { signal: options.signal }
@@ -29706,6 +29901,20 @@ var init_src3 = __esm({
29706
29901
  init_recorder();
29707
29902
  }
29708
29903
  });
29904
+
29905
+ // src/policy/index.ts
29906
+ var init_policy2 = __esm({
29907
+ "src/policy/index.ts"() {
29908
+ init_policy();
29909
+ }
29910
+ });
29911
+ function createRequestSignal2(options) {
29912
+ const timeoutSignal = AbortSignal.timeout(options.timeoutMs ?? 3e4);
29913
+ if (options.signal === void 0) {
29914
+ return timeoutSignal;
29915
+ }
29916
+ return AbortSignal.any([options.signal, timeoutSignal]);
29917
+ }
29709
29918
  function isFetchFailure(error) {
29710
29919
  if (!(error instanceof Error)) {
29711
29920
  return false;
@@ -29730,10 +29939,10 @@ var init_semantic_rest_client = __esm({
29730
29939
  constructor(connection) {
29731
29940
  this.connection = connection;
29732
29941
  }
29733
- async invoke(operation, input) {
29734
- return this.invokeInternal(operation, input, false);
29942
+ async invoke(operation, input, options = {}) {
29943
+ return this.invokeInternal(operation, input, false, options);
29735
29944
  }
29736
- async invokeInternal(operation, input, hasRetried) {
29945
+ async invokeInternal(operation, input, hasRetried, options) {
29737
29946
  const endpoint = opensteerSemanticRestEndpoints.find((entry) => entry.name === operation);
29738
29947
  if (!endpoint) {
29739
29948
  throw new Error(`unsupported semantic operation ${operation}`);
@@ -29747,10 +29956,11 @@ var init_semantic_rest_client = __esm({
29747
29956
  method: "POST",
29748
29957
  headers: {
29749
29958
  authorization: await this.connection.getAuthorizationHeader(),
29750
- "content-type": "application/json; charset=utf-8"
29959
+ "content-type": "application/json; charset=utf-8",
29960
+ ...options.timeoutMs === void 0 ? {} : { "x-opensteer-timeout-ms": String(options.timeoutMs) }
29751
29961
  },
29752
29962
  body: JSON.stringify(request),
29753
- signal: AbortSignal.timeout(3e4)
29963
+ signal: createRequestSignal2(options)
29754
29964
  });
29755
29965
  } catch (error) {
29756
29966
  if (operation === "session.close" && isFetchFailure(error)) {
@@ -29766,7 +29976,7 @@ var init_semantic_rest_client = __esm({
29766
29976
  return envelope.data;
29767
29977
  } catch (error) {
29768
29978
  if (!hasRetried && this.connection.handleError && await this.connection.handleError(error, { operation })) {
29769
- return this.invokeInternal(operation, input, true);
29979
+ return this.invokeInternal(operation, input, true, options);
29770
29980
  }
29771
29981
  if (operation === "session.close" && isFetchFailure(error)) {
29772
29982
  return { closed: true };
@@ -30147,11 +30357,42 @@ var init_automation_client = __esm({
30147
30357
  }
30148
30358
  });
30149
30359
 
30150
- // src/cloud/registry-sync.ts
30151
- async function syncLocalRegistryToCloud(client, workspace, store) {
30360
+ // src/cloud/workspace-sync.ts
30361
+ async function syncLocalWorkspaceToCloud(client, workspace, store) {
30362
+ await syncDescriptorRegistryToCloud(client, workspace, store);
30363
+ await syncRequestPlansToCloud(client, workspace, store);
30364
+ }
30365
+ async function syncDescriptorRegistryToCloud(client, workspace, store) {
30152
30366
  const descriptors = await store.registry.descriptors.list();
30153
- const descriptorEntries = descriptors.map((record) => toDescriptorImportEntry(workspace, record));
30154
- await importInBatches(descriptorEntries, (entries) => client.importDescriptors(entries));
30367
+ const entries = descriptors.map((record) => toDescriptorImportEntry(workspace, record));
30368
+ await importInBatches(entries, {
30369
+ getPayloadByteLength: (batch) => payloadByteLength({ entries: batch }),
30370
+ importBatch: (batch) => client.importDescriptors(batch)
30371
+ });
30372
+ }
30373
+ async function syncRequestPlansToCloud(client, workspace, store) {
30374
+ const requestPlans = await store.registry.requestPlans.list();
30375
+ const entries = requestPlans.map((record) => toRequestPlanImportEntry(workspace, record)).filter((entry) => entry !== void 0);
30376
+ await importInBatches(entries, {
30377
+ getPayloadByteLength: (batch) => payloadByteLength({ entries: batch }),
30378
+ importBatch: (batch) => client.importRequestPlans({ entries: batch })
30379
+ });
30380
+ }
30381
+ function toRequestPlanImportEntry(workspace, record) {
30382
+ const entry = {
30383
+ workspace,
30384
+ recordId: record.id,
30385
+ key: record.key,
30386
+ version: record.version,
30387
+ contentHash: record.contentHash,
30388
+ tags: [...record.tags],
30389
+ ...record.provenance === void 0 ? {} : { provenance: record.provenance },
30390
+ ...record.freshness === void 0 ? {} : { freshness: record.freshness },
30391
+ payload: record.payload,
30392
+ createdAt: record.createdAt,
30393
+ updatedAt: record.updatedAt
30394
+ };
30395
+ return payloadByteLength({ entries: [entry] }) <= WORKSPACE_SYNC_MAX_PAYLOAD_BYTES ? entry : void 0;
30155
30396
  }
30156
30397
  function toDescriptorImportEntry(workspace, record) {
30157
30398
  return {
@@ -30167,19 +30408,19 @@ function toDescriptorImportEntry(workspace, record) {
30167
30408
  updatedAt: record.updatedAt
30168
30409
  };
30169
30410
  }
30170
- async function importInBatches(entries, importBatch) {
30411
+ async function importInBatches(entries, options) {
30171
30412
  if (entries.length === 0) {
30172
30413
  return;
30173
30414
  }
30174
- for (const batch of chunkEntries(entries)) {
30175
- await importBatch(batch);
30415
+ for (const batch of chunkEntries(entries, options.getPayloadByteLength)) {
30416
+ await options.importBatch(batch);
30176
30417
  }
30177
30418
  }
30178
- function chunkEntries(entries) {
30419
+ function chunkEntries(entries, getPayloadByteLength) {
30179
30420
  const batches = [];
30180
30421
  let currentBatch = [];
30181
30422
  for (const entry of entries) {
30182
- if (payloadByteLength([entry]) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
30423
+ if (getPayloadByteLength([entry]) > WORKSPACE_SYNC_MAX_PAYLOAD_BYTES) {
30183
30424
  continue;
30184
30425
  }
30185
30426
  if (currentBatch.length === 0) {
@@ -30187,7 +30428,7 @@ function chunkEntries(entries) {
30187
30428
  continue;
30188
30429
  }
30189
30430
  const nextBatch = [...currentBatch, entry];
30190
- if (nextBatch.length > REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH || payloadByteLength(nextBatch) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
30431
+ if (nextBatch.length > WORKSPACE_SYNC_MAX_ENTRIES_PER_BATCH || getPayloadByteLength(nextBatch) > WORKSPACE_SYNC_MAX_PAYLOAD_BYTES) {
30191
30432
  batches.push(currentBatch);
30192
30433
  currentBatch = [entry];
30193
30434
  continue;
@@ -30199,14 +30440,14 @@ function chunkEntries(entries) {
30199
30440
  }
30200
30441
  return batches;
30201
30442
  }
30202
- function payloadByteLength(entries) {
30203
- return Buffer.byteLength(JSON.stringify({ entries }), "utf8");
30443
+ function payloadByteLength(value) {
30444
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
30204
30445
  }
30205
- var REGISTRY_SYNC_MAX_PAYLOAD_BYTES, REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH;
30206
- var init_registry_sync = __esm({
30207
- "src/cloud/registry-sync.ts"() {
30208
- REGISTRY_SYNC_MAX_PAYLOAD_BYTES = 15e5;
30209
- REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH = 100;
30446
+ var WORKSPACE_SYNC_MAX_PAYLOAD_BYTES, WORKSPACE_SYNC_MAX_ENTRIES_PER_BATCH;
30447
+ var init_workspace_sync = __esm({
30448
+ "src/cloud/workspace-sync.ts"() {
30449
+ WORKSPACE_SYNC_MAX_PAYLOAD_BYTES = 15e5;
30450
+ WORKSPACE_SYNC_MAX_ENTRIES_PER_BATCH = 100;
30210
30451
  }
30211
30452
  });
30212
30453
  function resolveCloudBrowserProfile(cloud, input) {
@@ -30239,9 +30480,10 @@ var init_session_proxy = __esm({
30239
30480
  init_src2();
30240
30481
  init_live_session();
30241
30482
  init_root2();
30483
+ init_policy2();
30242
30484
  init_semantic_rest_client();
30243
30485
  init_automation_client();
30244
- init_registry_sync();
30486
+ init_workspace_sync();
30245
30487
  TEMPORARY_CLOUD_WORKSPACE_PREFIX = "opensteer-cloud-workspace-";
30246
30488
  CloudSessionProxy = class {
30247
30489
  rootPath;
@@ -30249,14 +30491,17 @@ var init_session_proxy = __esm({
30249
30491
  cleanupRootOnClose;
30250
30492
  cloud;
30251
30493
  observability;
30494
+ policy;
30252
30495
  sessionId;
30253
30496
  semanticGrant;
30254
30497
  client;
30255
30498
  automation;
30256
30499
  workspaceStore;
30500
+ syncWorkspaceOnClose = false;
30257
30501
  constructor(cloud, options = {}) {
30258
30502
  this.cloud = cloud;
30259
30503
  this.workspace = options.workspace;
30504
+ this.policy = options.policy ?? defaultPolicy();
30260
30505
  this.observability = options.observability;
30261
30506
  this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path7__default.default.join(os.tmpdir(), `${TEMPORARY_CLOUD_WORKSPACE_PREFIX}${crypto.randomUUID()}`) : resolveFilesystemWorkspacePath({
30262
30507
  rootDir: path7__default.default.resolve(options.rootDir ?? process.cwd()),
@@ -30265,14 +30510,17 @@ var init_session_proxy = __esm({
30265
30510
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.workspace === void 0;
30266
30511
  }
30267
30512
  async open(input = {}) {
30268
- await this.ensureSession({
30269
- ...input.browser === void 0 ? {} : { browser: input.browser },
30270
- ...input.launch === void 0 ? {} : { launch: input.launch },
30271
- ...input.context === void 0 ? {} : { context: input.context }
30272
- });
30273
- return this.requireClient().invoke("session.open", {
30274
- ...input.url === void 0 ? {} : { url: input.url }
30275
- });
30513
+ return this.invokeSemanticOperation(
30514
+ "session.open",
30515
+ {
30516
+ ...input.url === void 0 ? {} : { url: input.url }
30517
+ },
30518
+ {
30519
+ ...input.browser === void 0 ? {} : { browser: input.browser },
30520
+ ...input.launch === void 0 ? {} : { launch: input.launch },
30521
+ ...input.context === void 0 ? {} : { context: input.context }
30522
+ }
30523
+ );
30276
30524
  }
30277
30525
  async info() {
30278
30526
  const persisted = this.client !== void 0 || this.sessionId !== void 0 ? void 0 : await this.loadPersistedSession();
@@ -30315,108 +30563,88 @@ var init_session_proxy = __esm({
30315
30563
  };
30316
30564
  }
30317
30565
  async listPages(input = {}) {
30318
- await this.ensureSession();
30319
- return this.requireClient().invoke("page.list", input);
30566
+ return this.invokeSemanticOperation("page.list", input);
30320
30567
  }
30321
30568
  async newPage(input = {}) {
30322
- await this.ensureSession();
30323
- return this.requireAutomation().invoke("page.new", input);
30569
+ return this.invokeAutomationOperation(
30570
+ "page.new",
30571
+ (automation) => automation.invoke("page.new", input)
30572
+ );
30324
30573
  }
30325
30574
  async activatePage(input) {
30326
- await this.ensureSession();
30327
- return this.requireClient().invoke("page.activate", input);
30575
+ return this.invokeSemanticOperation("page.activate", input);
30328
30576
  }
30329
30577
  async closePage(input = {}) {
30330
- await this.ensureSession();
30331
- return this.requireClient().invoke("page.close", input);
30578
+ return this.invokeSemanticOperation("page.close", input);
30332
30579
  }
30333
30580
  async goto(input) {
30334
- await this.ensureSession();
30335
- return this.requireClient().invoke("page.goto", input);
30581
+ return this.invokeSemanticOperation("page.goto", input);
30336
30582
  }
30337
30583
  async evaluate(input) {
30338
- await this.ensureSession();
30339
- return this.requireAutomation().invoke("page.evaluate", input);
30584
+ return this.invokeAutomationOperation(
30585
+ "page.evaluate",
30586
+ (automation) => automation.invoke("page.evaluate", input)
30587
+ );
30340
30588
  }
30341
30589
  async addInitScript(input) {
30342
- await this.ensureSession();
30343
- return this.requireClient().invoke("page.add-init-script", input);
30590
+ return this.invokeSemanticOperation("page.add-init-script", input);
30344
30591
  }
30345
30592
  async snapshot(input = {}) {
30346
- await this.ensureSession();
30347
- return this.requireClient().invoke("page.snapshot", input);
30593
+ return this.invokeSemanticOperation("page.snapshot", input);
30348
30594
  }
30349
30595
  async click(input) {
30350
- await this.ensureSession();
30351
- return this.requireClient().invoke("dom.click", input);
30596
+ return this.invokeSemanticOperation("dom.click", input);
30352
30597
  }
30353
30598
  async hover(input) {
30354
- await this.ensureSession();
30355
- return this.requireClient().invoke("dom.hover", input);
30599
+ return this.invokeSemanticOperation("dom.hover", input);
30356
30600
  }
30357
30601
  async input(input) {
30358
- await this.ensureSession();
30359
- return this.requireClient().invoke("dom.input", input);
30602
+ return this.invokeSemanticOperation("dom.input", input);
30360
30603
  }
30361
30604
  async scroll(input) {
30362
- await this.ensureSession();
30363
- return this.requireClient().invoke("dom.scroll", input);
30605
+ return this.invokeSemanticOperation("dom.scroll", input);
30364
30606
  }
30365
30607
  async extract(input) {
30366
- await this.ensureSession();
30367
- return this.requireClient().invoke("dom.extract", input);
30608
+ return this.invokeSemanticOperation("dom.extract", input);
30368
30609
  }
30369
30610
  async queryNetwork(input = {}) {
30370
- await this.ensureSession();
30371
- return this.requireClient().invoke("network.query", input);
30611
+ return this.invokeSemanticOperation("network.query", input);
30372
30612
  }
30373
30613
  async getNetworkDetail(input) {
30374
- await this.ensureSession();
30375
- return this.requireClient().invoke("network.detail", input);
30614
+ return this.invokeSemanticOperation("network.detail", input);
30376
30615
  }
30377
30616
  async captureInteraction(input) {
30378
- await this.ensureSession();
30379
- return this.requireClient().invoke("interaction.capture", input);
30617
+ return this.invokeSemanticOperation("interaction.capture", input);
30380
30618
  }
30381
30619
  async getInteraction(input) {
30382
- await this.ensureSession();
30383
- return this.requireClient().invoke("interaction.get", input);
30620
+ return this.invokeSemanticOperation("interaction.get", input);
30384
30621
  }
30385
30622
  async diffInteraction(input) {
30386
- await this.ensureSession();
30387
- return this.requireClient().invoke("interaction.diff", input);
30623
+ return this.invokeSemanticOperation("interaction.diff", input);
30388
30624
  }
30389
30625
  async replayInteraction(input) {
30390
- await this.ensureSession();
30391
- return this.requireClient().invoke("interaction.replay", input);
30626
+ return this.invokeSemanticOperation("interaction.replay", input);
30392
30627
  }
30393
30628
  async captureScripts(input = {}) {
30394
- await this.ensureSession();
30395
- return this.requireClient().invoke("scripts.capture", input);
30629
+ return this.invokeSemanticOperation("scripts.capture", input);
30396
30630
  }
30397
30631
  async readArtifact(input) {
30398
- await this.ensureSession();
30399
- return this.requireClient().invoke("artifact.read", input);
30632
+ return this.invokeSemanticOperation("artifact.read", input);
30400
30633
  }
30401
30634
  async beautifyScript(input) {
30402
- await this.ensureSession();
30403
- return this.requireClient().invoke("scripts.beautify", input);
30635
+ return this.invokeSemanticOperation("scripts.beautify", input);
30404
30636
  }
30405
30637
  async deobfuscateScript(input) {
30406
- await this.ensureSession();
30407
- return this.requireClient().invoke("scripts.deobfuscate", input);
30638
+ return this.invokeSemanticOperation("scripts.deobfuscate", input);
30408
30639
  }
30409
30640
  async sandboxScript(input) {
30410
- await this.ensureSession();
30411
- return this.requireClient().invoke("scripts.sandbox", input);
30641
+ return this.invokeSemanticOperation("scripts.sandbox", input);
30412
30642
  }
30413
30643
  async solveCaptcha(input) {
30414
- await this.ensureSession();
30415
- return this.requireClient().invoke("captcha.solve", input);
30644
+ return this.invokeSemanticOperation("captcha.solve", input);
30416
30645
  }
30417
30646
  async getCookies(input = {}) {
30418
- await this.ensureSession();
30419
- return this.requireClient().invoke("session.cookies", input);
30647
+ return this.invokeSemanticOperation("session.cookies", input);
30420
30648
  }
30421
30649
  async route(input) {
30422
30650
  await this.ensureSession();
@@ -30427,20 +30655,16 @@ var init_session_proxy = __esm({
30427
30655
  return this.requireAutomation().interceptScript(input);
30428
30656
  }
30429
30657
  async getStorageSnapshot(input = {}) {
30430
- await this.ensureSession();
30431
- return this.requireClient().invoke("session.storage", input);
30658
+ return this.invokeSemanticOperation("session.storage", input);
30432
30659
  }
30433
30660
  async getBrowserState(input = {}) {
30434
- await this.ensureSession();
30435
- return this.requireClient().invoke("session.state", input);
30661
+ return this.invokeSemanticOperation("session.state", input);
30436
30662
  }
30437
30663
  async fetch(input) {
30438
- await this.ensureSession();
30439
- return this.requireClient().invoke("session.fetch", input);
30664
+ return this.invokeSemanticOperation("session.fetch", input);
30440
30665
  }
30441
30666
  async computerExecute(input) {
30442
- await this.ensureSession();
30443
- return this.requireClient().invoke("computer.execute", input);
30667
+ return this.invokeSemanticOperation("computer.execute", input);
30444
30668
  }
30445
30669
  async close() {
30446
30670
  const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 ? void 0 : {
@@ -30452,6 +30676,14 @@ var init_session_proxy = __esm({
30452
30676
  startedAt: Date.now(),
30453
30677
  updatedAt: Date.now()
30454
30678
  });
30679
+ let syncError;
30680
+ if (this.syncWorkspaceOnClose) {
30681
+ try {
30682
+ await this.syncWorkspaceToCloud();
30683
+ } catch (error) {
30684
+ syncError = error;
30685
+ }
30686
+ }
30455
30687
  try {
30456
30688
  if (session !== void 0) {
30457
30689
  await this.cloud.closeSession(session.sessionId).catch((error) => {
@@ -30472,6 +30704,9 @@ var init_session_proxy = __esm({
30472
30704
  await promises.rm(this.rootPath, { recursive: true, force: true }).catch(() => void 0);
30473
30705
  }
30474
30706
  }
30707
+ if (syncError !== void 0) {
30708
+ throw syncError;
30709
+ }
30475
30710
  return { closed: true };
30476
30711
  }
30477
30712
  async disconnect() {
@@ -30479,34 +30714,38 @@ var init_session_proxy = __esm({
30479
30714
  await this.close();
30480
30715
  return;
30481
30716
  }
30717
+ let syncError;
30718
+ if (this.syncWorkspaceOnClose) {
30719
+ try {
30720
+ await this.syncWorkspaceToCloud();
30721
+ } catch (error) {
30722
+ syncError = error;
30723
+ }
30724
+ }
30482
30725
  this.client = void 0;
30483
30726
  await this.automation?.close().catch(() => void 0);
30484
30727
  this.automation = void 0;
30485
30728
  this.sessionId = void 0;
30486
30729
  this.semanticGrant = void 0;
30730
+ if (syncError !== void 0) {
30731
+ throw syncError;
30732
+ }
30487
30733
  }
30488
- async ensureSession(input = {}) {
30734
+ async ensureSession(input = {}, timeout) {
30489
30735
  if (this.client) {
30490
30736
  return;
30491
30737
  }
30492
30738
  assertSupportedCloudBrowserMode(input.browser);
30493
30739
  const localCloud = this.shouldUseLocalCloudTransport();
30740
+ this.syncWorkspaceOnClose = localCloud && this.workspace !== void 0;
30494
30741
  const browserProfile = resolveCloudBrowserProfile(this.cloud, input);
30495
30742
  const persisted = await this.loadPersistedSession();
30496
- if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
30497
- if (localCloud) {
30498
- void this.syncRegistryToCloud();
30499
- } else {
30500
- await this.syncRegistryToCloud();
30501
- }
30743
+ if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId, timeout)) {
30744
+ await this.syncWorkspaceToCloud();
30502
30745
  this.bindClient(persisted);
30503
30746
  return;
30504
30747
  }
30505
- if (localCloud) {
30506
- void this.syncRegistryToCloud();
30507
- } else {
30508
- await this.syncRegistryToCloud();
30509
- }
30748
+ await this.syncWorkspaceToCloud();
30510
30749
  const baseCreateInput = {
30511
30750
  ...this.workspace === void 0 ? {} : { name: this.workspace },
30512
30751
  ...input.launch === void 0 ? {} : { browser: input.launch },
@@ -30518,10 +30757,12 @@ var init_session_proxy = __esm({
30518
30757
  ...baseCreateInput,
30519
30758
  sourceType: "local-cloud",
30520
30759
  sourceRef: this.workspace,
30521
- localWorkspaceRootPath: this.rootPath,
30522
- locality: "auto"
30760
+ localWorkspaceRootPath: this.rootPath
30523
30761
  } : baseCreateInput;
30524
- const session = await this.cloud.createSession(createInput);
30762
+ const session = await this.cloud.createSession(createInput, {
30763
+ signal: timeout?.signal,
30764
+ timeoutMs: timeout?.remainingMs()
30765
+ });
30525
30766
  const record = {
30526
30767
  layout: "opensteer-session",
30527
30768
  version: 1,
@@ -30534,15 +30775,12 @@ var init_session_proxy = __esm({
30534
30775
  await this.writePersistedSession(record);
30535
30776
  this.bindClient(record, session.initialGrants?.semantic);
30536
30777
  }
30537
- async syncRegistryToCloud() {
30778
+ async syncWorkspaceToCloud() {
30538
30779
  if (this.workspace === void 0) {
30539
30780
  return;
30540
30781
  }
30541
- try {
30542
- const workspaceStore = await this.ensureWorkspaceStore();
30543
- await syncLocalRegistryToCloud(this.cloud, this.workspace, workspaceStore);
30544
- } catch {
30545
- }
30782
+ const workspaceStore = await this.ensureWorkspaceStore();
30783
+ await syncLocalWorkspaceToCloud(this.cloud, this.workspace, workspaceStore);
30546
30784
  }
30547
30785
  bindClient(record, initialSemanticGrant) {
30548
30786
  this.sessionId = record.sessionId;
@@ -30576,9 +30814,12 @@ var init_session_proxy = __esm({
30576
30814
  async clearPersistedSession() {
30577
30815
  await clearPersistedSessionRecord(this.rootPath, "cloud").catch(() => void 0);
30578
30816
  }
30579
- async isReusableCloudSession(sessionId) {
30817
+ async isReusableCloudSession(sessionId, timeout) {
30580
30818
  try {
30581
- const session = await this.cloud.getSession(sessionId);
30819
+ const session = await this.cloud.getSession(sessionId, {
30820
+ signal: timeout?.signal,
30821
+ timeoutMs: timeout?.remainingMs()
30822
+ });
30582
30823
  return session.status !== "closed" && session.status !== "failed";
30583
30824
  } catch (error) {
30584
30825
  if (isMissingCloudSessionError(error)) {
@@ -30599,14 +30840,17 @@ var init_session_proxy = __esm({
30599
30840
  }
30600
30841
  return this.automation;
30601
30842
  }
30602
- async ensureSemanticGrant(forceRefresh = false) {
30843
+ async ensureSemanticGrant(forceRefresh = false, timeout) {
30603
30844
  if (!forceRefresh && this.semanticGrant?.kind === "semantic" && this.semanticGrant.expiresAt > Date.now() + 1e4) {
30604
30845
  return this.semanticGrant;
30605
30846
  }
30606
30847
  if (!this.sessionId) {
30607
30848
  throw new Error("Cloud session has not been initialized.");
30608
30849
  }
30609
- const issued = await this.cloud.issueAccess(this.sessionId, ["semantic"]);
30850
+ const issued = await this.cloud.issueAccess(this.sessionId, ["semantic"], {
30851
+ signal: timeout?.signal,
30852
+ timeoutMs: timeout?.remainingMs()
30853
+ });
30610
30854
  const grant = issued.grants.semantic;
30611
30855
  if (!grant || grant.transport !== "http") {
30612
30856
  throw new Error("cloud did not issue a valid semantic grant");
@@ -30629,6 +30873,25 @@ var init_session_proxy = __esm({
30629
30873
  return false;
30630
30874
  }
30631
30875
  }
30876
+ async invokeSemanticOperation(operation, input, sessionInit = {}) {
30877
+ return this.runOperationWithPolicy(operation, async (timeout) => {
30878
+ await this.ensureSession(sessionInit, timeout);
30879
+ await this.ensureSemanticGrant(false, timeout);
30880
+ return this.requireClient().invoke(operation, input, {
30881
+ signal: timeout.signal,
30882
+ timeoutMs: timeout.remainingMs()
30883
+ });
30884
+ });
30885
+ }
30886
+ async invokeAutomationOperation(operation, invoke, sessionInit = {}) {
30887
+ return this.runOperationWithPolicy(operation, async (timeout) => {
30888
+ await this.ensureSession(sessionInit, timeout);
30889
+ return invoke(this.requireAutomation());
30890
+ });
30891
+ }
30892
+ async runOperationWithPolicy(operation, invoke) {
30893
+ return runWithPolicyTimeout(this.policy.timeout, { operation }, invoke);
30894
+ }
30632
30895
  shouldUseLocalCloudTransport() {
30633
30896
  if (this.workspace === void 0) {
30634
30897
  return false;
@@ -30760,6 +31023,7 @@ function createOpensteerSemanticRuntime(input = {}) {
30760
31023
  ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
30761
31024
  ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
30762
31025
  ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
31026
+ ...runtimeOptions.policy === void 0 ? {} : { policy: runtimeOptions.policy },
30763
31027
  ...runtimeOptions.cleanupRootOnClose === void 0 ? {} : { cleanupRootOnClose: runtimeOptions.cleanupRootOnClose },
30764
31028
  ...runtimeOptions.observability === void 0 ? {} : { observability: runtimeOptions.observability }
30765
31029
  });
@@ -30950,23 +31214,28 @@ function pickStorageDomainSnapshot(snapshot, domain) {
30950
31214
  return snapshot.domains.find((entry) => entry.domain === domain);
30951
31215
  }
30952
31216
  function buildFetchInput(url, options) {
31217
+ const { body, ...rest } = options;
30953
31218
  return {
30954
31219
  url,
30955
- ...options.method !== void 0 && { method: options.method },
30956
- ...options.headers !== void 0 && { headers: options.headers },
30957
- ...options.query !== void 0 && { query: options.query },
30958
- ...options.transport !== void 0 && { transport: options.transport },
30959
- ...options.cookies !== void 0 && { cookies: options.cookies },
30960
- ...options.followRedirects !== void 0 && { followRedirects: options.followRedirects },
30961
- ...options.body !== void 0 && { body: toRuntimeBody(options.body) }
31220
+ ...rest,
31221
+ ...body === void 0 ? {} : { body: normalizeFetchBody(body, rest.headers) }
30962
31222
  };
30963
31223
  }
30964
- function toRuntimeBody(body) {
30965
- try {
30966
- return { json: JSON.parse(body) };
30967
- } catch {
30968
- return { text: body };
31224
+ function normalizeFetchBody(body, headers) {
31225
+ if (typeof body !== "string") {
31226
+ return body;
31227
+ }
31228
+ const contentType = findHeaderValue3(headers, "content-type");
31229
+ return contentType === void 0 ? { text: body } : { text: body, contentType };
31230
+ }
31231
+ function findHeaderValue3(headers, headerName) {
31232
+ if (headers === void 0) {
31233
+ return void 0;
30969
31234
  }
31235
+ const match = Object.entries(headers).find(
31236
+ ([name]) => name.toLowerCase() === headerName.toLowerCase()
31237
+ );
31238
+ return match === void 0 ? void 0 : String(match[1]);
30970
31239
  }
30971
31240
  function toResponse(response) {
30972
31241
  return new Response(decodeBody(response), {
@@ -31255,7 +31524,7 @@ var init_opensteer = __esm({
31255
31524
 
31256
31525
  // package.json
31257
31526
  var package_default = {
31258
- version: "0.8.17"};
31527
+ version: "0.9.0"};
31259
31528
 
31260
31529
  // src/cli/bin.ts
31261
31530
  init_browser_manager();
@@ -31302,7 +31571,7 @@ Network:
31302
31571
  network query [--capture <label>] [--url <pattern>] [--hostname <host>] [--path <path>] [--method <m>] [--status <code>] [--type <resourceType>] [--json] [--before <id>] [--after <id>] [--limit <n>]
31303
31572
  --json filters to JSON and GraphQL responses only
31304
31573
  network detail <recordId> [--probe]
31305
- fetch <url> [--method <m>] [--header key=value ...] [--query key=value ...] [--body <json>] [--body-text <text>] [--transport auto|direct|matched-tls|page] [--cookies] [--follow-redirects]
31574
+ fetch <url> [--method <m>] [--header key=value ...] [--query key=value ...] [--body <json>] [--body-text <text>] [--transport auto|direct|matched-tls|context|page] [--cookies] [--follow-redirects]
31306
31575
 
31307
31576
  Browser State:
31308
31577
  state [domain]
@@ -31718,7 +31987,7 @@ function readJsonArray(options, name) {
31718
31987
 
31719
31988
  // src/cli/operation-input.ts
31720
31989
  var CLICK_BUTTONS = /* @__PURE__ */ new Set(["left", "middle", "right"]);
31721
- var FETCH_TRANSPORTS = /* @__PURE__ */ new Set(["auto", "direct", "matched-tls", "page"]);
31990
+ var FETCH_TRANSPORTS = /* @__PURE__ */ new Set(["auto", "direct", "matched-tls", "context", "page"]);
31722
31991
  var CAPTCHA_PROVIDERS = /* @__PURE__ */ new Set(["2captcha", "capsolver"]);
31723
31992
  var CAPTCHA_TYPES = /* @__PURE__ */ new Set(["recaptcha-v2", "hcaptcha", "turnstile"]);
31724
31993
  var SANDBOX_FIDELITIES = /* @__PURE__ */ new Set(["minimal", "standard", "full"]);
@@ -32199,7 +32468,9 @@ function readClickButton(value) {
32199
32468
  }
32200
32469
  function readFetchTransport(value) {
32201
32470
  if (value === void 0 || !FETCH_TRANSPORTS.has(value)) {
32202
- throw new Error('Expected "--transport" to be one of: auto, direct, matched-tls, page.');
32471
+ throw new Error(
32472
+ 'Expected "--transport" to be one of: auto, direct, matched-tls, context, page.'
32473
+ );
32203
32474
  }
32204
32475
  return value;
32205
32476
  }
@@ -33396,7 +33667,7 @@ function formatLaneRow(input) {
33396
33667
  const provider = input.provider.padEnd(7, " ");
33397
33668
  const status = input.status.padEnd(9, " ");
33398
33669
  const summary = input.summary.padEnd(16, " ");
33399
- return `${input.marker} ${provider} ${status} ${summary}${input.detail ?? ""}`.trimEnd();
33670
+ return `${input.marker} ${provider} ${status} ${summary}${input.detail === void 0 ? "" : ` ${input.detail}`}`.trimEnd();
33400
33671
  }
33401
33672
 
33402
33673
  // src/cli/exec.ts