opensteer 0.8.18 → 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.
@@ -3028,7 +3028,7 @@ objectSchema(
3028
3028
  }
3029
3029
  );
3030
3030
  var opensteerSessionFetchTransportSchema = enumSchema(
3031
- ["auto", "direct", "matched-tls", "page"],
3031
+ ["auto", "direct", "matched-tls", "context", "page"],
3032
3032
  {
3033
3033
  title: "OpensteerSessionFetchTransport"
3034
3034
  }
@@ -7381,6 +7381,7 @@ var opensteerSemanticOperationSpecificationsBase = [
7381
7381
  case "direct":
7382
7382
  return [];
7383
7383
  case "matched-tls":
7384
+ case "context":
7384
7385
  return ["inspect.cookies"];
7385
7386
  case "page":
7386
7387
  return ["pages.manage"];
@@ -7992,13 +7993,6 @@ var SqliteSavedNetworkStore = class {
7992
7993
  }
7993
7994
  async save(records, options) {
7994
7995
  const database = await this.requireDatabase();
7995
- const readExisting = database.prepare(`
7996
- SELECT record_id
7997
- FROM saved_network_records
7998
- WHERE session_ref = @session_ref
7999
- AND page_ref_key = @page_ref_key
8000
- AND request_id = @request_id
8001
- `);
8002
7996
  const upsertRecord = database.prepare(buildSavedNetworkUpsertSql(options.bodyWriteMode));
8003
7997
  const insertTag = database.prepare(`
8004
7998
  INSERT OR IGNORE INTO saved_network_tags (record_id, tag)
@@ -8009,14 +8003,8 @@ var SqliteSavedNetworkStore = class {
8009
8003
  for (const entry of records) {
8010
8004
  const url = new URL(entry.record.url);
8011
8005
  const pageRefKey = entry.record.pageRef ?? "";
8012
- const existing = readExisting.get({
8013
- session_ref: entry.record.sessionRef,
8014
- page_ref_key: pageRefKey,
8015
- request_id: entry.record.requestId
8016
- }) ?? void 0;
8017
- const recordId = existing?.record_id ?? entry.recordId;
8018
8006
  upsertRecord.run({
8019
- record_id: recordId,
8007
+ record_id: entry.recordId,
8020
8008
  request_id: entry.record.requestId,
8021
8009
  session_ref: entry.record.sessionRef,
8022
8010
  page_ref: entry.record.pageRef ?? null,
@@ -8061,7 +8049,7 @@ var SqliteSavedNetworkStore = class {
8061
8049
  }
8062
8050
  for (const currentTag of tags) {
8063
8051
  const result = insertTag.run({
8064
- record_id: recordId,
8052
+ record_id: entry.recordId,
8065
8053
  tag: currentTag
8066
8054
  });
8067
8055
  savedCount += result.changes ?? 0;
@@ -8164,6 +8152,49 @@ var SqliteSavedNetworkStore = class {
8164
8152
  return cleared;
8165
8153
  });
8166
8154
  }
8155
+ async *iterateBatches(options = {}) {
8156
+ const database = await this.requireDatabase();
8157
+ const batchSize = Math.max(1, Math.min(options.batchSize ?? 500, 1e3));
8158
+ let cursor;
8159
+ while (true) {
8160
+ const rows = database.prepare(
8161
+ `
8162
+ SELECT
8163
+ r.*,
8164
+ GROUP_CONCAT(t.tag, '${TAG_DELIMITER}') AS tags
8165
+ FROM saved_network_records r
8166
+ LEFT JOIN saved_network_tags t
8167
+ ON t.record_id = r.record_id
8168
+ ${cursor === void 0 ? "" : "WHERE r.saved_at > ? OR (r.saved_at = ? AND r.record_id > ?)"}
8169
+ GROUP BY r.record_id
8170
+ ORDER BY r.saved_at ASC, r.record_id ASC
8171
+ LIMIT ?
8172
+ `
8173
+ ).all(
8174
+ ...cursor === void 0 ? [] : [cursor.savedAt, cursor.savedAt, cursor.recordId],
8175
+ batchSize
8176
+ );
8177
+ if (rows.length === 0) {
8178
+ return;
8179
+ }
8180
+ yield rows.map((row) => inflateSavedNetworkRow(row, options.includeBodies ?? true));
8181
+ const lastRow = rows.at(-1);
8182
+ if (lastRow === void 0) {
8183
+ return;
8184
+ }
8185
+ cursor = {
8186
+ savedAt: lastRow.saved_at,
8187
+ recordId: lastRow.record_id
8188
+ };
8189
+ }
8190
+ }
8191
+ close() {
8192
+ if (this.database !== void 0) {
8193
+ closeSqliteDatabase(this.database);
8194
+ this.database = void 0;
8195
+ this.databaseInitialization = void 0;
8196
+ }
8197
+ }
8167
8198
  async requireDatabase() {
8168
8199
  if (this.database) {
8169
8200
  return this.database;
@@ -8248,15 +8279,6 @@ var SqliteSavedNetworkStore = class {
8248
8279
  saved_at INTEGER NOT NULL
8249
8280
  );
8250
8281
 
8251
- CREATE UNIQUE INDEX IF NOT EXISTS saved_network_records_scope_request
8252
- ON saved_network_records (session_ref, page_ref_key, request_id);
8253
-
8254
- CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
8255
- ON saved_network_records (saved_at DESC);
8256
-
8257
- CREATE INDEX IF NOT EXISTS saved_network_records_capture
8258
- ON saved_network_records (capture);
8259
-
8260
8282
  CREATE TABLE IF NOT EXISTS saved_network_tags (
8261
8283
  record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
8262
8284
  tag TEXT NOT NULL,
@@ -8266,6 +8288,19 @@ var SqliteSavedNetworkStore = class {
8266
8288
  CREATE INDEX IF NOT EXISTS saved_network_tags_tag
8267
8289
  ON saved_network_tags (tag);
8268
8290
  `);
8291
+ database.exec(`DROP INDEX IF EXISTS saved_network_records_scope_request`);
8292
+ database.exec(`
8293
+ CREATE INDEX IF NOT EXISTS saved_network_records_scope_request
8294
+ ON saved_network_records (session_ref, page_ref_key, request_id)
8295
+ `);
8296
+ database.exec(`
8297
+ CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
8298
+ ON saved_network_records (saved_at DESC)
8299
+ `);
8300
+ database.exec(`
8301
+ CREATE INDEX IF NOT EXISTS saved_network_records_capture
8302
+ ON saved_network_records (capture)
8303
+ `);
8269
8304
  this.ensureColumn(
8270
8305
  database,
8271
8306
  "saved_network_records",
@@ -8913,7 +8948,6 @@ var DEFAULT_TIMEOUTS = {
8913
8948
  "dom.extract": 15e3,
8914
8949
  "network.query": 15e3,
8915
8950
  "network.detail": 15e3,
8916
- "network.replay": 3e4,
8917
8951
  "scripts.capture": 15e3,
8918
8952
  "session.cookies": 1e4,
8919
8953
  "session.storage": 1e4,
@@ -15946,8 +15980,14 @@ async function launchOwnedBrowser(input) {
15946
15980
  await ensureDirectory(input.userDataDir);
15947
15981
  await clearChromeSingletonEntries(input.userDataDir);
15948
15982
  await sanitizeChromeProfile(input.userDataDir);
15983
+ const requestedRemoteDebuggingPort = readRequestedRemoteDebuggingPort(input.launch?.args);
15949
15984
  const executablePath = resolveChromeExecutablePath(input.launch?.executablePath);
15950
- const args = buildChromeArgs(input.userDataDir, input.launch, input.viewport);
15985
+ const args = buildChromeArgs(
15986
+ input.userDataDir,
15987
+ input.launch,
15988
+ input.viewport,
15989
+ requestedRemoteDebuggingPort
15990
+ );
15951
15991
  const child = spawn(executablePath, args, {
15952
15992
  stdio: ["ignore", "ignore", "pipe"],
15953
15993
  detached: process.platform !== "win32"
@@ -15963,7 +16003,8 @@ async function launchOwnedBrowser(input) {
15963
16003
  userDataDir: input.userDataDir,
15964
16004
  timeoutMs: input.launch?.timeoutMs ?? DEFAULT_TIMEOUT_MS,
15965
16005
  childExited: async () => child.exitCode,
15966
- stderrLines
16006
+ stderrLines,
16007
+ ...requestedRemoteDebuggingPort !== void 0 && requestedRemoteDebuggingPort > 0 ? { requestedRemoteDebuggingPort } : {}
15967
16008
  }).catch(async (error) => {
15968
16009
  child.kill("SIGKILL");
15969
16010
  throw error;
@@ -15974,10 +16015,10 @@ async function launchOwnedBrowser(input) {
15974
16015
  executablePath
15975
16016
  };
15976
16017
  }
15977
- function buildChromeArgs(userDataDir, launch, viewport) {
16018
+ function buildChromeArgs(userDataDir, launch, viewport, requestedRemoteDebuggingPort) {
15978
16019
  const isHeadless = launch?.headless ?? true;
15979
16020
  const args = [
15980
- "--remote-debugging-port=0",
16021
+ ...requestedRemoteDebuggingPort === void 0 ? ["--remote-debugging-port=0"] : [],
15981
16022
  "--no-first-run",
15982
16023
  "--no-default-browser-check",
15983
16024
  "--disable-blink-features=AutomationControlled",
@@ -16028,6 +16069,15 @@ async function waitForDevToolsEndpoint(input) {
16028
16069
  return `ws://127.0.0.1:${String(activePort.port)}${activePort.webSocketPath}`;
16029
16070
  }
16030
16071
  }
16072
+ if (input.requestedRemoteDebuggingPort !== void 0) {
16073
+ const endpoint = await tryInspectRemoteDebuggingPort(
16074
+ input.requestedRemoteDebuggingPort,
16075
+ input.timeoutMs
16076
+ );
16077
+ if (endpoint !== void 0) {
16078
+ return endpoint;
16079
+ }
16080
+ }
16031
16081
  const exitCode = await input.childExited();
16032
16082
  if (exitCode !== null) {
16033
16083
  throw new Error(formatChromeLaunchError(input.stderrLines));
@@ -16036,6 +16086,52 @@ async function waitForDevToolsEndpoint(input) {
16036
16086
  }
16037
16087
  throw new Error(formatChromeLaunchError(input.stderrLines));
16038
16088
  }
16089
+ function readRequestedRemoteDebuggingPort(args) {
16090
+ if (args === void 0 || args.length === 0) {
16091
+ return void 0;
16092
+ }
16093
+ let explicitFlagFound = false;
16094
+ let port;
16095
+ for (let index = 0; index < args.length; index += 1) {
16096
+ const entry = args[index];
16097
+ if (entry === "--remote-debugging-port") {
16098
+ explicitFlagFound = true;
16099
+ const next = args[index + 1];
16100
+ if (next !== void 0) {
16101
+ port = parseRemoteDebuggingPort(next);
16102
+ index += 1;
16103
+ }
16104
+ continue;
16105
+ }
16106
+ if (entry.startsWith("--remote-debugging-port=")) {
16107
+ explicitFlagFound = true;
16108
+ port = parseRemoteDebuggingPort(entry.slice("--remote-debugging-port=".length));
16109
+ }
16110
+ }
16111
+ return explicitFlagFound ? port : void 0;
16112
+ }
16113
+ function parseRemoteDebuggingPort(value) {
16114
+ const trimmed = value.trim();
16115
+ if (!/^\d+$/.test(trimmed)) {
16116
+ return void 0;
16117
+ }
16118
+ const parsed = Number.parseInt(trimmed, 10);
16119
+ if (!Number.isInteger(parsed) || parsed < 0) {
16120
+ return void 0;
16121
+ }
16122
+ return parsed;
16123
+ }
16124
+ async function tryInspectRemoteDebuggingPort(port, timeoutMs) {
16125
+ try {
16126
+ const inspected = await inspectCdpEndpoint({
16127
+ endpoint: `http://127.0.0.1:${String(port)}`,
16128
+ timeoutMs: Math.min(2e3, timeoutMs)
16129
+ });
16130
+ return inspected.endpoint;
16131
+ } catch {
16132
+ return void 0;
16133
+ }
16134
+ }
16039
16135
  function formatChromeLaunchError(stderrLines) {
16040
16136
  const collapsed = stderrLines.join("").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
16041
16137
  if (collapsed.length === 0) {
@@ -16766,21 +16862,24 @@ var OpensteerCloudClient = class {
16766
16862
  getConfig() {
16767
16863
  return this.config;
16768
16864
  }
16769
- async createSession(input = {}) {
16770
- const response = await this.request("/v1/sessions", {
16771
- method: "POST",
16772
- body: {
16773
- ...input.name === void 0 ? {} : { name: input.name },
16774
- ...input.browser === void 0 ? {} : { browser: input.browser },
16775
- ...input.context === void 0 ? {} : { context: input.context },
16776
- ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
16777
- ...input.observability === void 0 ? {} : { observability: input.observability },
16778
- ...input.sourceType === void 0 ? {} : { sourceType: input.sourceType },
16779
- ...input.sourceRef === void 0 ? {} : { sourceRef: input.sourceRef },
16780
- ...input.localWorkspaceRootPath === void 0 ? {} : { localWorkspaceRootPath: input.localWorkspaceRootPath },
16781
- ...input.locality === void 0 ? {} : { locality: input.locality }
16782
- }
16783
- });
16865
+ async createSession(input = {}, options = {}) {
16866
+ const response = await this.request(
16867
+ "/v1/sessions",
16868
+ {
16869
+ method: "POST",
16870
+ body: {
16871
+ ...input.name === void 0 ? {} : { name: input.name },
16872
+ ...input.browser === void 0 ? {} : { browser: input.browser },
16873
+ ...input.context === void 0 ? {} : { context: input.context },
16874
+ ...input.browserProfile === void 0 ? {} : { browserProfile: input.browserProfile },
16875
+ ...input.observability === void 0 ? {} : { observability: input.observability },
16876
+ ...input.sourceType === void 0 ? {} : { sourceType: input.sourceType },
16877
+ ...input.sourceRef === void 0 ? {} : { sourceRef: input.sourceRef },
16878
+ ...input.localWorkspaceRootPath === void 0 ? {} : { localWorkspaceRootPath: input.localWorkspaceRootPath }
16879
+ }
16880
+ },
16881
+ options
16882
+ );
16784
16883
  return await response.json();
16785
16884
  }
16786
16885
  async listSessions() {
@@ -16789,19 +16888,27 @@ var OpensteerCloudClient = class {
16789
16888
  });
16790
16889
  return response.json();
16791
16890
  }
16792
- async getSession(sessionId) {
16793
- const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}`, {
16794
- method: "GET"
16795
- });
16891
+ async getSession(sessionId, options = {}) {
16892
+ const response = await this.request(
16893
+ `/v1/sessions/${encodeURIComponent(sessionId)}`,
16894
+ {
16895
+ method: "GET"
16896
+ },
16897
+ options
16898
+ );
16796
16899
  return await response.json();
16797
16900
  }
16798
- async issueAccess(sessionId, capabilities) {
16799
- const response = await this.request(`/v1/sessions/${encodeURIComponent(sessionId)}/access`, {
16800
- method: "POST",
16801
- body: {
16802
- capabilities
16803
- }
16804
- });
16901
+ async issueAccess(sessionId, capabilities, options = {}) {
16902
+ const response = await this.request(
16903
+ `/v1/sessions/${encodeURIComponent(sessionId)}/access`,
16904
+ {
16905
+ method: "POST",
16906
+ body: {
16907
+ capabilities
16908
+ }
16909
+ },
16910
+ options
16911
+ );
16805
16912
  return await response.json();
16806
16913
  }
16807
16914
  async getSessionRecording(sessionId) {
@@ -16883,28 +16990,17 @@ var OpensteerCloudClient = class {
16883
16990
  async syncBrowserProfileCookies(input) {
16884
16991
  return syncBrowserProfileCookies(this, input);
16885
16992
  }
16886
- async importSelectorCache(entries) {
16887
- const response = await this.request("/selector-cache/import", {
16993
+ async importDescriptors(entries) {
16994
+ const response = await this.request("/registry/descriptors/import", {
16888
16995
  method: "POST",
16889
- body: {
16890
- entries: entries.map((entry) => ({
16891
- workspace: entry.workspace,
16892
- method: entry.method,
16893
- persistHash: entry.persistHash,
16894
- ...entry.persist === void 0 ? {} : { persist: entry.persist },
16895
- path: entry.path,
16896
- ...entry.schemaHash === void 0 ? {} : { schemaHash: entry.schemaHash },
16897
- createdAt: entry.createdAt,
16898
- updatedAt: entry.updatedAt
16899
- }))
16900
- }
16996
+ body: { entries }
16901
16997
  });
16902
16998
  return await response.json();
16903
16999
  }
16904
- async importDescriptors(entries) {
16905
- const response = await this.request("/registry/descriptors/import", {
17000
+ async importRequestPlans(input) {
17001
+ const response = await this.request("/registry/request-plans/import", {
16906
17002
  method: "POST",
16907
- body: { entries }
17003
+ body: input
16908
17004
  });
16909
17005
  return await response.json();
16910
17006
  }
@@ -16917,7 +17013,7 @@ var OpensteerCloudClient = class {
16917
17013
  "content-type": "application/json; charset=utf-8"
16918
17014
  };
16919
17015
  }
16920
- async request(pathname, init) {
17016
+ async request(pathname, init, options = {}) {
16921
17017
  const url = `${this.config.baseUrl}${pathname}`;
16922
17018
  let response;
16923
17019
  try {
@@ -16925,7 +17021,7 @@ var OpensteerCloudClient = class {
16925
17021
  method: init.method,
16926
17022
  headers: this.buildHeaders(),
16927
17023
  ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) },
16928
- signal: AbortSignal.timeout(3e4)
17024
+ signal: createRequestSignal(options)
16929
17025
  });
16930
17026
  } catch (error) {
16931
17027
  throw wrapCloudFetchError(error, {
@@ -16955,6 +17051,13 @@ var OpensteerCloudClient = class {
16955
17051
  throw new Error(`Timed out waiting for cloud session ${sessionId} to close.`);
16956
17052
  }
16957
17053
  };
17054
+ function createRequestSignal(options) {
17055
+ const timeoutSignal = AbortSignal.timeout(options.timeoutMs ?? 3e4);
17056
+ if (options.signal === void 0) {
17057
+ return timeoutSignal;
17058
+ }
17059
+ return AbortSignal.any([options.signal, timeoutSignal]);
17060
+ }
16958
17061
  function delay(ms) {
16959
17062
  return new Promise((resolve4) => {
16960
17063
  setTimeout(resolve4, ms);
@@ -17150,7 +17253,7 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
17150
17253
 
17151
17254
  // ../runtime-core/package.json
17152
17255
  var package_default = {
17153
- version: "0.1.7"};
17256
+ version: "0.2.0"};
17154
17257
 
17155
17258
  // ../runtime-core/src/version.ts
17156
17259
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
@@ -20968,6 +21071,9 @@ var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS = 5e3;
20968
21071
  var PERSISTED_NETWORK_FLUSH_TIMEOUT_MS = 5e3;
20969
21072
  var PENDING_OPERATION_EVENT_CAPTURE_LIMIT = 64;
20970
21073
  var PENDING_OPERATION_EVENT_CAPTURE_SKEW_MS = 1e3;
21074
+ var REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS = 3e3;
21075
+ var REPLAY_PROBE_MAX_ATTEMPT_TIMEOUT_MS = 15e3;
21076
+ var REPLAY_PROBE_POST_SUCCESS_ATTEMPT_TIMEOUT_MS = 5e3;
20971
21077
  var OpensteerSessionRuntime = class {
20972
21078
  workspace;
20973
21079
  rootPath;
@@ -21829,26 +21935,27 @@ var OpensteerSessionRuntime = class {
21829
21935
  }
21830
21936
  }
21831
21937
  async queryNetwork(input = {}, options = {}) {
21832
- assertValidSemanticOperationInput("network.query", input);
21938
+ const normalizedInput = normalizeNetworkQueryInput(input);
21939
+ assertValidSemanticOperationInput("network.query", normalizedInput);
21833
21940
  const root = await this.ensureRoot();
21834
21941
  const startedAt = Date.now();
21835
21942
  try {
21836
21943
  const output = await this.runWithOperationTimeout(
21837
21944
  "network.query",
21838
21945
  async (timeout) => {
21839
- await this.syncPersistedNetworkSelection(timeout, input, {
21946
+ await this.syncPersistedNetworkSelection(timeout, normalizedInput, {
21840
21947
  includeBodies: false
21841
21948
  });
21842
21949
  const rawRecords = await timeout.runStep(
21843
21950
  () => root.registry.savedNetwork.query({
21844
- ...this.toSavedNetworkQueryInput(input),
21845
- limit: Math.max(input.limit ?? 50, 1e3)
21951
+ ...this.toSavedNetworkQueryInput(normalizedInput),
21952
+ limit: Math.max(normalizedInput.limit ?? 50, 1e3)
21846
21953
  })
21847
21954
  );
21848
- const filtered = filterNetworkSummaryRecords(rawRecords, input);
21955
+ const filtered = filterNetworkSummaryRecords(rawRecords, normalizedInput);
21849
21956
  const sorted = sortPersistedNetworkRecordsChronologically(filtered);
21850
- const sliced = sliceNetworkSummaryWindow(sorted, input);
21851
- const limited = sliced.slice(0, Math.max(1, Math.min(input.limit ?? 50, 200)));
21957
+ const sliced = sliceNetworkSummaryWindow(sorted, normalizedInput);
21958
+ const limited = sliced.slice(0, Math.max(1, Math.min(normalizedInput.limit ?? 50, 200)));
21852
21959
  const summaries = await this.buildNetworkSummaryRecords(limited, timeout);
21853
21960
  return {
21854
21961
  records: summaries
@@ -21862,9 +21969,9 @@ var OpensteerSessionRuntime = class {
21862
21969
  completedAt: Date.now(),
21863
21970
  outcome: "ok",
21864
21971
  data: {
21865
- limit: input.limit ?? 50,
21866
- ...input.capture === void 0 ? {} : { capture: input.capture },
21867
- ...input.json === true ? { json: true } : {},
21972
+ limit: normalizedInput.limit ?? 50,
21973
+ ...normalizedInput.capture === void 0 ? {} : { capture: normalizedInput.capture },
21974
+ ...normalizedInput.json === true ? { json: true } : {},
21868
21975
  count: output.records.length
21869
21976
  },
21870
21977
  context: buildRuntimeTraceContext({
@@ -21889,12 +21996,13 @@ var OpensteerSessionRuntime = class {
21889
21996
  }
21890
21997
  }
21891
21998
  async getNetworkDetail(input, options = {}) {
21999
+ const normalizedRecordId = normalizeNetworkRecordId(input.recordId);
21892
22000
  const startedAt = Date.now();
21893
22001
  try {
21894
22002
  const output = await this.runWithOperationTimeout(
21895
22003
  "network.detail",
21896
22004
  async (timeout) => {
21897
- const record = await this.resolveNetworkRecordByRecordId(input.recordId, timeout, {
22005
+ const record = await this.resolveNetworkRecordByRecordId(normalizedRecordId, timeout, {
21898
22006
  includeBodies: true,
21899
22007
  redactSecretHeaders: false
21900
22008
  });
@@ -21913,8 +22021,8 @@ var OpensteerSessionRuntime = class {
21913
22021
  completedAt: Date.now(),
21914
22022
  outcome: "ok",
21915
22023
  data: {
21916
- recordId: input.recordId,
21917
- status: output.summary.status,
22024
+ recordId: normalizedRecordId,
22025
+ ...output.summary.status === void 0 ? {} : { status: output.summary.status },
21918
22026
  url: output.summary.url
21919
22027
  },
21920
22028
  context: buildRuntimeTraceContext({
@@ -23318,7 +23426,9 @@ var OpensteerSessionRuntime = class {
23318
23426
  ...graphql.persisted === void 0 ? {} : { persisted: graphql.persisted },
23319
23427
  ...graphqlVariables === void 0 ? {} : { variables: graphqlVariables }
23320
23428
  };
23321
- const requestBody = shouldShowRequestBody(record.record.method) && record.record.requestBody !== void 0 ? buildStructuredBodyPreview(record.record.requestBody, record.record.requestHeaders) : void 0;
23429
+ const requestBody = shouldShowRequestBody(record.record.method) && record.record.requestBody !== void 0 ? buildStructuredBodyPreview(record.record.requestBody, record.record.requestHeaders, {
23430
+ truncateData: false
23431
+ }) : void 0;
23322
23432
  const responseBody = record.record.responseBody === void 0 ? void 0 : buildStructuredBodyPreview(record.record.responseBody, record.record.responseHeaders);
23323
23433
  const notes = detectNetworkRecordNotes(record);
23324
23434
  return {
@@ -23348,8 +23458,18 @@ var OpensteerSessionRuntime = class {
23348
23458
  let recommended;
23349
23459
  for (const transport of REPLAY_TRANSPORT_LADDER) {
23350
23460
  const attemptStartedAt = Date.now();
23461
+ const attemptTimeoutMs = resolveReplayProbeAttemptTimeoutMs({
23462
+ remainingMs: timeout.remainingMs(),
23463
+ transportsRemaining: REPLAY_TRANSPORT_LADDER.length - attempts.length,
23464
+ recommendedFound: recommended !== void 0
23465
+ });
23351
23466
  try {
23352
- const output = await this.executeReplayTransportAttempt(transport, request, timeout);
23467
+ const output = await this.executeReplayTransportAttemptWithinBudget(
23468
+ transport,
23469
+ request,
23470
+ timeout,
23471
+ attemptTimeoutMs
23472
+ );
23353
23473
  const ok = matchesSuccessFingerprintFromProtocolResponse(output.response, fingerprint);
23354
23474
  attempts.push({
23355
23475
  transport,
@@ -23365,7 +23485,7 @@ var OpensteerSessionRuntime = class {
23365
23485
  transport,
23366
23486
  ok: false,
23367
23487
  durationMs: Date.now() - attemptStartedAt,
23368
- error: normalizeRuntimeErrorMessage(error)
23488
+ error: normalizeProbeTransportAttemptError(transport, error, attemptTimeoutMs)
23369
23489
  });
23370
23490
  }
23371
23491
  }
@@ -23569,6 +23689,23 @@ var OpensteerSessionRuntime = class {
23569
23689
  }
23570
23690
  }
23571
23691
  }
23692
+ async executeReplayTransportAttemptWithinBudget(transport, request, timeout, attemptTimeoutMs) {
23693
+ if (attemptTimeoutMs === void 0) {
23694
+ return this.executeReplayTransportAttempt(transport, request, timeout);
23695
+ }
23696
+ return runWithPolicyTimeout(
23697
+ {
23698
+ resolveTimeoutMs() {
23699
+ return attemptTimeoutMs;
23700
+ }
23701
+ },
23702
+ {
23703
+ operation: timeout.operation,
23704
+ signal: timeout.signal
23705
+ },
23706
+ (attemptTimeout) => this.executeReplayTransportAttempt(transport, request, attemptTimeout)
23707
+ );
23708
+ }
23572
23709
  async executeFetchTransportAttempt(transport, request, timeout, input) {
23573
23710
  let prepared = finalizeMaterializedTransportRequest(request, transport);
23574
23711
  if (input.cookies !== false && transport === "direct-http" && this.currentBinding() !== void 0) {
@@ -24483,10 +24620,15 @@ var OpensteerSessionRuntime = class {
24483
24620
  return this.observationSessionId ?? this.sessionRef;
24484
24621
  }
24485
24622
  runWithOperationTimeout(operation, callback, options = {}) {
24623
+ const timeoutPolicy = options.timeoutMs === void 0 ? this.policy.timeout : {
24624
+ resolveTimeoutMs() {
24625
+ return options.timeoutMs;
24626
+ }
24627
+ };
24486
24628
  const existingCollector = this.operationEventStorage.getStore();
24487
24629
  if (existingCollector !== void 0) {
24488
24630
  return runWithPolicyTimeout(
24489
- this.policy.timeout,
24631
+ timeoutPolicy,
24490
24632
  {
24491
24633
  operation,
24492
24634
  ...options.signal === void 0 ? {} : { signal: options.signal }
@@ -24499,7 +24641,7 @@ var OpensteerSessionRuntime = class {
24499
24641
  return this.operationEventStorage.run(collector, async () => {
24500
24642
  try {
24501
24643
  return await runWithPolicyTimeout(
24502
- this.policy.timeout,
24644
+ timeoutPolicy,
24503
24645
  {
24504
24646
  operation,
24505
24647
  ...options.signal === void 0 ? {} : { signal: options.signal }
@@ -24669,6 +24811,21 @@ function buildEngineNetworkRecordFilters(input) {
24669
24811
  function normalizeNetworkStatusFilter(status) {
24670
24812
  return String(status);
24671
24813
  }
24814
+ function normalizeNetworkQueryInput(input) {
24815
+ return {
24816
+ ...input,
24817
+ ...input.recordId === void 0 ? {} : { recordId: normalizeNetworkRecordId(input.recordId) },
24818
+ ...input.before === void 0 ? {} : { before: normalizeNetworkRecordId(input.before) },
24819
+ ...input.after === void 0 ? {} : { after: normalizeNetworkRecordId(input.after) }
24820
+ };
24821
+ }
24822
+ function normalizeNetworkRecordId(recordId) {
24823
+ const trimmed = recordId.trim();
24824
+ if (trimmed.length === 0 || trimmed.startsWith("record:")) {
24825
+ return trimmed;
24826
+ }
24827
+ return `record:${trimmed}`;
24828
+ }
24672
24829
  function resolveLiveQueryRequestIds(input, history) {
24673
24830
  const requestIdCandidates = [];
24674
24831
  if (input.recordId !== void 0) {
@@ -24881,6 +25038,20 @@ var REPLAY_TRANSPORT_LADDER = [
24881
25038
  "context-http",
24882
25039
  "page-http"
24883
25040
  ];
25041
+ function resolveReplayProbeAttemptTimeoutMs(input) {
25042
+ const attemptCapMs = input.recommendedFound ? REPLAY_PROBE_POST_SUCCESS_ATTEMPT_TIMEOUT_MS : REPLAY_PROBE_MAX_ATTEMPT_TIMEOUT_MS;
25043
+ const clampedRemaining = input.remainingMs === void 0 ? void 0 : Math.max(0, input.remainingMs);
25044
+ if (clampedRemaining === 0) {
25045
+ return 0;
25046
+ }
25047
+ if (clampedRemaining === void 0) {
25048
+ return attemptCapMs;
25049
+ }
25050
+ const sliceMs = Math.floor(clampedRemaining / Math.max(1, input.transportsRemaining));
25051
+ const minimumBudgetAffordable = clampedRemaining >= REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS * input.transportsRemaining;
25052
+ const attemptBudgetMs = minimumBudgetAffordable ? Math.max(REPLAY_PROBE_MIN_ATTEMPT_TIMEOUT_MS, sliceMs) : sliceMs;
25053
+ return Math.min(clampedRemaining, attemptCapMs, Math.max(1, attemptBudgetMs));
25054
+ }
24884
25055
  function filterNetworkSummaryRecords(records, input) {
24885
25056
  return records.filter((record) => {
24886
25057
  if (record.record.resourceType === "preflight" || record.record.method === "OPTIONS") {
@@ -25053,10 +25224,10 @@ function extractGraphqlOperationName(queryText) {
25053
25224
  function shouldShowRequestBody(method) {
25054
25225
  return !["GET", "HEAD", "DELETE", "OPTIONS"].includes(method.trim().toUpperCase());
25055
25226
  }
25056
- function buildStructuredBodyPreview(body, headers) {
25227
+ function buildStructuredBodyPreview(body, headers, options = {}) {
25057
25228
  const contentType = headerValue(headers, "content-type") ?? body?.mimeType;
25058
25229
  const parsed = parseStructuredPayload(body, contentType);
25059
- const data = parsed === void 0 ? void 0 : typeof parsed === "string" ? truncateInlineText(parsed) : truncateStructuredValue(parsed);
25230
+ const data = parsed === void 0 ? void 0 : options.truncateData === false ? parsed : typeof parsed === "string" ? truncateInlineText(parsed) : truncateStructuredValue(parsed);
25060
25231
  return {
25061
25232
  bytes: body?.originalByteLength ?? body?.capturedByteLength ?? 0,
25062
25233
  ...contentType === void 0 ? {} : { contentType },
@@ -25269,10 +25440,12 @@ function resolveSessionFetchTransportLadder(transport) {
25269
25440
  return ["direct-http"];
25270
25441
  case "matched-tls":
25271
25442
  return ["matched-tls"];
25443
+ case "context":
25444
+ return ["context-http"];
25272
25445
  case "page":
25273
25446
  return ["page-http"];
25274
25447
  case "auto":
25275
- return ["direct-http", "matched-tls", "page-http"];
25448
+ return ["direct-http", "matched-tls", "context-http", "page-http"];
25276
25449
  }
25277
25450
  }
25278
25451
  function detectChallengeNoteFromRecord(record) {
@@ -25417,6 +25590,12 @@ function diffStorageSnapshot(left, right) {
25417
25590
  function normalizeRuntimeErrorMessage(error) {
25418
25591
  return error instanceof Error ? error.message : String(error);
25419
25592
  }
25593
+ function normalizeProbeTransportAttemptError(transport, error, attemptTimeoutMs) {
25594
+ if (attemptTimeoutMs !== void 0 && error instanceof OpensteerProtocolError && error.code === "timeout") {
25595
+ return `${transport} probe exceeded ${String(attemptTimeoutMs)}ms`;
25596
+ }
25597
+ return normalizeRuntimeErrorMessage(error);
25598
+ }
25420
25599
  function applyBrowserCookiesToTransportRequest(request, cookies) {
25421
25600
  if (cookies.length === 0) {
25422
25601
  return request;
@@ -27812,10 +27991,10 @@ var OpensteerSemanticRestClient = class {
27812
27991
  constructor(connection) {
27813
27992
  this.connection = connection;
27814
27993
  }
27815
- async invoke(operation, input) {
27816
- return this.invokeInternal(operation, input, false);
27994
+ async invoke(operation, input, options = {}) {
27995
+ return this.invokeInternal(operation, input, false, options);
27817
27996
  }
27818
- async invokeInternal(operation, input, hasRetried) {
27997
+ async invokeInternal(operation, input, hasRetried, options) {
27819
27998
  const endpoint = opensteerSemanticRestEndpoints.find((entry) => entry.name === operation);
27820
27999
  if (!endpoint) {
27821
28000
  throw new Error(`unsupported semantic operation ${operation}`);
@@ -27829,10 +28008,11 @@ var OpensteerSemanticRestClient = class {
27829
28008
  method: "POST",
27830
28009
  headers: {
27831
28010
  authorization: await this.connection.getAuthorizationHeader(),
27832
- "content-type": "application/json; charset=utf-8"
28011
+ "content-type": "application/json; charset=utf-8",
28012
+ ...options.timeoutMs === void 0 ? {} : { "x-opensteer-timeout-ms": String(options.timeoutMs) }
27833
28013
  },
27834
28014
  body: JSON.stringify(request),
27835
- signal: AbortSignal.timeout(3e4)
28015
+ signal: createRequestSignal2(options)
27836
28016
  });
27837
28017
  } catch (error) {
27838
28018
  if (operation === "session.close" && isFetchFailure(error)) {
@@ -27848,7 +28028,7 @@ var OpensteerSemanticRestClient = class {
27848
28028
  return envelope.data;
27849
28029
  } catch (error) {
27850
28030
  if (!hasRetried && this.connection.handleError && await this.connection.handleError(error, { operation })) {
27851
- return this.invokeInternal(operation, input, true);
28031
+ return this.invokeInternal(operation, input, true, options);
27852
28032
  }
27853
28033
  if (operation === "session.close" && isFetchFailure(error)) {
27854
28034
  return { closed: true };
@@ -27860,6 +28040,13 @@ var OpensteerSemanticRestClient = class {
27860
28040
  return this.invoke("session.close", {});
27861
28041
  }
27862
28042
  };
28043
+ function createRequestSignal2(options) {
28044
+ const timeoutSignal = AbortSignal.timeout(options.timeoutMs ?? 3e4);
28045
+ if (options.signal === void 0) {
28046
+ return timeoutSignal;
28047
+ }
28048
+ return AbortSignal.any([options.signal, timeoutSignal]);
28049
+ }
27863
28050
  function isFetchFailure(error) {
27864
28051
  if (!(error instanceof Error)) {
27865
28052
  return false;
@@ -28226,13 +28413,44 @@ function asRecord(value) {
28226
28413
  return value;
28227
28414
  }
28228
28415
 
28229
- // src/cloud/registry-sync.ts
28230
- var REGISTRY_SYNC_MAX_PAYLOAD_BYTES = 15e5;
28231
- var REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH = 100;
28232
- async function syncLocalRegistryToCloud(client, workspace, store) {
28416
+ // src/cloud/workspace-sync.ts
28417
+ var WORKSPACE_SYNC_MAX_PAYLOAD_BYTES = 15e5;
28418
+ var WORKSPACE_SYNC_MAX_ENTRIES_PER_BATCH = 100;
28419
+ async function syncLocalWorkspaceToCloud(client, workspace, store) {
28420
+ await syncDescriptorRegistryToCloud(client, workspace, store);
28421
+ await syncRequestPlansToCloud(client, workspace, store);
28422
+ }
28423
+ async function syncDescriptorRegistryToCloud(client, workspace, store) {
28233
28424
  const descriptors = await store.registry.descriptors.list();
28234
- const descriptorEntries = descriptors.map((record) => toDescriptorImportEntry(workspace, record));
28235
- await importInBatches(descriptorEntries, (entries) => client.importDescriptors(entries));
28425
+ const entries = descriptors.map((record) => toDescriptorImportEntry(workspace, record));
28426
+ await importInBatches(entries, {
28427
+ getPayloadByteLength: (batch) => payloadByteLength({ entries: batch }),
28428
+ importBatch: (batch) => client.importDescriptors(batch)
28429
+ });
28430
+ }
28431
+ async function syncRequestPlansToCloud(client, workspace, store) {
28432
+ const requestPlans = await store.registry.requestPlans.list();
28433
+ const entries = requestPlans.map((record) => toRequestPlanImportEntry(workspace, record)).filter((entry) => entry !== void 0);
28434
+ await importInBatches(entries, {
28435
+ getPayloadByteLength: (batch) => payloadByteLength({ entries: batch }),
28436
+ importBatch: (batch) => client.importRequestPlans({ entries: batch })
28437
+ });
28438
+ }
28439
+ function toRequestPlanImportEntry(workspace, record) {
28440
+ const entry = {
28441
+ workspace,
28442
+ recordId: record.id,
28443
+ key: record.key,
28444
+ version: record.version,
28445
+ contentHash: record.contentHash,
28446
+ tags: [...record.tags],
28447
+ ...record.provenance === void 0 ? {} : { provenance: record.provenance },
28448
+ ...record.freshness === void 0 ? {} : { freshness: record.freshness },
28449
+ payload: record.payload,
28450
+ createdAt: record.createdAt,
28451
+ updatedAt: record.updatedAt
28452
+ };
28453
+ return payloadByteLength({ entries: [entry] }) <= WORKSPACE_SYNC_MAX_PAYLOAD_BYTES ? entry : void 0;
28236
28454
  }
28237
28455
  function toDescriptorImportEntry(workspace, record) {
28238
28456
  return {
@@ -28248,19 +28466,19 @@ function toDescriptorImportEntry(workspace, record) {
28248
28466
  updatedAt: record.updatedAt
28249
28467
  };
28250
28468
  }
28251
- async function importInBatches(entries, importBatch) {
28469
+ async function importInBatches(entries, options) {
28252
28470
  if (entries.length === 0) {
28253
28471
  return;
28254
28472
  }
28255
- for (const batch of chunkEntries(entries)) {
28256
- await importBatch(batch);
28473
+ for (const batch of chunkEntries(entries, options.getPayloadByteLength)) {
28474
+ await options.importBatch(batch);
28257
28475
  }
28258
28476
  }
28259
- function chunkEntries(entries) {
28477
+ function chunkEntries(entries, getPayloadByteLength) {
28260
28478
  const batches = [];
28261
28479
  let currentBatch = [];
28262
28480
  for (const entry of entries) {
28263
- if (payloadByteLength([entry]) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
28481
+ if (getPayloadByteLength([entry]) > WORKSPACE_SYNC_MAX_PAYLOAD_BYTES) {
28264
28482
  continue;
28265
28483
  }
28266
28484
  if (currentBatch.length === 0) {
@@ -28268,7 +28486,7 @@ function chunkEntries(entries) {
28268
28486
  continue;
28269
28487
  }
28270
28488
  const nextBatch = [...currentBatch, entry];
28271
- if (nextBatch.length > REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH || payloadByteLength(nextBatch) > REGISTRY_SYNC_MAX_PAYLOAD_BYTES) {
28489
+ if (nextBatch.length > WORKSPACE_SYNC_MAX_ENTRIES_PER_BATCH || getPayloadByteLength(nextBatch) > WORKSPACE_SYNC_MAX_PAYLOAD_BYTES) {
28272
28490
  batches.push(currentBatch);
28273
28491
  currentBatch = [entry];
28274
28492
  continue;
@@ -28280,8 +28498,8 @@ function chunkEntries(entries) {
28280
28498
  }
28281
28499
  return batches;
28282
28500
  }
28283
- function payloadByteLength(entries) {
28284
- return Buffer.byteLength(JSON.stringify({ entries }), "utf8");
28501
+ function payloadByteLength(value) {
28502
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
28285
28503
  }
28286
28504
 
28287
28505
  // src/cloud/session-proxy.ts
@@ -28292,14 +28510,17 @@ var CloudSessionProxy = class {
28292
28510
  cleanupRootOnClose;
28293
28511
  cloud;
28294
28512
  observability;
28513
+ policy;
28295
28514
  sessionId;
28296
28515
  semanticGrant;
28297
28516
  client;
28298
28517
  automation;
28299
28518
  workspaceStore;
28519
+ syncWorkspaceOnClose = false;
28300
28520
  constructor(cloud, options = {}) {
28301
28521
  this.cloud = cloud;
28302
28522
  this.workspace = options.workspace;
28523
+ this.policy = options.policy ?? defaultPolicy();
28303
28524
  this.observability = options.observability;
28304
28525
  this.rootPath = options.rootPath ?? (this.workspace === void 0 ? path7.join(tmpdir(), `${TEMPORARY_CLOUD_WORKSPACE_PREFIX}${randomUUID()}`) : resolveFilesystemWorkspacePath({
28305
28526
  rootDir: path7.resolve(options.rootDir ?? process.cwd()),
@@ -28308,14 +28529,17 @@ var CloudSessionProxy = class {
28308
28529
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? this.workspace === void 0;
28309
28530
  }
28310
28531
  async open(input = {}) {
28311
- await this.ensureSession({
28312
- ...input.browser === void 0 ? {} : { browser: input.browser },
28313
- ...input.launch === void 0 ? {} : { launch: input.launch },
28314
- ...input.context === void 0 ? {} : { context: input.context }
28315
- });
28316
- return this.requireClient().invoke("session.open", {
28317
- ...input.url === void 0 ? {} : { url: input.url }
28318
- });
28532
+ return this.invokeSemanticOperation(
28533
+ "session.open",
28534
+ {
28535
+ ...input.url === void 0 ? {} : { url: input.url }
28536
+ },
28537
+ {
28538
+ ...input.browser === void 0 ? {} : { browser: input.browser },
28539
+ ...input.launch === void 0 ? {} : { launch: input.launch },
28540
+ ...input.context === void 0 ? {} : { context: input.context }
28541
+ }
28542
+ );
28319
28543
  }
28320
28544
  async info() {
28321
28545
  const persisted = this.client !== void 0 || this.sessionId !== void 0 ? void 0 : await this.loadPersistedSession();
@@ -28358,108 +28582,88 @@ var CloudSessionProxy = class {
28358
28582
  };
28359
28583
  }
28360
28584
  async listPages(input = {}) {
28361
- await this.ensureSession();
28362
- return this.requireClient().invoke("page.list", input);
28585
+ return this.invokeSemanticOperation("page.list", input);
28363
28586
  }
28364
28587
  async newPage(input = {}) {
28365
- await this.ensureSession();
28366
- return this.requireAutomation().invoke("page.new", input);
28588
+ return this.invokeAutomationOperation(
28589
+ "page.new",
28590
+ (automation) => automation.invoke("page.new", input)
28591
+ );
28367
28592
  }
28368
28593
  async activatePage(input) {
28369
- await this.ensureSession();
28370
- return this.requireClient().invoke("page.activate", input);
28594
+ return this.invokeSemanticOperation("page.activate", input);
28371
28595
  }
28372
28596
  async closePage(input = {}) {
28373
- await this.ensureSession();
28374
- return this.requireClient().invoke("page.close", input);
28597
+ return this.invokeSemanticOperation("page.close", input);
28375
28598
  }
28376
28599
  async goto(input) {
28377
- await this.ensureSession();
28378
- return this.requireClient().invoke("page.goto", input);
28600
+ return this.invokeSemanticOperation("page.goto", input);
28379
28601
  }
28380
28602
  async evaluate(input) {
28381
- await this.ensureSession();
28382
- return this.requireAutomation().invoke("page.evaluate", input);
28603
+ return this.invokeAutomationOperation(
28604
+ "page.evaluate",
28605
+ (automation) => automation.invoke("page.evaluate", input)
28606
+ );
28383
28607
  }
28384
28608
  async addInitScript(input) {
28385
- await this.ensureSession();
28386
- return this.requireClient().invoke("page.add-init-script", input);
28609
+ return this.invokeSemanticOperation("page.add-init-script", input);
28387
28610
  }
28388
28611
  async snapshot(input = {}) {
28389
- await this.ensureSession();
28390
- return this.requireClient().invoke("page.snapshot", input);
28612
+ return this.invokeSemanticOperation("page.snapshot", input);
28391
28613
  }
28392
28614
  async click(input) {
28393
- await this.ensureSession();
28394
- return this.requireClient().invoke("dom.click", input);
28615
+ return this.invokeSemanticOperation("dom.click", input);
28395
28616
  }
28396
28617
  async hover(input) {
28397
- await this.ensureSession();
28398
- return this.requireClient().invoke("dom.hover", input);
28618
+ return this.invokeSemanticOperation("dom.hover", input);
28399
28619
  }
28400
28620
  async input(input) {
28401
- await this.ensureSession();
28402
- return this.requireClient().invoke("dom.input", input);
28621
+ return this.invokeSemanticOperation("dom.input", input);
28403
28622
  }
28404
28623
  async scroll(input) {
28405
- await this.ensureSession();
28406
- return this.requireClient().invoke("dom.scroll", input);
28624
+ return this.invokeSemanticOperation("dom.scroll", input);
28407
28625
  }
28408
28626
  async extract(input) {
28409
- await this.ensureSession();
28410
- return this.requireClient().invoke("dom.extract", input);
28627
+ return this.invokeSemanticOperation("dom.extract", input);
28411
28628
  }
28412
28629
  async queryNetwork(input = {}) {
28413
- await this.ensureSession();
28414
- return this.requireClient().invoke("network.query", input);
28630
+ return this.invokeSemanticOperation("network.query", input);
28415
28631
  }
28416
28632
  async getNetworkDetail(input) {
28417
- await this.ensureSession();
28418
- return this.requireClient().invoke("network.detail", input);
28633
+ return this.invokeSemanticOperation("network.detail", input);
28419
28634
  }
28420
28635
  async captureInteraction(input) {
28421
- await this.ensureSession();
28422
- return this.requireClient().invoke("interaction.capture", input);
28636
+ return this.invokeSemanticOperation("interaction.capture", input);
28423
28637
  }
28424
28638
  async getInteraction(input) {
28425
- await this.ensureSession();
28426
- return this.requireClient().invoke("interaction.get", input);
28639
+ return this.invokeSemanticOperation("interaction.get", input);
28427
28640
  }
28428
28641
  async diffInteraction(input) {
28429
- await this.ensureSession();
28430
- return this.requireClient().invoke("interaction.diff", input);
28642
+ return this.invokeSemanticOperation("interaction.diff", input);
28431
28643
  }
28432
28644
  async replayInteraction(input) {
28433
- await this.ensureSession();
28434
- return this.requireClient().invoke("interaction.replay", input);
28645
+ return this.invokeSemanticOperation("interaction.replay", input);
28435
28646
  }
28436
28647
  async captureScripts(input = {}) {
28437
- await this.ensureSession();
28438
- return this.requireClient().invoke("scripts.capture", input);
28648
+ return this.invokeSemanticOperation("scripts.capture", input);
28439
28649
  }
28440
28650
  async readArtifact(input) {
28441
- await this.ensureSession();
28442
- return this.requireClient().invoke("artifact.read", input);
28651
+ return this.invokeSemanticOperation("artifact.read", input);
28443
28652
  }
28444
28653
  async beautifyScript(input) {
28445
- await this.ensureSession();
28446
- return this.requireClient().invoke("scripts.beautify", input);
28654
+ return this.invokeSemanticOperation("scripts.beautify", input);
28447
28655
  }
28448
28656
  async deobfuscateScript(input) {
28449
- await this.ensureSession();
28450
- return this.requireClient().invoke("scripts.deobfuscate", input);
28657
+ return this.invokeSemanticOperation("scripts.deobfuscate", input);
28451
28658
  }
28452
28659
  async sandboxScript(input) {
28453
- await this.ensureSession();
28454
- return this.requireClient().invoke("scripts.sandbox", input);
28660
+ return this.invokeSemanticOperation("scripts.sandbox", input);
28455
28661
  }
28456
28662
  async solveCaptcha(input) {
28457
- await this.ensureSession();
28458
- return this.requireClient().invoke("captcha.solve", input);
28663
+ return this.invokeSemanticOperation("captcha.solve", input);
28459
28664
  }
28460
28665
  async getCookies(input = {}) {
28461
- await this.ensureSession();
28462
- return this.requireClient().invoke("session.cookies", input);
28666
+ return this.invokeSemanticOperation("session.cookies", input);
28463
28667
  }
28464
28668
  async route(input) {
28465
28669
  await this.ensureSession();
@@ -28470,20 +28674,16 @@ var CloudSessionProxy = class {
28470
28674
  return this.requireAutomation().interceptScript(input);
28471
28675
  }
28472
28676
  async getStorageSnapshot(input = {}) {
28473
- await this.ensureSession();
28474
- return this.requireClient().invoke("session.storage", input);
28677
+ return this.invokeSemanticOperation("session.storage", input);
28475
28678
  }
28476
28679
  async getBrowserState(input = {}) {
28477
- await this.ensureSession();
28478
- return this.requireClient().invoke("session.state", input);
28680
+ return this.invokeSemanticOperation("session.state", input);
28479
28681
  }
28480
28682
  async fetch(input) {
28481
- await this.ensureSession();
28482
- return this.requireClient().invoke("session.fetch", input);
28683
+ return this.invokeSemanticOperation("session.fetch", input);
28483
28684
  }
28484
28685
  async computerExecute(input) {
28485
- await this.ensureSession();
28486
- return this.requireClient().invoke("computer.execute", input);
28686
+ return this.invokeSemanticOperation("computer.execute", input);
28487
28687
  }
28488
28688
  async close() {
28489
28689
  const session = await this.loadPersistedSession() ?? (this.sessionId === void 0 ? void 0 : {
@@ -28495,6 +28695,14 @@ var CloudSessionProxy = class {
28495
28695
  startedAt: Date.now(),
28496
28696
  updatedAt: Date.now()
28497
28697
  });
28698
+ let syncError;
28699
+ if (this.syncWorkspaceOnClose) {
28700
+ try {
28701
+ await this.syncWorkspaceToCloud();
28702
+ } catch (error) {
28703
+ syncError = error;
28704
+ }
28705
+ }
28498
28706
  try {
28499
28707
  if (session !== void 0) {
28500
28708
  await this.cloud.closeSession(session.sessionId).catch((error) => {
@@ -28515,6 +28723,9 @@ var CloudSessionProxy = class {
28515
28723
  await rm(this.rootPath, { recursive: true, force: true }).catch(() => void 0);
28516
28724
  }
28517
28725
  }
28726
+ if (syncError !== void 0) {
28727
+ throw syncError;
28728
+ }
28518
28729
  return { closed: true };
28519
28730
  }
28520
28731
  async disconnect() {
@@ -28522,34 +28733,38 @@ var CloudSessionProxy = class {
28522
28733
  await this.close();
28523
28734
  return;
28524
28735
  }
28736
+ let syncError;
28737
+ if (this.syncWorkspaceOnClose) {
28738
+ try {
28739
+ await this.syncWorkspaceToCloud();
28740
+ } catch (error) {
28741
+ syncError = error;
28742
+ }
28743
+ }
28525
28744
  this.client = void 0;
28526
28745
  await this.automation?.close().catch(() => void 0);
28527
28746
  this.automation = void 0;
28528
28747
  this.sessionId = void 0;
28529
28748
  this.semanticGrant = void 0;
28749
+ if (syncError !== void 0) {
28750
+ throw syncError;
28751
+ }
28530
28752
  }
28531
- async ensureSession(input = {}) {
28753
+ async ensureSession(input = {}, timeout) {
28532
28754
  if (this.client) {
28533
28755
  return;
28534
28756
  }
28535
28757
  assertSupportedCloudBrowserMode(input.browser);
28536
28758
  const localCloud = this.shouldUseLocalCloudTransport();
28759
+ this.syncWorkspaceOnClose = localCloud && this.workspace !== void 0;
28537
28760
  const browserProfile = resolveCloudBrowserProfile(this.cloud, input);
28538
28761
  const persisted = await this.loadPersistedSession();
28539
- if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId)) {
28540
- if (localCloud) {
28541
- void this.syncRegistryToCloud();
28542
- } else {
28543
- await this.syncRegistryToCloud();
28544
- }
28762
+ if (persisted !== void 0 && await this.isReusableCloudSession(persisted.sessionId, timeout)) {
28763
+ await this.syncWorkspaceToCloud();
28545
28764
  this.bindClient(persisted);
28546
28765
  return;
28547
28766
  }
28548
- if (localCloud) {
28549
- void this.syncRegistryToCloud();
28550
- } else {
28551
- await this.syncRegistryToCloud();
28552
- }
28767
+ await this.syncWorkspaceToCloud();
28553
28768
  const baseCreateInput = {
28554
28769
  ...this.workspace === void 0 ? {} : { name: this.workspace },
28555
28770
  ...input.launch === void 0 ? {} : { browser: input.launch },
@@ -28561,10 +28776,12 @@ var CloudSessionProxy = class {
28561
28776
  ...baseCreateInput,
28562
28777
  sourceType: "local-cloud",
28563
28778
  sourceRef: this.workspace,
28564
- localWorkspaceRootPath: this.rootPath,
28565
- locality: "auto"
28779
+ localWorkspaceRootPath: this.rootPath
28566
28780
  } : baseCreateInput;
28567
- const session = await this.cloud.createSession(createInput);
28781
+ const session = await this.cloud.createSession(createInput, {
28782
+ signal: timeout?.signal,
28783
+ timeoutMs: timeout?.remainingMs()
28784
+ });
28568
28785
  const record = {
28569
28786
  layout: "opensteer-session",
28570
28787
  version: 1,
@@ -28577,15 +28794,12 @@ var CloudSessionProxy = class {
28577
28794
  await this.writePersistedSession(record);
28578
28795
  this.bindClient(record, session.initialGrants?.semantic);
28579
28796
  }
28580
- async syncRegistryToCloud() {
28797
+ async syncWorkspaceToCloud() {
28581
28798
  if (this.workspace === void 0) {
28582
28799
  return;
28583
28800
  }
28584
- try {
28585
- const workspaceStore = await this.ensureWorkspaceStore();
28586
- await syncLocalRegistryToCloud(this.cloud, this.workspace, workspaceStore);
28587
- } catch {
28588
- }
28801
+ const workspaceStore = await this.ensureWorkspaceStore();
28802
+ await syncLocalWorkspaceToCloud(this.cloud, this.workspace, workspaceStore);
28589
28803
  }
28590
28804
  bindClient(record, initialSemanticGrant) {
28591
28805
  this.sessionId = record.sessionId;
@@ -28619,9 +28833,12 @@ var CloudSessionProxy = class {
28619
28833
  async clearPersistedSession() {
28620
28834
  await clearPersistedSessionRecord(this.rootPath, "cloud").catch(() => void 0);
28621
28835
  }
28622
- async isReusableCloudSession(sessionId) {
28836
+ async isReusableCloudSession(sessionId, timeout) {
28623
28837
  try {
28624
- const session = await this.cloud.getSession(sessionId);
28838
+ const session = await this.cloud.getSession(sessionId, {
28839
+ signal: timeout?.signal,
28840
+ timeoutMs: timeout?.remainingMs()
28841
+ });
28625
28842
  return session.status !== "closed" && session.status !== "failed";
28626
28843
  } catch (error) {
28627
28844
  if (isMissingCloudSessionError(error)) {
@@ -28642,14 +28859,17 @@ var CloudSessionProxy = class {
28642
28859
  }
28643
28860
  return this.automation;
28644
28861
  }
28645
- async ensureSemanticGrant(forceRefresh = false) {
28862
+ async ensureSemanticGrant(forceRefresh = false, timeout) {
28646
28863
  if (!forceRefresh && this.semanticGrant?.kind === "semantic" && this.semanticGrant.expiresAt > Date.now() + 1e4) {
28647
28864
  return this.semanticGrant;
28648
28865
  }
28649
28866
  if (!this.sessionId) {
28650
28867
  throw new Error("Cloud session has not been initialized.");
28651
28868
  }
28652
- const issued = await this.cloud.issueAccess(this.sessionId, ["semantic"]);
28869
+ const issued = await this.cloud.issueAccess(this.sessionId, ["semantic"], {
28870
+ signal: timeout?.signal,
28871
+ timeoutMs: timeout?.remainingMs()
28872
+ });
28653
28873
  const grant = issued.grants.semantic;
28654
28874
  if (!grant || grant.transport !== "http") {
28655
28875
  throw new Error("cloud did not issue a valid semantic grant");
@@ -28672,6 +28892,25 @@ var CloudSessionProxy = class {
28672
28892
  return false;
28673
28893
  }
28674
28894
  }
28895
+ async invokeSemanticOperation(operation, input, sessionInit = {}) {
28896
+ return this.runOperationWithPolicy(operation, async (timeout) => {
28897
+ await this.ensureSession(sessionInit, timeout);
28898
+ await this.ensureSemanticGrant(false, timeout);
28899
+ return this.requireClient().invoke(operation, input, {
28900
+ signal: timeout.signal,
28901
+ timeoutMs: timeout.remainingMs()
28902
+ });
28903
+ });
28904
+ }
28905
+ async invokeAutomationOperation(operation, invoke, sessionInit = {}) {
28906
+ return this.runOperationWithPolicy(operation, async (timeout) => {
28907
+ await this.ensureSession(sessionInit, timeout);
28908
+ return invoke(this.requireAutomation());
28909
+ });
28910
+ }
28911
+ async runOperationWithPolicy(operation, invoke) {
28912
+ return runWithPolicyTimeout(this.policy.timeout, { operation }, invoke);
28913
+ }
28675
28914
  shouldUseLocalCloudTransport() {
28676
28915
  if (this.workspace === void 0) {
28677
28916
  return false;
@@ -28846,6 +29085,7 @@ function createOpensteerSemanticRuntime(input = {}) {
28846
29085
  ...runtimeOptions.rootDir === void 0 ? {} : { rootDir: runtimeOptions.rootDir },
28847
29086
  ...runtimeOptions.rootPath === void 0 ? {} : { rootPath: runtimeOptions.rootPath },
28848
29087
  ...runtimeOptions.workspace === void 0 ? {} : { workspace: runtimeOptions.workspace },
29088
+ ...runtimeOptions.policy === void 0 ? {} : { policy: runtimeOptions.policy },
28849
29089
  ...runtimeOptions.cleanupRootOnClose === void 0 ? {} : { cleanupRootOnClose: runtimeOptions.cleanupRootOnClose },
28850
29090
  ...runtimeOptions.observability === void 0 ? {} : { observability: runtimeOptions.observability }
28851
29091
  });
@@ -28857,5 +29097,5 @@ function createOpensteerSemanticRuntime(input = {}) {
28857
29097
  }
28858
29098
 
28859
29099
  export { CloudSessionProxy, DEFAULT_OPENSTEER_ENGINE, DEFERRED_MATCH_ATTR_KEYS, ElementPathError, FlowRecorderCollector, MATCH_ATTRIBUTE_PRIORITY, OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL, OPENSTEER_ENGINE_NAMES, OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OpensteerAttachAmbiguousError, OpensteerBrowserManager, OpensteerCloudClient, OpensteerRuntime, OpensteerSessionRuntime2 as OpensteerSessionRuntime, STABLE_PRIMARY_ATTR_KEYS, assertProviderSupportsEngine, buildArrayFieldPathCandidates, buildDomDescriptorKey, buildDomDescriptorPayload, buildDomDescriptorVersion, buildPathCandidates, buildPathSelectorHint, buildSegmentSelector, clearPersistedSessionRecord, cloneElementPath, cloneReplayElementPath, cloneStructuralElementAnchor, createArtifactStore, createDomDescriptorStore, createDomRuntime, createFilesystemOpensteerWorkspace, createObservationStore, createOpensteerExtractionDescriptorStore, createOpensteerSemanticRuntime, defaultFallbackPolicy, defaultPolicy, defaultRetryPolicy, defaultSettlePolicy, defaultTimeoutPolicy, delayWithSignal, discoverLocalCdpBrowsers, dispatchSemanticOperation, generateReplayScript, hashDomDescriptorPersist, inspectCdpEndpoint, isCurrentUrlField, isProcessRunning, isValidCssAttributeKey, listLocalChromeProfiles, loadEnvironment, manifestToExternalBinaryLocation, normalizeExtractedValue, normalizeObservabilityConfig, normalizeOpensteerEngineName, normalizeOpensteerProviderMode, normalizeWorkspaceId, parseDomDescriptorRecord, parseExtractionDescriptorRecord, pathExists, readPersistedCloudSessionRecord, readPersistedLocalBrowserSessionRecord, readPersistedSessionRecord, requireCloudAppBaseUrl, resolveCloudConfig, resolveCloudSessionRecordPath, resolveDomActionBridge, resolveExtractedValueInContext, resolveFilesystemWorkspacePath, resolveLiveSessionRecordPath, resolveLocalSessionRecordPath, resolveOpensteerEngineName, resolveOpensteerEnvironment, resolveOpensteerProvider, resolveOpensteerRuntimeConfig, runWithPolicyTimeout, sanitizeElementPath, sanitizeReplayElementPath, sanitizeStructuralElementAnchor, settleWithPolicy, shouldKeepAttributeForPath, writePersistedSessionRecord };
28860
- //# sourceMappingURL=chunk-GQ3PGLYQ.js.map
28861
- //# sourceMappingURL=chunk-GQ3PGLYQ.js.map
29100
+ //# sourceMappingURL=chunk-656MQUSM.js.map
29101
+ //# sourceMappingURL=chunk-656MQUSM.js.map