opensteer 0.8.6 → 0.8.8

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.
@@ -1439,14 +1439,10 @@ var networkRecordSchema = objectSchema(
1439
1439
  ]
1440
1440
  }
1441
1441
  );
1442
- var networkQuerySourceSchema = enumSchema(["live", "saved"], {
1443
- title: "NetworkQuerySource"
1444
- });
1445
1442
  var networkQueryRecordSchema = objectSchema(
1446
1443
  {
1447
1444
  recordId: stringSchema({ minLength: 1 }),
1448
- source: networkQuerySourceSchema,
1449
- actionId: stringSchema({ minLength: 1 }),
1445
+ capture: stringSchema({ minLength: 1 }),
1450
1446
  tags: arraySchema(stringSchema({ minLength: 1 }), {
1451
1447
  uniqueItems: true
1452
1448
  }),
@@ -1455,7 +1451,7 @@ var networkQueryRecordSchema = objectSchema(
1455
1451
  },
1456
1452
  {
1457
1453
  title: "NetworkQueryRecord",
1458
- required: ["recordId", "source", "record"]
1454
+ required: ["recordId", "record"]
1459
1455
  }
1460
1456
  );
1461
1457
  arraySchema(headerEntrySchema, {
@@ -1926,8 +1922,7 @@ var opensteerRecipeStepSchema = oneOfSchema(
1926
1922
  objectSchema(
1927
1923
  {
1928
1924
  kind: enumSchema(["goto"]),
1929
- url: stringSchema({ minLength: 1 }),
1930
- networkTag: stringSchema({ minLength: 1 })
1925
+ url: stringSchema({ minLength: 1 })
1931
1926
  },
1932
1927
  {
1933
1928
  title: "OpensteerAuthRecipeGotoStep",
@@ -1936,8 +1931,7 @@ var opensteerRecipeStepSchema = oneOfSchema(
1936
1931
  ),
1937
1932
  objectSchema(
1938
1933
  {
1939
- kind: enumSchema(["reload"]),
1940
- networkTag: stringSchema({ minLength: 1 })
1934
+ kind: enumSchema(["reload"])
1941
1935
  },
1942
1936
  {
1943
1937
  title: "OpensteerAuthRecipeReloadStep",
@@ -2151,13 +2145,10 @@ var opensteerRecipeRecordSchema = objectSchema(
2151
2145
  var opensteerAuthRecipeRecordSchema = opensteerRecipeRecordSchema;
2152
2146
  var opensteerNetworkQueryInputSchema = objectSchema(
2153
2147
  {
2154
- source: enumSchema(["live", "saved"], {
2155
- title: "OpensteerNetworkQuerySource"
2156
- }),
2157
2148
  pageRef: pageRefSchema,
2158
2149
  recordId: stringSchema({ minLength: 1 }),
2159
2150
  requestId: stringSchema({ minLength: 1 }),
2160
- actionId: stringSchema({ minLength: 1 }),
2151
+ capture: stringSchema({ minLength: 1 }),
2161
2152
  tag: stringSchema({ minLength: 1 }),
2162
2153
  url: stringSchema({ minLength: 1 }),
2163
2154
  hostname: stringSchema({ minLength: 1 }),
@@ -2181,12 +2172,12 @@ var opensteerNetworkQueryOutputSchema = objectSchema(
2181
2172
  required: ["records"]
2182
2173
  }
2183
2174
  );
2184
- var opensteerNetworkSaveInputSchema = objectSchema(
2175
+ var opensteerNetworkTagInputSchema = objectSchema(
2185
2176
  {
2186
2177
  pageRef: pageRefSchema,
2187
2178
  recordId: stringSchema({ minLength: 1 }),
2188
2179
  requestId: stringSchema({ minLength: 1 }),
2189
- actionId: stringSchema({ minLength: 1 }),
2180
+ capture: stringSchema({ minLength: 1 }),
2190
2181
  tag: stringSchema({ minLength: 1 }),
2191
2182
  url: stringSchema({ minLength: 1 }),
2192
2183
  hostname: stringSchema({ minLength: 1 }),
@@ -2196,21 +2187,22 @@ var opensteerNetworkSaveInputSchema = objectSchema(
2196
2187
  resourceType: networkResourceTypeSchema
2197
2188
  },
2198
2189
  {
2199
- title: "OpensteerNetworkSaveInput",
2190
+ title: "OpensteerNetworkTagInput",
2200
2191
  required: ["tag"]
2201
2192
  }
2202
2193
  );
2203
- var opensteerNetworkSaveOutputSchema = objectSchema(
2194
+ var opensteerNetworkTagOutputSchema = objectSchema(
2204
2195
  {
2205
- savedCount: integerSchema({ minimum: 0 })
2196
+ taggedCount: integerSchema({ minimum: 0 })
2206
2197
  },
2207
2198
  {
2208
- title: "OpensteerNetworkSaveOutput",
2209
- required: ["savedCount"]
2199
+ title: "OpensteerNetworkTagOutput",
2200
+ required: ["taggedCount"]
2210
2201
  }
2211
2202
  );
2212
2203
  var opensteerNetworkClearInputSchema = objectSchema(
2213
2204
  {
2205
+ capture: stringSchema({ minLength: 1 }),
2214
2206
  tag: stringSchema({ minLength: 1 })
2215
2207
  },
2216
2208
  {
@@ -5681,7 +5673,7 @@ var opensteerSemanticOperationNames = [
5681
5673
  "dom.scroll",
5682
5674
  "dom.extract",
5683
5675
  "network.query",
5684
- "network.save",
5676
+ "network.tag",
5685
5677
  "network.clear",
5686
5678
  "network.minimize",
5687
5679
  "network.diff",
@@ -5742,7 +5734,7 @@ var opensteerPackageRunnableSemanticOperationNames = /* @__PURE__ */ new Set([
5742
5734
  "dom.scroll",
5743
5735
  "dom.extract",
5744
5736
  "network.query",
5745
- "network.save",
5737
+ "network.tag",
5746
5738
  "network.clear",
5747
5739
  "network.minimize",
5748
5740
  "network.diff",
@@ -6062,7 +6054,7 @@ var opensteerPageCloseOutputSchema = objectSchema(
6062
6054
  var opensteerPageGotoInputSchema = objectSchema(
6063
6055
  {
6064
6056
  url: stringSchema(),
6065
- networkTag: stringSchema({ minLength: 1 })
6057
+ captureNetwork: stringSchema({ minLength: 1 })
6066
6058
  },
6067
6059
  {
6068
6060
  title: "OpensteerPageGotoInput",
@@ -6213,7 +6205,7 @@ var opensteerDomClickInputSchema = objectSchema(
6213
6205
  {
6214
6206
  target: opensteerTargetInputSchema,
6215
6207
  persistAsDescription: stringSchema(),
6216
- networkTag: stringSchema({ minLength: 1 })
6208
+ captureNetwork: stringSchema({ minLength: 1 })
6217
6209
  },
6218
6210
  {
6219
6211
  title: "OpensteerDomClickInput",
@@ -6224,7 +6216,7 @@ var opensteerDomHoverInputSchema = objectSchema(
6224
6216
  {
6225
6217
  target: opensteerTargetInputSchema,
6226
6218
  persistAsDescription: stringSchema(),
6227
- networkTag: stringSchema({ minLength: 1 })
6219
+ captureNetwork: stringSchema({ minLength: 1 })
6228
6220
  },
6229
6221
  {
6230
6222
  title: "OpensteerDomHoverInput",
@@ -6237,7 +6229,7 @@ var opensteerDomInputInputSchema = objectSchema(
6237
6229
  text: stringSchema(),
6238
6230
  pressEnter: { type: "boolean" },
6239
6231
  persistAsDescription: stringSchema(),
6240
- networkTag: stringSchema({ minLength: 1 })
6232
+ captureNetwork: stringSchema({ minLength: 1 })
6241
6233
  },
6242
6234
  {
6243
6235
  title: "OpensteerDomInputInput",
@@ -6250,7 +6242,7 @@ var opensteerDomScrollInputSchema = objectSchema(
6250
6242
  direction: enumSchema(["up", "down", "left", "right"]),
6251
6243
  amount: integerSchema({ minimum: 1 }),
6252
6244
  persistAsDescription: stringSchema(),
6253
- networkTag: stringSchema({ minLength: 1 })
6245
+ captureNetwork: stringSchema({ minLength: 1 })
6254
6246
  },
6255
6247
  {
6256
6248
  title: "OpensteerDomScrollInput",
@@ -6451,7 +6443,7 @@ var opensteerComputerExecuteInputSchema = objectSchema(
6451
6443
  {
6452
6444
  action: opensteerComputerActionSchema,
6453
6445
  screenshot: opensteerComputerScreenshotOptionsSchema,
6454
- networkTag: stringSchema({ minLength: 1 })
6446
+ captureNetwork: stringSchema({ minLength: 1 })
6455
6447
  },
6456
6448
  {
6457
6449
  title: "OpensteerComputerExecuteInput",
@@ -6652,18 +6644,17 @@ var opensteerSemanticOperationSpecificationsBase = [
6652
6644
  }),
6653
6645
  defineSemanticOperationSpec({
6654
6646
  name: "network.query",
6655
- description: "Query live or saved network records for reverse engineering workflows.",
6647
+ description: "Query persisted network records for reverse engineering workflows.",
6656
6648
  inputSchema: opensteerNetworkQueryInputSchema,
6657
6649
  outputSchema: opensteerNetworkQueryOutputSchema,
6658
- requiredCapabilities: [],
6659
- resolveRequiredCapabilities: (input) => input.source === "saved" ? [] : input.includeBodies === true ? ["inspect.network", "inspect.networkBodies"] : ["inspect.network"]
6650
+ requiredCapabilities: []
6660
6651
  }),
6661
6652
  defineSemanticOperationSpec({
6662
- name: "network.save",
6663
- description: "Persist filtered live network records into the saved network registry under a tag.",
6664
- inputSchema: opensteerNetworkSaveInputSchema,
6665
- outputSchema: opensteerNetworkSaveOutputSchema,
6666
- requiredCapabilities: ["inspect.network"]
6653
+ name: "network.tag",
6654
+ description: "Apply a tag to persisted network records matching the provided filters.",
6655
+ inputSchema: opensteerNetworkTagInputSchema,
6656
+ outputSchema: opensteerNetworkTagOutputSchema,
6657
+ requiredCapabilities: []
6667
6658
  }),
6668
6659
  defineSemanticOperationSpec({
6669
6660
  name: "network.clear",
@@ -7545,7 +7536,7 @@ var SqliteSavedNetworkStore = class {
7545
7536
  async initialize() {
7546
7537
  await this.ensureDatabaseDirectory();
7547
7538
  }
7548
- async save(records, tag) {
7539
+ async save(records, options) {
7549
7540
  const database = await this.requireDatabase();
7550
7541
  const readExisting = database.prepare(`
7551
7542
  SELECT record_id
@@ -7554,123 +7545,7 @@ var SqliteSavedNetworkStore = class {
7554
7545
  AND page_ref_key = @page_ref_key
7555
7546
  AND request_id = @request_id
7556
7547
  `);
7557
- const upsertRecord = database.prepare(`
7558
- INSERT INTO saved_network_records (
7559
- record_id,
7560
- request_id,
7561
- session_ref,
7562
- page_ref,
7563
- page_ref_key,
7564
- frame_ref,
7565
- document_ref,
7566
- action_id,
7567
- method,
7568
- method_lc,
7569
- url,
7570
- url_lc,
7571
- hostname,
7572
- hostname_lc,
7573
- path,
7574
- path_lc,
7575
- status,
7576
- status_text,
7577
- resource_type,
7578
- navigation_request,
7579
- request_headers_json,
7580
- response_headers_json,
7581
- request_body_json,
7582
- response_body_json,
7583
- initiator_json,
7584
- timing_json,
7585
- transfer_json,
7586
- source_json,
7587
- capture_state,
7588
- request_body_state,
7589
- response_body_state,
7590
- request_body_skip_reason,
7591
- response_body_skip_reason,
7592
- request_body_error,
7593
- response_body_error,
7594
- redirect_from_request_id,
7595
- redirect_to_request_id,
7596
- saved_at
7597
- ) VALUES (
7598
- @record_id,
7599
- @request_id,
7600
- @session_ref,
7601
- @page_ref,
7602
- @page_ref_key,
7603
- @frame_ref,
7604
- @document_ref,
7605
- @action_id,
7606
- @method,
7607
- @method_lc,
7608
- @url,
7609
- @url_lc,
7610
- @hostname,
7611
- @hostname_lc,
7612
- @path,
7613
- @path_lc,
7614
- @status,
7615
- @status_text,
7616
- @resource_type,
7617
- @navigation_request,
7618
- @request_headers_json,
7619
- @response_headers_json,
7620
- @request_body_json,
7621
- @response_body_json,
7622
- @initiator_json,
7623
- @timing_json,
7624
- @transfer_json,
7625
- @source_json,
7626
- @capture_state,
7627
- @request_body_state,
7628
- @response_body_state,
7629
- @request_body_skip_reason,
7630
- @response_body_skip_reason,
7631
- @request_body_error,
7632
- @response_body_error,
7633
- @redirect_from_request_id,
7634
- @redirect_to_request_id,
7635
- @saved_at
7636
- )
7637
- ON CONFLICT(record_id) DO UPDATE SET
7638
- page_ref = excluded.page_ref,
7639
- page_ref_key = excluded.page_ref_key,
7640
- frame_ref = excluded.frame_ref,
7641
- document_ref = excluded.document_ref,
7642
- action_id = excluded.action_id,
7643
- method = excluded.method,
7644
- method_lc = excluded.method_lc,
7645
- url = excluded.url,
7646
- url_lc = excluded.url_lc,
7647
- hostname = excluded.hostname,
7648
- hostname_lc = excluded.hostname_lc,
7649
- path = excluded.path,
7650
- path_lc = excluded.path_lc,
7651
- status = excluded.status,
7652
- status_text = excluded.status_text,
7653
- resource_type = excluded.resource_type,
7654
- navigation_request = excluded.navigation_request,
7655
- request_headers_json = excluded.request_headers_json,
7656
- response_headers_json = excluded.response_headers_json,
7657
- request_body_json = excluded.request_body_json,
7658
- response_body_json = excluded.response_body_json,
7659
- initiator_json = excluded.initiator_json,
7660
- timing_json = excluded.timing_json,
7661
- transfer_json = excluded.transfer_json,
7662
- source_json = excluded.source_json,
7663
- capture_state = excluded.capture_state,
7664
- request_body_state = excluded.request_body_state,
7665
- response_body_state = excluded.response_body_state,
7666
- request_body_skip_reason = excluded.request_body_skip_reason,
7667
- response_body_skip_reason = excluded.response_body_skip_reason,
7668
- request_body_error = excluded.request_body_error,
7669
- response_body_error = excluded.response_body_error,
7670
- redirect_from_request_id = excluded.redirect_from_request_id,
7671
- redirect_to_request_id = excluded.redirect_to_request_id,
7672
- saved_at = excluded.saved_at
7673
- `);
7548
+ const upsertRecord = database.prepare(buildSavedNetworkUpsertSql(options.bodyWriteMode));
7674
7549
  const insertTag = database.prepare(`
7675
7550
  INSERT OR IGNORE INTO saved_network_tags (record_id, tag)
7676
7551
  VALUES (@record_id, @tag)
@@ -7694,7 +7569,7 @@ var SqliteSavedNetworkStore = class {
7694
7569
  page_ref_key: pageRefKey,
7695
7570
  frame_ref: entry.record.frameRef ?? null,
7696
7571
  document_ref: entry.record.documentRef ?? null,
7697
- action_id: entry.actionId ?? null,
7572
+ capture: entry.capture ?? null,
7698
7573
  method: entry.record.method,
7699
7574
  method_lc: entry.record.method.toLowerCase(),
7700
7575
  url: entry.record.url,
@@ -7726,10 +7601,14 @@ var SqliteSavedNetworkStore = class {
7726
7601
  redirect_to_request_id: entry.record.redirectToRequestId ?? null,
7727
7602
  saved_at: entry.savedAt ?? Date.now()
7728
7603
  });
7729
- if (tag !== void 0) {
7604
+ const tags = new Set(entry.tags ?? []);
7605
+ if (options.tag !== void 0) {
7606
+ tags.add(options.tag);
7607
+ }
7608
+ for (const currentTag of tags) {
7730
7609
  const result = insertTag.run({
7731
7610
  record_id: recordId,
7732
- tag
7611
+ tag: currentTag
7733
7612
  });
7734
7613
  savedCount += result.changes ?? 0;
7735
7614
  }
@@ -7737,6 +7616,39 @@ var SqliteSavedNetworkStore = class {
7737
7616
  return savedCount;
7738
7617
  });
7739
7618
  }
7619
+ async tagByFilter(filter, tag) {
7620
+ const database = await this.requireDatabase();
7621
+ const { whereSql, parameters } = buildSavedNetworkWhere(filter);
7622
+ const selectRecords = database.prepare(
7623
+ `
7624
+ SELECT r.record_id
7625
+ FROM saved_network_records r
7626
+ ${whereSql}
7627
+ `
7628
+ );
7629
+ const insertTag = database.prepare(`
7630
+ INSERT OR IGNORE INTO saved_network_tags (record_id, tag)
7631
+ VALUES (@record_id, @tag)
7632
+ `);
7633
+ return withSqliteTransaction(database, () => {
7634
+ let taggedCount = 0;
7635
+ const rows = selectRecords.all(
7636
+ ...parameters
7637
+ );
7638
+ for (const row of rows) {
7639
+ const recordId = row.record_id;
7640
+ if (typeof recordId !== "string") {
7641
+ continue;
7642
+ }
7643
+ const result = insertTag.run({
7644
+ record_id: recordId,
7645
+ tag
7646
+ });
7647
+ taggedCount += result.changes ?? 0;
7648
+ }
7649
+ return taggedCount;
7650
+ });
7651
+ }
7740
7652
  async query(input = {}) {
7741
7653
  const database = await this.requireDatabase();
7742
7654
  const limit = Math.max(1, Math.min(input.limit ?? 50, 200));
@@ -7770,39 +7682,31 @@ var SqliteSavedNetworkStore = class {
7770
7682
  }
7771
7683
  async clear(input = {}) {
7772
7684
  const database = await this.requireDatabase();
7773
- const countAll = database.prepare(`
7774
- SELECT COUNT(*) AS cleared
7775
- FROM saved_network_records
7776
- `);
7777
- const countByTag = database.prepare(`
7778
- SELECT COUNT(DISTINCT record_id) AS cleared
7779
- FROM saved_network_tags
7780
- WHERE tag = @tag
7781
- `);
7782
- const deleteAllTags = database.prepare(`DELETE FROM saved_network_tags`);
7685
+ const countAll = database.prepare(`SELECT COUNT(*) AS cleared FROM saved_network_records`);
7783
7686
  const deleteAllRecords = database.prepare(`DELETE FROM saved_network_records`);
7784
- const deleteTag = database.prepare(`
7785
- DELETE FROM saved_network_tags
7786
- WHERE tag = @tag
7687
+ const { whereSql, parameters } = buildSavedNetworkWhere(input);
7688
+ const countFiltered = database.prepare(`
7689
+ SELECT COUNT(*) AS cleared
7690
+ FROM saved_network_records r
7691
+ ${whereSql}
7787
7692
  `);
7788
- const deleteOrphans = database.prepare(`
7693
+ const deleteFiltered = database.prepare(`
7789
7694
  DELETE FROM saved_network_records
7790
- WHERE NOT EXISTS (
7791
- SELECT 1
7792
- FROM saved_network_tags t
7793
- WHERE t.record_id = saved_network_records.record_id
7695
+ WHERE record_id IN (
7696
+ SELECT r.record_id
7697
+ FROM saved_network_records r
7698
+ ${whereSql}
7794
7699
  )
7795
7700
  `);
7796
7701
  return withSqliteTransaction(database, () => {
7797
- const tag = input.tag;
7798
- const cleared = tag === void 0 ? countAll.get().cleared : countByTag.get({ tag }).cleared;
7799
- if (tag === void 0) {
7800
- deleteAllTags.run();
7702
+ if (input.capture === void 0 && input.tag === void 0) {
7703
+ const cleared2 = countAll.get().cleared;
7801
7704
  deleteAllRecords.run();
7802
- return cleared;
7705
+ return cleared2;
7803
7706
  }
7804
- deleteTag.run({ tag });
7805
- deleteOrphans.run();
7707
+ const args = parameters;
7708
+ const cleared = countFiltered.get(...args).cleared;
7709
+ deleteFiltered.run(...args);
7806
7710
  return cleared;
7807
7711
  });
7808
7712
  }
@@ -7857,7 +7761,7 @@ var SqliteSavedNetworkStore = class {
7857
7761
  page_ref_key TEXT NOT NULL,
7858
7762
  frame_ref TEXT,
7859
7763
  document_ref TEXT,
7860
- action_id TEXT,
7764
+ capture TEXT,
7861
7765
  method TEXT NOT NULL,
7862
7766
  method_lc TEXT NOT NULL,
7863
7767
  url TEXT NOT NULL,
@@ -7896,6 +7800,9 @@ var SqliteSavedNetworkStore = class {
7896
7800
  CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
7897
7801
  ON saved_network_records (saved_at DESC);
7898
7802
 
7803
+ CREATE INDEX IF NOT EXISTS saved_network_records_capture
7804
+ ON saved_network_records (capture);
7805
+
7899
7806
  CREATE TABLE IF NOT EXISTS saved_network_tags (
7900
7807
  record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
7901
7808
  tag TEXT NOT NULL,
@@ -7911,6 +7818,7 @@ var SqliteSavedNetworkStore = class {
7911
7818
  "capture_state",
7912
7819
  "TEXT NOT NULL DEFAULT 'complete'"
7913
7820
  );
7821
+ this.ensureColumn(database, "saved_network_records", "capture", "TEXT");
7914
7822
  this.ensureColumn(
7915
7823
  database,
7916
7824
  "saved_network_records",
@@ -7939,6 +7847,10 @@ var SqliteSavedNetworkStore = class {
7939
7847
  function buildSavedNetworkWhere(input) {
7940
7848
  const clauses = [];
7941
7849
  const parameters = [];
7850
+ if (input.pageRef !== void 0) {
7851
+ clauses.push("r.page_ref_key = ?");
7852
+ parameters.push(input.pageRef);
7853
+ }
7942
7854
  if (input.recordId !== void 0) {
7943
7855
  clauses.push("r.record_id = ?");
7944
7856
  parameters.push(input.recordId);
@@ -7947,9 +7859,9 @@ function buildSavedNetworkWhere(input) {
7947
7859
  clauses.push("r.request_id = ?");
7948
7860
  parameters.push(input.requestId);
7949
7861
  }
7950
- if (input.actionId !== void 0) {
7951
- clauses.push("r.action_id = ?");
7952
- parameters.push(input.actionId);
7862
+ if (input.capture !== void 0) {
7863
+ clauses.push("r.capture = ?");
7864
+ parameters.push(input.capture);
7953
7865
  }
7954
7866
  if (input.tag !== void 0) {
7955
7867
  clauses.push(`
@@ -7991,6 +7903,127 @@ function buildSavedNetworkWhere(input) {
7991
7903
  parameters
7992
7904
  };
7993
7905
  }
7906
+ function buildSavedNetworkUpsertSql(bodyWriteMode) {
7907
+ const bodyUpdateSql = bodyWriteMode === "authoritative" ? `
7908
+ request_body_json = excluded.request_body_json,
7909
+ response_body_json = excluded.response_body_json,
7910
+ request_body_state = excluded.request_body_state,
7911
+ response_body_state = excluded.response_body_state,
7912
+ request_body_skip_reason = excluded.request_body_skip_reason,
7913
+ response_body_skip_reason = excluded.response_body_skip_reason,
7914
+ request_body_error = excluded.request_body_error,
7915
+ response_body_error = excluded.response_body_error,
7916
+ ` : "";
7917
+ return `
7918
+ INSERT INTO saved_network_records (
7919
+ record_id,
7920
+ request_id,
7921
+ session_ref,
7922
+ page_ref,
7923
+ page_ref_key,
7924
+ frame_ref,
7925
+ document_ref,
7926
+ capture,
7927
+ method,
7928
+ method_lc,
7929
+ url,
7930
+ url_lc,
7931
+ hostname,
7932
+ hostname_lc,
7933
+ path,
7934
+ path_lc,
7935
+ status,
7936
+ status_text,
7937
+ resource_type,
7938
+ navigation_request,
7939
+ request_headers_json,
7940
+ response_headers_json,
7941
+ request_body_json,
7942
+ response_body_json,
7943
+ initiator_json,
7944
+ timing_json,
7945
+ transfer_json,
7946
+ source_json,
7947
+ capture_state,
7948
+ request_body_state,
7949
+ response_body_state,
7950
+ request_body_skip_reason,
7951
+ response_body_skip_reason,
7952
+ request_body_error,
7953
+ response_body_error,
7954
+ redirect_from_request_id,
7955
+ redirect_to_request_id,
7956
+ saved_at
7957
+ ) VALUES (
7958
+ @record_id,
7959
+ @request_id,
7960
+ @session_ref,
7961
+ @page_ref,
7962
+ @page_ref_key,
7963
+ @frame_ref,
7964
+ @document_ref,
7965
+ @capture,
7966
+ @method,
7967
+ @method_lc,
7968
+ @url,
7969
+ @url_lc,
7970
+ @hostname,
7971
+ @hostname_lc,
7972
+ @path,
7973
+ @path_lc,
7974
+ @status,
7975
+ @status_text,
7976
+ @resource_type,
7977
+ @navigation_request,
7978
+ @request_headers_json,
7979
+ @response_headers_json,
7980
+ @request_body_json,
7981
+ @response_body_json,
7982
+ @initiator_json,
7983
+ @timing_json,
7984
+ @transfer_json,
7985
+ @source_json,
7986
+ @capture_state,
7987
+ @request_body_state,
7988
+ @response_body_state,
7989
+ @request_body_skip_reason,
7990
+ @response_body_skip_reason,
7991
+ @request_body_error,
7992
+ @response_body_error,
7993
+ @redirect_from_request_id,
7994
+ @redirect_to_request_id,
7995
+ @saved_at
7996
+ )
7997
+ ON CONFLICT(record_id) DO UPDATE SET
7998
+ page_ref = excluded.page_ref,
7999
+ page_ref_key = excluded.page_ref_key,
8000
+ frame_ref = excluded.frame_ref,
8001
+ document_ref = excluded.document_ref,
8002
+ capture = excluded.capture,
8003
+ method = excluded.method,
8004
+ method_lc = excluded.method_lc,
8005
+ url = excluded.url,
8006
+ url_lc = excluded.url_lc,
8007
+ hostname = excluded.hostname,
8008
+ hostname_lc = excluded.hostname_lc,
8009
+ path = excluded.path,
8010
+ path_lc = excluded.path_lc,
8011
+ status = excluded.status,
8012
+ status_text = excluded.status_text,
8013
+ resource_type = excluded.resource_type,
8014
+ navigation_request = excluded.navigation_request,
8015
+ request_headers_json = excluded.request_headers_json,
8016
+ response_headers_json = excluded.response_headers_json,
8017
+ ${bodyUpdateSql} initiator_json = excluded.initiator_json,
8018
+ timing_json = excluded.timing_json,
8019
+ transfer_json = excluded.transfer_json,
8020
+ source_json = excluded.source_json,
8021
+ capture_state = excluded.capture_state,
8022
+ redirect_from_request_id = excluded.redirect_from_request_id,
8023
+ redirect_to_request_id = excluded.redirect_to_request_id,
8024
+ saved_at = MIN(saved_network_records.saved_at, excluded.saved_at)
8025
+ `;
8026
+ }
7994
8027
  function inflateSavedNetworkRow(row, includeBodies) {
7995
8028
  const requestBody = includeBodies && row.request_body_json !== null ? JSON.parse(row.request_body_json) : void 0;
7996
8029
  const responseBody = includeBodies && row.response_body_json !== null ? JSON.parse(row.response_body_json) : void 0;
@@ -8061,8 +8094,7 @@ function inflateSavedNetworkRow(row, includeBodies) {
8061
8094
  }
8062
8095
  return {
8063
8096
  recordId: row.record_id,
8064
- source: "saved",
8065
- ...row.action_id === null ? {} : { actionId: row.action_id },
8097
+ ...row.capture === null ? {} : { capture: row.capture },
8066
8098
  ...row.tags === null || row.tags.length === 0 ? {} : { tags: row.tags.split(TAG_DELIMITER).filter((tag) => tag.length > 0) },
8067
8099
  savedAt: row.saved_at,
8068
8100
  record
@@ -8402,13 +8434,13 @@ var DEFAULT_TIMEOUTS = {
8402
8434
  "page.add-init-script": 1e4,
8403
8435
  "page.snapshot": 15e3,
8404
8436
  "computer.execute": 3e4,
8405
- "dom.click": 1e4,
8437
+ "dom.click": 3e4,
8406
8438
  "dom.hover": 1e4,
8407
- "dom.input": 1e4,
8439
+ "dom.input": 3e4,
8408
8440
  "dom.scroll": 1e4,
8409
8441
  "dom.extract": 15e3,
8410
8442
  "network.query": 15e3,
8411
- "network.save": 15e3,
8443
+ "network.tag": 15e3,
8412
8444
  "network.clear": 1e4,
8413
8445
  "scripts.capture": 15e3,
8414
8446
  "request.raw": 3e4,
@@ -10198,6 +10230,49 @@ var MemoryDomDescriptorStore = class {
10198
10230
  }
10199
10231
  };
10200
10232
 
10233
+ // ../runtime-core/src/action-boundary.ts
10234
+ var actionBoundaryDiagnosticsBySignal = /* @__PURE__ */ new WeakMap();
10235
+ async function captureActionBoundarySnapshot(engine, pageRef) {
10236
+ const frames = await engine.listFrames({ pageRef });
10237
+ const mainFrame = frames.find((frame) => frame.isMainFrame);
10238
+ if (!mainFrame) {
10239
+ throw new Error(`page ${pageRef} does not expose a main frame`);
10240
+ }
10241
+ return {
10242
+ pageRef,
10243
+ documentRef: mainFrame.documentRef
10244
+ };
10245
+ }
10246
+ function createActionBoundaryDiagnostics(input) {
10247
+ return {
10248
+ trigger: input.boundary.trigger,
10249
+ crossDocument: input.boundary.crossDocument,
10250
+ bootstrapSettled: input.boundary.bootstrapSettled,
10251
+ visualSettled: input.visualSettled,
10252
+ ...input.boundary.timedOutPhase !== void 0 ? { timedOutPhase: input.boundary.timedOutPhase } : !input.visualSettled ? { timedOutPhase: "visual" } : {}
10253
+ };
10254
+ }
10255
+ function recordActionBoundaryDiagnostics(signal, diagnostics) {
10256
+ actionBoundaryDiagnosticsBySignal.set(signal, diagnostics);
10257
+ }
10258
+ function takeActionBoundaryDiagnostics(signal) {
10259
+ const diagnostics = actionBoundaryDiagnosticsBySignal.get(signal);
10260
+ actionBoundaryDiagnosticsBySignal.delete(signal);
10261
+ return diagnostics;
10262
+ }
10263
+ function isSoftSettleTimeoutError(error, signal) {
10264
+ if (isTimeoutError(error)) {
10265
+ return true;
10266
+ }
10267
+ return signal?.aborted === true && isTimeoutError(signal.reason) && (error === signal.reason || isAbortError(error));
10268
+ }
10269
+ function isAbortError(error) {
10270
+ return error instanceof Error && error.name === "AbortError";
10271
+ }
10272
+ function isTimeoutError(error) {
10273
+ return isOpensteerProtocolError(error) && error.code === "timeout";
10274
+ }
10275
+
10201
10276
  // ../runtime-core/src/runtimes/dom/executor.ts
10202
10277
  var MAX_DOM_ACTION_ATTEMPTS = 3;
10203
10278
  var DEFAULT_SCROLL_OPTIONS = {
@@ -10327,8 +10402,9 @@ var DomActionExecutor = class {
10327
10402
  })
10328
10403
  );
10329
10404
  let finalResolved = resolved;
10405
+ let finalSnapshot;
10330
10406
  if (input.pressEnter) {
10331
- await this.settle(resolved.pageRef, "dom.input", timeout);
10407
+ await this.waitForPressEnterReaction(timeout);
10332
10408
  const enterSession = this.options.createResolutionSession();
10333
10409
  const enterResolved = await timeout.runStep(
10334
10410
  () => this.options.resolveTarget(enterSession, {
@@ -10342,6 +10418,9 @@ var DomActionExecutor = class {
10342
10418
  () => bridge.inspectActionTarget(enterResolved.locator)
10343
10419
  );
10344
10420
  this.assertKeyboardActionable("dom.input", enterResolved, inspectionBeforeEnter);
10421
+ finalSnapshot = await timeout.runStep(
10422
+ () => captureActionBoundarySnapshot(this.options.engine, enterResolved.pageRef)
10423
+ );
10345
10424
  await timeout.runStep(
10346
10425
  () => bridge.pressKey(enterResolved.locator, {
10347
10426
  key: "Enter"
@@ -10349,7 +10428,15 @@ var DomActionExecutor = class {
10349
10428
  );
10350
10429
  finalResolved = enterResolved;
10351
10430
  }
10352
- await this.settle(finalResolved.pageRef, "dom.input", timeout);
10431
+ const settleDiagnostics = await this.settle(
10432
+ finalResolved.pageRef,
10433
+ "dom.input",
10434
+ timeout,
10435
+ finalSnapshot
10436
+ );
10437
+ if (finalSnapshot !== void 0) {
10438
+ recordActionBoundaryDiagnostics(timeout.signal, settleDiagnostics);
10439
+ }
10353
10440
  return finalResolved;
10354
10441
  } catch (error) {
10355
10442
  lastError = error;
@@ -10422,8 +10509,17 @@ var DomActionExecutor = class {
10422
10509
  );
10423
10510
  }
10424
10511
  }
10512
+ const actionBoundarySnapshot = await timeout.runStep(
10513
+ () => captureActionBoundarySnapshot(this.options.engine, pointerTarget.resolved.pageRef)
10514
+ );
10425
10515
  const outcome = await dispatch(pointerTarget, point, timeout);
10426
- await this.settle(pointerTarget.resolved.pageRef, input.operation, timeout);
10516
+ const settleDiagnostics = await this.settle(
10517
+ pointerTarget.resolved.pageRef,
10518
+ input.operation,
10519
+ timeout,
10520
+ actionBoundarySnapshot
10521
+ );
10522
+ recordActionBoundaryDiagnostics(timeout.signal, settleDiagnostics);
10427
10523
  return outcome;
10428
10524
  } catch (error) {
10429
10525
  lastError = error;
@@ -10441,23 +10537,49 @@ var DomActionExecutor = class {
10441
10537
  }
10442
10538
  return runWithPolicyTimeout(this.options.policy.timeout, { operation }, execute);
10443
10539
  }
10444
- async settle(pageRef, operation, timeout) {
10540
+ async settle(pageRef, operation, timeout, snapshot) {
10445
10541
  const bridge = this.requireBridge();
10446
- await timeout.runStep(
10542
+ let visualSettled = true;
10543
+ const boundary = await timeout.runStep(
10447
10544
  () => bridge.finalizeDomAction(pageRef, {
10448
10545
  operation,
10546
+ ...snapshot === void 0 ? {} : { snapshot },
10449
10547
  signal: timeout.signal,
10450
10548
  remainingMs: () => timeout.remainingMs(),
10451
- policySettle: (targetPageRef) => settleWithPolicy(this.options.policy.settle, {
10452
- operation,
10453
- trigger: "dom-action",
10454
- engine: this.options.engine,
10455
- pageRef: targetPageRef,
10456
- signal: timeout.signal,
10457
- remainingMs: timeout.remainingMs()
10458
- })
10549
+ policySettle: async (targetPageRef, trigger) => {
10550
+ try {
10551
+ await settleWithPolicy(this.options.policy.settle, {
10552
+ operation,
10553
+ trigger,
10554
+ engine: this.options.engine,
10555
+ pageRef: targetPageRef,
10556
+ signal: timeout.signal,
10557
+ remainingMs: timeout.remainingMs()
10558
+ });
10559
+ } catch (error) {
10560
+ if (snapshot !== void 0 && isSoftSettleTimeoutError(error, timeout.signal)) {
10561
+ visualSettled = false;
10562
+ return;
10563
+ }
10564
+ throw error;
10565
+ }
10566
+ }
10459
10567
  })
10460
10568
  );
10569
+ return createActionBoundaryDiagnostics({
10570
+ boundary,
10571
+ visualSettled
10572
+ });
10573
+ }
10574
+ async waitForPressEnterReaction(timeout) {
10575
+ const delayMs = this.options.policy.settle.resolveDelayMs({
10576
+ operation: "dom.input",
10577
+ trigger: "dom-action"
10578
+ });
10579
+ if (delayMs <= 0) {
10580
+ return;
10581
+ }
10582
+ await delayWithSignal(delayMs, timeout.signal);
10461
10583
  }
10462
10584
  requireBridge() {
10463
10585
  if (this.bridge !== void 0) {
@@ -15772,8 +15894,8 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
15772
15894
  input,
15773
15895
  options
15774
15896
  );
15775
- case "network.save":
15776
- return runtime.saveNetwork(
15897
+ case "network.tag":
15898
+ return runtime.tagNetwork(
15777
15899
  input,
15778
15900
  options
15779
15901
  );
@@ -15981,7 +16103,7 @@ async function dispatchSemanticOperation(runtime, operation, input, options = {}
15981
16103
 
15982
16104
  // ../runtime-core/package.json
15983
16105
  var package_default = {
15984
- version: "0.1.1"};
16106
+ version: "0.1.2"};
15985
16107
 
15986
16108
  // ../runtime-core/src/version.ts
15987
16109
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
@@ -16279,23 +16401,47 @@ var DefaultComputerUseRuntime = class {
16279
16401
  const preActionDisplay = createComputerDisplayTransform(preActionNativeViewport);
16280
16402
  const nativeAction = toNativeComputerAction(input.input.action, preActionDisplay);
16281
16403
  const screenshot = normalizeScreenshotOptions(input.input.screenshot);
16404
+ const snapshot = await input.timeout.runStep(
16405
+ () => captureActionBoundarySnapshot(this.options.engine, input.pageRef)
16406
+ );
16407
+ let visualSettled = true;
16282
16408
  const executed = await input.timeout.runStep(
16283
16409
  () => bridge.execute({
16284
16410
  pageRef: input.pageRef,
16411
+ snapshot,
16285
16412
  action: nativeAction,
16286
16413
  screenshot,
16287
16414
  signal: input.timeout.signal,
16288
16415
  remainingMs: () => input.timeout.remainingMs(),
16289
- policySettle: async (pageRef) => settleWithPolicy(this.options.policy.settle, {
16290
- operation: "computer.execute",
16291
- trigger: "dom-action",
16292
- engine: this.options.engine,
16293
- pageRef,
16294
- signal: input.timeout.signal,
16295
- remainingMs: input.timeout.remainingMs()
16296
- })
16416
+ policySettle: async (pageRef, trigger) => {
16417
+ try {
16418
+ await settleWithPolicy(this.options.policy.settle, {
16419
+ operation: "computer.execute",
16420
+ trigger,
16421
+ engine: this.options.engine,
16422
+ pageRef,
16423
+ signal: input.timeout.signal,
16424
+ remainingMs: input.timeout.remainingMs()
16425
+ });
16426
+ } catch (error) {
16427
+ if (pageRef === input.pageRef && isSoftSettleTimeoutError(error, input.timeout.signal)) {
16428
+ visualSettled = false;
16429
+ return;
16430
+ }
16431
+ throw error;
16432
+ }
16433
+ }
16297
16434
  })
16298
16435
  );
16436
+ if (executed.boundary !== void 0 && executed.pageRef === input.pageRef) {
16437
+ recordActionBoundaryDiagnostics(
16438
+ input.timeout.signal,
16439
+ createActionBoundaryDiagnostics({
16440
+ boundary: executed.boundary,
16441
+ visualSettled
16442
+ })
16443
+ );
16444
+ }
16299
16445
  let trace = void 0;
16300
16446
  if (!input.timeout.signal.aborted) {
16301
16447
  try {
@@ -17022,9 +17168,9 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
17022
17168
  key: input.key,
17023
17169
  version: input.version,
17024
17170
  provenance: {
17025
- source: record.source === "saved" ? "saved-network-record" : "live-network-record",
17171
+ source: record.savedAt === void 0 ? "network-record" : "saved-network-record",
17026
17172
  sourceId: record.recordId,
17027
- ...record.source === "saved" ? record.savedAt === void 0 ? {} : { capturedAt: record.savedAt } : options.observedAt === void 0 ? {} : { capturedAt: options.observedAt }
17173
+ ...record.savedAt === void 0 ? options.observedAt === void 0 ? {} : { capturedAt: options.observedAt } : { capturedAt: record.savedAt }
17028
17174
  },
17029
17175
  payload,
17030
17176
  ...record.tags === void 0 || record.tags.length === 0 ? {} : { tags: record.tags }
@@ -17404,63 +17550,67 @@ function resolveBodyEncoding(charset) {
17404
17550
  return "utf8";
17405
17551
  }
17406
17552
  }
17407
- var NetworkJournal = class {
17553
+ var NetworkHistory = class {
17408
17554
  metadataByRequestId = /* @__PURE__ */ new Map();
17409
17555
  requestIdByRecordId = /* @__PURE__ */ new Map();
17410
- requestIdsByActionId = /* @__PURE__ */ new Map();
17556
+ requestIdsByCapture = /* @__PURE__ */ new Map();
17411
17557
  requestIdsByTag = /* @__PURE__ */ new Map();
17412
- sync(records, options = {}) {
17558
+ tombstonedRequestIds = /* @__PURE__ */ new Set();
17559
+ materialize(records, options = {}) {
17413
17560
  const observedAt = Date.now();
17414
- return records.map((record) => this.materializeLiveRecord(record, observedAt, options));
17415
- }
17416
- materializeLiveRecord(record, observedAt, options = {}) {
17417
- let metadata = this.metadataByRequestId.get(record.requestId);
17418
- if (!metadata) {
17419
- metadata = {
17420
- recordId: `record:${randomUUID()}`,
17421
- observedAt,
17422
- ...record.pageRef === void 0 ? {} : { pageRef: record.pageRef },
17423
- tags: /* @__PURE__ */ new Set()
17424
- };
17425
- this.metadataByRequestId.set(record.requestId, metadata);
17426
- this.requestIdByRecordId.set(metadata.recordId, record.requestId);
17427
- } else if (metadata.pageRef === void 0 && record.pageRef !== void 0) {
17428
- metadata.pageRef = record.pageRef;
17561
+ const materialized = [];
17562
+ for (const record of records) {
17563
+ const entry = this.materializeRecord(record, observedAt, options);
17564
+ if (entry !== void 0) {
17565
+ materialized.push(entry);
17566
+ }
17429
17567
  }
17430
- return {
17431
- recordId: metadata.recordId,
17432
- source: "live",
17433
- ...metadata.actionId === void 0 ? {} : { actionId: metadata.actionId },
17434
- ...metadata.tags.size === 0 ? {} : { tags: [...metadata.tags].sort() },
17435
- record: toProtocolNetworkRecord(record, {
17436
- redactSecretHeaders: options.redactSecretHeaders ?? true
17437
- })
17438
- };
17568
+ return materialized;
17439
17569
  }
17440
- diffNewRequestIds(records, baselineRequestIds) {
17441
- const observedAt = Date.now();
17442
- const all = records.map(
17443
- (record) => this.materializeLiveRecord(record, observedAt, {
17444
- redactSecretHeaders: true
17445
- })
17446
- );
17447
- const delta = all.filter((entry) => !baselineRequestIds.has(entry.record.requestId));
17448
- return {
17449
- all,
17450
- delta
17451
- };
17570
+ async persist(records, store, options) {
17571
+ const observedAt = options.observedAt ?? Date.now();
17572
+ const metadataToSave = /* @__PURE__ */ new Set();
17573
+ const persisted = [];
17574
+ for (const record of records) {
17575
+ const entry = this.materializeRecord(record, observedAt, {
17576
+ ...options.redactSecretHeaders === void 0 ? {} : { redactSecretHeaders: options.redactSecretHeaders }
17577
+ });
17578
+ if (entry === void 0) {
17579
+ continue;
17580
+ }
17581
+ const requestId = entry.record.requestId;
17582
+ const metadata = this.metadataByRequestId.get(requestId);
17583
+ if (metadata === void 0) {
17584
+ continue;
17585
+ }
17586
+ const savedAt = metadata.savedAt ?? observedAt;
17587
+ metadataToSave.add(metadata);
17588
+ persisted.push({
17589
+ ...entry,
17590
+ savedAt
17591
+ });
17592
+ }
17593
+ if (persisted.length > 0) {
17594
+ await store.save(persisted, {
17595
+ bodyWriteMode: options.bodyWriteMode
17596
+ });
17597
+ for (const metadata of metadataToSave) {
17598
+ metadata.savedAt ??= observedAt;
17599
+ }
17600
+ }
17601
+ return persisted;
17452
17602
  }
17453
- assignActionId(records, actionId) {
17603
+ assignCapture(records, capture) {
17454
17604
  for (const record of records) {
17455
17605
  const metadata = this.metadataByRequestId.get(record.record.requestId);
17456
- if (!metadata || metadata.actionId === actionId) {
17606
+ if (!metadata || metadata.capture === capture) {
17457
17607
  continue;
17458
17608
  }
17459
- if (metadata.actionId !== void 0) {
17460
- this.requestIdsByActionId.get(metadata.actionId)?.delete(record.record.requestId);
17609
+ if (metadata.capture !== void 0) {
17610
+ this.requestIdsByCapture.get(metadata.capture)?.delete(record.record.requestId);
17461
17611
  }
17462
- metadata.actionId = actionId;
17463
- this.addIndexedRequestId(this.requestIdsByActionId, actionId, record.record.requestId);
17612
+ metadata.capture = capture;
17613
+ this.addIndexedRequestId(this.requestIdsByCapture, capture, record.record.requestId);
17464
17614
  }
17465
17615
  }
17466
17616
  addTag(records, tag) {
@@ -17480,8 +17630,8 @@ var NetworkJournal = class {
17480
17630
  getRequestId(recordId) {
17481
17631
  return this.requestIdByRecordId.get(recordId);
17482
17632
  }
17483
- getRequestIdsForActionId(actionId) {
17484
- return new Set(this.requestIdsByActionId.get(actionId) ?? []);
17633
+ getRequestIdsForCapture(capture) {
17634
+ return new Set(this.requestIdsByCapture.get(capture) ?? []);
17485
17635
  }
17486
17636
  getRequestIdsForTag(tag) {
17487
17637
  return new Set(this.requestIdsByTag.get(tag) ?? []);
@@ -17489,11 +17639,59 @@ var NetworkJournal = class {
17489
17639
  getPageRefForRequestId(requestId) {
17490
17640
  return this.metadataByRequestId.get(requestId)?.pageRef;
17491
17641
  }
17642
+ getKnownRequestIds() {
17643
+ return new Set(this.metadataByRequestId.keys());
17644
+ }
17645
+ tombstoneRequestIds(requestIds) {
17646
+ for (const requestId of requestIds) {
17647
+ this.tombstonedRequestIds.add(requestId);
17648
+ const metadata = this.metadataByRequestId.get(requestId);
17649
+ if (!metadata) {
17650
+ continue;
17651
+ }
17652
+ this.metadataByRequestId.delete(requestId);
17653
+ this.requestIdByRecordId.delete(metadata.recordId);
17654
+ if (metadata.capture !== void 0) {
17655
+ this.requestIdsByCapture.get(metadata.capture)?.delete(requestId);
17656
+ }
17657
+ for (const tag of metadata.tags) {
17658
+ this.requestIdsByTag.get(tag)?.delete(requestId);
17659
+ }
17660
+ }
17661
+ }
17492
17662
  clear() {
17493
17663
  this.metadataByRequestId.clear();
17494
17664
  this.requestIdByRecordId.clear();
17495
- this.requestIdsByActionId.clear();
17665
+ this.requestIdsByCapture.clear();
17496
17666
  this.requestIdsByTag.clear();
17667
+ this.tombstonedRequestIds.clear();
17668
+ }
17669
+ materializeRecord(record, observedAt, options) {
17670
+ if (this.tombstonedRequestIds.has(record.requestId)) {
17671
+ return void 0;
17672
+ }
17673
+ let metadata = this.metadataByRequestId.get(record.requestId);
17674
+ if (!metadata) {
17675
+ metadata = {
17676
+ recordId: `record:${randomUUID()}`,
17677
+ observedAt,
17678
+ ...record.pageRef === void 0 ? {} : { pageRef: record.pageRef },
17679
+ tags: /* @__PURE__ */ new Set()
17680
+ };
17681
+ this.metadataByRequestId.set(record.requestId, metadata);
17682
+ this.requestIdByRecordId.set(metadata.recordId, record.requestId);
17683
+ } else if (metadata.pageRef === void 0 && record.pageRef !== void 0) {
17684
+ metadata.pageRef = record.pageRef;
17685
+ }
17686
+ return {
17687
+ recordId: metadata.recordId,
17688
+ ...metadata.capture === void 0 ? {} : { capture: metadata.capture },
17689
+ ...metadata.tags.size === 0 ? {} : { tags: [...metadata.tags].sort() },
17690
+ ...metadata.savedAt === void 0 ? {} : { savedAt: metadata.savedAt },
17691
+ record: toProtocolNetworkRecord(record, {
17692
+ redactSecretHeaders: options.redactSecretHeaders ?? true
17693
+ })
17694
+ };
17497
17695
  }
17498
17696
  addIndexedRequestId(index, key, requestId) {
17499
17697
  const requestIds = index.get(key) ?? /* @__PURE__ */ new Set();
@@ -22305,6 +22503,7 @@ function diffInteractionTraces(left, right) {
22305
22503
 
22306
22504
  // ../runtime-core/src/sdk/runtime.ts
22307
22505
  var requireForAuthRecipeHook = createRequire(import.meta.url);
22506
+ var MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS = 5e3;
22308
22507
  var OpensteerSessionRuntime = class {
22309
22508
  workspace;
22310
22509
  rootPath;
@@ -22321,12 +22520,11 @@ var OpensteerSessionRuntime = class {
22321
22520
  engine;
22322
22521
  dom;
22323
22522
  computer;
22324
- networkJournal = new NetworkJournal();
22523
+ networkHistory = new NetworkHistory();
22325
22524
  extractionDescriptors;
22326
22525
  sessionRef;
22327
22526
  pageRef;
22328
22527
  runId;
22329
- backgroundNetworkPersistence = /* @__PURE__ */ new Set();
22330
22528
  cookieJars = /* @__PURE__ */ new Map();
22331
22529
  recipeCache = /* @__PURE__ */ new Map();
22332
22530
  ownsEngine = false;
@@ -22687,35 +22885,33 @@ var OpensteerSessionRuntime = class {
22687
22885
  async goto(input, options = {}) {
22688
22886
  assertValidSemanticOperationInput("page.goto", input);
22689
22887
  const pageRef = await this.ensurePageRef();
22690
- const startedAt = Date.now();
22691
- try {
22692
- const { navigation, state } = await this.runWithOperationTimeout(
22693
- "page.goto",
22694
- async (timeout) => {
22695
- const baselineRequestIds = await this.beginMutationCapture(timeout);
22696
- try {
22697
- const navigation2 = await this.navigatePage(
22698
- {
22699
- operation: "page.goto",
22700
- pageRef,
22701
- url: input.url
22702
- },
22703
- timeout
22704
- );
22705
- timeout.throwIfAborted();
22706
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
22707
- return {
22708
- navigation: navigation2,
22709
- state: await timeout.runStep(() => this.readSessionState())
22710
- };
22711
- } catch (error) {
22712
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
22713
- () => void 0
22714
- );
22715
- throw error;
22716
- }
22888
+ const startedAt = Date.now();
22889
+ let mutationCaptureDiagnostics;
22890
+ try {
22891
+ const { navigation, state } = await this.runMutationCapturedOperation(
22892
+ "page.goto",
22893
+ {
22894
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
22895
+ options
22717
22896
  },
22718
- options
22897
+ async (timeout) => {
22898
+ const navigation2 = await this.navigatePage(
22899
+ {
22900
+ operation: "page.goto",
22901
+ pageRef,
22902
+ url: input.url
22903
+ },
22904
+ timeout
22905
+ );
22906
+ timeout.throwIfAborted();
22907
+ return {
22908
+ navigation: navigation2,
22909
+ state: await timeout.runStep(() => this.readSessionState())
22910
+ };
22911
+ },
22912
+ (diagnostics) => {
22913
+ mutationCaptureDiagnostics = diagnostics;
22914
+ }
22719
22915
  );
22720
22916
  await this.appendTrace({
22721
22917
  operation: "page.goto",
@@ -22724,7 +22920,8 @@ var OpensteerSessionRuntime = class {
22724
22920
  outcome: "ok",
22725
22921
  data: {
22726
22922
  url: input.url,
22727
- state
22923
+ state,
22924
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
22728
22925
  },
22729
22926
  context: buildRuntimeTraceContext({
22730
22927
  sessionRef: this.sessionRef,
@@ -22740,6 +22937,7 @@ var OpensteerSessionRuntime = class {
22740
22937
  completedAt: Date.now(),
22741
22938
  outcome: "error",
22742
22939
  error,
22940
+ data: buildMutationCaptureTraceData(mutationCaptureDiagnostics),
22743
22941
  context: buildRuntimeTraceContext({
22744
22942
  sessionRef: this.sessionRef,
22745
22943
  pageRef
@@ -22752,9 +22950,11 @@ var OpensteerSessionRuntime = class {
22752
22950
  assertValidSemanticOperationInput("page.evaluate", input);
22753
22951
  const pageRef = input.pageRef ?? await this.ensurePageRef();
22754
22952
  const startedAt = Date.now();
22953
+ let mutationCaptureDiagnostics;
22755
22954
  try {
22756
- const output = await this.runWithOperationTimeout(
22955
+ const output = await this.runMutationCapturedOperation(
22757
22956
  "page.evaluate",
22957
+ { options },
22758
22958
  async (timeout) => {
22759
22959
  const remainingMs = timeout.remainingMs();
22760
22960
  const evaluated = await timeout.runStep(
@@ -22770,7 +22970,9 @@ var OpensteerSessionRuntime = class {
22770
22970
  value: toJsonValueOrNull(evaluated.data)
22771
22971
  };
22772
22972
  },
22773
- options
22973
+ (diagnostics) => {
22974
+ mutationCaptureDiagnostics = diagnostics;
22975
+ }
22774
22976
  );
22775
22977
  await this.appendTrace({
22776
22978
  operation: "page.evaluate",
@@ -22779,7 +22981,8 @@ var OpensteerSessionRuntime = class {
22779
22981
  outcome: "ok",
22780
22982
  data: {
22781
22983
  pageRef: output.pageRef,
22782
- value: output.value
22984
+ value: output.value,
22985
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
22783
22986
  },
22784
22987
  context: buildRuntimeTraceContext({
22785
22988
  sessionRef: this.sessionRef,
@@ -22794,6 +22997,7 @@ var OpensteerSessionRuntime = class {
22794
22997
  completedAt: Date.now(),
22795
22998
  outcome: "error",
22796
22999
  error,
23000
+ data: buildMutationCaptureTraceData(mutationCaptureDiagnostics),
22797
23001
  context: buildRuntimeTraceContext({
22798
23002
  sessionRef: this.sessionRef,
22799
23003
  pageRef
@@ -23132,38 +23336,19 @@ var OpensteerSessionRuntime = class {
23132
23336
  }
23133
23337
  async queryNetwork(input = {}, options = {}) {
23134
23338
  assertValidSemanticOperationInput("network.query", input);
23135
- if (input.source !== "saved") {
23136
- await this.ensurePageRef();
23137
- }
23138
23339
  const root = await this.ensureRoot();
23139
23340
  const startedAt = Date.now();
23140
23341
  try {
23141
23342
  const output = await this.runWithOperationTimeout(
23142
23343
  "network.query",
23143
23344
  async (timeout) => {
23144
- if (input.source === "saved") {
23145
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
23146
- return {
23147
- records: await timeout.runStep(
23148
- () => root.registry.savedNetwork.query({
23149
- ...input.recordId === void 0 ? {} : { recordId: input.recordId },
23150
- ...input.requestId === void 0 ? {} : { requestId: input.requestId },
23151
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
23152
- ...input.tag === void 0 ? {} : { tag: input.tag },
23153
- ...input.url === void 0 ? {} : { url: input.url },
23154
- ...input.hostname === void 0 ? {} : { hostname: input.hostname },
23155
- ...input.path === void 0 ? {} : { path: input.path },
23156
- ...input.method === void 0 ? {} : { method: input.method },
23157
- ...input.status === void 0 ? {} : { status: input.status },
23158
- ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType },
23159
- ...input.includeBodies === void 0 ? {} : { includeBodies: input.includeBodies },
23160
- ...input.limit === void 0 ? {} : { limit: input.limit }
23161
- })
23162
- )
23163
- };
23164
- }
23345
+ await this.syncPersistedNetworkSelection(timeout, input, {
23346
+ includeBodies: input.includeBodies ?? false
23347
+ });
23165
23348
  return {
23166
- records: await this.queryLiveNetwork(input, timeout)
23349
+ records: await timeout.runStep(
23350
+ () => root.registry.savedNetwork.query(this.toSavedNetworkQueryInput(input))
23351
+ )
23167
23352
  };
23168
23353
  },
23169
23354
  options
@@ -23174,7 +23359,6 @@ var OpensteerSessionRuntime = class {
23174
23359
  completedAt: Date.now(),
23175
23360
  outcome: "ok",
23176
23361
  data: {
23177
- source: input.source ?? "live",
23178
23362
  includeBodies: input.includeBodies ?? false,
23179
23363
  limit: input.limit ?? 50,
23180
23364
  count: output.records.length
@@ -23200,56 +23384,42 @@ var OpensteerSessionRuntime = class {
23200
23384
  throw error;
23201
23385
  }
23202
23386
  }
23203
- async saveNetwork(input, options = {}) {
23204
- assertValidSemanticOperationInput("network.save", input);
23205
- await this.ensurePageRef();
23387
+ async tagNetwork(input, options = {}) {
23388
+ assertValidSemanticOperationInput("network.tag", input);
23206
23389
  const root = await this.ensureRoot();
23390
+ const filter = this.toQueryInputFromTagInput(input);
23391
+ const savedFilter = this.toSavedNetworkQueryInput(filter);
23207
23392
  const startedAt = Date.now();
23208
23393
  try {
23209
23394
  const output = await this.runWithOperationTimeout(
23210
- "network.save",
23395
+ "network.tag",
23211
23396
  async (timeout) => {
23212
- const records = await this.queryLiveNetwork(
23213
- {
23214
- includeBodies: true,
23215
- source: "live",
23216
- ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
23217
- ...input.recordId === void 0 ? {} : { recordId: input.recordId },
23218
- ...input.requestId === void 0 ? {} : { requestId: input.requestId },
23219
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
23220
- ...input.url === void 0 ? {} : { url: input.url },
23221
- ...input.hostname === void 0 ? {} : { hostname: input.hostname },
23222
- ...input.path === void 0 ? {} : { path: input.path },
23223
- ...input.method === void 0 ? {} : { method: input.method },
23224
- ...input.status === void 0 ? {} : { status: input.status },
23225
- ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
23226
- },
23227
- timeout,
23228
- { ignoreLimit: true, redactSecretHeaders: false }
23229
- );
23230
- this.networkJournal.addTag(records, input.tag);
23397
+ const records = await this.syncPersistedNetworkSelection(timeout, filter, {
23398
+ includeBodies: false
23399
+ });
23400
+ this.networkHistory.addTag(records, input.tag);
23231
23401
  return {
23232
- savedCount: await timeout.runStep(
23233
- () => root.registry.savedNetwork.save(records, input.tag)
23402
+ taggedCount: await timeout.runStep(
23403
+ () => root.registry.savedNetwork.tagByFilter(savedFilter, input.tag)
23234
23404
  )
23235
23405
  };
23236
23406
  },
23237
23407
  options
23238
23408
  );
23239
23409
  await this.appendTrace({
23240
- operation: "network.save",
23410
+ operation: "network.tag",
23241
23411
  startedAt,
23242
23412
  completedAt: Date.now(),
23243
23413
  outcome: "ok",
23244
23414
  data: {
23245
23415
  tag: input.tag,
23246
- savedCount: output.savedCount
23416
+ taggedCount: output.taggedCount
23247
23417
  }
23248
23418
  });
23249
23419
  return output;
23250
23420
  } catch (error) {
23251
23421
  await this.appendTrace({
23252
- operation: "network.save",
23422
+ operation: "network.tag",
23253
23423
  startedAt,
23254
23424
  completedAt: Date.now(),
23255
23425
  outcome: "error",
@@ -23266,7 +23436,31 @@ var OpensteerSessionRuntime = class {
23266
23436
  const output = await this.runWithOperationTimeout(
23267
23437
  "network.clear",
23268
23438
  async (timeout) => {
23269
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
23439
+ if (this.sessionRef !== void 0) {
23440
+ if (input.capture !== void 0 || input.tag !== void 0) {
23441
+ const records = await this.queryLiveNetwork(
23442
+ {
23443
+ ...input.capture === void 0 ? {} : { capture: input.capture },
23444
+ ...input.tag === void 0 ? {} : { tag: input.tag }
23445
+ },
23446
+ timeout,
23447
+ {
23448
+ ignoreLimit: true
23449
+ }
23450
+ );
23451
+ this.networkHistory.tombstoneRequestIds(
23452
+ records.map((record) => record.record.requestId)
23453
+ );
23454
+ } else {
23455
+ const liveRequestIds = await this.readLiveRequestIds(timeout, {
23456
+ includeCurrentPageOnly: false
23457
+ });
23458
+ this.networkHistory.tombstoneRequestIds(liveRequestIds);
23459
+ }
23460
+ }
23461
+ if (input.capture === void 0 && input.tag === void 0) {
23462
+ this.networkHistory.tombstoneRequestIds(this.networkHistory.getKnownRequestIds());
23463
+ }
23270
23464
  return {
23271
23465
  clearedCount: await timeout.runStep(() => root.registry.savedNetwork.clear(input))
23272
23466
  };
@@ -23279,6 +23473,7 @@ var OpensteerSessionRuntime = class {
23279
23473
  completedAt: Date.now(),
23280
23474
  outcome: "ok",
23281
23475
  data: {
23476
+ ...input.capture === void 0 ? {} : { capture: input.capture },
23282
23477
  ...input.tag === void 0 ? {} : { tag: input.tag },
23283
23478
  clearedCount: output.clearedCount
23284
23479
  }
@@ -23983,7 +24178,6 @@ var OpensteerSessionRuntime = class {
23983
24178
  });
23984
24179
  const networkRecords = await this.queryLiveNetwork(
23985
24180
  {
23986
- source: "live",
23987
24181
  pageRef,
23988
24182
  ...input.network?.url === void 0 ? {} : { url: input.network.url },
23989
24183
  ...input.network?.hostname === void 0 ? {} : { hostname: input.network.hostname },
@@ -23999,7 +24193,7 @@ var OpensteerSessionRuntime = class {
23999
24193
  );
24000
24194
  const persistedNetwork = filterReverseObservationWindow(
24001
24195
  networkRecords.filter(isReverseRelevantNetworkRecord),
24002
- this.networkJournal,
24196
+ this.networkHistory,
24003
24197
  input.captureWindowMs
24004
24198
  );
24005
24199
  const fallbackSavedNetwork = persistedNetwork.length === 0 ? (await root.registry.savedNetwork.query({
@@ -24014,7 +24208,10 @@ var OpensteerSessionRuntime = class {
24014
24208
  const observationId = `observation:${randomUUID()}`;
24015
24209
  const networkTag = `reverse-case:${caseRecord.id}:${observationId}`;
24016
24210
  if (observationNetwork.length > 0) {
24017
- await root.registry.savedNetwork.save(observationNetwork, networkTag);
24211
+ await root.registry.savedNetwork.save(observationNetwork, {
24212
+ tag: networkTag,
24213
+ bodyWriteMode: input.network?.includeBodies === false ? "metadata-only" : "authoritative"
24214
+ });
24018
24215
  }
24019
24216
  const scriptArtifactIds = input.includeScripts === false ? [] : (await this.captureScriptsInternal(
24020
24217
  pageRef,
@@ -24110,7 +24307,7 @@ var OpensteerSessionRuntime = class {
24110
24307
  includeBodies: true,
24111
24308
  redactSecretHeaders: false
24112
24309
  }),
24113
- observedAt: this.networkJournal.getObservedAt(recordId)
24310
+ observedAt: this.networkHistory.getObservedAt(recordId)
24114
24311
  }))
24115
24312
  );
24116
24313
  const clusteredRecords = observationRecords.map((entry) => {
@@ -24458,7 +24655,9 @@ var OpensteerSessionRuntime = class {
24458
24655
  };
24459
24656
  }
24460
24657
  const bindings = /* @__PURE__ */ new Map();
24461
- const baselineRequestIds = await this.beginMutationCapture(timeout);
24658
+ const baselineRequestIds = await this.readLiveRequestIds(timeout, {
24659
+ includeCurrentPageOnly: true
24660
+ });
24462
24661
  const pageRef = explicitPageRef ?? await this.ensurePageRef();
24463
24662
  const validatorMap = new Map(
24464
24663
  packageRecord.payload.validators.map((validator) => [validator.id, validator])
@@ -25050,7 +25249,10 @@ var OpensteerSessionRuntime = class {
25050
25249
  timeout.signal
25051
25250
  )).filter((record) => !baselineRequestIds.has(record.record.requestId));
25052
25251
  if (deltaRecords.length > 0) {
25053
- await root.registry.savedNetwork.save(deltaRecords, `interaction:${pageRef}`);
25252
+ await root.registry.savedNetwork.save(deltaRecords, {
25253
+ tag: `interaction:${pageRef}`,
25254
+ bodyWriteMode: "authoritative"
25255
+ });
25054
25256
  }
25055
25257
  const trace = await root.registry.interactionTraces.write({
25056
25258
  key: input.key ?? buildInteractionTraceKey(pageInfo.url),
@@ -25393,7 +25595,7 @@ var OpensteerSessionRuntime = class {
25393
25595
  includeBodies: true
25394
25596
  });
25395
25597
  const inferred = inferRequestPlanFromNetworkRecord(source, input, {
25396
- ...this.networkJournal.getObservedAt(source.recordId) === void 0 ? {} : { observedAt: this.networkJournal.getObservedAt(source.recordId) }
25598
+ ...this.networkHistory.getObservedAt(source.recordId) === void 0 ? {} : { observedAt: this.networkHistory.getObservedAt(source.recordId) }
25397
25599
  });
25398
25600
  return timeout.runStep(
25399
25601
  () => root.registry.requestPlans.write({
@@ -26127,33 +26329,38 @@ var OpensteerSessionRuntime = class {
26127
26329
  assertValidSemanticOperationInput("computer.execute", input);
26128
26330
  const pageRef = await this.ensurePageRef();
26129
26331
  const startedAt = Date.now();
26332
+ let mutationCaptureDiagnostics;
26333
+ let boundaryDiagnostics;
26130
26334
  try {
26131
- const { artifacts, output } = await this.runWithOperationTimeout(
26335
+ const { artifacts, output } = await this.runMutationCapturedOperation(
26132
26336
  "computer.execute",
26337
+ {
26338
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
26339
+ options
26340
+ },
26133
26341
  async (timeout) => {
26134
- const baselineRequestIds = await this.beginMutationCapture(timeout);
26135
26342
  try {
26136
26343
  const output2 = await this.requireComputer().execute({
26137
26344
  pageRef,
26138
26345
  input,
26139
26346
  timeout
26140
26347
  });
26348
+ boundaryDiagnostics = takeActionBoundaryDiagnostics(timeout.signal);
26141
26349
  timeout.throwIfAborted();
26142
26350
  this.pageRef = output2.pageRef;
26143
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
26144
26351
  const artifacts2 = await this.persistComputerArtifacts(output2, timeout);
26145
26352
  return {
26146
26353
  artifacts: { manifests: artifacts2.manifests },
26147
26354
  output: artifacts2.output
26148
26355
  };
26149
26356
  } catch (error) {
26150
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
26151
- () => void 0
26152
- );
26357
+ boundaryDiagnostics ??= takeActionBoundaryDiagnostics(timeout.signal);
26153
26358
  throw error;
26154
26359
  }
26155
26360
  },
26156
- options
26361
+ (diagnostics) => {
26362
+ mutationCaptureDiagnostics = diagnostics;
26363
+ }
26157
26364
  );
26158
26365
  await this.appendTrace({
26159
26366
  operation: "computer.execute",
@@ -26169,6 +26376,8 @@ var OpensteerSessionRuntime = class {
26169
26376
  nativeViewport: output.nativeViewport,
26170
26377
  displayScale: output.displayScale,
26171
26378
  timing: output.timing,
26379
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
26380
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics),
26172
26381
  ...output.trace === void 0 ? {} : { trace: output.trace }
26173
26382
  },
26174
26383
  context: buildRuntimeTraceContext({
@@ -26187,6 +26396,10 @@ var OpensteerSessionRuntime = class {
26187
26396
  completedAt: Date.now(),
26188
26397
  outcome: "error",
26189
26398
  error,
26399
+ data: {
26400
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
26401
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
26402
+ },
26190
26403
  context: buildRuntimeTraceContext({
26191
26404
  sessionRef: this.sessionRef,
26192
26405
  pageRef: this.pageRef
@@ -26205,7 +26418,7 @@ var OpensteerSessionRuntime = class {
26205
26418
  await this.runWithOperationTimeout(
26206
26419
  "session.close",
26207
26420
  async (timeout) => {
26208
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
26421
+ await timeout.runStep(() => this.flushPersistedNetworkHistory());
26209
26422
  if (engine === void 0) {
26210
26423
  return;
26211
26424
  }
@@ -26274,10 +26487,7 @@ var OpensteerSessionRuntime = class {
26274
26487
  }
26275
26488
  async disconnect() {
26276
26489
  try {
26277
- await this.flushBackgroundNetworkPersistence();
26278
- if (this.sessionRef !== void 0 && this.pageRef !== void 0) {
26279
- await this.saveNetwork({ tag: "auto" }).catch(() => void 0);
26280
- }
26490
+ await this.flushPersistedNetworkHistory();
26281
26491
  } finally {
26282
26492
  await this.resetRuntimeState({
26283
26493
  disposeEngine: true
@@ -26293,33 +26503,38 @@ var OpensteerSessionRuntime = class {
26293
26503
  async runDomAction(operation, input, executor, options = {}) {
26294
26504
  const pageRef = await this.ensurePageRef();
26295
26505
  const startedAt = Date.now();
26506
+ let mutationCaptureDiagnostics;
26507
+ let boundaryDiagnostics;
26296
26508
  try {
26297
- const { executed, preparedTarget } = await this.runWithOperationTimeout(
26509
+ const { executed, preparedTarget } = await this.runMutationCapturedOperation(
26298
26510
  operation,
26511
+ {
26512
+ ...input.captureNetwork === void 0 ? {} : { captureNetwork: input.captureNetwork },
26513
+ options
26514
+ },
26299
26515
  async (timeout) => {
26300
- const baselineRequestIds = await this.beginMutationCapture(timeout);
26516
+ const preparedTarget2 = await this.prepareDomTarget(
26517
+ pageRef,
26518
+ operation,
26519
+ input.target,
26520
+ input.persistAsDescription,
26521
+ timeout
26522
+ );
26301
26523
  try {
26302
- const preparedTarget2 = await this.prepareDomTarget(
26303
- pageRef,
26304
- operation,
26305
- input.target,
26306
- input.persistAsDescription,
26307
- timeout
26308
- );
26309
26524
  const executed2 = await executor(pageRef, preparedTarget2.target, timeout);
26310
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
26525
+ boundaryDiagnostics = takeActionBoundaryDiagnostics(timeout.signal);
26311
26526
  return {
26312
26527
  executed: executed2,
26313
26528
  preparedTarget: preparedTarget2
26314
26529
  };
26315
26530
  } catch (error) {
26316
- await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag).catch(
26317
- () => void 0
26318
- );
26531
+ boundaryDiagnostics ??= takeActionBoundaryDiagnostics(timeout.signal);
26319
26532
  throw error;
26320
26533
  }
26321
26534
  },
26322
- options
26535
+ (diagnostics) => {
26536
+ mutationCaptureDiagnostics = diagnostics;
26537
+ }
26323
26538
  );
26324
26539
  const output = toOpensteerActionResult(executed.result, preparedTarget.persistedDescription);
26325
26540
  await this.appendTrace({
@@ -26330,7 +26545,9 @@ var OpensteerSessionRuntime = class {
26330
26545
  data: {
26331
26546
  target: output.target,
26332
26547
  ...output.point === void 0 ? {} : { point: output.point },
26333
- ...output.persistedDescription === void 0 ? {} : { persistedDescription: output.persistedDescription }
26548
+ ...output.persistedDescription === void 0 ? {} : { persistedDescription: output.persistedDescription },
26549
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
26550
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
26334
26551
  },
26335
26552
  context: buildRuntimeTraceContext({
26336
26553
  sessionRef: this.sessionRef,
@@ -26348,6 +26565,10 @@ var OpensteerSessionRuntime = class {
26348
26565
  completedAt: Date.now(),
26349
26566
  outcome: "error",
26350
26567
  error,
26568
+ data: {
26569
+ ...boundaryDiagnostics === void 0 ? {} : { settle: boundaryDiagnostics },
26570
+ ...buildMutationCaptureTraceData(mutationCaptureDiagnostics)
26571
+ },
26351
26572
  context: buildRuntimeTraceContext({
26352
26573
  sessionRef: this.sessionRef,
26353
26574
  pageRef
@@ -26369,7 +26590,10 @@ var OpensteerSessionRuntime = class {
26369
26590
  };
26370
26591
  }
26371
26592
  if (target.kind === "element") {
26372
- const elementTarget = { kind: "selector", selector: `[c="${String(target.element)}"]` };
26593
+ const elementTarget = {
26594
+ kind: "selector",
26595
+ selector: `[c="${String(target.element)}"]`
26596
+ };
26373
26597
  const resolved2 = await timeout.runStep(
26374
26598
  () => this.requireDom().resolveTarget({
26375
26599
  pageRef,
@@ -26432,11 +26656,11 @@ var OpensteerSessionRuntime = class {
26432
26656
  };
26433
26657
  }
26434
26658
  async queryLiveNetwork(input, timeout, options = {}) {
26435
- const requestIds = resolveLiveQueryRequestIds(input, this.networkJournal);
26659
+ const requestIds = resolveLiveQueryRequestIds(input, this.networkHistory);
26436
26660
  if (requestIds !== void 0 && requestIds.length === 0) {
26437
26661
  return [];
26438
26662
  }
26439
- const pageRef = resolveLiveQueryPageRef(input, this.pageRef, requestIds, this.networkJournal);
26663
+ const pageRef = resolveLiveQueryPageRef(input, this.pageRef, requestIds, this.networkHistory);
26440
26664
  const includeCurrentPageOnly = pageRef === void 0 && input.recordId === void 0;
26441
26665
  const metadataRecords = await timeout.runStep(
26442
26666
  () => this.readLiveNetworkRecords(
@@ -26454,7 +26678,7 @@ var OpensteerSessionRuntime = class {
26454
26678
  const filtered = filterNetworkQueryRecords(metadataRecords, {
26455
26679
  ...input.recordId === void 0 ? {} : { recordId: input.recordId },
26456
26680
  ...input.requestId === void 0 ? {} : { requestId: input.requestId },
26457
- ...input.actionId === void 0 ? {} : { actionId: input.actionId },
26681
+ ...input.capture === void 0 ? {} : { capture: input.capture },
26458
26682
  ...input.tag === void 0 ? {} : { tag: input.tag },
26459
26683
  ...input.url === void 0 ? {} : { url: input.url },
26460
26684
  ...input.hostname === void 0 ? {} : { hostname: input.hostname },
@@ -26463,7 +26687,7 @@ var OpensteerSessionRuntime = class {
26463
26687
  ...input.status === void 0 ? {} : { status: input.status },
26464
26688
  ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
26465
26689
  });
26466
- const sorted = sortLiveNetworkRecords(filtered, this.networkJournal);
26690
+ const sorted = sortLiveNetworkRecords(filtered, this.networkHistory);
26467
26691
  const limit = options.ignoreLimit ? sorted.length : Math.max(1, Math.min(input.limit ?? 50, 200));
26468
26692
  const limited = sorted.slice(0, limit);
26469
26693
  if (!(input.includeBodies ?? false) || limited.length === 0) {
@@ -26660,40 +26884,95 @@ var OpensteerSessionRuntime = class {
26660
26884
  artifactId: manifest.artifactId
26661
26885
  };
26662
26886
  }
26663
- beginMutationCapture(timeout) {
26664
- return this.readLiveRequestIds(timeout, {
26665
- includeCurrentPageOnly: true
26666
- });
26667
- }
26668
- async completeMutationCapture(timeout, baselineRequestIds, networkTag) {
26669
- const records = await timeout.runStep(
26670
- () => this.readLiveNetworkRecords(
26671
- {
26672
- includeBodies: false,
26673
- includeCurrentPageOnly: true
26887
+ async runMutationCapturedOperation(operation, input, execute, onFinalized) {
26888
+ let plan;
26889
+ try {
26890
+ const result = await this.runWithOperationTimeout(
26891
+ operation,
26892
+ async (timeout) => {
26893
+ plan = await this.beginMutationCapture(timeout, input.captureNetwork);
26894
+ return execute(timeout);
26674
26895
  },
26675
- timeout.signal
26676
- )
26896
+ input.options
26897
+ );
26898
+ const diagnostics = await this.finalizeMutationCaptureBestEffort(plan);
26899
+ onFinalized?.(diagnostics);
26900
+ return result;
26901
+ } catch (error) {
26902
+ const diagnostics = await this.finalizeMutationCaptureBestEffort(plan);
26903
+ onFinalized?.(diagnostics);
26904
+ throw error;
26905
+ }
26906
+ }
26907
+ async beginMutationCapture(timeout, capture) {
26908
+ if (capture === void 0) {
26909
+ return void 0;
26910
+ }
26911
+ return {
26912
+ baselineRequestIds: await this.readLiveRequestIds(timeout, {
26913
+ includeCurrentPageOnly: true
26914
+ }),
26915
+ capture
26916
+ };
26917
+ }
26918
+ async finalizeMutationCaptureBestEffort(plan) {
26919
+ if (plan === void 0) {
26920
+ return {};
26921
+ }
26922
+ try {
26923
+ await withDetachedTimeoutSignal(MUTATION_CAPTURE_FINALIZE_TIMEOUT_MS, async (signal) => {
26924
+ await this.completeMutationCaptureWithSignal(signal, plan);
26925
+ });
26926
+ return {};
26927
+ } catch (error) {
26928
+ return {
26929
+ finalizeError: normalizeOpensteerError(error)
26930
+ };
26931
+ }
26932
+ }
26933
+ async completeMutationCaptureWithSignal(signal, plan) {
26934
+ const records = await this.readLiveNetworkRecords(
26935
+ {
26936
+ includeBodies: false,
26937
+ includeCurrentPageOnly: true
26938
+ },
26939
+ signal
26677
26940
  );
26678
- const delta = records.filter((record) => !baselineRequestIds.has(record.record.requestId));
26941
+ const delta = records.filter((record) => !plan.baselineRequestIds.has(record.record.requestId));
26679
26942
  if (delta.length === 0) {
26680
26943
  return;
26681
26944
  }
26682
- this.networkJournal.assignActionId(delta, `action:${randomUUID()}`);
26683
- if (networkTag === void 0) {
26684
- return;
26685
- }
26686
- this.networkJournal.addTag(delta, networkTag);
26687
- this.scheduleBackgroundNetworkSaveByRequestIds(
26945
+ this.networkHistory.assignCapture(delta, plan.capture);
26946
+ await this.persistLiveRequestIdsWithSignal(
26688
26947
  delta.map((record) => record.record.requestId),
26689
- networkTag
26948
+ signal,
26949
+ {
26950
+ includeCurrentPageOnly: true
26951
+ }
26690
26952
  );
26691
26953
  }
26692
26954
  async resolveNetworkRecordByRecordId(recordId, timeout, options) {
26693
26955
  const root = await this.ensureRoot();
26956
+ await this.syncPersistedNetworkSelection(
26957
+ timeout,
26958
+ {
26959
+ recordId,
26960
+ includeBodies: options.includeBodies
26961
+ },
26962
+ {
26963
+ includeBodies: options.includeBodies
26964
+ }
26965
+ );
26966
+ const saved = await timeout.runStep(
26967
+ () => root.registry.savedNetwork.getByRecordId(recordId, {
26968
+ includeBodies: options.includeBodies
26969
+ })
26970
+ );
26971
+ if (saved) {
26972
+ return saved;
26973
+ }
26694
26974
  const live = await this.queryLiveNetwork(
26695
26975
  {
26696
- source: "live",
26697
26976
  recordId,
26698
26977
  includeBodies: options.includeBodies,
26699
26978
  limit: 1
@@ -26704,24 +26983,15 @@ var OpensteerSessionRuntime = class {
26704
26983
  ...options.redactSecretHeaders === void 0 ? {} : { redactSecretHeaders: options.redactSecretHeaders }
26705
26984
  }
26706
26985
  );
26707
- if (live.length > 0) {
26986
+ if (live[0] !== void 0) {
26708
26987
  return live[0];
26709
26988
  }
26710
- await timeout.runStep(() => this.flushBackgroundNetworkPersistence());
26711
- const saved = await timeout.runStep(
26712
- () => root.registry.savedNetwork.getByRecordId(recordId, {
26713
- includeBodies: options.includeBodies
26714
- })
26715
- );
26716
- if (!saved) {
26717
- throw new OpensteerProtocolError("not-found", `network record ${recordId} was not found`, {
26718
- details: {
26719
- recordId,
26720
- kind: "network-record"
26721
- }
26722
- });
26723
- }
26724
- return saved;
26989
+ throw new OpensteerProtocolError("not-found", `network record ${recordId} was not found`, {
26990
+ details: {
26991
+ recordId,
26992
+ kind: "network-record"
26993
+ }
26994
+ });
26725
26995
  }
26726
26996
  resolveCurrentStateSource() {
26727
26997
  const ownership = this.sessionInfoBase.provider?.ownership;
@@ -26961,7 +27231,6 @@ var OpensteerSessionRuntime = class {
26961
27231
  timeout.throwIfAborted();
26962
27232
  const records = await this.queryLiveNetwork(
26963
27233
  {
26964
- source: "live",
26965
27234
  pageRef,
26966
27235
  url,
26967
27236
  method,
@@ -26992,7 +27261,6 @@ var OpensteerSessionRuntime = class {
26992
27261
  timeout.throwIfAborted();
26993
27262
  const records = await this.queryLiveNetwork(
26994
27263
  {
26995
- source: "live",
26996
27264
  pageRef,
26997
27265
  ...filter.url === void 0 ? {} : { url: filter.url },
26998
27266
  ...filter.host === void 0 ? {} : { hostname: filter.host },
@@ -27058,12 +27326,12 @@ var OpensteerSessionRuntime = class {
27058
27326
  };
27059
27327
  }
27060
27328
  }
27061
- async readLiveNetworkRecords(input, signal) {
27329
+ async readBrowserNetworkRecords(input, signal) {
27062
27330
  const sessionRef = this.sessionRef;
27063
27331
  if (!sessionRef) {
27064
27332
  throw new Error("Opensteer session is not initialized");
27065
27333
  }
27066
- const records = await this.requireEngine().getNetworkRecords({
27334
+ return this.requireEngine().getNetworkRecords({
27067
27335
  sessionRef,
27068
27336
  ...input.includeCurrentPageOnly === false || input.pageRef !== void 0 ? input.pageRef === void 0 ? {} : { pageRef: input.pageRef } : this.pageRef === void 0 ? {} : { pageRef: this.pageRef },
27069
27337
  ...input.requestIds === void 0 ? {} : { requestIds: input.requestIds },
@@ -27076,10 +27344,103 @@ var OpensteerSessionRuntime = class {
27076
27344
  includeBodies: input.includeBodies,
27077
27345
  signal
27078
27346
  });
27079
- return this.networkJournal.sync(records, {
27347
+ }
27348
+ async readLiveNetworkRecords(input, signal) {
27349
+ const records = await this.readBrowserNetworkRecords(input, signal);
27350
+ return this.networkHistory.materialize(records, {
27080
27351
  redactSecretHeaders: input.redactSecretHeaders ?? true
27081
27352
  });
27082
27353
  }
27354
+ async persistLiveRequestIds(requestIds, timeout, options) {
27355
+ return timeout.runStep(
27356
+ () => this.persistLiveRequestIdsWithSignal(requestIds, timeout.signal, options)
27357
+ );
27358
+ }
27359
+ async persistLiveRequestIdsWithSignal(requestIds, signal, options) {
27360
+ if (requestIds.length === 0) {
27361
+ return [];
27362
+ }
27363
+ const root = await this.ensureRoot();
27364
+ const browserRecords = await this.readBrowserNetworkRecords(
27365
+ {
27366
+ includeBodies: true,
27367
+ includeCurrentPageOnly: options.includeCurrentPageOnly,
27368
+ ...options.pageRef === void 0 ? {} : { pageRef: options.pageRef },
27369
+ requestIds
27370
+ },
27371
+ signal
27372
+ );
27373
+ return this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
27374
+ bodyWriteMode: "authoritative",
27375
+ redactSecretHeaders: false
27376
+ });
27377
+ }
27378
+ async syncPersistedNetworkSelection(timeout, input, options) {
27379
+ if (this.sessionRef === void 0) {
27380
+ return [];
27381
+ }
27382
+ const requestIds = resolveLiveQueryRequestIds(input, this.networkHistory);
27383
+ if (requestIds !== void 0 && requestIds.length === 0) {
27384
+ return [];
27385
+ }
27386
+ const pageRef = resolveLiveQueryPageRef(input, this.pageRef, requestIds, this.networkHistory);
27387
+ const includeCurrentPageOnly = pageRef === void 0 && input.recordId === void 0;
27388
+ const browserRecords = await timeout.runStep(
27389
+ () => this.readBrowserNetworkRecords(
27390
+ {
27391
+ ...pageRef === void 0 ? {} : { pageRef },
27392
+ ...requestIds === void 0 ? {} : { requestIds },
27393
+ ...input.url === void 0 ? {} : { url: input.url },
27394
+ ...input.hostname === void 0 ? {} : { hostname: input.hostname },
27395
+ ...input.path === void 0 ? {} : { path: input.path },
27396
+ ...input.method === void 0 ? {} : { method: input.method },
27397
+ ...input.status === void 0 ? {} : { status: input.status },
27398
+ ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType },
27399
+ includeBodies: options.includeBodies,
27400
+ includeCurrentPageOnly
27401
+ },
27402
+ timeout.signal
27403
+ )
27404
+ );
27405
+ const root = await this.ensureRoot();
27406
+ return timeout.runStep(
27407
+ () => this.networkHistory.persist(browserRecords, root.registry.savedNetwork, {
27408
+ bodyWriteMode: options.includeBodies ? "authoritative" : "metadata-only",
27409
+ redactSecretHeaders: false
27410
+ })
27411
+ );
27412
+ }
27413
+ toSavedNetworkQueryInput(input) {
27414
+ return {
27415
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
27416
+ ...input.recordId === void 0 ? {} : { recordId: input.recordId },
27417
+ ...input.requestId === void 0 ? {} : { requestId: input.requestId },
27418
+ ...input.capture === void 0 ? {} : { capture: input.capture },
27419
+ ...input.tag === void 0 ? {} : { tag: input.tag },
27420
+ ...input.url === void 0 ? {} : { url: input.url },
27421
+ ...input.hostname === void 0 ? {} : { hostname: input.hostname },
27422
+ ...input.path === void 0 ? {} : { path: input.path },
27423
+ ...input.method === void 0 ? {} : { method: input.method },
27424
+ ...input.status === void 0 ? {} : { status: input.status },
27425
+ ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType },
27426
+ ...input.includeBodies === void 0 ? {} : { includeBodies: input.includeBodies },
27427
+ ...input.limit === void 0 ? {} : { limit: input.limit }
27428
+ };
27429
+ }
27430
+ toQueryInputFromTagInput(input) {
27431
+ return {
27432
+ ...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
27433
+ ...input.recordId === void 0 ? {} : { recordId: input.recordId },
27434
+ ...input.requestId === void 0 ? {} : { requestId: input.requestId },
27435
+ ...input.capture === void 0 ? {} : { capture: input.capture },
27436
+ ...input.url === void 0 ? {} : { url: input.url },
27437
+ ...input.hostname === void 0 ? {} : { hostname: input.hostname },
27438
+ ...input.path === void 0 ? {} : { path: input.path },
27439
+ ...input.method === void 0 ? {} : { method: input.method },
27440
+ ...input.status === void 0 ? {} : { status: input.status },
27441
+ ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
27442
+ };
27443
+ }
27083
27444
  async readLiveRequestIds(timeout, options) {
27084
27445
  const records = await timeout.runStep(
27085
27446
  () => this.readLiveNetworkRecords(
@@ -27103,7 +27464,17 @@ var OpensteerSessionRuntime = class {
27103
27464
  )
27104
27465
  );
27105
27466
  const delta = records.filter((record) => !baselineRequestIds.has(record.record.requestId));
27106
- return sortLiveNetworkRecords(delta, this.networkJournal)[0]?.recordId;
27467
+ if (delta.length === 0) {
27468
+ return void 0;
27469
+ }
27470
+ await this.persistLiveRequestIds(
27471
+ delta.map((record) => record.record.requestId),
27472
+ timeout,
27473
+ {
27474
+ includeCurrentPageOnly: options.includeCurrentPageOnly
27475
+ }
27476
+ );
27477
+ return sortLiveNetworkRecords(delta, this.networkHistory)[0]?.recordId;
27107
27478
  }
27108
27479
  async executeTransportRequestWithJournal(request, timeout, sessionRef) {
27109
27480
  const baselineRequestIds = await this.readLiveRequestIds(timeout, {
@@ -27387,7 +27758,6 @@ var OpensteerSessionRuntime = class {
27387
27758
  const syntheticSessionRef = binding?.sessionRef ?? createSessionRef(`${transportLabel}-${this.workspace}`);
27388
27759
  const record = {
27389
27760
  recordId,
27390
- source: "saved",
27391
27761
  savedAt: now,
27392
27762
  record: {
27393
27763
  kind: "http",
@@ -27409,7 +27779,10 @@ var OpensteerSessionRuntime = class {
27409
27779
  ...response.body === void 0 ? {} : { responseBody: toProtocolBodyPayload(response.body) }
27410
27780
  }
27411
27781
  };
27412
- await root.registry.savedNetwork.save([record], tag);
27782
+ await root.registry.savedNetwork.save([record], {
27783
+ bodyWriteMode: "authoritative",
27784
+ ...tag === void 0 ? {} : { tag }
27785
+ });
27413
27786
  return recordId;
27414
27787
  }
27415
27788
  async executeResolvedRequestPlan(plan, input, timeout, binding) {
@@ -27782,7 +28155,6 @@ var OpensteerSessionRuntime = class {
27782
28155
  const record = await pollUntilResult(timeout, async () => {
27783
28156
  const matches = await this.queryLiveNetwork(
27784
28157
  {
27785
- source: "live",
27786
28158
  ...step.url === void 0 ? {} : { url: interpolateTemplate(step.url, variables) },
27787
28159
  ...step.hostname === void 0 ? {} : { hostname: interpolateTemplate(step.hostname, variables) },
27788
28160
  ...step.path === void 0 ? {} : { path: interpolateTemplate(step.path, variables) },
@@ -28240,37 +28612,7 @@ var OpensteerSessionRuntime = class {
28240
28612
  const pageUrl = step.pageUrl === void 0 ? void 0 : interpolateTemplate(step.pageUrl, variables);
28241
28613
  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;
28242
28614
  }
28243
- scheduleBackgroundNetworkSaveByRequestIds(requestIds, tag) {
28244
- const task = (async () => {
28245
- const root = await this.ensureRoot();
28246
- const requestIdSet = new Set(requestIds);
28247
- const records = await this.readLiveNetworkRecords(
28248
- {
28249
- includeBodies: true,
28250
- includeCurrentPageOnly: false,
28251
- ...this.pageRef === void 0 ? {} : { pageRef: this.pageRef },
28252
- requestIds,
28253
- redactSecretHeaders: false
28254
- },
28255
- new AbortController().signal
28256
- );
28257
- const filtered = records.filter((record) => requestIdSet.has(record.record.requestId));
28258
- if (filtered.length === 0) {
28259
- return;
28260
- }
28261
- await root.registry.savedNetwork.save(filtered, tag);
28262
- })();
28263
- this.backgroundNetworkPersistence.add(task);
28264
- task.finally(() => {
28265
- this.backgroundNetworkPersistence.delete(task);
28266
- });
28267
- void task.catch(() => void 0);
28268
- }
28269
- async flushBackgroundNetworkPersistence() {
28270
- if (this.backgroundNetworkPersistence.size === 0) {
28271
- return;
28272
- }
28273
- await Promise.all([...this.backgroundNetworkPersistence]);
28615
+ async flushPersistedNetworkHistory() {
28274
28616
  }
28275
28617
  toDomTargetRef(target) {
28276
28618
  if (target.kind === "description") {
@@ -28305,7 +28647,9 @@ var OpensteerSessionRuntime = class {
28305
28647
  ...workspace.registry,
28306
28648
  ...overrides.requestPlans === void 0 ? {} : { requestPlans: overrides.requestPlans },
28307
28649
  ...overrides.authRecipes === void 0 ? {} : { authRecipes: overrides.authRecipes },
28308
- ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes }
28650
+ ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes },
28651
+ ...overrides.reverseCases === void 0 ? {} : { reverseCases: overrides.reverseCases },
28652
+ ...overrides.reversePackages === void 0 ? {} : { reversePackages: overrides.reversePackages }
28309
28653
  }
28310
28654
  };
28311
28655
  } else {
@@ -28562,8 +28906,7 @@ var OpensteerSessionRuntime = class {
28562
28906
  }
28563
28907
  async resetRuntimeState(options) {
28564
28908
  const engine = this.engine;
28565
- this.networkJournal.clear();
28566
- this.backgroundNetworkPersistence.clear();
28909
+ this.networkHistory.clear();
28567
28910
  this.sessionRef = void 0;
28568
28911
  this.pageRef = void 0;
28569
28912
  this.runId = void 0;
@@ -28639,10 +28982,10 @@ function buildEngineNetworkRecordFilters(input) {
28639
28982
  ...input.resourceType === void 0 ? {} : { resourceType: input.resourceType }
28640
28983
  };
28641
28984
  }
28642
- function resolveLiveQueryRequestIds(input, journal) {
28985
+ function resolveLiveQueryRequestIds(input, history) {
28643
28986
  const requestIdCandidates = [];
28644
28987
  if (input.recordId !== void 0) {
28645
- const requestId = journal.getRequestId(input.recordId);
28988
+ const requestId = history.getRequestId(input.recordId);
28646
28989
  if (requestId === void 0) {
28647
28990
  return [];
28648
28991
  }
@@ -28651,25 +28994,25 @@ function resolveLiveQueryRequestIds(input, journal) {
28651
28994
  if (input.requestId !== void 0) {
28652
28995
  requestIdCandidates.push(/* @__PURE__ */ new Set([input.requestId]));
28653
28996
  }
28654
- if (input.actionId !== void 0) {
28655
- requestIdCandidates.push(journal.getRequestIdsForActionId(input.actionId));
28997
+ if (input.capture !== void 0) {
28998
+ requestIdCandidates.push(history.getRequestIdsForCapture(input.capture));
28656
28999
  }
28657
29000
  if (input.tag !== void 0) {
28658
- requestIdCandidates.push(journal.getRequestIdsForTag(input.tag));
29001
+ requestIdCandidates.push(history.getRequestIdsForTag(input.tag));
28659
29002
  }
28660
29003
  if (requestIdCandidates.length === 0) {
28661
29004
  return void 0;
28662
29005
  }
28663
29006
  return intersectRequestIdSets(requestIdCandidates);
28664
29007
  }
28665
- function resolveLiveQueryPageRef(input, currentPageRef, requestIds, journal) {
29008
+ function resolveLiveQueryPageRef(input, currentPageRef, requestIds, history) {
28666
29009
  const requestedPageRef = selectLiveQueryPageRef(input, currentPageRef);
28667
29010
  if (requestedPageRef !== void 0 || requestIds === void 0) {
28668
29011
  return requestedPageRef;
28669
29012
  }
28670
29013
  const pageRefs = /* @__PURE__ */ new Set();
28671
29014
  for (const requestId of requestIds) {
28672
- const pageRef = journal.getPageRefForRequestId(requestId);
29015
+ const pageRef = history.getPageRefForRequestId(requestId);
28673
29016
  if (pageRef === void 0) {
28674
29017
  continue;
28675
29018
  }
@@ -28699,7 +29042,7 @@ function filterNetworkQueryRecords(records, input) {
28699
29042
  if (input.requestId !== void 0 && record.record.requestId !== input.requestId) {
28700
29043
  return false;
28701
29044
  }
28702
- if (input.actionId !== void 0 && record.actionId !== input.actionId) {
29045
+ if (input.capture !== void 0 && record.capture !== input.capture) {
28703
29046
  return false;
28704
29047
  }
28705
29048
  if (input.tag !== void 0 && !(record.tags ?? []).includes(input.tag)) {
@@ -28711,10 +29054,10 @@ function filterNetworkQueryRecords(records, input) {
28711
29054
  return true;
28712
29055
  });
28713
29056
  }
28714
- function sortLiveNetworkRecords(records, journal) {
29057
+ function sortLiveNetworkRecords(records, history) {
28715
29058
  return [...records].sort((left, right) => {
28716
- const leftObservedAt = journal.getObservedAt(left.recordId) ?? 0;
28717
- const rightObservedAt = journal.getObservedAt(right.recordId) ?? 0;
29059
+ const leftObservedAt = history.getObservedAt(left.recordId) ?? 0;
29060
+ const rightObservedAt = history.getObservedAt(right.recordId) ?? 0;
28718
29061
  if (leftObservedAt !== rightObservedAt) {
28719
29062
  return rightObservedAt - leftObservedAt;
28720
29063
  }
@@ -28921,7 +29264,7 @@ function buildMinimizedRequestPlan(input) {
28921
29264
  provenance: {
28922
29265
  source: "network-minimize",
28923
29266
  sourceId: input.record.recordId,
28924
- ...input.record.source === "saved" && input.record.savedAt !== void 0 ? { capturedAt: input.record.savedAt } : {}
29267
+ ...input.record.savedAt === void 0 ? {} : { capturedAt: input.record.savedAt }
28925
29268
  },
28926
29269
  payload: normalizeRequestPlanPayload({
28927
29270
  transport: {
@@ -29140,12 +29483,12 @@ function originFromUrl(url) {
29140
29483
  return void 0;
29141
29484
  }
29142
29485
  }
29143
- function filterReverseObservationWindow(records, journal, captureWindowMs) {
29486
+ function filterReverseObservationWindow(records, history, captureWindowMs) {
29144
29487
  if (captureWindowMs === void 0) {
29145
29488
  return records;
29146
29489
  }
29147
29490
  const observedAfter = Date.now() - captureWindowMs;
29148
- return records.filter((record) => (journal.getObservedAt(record.recordId) ?? 0) >= observedAfter);
29491
+ return records.filter((record) => (history.getObservedAt(record.recordId) ?? 0) >= observedAfter);
29149
29492
  }
29150
29493
  function isReverseRelevantNetworkRecord(record) {
29151
29494
  return record.record.resourceType === "document" || record.record.resourceType === "fetch" || record.record.resourceType === "xhr" || record.record.resourceType === "websocket" || record.record.resourceType === "event-stream";
@@ -31109,9 +31452,40 @@ function toOpensteerResolvedTarget2(target) {
31109
31452
  function normalizeOpensteerError(error) {
31110
31453
  return normalizeThrownOpensteerError(error, "Unknown Opensteer runtime failure");
31111
31454
  }
31455
+ function buildMutationCaptureTraceData(diagnostics) {
31456
+ if (diagnostics?.finalizeError === void 0) {
31457
+ return {};
31458
+ }
31459
+ return {
31460
+ networkCapture: {
31461
+ finalizeError: diagnostics.finalizeError
31462
+ }
31463
+ };
31464
+ }
31112
31465
  function isIgnorableRuntimeBindingError(error) {
31113
31466
  return isBrowserCoreError(error) && (error.code === "not-found" || error.code === "page-closed" || error.code === "session-closed");
31114
31467
  }
31468
+ async function withDetachedTimeoutSignal(timeoutMs, operation) {
31469
+ const controller = new AbortController();
31470
+ const timeoutError = new OpensteerProtocolError(
31471
+ "timeout",
31472
+ `mutation capture finalization exceeded ${String(timeoutMs)}ms timeout`,
31473
+ {
31474
+ details: {
31475
+ policy: "mutation-capture-finalize",
31476
+ budgetMs: timeoutMs
31477
+ }
31478
+ }
31479
+ );
31480
+ const timer = setTimeout(() => {
31481
+ controller.abort(timeoutError);
31482
+ }, timeoutMs);
31483
+ try {
31484
+ return await operation(controller.signal);
31485
+ } finally {
31486
+ clearTimeout(timer);
31487
+ }
31488
+ }
31115
31489
  function screenshotMediaType(format2) {
31116
31490
  switch (format2) {
31117
31491
  case "png":
@@ -31152,6 +31526,7 @@ var OpensteerRuntime = class extends OpensteerSessionRuntime {
31152
31526
  ...options.policy === void 0 ? {} : { policy: options.policy },
31153
31527
  ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31154
31528
  ...options.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: options.extractionDescriptorStore },
31529
+ ...options.registryOverrides === void 0 ? {} : { registryOverrides: options.registryOverrides },
31155
31530
  cleanupRootOnClose
31156
31531
  })
31157
31532
  );
@@ -31180,6 +31555,7 @@ var OpensteerSessionRuntime2 = class extends OpensteerSessionRuntime {
31180
31555
  ...options.policy === void 0 ? {} : { policy: options.policy },
31181
31556
  ...options.descriptorStore === void 0 ? {} : { descriptorStore: options.descriptorStore },
31182
31557
  ...options.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: options.extractionDescriptorStore },
31558
+ ...options.registryOverrides === void 0 ? {} : { registryOverrides: options.registryOverrides },
31183
31559
  cleanupRootOnClose
31184
31560
  })
31185
31561
  );
@@ -31204,6 +31580,7 @@ function buildSharedRuntimeOptions(input) {
31204
31580
  ...input.policy === void 0 ? {} : { policy: input.policy },
31205
31581
  ...input.descriptorStore === void 0 ? {} : { descriptorStore: input.descriptorStore },
31206
31582
  ...input.extractionDescriptorStore === void 0 ? {} : { extractionDescriptorStore: input.extractionDescriptorStore },
31583
+ ...input.registryOverrides === void 0 ? {} : { registryOverrides: input.registryOverrides },
31207
31584
  cleanupRootOnClose: input.cleanupRootOnClose,
31208
31585
  sessionInfo: {
31209
31586
  provider: {
@@ -31944,6 +32321,20 @@ var OpensteerCloudClient = class {
31944
32321
  });
31945
32322
  return await response.json();
31946
32323
  }
32324
+ async importReverseCases(entries) {
32325
+ const response = await this.request("/registry/reverse-cases/import", {
32326
+ method: "POST",
32327
+ body: { entries }
32328
+ });
32329
+ return await response.json();
32330
+ }
32331
+ async importReversePackages(entries) {
32332
+ const response = await this.request("/registry/reverse-packages/import", {
32333
+ method: "POST",
32334
+ body: { entries }
32335
+ });
32336
+ return await response.json();
32337
+ }
31947
32338
  buildAuthorizationHeader() {
31948
32339
  return `Bearer ${this.config.apiKey}`;
31949
32340
  }
@@ -32459,11 +32850,13 @@ function asRecord(value) {
32459
32850
  var REGISTRY_SYNC_MAX_PAYLOAD_BYTES = 15e5;
32460
32851
  var REGISTRY_SYNC_MAX_ENTRIES_PER_BATCH = 100;
32461
32852
  async function syncLocalRegistryToCloud(client, workspace, store) {
32462
- const [descriptors, requestPlans, recipes, authRecipes] = await Promise.all([
32853
+ const [descriptors, requestPlans, recipes, authRecipes, reverseCases, reversePackages] = await Promise.all([
32463
32854
  store.registry.descriptors.list(),
32464
32855
  store.registry.requestPlans.list(),
32465
32856
  store.registry.recipes.list(),
32466
- store.registry.authRecipes.list()
32857
+ store.registry.authRecipes.list(),
32858
+ store.registry.reverseCases.list(),
32859
+ store.registry.reversePackages.list()
32467
32860
  ]);
32468
32861
  const descriptorEntries = descriptors.map((record) => toDescriptorImportEntry(workspace, record));
32469
32862
  await Promise.all([
@@ -32479,6 +32872,14 @@ async function syncLocalRegistryToCloud(client, workspace, store) {
32479
32872
  importInBatches(
32480
32873
  authRecipes.map((record) => toRegistryImportEntry(workspace, record)),
32481
32874
  (entries) => client.importAuthRecipes(entries)
32875
+ ),
32876
+ importInBatches(
32877
+ reverseCases.map((record) => toRegistryImportEntry(workspace, record)),
32878
+ (entries) => client.importReverseCases(entries)
32879
+ ),
32880
+ importInBatches(
32881
+ reversePackages.map((record) => toRegistryImportEntry(workspace, record)),
32882
+ (entries) => client.importReversePackages(entries)
32482
32883
  )
32483
32884
  ]);
32484
32885
  }
@@ -32688,9 +33089,9 @@ var CloudSessionProxy = class {
32688
33089
  await this.ensureSession();
32689
33090
  return this.requireClient().invoke("network.query", input);
32690
33091
  }
32691
- async saveNetwork(input) {
33092
+ async tagNetwork(input) {
32692
33093
  await this.ensureSession();
32693
- return this.requireClient().invoke("network.save", input);
33094
+ return this.requireClient().invoke("network.tag", input);
32694
33095
  }
32695
33096
  async minimizeNetwork(input) {
32696
33097
  await this.ensureSession();
@@ -33055,5 +33456,5 @@ function createOpensteerSemanticRuntime(input = {}) {
33055
33456
  }
33056
33457
 
33057
33458
  export { CloudSessionProxy, DEFAULT_OPENSTEER_ENGINE, DEFERRED_MATCH_ATTR_KEYS, ElementPathError, 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, createDomRuntime, createFilesystemOpensteerWorkspace, createOpensteerExtractionDescriptorStore, createOpensteerSemanticRuntime, defaultFallbackPolicy, defaultPolicy, defaultRetryPolicy, defaultSettlePolicy, defaultTimeoutPolicy, delayWithSignal, discoverLocalCdpBrowsers, dispatchSemanticOperation, hashDomDescriptorDescription, inspectCdpEndpoint, isCurrentUrlField, isProcessRunning, isValidCssAttributeKey, listLocalChromeProfiles, normalizeExtractedValue, normalizeOpensteerEngineName, normalizeOpensteerProviderMode, normalizeWorkspaceId, parseDomDescriptorRecord, parseExtractionDescriptorRecord, pathExists, readPersistedCloudSessionRecord, readPersistedLocalBrowserSessionRecord, readPersistedSessionRecord, resolveCloudConfig, resolveCloudSessionRecordPath, resolveDomActionBridge, resolveExtractedValueInContext, resolveFilesystemWorkspacePath, resolveLiveSessionRecordPath, resolveLocalSessionRecordPath, resolveOpensteerEngineName, resolveOpensteerProvider, resolveOpensteerRuntimeConfig, runWithPolicyTimeout, sanitizeElementPath, sanitizeReplayElementPath, sanitizeStructuralElementAnchor, settleWithPolicy, shouldKeepAttributeForPath, writePersistedSessionRecord };
33058
- //# sourceMappingURL=chunk-KYRC6CLB.js.map
33059
- //# sourceMappingURL=chunk-KYRC6CLB.js.map
33459
+ //# sourceMappingURL=chunk-3QJGBVWT.js.map
33460
+ //# sourceMappingURL=chunk-3QJGBVWT.js.map