@opensteer/runtime-core 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -42,7 +42,7 @@ var vm__default = /*#__PURE__*/_interopDefault(vm);
42
42
 
43
43
  // package.json
44
44
  var package_default = {
45
- version: "0.1.1"};
45
+ version: "0.1.2"};
46
46
 
47
47
  // src/version.ts
48
48
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
@@ -999,14 +999,10 @@ var networkRecordSchema = objectSchema(
999
999
  ]
1000
1000
  }
1001
1001
  );
1002
- var networkQuerySourceSchema = enumSchema(["live", "saved"], {
1003
- title: "NetworkQuerySource"
1004
- });
1005
1002
  var networkQueryRecordSchema = objectSchema(
1006
1003
  {
1007
1004
  recordId: stringSchema({ minLength: 1 }),
1008
- source: networkQuerySourceSchema,
1009
- actionId: stringSchema({ minLength: 1 }),
1005
+ capture: stringSchema({ minLength: 1 }),
1010
1006
  tags: arraySchema(stringSchema({ minLength: 1 }), {
1011
1007
  uniqueItems: true
1012
1008
  }),
@@ -1015,7 +1011,7 @@ var networkQueryRecordSchema = objectSchema(
1015
1011
  },
1016
1012
  {
1017
1013
  title: "NetworkQueryRecord",
1018
- required: ["recordId", "source", "record"]
1014
+ required: ["recordId", "record"]
1019
1015
  }
1020
1016
  );
1021
1017
  arraySchema(headerEntrySchema, {
@@ -1486,8 +1482,7 @@ var opensteerRecipeStepSchema = oneOfSchema(
1486
1482
  objectSchema(
1487
1483
  {
1488
1484
  kind: enumSchema(["goto"]),
1489
- url: stringSchema({ minLength: 1 }),
1490
- networkTag: stringSchema({ minLength: 1 })
1485
+ url: stringSchema({ minLength: 1 })
1491
1486
  },
1492
1487
  {
1493
1488
  title: "OpensteerAuthRecipeGotoStep",
@@ -1496,8 +1491,7 @@ var opensteerRecipeStepSchema = oneOfSchema(
1496
1491
  ),
1497
1492
  objectSchema(
1498
1493
  {
1499
- kind: enumSchema(["reload"]),
1500
- networkTag: stringSchema({ minLength: 1 })
1494
+ kind: enumSchema(["reload"])
1501
1495
  },
1502
1496
  {
1503
1497
  title: "OpensteerAuthRecipeReloadStep",
@@ -1711,13 +1705,10 @@ var opensteerRecipeRecordSchema = objectSchema(
1711
1705
  var opensteerAuthRecipeRecordSchema = opensteerRecipeRecordSchema;
1712
1706
  var opensteerNetworkQueryInputSchema = objectSchema(
1713
1707
  {
1714
- source: enumSchema(["live", "saved"], {
1715
- title: "OpensteerNetworkQuerySource"
1716
- }),
1717
1708
  pageRef: pageRefSchema,
1718
1709
  recordId: stringSchema({ minLength: 1 }),
1719
1710
  requestId: stringSchema({ minLength: 1 }),
1720
- actionId: stringSchema({ minLength: 1 }),
1711
+ capture: stringSchema({ minLength: 1 }),
1721
1712
  tag: stringSchema({ minLength: 1 }),
1722
1713
  url: stringSchema({ minLength: 1 }),
1723
1714
  hostname: stringSchema({ minLength: 1 }),
@@ -1741,12 +1732,12 @@ var opensteerNetworkQueryOutputSchema = objectSchema(
1741
1732
  required: ["records"]
1742
1733
  }
1743
1734
  );
1744
- var opensteerNetworkSaveInputSchema = objectSchema(
1735
+ var opensteerNetworkTagInputSchema = objectSchema(
1745
1736
  {
1746
1737
  pageRef: pageRefSchema,
1747
1738
  recordId: stringSchema({ minLength: 1 }),
1748
1739
  requestId: stringSchema({ minLength: 1 }),
1749
- actionId: stringSchema({ minLength: 1 }),
1740
+ capture: stringSchema({ minLength: 1 }),
1750
1741
  tag: stringSchema({ minLength: 1 }),
1751
1742
  url: stringSchema({ minLength: 1 }),
1752
1743
  hostname: stringSchema({ minLength: 1 }),
@@ -1756,21 +1747,22 @@ var opensteerNetworkSaveInputSchema = objectSchema(
1756
1747
  resourceType: networkResourceTypeSchema
1757
1748
  },
1758
1749
  {
1759
- title: "OpensteerNetworkSaveInput",
1750
+ title: "OpensteerNetworkTagInput",
1760
1751
  required: ["tag"]
1761
1752
  }
1762
1753
  );
1763
- var opensteerNetworkSaveOutputSchema = objectSchema(
1754
+ var opensteerNetworkTagOutputSchema = objectSchema(
1764
1755
  {
1765
- savedCount: integerSchema({ minimum: 0 })
1756
+ taggedCount: integerSchema({ minimum: 0 })
1766
1757
  },
1767
1758
  {
1768
- title: "OpensteerNetworkSaveOutput",
1769
- required: ["savedCount"]
1759
+ title: "OpensteerNetworkTagOutput",
1760
+ required: ["taggedCount"]
1770
1761
  }
1771
1762
  );
1772
1763
  var opensteerNetworkClearInputSchema = objectSchema(
1773
1764
  {
1765
+ capture: stringSchema({ minLength: 1 }),
1774
1766
  tag: stringSchema({ minLength: 1 })
1775
1767
  },
1776
1768
  {
@@ -5228,7 +5220,7 @@ var opensteerSemanticOperationNames = [
5228
5220
  "dom.scroll",
5229
5221
  "dom.extract",
5230
5222
  "network.query",
5231
- "network.save",
5223
+ "network.tag",
5232
5224
  "network.clear",
5233
5225
  "network.minimize",
5234
5226
  "network.diff",
@@ -5289,7 +5281,7 @@ var opensteerPackageRunnableSemanticOperationNames = /* @__PURE__ */ new Set([
5289
5281
  "dom.scroll",
5290
5282
  "dom.extract",
5291
5283
  "network.query",
5292
- "network.save",
5284
+ "network.tag",
5293
5285
  "network.clear",
5294
5286
  "network.minimize",
5295
5287
  "network.diff",
@@ -5609,7 +5601,7 @@ var opensteerPageCloseOutputSchema = objectSchema(
5609
5601
  var opensteerPageGotoInputSchema = objectSchema(
5610
5602
  {
5611
5603
  url: stringSchema(),
5612
- networkTag: stringSchema({ minLength: 1 })
5604
+ captureNetwork: stringSchema({ minLength: 1 })
5613
5605
  },
5614
5606
  {
5615
5607
  title: "OpensteerPageGotoInput",
@@ -5760,7 +5752,7 @@ var opensteerDomClickInputSchema = objectSchema(
5760
5752
  {
5761
5753
  target: opensteerTargetInputSchema,
5762
5754
  persistAsDescription: stringSchema(),
5763
- networkTag: stringSchema({ minLength: 1 })
5755
+ captureNetwork: stringSchema({ minLength: 1 })
5764
5756
  },
5765
5757
  {
5766
5758
  title: "OpensteerDomClickInput",
@@ -5771,7 +5763,7 @@ var opensteerDomHoverInputSchema = objectSchema(
5771
5763
  {
5772
5764
  target: opensteerTargetInputSchema,
5773
5765
  persistAsDescription: stringSchema(),
5774
- networkTag: stringSchema({ minLength: 1 })
5766
+ captureNetwork: stringSchema({ minLength: 1 })
5775
5767
  },
5776
5768
  {
5777
5769
  title: "OpensteerDomHoverInput",
@@ -5784,7 +5776,7 @@ var opensteerDomInputInputSchema = objectSchema(
5784
5776
  text: stringSchema(),
5785
5777
  pressEnter: { type: "boolean" },
5786
5778
  persistAsDescription: stringSchema(),
5787
- networkTag: stringSchema({ minLength: 1 })
5779
+ captureNetwork: stringSchema({ minLength: 1 })
5788
5780
  },
5789
5781
  {
5790
5782
  title: "OpensteerDomInputInput",
@@ -5797,7 +5789,7 @@ var opensteerDomScrollInputSchema = objectSchema(
5797
5789
  direction: enumSchema(["up", "down", "left", "right"]),
5798
5790
  amount: integerSchema({ minimum: 1 }),
5799
5791
  persistAsDescription: stringSchema(),
5800
- networkTag: stringSchema({ minLength: 1 })
5792
+ captureNetwork: stringSchema({ minLength: 1 })
5801
5793
  },
5802
5794
  {
5803
5795
  title: "OpensteerDomScrollInput",
@@ -5998,7 +5990,7 @@ var opensteerComputerExecuteInputSchema = objectSchema(
5998
5990
  {
5999
5991
  action: opensteerComputerActionSchema,
6000
5992
  screenshot: opensteerComputerScreenshotOptionsSchema,
6001
- networkTag: stringSchema({ minLength: 1 })
5993
+ captureNetwork: stringSchema({ minLength: 1 })
6002
5994
  },
6003
5995
  {
6004
5996
  title: "OpensteerComputerExecuteInput",
@@ -6199,18 +6191,17 @@ var opensteerSemanticOperationSpecificationsBase = [
6199
6191
  }),
6200
6192
  defineSemanticOperationSpec({
6201
6193
  name: "network.query",
6202
- description: "Query live or saved network records for reverse engineering workflows.",
6194
+ description: "Query persisted network records for reverse engineering workflows.",
6203
6195
  inputSchema: opensteerNetworkQueryInputSchema,
6204
6196
  outputSchema: opensteerNetworkQueryOutputSchema,
6205
- requiredCapabilities: [],
6206
- resolveRequiredCapabilities: (input) => input.source === "saved" ? [] : input.includeBodies === true ? ["inspect.network", "inspect.networkBodies"] : ["inspect.network"]
6197
+ requiredCapabilities: []
6207
6198
  }),
6208
6199
  defineSemanticOperationSpec({
6209
- name: "network.save",
6210
- description: "Persist filtered live network records into the saved network registry under a tag.",
6211
- inputSchema: opensteerNetworkSaveInputSchema,
6212
- outputSchema: opensteerNetworkSaveOutputSchema,
6213
- requiredCapabilities: ["inspect.network"]
6200
+ name: "network.tag",
6201
+ description: "Apply a tag to persisted network records matching the provided filters.",
6202
+ inputSchema: opensteerNetworkTagInputSchema,
6203
+ outputSchema: opensteerNetworkTagOutputSchema,
6204
+ requiredCapabilities: []
6214
6205
  }),
6215
6206
  defineSemanticOperationSpec({
6216
6207
  name: "network.clear",
@@ -7031,6 +7022,49 @@ function mediaTypeExtension(mediaType) {
7031
7022
  }
7032
7023
  }
7033
7024
 
7025
+ // src/action-boundary.ts
7026
+ var actionBoundaryDiagnosticsBySignal = /* @__PURE__ */ new WeakMap();
7027
+ async function captureActionBoundarySnapshot(engine, pageRef) {
7028
+ const frames = await engine.listFrames({ pageRef });
7029
+ const mainFrame = frames.find((frame) => frame.isMainFrame);
7030
+ if (!mainFrame) {
7031
+ throw new Error(`page ${pageRef} does not expose a main frame`);
7032
+ }
7033
+ return {
7034
+ pageRef,
7035
+ documentRef: mainFrame.documentRef
7036
+ };
7037
+ }
7038
+ function createActionBoundaryDiagnostics(input) {
7039
+ return {
7040
+ trigger: input.boundary.trigger,
7041
+ crossDocument: input.boundary.crossDocument,
7042
+ bootstrapSettled: input.boundary.bootstrapSettled,
7043
+ visualSettled: input.visualSettled,
7044
+ ...input.boundary.timedOutPhase !== void 0 ? { timedOutPhase: input.boundary.timedOutPhase } : !input.visualSettled ? { timedOutPhase: "visual" } : {}
7045
+ };
7046
+ }
7047
+ function recordActionBoundaryDiagnostics(signal, diagnostics) {
7048
+ actionBoundaryDiagnosticsBySignal.set(signal, diagnostics);
7049
+ }
7050
+ function takeActionBoundaryDiagnostics(signal) {
7051
+ const diagnostics = actionBoundaryDiagnosticsBySignal.get(signal);
7052
+ actionBoundaryDiagnosticsBySignal.delete(signal);
7053
+ return diagnostics;
7054
+ }
7055
+ function isSoftSettleTimeoutError(error, signal) {
7056
+ if (isTimeoutError(error)) {
7057
+ return true;
7058
+ }
7059
+ return signal?.aborted === true && isTimeoutError(signal.reason) && (error === signal.reason || isAbortError(error));
7060
+ }
7061
+ function isAbortError(error) {
7062
+ return error instanceof Error && error.name === "AbortError";
7063
+ }
7064
+ function isTimeoutError(error) {
7065
+ return isOpensteerProtocolError(error) && error.code === "timeout";
7066
+ }
7067
+
7034
7068
  // src/internal/errors.ts
7035
7069
  function normalizeThrownOpensteerError(error, fallbackMessage) {
7036
7070
  if (isOpensteerProtocolError(error)) {
@@ -7063,13 +7097,13 @@ var DEFAULT_TIMEOUTS = {
7063
7097
  "page.add-init-script": 1e4,
7064
7098
  "page.snapshot": 15e3,
7065
7099
  "computer.execute": 3e4,
7066
- "dom.click": 1e4,
7100
+ "dom.click": 3e4,
7067
7101
  "dom.hover": 1e4,
7068
- "dom.input": 1e4,
7102
+ "dom.input": 3e4,
7069
7103
  "dom.scroll": 1e4,
7070
7104
  "dom.extract": 15e3,
7071
7105
  "network.query": 15e3,
7072
- "network.save": 15e3,
7106
+ "network.tag": 15e3,
7073
7107
  "network.clear": 1e4,
7074
7108
  "scripts.capture": 15e3,
7075
7109
  "request.raw": 3e4,
@@ -7884,7 +7918,7 @@ var SqliteSavedNetworkStore = class {
7884
7918
  async initialize() {
7885
7919
  await this.ensureDatabaseDirectory();
7886
7920
  }
7887
- async save(records, tag) {
7921
+ async save(records, options) {
7888
7922
  const database = await this.requireDatabase();
7889
7923
  const readExisting = database.prepare(`
7890
7924
  SELECT record_id
@@ -7893,123 +7927,7 @@ var SqliteSavedNetworkStore = class {
7893
7927
  AND page_ref_key = @page_ref_key
7894
7928
  AND request_id = @request_id
7895
7929
  `);
7896
- const upsertRecord = database.prepare(`
7897
- INSERT INTO saved_network_records (
7898
- record_id,
7899
- request_id,
7900
- session_ref,
7901
- page_ref,
7902
- page_ref_key,
7903
- frame_ref,
7904
- document_ref,
7905
- action_id,
7906
- method,
7907
- method_lc,
7908
- url,
7909
- url_lc,
7910
- hostname,
7911
- hostname_lc,
7912
- path,
7913
- path_lc,
7914
- status,
7915
- status_text,
7916
- resource_type,
7917
- navigation_request,
7918
- request_headers_json,
7919
- response_headers_json,
7920
- request_body_json,
7921
- response_body_json,
7922
- initiator_json,
7923
- timing_json,
7924
- transfer_json,
7925
- source_json,
7926
- capture_state,
7927
- request_body_state,
7928
- response_body_state,
7929
- request_body_skip_reason,
7930
- response_body_skip_reason,
7931
- request_body_error,
7932
- response_body_error,
7933
- redirect_from_request_id,
7934
- redirect_to_request_id,
7935
- saved_at
7936
- ) VALUES (
7937
- @record_id,
7938
- @request_id,
7939
- @session_ref,
7940
- @page_ref,
7941
- @page_ref_key,
7942
- @frame_ref,
7943
- @document_ref,
7944
- @action_id,
7945
- @method,
7946
- @method_lc,
7947
- @url,
7948
- @url_lc,
7949
- @hostname,
7950
- @hostname_lc,
7951
- @path,
7952
- @path_lc,
7953
- @status,
7954
- @status_text,
7955
- @resource_type,
7956
- @navigation_request,
7957
- @request_headers_json,
7958
- @response_headers_json,
7959
- @request_body_json,
7960
- @response_body_json,
7961
- @initiator_json,
7962
- @timing_json,
7963
- @transfer_json,
7964
- @source_json,
7965
- @capture_state,
7966
- @request_body_state,
7967
- @response_body_state,
7968
- @request_body_skip_reason,
7969
- @response_body_skip_reason,
7970
- @request_body_error,
7971
- @response_body_error,
7972
- @redirect_from_request_id,
7973
- @redirect_to_request_id,
7974
- @saved_at
7975
- )
7976
- ON CONFLICT(record_id) DO UPDATE SET
7977
- page_ref = excluded.page_ref,
7978
- page_ref_key = excluded.page_ref_key,
7979
- frame_ref = excluded.frame_ref,
7980
- document_ref = excluded.document_ref,
7981
- action_id = excluded.action_id,
7982
- method = excluded.method,
7983
- method_lc = excluded.method_lc,
7984
- url = excluded.url,
7985
- url_lc = excluded.url_lc,
7986
- hostname = excluded.hostname,
7987
- hostname_lc = excluded.hostname_lc,
7988
- path = excluded.path,
7989
- path_lc = excluded.path_lc,
7990
- status = excluded.status,
7991
- status_text = excluded.status_text,
7992
- resource_type = excluded.resource_type,
7993
- navigation_request = excluded.navigation_request,
7994
- request_headers_json = excluded.request_headers_json,
7995
- response_headers_json = excluded.response_headers_json,
7996
- request_body_json = excluded.request_body_json,
7997
- response_body_json = excluded.response_body_json,
7998
- initiator_json = excluded.initiator_json,
7999
- timing_json = excluded.timing_json,
8000
- transfer_json = excluded.transfer_json,
8001
- source_json = excluded.source_json,
8002
- capture_state = excluded.capture_state,
8003
- request_body_state = excluded.request_body_state,
8004
- response_body_state = excluded.response_body_state,
8005
- request_body_skip_reason = excluded.request_body_skip_reason,
8006
- response_body_skip_reason = excluded.response_body_skip_reason,
8007
- request_body_error = excluded.request_body_error,
8008
- response_body_error = excluded.response_body_error,
8009
- redirect_from_request_id = excluded.redirect_from_request_id,
8010
- redirect_to_request_id = excluded.redirect_to_request_id,
8011
- saved_at = excluded.saved_at
8012
- `);
7930
+ const upsertRecord = database.prepare(buildSavedNetworkUpsertSql(options.bodyWriteMode));
8013
7931
  const insertTag = database.prepare(`
8014
7932
  INSERT OR IGNORE INTO saved_network_tags (record_id, tag)
8015
7933
  VALUES (@record_id, @tag)
@@ -8033,7 +7951,7 @@ var SqliteSavedNetworkStore = class {
8033
7951
  page_ref_key: pageRefKey,
8034
7952
  frame_ref: entry.record.frameRef ?? null,
8035
7953
  document_ref: entry.record.documentRef ?? null,
8036
- action_id: entry.actionId ?? null,
7954
+ capture: entry.capture ?? null,
8037
7955
  method: entry.record.method,
8038
7956
  method_lc: entry.record.method.toLowerCase(),
8039
7957
  url: entry.record.url,
@@ -8065,10 +7983,14 @@ var SqliteSavedNetworkStore = class {
8065
7983
  redirect_to_request_id: entry.record.redirectToRequestId ?? null,
8066
7984
  saved_at: entry.savedAt ?? Date.now()
8067
7985
  });
8068
- if (tag !== void 0) {
7986
+ const tags = new Set(entry.tags ?? []);
7987
+ if (options.tag !== void 0) {
7988
+ tags.add(options.tag);
7989
+ }
7990
+ for (const currentTag of tags) {
8069
7991
  const result = insertTag.run({
8070
7992
  record_id: recordId,
8071
- tag
7993
+ tag: currentTag
8072
7994
  });
8073
7995
  savedCount += result.changes ?? 0;
8074
7996
  }
@@ -8076,6 +7998,39 @@ var SqliteSavedNetworkStore = class {
8076
7998
  return savedCount;
8077
7999
  });
8078
8000
  }
8001
+ async tagByFilter(filter, tag) {
8002
+ const database = await this.requireDatabase();
8003
+ const { whereSql, parameters } = buildSavedNetworkWhere(filter);
8004
+ const selectRecords = database.prepare(
8005
+ `
8006
+ SELECT r.record_id
8007
+ FROM saved_network_records r
8008
+ ${whereSql}
8009
+ `
8010
+ );
8011
+ const insertTag = database.prepare(`
8012
+ INSERT OR IGNORE INTO saved_network_tags (record_id, tag)
8013
+ VALUES (@record_id, @tag)
8014
+ `);
8015
+ return withSqliteTransaction(database, () => {
8016
+ let taggedCount = 0;
8017
+ const rows = selectRecords.all(
8018
+ ...parameters
8019
+ );
8020
+ for (const row of rows) {
8021
+ const recordId = row.record_id;
8022
+ if (typeof recordId !== "string") {
8023
+ continue;
8024
+ }
8025
+ const result = insertTag.run({
8026
+ record_id: recordId,
8027
+ tag
8028
+ });
8029
+ taggedCount += result.changes ?? 0;
8030
+ }
8031
+ return taggedCount;
8032
+ });
8033
+ }
8079
8034
  async query(input = {}) {
8080
8035
  const database = await this.requireDatabase();
8081
8036
  const limit = Math.max(1, Math.min(input.limit ?? 50, 200));
@@ -8109,39 +8064,31 @@ var SqliteSavedNetworkStore = class {
8109
8064
  }
8110
8065
  async clear(input = {}) {
8111
8066
  const database = await this.requireDatabase();
8112
- const countAll = database.prepare(`
8113
- SELECT COUNT(*) AS cleared
8114
- FROM saved_network_records
8115
- `);
8116
- const countByTag = database.prepare(`
8117
- SELECT COUNT(DISTINCT record_id) AS cleared
8118
- FROM saved_network_tags
8119
- WHERE tag = @tag
8120
- `);
8121
- const deleteAllTags = database.prepare(`DELETE FROM saved_network_tags`);
8067
+ const countAll = database.prepare(`SELECT COUNT(*) AS cleared FROM saved_network_records`);
8122
8068
  const deleteAllRecords = database.prepare(`DELETE FROM saved_network_records`);
8123
- const deleteTag = database.prepare(`
8124
- DELETE FROM saved_network_tags
8125
- WHERE tag = @tag
8069
+ const { whereSql, parameters } = buildSavedNetworkWhere(input);
8070
+ const countFiltered = database.prepare(`
8071
+ SELECT COUNT(*) AS cleared
8072
+ FROM saved_network_records r
8073
+ ${whereSql}
8126
8074
  `);
8127
- const deleteOrphans = database.prepare(`
8075
+ const deleteFiltered = database.prepare(`
8128
8076
  DELETE FROM saved_network_records
8129
- WHERE NOT EXISTS (
8130
- SELECT 1
8131
- FROM saved_network_tags t
8132
- WHERE t.record_id = saved_network_records.record_id
8077
+ WHERE record_id IN (
8078
+ SELECT r.record_id
8079
+ FROM saved_network_records r
8080
+ ${whereSql}
8133
8081
  )
8134
8082
  `);
8135
8083
  return withSqliteTransaction(database, () => {
8136
- const tag = input.tag;
8137
- const cleared = tag === void 0 ? countAll.get().cleared : countByTag.get({ tag }).cleared;
8138
- if (tag === void 0) {
8139
- deleteAllTags.run();
8084
+ if (input.capture === void 0 && input.tag === void 0) {
8085
+ const cleared2 = countAll.get().cleared;
8140
8086
  deleteAllRecords.run();
8141
- return cleared;
8087
+ return cleared2;
8142
8088
  }
8143
- deleteTag.run({ tag });
8144
- deleteOrphans.run();
8089
+ const args = parameters;
8090
+ const cleared = countFiltered.get(...args).cleared;
8091
+ deleteFiltered.run(...args);
8145
8092
  return cleared;
8146
8093
  });
8147
8094
  }
@@ -8196,7 +8143,7 @@ var SqliteSavedNetworkStore = class {
8196
8143
  page_ref_key TEXT NOT NULL,
8197
8144
  frame_ref TEXT,
8198
8145
  document_ref TEXT,
8199
- action_id TEXT,
8146
+ capture TEXT,
8200
8147
  method TEXT NOT NULL,
8201
8148
  method_lc TEXT NOT NULL,
8202
8149
  url TEXT NOT NULL,
@@ -8235,6 +8182,9 @@ var SqliteSavedNetworkStore = class {
8235
8182
  CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
8236
8183
  ON saved_network_records (saved_at DESC);
8237
8184
 
8185
+ CREATE INDEX IF NOT EXISTS saved_network_records_capture
8186
+ ON saved_network_records (capture);
8187
+
8238
8188
  CREATE TABLE IF NOT EXISTS saved_network_tags (
8239
8189
  record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
8240
8190
  tag TEXT NOT NULL,
@@ -8250,6 +8200,7 @@ var SqliteSavedNetworkStore = class {
8250
8200
  "capture_state",
8251
8201
  "TEXT NOT NULL DEFAULT 'complete'"
8252
8202
  );
8203
+ this.ensureColumn(database, "saved_network_records", "capture", "TEXT");
8253
8204
  this.ensureColumn(
8254
8205
  database,
8255
8206
  "saved_network_records",
@@ -8278,6 +8229,10 @@ var SqliteSavedNetworkStore = class {
8278
8229
  function buildSavedNetworkWhere(input) {
8279
8230
  const clauses = [];
8280
8231
  const parameters = [];
8232
+ if (input.pageRef !== void 0) {
8233
+ clauses.push("r.page_ref_key = ?");
8234
+ parameters.push(input.pageRef);
8235
+ }
8281
8236
  if (input.recordId !== void 0) {
8282
8237
  clauses.push("r.record_id = ?");
8283
8238
  parameters.push(input.recordId);
@@ -8286,9 +8241,9 @@ function buildSavedNetworkWhere(input) {
8286
8241
  clauses.push("r.request_id = ?");
8287
8242
  parameters.push(input.requestId);
8288
8243
  }
8289
- if (input.actionId !== void 0) {
8290
- clauses.push("r.action_id = ?");
8291
- parameters.push(input.actionId);
8244
+ if (input.capture !== void 0) {
8245
+ clauses.push("r.capture = ?");
8246
+ parameters.push(input.capture);
8292
8247
  }
8293
8248
  if (input.tag !== void 0) {
8294
8249
  clauses.push(`
@@ -8330,6 +8285,127 @@ function buildSavedNetworkWhere(input) {
8330
8285
  parameters
8331
8286
  };
8332
8287
  }
8288
+ function buildSavedNetworkUpsertSql(bodyWriteMode) {
8289
+ const bodyUpdateSql = bodyWriteMode === "authoritative" ? `
8290
+ request_body_json = excluded.request_body_json,
8291
+ response_body_json = excluded.response_body_json,
8292
+ request_body_state = excluded.request_body_state,
8293
+ response_body_state = excluded.response_body_state,
8294
+ request_body_skip_reason = excluded.request_body_skip_reason,
8295
+ response_body_skip_reason = excluded.response_body_skip_reason,
8296
+ request_body_error = excluded.request_body_error,
8297
+ response_body_error = excluded.response_body_error,
8298
+ ` : "";
8299
+ return `
8300
+ INSERT INTO saved_network_records (
8301
+ record_id,
8302
+ request_id,
8303
+ session_ref,
8304
+ page_ref,
8305
+ page_ref_key,
8306
+ frame_ref,
8307
+ document_ref,
8308
+ capture,
8309
+ method,
8310
+ method_lc,
8311
+ url,
8312
+ url_lc,
8313
+ hostname,
8314
+ hostname_lc,
8315
+ path,
8316
+ path_lc,
8317
+ status,
8318
+ status_text,
8319
+ resource_type,
8320
+ navigation_request,
8321
+ request_headers_json,
8322
+ response_headers_json,
8323
+ request_body_json,
8324
+ response_body_json,
8325
+ initiator_json,
8326
+ timing_json,
8327
+ transfer_json,
8328
+ source_json,
8329
+ capture_state,
8330
+ request_body_state,
8331
+ response_body_state,
8332
+ request_body_skip_reason,
8333
+ response_body_skip_reason,
8334
+ request_body_error,
8335
+ response_body_error,
8336
+ redirect_from_request_id,
8337
+ redirect_to_request_id,
8338
+ saved_at
8339
+ ) VALUES (
8340
+ @record_id,
8341
+ @request_id,
8342
+ @session_ref,
8343
+ @page_ref,
8344
+ @page_ref_key,
8345
+ @frame_ref,
8346
+ @document_ref,
8347
+ @capture,
8348
+ @method,
8349
+ @method_lc,
8350
+ @url,
8351
+ @url_lc,
8352
+ @hostname,
8353
+ @hostname_lc,
8354
+ @path,
8355
+ @path_lc,
8356
+ @status,
8357
+ @status_text,
8358
+ @resource_type,
8359
+ @navigation_request,
8360
+ @request_headers_json,
8361
+ @response_headers_json,
8362
+ @request_body_json,
8363
+ @response_body_json,
8364
+ @initiator_json,
8365
+ @timing_json,
8366
+ @transfer_json,
8367
+ @source_json,
8368
+ @capture_state,
8369
+ @request_body_state,
8370
+ @response_body_state,
8371
+ @request_body_skip_reason,
8372
+ @response_body_skip_reason,
8373
+ @request_body_error,
8374
+ @response_body_error,
8375
+ @redirect_from_request_id,
8376
+ @redirect_to_request_id,
8377
+ @saved_at
8378
+ )
8379
+ ON CONFLICT(record_id) DO UPDATE SET
8380
+ page_ref = excluded.page_ref,
8381
+ page_ref_key = excluded.page_ref_key,
8382
+ frame_ref = excluded.frame_ref,
8383
+ document_ref = excluded.document_ref,
8384
+ capture = excluded.capture,
8385
+ method = excluded.method,
8386
+ method_lc = excluded.method_lc,
8387
+ url = excluded.url,
8388
+ url_lc = excluded.url_lc,
8389
+ hostname = excluded.hostname,
8390
+ hostname_lc = excluded.hostname_lc,
8391
+ path = excluded.path,
8392
+ path_lc = excluded.path_lc,
8393
+ status = excluded.status,
8394
+ status_text = excluded.status_text,
8395
+ resource_type = excluded.resource_type,
8396
+ navigation_request = excluded.navigation_request,
8397
+ request_headers_json = excluded.request_headers_json,
8398
+ response_headers_json = excluded.response_headers_json,
8399
+ ${bodyUpdateSql} initiator_json = excluded.initiator_json,
8400
+ timing_json = excluded.timing_json,
8401
+ transfer_json = excluded.transfer_json,
8402
+ source_json = excluded.source_json,
8403
+ capture_state = excluded.capture_state,
8404
+ redirect_from_request_id = excluded.redirect_from_request_id,
8405
+ redirect_to_request_id = excluded.redirect_to_request_id,
8406
+ saved_at = MIN(saved_network_records.saved_at, excluded.saved_at)
8407
+ `;
8408
+ }
8333
8409
  function inflateSavedNetworkRow(row, includeBodies) {
8334
8410
  const requestBody = includeBodies && row.request_body_json !== null ? JSON.parse(row.request_body_json) : void 0;
8335
8411
  const responseBody = includeBodies && row.response_body_json !== null ? JSON.parse(row.response_body_json) : void 0;
@@ -8400,8 +8476,7 @@ function inflateSavedNetworkRow(row, includeBodies) {
8400
8476
  }
8401
8477
  return {
8402
8478
  recordId: row.record_id,
8403
- source: "saved",
8404
- ...row.action_id === null ? {} : { actionId: row.action_id },
8479
+ ...row.capture === null ? {} : { capture: row.capture },
8405
8480
  ...row.tags === null || row.tags.length === 0 ? {} : { tags: row.tags.split(TAG_DELIMITER).filter((tag) => tag.length > 0) },
8406
8481
  savedAt: row.saved_at,
8407
8482
  record
@@ -10357,8 +10432,9 @@ var DomActionExecutor = class {
10357
10432
  })
10358
10433
  );
10359
10434
  let finalResolved = resolved;
10435
+ let finalSnapshot;
10360
10436
  if (input.pressEnter) {
10361
- await this.settle(resolved.pageRef, "dom.input", timeout);
10437
+ await this.waitForPressEnterReaction(timeout);
10362
10438
  const enterSession = this.options.createResolutionSession();
10363
10439
  const enterResolved = await timeout.runStep(
10364
10440
  () => this.options.resolveTarget(enterSession, {
@@ -10372,6 +10448,9 @@ var DomActionExecutor = class {
10372
10448
  () => bridge.inspectActionTarget(enterResolved.locator)
10373
10449
  );
10374
10450
  this.assertKeyboardActionable("dom.input", enterResolved, inspectionBeforeEnter);
10451
+ finalSnapshot = await timeout.runStep(
10452
+ () => captureActionBoundarySnapshot(this.options.engine, enterResolved.pageRef)
10453
+ );
10375
10454
  await timeout.runStep(
10376
10455
  () => bridge.pressKey(enterResolved.locator, {
10377
10456
  key: "Enter"
@@ -10379,7 +10458,15 @@ var DomActionExecutor = class {
10379
10458
  );
10380
10459
  finalResolved = enterResolved;
10381
10460
  }
10382
- await this.settle(finalResolved.pageRef, "dom.input", timeout);
10461
+ const settleDiagnostics = await this.settle(
10462
+ finalResolved.pageRef,
10463
+ "dom.input",
10464
+ timeout,
10465
+ finalSnapshot
10466
+ );
10467
+ if (finalSnapshot !== void 0) {
10468
+ recordActionBoundaryDiagnostics(timeout.signal, settleDiagnostics);
10469
+ }
10383
10470
  return finalResolved;
10384
10471
  } catch (error) {
10385
10472
  lastError = error;
@@ -10452,8 +10539,17 @@ var DomActionExecutor = class {
10452
10539
  );
10453
10540
  }
10454
10541
  }
10542
+ const actionBoundarySnapshot = await timeout.runStep(
10543
+ () => captureActionBoundarySnapshot(this.options.engine, pointerTarget.resolved.pageRef)
10544
+ );
10455
10545
  const outcome = await dispatch(pointerTarget, point, timeout);
10456
- await this.settle(pointerTarget.resolved.pageRef, input.operation, timeout);
10546
+ const settleDiagnostics = await this.settle(
10547
+ pointerTarget.resolved.pageRef,
10548
+ input.operation,
10549
+ timeout,
10550
+ actionBoundarySnapshot
10551
+ );
10552
+ recordActionBoundaryDiagnostics(timeout.signal, settleDiagnostics);
10457
10553
  return outcome;
10458
10554
  } catch (error) {
10459
10555
  lastError = error;
@@ -10471,23 +10567,49 @@ var DomActionExecutor = class {
10471
10567
  }
10472
10568
  return runWithPolicyTimeout(this.options.policy.timeout, { operation }, execute);
10473
10569
  }
10474
- async settle(pageRef, operation, timeout) {
10570
+ async settle(pageRef, operation, timeout, snapshot) {
10475
10571
  const bridge = this.requireBridge();
10476
- await timeout.runStep(
10572
+ let visualSettled = true;
10573
+ const boundary = await timeout.runStep(
10477
10574
  () => bridge.finalizeDomAction(pageRef, {
10478
10575
  operation,
10576
+ ...snapshot === void 0 ? {} : { snapshot },
10479
10577
  signal: timeout.signal,
10480
10578
  remainingMs: () => timeout.remainingMs(),
10481
- policySettle: (targetPageRef) => settleWithPolicy(this.options.policy.settle, {
10482
- operation,
10483
- trigger: "dom-action",
10484
- engine: this.options.engine,
10485
- pageRef: targetPageRef,
10486
- signal: timeout.signal,
10487
- remainingMs: timeout.remainingMs()
10488
- })
10579
+ policySettle: async (targetPageRef, trigger) => {
10580
+ try {
10581
+ await settleWithPolicy(this.options.policy.settle, {
10582
+ operation,
10583
+ trigger,
10584
+ engine: this.options.engine,
10585
+ pageRef: targetPageRef,
10586
+ signal: timeout.signal,
10587
+ remainingMs: timeout.remainingMs()
10588
+ });
10589
+ } catch (error) {
10590
+ if (snapshot !== void 0 && isSoftSettleTimeoutError(error, timeout.signal)) {
10591
+ visualSettled = false;
10592
+ return;
10593
+ }
10594
+ throw error;
10595
+ }
10596
+ }
10489
10597
  })
10490
10598
  );
10599
+ return createActionBoundaryDiagnostics({
10600
+ boundary,
10601
+ visualSettled
10602
+ });
10603
+ }
10604
+ async waitForPressEnterReaction(timeout) {
10605
+ const delayMs = this.options.policy.settle.resolveDelayMs({
10606
+ operation: "dom.input",
10607
+ trigger: "dom-action"
10608
+ });
10609
+ if (delayMs <= 0) {
10610
+ return;
10611
+ }
10612
+ await delayWithSignal(delayMs, timeout.signal);
10491
10613
  }
10492
10614
  requireBridge() {
10493
10615
  if (this.bridge !== void 0) {
@@ -11754,23 +11876,47 @@ var DefaultComputerUseRuntime = class {
11754
11876
  const preActionDisplay = createComputerDisplayTransform(preActionNativeViewport);
11755
11877
  const nativeAction = toNativeComputerAction(input.input.action, preActionDisplay);
11756
11878
  const screenshot = normalizeScreenshotOptions(input.input.screenshot);
11879
+ const snapshot = await input.timeout.runStep(
11880
+ () => captureActionBoundarySnapshot(this.options.engine, input.pageRef)
11881
+ );
11882
+ let visualSettled = true;
11757
11883
  const executed = await input.timeout.runStep(
11758
11884
  () => bridge.execute({
11759
11885
  pageRef: input.pageRef,
11886
+ snapshot,
11760
11887
  action: nativeAction,
11761
11888
  screenshot,
11762
11889
  signal: input.timeout.signal,
11763
11890
  remainingMs: () => input.timeout.remainingMs(),
11764
- policySettle: async (pageRef) => settleWithPolicy(this.options.policy.settle, {
11765
- operation: "computer.execute",
11766
- trigger: "dom-action",
11767
- engine: this.options.engine,
11768
- pageRef,
11769
- signal: input.timeout.signal,
11770
- remainingMs: input.timeout.remainingMs()
11771
- })
11891
+ policySettle: async (pageRef, trigger) => {
11892
+ try {
11893
+ await settleWithPolicy(this.options.policy.settle, {
11894
+ operation: "computer.execute",
11895
+ trigger,
11896
+ engine: this.options.engine,
11897
+ pageRef,
11898
+ signal: input.timeout.signal,
11899
+ remainingMs: input.timeout.remainingMs()
11900
+ });
11901
+ } catch (error) {
11902
+ if (pageRef === input.pageRef && isSoftSettleTimeoutError(error, input.timeout.signal)) {
11903
+ visualSettled = false;
11904
+ return;
11905
+ }
11906
+ throw error;
11907
+ }
11908
+ }
11772
11909
  })
11773
11910
  );
11911
+ if (executed.boundary !== void 0 && executed.pageRef === input.pageRef) {
11912
+ recordActionBoundaryDiagnostics(
11913
+ input.timeout.signal,
11914
+ createActionBoundaryDiagnostics({
11915
+ boundary: executed.boundary,
11916
+ visualSettled
11917
+ })
11918
+ );
11919
+ }
11774
11920
  let trace = void 0;
11775
11921
  if (!input.timeout.signal.aborted) {
11776
11922
  try {
@@ -11883,8 +12029,8 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
11883
12029
  input,
11884
12030
  options
11885
12031
  );
11886
- case "network.save":
11887
- return runtime.saveNetwork(
12032
+ case "network.tag":
12033
+ return runtime.tagNetwork(
11888
12034
  input,
11889
12035
  options
11890
12036
  );
@@ -12758,9 +12904,9 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
12758
12904
  key: input.key,
12759
12905
  version: input.version,
12760
12906
  provenance: {
12761
- source: record.source === "saved" ? "saved-network-record" : "live-network-record",
12907
+ source: record.savedAt === void 0 ? "network-record" : "saved-network-record",
12762
12908
  sourceId: record.recordId,
12763
- ...record.source === "saved" ? record.savedAt === void 0 ? {} : { capturedAt: record.savedAt } : options.observedAt === void 0 ? {} : { capturedAt: options.observedAt }
12909
+ ...record.savedAt === void 0 ? options.observedAt === void 0 ? {} : { capturedAt: options.observedAt } : { capturedAt: record.savedAt }
12764
12910
  },
12765
12911
  payload,
12766
12912
  ...record.tags === void 0 || record.tags.length === 0 ? {} : { tags: record.tags }
@@ -13140,63 +13286,67 @@ function resolveBodyEncoding(charset) {
13140
13286
  return "utf8";
13141
13287
  }
13142
13288
  }
13143
- var NetworkJournal = class {
13289
+ var NetworkHistory = class {
13144
13290
  metadataByRequestId = /* @__PURE__ */ new Map();
13145
13291
  requestIdByRecordId = /* @__PURE__ */ new Map();
13146
- requestIdsByActionId = /* @__PURE__ */ new Map();
13292
+ requestIdsByCapture = /* @__PURE__ */ new Map();
13147
13293
  requestIdsByTag = /* @__PURE__ */ new Map();
13148
- sync(records, options = {}) {
13294
+ tombstonedRequestIds = /* @__PURE__ */ new Set();
13295
+ materialize(records, options = {}) {
13149
13296
  const observedAt = Date.now();
13150
- return records.map((record) => this.materializeLiveRecord(record, observedAt, options));
13151
- }
13152
- materializeLiveRecord(record, observedAt, options = {}) {
13153
- let metadata = this.metadataByRequestId.get(record.requestId);
13154
- if (!metadata) {
13155
- metadata = {
13156
- recordId: `record:${crypto.randomUUID()}`,
13157
- observedAt,
13158
- ...record.pageRef === void 0 ? {} : { pageRef: record.pageRef },
13159
- tags: /* @__PURE__ */ new Set()
13160
- };
13161
- this.metadataByRequestId.set(record.requestId, metadata);
13162
- this.requestIdByRecordId.set(metadata.recordId, record.requestId);
13163
- } else if (metadata.pageRef === void 0 && record.pageRef !== void 0) {
13164
- metadata.pageRef = record.pageRef;
13297
+ const materialized = [];
13298
+ for (const record of records) {
13299
+ const entry = this.materializeRecord(record, observedAt, options);
13300
+ if (entry !== void 0) {
13301
+ materialized.push(entry);
13302
+ }
13165
13303
  }
13166
- return {
13167
- recordId: metadata.recordId,
13168
- source: "live",
13169
- ...metadata.actionId === void 0 ? {} : { actionId: metadata.actionId },
13170
- ...metadata.tags.size === 0 ? {} : { tags: [...metadata.tags].sort() },
13171
- record: toProtocolNetworkRecord(record, {
13172
- redactSecretHeaders: options.redactSecretHeaders ?? true
13173
- })
13174
- };
13304
+ return materialized;
13175
13305
  }
13176
- diffNewRequestIds(records, baselineRequestIds) {
13177
- const observedAt = Date.now();
13178
- const all = records.map(
13179
- (record) => this.materializeLiveRecord(record, observedAt, {
13180
- redactSecretHeaders: true
13181
- })
13182
- );
13183
- const delta = all.filter((entry) => !baselineRequestIds.has(entry.record.requestId));
13184
- return {
13185
- all,
13186
- delta
13187
- };
13306
+ async persist(records, store, options) {
13307
+ const observedAt = options.observedAt ?? Date.now();
13308
+ const metadataToSave = /* @__PURE__ */ new Set();
13309
+ const persisted = [];
13310
+ for (const record of records) {
13311
+ const entry = this.materializeRecord(record, observedAt, {
13312
+ ...options.redactSecretHeaders === void 0 ? {} : { redactSecretHeaders: options.redactSecretHeaders }
13313
+ });
13314
+ if (entry === void 0) {
13315
+ continue;
13316
+ }
13317
+ const requestId = entry.record.requestId;
13318
+ const metadata = this.metadataByRequestId.get(requestId);
13319
+ if (metadata === void 0) {
13320
+ continue;
13321
+ }
13322
+ const savedAt = metadata.savedAt ?? observedAt;
13323
+ metadataToSave.add(metadata);
13324
+ persisted.push({
13325
+ ...entry,
13326
+ savedAt
13327
+ });
13328
+ }
13329
+ if (persisted.length > 0) {
13330
+ await store.save(persisted, {
13331
+ bodyWriteMode: options.bodyWriteMode
13332
+ });
13333
+ for (const metadata of metadataToSave) {
13334
+ metadata.savedAt ??= observedAt;
13335
+ }
13336
+ }
13337
+ return persisted;
13188
13338
  }
13189
- assignActionId(records, actionId) {
13339
+ assignCapture(records, capture) {
13190
13340
  for (const record of records) {
13191
13341
  const metadata = this.metadataByRequestId.get(record.record.requestId);
13192
- if (!metadata || metadata.actionId === actionId) {
13342
+ if (!metadata || metadata.capture === capture) {
13193
13343
  continue;
13194
13344
  }
13195
- if (metadata.actionId !== void 0) {
13196
- this.requestIdsByActionId.get(metadata.actionId)?.delete(record.record.requestId);
13345
+ if (metadata.capture !== void 0) {
13346
+ this.requestIdsByCapture.get(metadata.capture)?.delete(record.record.requestId);
13197
13347
  }
13198
- metadata.actionId = actionId;
13199
- this.addIndexedRequestId(this.requestIdsByActionId, actionId, record.record.requestId);
13348
+ metadata.capture = capture;
13349
+ this.addIndexedRequestId(this.requestIdsByCapture, capture, record.record.requestId);
13200
13350
  }
13201
13351
  }
13202
13352
  addTag(records, tag) {
@@ -13216,8 +13366,8 @@ var NetworkJournal = class {
13216
13366
  getRequestId(recordId) {
13217
13367
  return this.requestIdByRecordId.get(recordId);
13218
13368
  }
13219
- getRequestIdsForActionId(actionId) {
13220
- return new Set(this.requestIdsByActionId.get(actionId) ?? []);
13369
+ getRequestIdsForCapture(capture) {
13370
+ return new Set(this.requestIdsByCapture.get(capture) ?? []);
13221
13371
  }
13222
13372
  getRequestIdsForTag(tag) {
13223
13373
  return new Set(this.requestIdsByTag.get(tag) ?? []);
@@ -13225,11 +13375,59 @@ var NetworkJournal = class {
13225
13375
  getPageRefForRequestId(requestId) {
13226
13376
  return this.metadataByRequestId.get(requestId)?.pageRef;
13227
13377
  }
13378
+ getKnownRequestIds() {
13379
+ return new Set(this.metadataByRequestId.keys());
13380
+ }
13381
+ tombstoneRequestIds(requestIds) {
13382
+ for (const requestId of requestIds) {
13383
+ this.tombstonedRequestIds.add(requestId);
13384
+ const metadata = this.metadataByRequestId.get(requestId);
13385
+ if (!metadata) {
13386
+ continue;
13387
+ }
13388
+ this.metadataByRequestId.delete(requestId);
13389
+ this.requestIdByRecordId.delete(metadata.recordId);
13390
+ if (metadata.capture !== void 0) {
13391
+ this.requestIdsByCapture.get(metadata.capture)?.delete(requestId);
13392
+ }
13393
+ for (const tag of metadata.tags) {
13394
+ this.requestIdsByTag.get(tag)?.delete(requestId);
13395
+ }
13396
+ }
13397
+ }
13228
13398
  clear() {
13229
13399
  this.metadataByRequestId.clear();
13230
13400
  this.requestIdByRecordId.clear();
13231
- this.requestIdsByActionId.clear();
13401
+ this.requestIdsByCapture.clear();
13232
13402
  this.requestIdsByTag.clear();
13403
+ this.tombstonedRequestIds.clear();
13404
+ }
13405
+ materializeRecord(record, observedAt, options) {
13406
+ if (this.tombstonedRequestIds.has(record.requestId)) {
13407
+ return void 0;
13408
+ }
13409
+ let metadata = this.metadataByRequestId.get(record.requestId);
13410
+ if (!metadata) {
13411
+ metadata = {
13412
+ recordId: `record:${crypto.randomUUID()}`,
13413
+ observedAt,
13414
+ ...record.pageRef === void 0 ? {} : { pageRef: record.pageRef },
13415
+ tags: /* @__PURE__ */ new Set()
13416
+ };
13417
+ this.metadataByRequestId.set(record.requestId, metadata);
13418
+ this.requestIdByRecordId.set(metadata.recordId, record.requestId);
13419
+ } else if (metadata.pageRef === void 0 && record.pageRef !== void 0) {
13420
+ metadata.pageRef = record.pageRef;
13421
+ }
13422
+ return {
13423
+ recordId: metadata.recordId,
13424
+ ...metadata.capture === void 0 ? {} : { capture: metadata.capture },
13425
+ ...metadata.tags.size === 0 ? {} : { tags: [...metadata.tags].sort() },
13426
+ ...metadata.savedAt === void 0 ? {} : { savedAt: metadata.savedAt },
13427
+ record: toProtocolNetworkRecord(record, {
13428
+ redactSecretHeaders: options.redactSecretHeaders ?? true
13429
+ })
13430
+ };
13233
13431
  }
13234
13432
  addIndexedRequestId(index, key, requestId) {
13235
13433
  const requestIds = index.get(key) ?? /* @__PURE__ */ new Set();
@@ -19964,6 +20162,7 @@ function diffInteractionTraces(left, right) {
19964
20162
 
19965
20163
  // src/sdk/runtime.ts
19966
20164
  var requireForAuthRecipeHook = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
20165
+ var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS = 5e3;
19967
20166
  var OpensteerSessionRuntime = class {
19968
20167
  workspace;
19969
20168
  rootPath;
@@ -19980,12 +20179,11 @@ var OpensteerSessionRuntime = class {
19980
20179
  engine;
19981
20180
  dom;
19982
20181
  computer;
19983
- networkJournal = new NetworkJournal();
20182
+ networkHistory = new NetworkHistory();
19984
20183
  extractionDescriptors;
19985
20184
  sessionRef;
19986
20185
  pageRef;
19987
20186
  runId;
19988
- backgroundNetworkPersistence = /* @__PURE__ */ new Set();
19989
20187
  cookieJars = /* @__PURE__ */ new Map();
19990
20188
  recipeCache = /* @__PURE__ */ new Map();
19991
20189
  ownsEngine = false;
@@ -20347,34 +20545,32 @@ var OpensteerSessionRuntime = class {
20347
20545
  assertValidSemanticOperationInput("page.goto", input);
20348
20546
  const pageRef = await this.ensurePageRef();
20349
20547
  const startedAt = Date.now();
20548
+ let mutationCaptureDiagnostics;
20350
20549
  try {
20351
- const { navigation, state } = await this.runWithOperationTimeout(
20550
+ const { navigation, state } = await this.runMutationCapturedOperation(
20352
20551
  "page.goto",
20552
+ {
20553
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
20554
+ options
20555
+ },
20353
20556
  async (timeout) => {
20354
- const baselineRequestIds = await this.beginMutationCapture(timeout);
20355
- try {
20356
- const navigation2 = await this.navigatePage(
20357
- {
20358
- operation: "page.goto",
20359
- pageRef,
20360
- url: input.url
20361
- },
20362
- timeout
20363
- );
20364
- timeout.throwIfAborted();
20365
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
20366
- return {
20367
- navigation: navigation2,
20368
- state: await timeout.runStep(() => this.readSessionState())
20369
- };
20370
- } catch (error) {
20371
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
20372
- () => void 0
20373
- );
20374
- throw error;
20375
- }
20557
+ const navigation2 = await this.navigatePage(
20558
+ {
20559
+ operation: "page.goto",
20560
+ pageRef,
20561
+ url: input.url
20562
+ },
20563
+ timeout
20564
+ );
20565
+ timeout.throwIfAborted();
20566
+ return {
20567
+ navigation: navigation2,
20568
+ state: await timeout.runStep(() => this.readSessionState())
20569
+ };
20376
20570
  },
20377
- options
20571
+ (diagnostics) => {
20572
+ mutationCaptureDiagnostics = diagnostics;
20573
+ }
20378
20574
  );
20379
20575
  await this.appendTrace({
20380
20576
  operation: "page.goto",
@@ -20383,7 +20579,8 @@ var OpensteerSessionRuntime = class {
20383
20579
  outcome: "ok",
20384
20580
  data: {
20385
20581
  url: input.url,
20386
- state
20582
+ state,
20583
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
20387
20584
  },
20388
20585
  context: buildRuntimeTraceContext({
20389
20586
  sessionRef: this.sessionRef,
@@ -20399,6 +20596,7 @@ var OpensteerSessionRuntime = class {
20399
20596
  completedAt: Date.now(),
20400
20597
  outcome: "error",
20401
20598
  error,
20599
+ data: buildMutationCaptureTraceData(mutationCaptureDiagnostics),
20402
20600
  context: buildRuntimeTraceContext({
20403
20601
  sessionRef: this.sessionRef,
20404
20602
  pageRef
@@ -20411,9 +20609,11 @@ var OpensteerSessionRuntime = class {
20411
20609
  assertValidSemanticOperationInput("page.evaluate", input);
20412
20610
  const pageRef = input.pageRef ?? await this.ensurePageRef();
20413
20611
  const startedAt = Date.now();
20612
+ let mutationCaptureDiagnostics;
20414
20613
  try {
20415
- const output = await this.runWithOperationTimeout(
20614
+ const output = await this.runMutationCapturedOperation(
20416
20615
  "page.evaluate",
20616
+ { options },
20417
20617
  async (timeout) => {
20418
20618
  const remainingMs = timeout.remainingMs();
20419
20619
  const evaluated = await timeout.runStep(
@@ -20429,7 +20629,9 @@ var OpensteerSessionRuntime = class {
20429
20629
  value: toJsonValueOrNull(evaluated.data)
20430
20630
  };
20431
20631
  },
20432
- options
20632
+ (diagnostics) => {
20633
+ mutationCaptureDiagnostics = diagnostics;
20634
+ }
20433
20635
  );
20434
20636
  await this.appendTrace({
20435
20637
  operation: "page.evaluate",
@@ -20438,7 +20640,8 @@ var OpensteerSessionRuntime = class {
20438
20640
  outcome: "ok",
20439
20641
  data: {
20440
20642
  pageRef: output.pageRef,
20441
- value: output.value
20643
+ value: output.value,
20644
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
20442
20645
  },
20443
20646
  context: buildRuntimeTraceContext({
20444
20647
  sessionRef: this.sessionRef,
@@ -20453,6 +20656,7 @@ var OpensteerSessionRuntime = class {
20453
20656
  completedAt: Date.now(),
20454
20657
  outcome: "error",
20455
20658
  error,
20659
+ data: buildMutationCaptureTraceData(mutationCaptureDiagnostics),
20456
20660
  context: buildRuntimeTraceContext({
20457
20661
  sessionRef: this.sessionRef,
20458
20662
  pageRef
@@ -20791,38 +20995,19 @@ var OpensteerSessionRuntime = class {
20791
20995
  }
20792
20996
  async queryNetwork(input = {}, options = {}) {
20793
20997
  assertValidSemanticOperationInput("network.query", input);
20794
- if (input.source !== "saved") {
20795
- await this.ensurePageRef();
20796
- }
20797
20998
  const root = await this.ensureRoot();
20798
20999
  const startedAt = Date.now();
20799
21000
  try {
20800
21001
  const output = await this.runWithOperationTimeout(
20801
21002
  "network.query",
20802
21003
  async (timeout) => {
20803
- if (input.source === "saved") {
20804
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
20805
- return {
20806
- records: await timeout.runStep(
20807
- () => root.registry.savedNetwork.query({
20808
- ...input.recordId === void 0 ? {} : { recordId: input.recordId },
20809
- ...input.requestId === void 0 ? {} : { requestId: input.requestId },
20810
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
20811
- ...input.tag === void 0 ? {} : { tag: input.tag },
20812
- ...input.url === void 0 ? {} : { url: input.url },
20813
- ...input.hostname === void 0 ? {} : { hostname: input.hostname },
20814
- ...input.path === void 0 ? {} : { path: input.path },
20815
- ...input.method === void 0 ? {} : { method: input.method },
20816
- ...input.status === void 0 ? {} : { status: input.status },
20817
- ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType },
20818
- ...input.includeBodies === void 0 ? {} : { includeBodies: input.includeBodies },
20819
- ...input.limit === void 0 ? {} : { limit: input.limit }
20820
- })
20821
- )
20822
- };
20823
- }
21004
+ await this.syncPersistedNetworkSelection(timeout, input, {
21005
+ includeBodies: input.includeBodies ?? false
21006
+ });
20824
21007
  return {
20825
- records: await this.queryLiveNetwork(input, timeout)
21008
+ records: await timeout.runStep(
21009
+ () => root.registry.savedNetwork.query(this.toSavedNetworkQueryInput(input))
21010
+ )
20826
21011
  };
20827
21012
  },
20828
21013
  options
@@ -20833,7 +21018,6 @@ var OpensteerSessionRuntime = class {
20833
21018
  completedAt: Date.now(),
20834
21019
  outcome: "ok",
20835
21020
  data: {
20836
- source: input.source ?? "live",
20837
21021
  includeBodies: input.includeBodies ?? false,
20838
21022
  limit: input.limit ?? 50,
20839
21023
  count: output.records.length
@@ -20859,56 +21043,42 @@ var OpensteerSessionRuntime = class {
20859
21043
  throw error;
20860
21044
  }
20861
21045
  }
20862
- async saveNetwork(input, options = {}) {
20863
- assertValidSemanticOperationInput("network.save", input);
20864
- await this.ensurePageRef();
21046
+ async tagNetwork(input, options = {}) {
21047
+ assertValidSemanticOperationInput("network.tag", input);
20865
21048
  const root = await this.ensureRoot();
21049
+ const filter = this.toQueryInputFromTagInput(input);
21050
+ const savedFilter = this.toSavedNetworkQueryInput(filter);
20866
21051
  const startedAt = Date.now();
20867
21052
  try {
20868
21053
  const output = await this.runWithOperationTimeout(
20869
- "network.save",
21054
+ "network.tag",
20870
21055
  async (timeout) => {
20871
- const records = await this.queryLiveNetwork(
20872
- {
20873
- includeBodies: true,
20874
- source: "live",
20875
- ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
20876
- ...input.recordId === void 0 ? {} : { recordId: input.recordId },
20877
- ...input.requestId === void 0 ? {} : { requestId: input.requestId },
20878
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
20879
- ...input.url === void 0 ? {} : { url: input.url },
20880
- ...input.hostname === void 0 ? {} : { hostname: input.hostname },
20881
- ...input.path === void 0 ? {} : { path: input.path },
20882
- ...input.method === void 0 ? {} : { method: input.method },
20883
- ...input.status === void 0 ? {} : { status: input.status },
20884
- ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
20885
- },
20886
- timeout,
20887
- { ignoreLimit: true, redactSecretHeaders: false }
20888
- );
20889
- this.networkJournal.addTag(records, input.tag);
21056
+ const records = await this.syncPersistedNetworkSelection(timeout, filter, {
21057
+ includeBodies: false
21058
+ });
21059
+ this.networkHistory.addTag(records, input.tag);
20890
21060
  return {
20891
- savedCount: await timeout.runStep(
20892
- () => root.registry.savedNetwork.save(records, input.tag)
21061
+ taggedCount: await timeout.runStep(
21062
+ () => root.registry.savedNetwork.tagByFilter(savedFilter, input.tag)
20893
21063
  )
20894
21064
  };
20895
21065
  },
20896
21066
  options
20897
21067
  );
20898
21068
  await this.appendTrace({
20899
- operation: "network.save",
21069
+ operation: "network.tag",
20900
21070
  startedAt,
20901
21071
  completedAt: Date.now(),
20902
21072
  outcome: "ok",
20903
21073
  data: {
20904
21074
  tag: input.tag,
20905
- savedCount: output.savedCount
21075
+ taggedCount: output.taggedCount
20906
21076
  }
20907
21077
  });
20908
21078
  return output;
20909
21079
  } catch (error) {
20910
21080
  await this.appendTrace({
20911
- operation: "network.save",
21081
+ operation: "network.tag",
20912
21082
  startedAt,
20913
21083
  completedAt: Date.now(),
20914
21084
  outcome: "error",
@@ -20925,7 +21095,31 @@ var OpensteerSessionRuntime = class {
20925
21095
  const output = await this.runWithOperationTimeout(
20926
21096
  "network.clear",
20927
21097
  async (timeout) => {
20928
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
21098
+ if (this.sessionRef !== void 0) {
21099
+ if (input.capture !== void 0 || input.tag !== void 0) {
21100
+ const records = await this.queryLiveNetwork(
21101
+ {
21102
+ ...input.capture === void 0 ? {} : { capture: input.capture },
21103
+ ...input.tag === void 0 ? {} : { tag: input.tag }
21104
+ },
21105
+ timeout,
21106
+ {
21107
+ ignoreLimit: true
21108
+ }
21109
+ );
21110
+ this.networkHistory.tombstoneRequestIds(
21111
+ records.map((record) => record.record.requestId)
21112
+ );
21113
+ } else {
21114
+ const liveRequestIds = await this.readLiveRequestIds(timeout, {
21115
+ includeCurrentPageOnly: false
21116
+ });
21117
+ this.networkHistory.tombstoneRequestIds(liveRequestIds);
21118
+ }
21119
+ }
21120
+ if (input.capture === void 0 && input.tag === void 0) {
21121
+ this.networkHistory.tombstoneRequestIds(this.networkHistory.getKnownRequestIds());
21122
+ }
20929
21123
  return {
20930
21124
  clearedCount: await timeout.runStep(() => root.registry.savedNetwork.clear(input))
20931
21125
  };
@@ -20938,6 +21132,7 @@ var OpensteerSessionRuntime = class {
20938
21132
  completedAt: Date.now(),
20939
21133
  outcome: "ok",
20940
21134
  data: {
21135
+ ...input.capture === void 0 ? {} : { capture: input.capture },
20941
21136
  ...input.tag === void 0 ? {} : { tag: input.tag },
20942
21137
  clearedCount: output.clearedCount
20943
21138
  }
@@ -21642,7 +21837,6 @@ var OpensteerSessionRuntime = class {
21642
21837
  });
21643
21838
  const networkRecords = await this.queryLiveNetwork(
21644
21839
  {
21645
- source: "live",
21646
21840
  pageRef,
21647
21841
  ...input.network?.url === void 0 ? {} : { url: input.network.url },
21648
21842
  ...input.network?.hostname === void 0 ? {} : { hostname: input.network.hostname },
@@ -21658,7 +21852,7 @@ var OpensteerSessionRuntime = class {
21658
21852
  );
21659
21853
  const persistedNetwork = filterReverseObservationWindow(
21660
21854
  networkRecords.filter(isReverseRelevantNetworkRecord),
21661
- this.networkJournal,
21855
+ this.networkHistory,
21662
21856
  input.captureWindowMs
21663
21857
  );
21664
21858
  const fallbackSavedNetwork = persistedNetwork.length === 0 ? (await root.registry.savedNetwork.query({
@@ -21673,7 +21867,10 @@ var OpensteerSessionRuntime = class {
21673
21867
  const observationId = `observation:${crypto.randomUUID()}`;
21674
21868
  const networkTag = `reverse-case:${caseRecord.id}:${observationId}`;
21675
21869
  if (observationNetwork.length > 0) {
21676
- await root.registry.savedNetwork.save(observationNetwork, networkTag);
21870
+ await root.registry.savedNetwork.save(observationNetwork, {
21871
+ tag: networkTag,
21872
+ bodyWriteMode: input.network?.includeBodies === false ? "metadata-only" : "authoritative"
21873
+ });
21677
21874
  }
21678
21875
  const scriptArtifactIds = input.includeScripts === false ? [] : (await this.captureScriptsInternal(
21679
21876
  pageRef,
@@ -21769,7 +21966,7 @@ var OpensteerSessionRuntime = class {
21769
21966
  includeBodies: true,
21770
21967
  redactSecretHeaders: false
21771
21968
  }),
21772
- observedAt: this.networkJournal.getObservedAt(recordId)
21969
+ observedAt: this.networkHistory.getObservedAt(recordId)
21773
21970
  }))
21774
21971
  );
21775
21972
  const clusteredRecords = observationRecords.map((entry) => {
@@ -22117,7 +22314,9 @@ var OpensteerSessionRuntime = class {
22117
22314
  };
22118
22315
  }
22119
22316
  const bindings = /* @__PURE__ */ new Map();
22120
- const baselineRequestIds = await this.beginMutationCapture(timeout);
22317
+ const baselineRequestIds = await this.readLiveRequestIds(timeout, {
22318
+ includeCurrentPageOnly: true
22319
+ });
22121
22320
  const pageRef = explicitPageRef ?? await this.ensurePageRef();
22122
22321
  const validatorMap = new Map(
22123
22322
  packageRecord.payload.validators.map((validator) => [validator.id, validator])
@@ -22709,7 +22908,10 @@ var OpensteerSessionRuntime = class {
22709
22908
  timeout.signal
22710
22909
  )).filter((record) => !baselineRequestIds.has(record.record.requestId));
22711
22910
  if (deltaRecords.length > 0) {
22712
- await root.registry.savedNetwork.save(deltaRecords, `interaction:${pageRef}`);
22911
+ await root.registry.savedNetwork.save(deltaRecords, {
22912
+ tag: `interaction:${pageRef}`,
22913
+ bodyWriteMode: "authoritative"
22914
+ });
22713
22915
  }
22714
22916
  const trace = await root.registry.interactionTraces.write({
22715
22917
  key: input.key ?? buildInteractionTraceKey(pageInfo.url),
@@ -23052,7 +23254,7 @@ var OpensteerSessionRuntime = class {
23052
23254
  includeBodies: true
23053
23255
  });
23054
23256
  const inferred = inferRequestPlanFromNetworkRecord(source, input, {
23055
- ...this.networkJournal.getObservedAt(source.recordId) === void 0 ? {} : { observedAt: this.networkJournal.getObservedAt(source.recordId) }
23257
+ ...this.networkHistory.getObservedAt(source.recordId) === void 0 ? {} : { observedAt: this.networkHistory.getObservedAt(source.recordId) }
23056
23258
  });
23057
23259
  return timeout.runStep(
23058
23260
  () => root.registry.requestPlans.write({
@@ -23786,33 +23988,38 @@ var OpensteerSessionRuntime = class {
23786
23988
  assertValidSemanticOperationInput("computer.execute", input);
23787
23989
  const pageRef = await this.ensurePageRef();
23788
23990
  const startedAt = Date.now();
23991
+ let mutationCaptureDiagnostics;
23992
+ let boundaryDiagnostics;
23789
23993
  try {
23790
- const { artifacts, output } = await this.runWithOperationTimeout(
23994
+ const { artifacts, output } = await this.runMutationCapturedOperation(
23791
23995
  "computer.execute",
23996
+ {
23997
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
23998
+ options
23999
+ },
23792
24000
  async (timeout) => {
23793
- const baselineRequestIds = await this.beginMutationCapture(timeout);
23794
24001
  try {
23795
24002
  const output2 = await this.requireComputer().execute({
23796
24003
  pageRef,
23797
24004
  input,
23798
24005
  timeout
23799
24006
  });
24007
+ boundaryDiagnostics = takeActionBoundaryDiagnostics(timeout.signal);
23800
24008
  timeout.throwIfAborted();
23801
24009
  this.pageRef = output2.pageRef;
23802
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
23803
24010
  const artifacts2 = await this.persistComputerArtifacts(output2, timeout);
23804
24011
  return {
23805
24012
  artifacts: { manifests: artifacts2.manifests },
23806
24013
  output: artifacts2.output
23807
24014
  };
23808
24015
  } catch (error) {
23809
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
23810
- () => void 0
23811
- );
24016
+ boundaryDiagnostics ??= takeActionBoundaryDiagnostics(timeout.signal);
23812
24017
  throw error;
23813
24018
  }
23814
24019
  },
23815
- options
24020
+ (diagnostics) => {
24021
+ mutationCaptureDiagnostics = diagnostics;
24022
+ }
23816
24023
  );
23817
24024
  await this.appendTrace({
23818
24025
  operation: "computer.execute",
@@ -23828,6 +24035,8 @@ var OpensteerSessionRuntime = class {
23828
24035
  nativeViewport: output.nativeViewport,
23829
24036
  displayScale: output.displayScale,
23830
24037
  timing: output.timing,
24038
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
24039
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics),
23831
24040
  ...output.trace === void 0 ? {} : { trace: output.trace }
23832
24041
  },
23833
24042
  context: buildRuntimeTraceContext({
@@ -23846,6 +24055,10 @@ var OpensteerSessionRuntime = class {
23846
24055
  completedAt: Date.now(),
23847
24056
  outcome: "error",
23848
24057
  error,
24058
+ data: {
24059
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
24060
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
24061
+ },
23849
24062
  context: buildRuntimeTraceContext({
23850
24063
  sessionRef: this.sessionRef,
23851
24064
  pageRef: this.pageRef
@@ -23864,7 +24077,7 @@ var OpensteerSessionRuntime = class {
23864
24077
  await this.runWithOperationTimeout(
23865
24078
  "session.close",
23866
24079
  async (timeout) => {
23867
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
24080
+ await timeout.runStep(() => this.flushPersistedNetworkHistory());
23868
24081
  if (engine === void 0) {
23869
24082
  return;
23870
24083
  }
@@ -23933,10 +24146,7 @@ var OpensteerSessionRuntime = class {
23933
24146
  }
23934
24147
  async disconnect() {
23935
24148
  try {
23936
- await this.flushBackgroundNetworkPersistence();
23937
- if (this.sessionRef !== void 0 && this.pageRef !== void 0) {
23938
- await this.saveNetwork({ tag: "auto" }).catch(() => void 0);
23939
- }
24149
+ await this.flushPersistedNetworkHistory();
23940
24150
  } finally {
23941
24151
  await this.resetRuntimeState({
23942
24152
  disposeEngine: true
@@ -23952,33 +24162,38 @@ var OpensteerSessionRuntime = class {
23952
24162
  async runDomAction(operation, input, executor, options = {}) {
23953
24163
  const pageRef = await this.ensurePageRef();
23954
24164
  const startedAt = Date.now();
24165
+ let mutationCaptureDiagnostics;
24166
+ let boundaryDiagnostics;
23955
24167
  try {
23956
- const { executed, preparedTarget } = await this.runWithOperationTimeout(
24168
+ const { executed, preparedTarget } = await this.runMutationCapturedOperation(
23957
24169
  operation,
24170
+ {
24171
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
24172
+ options
24173
+ },
23958
24174
  async (timeout) => {
23959
- const baselineRequestIds = await this.beginMutationCapture(timeout);
24175
+ const preparedTarget2 = await this.prepareDomTarget(
24176
+ pageRef,
24177
+ operation,
24178
+ input.target,
24179
+ input.persistAsDescription,
24180
+ timeout
24181
+ );
23960
24182
  try {
23961
- const preparedTarget2 = await this.prepareDomTarget(
23962
- pageRef,
23963
- operation,
23964
- input.target,
23965
- input.persistAsDescription,
23966
- timeout
23967
- );
23968
24183
  const executed2 = await executor(pageRef, preparedTarget2.target, timeout);
23969
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
24184
+ boundaryDiagnostics = takeActionBoundaryDiagnostics(timeout.signal);
23970
24185
  return {
23971
24186
  executed: executed2,
23972
24187
  preparedTarget: preparedTarget2
23973
24188
  };
23974
24189
  } catch (error) {
23975
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
23976
- () => void 0
23977
- );
24190
+ boundaryDiagnostics ??= takeActionBoundaryDiagnostics(timeout.signal);
23978
24191
  throw error;
23979
24192
  }
23980
24193
  },
23981
- options
24194
+ (diagnostics) => {
24195
+ mutationCaptureDiagnostics = diagnostics;
24196
+ }
23982
24197
  );
23983
24198
  const output = toOpensteerActionResult(executed.result, preparedTarget.persistedDescription);
23984
24199
  await this.appendTrace({
@@ -23989,7 +24204,9 @@ var OpensteerSessionRuntime = class {
23989
24204
  data: {
23990
24205
  target: output.target,
23991
24206
  ...output.point === void 0 ? {} : { point: output.point },
23992
- ...output.persistedDescription === void 0 ? {} : { persistedDescription: output.persistedDescription }
24207
+ ...output.persistedDescription === void 0 ? {} : { persistedDescription: output.persistedDescription },
24208
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
24209
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
23993
24210
  },
23994
24211
  context: buildRuntimeTraceContext({
23995
24212
  sessionRef: this.sessionRef,
@@ -24007,6 +24224,10 @@ var OpensteerSessionRuntime = class {
24007
24224
  completedAt: Date.now(),
24008
24225
  outcome: "error",
24009
24226
  error,
24227
+ data: {
24228
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
24229
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
24230
+ },
24010
24231
  context: buildRuntimeTraceContext({
24011
24232
  sessionRef: this.sessionRef,
24012
24233
  pageRef
@@ -24028,7 +24249,10 @@ var OpensteerSessionRuntime = class {
24028
24249
  };
24029
24250
  }
24030
24251
  if (target.kind === "element") {
24031
- const elementTarget = { kind: "selector", selector: `[c="${String(target.element)}"]` };
24252
+ const elementTarget = {
24253
+ kind: "selector",
24254
+ selector: `[c="${String(target.element)}"]`
24255
+ };
24032
24256
  const resolved2 = await timeout.runStep(
24033
24257
  () => this.requireDom().resolveTarget({
24034
24258
  pageRef,
@@ -24091,11 +24315,11 @@ var OpensteerSessionRuntime = class {
24091
24315
  };
24092
24316
  }
24093
24317
  async queryLiveNetwork(input, timeout, options = {}) {
24094
- const requestIds = resolveLiveQueryRequestIds(input, this.networkJournal);
24318
+ const requestIds = resolveLiveQueryRequestIds(input, this.networkHistory);
24095
24319
  if (requestIds !== void 0 && requestIds.length === 0) {
24096
24320
  return [];
24097
24321
  }
24098
- const pageRef = resolveLiveQueryPageRef(input, this.pageRef, requestIds, this.networkJournal);
24322
+ const pageRef = resolveLiveQueryPageRef(input, this.pageRef, requestIds, this.networkHistory);
24099
24323
  const includeCurrentPageOnly = pageRef === void 0 && input.recordId === void 0;
24100
24324
  const metadataRecords = await timeout.runStep(
24101
24325
  () => this.readLiveNetworkRecords(
@@ -24113,7 +24337,7 @@ var OpensteerSessionRuntime = class {
24113
24337
  const filtered = filterNetworkQueryRecords(metadataRecords, {
24114
24338
  ...input.recordId === void 0 ? {} : { recordId: input.recordId },
24115
24339
  ...input.requestId === void 0 ? {} : { requestId: input.requestId },
24116
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
24340
+ ...input.capture === void 0 ? {} : { capture: input.capture },
24117
24341
  ...input.tag === void 0 ? {} : { tag: input.tag },
24118
24342
  ...input.url === void 0 ? {} : { url: input.url },
24119
24343
  ...input.hostname === void 0 ? {} : { hostname: input.hostname },
@@ -24122,7 +24346,7 @@ var OpensteerSessionRuntime = class {
24122
24346
  ...input.status === void 0 ? {} : { status: input.status },
24123
24347
  ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
24124
24348
  });
24125
- const sorted = sortLiveNetworkRecords(filtered, this.networkJournal);
24349
+ const sorted = sortLiveNetworkRecords(filtered, this.networkHistory);
24126
24350
  const limit = options.ignoreLimit ? sorted.length : Math.max(1, Math.min(input.limit ?? 50, 200));
24127
24351
  const limited = sorted.slice(0, limit);
24128
24352
  if (!(input.includeBodies ?? false) || limited.length === 0) {
@@ -24319,40 +24543,95 @@ var OpensteerSessionRuntime = class {
24319
24543
  artifactId: manifest.artifactId
24320
24544
  };
24321
24545
  }
24322
- beginMutationCapture(timeout) {
24323
- return this.readLiveRequestIds(timeout, {
24324
- includeCurrentPageOnly: true
24325
- });
24326
- }
24327
- async completeMutationCapture(timeout, baselineRequestIds, networkTag) {
24328
- const records = await timeout.runStep(
24329
- () => this.readLiveNetworkRecords(
24330
- {
24331
- includeBodies: false,
24332
- includeCurrentPageOnly: true
24546
+ async runMutationCapturedOperation(operation, input, execute, onFinalized) {
24547
+ let plan;
24548
+ try {
24549
+ const result = await this.runWithOperationTimeout(
24550
+ operation,
24551
+ async (timeout) => {
24552
+ plan = await this.beginMutationCapture(timeout, input.captureNetwork);
24553
+ return execute(timeout);
24333
24554
  },
24334
- timeout.signal
24335
- )
24555
+ input.options
24556
+ );
24557
+ const diagnostics = await this.finalizeMutationCaptureBestEffort(plan);
24558
+ onFinalized?.(diagnostics);
24559
+ return result;
24560
+ } catch (error) {
24561
+ const diagnostics = await this.finalizeMutationCaptureBestEffort(plan);
24562
+ onFinalized?.(diagnostics);
24563
+ throw error;
24564
+ }
24565
+ }
24566
+ async beginMutationCapture(timeout, capture) {
24567
+ if (capture === void 0) {
24568
+ return void 0;
24569
+ }
24570
+ return {
24571
+ baselineRequestIds: await this.readLiveRequestIds(timeout, {
24572
+ includeCurrentPageOnly: true
24573
+ }),
24574
+ capture
24575
+ };
24576
+ }
24577
+ async finalizeMutationCaptureBestEffort(plan) {
24578
+ if (plan === void 0) {
24579
+ return {};
24580
+ }
24581
+ try {
24582
+ await withDetachedTimeoutSignal(MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS, async (signal) => {
24583
+ await this.completeMutationCaptureWithSignal(signal, plan);
24584
+ });
24585
+ return {};
24586
+ } catch (error) {
24587
+ return {
24588
+ finalizeError: normalizeOpensteerError(error)
24589
+ };
24590
+ }
24591
+ }
24592
+ async completeMutationCaptureWithSignal(signal, plan) {
24593
+ const records = await this.readLiveNetworkRecords(
24594
+ {
24595
+ includeBodies: false,
24596
+ includeCurrentPageOnly: true
24597
+ },
24598
+ signal
24336
24599
  );
24337
- const delta = records.filter((record) => !baselineRequestIds.has(record.record.requestId));
24600
+ const delta = records.filter((record) => !plan.baselineRequestIds.has(record.record.requestId));
24338
24601
  if (delta.length === 0) {
24339
24602
  return;
24340
24603
  }
24341
- this.networkJournal.assignActionId(delta, `action:${crypto.randomUUID()}`);
24342
- if (networkTag === void 0) {
24343
- return;
24344
- }
24345
- this.networkJournal.addTag(delta, networkTag);
24346
- this.scheduleBackgroundNetworkSaveByRequestIds(
24604
+ this.networkHistory.assignCapture(delta, plan.capture);
24605
+ await this.persistLiveRequestIdsWithSignal(
24347
24606
  delta.map((record) => record.record.requestId),
24348
- networkTag
24607
+ signal,
24608
+ {
24609
+ includeCurrentPageOnly: true
24610
+ }
24349
24611
  );
24350
24612
  }
24351
24613
  async resolveNetworkRecordByRecordId(recordId, timeout, options) {
24352
24614
  const root = await this.ensureRoot();
24615
+ await this.syncPersistedNetworkSelection(
24616
+ timeout,
24617
+ {
24618
+ recordId,
24619
+ includeBodies: options.includeBodies
24620
+ },
24621
+ {
24622
+ includeBodies: options.includeBodies
24623
+ }
24624
+ );
24625
+ const saved = await timeout.runStep(
24626
+ () => root.registry.savedNetwork.getByRecordId(recordId, {
24627
+ includeBodies: options.includeBodies
24628
+ })
24629
+ );
24630
+ if (saved) {
24631
+ return saved;
24632
+ }
24353
24633
  const live = await this.queryLiveNetwork(
24354
24634
  {
24355
- source: "live",
24356
24635
  recordId,
24357
24636
  includeBodies: options.includeBodies,
24358
24637
  limit: 1
@@ -24363,24 +24642,15 @@ var OpensteerSessionRuntime = class {
24363
24642
  ...options.redactSecretHeaders === void 0 ? {} : { redactSecretHeaders: options.redactSecretHeaders }
24364
24643
  }
24365
24644
  );
24366
- if (live.length > 0) {
24645
+ if (live[0] !== void 0) {
24367
24646
  return live[0];
24368
24647
  }
24369
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
24370
- const saved = await timeout.runStep(
24371
- () => root.registry.savedNetwork.getByRecordId(recordId, {
24372
- includeBodies: options.includeBodies
24373
- })
24374
- );
24375
- if (!saved) {
24376
- throw new OpensteerProtocolError("not-found", `network record ${recordId} was not found`, {
24377
- details: {
24378
- recordId,
24379
- kind: "network-record"
24380
- }
24381
- });
24382
- }
24383
- return saved;
24648
+ throw new OpensteerProtocolError("not-found", `network record ${recordId} was not found`, {
24649
+ details: {
24650
+ recordId,
24651
+ kind: "network-record"
24652
+ }
24653
+ });
24384
24654
  }
24385
24655
  resolveCurrentStateSource() {
24386
24656
  const ownership = this.sessionInfoBase.provider?.ownership;
@@ -24620,7 +24890,6 @@ var OpensteerSessionRuntime = class {
24620
24890
  timeout.throwIfAborted();
24621
24891
  const records = await this.queryLiveNetwork(
24622
24892
  {
24623
- source: "live",
24624
24893
  pageRef,
24625
24894
  url,
24626
24895
  method,
@@ -24651,7 +24920,6 @@ var OpensteerSessionRuntime = class {
24651
24920
  timeout.throwIfAborted();
24652
24921
  const records = await this.queryLiveNetwork(
24653
24922
  {
24654
- source: "live",
24655
24923
  pageRef,
24656
24924
  ...filter.url === void 0 ? {} : { url: filter.url },
24657
24925
  ...filter.host === void 0 ? {} : { hostname: filter.host },
@@ -24717,12 +24985,12 @@ var OpensteerSessionRuntime = class {
24717
24985
  };
24718
24986
  }
24719
24987
  }
24720
- async readLiveNetworkRecords(input, signal) {
24988
+ async readBrowserNetworkRecords(input, signal) {
24721
24989
  const sessionRef = this.sessionRef;
24722
24990
  if (!sessionRef) {
24723
24991
  throw new Error("Opensteer session is not initialized");
24724
24992
  }
24725
- const records = await this.requireEngine().getNetworkRecords({
24993
+ return this.requireEngine().getNetworkRecords({
24726
24994
  sessionRef,
24727
24995
  ...input.includeCurrentPageOnly === false || input.pageRef !== void 0 ? input.pageRef === void 0 ? {} : { pageRef: input.pageRef } : this.pageRef === void 0 ? {} : { pageRef: this.pageRef },
24728
24996
  ...input.requestIds === void 0 ? {} : { requestIds: input.requestIds },
@@ -24735,10 +25003,103 @@ var OpensteerSessionRuntime = class {
24735
25003
  includeBodies: input.includeBodies,
24736
25004
  signal
24737
25005
  });
24738
- return this.networkJournal.sync(records, {
25006
+ }
25007
+ async readLiveNetworkRecords(input, signal) {
25008
+ const records = await this.readBrowserNetworkRecords(input, signal);
25009
+ return this.networkHistory.materialize(records, {
24739
25010
  redactSecretHeaders: input.redactSecretHeaders ?? true
24740
25011
  });
24741
25012
  }
25013
+ async persistLiveRequestIds(requestIds, timeout, options) {
25014
+ return timeout.runStep(
25015
+ () => this.persistLiveRequestIdsWithSignal(requestIds, timeout.signal, options)
25016
+ );
25017
+ }
25018
+ async persistLiveRequestIdsWithSignal(requestIds, signal, options) {
25019
+ if (requestIds.length === 0) {
25020
+ return [];
25021
+ }
25022
+ const root = await this.ensureRoot();
25023
+ const browserRecords = await this.readBrowserNetworkRecords(
25024
+ {
25025
+ includeBodies: true,
25026
+ includeCurrentPageOnly: options.includeCurrentPageOnly,
25027
+ ...options.pageRef === void 0 ? {} : { pageRef: options.pageRef },
25028
+ requestIds
25029
+ },
25030
+ signal
25031
+ );
25032
+ return this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
25033
+ bodyWriteMode: "authoritative",
25034
+ redactSecretHeaders: false
25035
+ });
25036
+ }
25037
+ async syncPersistedNetworkSelection(timeout, input, options) {
25038
+ if (this.sessionRef === void 0) {
25039
+ return [];
25040
+ }
25041
+ const requestIds = resolveLiveQueryRequestIds(input, this.networkHistory);
25042
+ if (requestIds !== void 0 && requestIds.length === 0) {
25043
+ return [];
25044
+ }
25045
+ const pageRef = resolveLiveQueryPageRef(input, this.pageRef, requestIds, this.networkHistory);
25046
+ const includeCurrentPageOnly = pageRef === void 0 && input.recordId === void 0;
25047
+ const browserRecords = await timeout.runStep(
25048
+ () => this.readBrowserNetworkRecords(
25049
+ {
25050
+ ...pageRef === void 0 ? {} : { pageRef },
25051
+ ...requestIds === void 0 ? {} : { requestIds },
25052
+ ...input.url === void 0 ? {} : { url: input.url },
25053
+ ...input.hostname === void 0 ? {} : { hostname: input.hostname },
25054
+ ...input.path === void 0 ? {} : { path: input.path },
25055
+ ...input.method === void 0 ? {} : { method: input.method },
25056
+ ...input.status === void 0 ? {} : { status: input.status },
25057
+ ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType },
25058
+ includeBodies: options.includeBodies,
25059
+ includeCurrentPageOnly
25060
+ },
25061
+ timeout.signal
25062
+ )
25063
+ );
25064
+ const root = await this.ensureRoot();
25065
+ return timeout.runStep(
25066
+ () => this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
25067
+ bodyWriteMode: options.includeBodies ? "authoritative" : "metadata-only",
25068
+ redactSecretHeaders: false
25069
+ })
25070
+ );
25071
+ }
25072
+ toSavedNetworkQueryInput(input) {
25073
+ return {
25074
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
25075
+ ...input.recordId === void 0 ? {} : { recordId: input.recordId },
25076
+ ...input.requestId === void 0 ? {} : { requestId: input.requestId },
25077
+ ...input.capture === void 0 ? {} : { capture: input.capture },
25078
+ ...input.tag === void 0 ? {} : { tag: input.tag },
25079
+ ...input.url === void 0 ? {} : { url: input.url },
25080
+ ...input.hostname === void 0 ? {} : { hostname: input.hostname },
25081
+ ...input.path === void 0 ? {} : { path: input.path },
25082
+ ...input.method === void 0 ? {} : { method: input.method },
25083
+ ...input.status === void 0 ? {} : { status: input.status },
25084
+ ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType },
25085
+ ...input.includeBodies === void 0 ? {} : { includeBodies: input.includeBodies },
25086
+ ...input.limit === void 0 ? {} : { limit: input.limit }
25087
+ };
25088
+ }
25089
+ toQueryInputFromTagInput(input) {
25090
+ return {
25091
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
25092
+ ...input.recordId === void 0 ? {} : { recordId: input.recordId },
25093
+ ...input.requestId === void 0 ? {} : { requestId: input.requestId },
25094
+ ...input.capture === void 0 ? {} : { capture: input.capture },
25095
+ ...input.url === void 0 ? {} : { url: input.url },
25096
+ ...input.hostname === void 0 ? {} : { hostname: input.hostname },
25097
+ ...input.path === void 0 ? {} : { path: input.path },
25098
+ ...input.method === void 0 ? {} : { method: input.method },
25099
+ ...input.status === void 0 ? {} : { status: input.status },
25100
+ ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
25101
+ };
25102
+ }
24742
25103
  async readLiveRequestIds(timeout, options) {
24743
25104
  const records = await timeout.runStep(
24744
25105
  () => this.readLiveNetworkRecords(
@@ -24762,7 +25123,17 @@ var OpensteerSessionRuntime = class {
24762
25123
  )
24763
25124
  );
24764
25125
  const delta = records.filter((record) => !baselineRequestIds.has(record.record.requestId));
24765
- return sortLiveNetworkRecords(delta, this.networkJournal)[0]?.recordId;
25126
+ if (delta.length === 0) {
25127
+ return void 0;
25128
+ }
25129
+ await this.persistLiveRequestIds(
25130
+ delta.map((record) => record.record.requestId),
25131
+ timeout,
25132
+ {
25133
+ includeCurrentPageOnly: options.includeCurrentPageOnly
25134
+ }
25135
+ );
25136
+ return sortLiveNetworkRecords(delta, this.networkHistory)[0]?.recordId;
24766
25137
  }
24767
25138
  async executeTransportRequestWithJournal(request, timeout, sessionRef) {
24768
25139
  const baselineRequestIds = await this.readLiveRequestIds(timeout, {
@@ -25046,7 +25417,6 @@ var OpensteerSessionRuntime = class {
25046
25417
  const syntheticSessionRef = binding?.sessionRef ?? createSessionRef(`${transportLabel}-${this.workspace}`);
25047
25418
  const record = {
25048
25419
  recordId,
25049
- source: "saved",
25050
25420
  savedAt: now,
25051
25421
  record: {
25052
25422
  kind: "http",
@@ -25068,7 +25438,10 @@ var OpensteerSessionRuntime = class {
25068
25438
  ...response.body === void 0 ? {} : { responseBody: toProtocolBodyPayload(response.body) }
25069
25439
  }
25070
25440
  };
25071
- await root.registry.savedNetwork.save([record], tag);
25441
+ await root.registry.savedNetwork.save([record], {
25442
+ bodyWriteMode: "authoritative",
25443
+ ...tag === void 0 ? {} : { tag }
25444
+ });
25072
25445
  return recordId;
25073
25446
  }
25074
25447
  async executeResolvedRequestPlan(plan, input, timeout, binding) {
@@ -25441,7 +25814,6 @@ var OpensteerSessionRuntime = class {
25441
25814
  const record = await pollUntilResult(timeout, async () => {
25442
25815
  const matches = await this.queryLiveNetwork(
25443
25816
  {
25444
- source: "live",
25445
25817
  ...step.url === void 0 ? {} : { url: interpolateTemplate(step.url, variables) },
25446
25818
  ...step.hostname === void 0 ? {} : { hostname: interpolateTemplate(step.hostname, variables) },
25447
25819
  ...step.path === void 0 ? {} : { path: interpolateTemplate(step.path, variables) },
@@ -25899,37 +26271,7 @@ var OpensteerSessionRuntime = class {
25899
26271
  const pageUrl = step.pageUrl === void 0 ? void 0 : interpolateTemplate(step.pageUrl, variables);
25900
26272
  return snapshot.sessionStorage?.filter((entry) => entry.origin === origin).find((entry) => pageUrl === void 0 || entry.origin === new URL(pageUrl).origin)?.entries.find((entry) => entry.key === key)?.value;
25901
26273
  }
25902
- scheduleBackgroundNetworkSaveByRequestIds(requestIds, tag) {
25903
- const task = (async () => {
25904
- const root = await this.ensureRoot();
25905
- const requestIdSet = new Set(requestIds);
25906
- const records = await this.readLiveNetworkRecords(
25907
- {
25908
- includeBodies: true,
25909
- includeCurrentPageOnly: false,
25910
- ...this.pageRef === void 0 ? {} : { pageRef: this.pageRef },
25911
- requestIds,
25912
- redactSecretHeaders: false
25913
- },
25914
- new AbortController().signal
25915
- );
25916
- const filtered = records.filter((record) => requestIdSet.has(record.record.requestId));
25917
- if (filtered.length === 0) {
25918
- return;
25919
- }
25920
- await root.registry.savedNetwork.save(filtered, tag);
25921
- })();
25922
- this.backgroundNetworkPersistence.add(task);
25923
- task.finally(() => {
25924
- this.backgroundNetworkPersistence.delete(task);
25925
- });
25926
- void task.catch(() => void 0);
25927
- }
25928
- async flushBackgroundNetworkPersistence() {
25929
- if (this.backgroundNetworkPersistence.size === 0) {
25930
- return;
25931
- }
25932
- await Promise.all([...this.backgroundNetworkPersistence]);
26274
+ async flushPersistedNetworkHistory() {
25933
26275
  }
25934
26276
  toDomTargetRef(target) {
25935
26277
  if (target.kind === "description") {
@@ -25964,7 +26306,9 @@ var OpensteerSessionRuntime = class {
25964
26306
  ...workspace.registry,
25965
26307
  ...overrides.requestPlans === void 0 ? {} : { requestPlans: overrides.requestPlans },
25966
26308
  ...overrides.authRecipes === void 0 ? {} : { authRecipes: overrides.authRecipes },
25967
- ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes }
26309
+ ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes },
26310
+ ...overrides.reverseCases === void 0 ? {} : { reverseCases: overrides.reverseCases },
26311
+ ...overrides.reversePackages === void 0 ? {} : { reversePackages: overrides.reversePackages }
25968
26312
  }
25969
26313
  };
25970
26314
  } else {
@@ -26221,8 +26565,7 @@ var OpensteerSessionRuntime = class {
26221
26565
  }
26222
26566
  async resetRuntimeState(options) {
26223
26567
  const engine = this.engine;
26224
- this.networkJournal.clear();
26225
- this.backgroundNetworkPersistence.clear();
26568
+ this.networkHistory.clear();
26226
26569
  this.sessionRef = void 0;
26227
26570
  this.pageRef = void 0;
26228
26571
  this.runId = void 0;
@@ -26298,10 +26641,10 @@ function buildEngineNetworkRecordFilters(input) {
26298
26641
  ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
26299
26642
  };
26300
26643
  }
26301
- function resolveLiveQueryRequestIds(input, journal) {
26644
+ function resolveLiveQueryRequestIds(input, history) {
26302
26645
  const requestIdCandidates = [];
26303
26646
  if (input.recordId !== void 0) {
26304
- const requestId = journal.getRequestId(input.recordId);
26647
+ const requestId = history.getRequestId(input.recordId);
26305
26648
  if (requestId === void 0) {
26306
26649
  return [];
26307
26650
  }
@@ -26310,25 +26653,25 @@ function resolveLiveQueryRequestIds(input, journal) {
26310
26653
  if (input.requestId !== void 0) {
26311
26654
  requestIdCandidates.push(/* @__PURE__ */ new Set([input.requestId]));
26312
26655
  }
26313
- if (input.actionId !== void 0) {
26314
- requestIdCandidates.push(journal.getRequestIdsForActionId(input.actionId));
26656
+ if (input.capture !== void 0) {
26657
+ requestIdCandidates.push(history.getRequestIdsForCapture(input.capture));
26315
26658
  }
26316
26659
  if (input.tag !== void 0) {
26317
- requestIdCandidates.push(journal.getRequestIdsForTag(input.tag));
26660
+ requestIdCandidates.push(history.getRequestIdsForTag(input.tag));
26318
26661
  }
26319
26662
  if (requestIdCandidates.length === 0) {
26320
26663
  return void 0;
26321
26664
  }
26322
26665
  return intersectRequestIdSets(requestIdCandidates);
26323
26666
  }
26324
- function resolveLiveQueryPageRef(input, currentPageRef, requestIds, journal) {
26667
+ function resolveLiveQueryPageRef(input, currentPageRef, requestIds, history) {
26325
26668
  const requestedPageRef = selectLiveQueryPageRef(input, currentPageRef);
26326
26669
  if (requestedPageRef !== void 0 || requestIds === void 0) {
26327
26670
  return requestedPageRef;
26328
26671
  }
26329
26672
  const pageRefs = /* @__PURE__ */ new Set();
26330
26673
  for (const requestId of requestIds) {
26331
- const pageRef = journal.getPageRefForRequestId(requestId);
26674
+ const pageRef = history.getPageRefForRequestId(requestId);
26332
26675
  if (pageRef === void 0) {
26333
26676
  continue;
26334
26677
  }
@@ -26358,7 +26701,7 @@ function filterNetworkQueryRecords(records, input) {
26358
26701
  if (input.requestId !== void 0 && record.record.requestId !== input.requestId) {
26359
26702
  return false;
26360
26703
  }
26361
- if (input.actionId !== void 0 && record.actionId !== input.actionId) {
26704
+ if (input.capture !== void 0 && record.capture !== input.capture) {
26362
26705
  return false;
26363
26706
  }
26364
26707
  if (input.tag !== void 0 && !(record.tags ?? []).includes(input.tag)) {
@@ -26370,10 +26713,10 @@ function filterNetworkQueryRecords(records, input) {
26370
26713
  return true;
26371
26714
  });
26372
26715
  }
26373
- function sortLiveNetworkRecords(records, journal) {
26716
+ function sortLiveNetworkRecords(records, history) {
26374
26717
  return [...records].sort((left, right) => {
26375
- const leftObservedAt = journal.getObservedAt(left.recordId) ?? 0;
26376
- const rightObservedAt = journal.getObservedAt(right.recordId) ?? 0;
26718
+ const leftObservedAt = history.getObservedAt(left.recordId) ?? 0;
26719
+ const rightObservedAt = history.getObservedAt(right.recordId) ?? 0;
26377
26720
  if (leftObservedAt !== rightObservedAt) {
26378
26721
  return rightObservedAt - leftObservedAt;
26379
26722
  }
@@ -26580,7 +26923,7 @@ function buildMinimizedRequestPlan(input) {
26580
26923
  provenance: {
26581
26924
  source: "network-minimize",
26582
26925
  sourceId: input.record.recordId,
26583
- ...input.record.source === "saved" && input.record.savedAt !== void 0 ? { capturedAt: input.record.savedAt } : {}
26926
+ ...input.record.savedAt === void 0 ? {} : { capturedAt: input.record.savedAt }
26584
26927
  },
26585
26928
  payload: normalizeRequestPlanPayload({
26586
26929
  transport: {
@@ -26799,12 +27142,12 @@ function originFromUrl(url) {
26799
27142
  return void 0;
26800
27143
  }
26801
27144
  }
26802
- function filterReverseObservationWindow(records, journal, captureWindowMs) {
27145
+ function filterReverseObservationWindow(records, history, captureWindowMs) {
26803
27146
  if (captureWindowMs === void 0) {
26804
27147
  return records;
26805
27148
  }
26806
27149
  const observedAfter = Date.now() - captureWindowMs;
26807
- return records.filter((record) => (journal.getObservedAt(record.recordId) ?? 0) >= observedAfter);
27150
+ return records.filter((record) => (history.getObservedAt(record.recordId) ?? 0) >= observedAfter);
26808
27151
  }
26809
27152
  function isReverseRelevantNetworkRecord(record) {
26810
27153
  return record.record.resourceType === "document" || record.record.resourceType === "fetch" || record.record.resourceType === "xhr" || record.record.resourceType === "websocket" || record.record.resourceType === "event-stream";
@@ -28768,9 +29111,40 @@ function toOpensteerResolvedTarget2(target) {
28768
29111
  function normalizeOpensteerError(error) {
28769
29112
  return normalizeThrownOpensteerError(error, "Unknown Opensteer runtime failure");
28770
29113
  }
29114
+ function buildMutationCaptureTraceData(diagnostics) {
29115
+ if (diagnostics?.finalizeError === void 0) {
29116
+ return {};
29117
+ }
29118
+ return {
29119
+ networkCapture: {
29120
+ finalizeError: diagnostics.finalizeError
29121
+ }
29122
+ };
29123
+ }
28771
29124
  function isIgnorableRuntimeBindingError(error) {
28772
29125
  return isBrowserCoreError(error) && (error.code === "not-found" || error.code === "page-closed" || error.code === "session-closed");
28773
29126
  }
29127
+ async function withDetachedTimeoutSignal(timeoutMs, operation) {
29128
+ const controller = new AbortController();
29129
+ const timeoutError = new OpensteerProtocolError(
29130
+ "timeout",
29131
+ `mutation capture finalization exceeded ${String(timeoutMs)}ms timeout`,
29132
+ {
29133
+ details: {
29134
+ policy: "mutation-capture-finalize",
29135
+ budgetMs: timeoutMs
29136
+ }
29137
+ }
29138
+ );
29139
+ const timer = setTimeout(() => {
29140
+ controller.abort(timeoutError);
29141
+ }, timeoutMs);
29142
+ try {
29143
+ return await operation(controller.signal);
29144
+ } finally {
29145
+ clearTimeout(timer);
29146
+ }
29147
+ }
28774
29148
  function screenshotMediaType(format2) {
28775
29149
  switch (format2) {
28776
29150
  case "png":