@opensteer/runtime-core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import path6 from 'path';
2
- import { randomUUID, createHash } from 'crypto';
2
+ import { createHash, randomUUID } from 'crypto';
3
3
  import { rm, mkdir, access, readFile, mkdtemp, writeFile, rename, open, readdir } from 'fs/promises';
4
4
  import { createRequire } from 'module';
5
5
  import { pathToFileURL } from 'url';
@@ -13,7 +13,7 @@ import vm from 'vm';
13
13
 
14
14
  // package.json
15
15
  var package_default = {
16
- version: "0.1.0"};
16
+ version: "0.1.1"};
17
17
 
18
18
  // src/version.ts
19
19
  var OPENSTEER_RUNTIME_CORE_VERSION = package_default.version;
@@ -1296,12 +1296,6 @@ var opensteerRegistryProvenanceSchema = objectSchema(
1296
1296
  required: ["source"]
1297
1297
  }
1298
1298
  );
1299
- var opensteerRequestPlanLifecycleSchema = enumSchema(
1300
- ["draft", "active", "deprecated", "retired"],
1301
- {
1302
- title: "OpensteerRequestPlanLifecycle"
1303
- }
1304
- );
1305
1299
  var opensteerRequestPlanFreshnessSchema = objectSchema(
1306
1300
  {
1307
1301
  lastValidatedAt: integerSchema({ minimum: 0 }),
@@ -1324,23 +1318,12 @@ var opensteerRequestPlanRecordSchema = objectSchema(
1324
1318
  uniqueItems: true
1325
1319
  }),
1326
1320
  provenance: opensteerRegistryProvenanceSchema,
1327
- lifecycle: opensteerRequestPlanLifecycleSchema,
1328
1321
  freshness: opensteerRequestPlanFreshnessSchema,
1329
1322
  payload: opensteerRequestPlanPayloadSchema
1330
1323
  },
1331
1324
  {
1332
1325
  title: "OpensteerRequestPlanRecord",
1333
- required: [
1334
- "id",
1335
- "key",
1336
- "version",
1337
- "createdAt",
1338
- "updatedAt",
1339
- "contentHash",
1340
- "tags",
1341
- "lifecycle",
1342
- "payload"
1343
- ]
1326
+ required: ["id", "key", "version", "createdAt", "updatedAt", "contentHash", "tags", "payload"]
1344
1327
  }
1345
1328
  );
1346
1329
  var jsonValueSchema = defineSchema({
@@ -1783,7 +1766,6 @@ var opensteerWriteRequestPlanInputSchema = objectSchema(
1783
1766
  uniqueItems: true
1784
1767
  }),
1785
1768
  provenance: opensteerRegistryProvenanceSchema,
1786
- lifecycle: opensteerRequestPlanLifecycleSchema,
1787
1769
  freshness: opensteerRequestPlanFreshnessSchema,
1788
1770
  payload: opensteerRequestPlanPayloadSchema
1789
1771
  },
@@ -2024,7 +2006,7 @@ var opensteerInferRequestPlanInputSchema = objectSchema(
2024
2006
  recordId: stringSchema({ minLength: 1 }),
2025
2007
  key: stringSchema({ minLength: 1 }),
2026
2008
  version: stringSchema({ minLength: 1 }),
2027
- lifecycle: opensteerRequestPlanLifecycleSchema
2009
+ transport: transportKindSchema
2028
2010
  },
2029
2011
  {
2030
2012
  title: "OpensteerInferRequestPlanInput",
@@ -7089,8 +7071,74 @@ var defaultSnapshotSettleObserver = {
7089
7071
  }
7090
7072
  };
7091
7073
  Object.freeze(defaultSnapshotSettleObserver);
7074
+ var DOM_ACTION_VISUAL_STABILITY_PROFILES = {
7075
+ "dom.click": { settleMs: 750, scope: "visible-frames", timeoutMs: 7e3 },
7076
+ "dom.input": { settleMs: 750, scope: "visible-frames", timeoutMs: 7e3 },
7077
+ "dom.scroll": { settleMs: 600, scope: "visible-frames", timeoutMs: 7e3 },
7078
+ "dom.hover": { settleMs: 200, scope: "main-frame", timeoutMs: 2500 }
7079
+ };
7080
+ var DEFAULT_DOM_ACTION_VISUAL_STABILITY_PROFILE = {
7081
+ settleMs: 750,
7082
+ scope: "visible-frames",
7083
+ timeoutMs: 7e3
7084
+ };
7085
+ var NAVIGATION_VISUAL_STABILITY_PROFILE = {
7086
+ settleMs: 750,
7087
+ scope: "visible-frames",
7088
+ timeoutMs: 7e3
7089
+ };
7090
+ var defaultDomActionSettleObserver = {
7091
+ async settle(input) {
7092
+ if (input.trigger !== "dom-action") {
7093
+ return false;
7094
+ }
7095
+ const profile = DOM_ACTION_VISUAL_STABILITY_PROFILES[input.operation] ?? DEFAULT_DOM_ACTION_VISUAL_STABILITY_PROFILE;
7096
+ const effectiveTimeout = input.remainingMs === void 0 ? profile.timeoutMs : Math.min(profile.timeoutMs, input.remainingMs);
7097
+ if (effectiveTimeout <= 0) {
7098
+ return false;
7099
+ }
7100
+ try {
7101
+ await input.engine.waitForVisualStability({
7102
+ pageRef: input.pageRef,
7103
+ timeoutMs: effectiveTimeout,
7104
+ settleMs: profile.settleMs,
7105
+ scope: profile.scope
7106
+ });
7107
+ return true;
7108
+ } catch {
7109
+ return false;
7110
+ }
7111
+ }
7112
+ };
7113
+ Object.freeze(defaultDomActionSettleObserver);
7114
+ var defaultNavigationSettleObserver = {
7115
+ async settle(input) {
7116
+ if (input.trigger !== "navigation") {
7117
+ return false;
7118
+ }
7119
+ const profile = NAVIGATION_VISUAL_STABILITY_PROFILE;
7120
+ const effectiveTimeout = input.remainingMs === void 0 ? profile.timeoutMs : Math.min(profile.timeoutMs, input.remainingMs);
7121
+ if (effectiveTimeout <= 0) {
7122
+ return false;
7123
+ }
7124
+ try {
7125
+ await input.engine.waitForVisualStability({
7126
+ pageRef: input.pageRef,
7127
+ timeoutMs: effectiveTimeout,
7128
+ settleMs: profile.settleMs,
7129
+ scope: profile.scope
7130
+ });
7131
+ return true;
7132
+ } catch {
7133
+ return false;
7134
+ }
7135
+ }
7136
+ };
7137
+ Object.freeze(defaultNavigationSettleObserver);
7092
7138
  var DEFAULT_SETTLE_OBSERVERS = Object.freeze([
7093
- defaultSnapshotSettleObserver
7139
+ defaultSnapshotSettleObserver,
7140
+ defaultDomActionSettleObserver,
7141
+ defaultNavigationSettleObserver
7094
7142
  ]);
7095
7143
  var defaultTimeoutPolicy = {
7096
7144
  resolveTimeoutMs(input) {
@@ -7341,9 +7389,7 @@ var FilesystemRegistryStore = class {
7341
7389
  if (input.version !== void 0) {
7342
7390
  return this.resolveIndexedRecord(key, normalizeNonEmptyString("version", input.version));
7343
7391
  }
7344
- const matches = (await this.readAllRecords()).filter(
7345
- (record) => this.isActive(record) && record.key === key
7346
- );
7392
+ const matches = (await this.readAllRecords()).filter((record) => record.key === key);
7347
7393
  matches.sort(compareByCreatedAtAndId);
7348
7394
  return matches[0];
7349
7395
  }
@@ -7466,8 +7512,10 @@ var FilesystemDescriptorRegistry = class extends FilesystemRegistryStore {
7466
7512
  };
7467
7513
  return this.writeRecord(record);
7468
7514
  }
7469
- isActive(_record) {
7470
- return true;
7515
+ async list(input = {}) {
7516
+ const key = input.key === void 0 ? void 0 : normalizeNonEmptyString("key", input.key);
7517
+ const records = await this.readAllRecords();
7518
+ return key === void 0 ? records : records.filter((record) => record.key === key);
7471
7519
  }
7472
7520
  };
7473
7521
  var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
@@ -7497,7 +7545,6 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7497
7545
  tags: normalizeTags(input.tags),
7498
7546
  ...provenance === void 0 ? {} : { provenance },
7499
7547
  payload,
7500
- lifecycle: input.lifecycle ?? "active",
7501
7548
  ...freshness === void 0 ? {} : { freshness }
7502
7549
  };
7503
7550
  return this.writeRecord(record);
@@ -7507,7 +7554,7 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7507
7554
  const records = await this.readAllRecords();
7508
7555
  return key === void 0 ? records : records.filter((record) => record.key === key);
7509
7556
  }
7510
- async updateMetadata(input) {
7557
+ async updateFreshness(input) {
7511
7558
  const id = normalizeNonEmptyString("id", input.id);
7512
7559
  return withFilesystemLock(this.writeLockPath(), async () => {
7513
7560
  const existing = await this.getById(id);
@@ -7525,16 +7572,12 @@ var FilesystemRequestPlanRegistry = class extends FilesystemRegistryStore {
7525
7572
  const nextRecord = {
7526
7573
  ...existing,
7527
7574
  updatedAt: nextUpdatedAt,
7528
- lifecycle: input.lifecycle ?? existing.lifecycle,
7529
7575
  ...nextFreshness === void 0 ? {} : { freshness: nextFreshness }
7530
7576
  };
7531
7577
  await writeJsonFileAtomic(this.recordPath(id), nextRecord);
7532
7578
  return nextRecord;
7533
7579
  });
7534
7580
  }
7535
- isActive(record) {
7536
- return record.lifecycle === "active";
7537
- }
7538
7581
  };
7539
7582
  var FilesystemAuthRecipeRegistry = class extends FilesystemRegistryStore {
7540
7583
  constructor(rootPath) {
@@ -7570,9 +7613,6 @@ var FilesystemAuthRecipeRegistry = class extends FilesystemRegistryStore {
7570
7613
  const records = await this.readAllRecords();
7571
7614
  return key === void 0 ? records : records.filter((record) => record.key === key);
7572
7615
  }
7573
- isActive(_record) {
7574
- return true;
7575
- }
7576
7616
  };
7577
7617
  var FilesystemRecipeRegistry = class extends FilesystemRegistryStore {
7578
7618
  constructor(rootPath) {
@@ -7608,9 +7648,6 @@ var FilesystemRecipeRegistry = class extends FilesystemRegistryStore {
7608
7648
  const records = await this.readAllRecords();
7609
7649
  return key === void 0 ? records : records.filter((record) => record.key === key);
7610
7650
  }
7611
- isActive(_record) {
7612
- return true;
7613
- }
7614
7651
  };
7615
7652
  var FilesystemInteractionTraceRegistry = class extends FilesystemRegistryStore {
7616
7653
  constructor(rootPath) {
@@ -7646,9 +7683,6 @@ var FilesystemInteractionTraceRegistry = class extends FilesystemRegistryStore {
7646
7683
  const records = await this.readAllRecords();
7647
7684
  return key === void 0 ? records : records.filter((record) => record.key === key);
7648
7685
  }
7649
- isActive(_record) {
7650
- return true;
7651
- }
7652
7686
  };
7653
7687
  var FilesystemReverseCaseRegistry = class extends FilesystemRegistryStore {
7654
7688
  constructor(rootPath) {
@@ -7712,9 +7746,6 @@ var FilesystemReverseCaseRegistry = class extends FilesystemRegistryStore {
7712
7746
  return nextRecord;
7713
7747
  });
7714
7748
  }
7715
- isActive(_record) {
7716
- return true;
7717
- }
7718
7749
  };
7719
7750
  var FilesystemReversePackageRegistry = class extends FilesystemRegistryStore {
7720
7751
  constructor(rootPath) {
@@ -7750,9 +7781,6 @@ var FilesystemReversePackageRegistry = class extends FilesystemRegistryStore {
7750
7781
  const records = await this.readAllRecords();
7751
7782
  return key === void 0 ? records : records.filter((record) => record.key === key);
7752
7783
  }
7753
- isActive(_record) {
7754
- return true;
7755
- }
7756
7784
  };
7757
7785
  var FilesystemReverseReportRegistry = class extends FilesystemRegistryStore {
7758
7786
  constructor(rootPath) {
@@ -7788,9 +7816,6 @@ var FilesystemReverseReportRegistry = class extends FilesystemRegistryStore {
7788
7816
  const records = await this.readAllRecords();
7789
7817
  return key === void 0 ? records : records.filter((record) => record.key === key);
7790
7818
  }
7791
- isActive(_record) {
7792
- return true;
7793
- }
7794
7819
  };
7795
7820
  function createDescriptorRegistry(rootPath) {
7796
7821
  return new FilesystemDescriptorRegistry(rootPath);
@@ -7818,101 +7843,20 @@ function createReverseReportRegistry(rootPath) {
7818
7843
  }
7819
7844
  var TAG_DELIMITER = "";
7820
7845
  var NODE_SQLITE_SPECIFIER = `node:${"sqlite"}`;
7846
+ var SAVED_NETWORK_SQLITE_SUPPORT_ERROR = "Saved-network operations require Node's built-in SQLite support. Use a Node runtime with node:sqlite enabled.";
7821
7847
  var SqliteSavedNetworkStore = class {
7822
7848
  databasePath;
7823
7849
  database;
7850
+ directoryInitialization;
7851
+ databaseInitialization;
7824
7852
  constructor(rootPath) {
7825
7853
  this.databasePath = path6.join(rootPath, "registry", "saved-network.sqlite");
7826
7854
  }
7827
7855
  async initialize() {
7828
- await ensureDirectory(path6.dirname(this.databasePath));
7829
- const { DatabaseSync } = await import(NODE_SQLITE_SPECIFIER);
7830
- const database = new DatabaseSync(this.databasePath);
7831
- database.exec("PRAGMA journal_mode = WAL");
7832
- database.exec("PRAGMA foreign_keys = ON");
7833
- database.exec(`
7834
- CREATE TABLE IF NOT EXISTS saved_network_records (
7835
- record_id TEXT PRIMARY KEY,
7836
- request_id TEXT NOT NULL,
7837
- session_ref TEXT NOT NULL,
7838
- page_ref TEXT,
7839
- page_ref_key TEXT NOT NULL,
7840
- frame_ref TEXT,
7841
- document_ref TEXT,
7842
- action_id TEXT,
7843
- method TEXT NOT NULL,
7844
- method_lc TEXT NOT NULL,
7845
- url TEXT NOT NULL,
7846
- url_lc TEXT NOT NULL,
7847
- hostname TEXT NOT NULL,
7848
- hostname_lc TEXT NOT NULL,
7849
- path TEXT NOT NULL,
7850
- path_lc TEXT NOT NULL,
7851
- status INTEGER,
7852
- status_text TEXT,
7853
- resource_type TEXT NOT NULL,
7854
- navigation_request INTEGER NOT NULL,
7855
- request_headers_json TEXT NOT NULL,
7856
- response_headers_json TEXT NOT NULL,
7857
- request_body_json TEXT,
7858
- response_body_json TEXT,
7859
- initiator_json TEXT,
7860
- timing_json TEXT,
7861
- transfer_json TEXT,
7862
- source_json TEXT,
7863
- capture_state TEXT NOT NULL,
7864
- request_body_state TEXT NOT NULL,
7865
- response_body_state TEXT NOT NULL,
7866
- request_body_skip_reason TEXT,
7867
- response_body_skip_reason TEXT,
7868
- request_body_error TEXT,
7869
- response_body_error TEXT,
7870
- redirect_from_request_id TEXT,
7871
- redirect_to_request_id TEXT,
7872
- saved_at INTEGER NOT NULL
7873
- );
7874
-
7875
- CREATE UNIQUE INDEX IF NOT EXISTS saved_network_records_scope_request
7876
- ON saved_network_records (session_ref, page_ref_key, request_id);
7877
-
7878
- CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
7879
- ON saved_network_records (saved_at DESC);
7880
-
7881
- CREATE TABLE IF NOT EXISTS saved_network_tags (
7882
- record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
7883
- tag TEXT NOT NULL,
7884
- PRIMARY KEY (record_id, tag)
7885
- );
7886
-
7887
- CREATE INDEX IF NOT EXISTS saved_network_tags_tag
7888
- ON saved_network_tags (tag);
7889
- `);
7890
- this.ensureColumn(
7891
- database,
7892
- "saved_network_records",
7893
- "capture_state",
7894
- "TEXT NOT NULL DEFAULT 'complete'"
7895
- );
7896
- this.ensureColumn(
7897
- database,
7898
- "saved_network_records",
7899
- "request_body_state",
7900
- "TEXT NOT NULL DEFAULT 'skipped'"
7901
- );
7902
- this.ensureColumn(
7903
- database,
7904
- "saved_network_records",
7905
- "response_body_state",
7906
- "TEXT NOT NULL DEFAULT 'skipped'"
7907
- );
7908
- this.ensureColumn(database, "saved_network_records", "request_body_skip_reason", "TEXT");
7909
- this.ensureColumn(database, "saved_network_records", "response_body_skip_reason", "TEXT");
7910
- this.ensureColumn(database, "saved_network_records", "request_body_error", "TEXT");
7911
- this.ensureColumn(database, "saved_network_records", "response_body_error", "TEXT");
7912
- this.database = database;
7856
+ await this.ensureDatabaseDirectory();
7913
7857
  }
7914
7858
  async save(records, tag) {
7915
- const database = this.requireDatabase();
7859
+ const database = await this.requireDatabase();
7916
7860
  const readExisting = database.prepare(`
7917
7861
  SELECT record_id
7918
7862
  FROM saved_network_records
@@ -8104,7 +8048,7 @@ var SqliteSavedNetworkStore = class {
8104
8048
  });
8105
8049
  }
8106
8050
  async query(input = {}) {
8107
- const database = this.requireDatabase();
8051
+ const database = await this.requireDatabase();
8108
8052
  const limit = Math.max(1, Math.min(input.limit ?? 50, 200));
8109
8053
  const { whereSql, parameters } = buildSavedNetworkWhere(input);
8110
8054
  const rows = database.prepare(
@@ -8135,7 +8079,7 @@ var SqliteSavedNetworkStore = class {
8135
8079
  return record;
8136
8080
  }
8137
8081
  async clear(input = {}) {
8138
- const database = this.requireDatabase();
8082
+ const database = await this.requireDatabase();
8139
8083
  const countAll = database.prepare(`
8140
8084
  SELECT COUNT(*) AS cleared
8141
8085
  FROM saved_network_records
@@ -8172,11 +8116,127 @@ var SqliteSavedNetworkStore = class {
8172
8116
  return cleared;
8173
8117
  });
8174
8118
  }
8175
- requireDatabase() {
8176
- if (!this.database) {
8177
- throw new Error("saved network store is not initialized");
8119
+ async requireDatabase() {
8120
+ if (this.database) {
8121
+ return this.database;
8122
+ }
8123
+ this.databaseInitialization ??= this.openDatabase();
8124
+ try {
8125
+ return await this.databaseInitialization;
8126
+ } catch (error) {
8127
+ this.databaseInitialization = void 0;
8128
+ throw error;
8129
+ }
8130
+ }
8131
+ async openDatabase() {
8132
+ await this.ensureDatabaseDirectory();
8133
+ let DatabaseSync;
8134
+ try {
8135
+ ({ DatabaseSync } = await import(NODE_SQLITE_SPECIFIER));
8136
+ } catch (error) {
8137
+ throw normalizeSqliteImportError(error);
8178
8138
  }
8179
- return this.database;
8139
+ const database = new DatabaseSync(this.databasePath);
8140
+ try {
8141
+ this.configureDatabase(database);
8142
+ this.database = database;
8143
+ return database;
8144
+ } catch (error) {
8145
+ closeSqliteDatabase(database);
8146
+ throw error;
8147
+ }
8148
+ }
8149
+ async ensureDatabaseDirectory() {
8150
+ this.directoryInitialization ??= ensureDirectory(path6.dirname(this.databasePath)).catch(
8151
+ (error) => {
8152
+ this.directoryInitialization = void 0;
8153
+ throw error;
8154
+ }
8155
+ );
8156
+ await this.directoryInitialization;
8157
+ }
8158
+ configureDatabase(database) {
8159
+ database.exec("PRAGMA journal_mode = WAL");
8160
+ database.exec("PRAGMA foreign_keys = ON");
8161
+ database.exec(`
8162
+ CREATE TABLE IF NOT EXISTS saved_network_records (
8163
+ record_id TEXT PRIMARY KEY,
8164
+ request_id TEXT NOT NULL,
8165
+ session_ref TEXT NOT NULL,
8166
+ page_ref TEXT,
8167
+ page_ref_key TEXT NOT NULL,
8168
+ frame_ref TEXT,
8169
+ document_ref TEXT,
8170
+ action_id TEXT,
8171
+ method TEXT NOT NULL,
8172
+ method_lc TEXT NOT NULL,
8173
+ url TEXT NOT NULL,
8174
+ url_lc TEXT NOT NULL,
8175
+ hostname TEXT NOT NULL,
8176
+ hostname_lc TEXT NOT NULL,
8177
+ path TEXT NOT NULL,
8178
+ path_lc TEXT NOT NULL,
8179
+ status INTEGER,
8180
+ status_text TEXT,
8181
+ resource_type TEXT NOT NULL,
8182
+ navigation_request INTEGER NOT NULL,
8183
+ request_headers_json TEXT NOT NULL,
8184
+ response_headers_json TEXT NOT NULL,
8185
+ request_body_json TEXT,
8186
+ response_body_json TEXT,
8187
+ initiator_json TEXT,
8188
+ timing_json TEXT,
8189
+ transfer_json TEXT,
8190
+ source_json TEXT,
8191
+ capture_state TEXT NOT NULL,
8192
+ request_body_state TEXT NOT NULL,
8193
+ response_body_state TEXT NOT NULL,
8194
+ request_body_skip_reason TEXT,
8195
+ response_body_skip_reason TEXT,
8196
+ request_body_error TEXT,
8197
+ response_body_error TEXT,
8198
+ redirect_from_request_id TEXT,
8199
+ redirect_to_request_id TEXT,
8200
+ saved_at INTEGER NOT NULL
8201
+ );
8202
+
8203
+ CREATE UNIQUE INDEX IF NOT EXISTS saved_network_records_scope_request
8204
+ ON saved_network_records (session_ref, page_ref_key, request_id);
8205
+
8206
+ CREATE INDEX IF NOT EXISTS saved_network_records_saved_at
8207
+ ON saved_network_records (saved_at DESC);
8208
+
8209
+ CREATE TABLE IF NOT EXISTS saved_network_tags (
8210
+ record_id TEXT NOT NULL REFERENCES saved_network_records(record_id) ON DELETE CASCADE,
8211
+ tag TEXT NOT NULL,
8212
+ PRIMARY KEY (record_id, tag)
8213
+ );
8214
+
8215
+ CREATE INDEX IF NOT EXISTS saved_network_tags_tag
8216
+ ON saved_network_tags (tag);
8217
+ `);
8218
+ this.ensureColumn(
8219
+ database,
8220
+ "saved_network_records",
8221
+ "capture_state",
8222
+ "TEXT NOT NULL DEFAULT 'complete'"
8223
+ );
8224
+ this.ensureColumn(
8225
+ database,
8226
+ "saved_network_records",
8227
+ "request_body_state",
8228
+ "TEXT NOT NULL DEFAULT 'skipped'"
8229
+ );
8230
+ this.ensureColumn(
8231
+ database,
8232
+ "saved_network_records",
8233
+ "response_body_state",
8234
+ "TEXT NOT NULL DEFAULT 'skipped'"
8235
+ );
8236
+ this.ensureColumn(database, "saved_network_records", "request_body_skip_reason", "TEXT");
8237
+ this.ensureColumn(database, "saved_network_records", "response_body_skip_reason", "TEXT");
8238
+ this.ensureColumn(database, "saved_network_records", "request_body_error", "TEXT");
8239
+ this.ensureColumn(database, "saved_network_records", "response_body_error", "TEXT");
8180
8240
  }
8181
8241
  ensureColumn(database, table, column, definition) {
8182
8242
  const rows = database.prepare(`PRAGMA table_info(${table})`).all();
@@ -8321,6 +8381,20 @@ function inflateSavedNetworkRow(row, includeBodies) {
8321
8381
  function stringifyOptional(value) {
8322
8382
  return value === void 0 ? null : JSON.stringify(value);
8323
8383
  }
8384
+ function normalizeSqliteImportError(error) {
8385
+ if (error instanceof Error && error.code === "ERR_UNKNOWN_BUILTIN_MODULE" && error.message.includes(NODE_SQLITE_SPECIFIER)) {
8386
+ return new Error(SAVED_NETWORK_SQLITE_SUPPORT_ERROR, {
8387
+ cause: error
8388
+ });
8389
+ }
8390
+ return error instanceof Error ? error : new Error(String(error));
8391
+ }
8392
+ function closeSqliteDatabase(database) {
8393
+ try {
8394
+ database.close();
8395
+ } catch {
8396
+ }
8397
+ }
8324
8398
  function withSqliteTransaction(database, task) {
8325
8399
  database.exec("BEGIN IMMEDIATE");
8326
8400
  try {
@@ -8530,8 +8604,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8530
8604
  const browserManifestPath = path6.join(browserPath, "manifest.json");
8531
8605
  const browserUserDataDir = path6.join(browserPath, "user-data");
8532
8606
  const livePath = path6.join(options.rootPath, "live");
8533
- const liveSessionPath = path6.join(livePath, "session.json");
8534
- const liveBrowserPath = path6.join(livePath, "browser.json");
8607
+ const liveLocalPath = path6.join(livePath, "local.json");
8608
+ const liveCloudPath = path6.join(livePath, "cloud.json");
8535
8609
  const artifactsPath = path6.join(options.rootPath, "artifacts");
8536
8610
  const tracesPath = path6.join(options.rootPath, "traces");
8537
8611
  const registryPath = path6.join(options.rootPath, "registry");
@@ -8606,8 +8680,8 @@ async function createFilesystemOpensteerWorkspace(options) {
8606
8680
  browserManifestPath,
8607
8681
  browserUserDataDir,
8608
8682
  livePath,
8609
- liveSessionPath,
8610
- liveBrowserPath,
8683
+ liveLocalPath,
8684
+ liveCloudPath,
8611
8685
  artifactsPath,
8612
8686
  tracesPath,
8613
8687
  registryPath,
@@ -8631,6 +8705,16 @@ async function createFilesystemOpensteerWorkspace(options) {
8631
8705
  };
8632
8706
  }
8633
8707
 
8708
+ // src/runtimes/dom/errors.ts
8709
+ var ElementPathError = class extends Error {
8710
+ code;
8711
+ constructor(code, message) {
8712
+ super(message);
8713
+ this.name = "ElementPathError";
8714
+ this.code = code;
8715
+ }
8716
+ };
8717
+
8634
8718
  // src/runtimes/dom/match-policy.ts
8635
8719
  var ATTRIBUTE_DENY_KEYS = /* @__PURE__ */ new Set([
8636
8720
  "style",
@@ -9191,16 +9275,6 @@ function readDescriptorToken(value, index) {
9191
9275
  nextIndex: cursor
9192
9276
  };
9193
9277
  }
9194
-
9195
- // src/runtimes/dom/errors.ts
9196
- var ElementPathError = class extends Error {
9197
- code;
9198
- constructor(code, message) {
9199
- super(message);
9200
- this.name = "ElementPathError";
9201
- this.code = code;
9202
- }
9203
- };
9204
9278
  var selectorAdapter = {
9205
9279
  isTag(node) {
9206
9280
  return node.kind === "element" && node.source.nodeType === 1;
@@ -9955,24 +10029,31 @@ function collectChildrenInScope(index, node, scopeHostNodeRef) {
9955
10029
  function getShadowScopeNodeRef(index, node) {
9956
10030
  return findContainingShadowHostNode(index, node)?.nodeRef;
9957
10031
  }
10032
+
10033
+ // src/runtimes/dom/descriptors.ts
9958
10034
  function createDomDescriptorStore(options) {
9959
- const namespace = normalizeNamespace(options.namespace);
10035
+ const namespace = normalizeDomDescriptorNamespace(options.namespace);
9960
10036
  if (options.root) {
9961
10037
  return new FilesystemDomDescriptorStore(options.root.registry.descriptors, namespace);
9962
10038
  }
9963
10039
  return new MemoryDomDescriptorStore(namespace);
9964
10040
  }
9965
- function descriptionKey(namespace, method, description) {
9966
- return `dom:${namespace}:${method}:${sha256Hex2(description.trim())}`;
10041
+ function hashDomDescriptorDescription(description) {
10042
+ return sha256Hex2(description.trim());
9967
10043
  }
9968
- function normalizeNamespace(namespace) {
10044
+ function buildDomDescriptorKey(options) {
10045
+ return `dom:${normalizeDomDescriptorNamespace(options.namespace)}:${options.method}:${hashDomDescriptorDescription(
10046
+ options.description
10047
+ )}`;
10048
+ }
10049
+ function normalizeDomDescriptorNamespace(namespace) {
9969
10050
  const normalized = String(namespace || "default").trim();
9970
10051
  return normalized.length === 0 ? "default" : normalized;
9971
10052
  }
9972
10053
  function sha256Hex2(value) {
9973
10054
  return createHash("sha256").update(value).digest("hex");
9974
10055
  }
9975
- function buildPayload(input) {
10056
+ function buildDomDescriptorPayload(input) {
9976
10057
  return {
9977
10058
  kind: "dom-target",
9978
10059
  method: input.method,
@@ -9981,6 +10062,9 @@ function buildPayload(input) {
9981
10062
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
9982
10063
  };
9983
10064
  }
10065
+ function buildDomDescriptorVersion(payload) {
10066
+ return sha256Hex2(canonicalJsonString(payload));
10067
+ }
9984
10068
  function parseDomDescriptorRecord(record) {
9985
10069
  const payload = record.payload;
9986
10070
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
@@ -10022,7 +10106,11 @@ var FilesystemDomDescriptorStore = class {
10022
10106
  }
10023
10107
  async read(input) {
10024
10108
  const record = await this.registry.resolve({
10025
- key: descriptionKey(this.namespace, input.method, input.description)
10109
+ key: buildDomDescriptorKey({
10110
+ namespace: this.namespace,
10111
+ method: input.method,
10112
+ description: input.description
10113
+ })
10026
10114
  });
10027
10115
  if (!record) {
10028
10116
  return void 0;
@@ -10030,9 +10118,13 @@ var FilesystemDomDescriptorStore = class {
10030
10118
  return parseDomDescriptorRecord(record);
10031
10119
  }
10032
10120
  async write(input) {
10033
- const payload = buildPayload(input);
10034
- const key = descriptionKey(this.namespace, input.method, input.description);
10035
- const version = sha256Hex2(canonicalJsonString(payload));
10121
+ const payload = buildDomDescriptorPayload(input);
10122
+ const key = buildDomDescriptorKey({
10123
+ namespace: this.namespace,
10124
+ method: input.method,
10125
+ description: input.description
10126
+ });
10127
+ const version = buildDomDescriptorVersion(payload);
10036
10128
  const existing = await this.registry.resolve({ key, version });
10037
10129
  if (existing) {
10038
10130
  const parsed2 = parseDomDescriptorRecord(existing);
@@ -10070,12 +10162,22 @@ var MemoryDomDescriptorStore = class {
10070
10162
  latestByKey = /* @__PURE__ */ new Map();
10071
10163
  recordsByKey = /* @__PURE__ */ new Map();
10072
10164
  async read(input) {
10073
- return this.latestByKey.get(descriptionKey(this.namespace, input.method, input.description));
10165
+ return this.latestByKey.get(
10166
+ buildDomDescriptorKey({
10167
+ namespace: this.namespace,
10168
+ method: input.method,
10169
+ description: input.description
10170
+ })
10171
+ );
10074
10172
  }
10075
10173
  async write(input) {
10076
- const payload = buildPayload(input);
10077
- const key = descriptionKey(this.namespace, input.method, input.description);
10078
- const version = sha256Hex2(canonicalJsonString(payload));
10174
+ const payload = buildDomDescriptorPayload(input);
10175
+ const key = buildDomDescriptorKey({
10176
+ namespace: this.namespace,
10177
+ method: input.method,
10178
+ description: input.description
10179
+ });
10180
+ const version = buildDomDescriptorVersion(payload);
10079
10181
  const existing = this.recordsByKey.get(key)?.get(version);
10080
10182
  if (existing) {
10081
10183
  return existing;
@@ -10718,7 +10820,7 @@ var DefaultDomRuntime = class {
10718
10820
  bridge;
10719
10821
  constructor(options) {
10720
10822
  this.engine = options.engine;
10721
- this.descriptors = createDomDescriptorStore({
10823
+ this.descriptors = options.descriptorStore ?? createDomDescriptorStore({
10722
10824
  ...options.root === void 0 ? {} : { root: options.root },
10723
10825
  ...options.namespace === void 0 ? {} : { namespace: options.namespace }
10724
10826
  });
@@ -12606,7 +12708,7 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
12606
12708
  const body = inferRequestPlanBody(record.record.requestBody, requestContentType);
12607
12709
  const payload = normalizeRequestPlanPayload({
12608
12710
  transport: {
12609
- kind: "context-http"
12711
+ kind: input.transport ?? "context-http"
12610
12712
  },
12611
12713
  endpoint: {
12612
12714
  method: record.record.method,
@@ -12626,7 +12728,6 @@ function inferRequestPlanFromNetworkRecord(record, input, options = {}) {
12626
12728
  return {
12627
12729
  key: input.key,
12628
12730
  version: input.version,
12629
- lifecycle: input.lifecycle ?? "draft",
12630
12731
  provenance: {
12631
12732
  source: record.source === "saved" ? "saved-network-record" : "live-network-record",
12632
12733
  sourceId: record.recordId,
@@ -16898,7 +16999,6 @@ async function compileOpensteerExtractionFieldTargets(options) {
16898
16999
  await collectFieldTargetsFromSchemaObject({
16899
17000
  dom: options.dom,
16900
17001
  pageRef: options.pageRef,
16901
- latestSnapshotCounters: options.latestSnapshotCounters,
16902
17002
  value: options.schema,
16903
17003
  path: "",
16904
17004
  fields,
@@ -16916,22 +17016,11 @@ async function extractOpensteerExtractionFieldTargets(options) {
16916
17016
  source: "current_url"
16917
17017
  };
16918
17018
  }
16919
- if ("path" in field) {
16920
- return {
16921
- key: field.key,
16922
- target: {
16923
- kind: "path",
16924
- path: field.path
16925
- },
16926
- ...field.attribute === void 0 ? {} : { attribute: field.attribute }
16927
- };
16928
- }
16929
17019
  return {
16930
17020
  key: field.key,
16931
17021
  target: {
16932
- kind: "live",
16933
- locator: field.locator,
16934
- anchor: field.anchor
17022
+ kind: "path",
17023
+ path: field.path
16935
17024
  },
16936
17025
  ...field.attribute === void 0 ? {} : { attribute: field.attribute }
16937
17026
  };
@@ -16940,8 +17029,6 @@ async function extractOpensteerExtractionFieldTargets(options) {
16940
17029
  }
16941
17030
  async function compilePersistedOpensteerExtractionPayloadFromFieldTargets(options) {
16942
17031
  const fields = await resolvePersistableFieldTargets({
16943
- pageRef: options.pageRef,
16944
- dom: options.dom,
16945
17032
  fieldTargets: options.fieldTargets
16946
17033
  });
16947
17034
  const payload = buildPersistedOpensteerExtractionPayload(fields);
@@ -16955,7 +17042,7 @@ async function replayOpensteerExtractionPayload(options) {
16955
17042
  return extractPersistedObjectNode(options.pageRef, options.dom, options.payload);
16956
17043
  }
16957
17044
  function createOpensteerExtractionDescriptorStore(options) {
16958
- const namespace = normalizeNamespace2(options.namespace);
17045
+ const namespace = normalizeNamespace(options.namespace);
16959
17046
  if (options.root) {
16960
17047
  return new FilesystemOpensteerExtractionDescriptorStore(
16961
17048
  options.root.registry.descriptors,
@@ -16973,7 +17060,6 @@ async function collectFieldTargetsFromSchemaObject(options) {
16973
17060
  await collectFieldTargetsFromSchemaValue({
16974
17061
  dom: options.dom,
16975
17062
  pageRef: options.pageRef,
16976
- latestSnapshotCounters: options.latestSnapshotCounters,
16977
17063
  value: childValue,
16978
17064
  path: joinDataPath(options.path, normalizedKey),
16979
17065
  fields: options.fields,
@@ -16988,7 +17074,6 @@ async function collectFieldTargetsFromSchemaValue(options) {
16988
17074
  await compileFieldTarget({
16989
17075
  dom: options.dom,
16990
17076
  pageRef: options.pageRef,
16991
- latestSnapshotCounters: options.latestSnapshotCounters,
16992
17077
  field: normalizedField,
16993
17078
  path: options.path
16994
17079
  })
@@ -17017,7 +17102,6 @@ async function collectFieldTargetsFromSchemaValue(options) {
17017
17102
  await collectFieldTargetsFromSchemaObject({
17018
17103
  dom: options.dom,
17019
17104
  pageRef: options.pageRef,
17020
- latestSnapshotCounters: options.latestSnapshotCounters,
17021
17105
  value: itemValue,
17022
17106
  path: appendDataPathIndex(options.path, index),
17023
17107
  fields: options.fields,
@@ -17040,7 +17124,6 @@ async function collectFieldTargetsFromSchemaValue(options) {
17040
17124
  await collectFieldTargetsFromSchemaObject({
17041
17125
  dom: options.dom,
17042
17126
  pageRef: options.pageRef,
17043
- latestSnapshotCounters: options.latestSnapshotCounters,
17044
17127
  value: options.value,
17045
17128
  path: options.path,
17046
17129
  fields: options.fields,
@@ -17067,10 +17150,10 @@ async function compileFieldTarget(options) {
17067
17150
  }
17068
17151
  return {
17069
17152
  key: options.path,
17070
- ...await resolveLiveFieldTarget({
17071
- latestSnapshotCounters: options.latestSnapshotCounters,
17072
- field: options.field,
17073
- path: options.path
17153
+ path: await resolveSelectorFieldPath({
17154
+ dom: options.dom,
17155
+ pageRef: options.pageRef,
17156
+ selector: `[c="${String(options.field.element)}"]`
17074
17157
  }),
17075
17158
  ...options.field.attribute === void 0 ? {} : { attribute: options.field.attribute }
17076
17159
  };
@@ -17088,24 +17171,6 @@ async function resolveSelectorFieldPath(options) {
17088
17171
  locator: resolved.locator
17089
17172
  });
17090
17173
  }
17091
- async function resolveLiveFieldTarget(options) {
17092
- const counters = options.latestSnapshotCounters;
17093
- if (counters === void 0) {
17094
- throw new Error(
17095
- `Extraction schema field "${labelForPath(options.path)}" uses element ${String(options.field.element)} but no snapshot is available.`
17096
- );
17097
- }
17098
- const counter = counters.get(options.field.element);
17099
- if (!counter) {
17100
- throw new Error(
17101
- `Extraction schema field "${labelForPath(options.path)}" references missing counter ${String(options.field.element)}.`
17102
- );
17103
- }
17104
- return {
17105
- locator: counter.locator,
17106
- anchor: counter.anchor
17107
- };
17108
- }
17109
17174
  async function resolvePersistableFieldTargets(options) {
17110
17175
  const fields = [];
17111
17176
  for (const field of options.fieldTargets) {
@@ -17116,29 +17181,9 @@ async function resolvePersistableFieldTargets(options) {
17116
17181
  });
17117
17182
  continue;
17118
17183
  }
17119
- if ("path" in field) {
17120
- fields.push({
17121
- key: field.key,
17122
- path: sanitizeElementPath(field.path),
17123
- ...field.attribute === void 0 ? {} : { attribute: field.attribute }
17124
- });
17125
- continue;
17126
- }
17127
- const resolved = await options.dom.resolveTarget({
17128
- pageRef: options.pageRef,
17129
- method: "extract",
17130
- target: {
17131
- kind: "live",
17132
- locator: field.locator,
17133
- anchor: field.anchor
17134
- }
17135
- });
17136
- const path9 = resolved.replayPath ?? await options.dom.buildPath({
17137
- locator: resolved.locator
17138
- });
17139
17184
  fields.push({
17140
17185
  key: field.key,
17141
- path: sanitizeElementPath(path9),
17186
+ path: sanitizeElementPath(field.path),
17142
17187
  ...field.attribute === void 0 ? {} : { attribute: field.attribute }
17143
17188
  });
17144
17189
  }
@@ -17452,11 +17497,11 @@ function normalizeSchemaField(value) {
17452
17497
  ...attribute === void 0 ? {} : { attribute }
17453
17498
  };
17454
17499
  }
17455
- function normalizeNamespace2(namespace) {
17500
+ function normalizeNamespace(namespace) {
17456
17501
  const normalized = String(namespace ?? "default").trim();
17457
17502
  return normalized.length === 0 ? "default" : normalized;
17458
17503
  }
17459
- function descriptionKey2(namespace, description) {
17504
+ function descriptionKey(namespace, description) {
17460
17505
  return `extract:${namespace}:${sha256Hex3(description.trim())}`;
17461
17506
  }
17462
17507
  function parseExtractionDescriptorRecord(record) {
@@ -17559,7 +17604,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
17559
17604
  }
17560
17605
  async read(input) {
17561
17606
  const record = await this.registry.resolve({
17562
- key: descriptionKey2(this.namespace, input.description)
17607
+ key: descriptionKey(this.namespace, input.description)
17563
17608
  });
17564
17609
  return record === void 0 ? void 0 : parseExtractionDescriptorRecord(record);
17565
17610
  }
@@ -17571,7 +17616,7 @@ var FilesystemOpensteerExtractionDescriptorStore = class {
17571
17616
  ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
17572
17617
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
17573
17618
  };
17574
- const key = descriptionKey2(this.namespace, input.description);
17619
+ const key = descriptionKey(this.namespace, input.description);
17575
17620
  const version = sha256Hex3(canonicalJsonString(payload));
17576
17621
  const existing = await this.registry.resolve({ key, version });
17577
17622
  if (existing) {
@@ -17610,7 +17655,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
17610
17655
  latestByKey = /* @__PURE__ */ new Map();
17611
17656
  recordsByKey = /* @__PURE__ */ new Map();
17612
17657
  async read(input) {
17613
- return this.latestByKey.get(descriptionKey2(this.namespace, input.description));
17658
+ return this.latestByKey.get(descriptionKey(this.namespace, input.description));
17614
17659
  }
17615
17660
  async write(input) {
17616
17661
  const payload = {
@@ -17620,7 +17665,7 @@ var MemoryOpensteerExtractionDescriptorStore = class {
17620
17665
  ...input.schemaHash === void 0 ? {} : { schemaHash: input.schemaHash },
17621
17666
  ...input.sourceUrl === void 0 ? {} : { sourceUrl: input.sourceUrl }
17622
17667
  };
17623
- const key = descriptionKey2(this.namespace, input.description);
17668
+ const key = descriptionKey(this.namespace, input.description);
17624
17669
  const version = sha256Hex3(canonicalJsonString(payload));
17625
17670
  const existing = this.recordsByKey.get(key)?.get(version);
17626
17671
  if (existing) {
@@ -17664,6 +17709,7 @@ var OPENSTEER_INTERACTIVE_ATTR = "data-opensteer-interactive";
17664
17709
  var OPENSTEER_HIDDEN_ATTR = "data-opensteer-hidden";
17665
17710
  var OPENSTEER_SCROLLABLE_ATTR = "data-opensteer-scrollable";
17666
17711
  var OPENSTEER_NODE_ID_ATTR = "data-os-node-id";
17712
+ var OPENSTEER_SPARSE_COUNTER_ATTR = "data-os-c";
17667
17713
  var OPENSTEER_BOUNDARY_ATTR = "data-os-boundary";
17668
17714
  var OPENSTEER_UNAVAILABLE_ATTR = "data-os-unavailable";
17669
17715
  var OPENSTEER_IFRAME_BOUNDARY_TAG = "os-iframe-root";
@@ -18168,7 +18214,82 @@ var VOID_TAGS2 = /* @__PURE__ */ new Set([
18168
18214
  ]);
18169
18215
 
18170
18216
  // src/sdk/snapshot/compiler.ts
18217
+ async function assignSparseCountersToLiveDom(engine, pageRef) {
18218
+ try {
18219
+ await engine.evaluatePage({
18220
+ pageRef,
18221
+ script: `(() => {
18222
+ let counter = 1;
18223
+ const walk = (root) => {
18224
+ for (const child of root.children) {
18225
+ child.setAttribute('data-os-c', String(counter++));
18226
+ walk(child);
18227
+ if (child.shadowRoot) walk(child.shadowRoot);
18228
+ }
18229
+ };
18230
+ walk(document);
18231
+ })()`
18232
+ });
18233
+ return true;
18234
+ } catch {
18235
+ return false;
18236
+ }
18237
+ }
18238
+ async function syncDenseCountersToLiveDom(engine, pageRef, sparseToDirectMapping) {
18239
+ const mappingObj = Object.fromEntries(sparseToDirectMapping);
18240
+ await engine.evaluatePage({
18241
+ pageRef,
18242
+ script: `((mapping) => {
18243
+ const walk = (root) => {
18244
+ for (const child of root.children) {
18245
+ child.removeAttribute('c');
18246
+ const sparse = child.getAttribute('data-os-c');
18247
+ if (sparse !== null) {
18248
+ const dense = mapping[sparse];
18249
+ if (dense !== undefined) {
18250
+ child.setAttribute('c', String(dense));
18251
+ }
18252
+ child.removeAttribute('data-os-c');
18253
+ }
18254
+ walk(child);
18255
+ if (child.shadowRoot) walk(child.shadowRoot);
18256
+ }
18257
+ };
18258
+ walk(document);
18259
+ })`,
18260
+ args: [mappingObj]
18261
+ });
18262
+ }
18263
+ function renumberCountersDensely(cleanedHtml, counterRecords) {
18264
+ const $ = cheerio.load(cleanedHtml, { xmlMode: false });
18265
+ const newRecords = /* @__PURE__ */ new Map();
18266
+ const sparseToDirectMapping = /* @__PURE__ */ new Map();
18267
+ let nextDense = 1;
18268
+ $("[c]").each(function renumberElement() {
18269
+ const el = $(this);
18270
+ const oldC = Number.parseInt(String(el.attr("c") || ""), 10);
18271
+ if (!Number.isFinite(oldC)) {
18272
+ return;
18273
+ }
18274
+ const record = counterRecords.get(oldC);
18275
+ if (!record) {
18276
+ return;
18277
+ }
18278
+ const denseC = nextDense++;
18279
+ el.attr("c", String(denseC));
18280
+ newRecords.set(denseC, { ...record, element: denseC });
18281
+ if (record.sparseCounter !== void 0) {
18282
+ sparseToDirectMapping.set(record.sparseCounter, denseC);
18283
+ }
18284
+ });
18285
+ return {
18286
+ html: $.html(),
18287
+ counterRecords: newRecords,
18288
+ sparseToDirectMapping
18289
+ };
18290
+ }
18171
18291
  async function compileOpensteerSnapshot(options) {
18292
+ const liveCountersEnabled = await assignSparseCountersToLiveDom(options.engine, options.pageRef);
18172
18293
  const pageInfo = await options.engine.getPageInfo({ pageRef: options.pageRef });
18173
18294
  const mainSnapshot = await getMainDocumentSnapshot(options.engine, options.pageRef);
18174
18295
  const snapshotsByDocumentRef = await collectDocumentSnapshots(options.engine, mainSnapshot);
@@ -18187,13 +18308,23 @@ async function compileOpensteerSnapshot(options) {
18187
18308
  const compiledHtml = assignCounters(rawHtml, renderedNodes);
18188
18309
  const cleanedHtml = options.mode === "extraction" ? cleanForExtraction(compiledHtml.html) : cleanForAction(compiledHtml.html);
18189
18310
  const filtered = retainVisibleCounterRecords(cleanedHtml, compiledHtml.counterRecords);
18311
+ const dense = renumberCountersDensely(cleanedHtml, filtered);
18312
+ if (liveCountersEnabled && dense.sparseToDirectMapping.size > 0) {
18313
+ try {
18314
+ await syncDenseCountersToLiveDom(
18315
+ options.engine,
18316
+ options.pageRef,
18317
+ dense.sparseToDirectMapping
18318
+ );
18319
+ } catch {
18320
+ }
18321
+ }
18190
18322
  return {
18191
18323
  url: pageInfo.url,
18192
18324
  title: pageInfo.title,
18193
18325
  mode: options.mode,
18194
- html: cleanedHtml,
18195
- counters: [...filtered.values()].map(toPublicCounterRecord),
18196
- counterRecords: filtered
18326
+ html: dense.html,
18327
+ counters: [...dense.counterRecords.values()].map(toPublicCounterRecord)
18197
18328
  };
18198
18329
  }
18199
18330
  async function getMainDocumentSnapshot(engine, pageRef) {
@@ -18422,6 +18553,9 @@ function assignCounters(rawHtml, renderedNodes) {
18422
18553
  if (!rendered) {
18423
18554
  return;
18424
18555
  }
18556
+ const rawSparseCounter = el.attr(OPENSTEER_SPARSE_COUNTER_ATTR);
18557
+ el.removeAttr(OPENSTEER_SPARSE_COUNTER_ATTR);
18558
+ const sparseCounter = rawSparseCounter ? Number.parseInt(rawSparseCounter, 10) : void 0;
18425
18559
  const counter = nextCounter++;
18426
18560
  el.attr("c", String(counter));
18427
18561
  counterRecords.set(counter, {
@@ -18439,7 +18573,8 @@ function assignCounters(rawHtml, renderedNodes) {
18439
18573
  shadowDepth: rendered.shadowDepth,
18440
18574
  interactive: rendered.interactive,
18441
18575
  locator: rendered.locator,
18442
- anchor: rendered.anchor
18576
+ anchor: rendered.anchor,
18577
+ ...sparseCounter !== void 0 && Number.isFinite(sparseCounter) ? { sparseCounter } : {}
18443
18578
  });
18444
18579
  });
18445
18580
  return {
@@ -19807,6 +19942,9 @@ var OpensteerSessionRuntime = class {
19807
19942
  injectedEngine;
19808
19943
  engineFactory;
19809
19944
  policy;
19945
+ injectedDescriptorStore;
19946
+ injectedExtractionDescriptorStore;
19947
+ registryOverrides;
19810
19948
  cleanupRootOnClose;
19811
19949
  sessionInfoBase;
19812
19950
  root;
@@ -19818,19 +19956,21 @@ var OpensteerSessionRuntime = class {
19818
19956
  sessionRef;
19819
19957
  pageRef;
19820
19958
  runId;
19821
- latestSnapshot;
19822
19959
  backgroundNetworkPersistence = /* @__PURE__ */ new Set();
19823
19960
  cookieJars = /* @__PURE__ */ new Map();
19824
19961
  recipeCache = /* @__PURE__ */ new Map();
19825
19962
  ownsEngine = false;
19826
19963
  constructor(options) {
19827
- this.workspace = normalizeNamespace3(options.name);
19964
+ this.workspace = normalizeNamespace2(options.name);
19828
19965
  this.workspaceName = options.workspaceName?.trim() === void 0 || options.workspaceName?.trim().length === 0 ? void 0 : options.workspaceName.trim();
19829
19966
  this.root = options.workspace;
19830
19967
  this.rootPath = options.workspace?.rootPath ?? options.rootPath ?? path6.resolve(process.cwd(), ".opensteer", "temporary", randomUUID());
19831
19968
  this.injectedEngine = options.engine;
19832
19969
  this.engineFactory = options.engineFactory;
19833
19970
  this.policy = options.policy ?? defaultPolicy();
19971
+ this.injectedDescriptorStore = options.descriptorStore;
19972
+ this.injectedExtractionDescriptorStore = options.extractionDescriptorStore;
19973
+ this.registryOverrides = options.registryOverrides;
19834
19974
  this.cleanupRootOnClose = options.cleanupRootOnClose ?? options.workspace === void 0;
19835
19975
  this.sessionInfoBase = options.sessionInfo ?? {};
19836
19976
  if (this.injectedEngine === void 0 && this.engineFactory === void 0) {
@@ -19841,7 +19981,7 @@ var OpensteerSessionRuntime = class {
19841
19981
  const base = this.sessionInfoBase;
19842
19982
  return {
19843
19983
  provider: base.provider ?? {
19844
- kind: "local",
19984
+ mode: "local",
19845
19985
  ownership: "owned",
19846
19986
  engine: "playwright"
19847
19987
  },
@@ -19866,7 +20006,7 @@ var OpensteerSessionRuntime = class {
19866
20006
  }
19867
20007
  async open(input = {}, options = {}) {
19868
20008
  assertValidSemanticOperationInput("session.open", input);
19869
- if (input.workspace !== void 0 && normalizeNamespace3(input.workspace) !== this.workspace) {
20009
+ if (input.workspace !== void 0 && normalizeNamespace2(input.workspace) !== this.workspace) {
19870
20010
  throw new Error(
19871
20011
  `session.open requested workspace "${input.workspace}" but runtime is bound to "${this.workspace}"`
19872
20012
  );
@@ -19908,7 +20048,6 @@ var OpensteerSessionRuntime = class {
19908
20048
  timeout.throwIfAborted();
19909
20049
  this.sessionRef = sessionRef;
19910
20050
  this.pageRef = createdPage.data.pageRef;
19911
- this.latestSnapshot = void 0;
19912
20051
  await timeout.runStep(() => this.ensureSemantics());
19913
20052
  let frameRef2 = createdPage.frameRef;
19914
20053
  if (input.url !== void 0) {
@@ -20031,7 +20170,6 @@ var OpensteerSessionRuntime = class {
20031
20170
  })
20032
20171
  );
20033
20172
  this.pageRef = created.data.pageRef;
20034
- this.latestSnapshot = void 0;
20035
20173
  return this.readSessionState();
20036
20174
  },
20037
20175
  options
@@ -20074,7 +20212,6 @@ var OpensteerSessionRuntime = class {
20074
20212
  () => this.requireEngine().activatePage({ pageRef: input.pageRef })
20075
20213
  );
20076
20214
  this.pageRef = input.pageRef;
20077
- this.latestSnapshot = void 0;
20078
20215
  return this.readSessionState();
20079
20216
  },
20080
20217
  options
@@ -20138,7 +20275,6 @@ var OpensteerSessionRuntime = class {
20138
20275
  );
20139
20276
  }
20140
20277
  this.pageRef = activePageRef;
20141
- this.latestSnapshot = void 0;
20142
20278
  return {
20143
20279
  closedPageRef: targetPageRef,
20144
20280
  ...activePageRef === void 0 ? {} : { activePageRef },
@@ -20197,7 +20333,6 @@ var OpensteerSessionRuntime = class {
20197
20333
  timeout
20198
20334
  );
20199
20335
  timeout.throwIfAborted();
20200
- this.latestSnapshot = void 0;
20201
20336
  await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
20202
20337
  return {
20203
20338
  navigation: navigation2,
@@ -20367,7 +20502,6 @@ var OpensteerSessionRuntime = class {
20367
20502
  })
20368
20503
  );
20369
20504
  timeout.throwIfAborted();
20370
- this.latestSnapshot = compiled;
20371
20505
  const artifacts2 = await this.captureSnapshotArtifacts(
20372
20506
  pageRef,
20373
20507
  {
@@ -20517,8 +20651,7 @@ var OpensteerSessionRuntime = class {
20517
20651
  () => compileOpensteerExtractionFieldTargets({
20518
20652
  pageRef,
20519
20653
  schema: input.schema,
20520
- dom: this.requireDom(),
20521
- ...this.latestSnapshot?.counterRecords === void 0 ? {} : { latestSnapshotCounters: this.latestSnapshot.counterRecords }
20654
+ dom: this.requireDom()
20522
20655
  })
20523
20656
  );
20524
20657
  data = toCanonicalJsonValue(
@@ -22282,8 +22415,7 @@ var OpensteerSessionRuntime = class {
22282
22415
  const inferred = inferRequestPlanFromNetworkRecord(record, {
22283
22416
  recordId: candidate.recordId,
22284
22417
  key: input.key,
22285
- version: input.version,
22286
- lifecycle: "draft"
22418
+ version: input.version
22287
22419
  });
22288
22420
  const defaultHeaders = inferred.payload.endpoint.defaultHeaders === void 0 ? void 0 : stripManagedRequestHeaders(
22289
22421
  inferred.payload.endpoint.defaultHeaders,
@@ -22911,8 +23043,7 @@ var OpensteerSessionRuntime = class {
22911
23043
  recordId: input.recordId,
22912
23044
  id: record.id,
22913
23045
  key: record.key,
22914
- version: record.version,
22915
- lifecycle: record.lifecycle
23046
+ version: record.version
22916
23047
  }
22917
23048
  });
22918
23049
  return record;
@@ -22953,8 +23084,7 @@ var OpensteerSessionRuntime = class {
22953
23084
  data: {
22954
23085
  id: record.id,
22955
23086
  key: record.key,
22956
- version: record.version,
22957
- lifecycle: record.lifecycle
23087
+ version: record.version
22958
23088
  }
22959
23089
  });
22960
23090
  return record;
@@ -23000,8 +23130,7 @@ var OpensteerSessionRuntime = class {
23000
23130
  data: {
23001
23131
  id: record.id,
23002
23132
  key: record.key,
23003
- version: record.version,
23004
- lifecycle: record.lifecycle
23133
+ version: record.version
23005
23134
  }
23006
23135
  });
23007
23136
  return record;
@@ -23641,7 +23770,6 @@ var OpensteerSessionRuntime = class {
23641
23770
  });
23642
23771
  timeout.throwIfAborted();
23643
23772
  this.pageRef = output2.pageRef;
23644
- this.latestSnapshot = void 0;
23645
23773
  await this.completeMutationCapture(timeout, baselineRequestIds, input.networkTag);
23646
23774
  const artifacts2 = await this.persistComputerArtifacts(output2, timeout);
23647
23775
  return {
@@ -23871,19 +23999,12 @@ var OpensteerSessionRuntime = class {
23871
23999
  };
23872
24000
  }
23873
24001
  if (target.kind === "element") {
23874
- const counter = this.latestSnapshot?.counterRecords.get(target.element);
23875
- if (!counter) {
23876
- throw new Error(`no counter ${String(target.element)} is available in the latest snapshot`);
23877
- }
24002
+ const elementTarget = { kind: "selector", selector: `[c="${String(target.element)}"]` };
23878
24003
  const resolved2 = await timeout.runStep(
23879
24004
  () => this.requireDom().resolveTarget({
23880
24005
  pageRef,
23881
24006
  method,
23882
- target: {
23883
- kind: "live",
23884
- locator: counter.locator,
23885
- anchor: counter.anchor
23886
- }
24007
+ target: elementTarget
23887
24008
  })
23888
24009
  );
23889
24010
  const stablePath2 = resolved2.replayPath ?? await timeout.runStep(
@@ -25126,7 +25247,7 @@ var OpensteerSessionRuntime = class {
25126
25247
  }
25127
25248
  async touchRequestPlanFreshness(plan) {
25128
25249
  const freshness = touchFreshness(plan.freshness);
25129
- await this.requireRoot().registry.requestPlans.updateMetadata({
25250
+ await this.requireRoot().registry.requestPlans.updateFreshness({
25130
25251
  id: plan.id,
25131
25252
  ...freshness === void 0 ? {} : { freshness }
25132
25253
  });
@@ -25794,22 +25915,33 @@ var OpensteerSessionRuntime = class {
25794
25915
  selector: target.selector
25795
25916
  };
25796
25917
  }
25797
- const counter = this.latestSnapshot?.counterRecords.get(target.element);
25798
- if (!counter) {
25799
- throw new Error(`no counter ${String(target.element)} is available in the latest snapshot`);
25800
- }
25801
25918
  return {
25802
- kind: "live",
25803
- locator: counter.locator,
25804
- anchor: counter.anchor
25919
+ kind: "selector",
25920
+ selector: `[c="${String(target.element)}"]`
25805
25921
  };
25806
25922
  }
25807
25923
  async ensureRoot() {
25808
- this.root ??= await createFilesystemOpensteerWorkspace({
25809
- rootPath: this.rootPath,
25810
- ...this.workspaceName === void 0 ? {} : { workspace: this.workspaceName },
25811
- scope: this.workspaceName === void 0 ? "temporary" : "workspace"
25812
- });
25924
+ if (!this.root) {
25925
+ const workspace = await createFilesystemOpensteerWorkspace({
25926
+ rootPath: this.rootPath,
25927
+ ...this.workspaceName === void 0 ? {} : { workspace: this.workspaceName },
25928
+ scope: this.workspaceName === void 0 ? "temporary" : "workspace"
25929
+ });
25930
+ if (this.registryOverrides) {
25931
+ const overrides = this.registryOverrides;
25932
+ this.root = {
25933
+ ...workspace,
25934
+ registry: {
25935
+ ...workspace.registry,
25936
+ ...overrides.requestPlans === void 0 ? {} : { requestPlans: overrides.requestPlans },
25937
+ ...overrides.authRecipes === void 0 ? {} : { authRecipes: overrides.authRecipes },
25938
+ ...overrides.recipes === void 0 ? {} : { recipes: overrides.recipes }
25939
+ }
25940
+ };
25941
+ } else {
25942
+ this.root = workspace;
25943
+ }
25944
+ }
25813
25945
  return this.root;
25814
25946
  }
25815
25947
  async ensureEngine(overrides = {}) {
@@ -25835,6 +25967,7 @@ var OpensteerSessionRuntime = class {
25835
25967
  engine,
25836
25968
  root,
25837
25969
  namespace: this.workspace,
25970
+ ...this.injectedDescriptorStore === void 0 ? {} : { descriptorStore: this.injectedDescriptorStore },
25838
25971
  policy: this.policy
25839
25972
  });
25840
25973
  this.computer = createComputerUseRuntime({
@@ -25842,7 +25975,7 @@ var OpensteerSessionRuntime = class {
25842
25975
  dom: this.dom,
25843
25976
  policy: this.policy
25844
25977
  });
25845
- this.extractionDescriptors = createOpensteerExtractionDescriptorStore({
25978
+ this.extractionDescriptors = this.injectedExtractionDescriptorStore ?? createOpensteerExtractionDescriptorStore({
25846
25979
  root,
25847
25980
  namespace: this.workspace
25848
25981
  });
@@ -26063,7 +26196,6 @@ var OpensteerSessionRuntime = class {
26063
26196
  this.backgroundNetworkPersistence.clear();
26064
26197
  this.sessionRef = void 0;
26065
26198
  this.pageRef = void 0;
26066
- this.latestSnapshot = void 0;
26067
26199
  this.runId = void 0;
26068
26200
  this.dom = void 0;
26069
26201
  this.computer = void 0;
@@ -26421,7 +26553,6 @@ function buildMinimizedRequestPlan(input) {
26421
26553
  sourceId: input.record.recordId,
26422
26554
  ...input.record.source === "saved" && input.record.savedAt !== void 0 ? { capturedAt: input.record.savedAt } : {}
26423
26555
  },
26424
- lifecycle: "draft",
26425
26556
  payload: normalizeRequestPlanPayload({
26426
26557
  transport: {
26427
26558
  kind: input.transport
@@ -28576,7 +28707,7 @@ function directionToDelta(direction, amount) {
28576
28707
  return { x: amount, y: 0 };
28577
28708
  }
28578
28709
  }
28579
- function normalizeNamespace3(value) {
28710
+ function normalizeNamespace2(value) {
28580
28711
  const normalized = String(value ?? "default").trim();
28581
28712
  return normalized.length === 0 ? "default" : normalized;
28582
28713
  }
@@ -28622,6 +28753,6 @@ function screenshotMediaType(format2) {
28622
28753
  }
28623
28754
  }
28624
28755
 
28625
- export { OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OPENSTEER_RUNTIME_CORE_VERSION, OpensteerSessionRuntime, createFilesystemOpensteerWorkspace, dispatchSemanticOperation, normalizeWorkspaceId, resolveFilesystemWorkspacePath };
28756
+ export { OPENSTEER_FILESYSTEM_WORKSPACE_LAYOUT, OPENSTEER_FILESYSTEM_WORKSPACE_VERSION, OPENSTEER_RUNTIME_CORE_VERSION, OpensteerSessionRuntime, buildDomDescriptorKey, buildDomDescriptorPayload, buildDomDescriptorVersion, createDomDescriptorStore, createFilesystemOpensteerWorkspace, createOpensteerExtractionDescriptorStore, dispatchSemanticOperation, hashDomDescriptorDescription, normalizeWorkspaceId, parseDomDescriptorRecord, parseExtractionDescriptorRecord, resolveFilesystemWorkspacePath, sanitizeReplayElementPath };
28626
28757
  //# sourceMappingURL=index.js.map
28627
28758
  //# sourceMappingURL=index.js.map