@vostride/agent-qa-core 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -45,43 +45,43 @@ var init_config = __esm({
45
45
  });
46
46
 
47
47
  // src/memory/schema.ts
48
- var import_zod18, import_agent_qa_ids5, ObservationIdSchema, CanonicalObservationIdSchema, ObservationSuiteSnapshotEntrySchema, BaseObservationSchema, SuiteObservationSchema, BaseObservationWriteSchema, SuiteObservationWriteSchema;
48
+ var import_zod19, import_agent_qa_ids5, ObservationIdSchema, CanonicalObservationIdSchema, ObservationSuiteSnapshotEntrySchema, BaseObservationSchema, SuiteObservationSchema, BaseObservationWriteSchema, SuiteObservationWriteSchema;
49
49
  var init_schema = __esm({
50
50
  "src/memory/schema.ts"() {
51
51
  "use strict";
52
- import_zod18 = require("zod");
52
+ import_zod19 = require("zod");
53
53
  import_agent_qa_ids5 = require("@vostride/agent-qa-ids");
54
- ObservationIdSchema = import_zod18.z.string().refine((value) => (0, import_agent_qa_ids5.isObservationId)(value), {
54
+ ObservationIdSchema = import_zod19.z.string().refine((value) => (0, import_agent_qa_ids5.isObservationId)(value), {
55
55
  message: "Observation ID must be obs_ followed by either 10 canonical words or a legacy 6-word body"
56
56
  });
57
- CanonicalObservationIdSchema = import_zod18.z.string().refine((value) => (0, import_agent_qa_ids5.isCanonicalObservationId)(value), {
57
+ CanonicalObservationIdSchema = import_zod19.z.string().refine((value) => (0, import_agent_qa_ids5.isCanonicalObservationId)(value), {
58
58
  message: "Observation ID must be obs_ followed by 10 id-agent words"
59
59
  });
60
- ObservationSuiteSnapshotEntrySchema = import_zod18.z.object({
61
- test: import_zod18.z.string(),
62
- id: import_zod18.z.string()
60
+ ObservationSuiteSnapshotEntrySchema = import_zod19.z.object({
61
+ test: import_zod19.z.string(),
62
+ id: import_zod19.z.string()
63
63
  }).strict();
64
- BaseObservationSchema = import_zod18.z.object({
64
+ BaseObservationSchema = import_zod19.z.object({
65
65
  id: ObservationIdSchema,
66
- title: import_zod18.z.string().min(1),
67
- content: import_zod18.z.string().min(1),
68
- trust: import_zod18.z.number().min(0).max(1),
69
- created: import_zod18.z.string().datetime(),
70
- last_confirmed: import_zod18.z.string().datetime(),
71
- confirmed_count: import_zod18.z.number().int().min(0),
72
- contradicted_count: import_zod18.z.number().int().min(0),
73
- source_test: import_zod18.z.string().min(1)
66
+ title: import_zod19.z.string().min(1),
67
+ content: import_zod19.z.string().min(1),
68
+ trust: import_zod19.z.number().min(0).max(1),
69
+ created: import_zod19.z.string().datetime(),
70
+ last_confirmed: import_zod19.z.string().datetime(),
71
+ confirmed_count: import_zod19.z.number().int().min(0),
72
+ contradicted_count: import_zod19.z.number().int().min(0),
73
+ source_test: import_zod19.z.string().min(1)
74
74
  }).strip();
75
75
  SuiteObservationSchema = BaseObservationSchema.extend({
76
- position: import_zod18.z.number().int().min(0),
77
- suite_snapshot: import_zod18.z.array(ObservationSuiteSnapshotEntrySchema).min(1)
76
+ position: import_zod19.z.number().int().min(0),
77
+ suite_snapshot: import_zod19.z.array(ObservationSuiteSnapshotEntrySchema).min(1)
78
78
  }).strip();
79
79
  BaseObservationWriteSchema = BaseObservationSchema.extend({
80
80
  id: CanonicalObservationIdSchema
81
81
  }).strip();
82
82
  SuiteObservationWriteSchema = BaseObservationWriteSchema.extend({
83
- position: import_zod18.z.number().int().min(0),
84
- suite_snapshot: import_zod18.z.array(ObservationSuiteSnapshotEntrySchema).min(1)
83
+ position: import_zod19.z.number().int().min(0),
84
+ suite_snapshot: import_zod19.z.array(ObservationSuiteSnapshotEntrySchema).min(1)
85
85
  }).strip();
86
86
  }
87
87
  });
@@ -93,26 +93,26 @@ function toObservationFrontmatter(data) {
93
93
  }
94
94
  async function ensureMemoryDirs(root) {
95
95
  await Promise.all(
96
- MEMORY_TIERS.map((tier) => (0, import_promises8.mkdir)((0, import_node_path12.join)(root, tier), { recursive: true }))
96
+ MEMORY_TIERS.map((tier) => (0, import_promises10.mkdir)((0, import_node_path14.join)(root, tier), { recursive: true }))
97
97
  );
98
98
  }
99
99
  async function writeObservation(root, tier, scope, data) {
100
- const dir = (0, import_node_path12.join)(root, tier, scope);
101
- const resolved = (0, import_node_path12.resolve)(dir);
102
- const boundary = (0, import_node_path12.resolve)(root);
103
- if (!resolved.startsWith(boundary + import_node_path12.sep)) {
100
+ const dir = (0, import_node_path14.join)(root, tier, scope);
101
+ const resolved = (0, import_node_path14.resolve)(dir);
102
+ const boundary = (0, import_node_path14.resolve)(root);
103
+ if (!resolved.startsWith(boundary + import_node_path14.sep)) {
104
104
  throw new Error(`Scope "${scope}" escapes memory root`);
105
105
  }
106
106
  const schema = "position" in data ? SuiteObservationWriteSchema : BaseObservationWriteSchema;
107
107
  const validated = schema.parse(data);
108
108
  const frontmatter = toObservationFrontmatter(validated);
109
- await (0, import_promises8.mkdir)(dir, { recursive: true });
109
+ await (0, import_promises10.mkdir)(dir, { recursive: true });
110
110
  const content = `---
111
111
  ${(0, import_yaml3.stringify)({ ...frontmatter }, { lineWidth: 0 })}---
112
112
  ${validated.content}
113
113
  `;
114
- const filePath = (0, import_node_path12.join)(dir, `${data.id}.md`);
115
- await (0, import_promises8.writeFile)(filePath, content, "utf-8");
114
+ const filePath = (0, import_node_path14.join)(dir, `${data.id}.md`);
115
+ await (0, import_promises10.writeFile)(filePath, content, "utf-8");
116
116
  return filePath;
117
117
  }
118
118
  function parseObservation(content, filename) {
@@ -149,7 +149,7 @@ function parseObservation(content, filename) {
149
149
  async function listObservations(dir) {
150
150
  let entries;
151
151
  try {
152
- entries = await (0, import_promises8.readdir)(dir);
152
+ entries = await (0, import_promises10.readdir)(dir);
153
153
  } catch (e) {
154
154
  if (e instanceof Error && "code" in e && e.code === "ENOENT") {
155
155
  return [];
@@ -158,13 +158,13 @@ async function listObservations(dir) {
158
158
  }
159
159
  return entries.filter((f) => f.startsWith("obs_") && f.endsWith(".md")).sort();
160
160
  }
161
- var import_yaml3, import_promises8, import_node_path12, MEMORY_TIERS;
161
+ var import_yaml3, import_promises10, import_node_path14, MEMORY_TIERS;
162
162
  var init_observation_io = __esm({
163
163
  "src/memory/observation-io.ts"() {
164
164
  "use strict";
165
165
  import_yaml3 = require("yaml");
166
- import_promises8 = require("fs/promises");
167
- import_node_path12 = require("path");
166
+ import_promises10 = require("fs/promises");
167
+ import_node_path14 = require("path");
168
168
  init_schema();
169
169
  MEMORY_TIERS = ["products", "suites", "tests"];
170
170
  }
@@ -238,13 +238,13 @@ function isBetterSqlite3NodeGypSymlinkConflict(error) {
238
238
  return message.includes("node_gyp_bins/python3") && message.includes("EEXIST");
239
239
  }
240
240
  function resolveCurrentRuntimeNpmCliPath() {
241
- const nodeInstallRoot = (0, import_node_path19.dirname)((0, import_node_path19.dirname)(process.execPath));
242
- const npmCliPath = (0, import_node_path19.join)(nodeInstallRoot, "lib", "node_modules", "npm", "bin", "npm-cli.js");
241
+ const nodeInstallRoot = (0, import_node_path21.dirname)((0, import_node_path21.dirname)(process.execPath));
242
+ const npmCliPath = (0, import_node_path21.join)(nodeInstallRoot, "lib", "node_modules", "npm", "bin", "npm-cli.js");
243
243
  return (0, import_node_fs7.existsSync)(npmCliPath) ? npmCliPath : null;
244
244
  }
245
245
  function resolveCurrentRuntimeNodeDir() {
246
- const nodeInstallRoot = (0, import_node_path19.dirname)((0, import_node_path19.dirname)(process.execPath));
247
- const nodeHeaderPath = (0, import_node_path19.join)(nodeInstallRoot, "include", "node", "node.h");
246
+ const nodeInstallRoot = (0, import_node_path21.dirname)((0, import_node_path21.dirname)(process.execPath));
247
+ const nodeHeaderPath = (0, import_node_path21.join)(nodeInstallRoot, "include", "node", "node.h");
248
248
  return (0, import_node_fs7.existsSync)(nodeHeaderPath) ? nodeInstallRoot : null;
249
249
  }
250
250
  function resolveBetterSqliteRebuildCommand() {
@@ -266,7 +266,7 @@ function sleepSync(milliseconds) {
266
266
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
267
267
  }
268
268
  function waitForBetterSqlite3BuildOutput(installRoot, timeoutMs = 3e4) {
269
- const bindingPath = (0, import_node_path19.join)(installRoot, "build", "Release", "better_sqlite3.node");
269
+ const bindingPath = (0, import_node_path21.join)(installRoot, "build", "Release", "better_sqlite3.node");
270
270
  const deadline = Date.now() + timeoutMs;
271
271
  while (Date.now() < deadline) {
272
272
  if ((0, import_node_fs7.existsSync)(bindingPath)) {
@@ -277,15 +277,15 @@ function waitForBetterSqlite3BuildOutput(installRoot, timeoutMs = 3e4) {
277
277
  return (0, import_node_fs7.existsSync)(bindingPath);
278
278
  }
279
279
  function acquireBetterSqlite3RebuildLock(installRoot) {
280
- const lockRoot = (0, import_node_path19.join)((0, import_node_os3.tmpdir)(), "agent-qa-better-sqlite3-rebuild-locks");
281
- const lockKey = (0, import_node_crypto6.createHash)("sha256").update(`${installRoot}\0${process.version}`).digest("hex");
282
- const lockDir = (0, import_node_path19.join)(lockRoot, lockKey);
280
+ const lockRoot = (0, import_node_path21.join)((0, import_node_os3.tmpdir)(), "agent-qa-better-sqlite3-rebuild-locks");
281
+ const lockKey = (0, import_node_crypto7.createHash)("sha256").update(`${installRoot}\0${process.version}`).digest("hex");
282
+ const lockDir = (0, import_node_path21.join)(lockRoot, lockKey);
283
283
  const deadline = Date.now() + 12e4;
284
284
  (0, import_node_fs7.mkdirSync)(lockRoot, { recursive: true });
285
285
  while (true) {
286
286
  try {
287
287
  (0, import_node_fs7.mkdirSync)(lockDir);
288
- (0, import_node_fs7.writeFileSync)((0, import_node_path19.join)(lockDir, "owner"), `${process.pid}
288
+ (0, import_node_fs7.writeFileSync)((0, import_node_path21.join)(lockDir, "owner"), `${process.pid}
289
289
  ${(/* @__PURE__ */ new Date()).toISOString()}
290
290
  ${installRoot}
291
291
  `);
@@ -314,13 +314,13 @@ function rebuildBetterSqlite3ForCurrentRuntime(originalError) {
314
314
  }
315
315
  rebuildAttempted = true;
316
316
  const packageJsonPath = require2.resolve("better-sqlite3/package.json");
317
- const installRoot = (0, import_node_path19.dirname)(packageJsonPath);
317
+ const installRoot = (0, import_node_path21.dirname)(packageJsonPath);
318
318
  const rebuildCommand = resolveBetterSqliteRebuildCommand();
319
- const nodeGypDevDir = (0, import_node_path19.join)((0, import_node_os3.tmpdir)(), "agent-qa-node-gyp", process.version.replace(/^v/, ""));
320
- const npmCacheDir = (0, import_node_path19.join)((0, import_node_os3.tmpdir)(), "agent-qa-npm-cache");
319
+ const nodeGypDevDir = (0, import_node_path21.join)((0, import_node_os3.tmpdir)(), "agent-qa-node-gyp", process.version.replace(/^v/, ""));
320
+ const npmCacheDir = (0, import_node_path21.join)((0, import_node_os3.tmpdir)(), "agent-qa-npm-cache");
321
321
  const nodeDir = resolveCurrentRuntimeNodeDir();
322
- const nodeGypBinsPath = (0, import_node_path19.join)(installRoot, "build", "node_gyp_bins");
323
- const buildRoot = (0, import_node_path19.join)(installRoot, "build");
322
+ const nodeGypBinsPath = (0, import_node_path21.join)(installRoot, "build", "node_gyp_bins");
323
+ const buildRoot = (0, import_node_path21.join)(installRoot, "build");
324
324
  const releaseLock = acquireBetterSqlite3RebuildLock(installRoot);
325
325
  try {
326
326
  clearBetterSqlite3Cache();
@@ -375,31 +375,31 @@ function loadBetterSqlite3() {
375
375
  sqliteConstructor = require2("better-sqlite3");
376
376
  return sqliteConstructor;
377
377
  }
378
- function openBetterSqlite3Database(path5) {
378
+ function openBetterSqlite3Database(path7) {
379
379
  const Database = loadBetterSqlite3();
380
- return new Database(path5);
380
+ return new Database(path7);
381
381
  }
382
- function createBetterSqlite3Database(path5) {
382
+ function createBetterSqlite3Database(path7) {
383
383
  try {
384
- return openBetterSqlite3Database(path5);
384
+ return openBetterSqlite3Database(path7);
385
385
  } catch (error) {
386
386
  if (!isBetterSqlite3NativeModuleError(error)) {
387
387
  throw error;
388
388
  }
389
389
  rebuildBetterSqlite3ForCurrentRuntime(error);
390
- return openBetterSqlite3Database(path5);
390
+ return openBetterSqlite3Database(path7);
391
391
  }
392
392
  }
393
- var import_node_child_process2, import_node_fs7, import_node_crypto6, import_node_module3, import_node_os3, import_node_path19, import_meta3, require2, sqliteConstructor, rebuildAttempted, rebuildFailureMessage;
393
+ var import_node_child_process2, import_node_fs7, import_node_crypto7, import_node_module3, import_node_os3, import_node_path21, import_meta3, require2, sqliteConstructor, rebuildAttempted, rebuildFailureMessage;
394
394
  var init_sqlite = __esm({
395
395
  "src/sqlite.ts"() {
396
396
  "use strict";
397
397
  import_node_child_process2 = require("child_process");
398
398
  import_node_fs7 = require("fs");
399
- import_node_crypto6 = require("crypto");
399
+ import_node_crypto7 = require("crypto");
400
400
  import_node_module3 = require("module");
401
401
  import_node_os3 = require("os");
402
- import_node_path19 = require("path");
402
+ import_node_path21 = require("path");
403
403
  import_meta3 = {};
404
404
  require2 = (0, import_node_module3.createRequire)(import_meta3.url);
405
405
  sqliteConstructor = null;
@@ -430,13 +430,13 @@ async function buildMemoryIndex(params) {
430
430
  const insert = db.prepare("INSERT INTO observations(title, content, id, trust) VALUES (?, ?, ?, ?)");
431
431
  const dirs = [];
432
432
  if (validatePathComponent(params.product)) {
433
- dirs.push({ path: (0, import_node_path20.join)(params.memoryRoot, "products", params.product), isSuite: false });
433
+ dirs.push({ path: (0, import_node_path22.join)(params.memoryRoot, "products", params.product), isSuite: false });
434
434
  }
435
435
  if (params.suiteId && validatePathComponent(params.suiteId)) {
436
- dirs.push({ path: (0, import_node_path20.join)(params.memoryRoot, "suites", params.suiteId), isSuite: true });
436
+ dirs.push({ path: (0, import_node_path22.join)(params.memoryRoot, "suites", params.suiteId), isSuite: true });
437
437
  }
438
438
  if (validatePathComponent(params.testId)) {
439
- dirs.push({ path: (0, import_node_path20.join)(params.memoryRoot, "tests", params.testId), isSuite: false });
439
+ dirs.push({ path: (0, import_node_path22.join)(params.memoryRoot, "tests", params.testId), isSuite: false });
440
440
  }
441
441
  if (dirs.length === 0) {
442
442
  console.warn("[memory-index] All path components failed validation", {
@@ -455,10 +455,10 @@ async function buildMemoryIndex(params) {
455
455
  for (const { path: dirPath, isSuite } of dirs) {
456
456
  const filenames = await listObservations(dirPath);
457
457
  for (const filename of filenames) {
458
- const filePath = (0, import_node_path20.join)(dirPath, filename);
458
+ const filePath = (0, import_node_path22.join)(dirPath, filename);
459
459
  let raw;
460
460
  try {
461
- raw = await (0, import_promises14.readFile)(filePath, "utf-8");
461
+ raw = await (0, import_promises16.readFile)(filePath, "utf-8");
462
462
  } catch {
463
463
  continue;
464
464
  }
@@ -485,12 +485,12 @@ async function buildMemoryIndex(params) {
485
485
  return null;
486
486
  }
487
487
  }
488
- var import_promises14, import_node_path20;
488
+ var import_promises16, import_node_path22;
489
489
  var init_memory_index = __esm({
490
490
  "src/memory/memory-index.ts"() {
491
491
  "use strict";
492
- import_promises14 = require("fs/promises");
493
- import_node_path20 = require("path");
492
+ import_promises16 = require("fs/promises");
493
+ import_node_path22 = require("path");
494
494
  init_observation_io();
495
495
  init_security_scanner();
496
496
  init_sqlite();
@@ -508,12 +508,12 @@ var init_xml_escape = __esm({
508
508
  });
509
509
 
510
510
  // src/memory/lock-manager.ts
511
- var import_promises15, import_node_path21, LockManager;
511
+ var import_promises17, import_node_path23, LockManager;
512
512
  var init_lock_manager = __esm({
513
513
  "src/memory/lock-manager.ts"() {
514
514
  "use strict";
515
- import_promises15 = require("fs/promises");
516
- import_node_path21 = require("path");
515
+ import_promises17 = require("fs/promises");
516
+ import_node_path23 = require("path");
517
517
  LockManager = class {
518
518
  lockPath;
519
519
  timeout;
@@ -522,17 +522,17 @@ var init_lock_manager = __esm({
522
522
  this.timeout = timeout;
523
523
  }
524
524
  async acquire() {
525
- await (0, import_promises15.mkdir)((0, import_node_path21.dirname)(this.lockPath), { recursive: true });
525
+ await (0, import_promises17.mkdir)((0, import_node_path23.dirname)(this.lockPath), { recursive: true });
526
526
  const deadline = Date.now() + this.timeout;
527
527
  while (Date.now() < deadline) {
528
528
  try {
529
- await (0, import_promises15.writeFile)(
529
+ await (0, import_promises17.writeFile)(
530
530
  this.lockPath,
531
531
  JSON.stringify({ pid: process.pid, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
532
532
  { flag: "wx" }
533
533
  );
534
534
  try {
535
- const raw = await (0, import_promises15.readFile)(this.lockPath, "utf-8");
535
+ const raw = await (0, import_promises17.readFile)(this.lockPath, "utf-8");
536
536
  const { pid } = JSON.parse(raw);
537
537
  if (pid === process.pid) return;
538
538
  } catch {
@@ -541,7 +541,7 @@ var init_lock_manager = __esm({
541
541
  } catch (err) {
542
542
  if (err instanceof Error && "code" in err && err.code === "EEXIST") {
543
543
  if (await this.isStale()) {
544
- await (0, import_promises15.unlink)(this.lockPath).catch(() => {
544
+ await (0, import_promises17.unlink)(this.lockPath).catch(() => {
545
545
  });
546
546
  continue;
547
547
  }
@@ -556,7 +556,7 @@ var init_lock_manager = __esm({
556
556
  async release() {
557
557
  let raw;
558
558
  try {
559
- raw = await (0, import_promises15.readFile)(this.lockPath, "utf-8");
559
+ raw = await (0, import_promises17.readFile)(this.lockPath, "utf-8");
560
560
  } catch (err) {
561
561
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
562
562
  return;
@@ -567,19 +567,19 @@ var init_lock_manager = __esm({
567
567
  try {
568
568
  ({ pid } = JSON.parse(raw));
569
569
  } catch {
570
- await (0, import_promises15.unlink)(this.lockPath).catch(() => {
570
+ await (0, import_promises17.unlink)(this.lockPath).catch(() => {
571
571
  });
572
572
  return;
573
573
  }
574
574
  if (pid === process.pid) {
575
- await (0, import_promises15.unlink)(this.lockPath).catch(() => {
575
+ await (0, import_promises17.unlink)(this.lockPath).catch(() => {
576
576
  });
577
577
  }
578
578
  }
579
579
  async isStale() {
580
580
  let raw;
581
581
  try {
582
- raw = await (0, import_promises15.readFile)(this.lockPath, "utf-8");
582
+ raw = await (0, import_promises17.readFile)(this.lockPath, "utf-8");
583
583
  } catch (err) {
584
584
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
585
585
  return true;
@@ -654,13 +654,13 @@ var local_provider_exports = {};
654
654
  __export(local_provider_exports, {
655
655
  LocalMemoryProvider: () => LocalMemoryProvider
656
656
  });
657
- var import_node_path22, import_node_fs8, import_promises16, LocalMemoryProvider;
657
+ var import_node_path24, import_node_fs8, import_promises18, LocalMemoryProvider;
658
658
  var init_local_provider = __esm({
659
659
  "src/memory/local-provider.ts"() {
660
660
  "use strict";
661
- import_node_path22 = require("path");
661
+ import_node_path24 = require("path");
662
662
  import_node_fs8 = require("fs");
663
- import_promises16 = require("fs/promises");
663
+ import_promises18 = require("fs/promises");
664
664
  init_memory_index();
665
665
  init_xml_escape();
666
666
  init_lock_manager();
@@ -681,7 +681,7 @@ var init_local_provider = __esm({
681
681
  this.minTrust = opts?.minTrust ?? 0.3;
682
682
  this.maxInjections = opts?.maxInjections ?? 3;
683
683
  this.lockManager = new LockManager(
684
- (0, import_node_path22.join)(this.memoryRoot, ".curator.lock"),
684
+ (0, import_node_path24.join)(this.memoryRoot, ".curator.lock"),
685
685
  opts?.curatorLockTimeout ?? 12e4
686
686
  );
687
687
  }
@@ -751,13 +751,13 @@ ${lines.join("\n")}
751
751
  return writeObservation(this.memoryRoot, tier, scope, data);
752
752
  }
753
753
  async deleteObservation(tier, scope, id) {
754
- const filePath = (0, import_node_path22.join)(this.memoryRoot, tier, scope, `${id}.md`);
755
- const resolved = (0, import_node_path22.resolve)(filePath);
756
- if (!resolved.startsWith((0, import_node_path22.resolve)(this.memoryRoot) + import_node_path22.sep)) {
754
+ const filePath = (0, import_node_path24.join)(this.memoryRoot, tier, scope, `${id}.md`);
755
+ const resolved = (0, import_node_path24.resolve)(filePath);
756
+ if (!resolved.startsWith((0, import_node_path24.resolve)(this.memoryRoot) + import_node_path24.sep)) {
757
757
  throw new Error("Path escapes memory root");
758
758
  }
759
759
  try {
760
- await (0, import_promises16.unlink)(filePath);
760
+ await (0, import_promises18.unlink)(filePath);
761
761
  } catch (err) {
762
762
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
763
763
  return;
@@ -770,7 +770,7 @@ ${lines.join("\n")}
770
770
  const results = [];
771
771
  const tiers = ["products", "suites", "tests"];
772
772
  for (const tier of tiers) {
773
- const tierDir = (0, import_node_path22.join)(this.memoryRoot, tier);
773
+ const tierDir = (0, import_node_path24.join)(this.memoryRoot, tier);
774
774
  let scopes;
775
775
  try {
776
776
  scopes = (0, import_node_fs8.readdirSync)(tierDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -778,7 +778,7 @@ ${lines.join("\n")}
778
778
  continue;
779
779
  }
780
780
  for (const scope of scopes) {
781
- const scopeDir = (0, import_node_path22.join)(tierDir, scope);
781
+ const scopeDir = (0, import_node_path24.join)(tierDir, scope);
782
782
  let files;
783
783
  try {
784
784
  files = (0, import_node_fs8.readdirSync)(scopeDir).filter((f) => f.startsWith("obs_") && f.endsWith(".md"));
@@ -788,7 +788,7 @@ ${lines.join("\n")}
788
788
  for (const file of files) {
789
789
  let raw;
790
790
  try {
791
- raw = (0, import_node_fs8.readFileSync)((0, import_node_path22.join)(scopeDir, file), "utf-8");
791
+ raw = (0, import_node_fs8.readFileSync)((0, import_node_path24.join)(scopeDir, file), "utf-8");
792
792
  } catch {
793
793
  continue;
794
794
  }
@@ -823,7 +823,7 @@ ${lines.join("\n")}
823
823
  const tiers = ["products", "suites", "tests"];
824
824
  const toInsert = [];
825
825
  for (const tier of tiers) {
826
- const tierDir = (0, import_node_path22.join)(this.memoryRoot, tier);
826
+ const tierDir = (0, import_node_path24.join)(this.memoryRoot, tier);
827
827
  let scopes;
828
828
  try {
829
829
  scopes = (0, import_node_fs8.readdirSync)(tierDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -831,7 +831,7 @@ ${lines.join("\n")}
831
831
  continue;
832
832
  }
833
833
  for (const scope of scopes) {
834
- const scopeDir = (0, import_node_path22.join)(tierDir, scope);
834
+ const scopeDir = (0, import_node_path24.join)(tierDir, scope);
835
835
  let files;
836
836
  try {
837
837
  files = (0, import_node_fs8.readdirSync)(scopeDir).filter((f) => f.startsWith("obs_") && f.endsWith(".md"));
@@ -841,7 +841,7 @@ ${lines.join("\n")}
841
841
  for (const file of files) {
842
842
  let raw;
843
843
  try {
844
- raw = (0, import_node_fs8.readFileSync)((0, import_node_path22.join)(scopeDir, file), "utf-8");
844
+ raw = (0, import_node_fs8.readFileSync)((0, import_node_path24.join)(scopeDir, file), "utf-8");
845
845
  } catch {
846
846
  continue;
847
847
  }
@@ -920,6 +920,14 @@ __export(index_exports, {
920
920
  ANDROID_ROLE_MAP: () => ANDROID_ROLE_MAP,
921
921
  ATTR_RUNNER: () => ATTR_RUNNER,
922
922
  ATTR_TRIGGER: () => ATTR_TRIGGER,
923
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH: () => AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,
924
+ AUTH_STATE_HOOK_JSON_ENV: () => AUTH_STATE_HOOK_JSON_ENV,
925
+ AUTH_STATE_HOOK_STORAGE_STATE_FILENAME: () => AUTH_STATE_HOOK_STORAGE_STATE_FILENAME,
926
+ AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV: () => AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV,
927
+ AUTH_STATE_HOOK_WORKSPACE_DIR: () => AUTH_STATE_HOOK_WORKSPACE_DIR,
928
+ AUTH_STATE_REDACTION_MARKER: () => AUTH_STATE_REDACTION_MARKER,
929
+ AUTH_STATE_SCHEMA_VERSION: () => AUTH_STATE_SCHEMA_VERSION,
930
+ AUTH_STATE_SLUG_PATTERN: () => AUTH_STATE_SLUG_PATTERN,
923
931
  AccessibilityConfigSchema: () => AccessibilityConfigSchema,
924
932
  ActionPlanSchema: () => ActionPlanSchema,
925
933
  AdapterLogDataSchema: () => AdapterLogDataSchema,
@@ -930,6 +938,10 @@ __export(index_exports, {
930
938
  AssertionEvaluator: () => AssertionEvaluator,
931
939
  AssertionResultSchema: () => AssertionResultSchema,
932
940
  AuthPluginDeclarationSchema: () => AuthPluginDeclarationSchema,
941
+ AuthStateConfigSchema: () => AuthStateConfigSchema,
942
+ AuthStateMetadataSchema: () => AuthStateMetadataSchema,
943
+ AuthStateNameSchema: () => AuthStateNameSchema,
944
+ AuthStateUseSchema: () => AuthStateUseSchema,
933
945
  BaseObservationSchema: () => BaseObservationSchema,
934
946
  BrowserConfigSchema: () => BrowserConfigSchema,
935
947
  CACHE_SCHEMA_VERSION: () => CACHE_SCHEMA_VERSION,
@@ -940,6 +952,7 @@ __export(index_exports, {
940
952
  ConsoleReporter: () => ConsoleReporter,
941
953
  CuratorResponseSchema: () => CuratorResponseSchema,
942
954
  DEFAULT_AGENT_QA_ARTIFACTS_DIR: () => DEFAULT_AGENT_QA_ARTIFACTS_DIR,
955
+ DEFAULT_AGENT_QA_AUTH_STATES_DIR: () => DEFAULT_AGENT_QA_AUTH_STATES_DIR,
943
956
  DEFAULT_AGENT_QA_CACHE_DIR: () => DEFAULT_AGENT_QA_CACHE_DIR,
944
957
  DEFAULT_AGENT_QA_RUNS_DB_PATH: () => DEFAULT_AGENT_QA_RUNS_DB_PATH,
945
958
  DEFAULT_AGENT_QA_RUNTIME_DIR: () => DEFAULT_AGENT_QA_RUNTIME_DIR,
@@ -1010,6 +1023,7 @@ __export(index_exports, {
1010
1023
  SuiteDefinitionSchema: () => SuiteDefinitionSchema,
1011
1024
  SuiteObservationSchema: () => SuiteObservationSchema,
1012
1025
  SuiteTestEntrySchema: () => SuiteTestEntrySchema,
1026
+ TargetNameSchema: () => TargetNameSchema,
1013
1027
  TargetSchema: () => TargetSchema,
1014
1028
  TestDefinitionSchema: () => TestDefinitionSchema,
1015
1029
  TestMetaSchema: () => TestMetaSchema,
@@ -1028,6 +1042,7 @@ __export(index_exports, {
1028
1042
  browserstackProvider: () => browserstackProvider,
1029
1043
  buildAnalyticsEvent: () => buildAnalyticsEvent,
1030
1044
  buildAssertionPrompt: () => buildAssertionPrompt,
1045
+ buildAuthStateHookEnv: () => buildAuthStateHookEnv,
1031
1046
  buildExtractionPrompt: () => buildExtractionPrompt,
1032
1047
  buildInternalRunAttributes: () => buildInternalRunAttributes,
1033
1048
  buildMemoryIndex: () => buildMemoryIndex,
@@ -1098,7 +1113,9 @@ __export(index_exports, {
1098
1113
  isBetterSqlite3NodeGypSymlinkConflict: () => isBetterSqlite3NodeGypSymlinkConflict,
1099
1114
  isMacPlatform: () => isMacPlatform,
1100
1115
  isPathInsideDir: () => isPathInsideDir,
1116
+ isReservedAuthStateHookEnvKey: () => isReservedAuthStateHookEnvKey,
1101
1117
  isWorkspacePathMatch: () => isWorkspacePathMatch,
1118
+ listAuthStateMetadata: () => listAuthStateMetadata,
1102
1119
  listLLMAuthProviderPlugins: () => listLLMAuthProviderPlugins,
1103
1120
  listObservations: () => listObservations,
1104
1121
  listProviders: () => listProviders,
@@ -1107,6 +1124,7 @@ __export(index_exports, {
1107
1124
  mapMobileCapabilities: () => mapMobileCapabilities,
1108
1125
  mapWebCapabilities: () => mapWebCapabilities,
1109
1126
  mergeRunAttributes: () => mergeRunAttributes,
1127
+ normalizeAuthStateUse: () => normalizeAuthStateUse,
1110
1128
  normalizeRole: () => normalizeRole,
1111
1129
  parseAllTests: () => parseAllTests,
1112
1130
  parseEnvFile: () => parseEnvFile,
@@ -1120,17 +1138,25 @@ __export(index_exports, {
1120
1138
  parseTestFile: () => parseTestFile,
1121
1139
  readAnalyticsIdentity: () => readAnalyticsIdentity,
1122
1140
  readAuth: () => readAuth,
1141
+ readAuthStateMetadata: () => readAuthStateMetadata,
1142
+ redactAuthStateString: () => redactAuthStateString,
1143
+ redactAuthStateValue: () => redactAuthStateValue,
1123
1144
  redactSecretValue: () => redactSecretValue,
1124
1145
  registerAllProviders: () => registerAllProviders,
1125
1146
  registerLLMAuthProviderPlugin: () => registerLLMAuthProviderPlugin,
1126
1147
  registerLLMAuthProviderPlugins: () => registerLLMAuthProviderPlugins,
1127
1148
  registerProvider: () => registerProvider,
1128
1149
  removeAuth: () => removeAuth,
1150
+ removeAuthStateFiles: () => removeAuthStateFiles,
1151
+ removeAuthStateTarget: () => removeAuthStateTarget,
1129
1152
  resetAnalyticsServiceForTests: () => resetAnalyticsServiceForTests,
1130
1153
  resolveAnalyticsAgentProduct: () => resolveAnalyticsAgentProduct,
1131
1154
  resolveAnalyticsIdentity: () => resolveAnalyticsIdentity,
1132
1155
  resolveAnalyticsStandardProperties: () => resolveAnalyticsStandardProperties,
1133
1156
  resolveAppiumExecutable: () => resolveAppiumExecutable,
1157
+ resolveAuthStateForRun: () => resolveAuthStateForRun,
1158
+ resolveAuthStatePaths: () => resolveAuthStatePaths,
1159
+ resolveAuthStateRoot: () => resolveAuthStateRoot,
1134
1160
  resolveBetterSqliteRebuildCommand: () => resolveBetterSqliteRebuildCommand,
1135
1161
  resolveFarmCredentials: () => resolveFarmCredentials,
1136
1162
  resolveFileReferences: () => resolveFileReferences,
@@ -1151,6 +1177,7 @@ __export(index_exports, {
1151
1177
  shouldAblate: () => shouldAblate,
1152
1178
  sortRunAttributesForDisplay: () => sortRunAttributesForDisplay,
1153
1179
  stripHookInline: () => stripHookInline,
1180
+ stripReservedAuthStateHookEnv: () => stripReservedAuthStateHookEnv,
1154
1181
  toolCallToActionPlan: () => toolCallToActionPlan,
1155
1182
  toolSchemaMiddleware: () => toolSchemaMiddleware,
1156
1183
  truncateScreenState: () => truncateScreenState,
@@ -1165,12 +1192,13 @@ __export(index_exports, {
1165
1192
  warnIfOutOfBounds: () => warnIfOutOfBounds,
1166
1193
  writeAnalyticsIdentity: () => writeAnalyticsIdentity,
1167
1194
  writeAuth: () => writeAuth,
1195
+ writeAuthStateFiles: () => writeAuthStateFiles,
1168
1196
  writeObservation: () => writeObservation
1169
1197
  });
1170
1198
  module.exports = __toCommonJS(index_exports);
1171
1199
 
1172
1200
  // src/schema/config-schema.ts
1173
- var import_zod7 = require("zod");
1201
+ var import_zod8 = require("zod");
1174
1202
 
1175
1203
  // src/schema/workspace-schema.ts
1176
1204
  var import_zod = require("zod");
@@ -1340,6 +1368,9 @@ var CacheConfigSchema = import_zod3.z.object({
1340
1368
  dir: import_zod3.z.string(),
1341
1369
  ttl: DurationString
1342
1370
  }).strict();
1371
+ var AuthStateConfigSchema = import_zod3.z.object({
1372
+ dir: import_zod3.z.string().trim().min(1)
1373
+ }).strict();
1343
1374
  var LoggingConfigSchema = import_zod3.z.object({
1344
1375
  level: import_zod3.z.enum(["silent", "error", "warn", "info", "debug"])
1345
1376
  }).strict();
@@ -1374,6 +1405,7 @@ var ServicesSchema = import_zod3.z.object({
1374
1405
  dashboard: DashboardConfigSchema.optional(),
1375
1406
  mcp: McpConfigSchema.optional(),
1376
1407
  cache: CacheConfigSchema.optional(),
1408
+ authState: AuthStateConfigSchema.optional(),
1377
1409
  logging: LoggingConfigSchema.optional(),
1378
1410
  recording: RecordingConfigSchema.optional(),
1379
1411
  accessibility: AccessibilityConfigSchema.optional(),
@@ -1381,34 +1413,56 @@ var ServicesSchema = import_zod3.z.object({
1381
1413
  }).strict();
1382
1414
 
1383
1415
  // src/schema/registry-schema.ts
1416
+ var import_zod5 = require("zod");
1417
+
1418
+ // src/auth-state/schema.ts
1384
1419
  var import_zod4 = require("zod");
1420
+ var AUTH_STATE_SCHEMA_VERSION = 1;
1421
+ var AUTH_STATE_SLUG_PATTERN = /^[a-z][a-z0-9-]*[a-z0-9]$/;
1422
+ var AuthStateNameSchema = import_zod4.z.string().regex(
1423
+ AUTH_STATE_SLUG_PATTERN,
1424
+ "Auth state name must match ^[a-z][a-z0-9-]*[a-z0-9]$"
1425
+ );
1426
+ var TargetNameSchema = import_zod4.z.string().regex(
1427
+ AUTH_STATE_SLUG_PATTERN,
1428
+ "Target name must match ^[a-z][a-z0-9-]*[a-z0-9]$"
1429
+ );
1430
+ var AuthStateMetadataSchema = import_zod4.z.object({
1431
+ version: import_zod4.z.literal(AUTH_STATE_SCHEMA_VERSION),
1432
+ kind: import_zod4.z.literal("web"),
1433
+ target: TargetNameSchema,
1434
+ name: AuthStateNameSchema,
1435
+ capturedAt: import_zod4.z.string().datetime()
1436
+ }).strict();
1437
+
1438
+ // src/schema/registry-schema.ts
1385
1439
  function isAbsoluteAppPath(value) {
1386
1440
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
1387
1441
  }
1388
- var AppInstallSchema = import_zod4.z.object({
1389
- path: import_zod4.z.string().refine((v) => !isAbsoluteAppPath(v), { message: "app.path must be relative" }).optional(),
1390
- browserstack: import_zod4.z.string().optional()
1442
+ var AppInstallSchema = import_zod5.z.object({
1443
+ path: import_zod5.z.string().refine((v) => !isAbsoluteAppPath(v), { message: "app.path must be relative" }).optional(),
1444
+ browserstack: import_zod5.z.string().optional()
1391
1445
  }).strict();
1392
- var TargetSchema = import_zod4.z.object({
1393
- product: import_zod4.z.string().refine(
1446
+ var TargetSchema = import_zod5.z.object({
1447
+ product: import_zod5.z.string().refine(
1394
1448
  (v) => !/\.\./.test(v) && !/[/\\]/.test(v) && !/\0/.test(v),
1395
1449
  { message: 'product must not contain "..", "/", "\\", or null bytes' }
1396
1450
  ).optional(),
1397
- platform: import_zod4.z.enum(["web", "android", "ios"]),
1398
- bundleId: import_zod4.z.string().optional(),
1399
- appPackage: import_zod4.z.string().optional(),
1400
- appActivity: import_zod4.z.string().optional(),
1451
+ platform: import_zod5.z.enum(["web", "android", "ios"]),
1452
+ bundleId: import_zod5.z.string().optional(),
1453
+ appPackage: import_zod5.z.string().optional(),
1454
+ appActivity: import_zod5.z.string().optional(),
1401
1455
  app: AppInstallSchema.optional(),
1402
- url: import_zod4.z.string().optional()
1456
+ url: import_zod5.z.string().optional()
1403
1457
  }).strict().superRefine((val, ctx) => {
1404
1458
  if (val.platform === "web" && !val.url) {
1405
- ctx.addIssue({ code: import_zod4.z.ZodIssueCode.custom, message: "Web targets must have a url" });
1459
+ ctx.addIssue({ code: import_zod5.z.ZodIssueCode.custom, message: "Web targets must have a url" });
1406
1460
  }
1407
1461
  });
1408
- var DeviceProfileSchema = import_zod4.z.object({
1409
- platform: import_zod4.z.enum(["android", "ios"]),
1462
+ var DeviceProfileSchema = import_zod5.z.object({
1463
+ platform: import_zod5.z.enum(["android", "ios"]),
1410
1464
  transport: TransportSchema,
1411
- match: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional().default({})
1465
+ match: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.unknown()).optional().default({})
1412
1466
  }).strict().superRefine((val, ctx) => {
1413
1467
  if (val.transport === "local") {
1414
1468
  const androidOnly = ["avd", "serial", "appPackage", "appActivity", "automationName", "browserName", "platformVersion"];
@@ -1417,7 +1471,7 @@ var DeviceProfileSchema = import_zod4.z.object({
1417
1471
  for (const key of Object.keys(val.match)) {
1418
1472
  if (!allowed.includes(key)) {
1419
1473
  ctx.addIssue({
1420
- code: import_zod4.z.ZodIssueCode.custom,
1474
+ code: import_zod5.z.ZodIssueCode.custom,
1421
1475
  path: ["match", key],
1422
1476
  message: `Match field "${key}" is not valid for ${val.platform} local transport. Allowed: ${allowed.join(", ")}`
1423
1477
  });
@@ -1425,94 +1479,119 @@ var DeviceProfileSchema = import_zod4.z.object({
1425
1479
  }
1426
1480
  }
1427
1481
  });
1428
- var ProviderConfigSchema = import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown());
1429
- var RegistrySchema = import_zod4.z.object({
1430
- llms: import_zod4.z.array(NamedLLMConfigSchema).optional().default([]),
1431
- targets: import_zod4.z.record(import_zod4.z.string(), TargetSchema).optional(),
1432
- devices: import_zod4.z.record(import_zod4.z.string(), DeviceProfileSchema).optional(),
1433
- providers: import_zod4.z.record(import_zod4.z.string(), ProviderConfigSchema).optional()
1482
+ var ProviderConfigSchema = import_zod5.z.record(import_zod5.z.string(), import_zod5.z.unknown());
1483
+ var RegistrySchema = import_zod5.z.object({
1484
+ llms: import_zod5.z.array(NamedLLMConfigSchema).optional().default([]),
1485
+ targets: import_zod5.z.record(TargetNameSchema, TargetSchema).optional(),
1486
+ devices: import_zod5.z.record(import_zod5.z.string(), DeviceProfileSchema).optional(),
1487
+ providers: import_zod5.z.record(import_zod5.z.string(), ProviderConfigSchema).optional()
1434
1488
  }).strict();
1435
1489
 
1436
1490
  // src/schema/use-schema.ts
1437
- var import_zod5 = require("zod");
1438
- var MobileAppStateSchema = import_zod5.z.enum(["preserve", "reset"]);
1439
- var MobileUseSchema = import_zod5.z.object({
1491
+ var import_zod6 = require("zod");
1492
+ var MobileAppStateSchema = import_zod6.z.enum(["preserve", "reset"]);
1493
+ var MobileUseSchema = import_zod6.z.object({
1440
1494
  appState: MobileAppStateSchema
1441
1495
  }).strict();
1442
- var MobileUseOverrideSchema = import_zod5.z.object({
1496
+ var MobileUseOverrideSchema = import_zod6.z.object({
1443
1497
  appState: MobileAppStateSchema.optional()
1444
1498
  }).strict();
1445
- var UseSchema = import_zod5.z.object({
1499
+ var AuthStateUseSchema = import_zod6.z.union([
1500
+ AuthStateNameSchema,
1501
+ import_zod6.z.object({
1502
+ name: AuthStateNameSchema,
1503
+ load: import_zod6.z.boolean().optional(),
1504
+ capture: import_zod6.z.boolean().optional()
1505
+ }).strict()
1506
+ ]);
1507
+ function normalizeAuthStateUse(use) {
1508
+ const parsed = AuthStateUseSchema.safeParse(use?.authState);
1509
+ if (!parsed.success) return void 0;
1510
+ if (typeof parsed.data === "string") {
1511
+ return {
1512
+ name: parsed.data,
1513
+ load: true,
1514
+ capture: false
1515
+ };
1516
+ }
1517
+ return {
1518
+ name: parsed.data.name,
1519
+ load: parsed.data.load ?? true,
1520
+ capture: parsed.data.capture ?? false
1521
+ };
1522
+ }
1523
+ var UseSchema = import_zod6.z.object({
1446
1524
  browser: BrowserConfigSchema.optional(),
1447
1525
  mobile: MobileUseSchema.optional(),
1448
1526
  timeout: TimeoutConfigSchema.optional(),
1449
1527
  healing: HealingConfigSchema.optional(),
1450
1528
  planner: PlannerConfigSchema.optional(),
1451
1529
  logCapture: LogCaptureConfigSchema.optional(),
1452
- cache: import_zod5.z.boolean().optional(),
1453
- llm: import_zod5.z.string().optional(),
1454
- parallel: import_zod5.z.boolean().optional()
1530
+ cache: import_zod6.z.boolean().optional(),
1531
+ llm: import_zod6.z.string().optional(),
1532
+ parallel: import_zod6.z.boolean().optional()
1455
1533
  }).strict();
1456
- var UseOverrideSchema = import_zod5.z.object({
1457
- browser: import_zod5.z.object({
1458
- name: import_zod5.z.enum(["chromium", "firefox", "webkit"]).optional(),
1459
- headless: import_zod5.z.boolean().optional(),
1460
- viewport: import_zod5.z.object({
1461
- width: import_zod5.z.number().optional(),
1462
- height: import_zod5.z.number().optional()
1534
+ var UseOverrideSchema = import_zod6.z.object({
1535
+ browser: import_zod6.z.object({
1536
+ name: import_zod6.z.enum(["chromium", "firefox", "webkit"]).optional(),
1537
+ headless: import_zod6.z.boolean().optional(),
1538
+ viewport: import_zod6.z.object({
1539
+ width: import_zod6.z.number().optional(),
1540
+ height: import_zod6.z.number().optional()
1463
1541
  }).strict().optional()
1464
1542
  }).strict().optional(),
1465
- timeout: import_zod5.z.object({
1543
+ timeout: import_zod6.z.object({
1466
1544
  step: DurationString.optional(),
1467
1545
  test: DurationString.optional(),
1468
1546
  navigation: DurationString.optional()
1469
1547
  }).strict().optional(),
1470
- healing: import_zod5.z.object({
1471
- maxAttempts: import_zod5.z.number().optional()
1548
+ healing: import_zod6.z.object({
1549
+ maxAttempts: import_zod6.z.number().optional()
1472
1550
  }).strict().optional(),
1473
- planner: import_zod5.z.object({
1474
- maxSubActions: import_zod5.z.number().optional(),
1475
- previousStepCount: import_zod5.z.number().optional()
1551
+ planner: import_zod6.z.object({
1552
+ maxSubActions: import_zod6.z.number().optional(),
1553
+ previousStepCount: import_zod6.z.number().optional()
1476
1554
  }).strict().optional(),
1477
- logCapture: import_zod5.z.object({
1478
- console: import_zod5.z.boolean().optional(),
1479
- network: import_zod5.z.boolean().optional()
1555
+ logCapture: import_zod6.z.object({
1556
+ console: import_zod6.z.boolean().optional(),
1557
+ network: import_zod6.z.boolean().optional()
1480
1558
  }).strict().optional(),
1481
- cache: import_zod5.z.boolean().optional(),
1559
+ cache: import_zod6.z.boolean().optional(),
1560
+ authState: AuthStateUseSchema.optional(),
1482
1561
  mobile: MobileUseOverrideSchema.optional(),
1483
- llm: import_zod5.z.string().optional(),
1484
- parallel: import_zod5.z.boolean().optional(),
1485
- device: import_zod5.z.string().optional()
1562
+ llm: import_zod6.z.string().optional(),
1563
+ parallel: import_zod6.z.boolean().optional(),
1564
+ device: import_zod6.z.string().optional()
1486
1565
  }).strict();
1487
1566
 
1488
1567
  // src/schema/analytics-schema.ts
1489
- var import_zod6 = require("zod");
1490
- var AttributePredicateSchema = import_zod6.z.union([
1491
- import_zod6.z.string(),
1492
- import_zod6.z.object({
1493
- regex: import_zod6.z.string().min(1)
1568
+ var import_zod7 = require("zod");
1569
+ var AttributePredicateSchema = import_zod7.z.union([
1570
+ import_zod7.z.string(),
1571
+ import_zod7.z.object({
1572
+ regex: import_zod7.z.string().min(1)
1494
1573
  }).strict()
1495
1574
  ]);
1496
- var AnalyticsSchema = import_zod6.z.object({
1497
- privacy: import_zod6.z.literal(true).optional(),
1498
- passRateScope: import_zod6.z.object({
1499
- attributes: import_zod6.z.record(import_zod6.z.string(), AttributePredicateSchema).optional()
1575
+ var AnalyticsSchema = import_zod7.z.object({
1576
+ privacy: import_zod7.z.literal(true).optional(),
1577
+ passRateScope: import_zod7.z.object({
1578
+ attributes: import_zod7.z.record(import_zod7.z.string(), AttributePredicateSchema).optional()
1500
1579
  }).strict().optional()
1501
1580
  }).strict();
1502
1581
 
1503
1582
  // src/schema/config-schema.ts
1504
- var AuthPluginDeclarationSchema = import_zod7.z.union([
1505
- import_zod7.z.object({
1506
- package: import_zod7.z.string().trim().min(1)
1583
+ var AuthPluginDeclarationSchema = import_zod8.z.union([
1584
+ import_zod8.z.object({
1585
+ package: import_zod8.z.string().trim().min(1)
1507
1586
  }).strict(),
1508
- import_zod7.z.object({
1509
- path: import_zod7.z.string().trim().min(1)
1587
+ import_zod8.z.object({
1588
+ path: import_zod8.z.string().trim().min(1)
1510
1589
  }).strict()
1511
1590
  ]);
1512
- var PluginsSchema = import_zod7.z.object({
1513
- auth: import_zod7.z.array(AuthPluginDeclarationSchema).optional().default([])
1591
+ var PluginsSchema = import_zod8.z.object({
1592
+ auth: import_zod8.z.array(AuthPluginDeclarationSchema).optional().default([])
1514
1593
  }).strict();
1515
- var AgentQaConfigSchema = import_zod7.z.object({
1594
+ var AgentQaConfigSchema = import_zod8.z.object({
1516
1595
  workspace: WorkspaceSchema,
1517
1596
  services: ServicesSchema.optional(),
1518
1597
  registry: RegistrySchema.optional(),
@@ -1525,28 +1604,28 @@ var AgentQaConfigSchema = import_zod7.z.object({
1525
1604
  const dupes = names.filter((n, i) => names.indexOf(n) !== i);
1526
1605
  for (const dupe of new Set(dupes)) {
1527
1606
  ctx.addIssue({
1528
- code: import_zod7.z.ZodIssueCode.custom,
1607
+ code: import_zod8.z.ZodIssueCode.custom,
1529
1608
  path: ["registry", "llms"],
1530
1609
  message: `Duplicate LLM config name: "${dupe}"`
1531
1610
  });
1532
1611
  }
1533
1612
  if (val.use?.platform) {
1534
1613
  ctx.addIssue({
1535
- code: import_zod7.z.ZodIssueCode.custom,
1614
+ code: import_zod8.z.ZodIssueCode.custom,
1536
1615
  path: ["use", "platform"],
1537
1616
  message: "use.platform cannot be set at global config level. Set platform in test or suite YAML instead."
1538
1617
  });
1539
1618
  }
1540
1619
  if (val.use?.llm && !names.includes(val.use.llm)) {
1541
1620
  ctx.addIssue({
1542
- code: import_zod7.z.ZodIssueCode.custom,
1621
+ code: import_zod8.z.ZodIssueCode.custom,
1543
1622
  path: ["use", "llm"],
1544
1623
  message: `use.llm "${val.use.llm}" does not match any name in registry.llms`
1545
1624
  });
1546
1625
  }
1547
1626
  if (!MobileAppStateSchema.safeParse(val.use?.mobile?.appState).success) {
1548
1627
  ctx.addIssue({
1549
- code: import_zod7.z.ZodIssueCode.custom,
1628
+ code: import_zod8.z.ZodIssueCode.custom,
1550
1629
  path: ["use", "mobile", "appState"],
1551
1630
  message: "use.mobile.appState is required and must be one of: preserve | reset"
1552
1631
  });
@@ -1554,123 +1633,123 @@ var AgentQaConfigSchema = import_zod7.z.object({
1554
1633
  });
1555
1634
 
1556
1635
  // src/schema/test-schema.ts
1557
- var import_zod8 = require("zod");
1636
+ var import_zod9 = require("zod");
1558
1637
  var import_ms2 = __toESM(require("ms"), 1);
1559
1638
  var import_agent_qa_ids = require("@vostride/agent-qa-ids");
1560
- var OptionalDuration = import_zod8.z.string().refine((v) => (0, import_ms2.default)(v) !== void 0, {
1639
+ var OptionalDuration = import_zod9.z.string().refine((v) => (0, import_ms2.default)(v) !== void 0, {
1561
1640
  message: 'Invalid duration format (e.g., "30s", "5m", "1h")'
1562
1641
  }).transform((v) => (0, import_ms2.default)(v)).optional();
1563
- var CaptureConfigSchema = import_zod8.z.object({
1564
- variable: import_zod8.z.string(),
1565
- method: import_zod8.z.enum(["regex", "selector", "ai"]),
1566
- pattern: import_zod8.z.string().optional(),
1567
- selector: import_zod8.z.string().optional(),
1568
- description: import_zod8.z.string().optional()
1642
+ var CaptureConfigSchema = import_zod9.z.object({
1643
+ variable: import_zod9.z.string(),
1644
+ method: import_zod9.z.enum(["regex", "selector", "ai"]),
1645
+ pattern: import_zod9.z.string().optional(),
1646
+ selector: import_zod9.z.string().optional(),
1647
+ description: import_zod9.z.string().optional()
1569
1648
  }).strict();
1570
- var TestStepSchema = import_zod8.z.union([
1571
- import_zod8.z.string(),
1572
- import_zod8.z.object({
1573
- step: import_zod8.z.string(),
1649
+ var TestStepSchema = import_zod9.z.union([
1650
+ import_zod9.z.string(),
1651
+ import_zod9.z.object({
1652
+ step: import_zod9.z.string(),
1574
1653
  timeout: OptionalDuration,
1575
- retries: import_zod8.z.number().optional(),
1576
- screenshot: import_zod8.z.boolean().optional(),
1654
+ retries: import_zod9.z.number().optional(),
1655
+ screenshot: import_zod9.z.boolean().optional(),
1577
1656
  capture: CaptureConfigSchema.optional(),
1578
- maxAttempts: import_zod8.z.number().optional()
1657
+ maxAttempts: import_zod9.z.number().optional()
1579
1658
  }).strict()
1580
1659
  ]);
1581
- var TestMetaSchema = import_zod8.z.object({
1660
+ var TestMetaSchema = import_zod9.z.object({
1582
1661
  timeout: OptionalDuration,
1583
- retries: import_zod8.z.number().optional(),
1584
- record: import_zod8.z.boolean().optional()
1662
+ retries: import_zod9.z.number().optional(),
1663
+ record: import_zod9.z.boolean().optional()
1585
1664
  }).strict();
1586
- var HookIdSchema = import_zod8.z.string().refine((value) => (0, import_agent_qa_ids.isCanonicalHookId)(value), {
1665
+ var HookIdSchema = import_zod9.z.string().refine((value) => (0, import_agent_qa_ids.isCanonicalHookId)(value), {
1587
1666
  message: "Hook ID must be h_ followed by 10 id-agent words"
1588
1667
  });
1589
- var TestDefinitionSchema = import_zod8.z.object({
1590
- "test-id": import_zod8.z.string().refine((value) => (0, import_agent_qa_ids.isCanonicalTestId)(value), {
1668
+ var TestDefinitionSchema = import_zod9.z.object({
1669
+ "test-id": import_zod9.z.string().refine((value) => (0, import_agent_qa_ids.isCanonicalTestId)(value), {
1591
1670
  message: "Test ID must be t_ followed by 10 id-agent words"
1592
1671
  }),
1593
- name: import_zod8.z.string(),
1594
- target: import_zod8.z.string(),
1595
- context: import_zod8.z.string().optional(),
1672
+ name: import_zod9.z.string(),
1673
+ target: import_zod9.z.string(),
1674
+ context: import_zod9.z.string().optional(),
1596
1675
  use: UseOverrideSchema.optional(),
1597
1676
  meta: TestMetaSchema.optional(),
1598
- setup: import_zod8.z.array(HookIdSchema).optional(),
1599
- teardown: import_zod8.z.array(HookIdSchema).optional(),
1600
- steps: import_zod8.z.array(TestStepSchema).min(1)
1677
+ setup: import_zod9.z.array(HookIdSchema).optional(),
1678
+ teardown: import_zod9.z.array(HookIdSchema).optional(),
1679
+ steps: import_zod9.z.array(TestStepSchema).min(1)
1601
1680
  }).strict();
1602
1681
 
1603
1682
  // src/schema/action-schema.ts
1604
- var import_zod9 = require("zod");
1605
- var ActionPlanSchema = import_zod9.z.object({
1606
- reasoning: import_zod9.z.string().describe("Brief explanation of why this action was chosen"),
1607
- action: import_zod9.z.object({ type: import_zod9.z.string() }).passthrough(),
1608
- confidence: import_zod9.z.number().describe("Confidence level from 0 to 1"),
1609
- stepComplete: import_zod9.z.boolean().default(false).describe("Whether this action completes the step goal. Set true when the step objective is fully accomplished, false when more actions are needed."),
1610
- stepFailed: import_zod9.z.boolean().optional().default(false).describe("Set true when the step goal cannot be achieved from the current screen state. When true, no action is executed and the step fails with the reasoning as the error message.")
1683
+ var import_zod10 = require("zod");
1684
+ var ActionPlanSchema = import_zod10.z.object({
1685
+ reasoning: import_zod10.z.string().describe("Brief explanation of why this action was chosen"),
1686
+ action: import_zod10.z.object({ type: import_zod10.z.string() }).passthrough(),
1687
+ confidence: import_zod10.z.number().describe("Confidence level from 0 to 1"),
1688
+ stepComplete: import_zod10.z.boolean().default(false).describe("Whether this action completes the step goal. Set true when the step objective is fully accomplished, false when more actions are needed."),
1689
+ stepFailed: import_zod10.z.boolean().optional().default(false).describe("Set true when the step goal cannot be achieved from the current screen state. When true, no action is executed and the step fails with the reasoning as the error message.")
1611
1690
  });
1612
1691
 
1613
1692
  // src/schema/suite-schema.ts
1614
- var import_zod10 = require("zod");
1693
+ var import_zod11 = require("zod");
1615
1694
  var import_agent_qa_ids2 = require("@vostride/agent-qa-ids");
1616
- var SuiteTestEntrySchema = import_zod10.z.object({
1617
- test: import_zod10.z.string(),
1618
- id: import_zod10.z.string().refine((value) => (0, import_agent_qa_ids2.isCanonicalTestId)(value), {
1695
+ var SuiteTestEntrySchema = import_zod11.z.object({
1696
+ test: import_zod11.z.string(),
1697
+ id: import_zod11.z.string().refine((value) => (0, import_agent_qa_ids2.isCanonicalTestId)(value), {
1619
1698
  message: "Test ID must be t_ followed by 10 id-agent words"
1620
1699
  })
1621
1700
  }).strict();
1622
- var HookIdSchema2 = import_zod10.z.string().refine((value) => (0, import_agent_qa_ids2.isCanonicalHookId)(value), {
1701
+ var HookIdSchema2 = import_zod11.z.string().refine((value) => (0, import_agent_qa_ids2.isCanonicalHookId)(value), {
1623
1702
  message: "Hook ID must be h_ followed by 10 id-agent words"
1624
1703
  });
1625
- var SuiteDefinitionSchema = import_zod10.z.object({
1626
- "suite-id": import_zod10.z.string().refine((value) => (0, import_agent_qa_ids2.isCanonicalSuiteId)(value), {
1704
+ var SuiteDefinitionSchema = import_zod11.z.object({
1705
+ "suite-id": import_zod11.z.string().refine((value) => (0, import_agent_qa_ids2.isCanonicalSuiteId)(value), {
1627
1706
  message: "Suite ID must be s_ followed by 10 id-agent words"
1628
1707
  }).optional(),
1629
- name: import_zod10.z.string(),
1630
- target: import_zod10.z.string(),
1631
- context: import_zod10.z.string().optional(),
1632
- setup: import_zod10.z.array(HookIdSchema2).optional(),
1633
- teardown: import_zod10.z.array(HookIdSchema2).optional(),
1634
- tests: import_zod10.z.array(SuiteTestEntrySchema).min(1),
1708
+ name: import_zod11.z.string(),
1709
+ target: import_zod11.z.string(),
1710
+ context: import_zod11.z.string().optional(),
1711
+ setup: import_zod11.z.array(HookIdSchema2).optional(),
1712
+ teardown: import_zod11.z.array(HookIdSchema2).optional(),
1713
+ tests: import_zod11.z.array(SuiteTestEntrySchema).min(1),
1635
1714
  use: UseOverrideSchema.optional()
1636
1715
  }).strict();
1637
1716
 
1638
1717
  // src/hooks/schema.ts
1639
- var import_zod11 = require("zod");
1718
+ var import_zod12 = require("zod");
1640
1719
  var import_ms3 = __toESM(require("ms"), 1);
1641
1720
  var import_agent_qa_ids3 = require("@vostride/agent-qa-ids");
1642
- var HookDurationString = import_zod11.z.string().refine((v) => (0, import_ms3.default)(v) !== void 0, {
1721
+ var HookDurationString = import_zod12.z.string().refine((v) => (0, import_ms3.default)(v) !== void 0, {
1643
1722
  message: 'Invalid duration format (e.g., "30s", "2m", "1h")'
1644
1723
  }).transform((v) => (0, import_ms3.default)(v));
1645
1724
  var HOOK_ID_MESSAGE = "Hook ID must be h_ followed by 10 id-agent words";
1646
- var HookDefinitionSchema = import_zod11.z.object({
1647
- id: import_zod11.z.string().refine((value) => (0, import_agent_qa_ids3.isCanonicalHookId)(value), {
1725
+ var HookDefinitionSchema = import_zod12.z.object({
1726
+ id: import_zod12.z.string().refine((value) => (0, import_agent_qa_ids3.isCanonicalHookId)(value), {
1648
1727
  message: HOOK_ID_MESSAGE
1649
1728
  }),
1650
- name: import_zod11.z.string().min(1),
1651
- runtime: import_zod11.z.enum(["node", "bun", "python", "bash"]),
1652
- file: import_zod11.z.string().min(1),
1653
- deps: import_zod11.z.array(import_zod11.z.string()).optional().default([]),
1654
- packageFile: import_zod11.z.string().optional(),
1729
+ name: import_zod12.z.string().min(1),
1730
+ runtime: import_zod12.z.enum(["node", "bun", "python", "bash"]),
1731
+ file: import_zod12.z.string().min(1),
1732
+ deps: import_zod12.z.array(import_zod12.z.string()).optional().default([]),
1733
+ packageFile: import_zod12.z.string().optional(),
1655
1734
  timeout: HookDurationString,
1656
- network: import_zod11.z.boolean().optional().default(true)
1735
+ network: import_zod12.z.boolean().optional().default(true)
1657
1736
  });
1658
- var HooksFileSchema = import_zod11.z.object({
1659
- hooks: import_zod11.z.array(HookDefinitionSchema)
1737
+ var HooksFileSchema = import_zod12.z.object({
1738
+ hooks: import_zod12.z.array(HookDefinitionSchema)
1660
1739
  }).superRefine((val, ctx) => {
1661
1740
  const ids = /* @__PURE__ */ new Set();
1662
1741
  const names = /* @__PURE__ */ new Set();
1663
1742
  for (let i = 0; i < val.hooks.length; i++) {
1664
1743
  if (ids.has(val.hooks[i].id)) {
1665
1744
  ctx.addIssue({
1666
- code: import_zod11.z.ZodIssueCode.custom,
1745
+ code: import_zod12.z.ZodIssueCode.custom,
1667
1746
  path: ["hooks", i, "id"],
1668
1747
  message: `Duplicate hook id: "${val.hooks[i].id}"`
1669
1748
  });
1670
1749
  }
1671
1750
  if (names.has(val.hooks[i].name)) {
1672
1751
  ctx.addIssue({
1673
- code: import_zod11.z.ZodIssueCode.custom,
1752
+ code: import_zod12.z.ZodIssueCode.custom,
1674
1753
  path: ["hooks", i, "name"],
1675
1754
  message: `Duplicate hook name: "${val.hooks[i].name}"`
1676
1755
  });
@@ -1736,8 +1815,8 @@ function formatYamlError(err, linePos, content, filePath) {
1736
1815
  suggestion: void 0
1737
1816
  };
1738
1817
  }
1739
- function zodPathToSuggestion(code, path5, message) {
1740
- const field = path5[path5.length - 1];
1818
+ function zodPathToSuggestion(code, path7, message) {
1819
+ const field = path7[path7.length - 1];
1741
1820
  if (code === "invalid_type") {
1742
1821
  if (typeof field === "string") {
1743
1822
  return `check that '${field}' has the correct type`;
@@ -1761,10 +1840,10 @@ function zodPathToSuggestion(code, path5, message) {
1761
1840
  }
1762
1841
  return void 0;
1763
1842
  }
1764
- function resolveNodeAtPath(doc, path5) {
1843
+ function resolveNodeAtPath(doc, path7) {
1765
1844
  let current = doc.contents;
1766
1845
  if (!current) return null;
1767
- for (const segment of path5) {
1846
+ for (const segment of path7) {
1768
1847
  if (!current) return null;
1769
1848
  if (typeof segment === "number") {
1770
1849
  const items = current.items;
@@ -1827,7 +1906,7 @@ function formatZodErrors(zodError, doc, lineCounter, content, filePath) {
1827
1906
 
1828
1907
  // src/agent/variables.ts
1829
1908
  var import_ai2 = require("ai");
1830
- var import_zod14 = require("zod");
1909
+ var import_zod15 = require("zod");
1831
1910
 
1832
1911
  // src/agent/observation.ts
1833
1912
  var import_node_crypto = require("crypto");
@@ -1964,12 +2043,12 @@ function getPlatformFilter(name) {
1964
2043
 
1965
2044
  // src/tools/builder.ts
1966
2045
  var import_ai = require("ai");
1967
- var import_zod12 = require("zod");
2046
+ var import_zod13 = require("zod");
1968
2047
  var PLAN_FIELDS = {
1969
- reasoning: import_zod12.z.string().describe("Brief explanation of why this action was chosen"),
1970
- confidence: import_zod12.z.number().describe("Confidence level from 0 to 1"),
1971
- stepComplete: import_zod12.z.boolean().describe("Whether this action completes the step goal"),
1972
- stepFailed: import_zod12.z.boolean().optional().describe("Set true when the step goal cannot be achieved")
2048
+ reasoning: import_zod13.z.string().describe("Brief explanation of why this action was chosen"),
2049
+ confidence: import_zod13.z.number().describe("Confidence level from 0 to 1"),
2050
+ stepComplete: import_zod13.z.boolean().describe("Whether this action completes the step goal"),
2051
+ stepFailed: import_zod13.z.boolean().optional().describe("Set true when the step goal cannot be achieved")
1973
2052
  };
1974
2053
  var ToolValidationError = class extends Error {
1975
2054
  toolName;
@@ -1987,7 +2066,7 @@ function buildTools(registry, options) {
1987
2066
  const actionShape = def.schema.shape;
1988
2067
  tools[def.name] = (0, import_ai.tool)({
1989
2068
  description: def.description,
1990
- inputSchema: import_zod12.z.object({ ...PLAN_FIELDS, ...actionShape })
2069
+ inputSchema: import_zod13.z.object({ ...PLAN_FIELDS, ...actionShape })
1991
2070
  });
1992
2071
  }
1993
2072
  return tools;
@@ -2009,7 +2088,7 @@ function toolCallToActionPlan(toolName, args, registry) {
2009
2088
  }
2010
2089
 
2011
2090
  // src/tools/actions/index.ts
2012
- var import_zod13 = require("zod");
2091
+ var import_zod14 = require("zod");
2013
2092
  function action(name, description, schema) {
2014
2093
  return {
2015
2094
  name,
@@ -2020,204 +2099,204 @@ function action(name, description, schema) {
2020
2099
  };
2021
2100
  }
2022
2101
  var ACTION_DEFINITIONS = [
2023
- action("click", "Click an element", import_zod13.z.object({
2024
- ref: import_zod13.z.string().describe("Element reference from the screen state"),
2025
- clickDelay: import_zod13.z.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
2102
+ action("click", "Click an element", import_zod14.z.object({
2103
+ ref: import_zod14.z.string().describe("Element reference from the screen state"),
2104
+ clickDelay: import_zod14.z.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
2026
2105
  })),
2027
- action("fill", "Fill text into an input field", import_zod13.z.object({
2028
- ref: import_zod13.z.string().describe("Element reference for the input field"),
2029
- value: import_zod13.z.string().describe("Text value to fill into the input")
2106
+ action("fill", "Fill text into an input field", import_zod14.z.object({
2107
+ ref: import_zod14.z.string().describe("Element reference for the input field"),
2108
+ value: import_zod14.z.string().describe("Text value to fill into the input")
2030
2109
  })),
2031
- action("select", "Select an option from a dropdown", import_zod13.z.object({
2032
- ref: import_zod13.z.string().describe("Element reference for the select/dropdown"),
2033
- value: import_zod13.z.string().describe("Option value to select")
2110
+ action("select", "Select an option from a dropdown", import_zod14.z.object({
2111
+ ref: import_zod14.z.string().describe("Element reference for the select/dropdown"),
2112
+ value: import_zod14.z.string().describe("Option value to select")
2034
2113
  })),
2035
- action("nativeSelect", "Select a value from a native mobile picker, picker wheel, spinner, or dropdown/list control", import_zod13.z.object({
2036
- ref: import_zod13.z.string().describe("Element reference for the native picker/dropdown control"),
2037
- value: import_zod13.z.string().describe("Visible text/value to select")
2114
+ action("nativeSelect", "Select a value from a native mobile picker, picker wheel, spinner, or dropdown/list control", import_zod14.z.object({
2115
+ ref: import_zod14.z.string().describe("Element reference for the native picker/dropdown control"),
2116
+ value: import_zod14.z.string().describe("Visible text/value to select")
2038
2117
  })),
2039
- action("navigate", "Navigate to a URL", import_zod13.z.object({
2040
- url: import_zod13.z.string().describe("URL to navigate to")
2118
+ action("navigate", "Navigate to a URL", import_zod14.z.object({
2119
+ url: import_zod14.z.string().describe("URL to navigate to")
2041
2120
  })),
2042
- action("scroll", "Scroll the page or a specific element", import_zod13.z.object({
2043
- scrollType: import_zod13.z.enum(["vertical", "horizontal"]).describe("Scroll axis: vertical (up/down) or horizontal (left/right)"),
2044
- value: import_zod13.z.number().describe("Scroll distance in pixels. Positive = down/right, negative = up/left"),
2045
- ref: import_zod13.z.string().optional().describe("Optional element to scroll within"),
2046
- duration: import_zod13.z.number().optional().describe("Scroll duration in ms (mobile only \u2014 web ignores this)")
2121
+ action("scroll", "Scroll the page or a specific element", import_zod14.z.object({
2122
+ scrollType: import_zod14.z.enum(["vertical", "horizontal"]).describe("Scroll axis: vertical (up/down) or horizontal (left/right)"),
2123
+ value: import_zod14.z.number().describe("Scroll distance in pixels. Positive = down/right, negative = up/left"),
2124
+ ref: import_zod14.z.string().optional().describe("Optional element to scroll within"),
2125
+ duration: import_zod14.z.number().optional().describe("Scroll duration in ms (mobile only \u2014 web ignores this)")
2047
2126
  })),
2048
- action("delay", 'Pause execution for a fixed duration \u2014 use when a specific duration is requested (e.g. "wait 3 seconds"). Do NOT use for waiting on conditions (use waitFor for that).', import_zod13.z.object({
2049
- ms: import_zod13.z.number().describe("Duration in milliseconds")
2127
+ action("delay", 'Pause execution for a fixed duration \u2014 use when a specific duration is requested (e.g. "wait 3 seconds"). Do NOT use for waiting on conditions (use waitFor for that).', import_zod14.z.object({
2128
+ ms: import_zod14.z.number().describe("Duration in milliseconds")
2050
2129
  })),
2051
- action("waitFor", "Wait for a condition to be met (text content match or selector)", import_zod13.z.object({
2052
- condition: import_zod13.z.string().describe("Condition to wait for \u2014 either visible text content or a CSS selector"),
2053
- timeout: import_zod13.z.number().optional().describe("Maximum wait time in ms (default: 5000)")
2130
+ action("waitFor", "Wait for a condition to be met (text content match or selector)", import_zod14.z.object({
2131
+ condition: import_zod14.z.string().describe("Condition to wait for \u2014 either visible text content or a CSS selector"),
2132
+ timeout: import_zod14.z.number().optional().describe("Maximum wait time in ms (default: 5000)")
2054
2133
  })),
2055
- action("assert", "Assert a condition on the current page state", import_zod13.z.object({
2056
- condition: import_zod13.z.string().describe("Assertion condition to check"),
2057
- expected: import_zod13.z.string().optional().describe("Expected value for comparison"),
2058
- visual: import_zod13.z.boolean().optional().default(true).describe("Whether this assertion requires screen evidence. Set false for non-visual checks (tautologies, hook/env results, runJS outputs, computed values). Default true for screen-visible assertions.")
2134
+ action("assert", "Assert a condition on the current page state", import_zod14.z.object({
2135
+ condition: import_zod14.z.string().describe("Assertion condition to check"),
2136
+ expected: import_zod14.z.string().optional().describe("Expected value for comparison"),
2137
+ visual: import_zod14.z.boolean().optional().default(true).describe("Whether this assertion requires screen evidence. Set false for non-visual checks (tautologies, hook/env results, runJS outputs, computed values). Default true for screen-visible assertions.")
2059
2138
  })),
2060
- action("keypress", "Press one or more keyboard keys/combos in sequence", import_zod13.z.object({
2061
- keys: import_zod13.z.array(import_zod13.z.string()).min(1).describe('Array of keys/combos to press in sequence. Each entry may be a single key (e.g. "Enter", "Tab", "Escape") or a combo with "+" separators (e.g. "Meta+k", "Control+Shift+T"). Use "Meta" for the Cmd/Win/Super key \u2014 on non-Mac platforms it is automatically converted to "Control" when convertPlatformKeys is true. On mobile, only single special keys from the KEY_MAP work meaningfully; combos are a no-op.'),
2062
- convertPlatformKeys: import_zod13.z.boolean().optional().default(true).describe('When true (default), replaces "Meta" with "Control" in each key string on non-Mac platforms so that "Meta+k" works as Cmd+K on Mac and Ctrl+K on Windows/Linux. Set to false to pass keys through unchanged. No-op on mobile.')
2139
+ action("keypress", "Press one or more keyboard keys/combos in sequence", import_zod14.z.object({
2140
+ keys: import_zod14.z.array(import_zod14.z.string()).min(1).describe('Array of keys/combos to press in sequence. Each entry may be a single key (e.g. "Enter", "Tab", "Escape") or a combo with "+" separators (e.g. "Meta+k", "Control+Shift+T"). Use "Meta" for the Cmd/Win/Super key \u2014 on non-Mac platforms it is automatically converted to "Control" when convertPlatformKeys is true. On mobile, only single special keys from the KEY_MAP work meaningfully; combos are a no-op.'),
2141
+ convertPlatformKeys: import_zod14.z.boolean().optional().default(true).describe('When true (default), replaces "Meta" with "Control" in each key string on non-Mac platforms so that "Meta+k" works as Cmd+K on Mac and Ctrl+K on Windows/Linux. Set to false to pass keys through unchanged. No-op on mobile.')
2063
2142
  })),
2064
- action("hover", "Hover over an element", import_zod13.z.object({
2065
- ref: import_zod13.z.string().describe("Element reference to hover over")
2143
+ action("hover", "Hover over an element", import_zod14.z.object({
2144
+ ref: import_zod14.z.string().describe("Element reference to hover over")
2066
2145
  })),
2067
- action("paste", "Paste text into an element via clipboard paste event", import_zod13.z.object({
2068
- ref: import_zod13.z.string().describe("Element reference for the target element"),
2069
- value: import_zod13.z.string().describe("Text value to paste")
2146
+ action("paste", "Paste text into an element via clipboard paste event", import_zod14.z.object({
2147
+ ref: import_zod14.z.string().describe("Element reference for the target element"),
2148
+ value: import_zod14.z.string().describe("Text value to paste")
2070
2149
  })),
2071
- action("keyDown", "Hold down a key (for modifier combos like Shift+Click)", import_zod13.z.object({
2072
- key: import_zod13.z.string().describe("Key to hold down (e.g., Shift, Control, Alt, Meta)")
2150
+ action("keyDown", "Hold down a key (for modifier combos like Shift+Click)", import_zod14.z.object({
2151
+ key: import_zod14.z.string().describe("Key to hold down (e.g., Shift, Control, Alt, Meta)")
2073
2152
  })),
2074
- action("keyUp", "Release a held key", import_zod13.z.object({
2075
- key: import_zod13.z.string().describe("Key to release (e.g., Shift, Control, Alt, Meta)")
2153
+ action("keyUp", "Release a held key", import_zod14.z.object({
2154
+ key: import_zod14.z.string().describe("Key to release (e.g., Shift, Control, Alt, Meta)")
2076
2155
  })),
2077
- action("refresh", "Refresh the current page", import_zod13.z.object({})),
2078
- action("navigateHistory", "Navigate browser history (back or forward)", import_zod13.z.object({
2079
- direction: import_zod13.z.enum(["back", "forward"]).describe("Navigation direction in browser history")
2156
+ action("refresh", "Refresh the current page", import_zod14.z.object({})),
2157
+ action("navigateHistory", "Navigate browser history (back or forward)", import_zod14.z.object({
2158
+ direction: import_zod14.z.enum(["back", "forward"]).describe("Navigation direction in browser history")
2080
2159
  })),
2081
- action("readConsoleLogs", "Read console log entries from the browser", import_zod13.z.object({
2082
- level: import_zod13.z.enum(["log", "info", "warn", "error"]).optional().describe("Filter by log level. Omit to get all levels."),
2083
- tab: import_zod13.z.object({
2084
- index: import_zod13.z.number().optional().describe("0-based tab index"),
2085
- title: import_zod13.z.string().optional().describe("Substring match on page title"),
2086
- url: import_zod13.z.string().optional().describe("Substring match on page URL")
2160
+ action("readConsoleLogs", "Read console log entries from the browser", import_zod14.z.object({
2161
+ level: import_zod14.z.enum(["log", "info", "warn", "error"]).optional().describe("Filter by log level. Omit to get all levels."),
2162
+ tab: import_zod14.z.object({
2163
+ index: import_zod14.z.number().optional().describe("0-based tab index"),
2164
+ title: import_zod14.z.string().optional().describe("Substring match on page title"),
2165
+ url: import_zod14.z.string().optional().describe("Substring match on page URL")
2087
2166
  }).optional().describe("Target a specific tab. Omit to read logs from all tabs.")
2088
2167
  })),
2089
- action("readNetworkLogs", "Read network request/response log entries", import_zod13.z.object({
2090
- urlPattern: import_zod13.z.string().optional().describe("Filter by URL substring match. Omit to get all requests."),
2091
- tab: import_zod13.z.object({
2092
- index: import_zod13.z.number().optional().describe("0-based tab index"),
2093
- title: import_zod13.z.string().optional().describe("Substring match on page title"),
2094
- url: import_zod13.z.string().optional().describe("Substring match on page URL")
2168
+ action("readNetworkLogs", "Read network request/response log entries", import_zod14.z.object({
2169
+ urlPattern: import_zod14.z.string().optional().describe("Filter by URL substring match. Omit to get all requests."),
2170
+ tab: import_zod14.z.object({
2171
+ index: import_zod14.z.number().optional().describe("0-based tab index"),
2172
+ title: import_zod14.z.string().optional().describe("Substring match on page title"),
2173
+ url: import_zod14.z.string().optional().describe("Substring match on page URL")
2095
2174
  }).optional().describe("Target a specific tab. Omit to read logs from all tabs.")
2096
2175
  })),
2097
- action("readCookies", "Read browser cookies", import_zod13.z.object({
2098
- name: import_zod13.z.string().optional().describe("Cookie name to read. Omit to get all cookies.")
2176
+ action("readCookies", "Read browser cookies", import_zod14.z.object({
2177
+ name: import_zod14.z.string().optional().describe("Cookie name to read. Omit to get all cookies.")
2099
2178
  })),
2100
- action("setCookies", "Set browser cookies", import_zod13.z.object({
2101
- cookies: import_zod13.z.array(import_zod13.z.object({
2102
- name: import_zod13.z.string().describe("Cookie name"),
2103
- value: import_zod13.z.string().describe("Cookie value"),
2104
- domain: import_zod13.z.string().optional().describe("Cookie domain"),
2105
- path: import_zod13.z.string().optional().describe("Cookie path"),
2106
- httpOnly: import_zod13.z.boolean().optional().describe("HTTP only flag"),
2107
- secure: import_zod13.z.boolean().optional().describe("Secure flag"),
2108
- sameSite: import_zod13.z.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute"),
2109
- expires: import_zod13.z.number().optional().describe("Expiry as Unix timestamp in seconds")
2179
+ action("setCookies", "Set browser cookies", import_zod14.z.object({
2180
+ cookies: import_zod14.z.array(import_zod14.z.object({
2181
+ name: import_zod14.z.string().describe("Cookie name"),
2182
+ value: import_zod14.z.string().describe("Cookie value"),
2183
+ domain: import_zod14.z.string().optional().describe("Cookie domain"),
2184
+ path: import_zod14.z.string().optional().describe("Cookie path"),
2185
+ httpOnly: import_zod14.z.boolean().optional().describe("HTTP only flag"),
2186
+ secure: import_zod14.z.boolean().optional().describe("Secure flag"),
2187
+ sameSite: import_zod14.z.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute"),
2188
+ expires: import_zod14.z.number().optional().describe("Expiry as Unix timestamp in seconds")
2110
2189
  })).describe("Array of cookies to set")
2111
2190
  })),
2112
- action("readLocalStorage", "Read local storage entries", import_zod13.z.object({
2113
- key: import_zod13.z.string().optional().describe("Storage key to read. Omit to get all entries.")
2191
+ action("readLocalStorage", "Read local storage entries", import_zod14.z.object({
2192
+ key: import_zod14.z.string().optional().describe("Storage key to read. Omit to get all entries.")
2114
2193
  })),
2115
- action("setLocalStorage", "Set local storage entries", import_zod13.z.object({
2116
- entries: import_zod13.z.array(import_zod13.z.object({
2117
- key: import_zod13.z.string().describe("Storage key"),
2118
- value: import_zod13.z.string().describe("Storage value")
2194
+ action("setLocalStorage", "Set local storage entries", import_zod14.z.object({
2195
+ entries: import_zod14.z.array(import_zod14.z.object({
2196
+ key: import_zod14.z.string().describe("Storage key"),
2197
+ value: import_zod14.z.string().describe("Storage value")
2119
2198
  })).describe("Array of key-value pairs to set")
2120
2199
  })),
2121
- action("tap", "Tap an element on a mobile device", import_zod13.z.object({
2122
- ref: import_zod13.z.string().describe("Element reference to tap")
2200
+ action("tap", "Tap an element on a mobile device", import_zod14.z.object({
2201
+ ref: import_zod14.z.string().describe("Element reference to tap")
2123
2202
  })),
2124
- action("swipe", "Swipe gesture on a mobile device", import_zod13.z.object({
2125
- direction: import_zod13.z.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
2126
- ref: import_zod13.z.string().optional().describe("Optional element to swipe within"),
2127
- startX: import_zod13.z.number().optional().describe("Start X coordinate (overrides direction-based calculation)"),
2128
- startY: import_zod13.z.number().optional().describe("Start Y coordinate (overrides direction-based calculation)"),
2129
- endX: import_zod13.z.number().optional().describe("End X coordinate (overrides direction-based calculation)"),
2130
- endY: import_zod13.z.number().optional().describe("End Y coordinate (overrides direction-based calculation)"),
2131
- duration: import_zod13.z.number().optional().describe("Swipe duration in ms (default: 300)")
2203
+ action("swipe", "Swipe gesture on a mobile device", import_zod14.z.object({
2204
+ direction: import_zod14.z.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
2205
+ ref: import_zod14.z.string().optional().describe("Optional element to swipe within"),
2206
+ startX: import_zod14.z.number().optional().describe("Start X coordinate (overrides direction-based calculation)"),
2207
+ startY: import_zod14.z.number().optional().describe("Start Y coordinate (overrides direction-based calculation)"),
2208
+ endX: import_zod14.z.number().optional().describe("End X coordinate (overrides direction-based calculation)"),
2209
+ endY: import_zod14.z.number().optional().describe("End Y coordinate (overrides direction-based calculation)"),
2210
+ duration: import_zod14.z.number().optional().describe("Swipe duration in ms (default: 300)")
2132
2211
  })),
2133
- action("longpress", "Long-press an element on a mobile device", import_zod13.z.object({
2134
- ref: import_zod13.z.string().describe("Element reference to long-press"),
2135
- duration: import_zod13.z.number().optional().describe("Long-press duration in ms")
2212
+ action("longpress", "Long-press an element on a mobile device", import_zod14.z.object({
2213
+ ref: import_zod14.z.string().describe("Element reference to long-press"),
2214
+ duration: import_zod14.z.number().optional().describe("Long-press duration in ms")
2136
2215
  })),
2137
- action("hideKeyboard", "Dismiss the on-screen keyboard (mobile only, no-op on web)", import_zod13.z.object({})),
2138
- action("clearText", "Clear all text from an input field without typing new text", import_zod13.z.object({
2139
- ref: import_zod13.z.string().describe("Element reference for the input field to clear")
2216
+ action("hideKeyboard", "Dismiss the on-screen keyboard (mobile only, no-op on web)", import_zod14.z.object({})),
2217
+ action("clearText", "Clear all text from an input field without typing new text", import_zod14.z.object({
2218
+ ref: import_zod14.z.string().describe("Element reference for the input field to clear")
2140
2219
  })),
2141
- action("openLink", "Open a deep link in a mobile app \u2014 use navigate for web URLs", import_zod13.z.object({
2142
- url: import_zod13.z.string().describe("Deep link URL to open (e.g. myapp://screen, intent://...)"),
2143
- appId: import_zod13.z.string().optional().describe("Generic mobile app identifier. Android uses package name; iOS uses bundle ID."),
2144
- bundleId: import_zod13.z.string().optional().describe("iOS bundle ID to open the link in"),
2145
- appPackage: import_zod13.z.string().optional().describe("Android package name to open the link in"),
2146
- waitForLaunch: import_zod13.z.boolean().optional().describe("Whether to wait for the app to launch after opening the link")
2220
+ action("openLink", "Open a deep link in a mobile app \u2014 use navigate for web URLs", import_zod14.z.object({
2221
+ url: import_zod14.z.string().describe("Deep link URL to open (e.g. myapp://screen, intent://...)"),
2222
+ appId: import_zod14.z.string().optional().describe("Generic mobile app identifier. Android uses package name; iOS uses bundle ID."),
2223
+ bundleId: import_zod14.z.string().optional().describe("iOS bundle ID to open the link in"),
2224
+ appPackage: import_zod14.z.string().optional().describe("Android package name to open the link in"),
2225
+ waitForLaunch: import_zod14.z.boolean().optional().describe("Whether to wait for the app to launch after opening the link")
2147
2226
  })),
2148
- action("drag", "Drag an element to another element (reorder lists, sliders)", import_zod13.z.object({
2149
- fromRef: import_zod13.z.string().describe("Element reference to drag from"),
2150
- toRef: import_zod13.z.string().describe("Element reference to drag to")
2227
+ action("drag", "Drag an element to another element (reorder lists, sliders)", import_zod14.z.object({
2228
+ fromRef: import_zod14.z.string().describe("Element reference to drag from"),
2229
+ toRef: import_zod14.z.string().describe("Element reference to drag to")
2151
2230
  })),
2152
- action("doubleTap", "Double-tap an element (text selection, zoom)", import_zod13.z.object({
2153
- ref: import_zod13.z.string().describe("Element reference to double-tap")
2231
+ action("doubleTap", "Double-tap an element (text selection, zoom)", import_zod14.z.object({
2232
+ ref: import_zod14.z.string().describe("Element reference to double-tap")
2154
2233
  })),
2155
- action("launchApp", "Launch or bring an app to the foreground", import_zod13.z.object({
2156
- bundleId: import_zod13.z.string().describe("App bundle ID (iOS) or package name (Android)")
2234
+ action("launchApp", "Launch or bring an app to the foreground", import_zod14.z.object({
2235
+ bundleId: import_zod14.z.string().describe("App bundle ID (iOS) or package name (Android)")
2157
2236
  })),
2158
- action("stopApp", "Terminate a running app", import_zod13.z.object({
2159
- bundleId: import_zod13.z.string().describe("App bundle ID (iOS) or package name (Android)")
2237
+ action("stopApp", "Terminate a running app", import_zod14.z.object({
2238
+ bundleId: import_zod14.z.string().describe("App bundle ID (iOS) or package name (Android)")
2160
2239
  })),
2161
- action("setOrientation", "Set the device orientation (mobile only)", import_zod13.z.object({
2162
- orientation: import_zod13.z.enum(["portrait", "landscape"]).describe("Device orientation")
2240
+ action("setOrientation", "Set the device orientation (mobile only)", import_zod14.z.object({
2241
+ orientation: import_zod14.z.enum(["portrait", "landscape"]).describe("Device orientation")
2163
2242
  })),
2164
- action("pinch", "Pinch zoom gesture on a mobile device (mobile only)", import_zod13.z.object({
2165
- scale: import_zod13.z.number().describe("Scale factor: >1 to zoom in (spread fingers), <1 to zoom out (pinch fingers)"),
2166
- x: import_zod13.z.number().optional().describe("Center X coordinate for pinch gesture"),
2167
- y: import_zod13.z.number().optional().describe("Center Y coordinate for pinch gesture"),
2168
- ref: import_zod13.z.string().optional().describe("Optional element to center the pinch on")
2243
+ action("pinch", "Pinch zoom gesture on a mobile device (mobile only)", import_zod14.z.object({
2244
+ scale: import_zod14.z.number().describe("Scale factor: >1 to zoom in (spread fingers), <1 to zoom out (pinch fingers)"),
2245
+ x: import_zod14.z.number().optional().describe("Center X coordinate for pinch gesture"),
2246
+ y: import_zod14.z.number().optional().describe("Center Y coordinate for pinch gesture"),
2247
+ ref: import_zod14.z.string().optional().describe("Optional element to center the pinch on")
2169
2248
  })),
2170
- action("multiTap", "Multi-finger tap gesture on a mobile device (mobile only)", import_zod13.z.object({
2171
- fingers: import_zod13.z.number().describe("Number of fingers (2 or 3)"),
2172
- x: import_zod13.z.number().optional().describe("Center X coordinate for multi-finger tap"),
2173
- y: import_zod13.z.number().optional().describe("Center Y coordinate for multi-finger tap"),
2174
- ref: import_zod13.z.string().optional().describe("Optional element to center the tap on")
2249
+ action("multiTap", "Multi-finger tap gesture on a mobile device (mobile only)", import_zod14.z.object({
2250
+ fingers: import_zod14.z.number().describe("Number of fingers (2 or 3)"),
2251
+ x: import_zod14.z.number().optional().describe("Center X coordinate for multi-finger tap"),
2252
+ y: import_zod14.z.number().optional().describe("Center Y coordinate for multi-finger tap"),
2253
+ ref: import_zod14.z.string().optional().describe("Optional element to center the tap on")
2175
2254
  })),
2176
- action("tapCoordinate", "Tap at specific pixel coordinates \u2014 use when target element has no ref in accessibility tree", import_zod13.z.object({
2177
- x: import_zod13.z.number().describe("X coordinate in pixels"),
2178
- y: import_zod13.z.number().describe("Y coordinate in pixels")
2255
+ action("tapCoordinate", "Tap at specific pixel coordinates \u2014 use when target element has no ref in accessibility tree", import_zod14.z.object({
2256
+ x: import_zod14.z.number().describe("X coordinate in pixels"),
2257
+ y: import_zod14.z.number().describe("Y coordinate in pixels")
2179
2258
  })),
2180
- action("executeScript", "Execute an Appium script command (mobile only)", import_zod13.z.object({
2181
- command: import_zod13.z.string().describe('Appium command name (e.g., "mobile: enrollBiometric", "mobile: terminateApp")'),
2182
- args: import_zod13.z.any().optional().describe("Command arguments \u2014 object with key-value pairs, or array for some commands")
2259
+ action("executeScript", "Execute an Appium script command (mobile only)", import_zod14.z.object({
2260
+ command: import_zod14.z.string().describe('Appium command name (e.g., "mobile: enrollBiometric", "mobile: terminateApp")'),
2261
+ args: import_zod14.z.any().optional().describe("Command arguments \u2014 object with key-value pairs, or array for some commands")
2183
2262
  })),
2184
- action("setVariable", "Set a runtime environment variable for use in subsequent steps", import_zod13.z.object({
2185
- name: import_zod13.z.string().describe("Variable name (will be accessible via {{env:varName}})"),
2186
- value: import_zod13.z.string().describe("Variable value to store")
2263
+ action("setVariable", "Set a runtime environment variable for use in subsequent steps", import_zod14.z.object({
2264
+ name: import_zod14.z.string().describe("Variable name (will be accessible via {{env:varName}})"),
2265
+ value: import_zod14.z.string().describe("Variable value to store")
2187
2266
  })),
2188
- action("newTab", "Open a URL in a new browser tab and switch to it", import_zod13.z.object({
2189
- url: import_zod13.z.string().describe("URL to open in the new tab")
2267
+ action("newTab", "Open a URL in a new browser tab and switch to it", import_zod14.z.object({
2268
+ url: import_zod14.z.string().describe("URL to open in the new tab")
2190
2269
  })),
2191
- action("switchTab", "Switch to an open browser tab", import_zod13.z.object({
2192
- index: import_zod13.z.number().optional().describe("0-based tab index to switch to"),
2193
- title: import_zod13.z.string().optional().describe("Substring match on page title"),
2194
- url: import_zod13.z.string().optional().describe("Substring match on page URL")
2270
+ action("switchTab", "Switch to an open browser tab", import_zod14.z.object({
2271
+ index: import_zod14.z.number().optional().describe("0-based tab index to switch to"),
2272
+ title: import_zod14.z.string().optional().describe("Substring match on page title"),
2273
+ url: import_zod14.z.string().optional().describe("Substring match on page URL")
2195
2274
  })),
2196
- action("doubleClick", "Double-click an element (text selection, expand, web-only)", import_zod13.z.object({
2197
- ref: import_zod13.z.string().describe("Element reference from the screen state"),
2198
- relativePosition: import_zod13.z.object({
2199
- x: import_zod13.z.number().describe("X offset in pixels from element top-left"),
2200
- y: import_zod13.z.number().describe("Y offset in pixels from element top-left")
2275
+ action("doubleClick", "Double-click an element (text selection, expand, web-only)", import_zod14.z.object({
2276
+ ref: import_zod14.z.string().describe("Element reference from the screen state"),
2277
+ relativePosition: import_zod14.z.object({
2278
+ x: import_zod14.z.number().describe("X offset in pixels from element top-left"),
2279
+ y: import_zod14.z.number().describe("Y offset in pixels from element top-left")
2201
2280
  }).optional().describe("Omit for normal element-center interaction. Only provide when the user explicitly asks for an offset. Do not use { x: 0, y: 0 } for a normal button double-click/right-click; top-left is often intercepted."),
2202
- clickDelay: import_zod13.z.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
2281
+ clickDelay: import_zod14.z.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
2203
2282
  })),
2204
- action("rightClick", "Right-click an element to open context menu (web-only)", import_zod13.z.object({
2205
- ref: import_zod13.z.string().describe("Element reference from the screen state"),
2206
- relativePosition: import_zod13.z.object({
2207
- x: import_zod13.z.number().describe("X offset in pixels from element top-left"),
2208
- y: import_zod13.z.number().describe("Y offset in pixels from element top-left")
2283
+ action("rightClick", "Right-click an element to open context menu (web-only)", import_zod14.z.object({
2284
+ ref: import_zod14.z.string().describe("Element reference from the screen state"),
2285
+ relativePosition: import_zod14.z.object({
2286
+ x: import_zod14.z.number().describe("X offset in pixels from element top-left"),
2287
+ y: import_zod14.z.number().describe("Y offset in pixels from element top-left")
2209
2288
  }).optional().describe("Omit for normal element-center interaction. Only provide when the user explicitly asks for an offset. Do not use { x: 0, y: 0 } for a normal button double-click/right-click; top-left is often intercepted."),
2210
- clickDelay: import_zod13.z.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
2289
+ clickDelay: import_zod14.z.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
2211
2290
  })),
2212
- action("waitForUrl", "Wait for the page URL to match a glob pattern (web only)", import_zod13.z.object({
2213
- pattern: import_zod13.z.string().describe('URL glob pattern. Use "**" for substring matching (e.g., "**/dashboard**"). Plain strings WITHOUT wildcards require EXACT URL match, not substring.')
2291
+ action("waitForUrl", "Wait for the page URL to match a glob pattern (web only)", import_zod14.z.object({
2292
+ pattern: import_zod14.z.string().describe('URL glob pattern. Use "**" for substring matching (e.g., "**/dashboard**"). Plain strings WITHOUT wildcards require EXACT URL match, not substring.')
2214
2293
  })),
2215
- action("fileUpload", "Upload one or more files to a file input element (web only)", import_zod13.z.object({
2216
- ref: import_zod13.z.string().describe("Element reference for the file input"),
2217
- files: import_zod13.z.array(import_zod13.z.string()).min(1).describe("Paths to files \u2014 relative to the test YAML file, or absolute paths. Missing files fail the action.")
2294
+ action("fileUpload", "Upload one or more files to a file input element (web only)", import_zod14.z.object({
2295
+ ref: import_zod14.z.string().describe("Element reference for the file input"),
2296
+ files: import_zod14.z.array(import_zod14.z.string()).min(1).describe("Paths to files \u2014 relative to the test YAML file, or absolute paths. Missing files fail the action.")
2218
2297
  })),
2219
- action("copy", "Copy the text content of an element to the system clipboard (web only, chromium only)", import_zod13.z.object({
2220
- ref: import_zod13.z.string().describe("Element reference whose text content to copy")
2298
+ action("copy", "Copy the text content of an element to the system clipboard (web only, chromium only)", import_zod14.z.object({
2299
+ ref: import_zod14.z.string().describe("Element reference whose text content to copy")
2221
2300
  }))
2222
2301
  ];
2223
2302
  function registerAllActions(registry) {
@@ -2631,9 +2710,9 @@ function buildExtractionPrompt(input, screenState) {
2631
2710
  }
2632
2711
 
2633
2712
  // src/agent/variables.ts
2634
- var ExtractionResultSchema = import_zod14.z.object({
2635
- value: import_zod14.z.string(),
2636
- reasoning: import_zod14.z.string()
2713
+ var ExtractionResultSchema = import_zod15.z.object({
2714
+ value: import_zod15.z.string(),
2715
+ reasoning: import_zod15.z.string()
2637
2716
  });
2638
2717
  var VariableStore = class {
2639
2718
  storage = /* @__PURE__ */ new Map();
@@ -3133,11 +3212,11 @@ var LLMPlanner = class {
3133
3212
 
3134
3213
  // src/agent/verifier.ts
3135
3214
  var import_ai5 = require("ai");
3136
- var import_zod15 = require("zod");
3137
- var VerificationResultSchema = import_zod15.z.object({
3138
- success: import_zod15.z.boolean().describe("Whether the step goal was accomplished"),
3139
- reasoning: import_zod15.z.string().describe("Explanation of why the step succeeded or failed"),
3140
- isAppError: import_zod15.z.boolean().describe(
3215
+ var import_zod16 = require("zod");
3216
+ var VerificationResultSchema = import_zod16.z.object({
3217
+ success: import_zod16.z.boolean().describe("Whether the step goal was accomplished"),
3218
+ reasoning: import_zod16.z.string().describe("Explanation of why the step succeeded or failed"),
3219
+ isAppError: import_zod16.z.boolean().describe(
3141
3220
  "Whether the page shows an application error (HTTP error, error toast, crash) vs the agent simply not accomplishing the goal"
3142
3221
  )
3143
3222
  });
@@ -3329,11 +3408,11 @@ async function createOpenAICompatibleModel(config) {
3329
3408
 
3330
3409
  // src/agent/asserter.ts
3331
3410
  var import_ai6 = require("ai");
3332
- var import_zod16 = require("zod");
3333
- var AssertionResultSchema = import_zod16.z.object({
3334
- passed: import_zod16.z.boolean(),
3335
- reasoning: import_zod16.z.string(),
3336
- evidence: import_zod16.z.string()
3411
+ var import_zod17 = require("zod");
3412
+ var AssertionResultSchema = import_zod17.z.object({
3413
+ passed: import_zod17.z.boolean(),
3414
+ reasoning: import_zod17.z.string(),
3415
+ evidence: import_zod17.z.string()
3337
3416
  });
3338
3417
  var AssertionEvaluator = class {
3339
3418
  async evaluate(assertion, screenState) {
@@ -4962,6 +5041,192 @@ var RUNTIME_IMAGE_MAP = {
4962
5041
  bash: "vostride/agent-qa-hook-runner-bash"
4963
5042
  };
4964
5043
 
5044
+ // src/auth-state/hook-env.ts
5045
+ var AUTH_STATE_HOOK_JSON_ENV = "AGENT_QA_AUTH_STATE_JSON";
5046
+ var AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV = "AGENT_QA_AUTH_STATE_STORAGE_STATE_PATH";
5047
+ var AUTH_STATE_HOOK_WORKSPACE_DIR = ".agent-qa-auth-state";
5048
+ var AUTH_STATE_HOOK_STORAGE_STATE_FILENAME = "storage-state.json";
5049
+ var AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH = `/workspace/${AUTH_STATE_HOOK_WORKSPACE_DIR}/${AUTH_STATE_HOOK_STORAGE_STATE_FILENAME}`;
5050
+ var RESERVED_AUTH_STATE_HOOK_ENV_KEYS = /* @__PURE__ */ new Set([
5051
+ AUTH_STATE_HOOK_JSON_ENV,
5052
+ AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV
5053
+ ]);
5054
+ function isReservedAuthStateHookEnvKey(key) {
5055
+ return RESERVED_AUTH_STATE_HOOK_ENV_KEYS.has(key);
5056
+ }
5057
+ function stripReservedAuthStateHookEnv(variables) {
5058
+ return Object.fromEntries(
5059
+ Object.entries(variables).filter(([key]) => !isReservedAuthStateHookEnvKey(key))
5060
+ );
5061
+ }
5062
+ function buildAuthStateHookEnv(authState, storageStatePath = AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH) {
5063
+ if (!authState) return {};
5064
+ const metadata = {
5065
+ version: authState.version,
5066
+ kind: authState.kind,
5067
+ target: authState.targetName,
5068
+ name: authState.stateName,
5069
+ capturedAt: authState.capturedAt,
5070
+ storageStatePath
5071
+ };
5072
+ return {
5073
+ [AUTH_STATE_HOOK_JSON_ENV]: JSON.stringify(metadata),
5074
+ [AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV]: storageStatePath
5075
+ };
5076
+ }
5077
+
5078
+ // src/auth-state/redaction.ts
5079
+ var AUTH_STATE_REDACTION_MARKER = "[auth state redacted]";
5080
+ var AUTH_STATE_JSON_KEY = normalizeKey(AUTH_STATE_HOOK_JSON_ENV);
5081
+ var AUTH_STATE_PATH_KEY = normalizeKey(AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV);
5082
+ var STRUCTURED_AUTH_STATE_KEYS = /* @__PURE__ */ new Set(["authstate", "auth_state"]);
5083
+ var STRUCTURED_PATH_KEYS = /* @__PURE__ */ new Set(["storagestatepath", AUTH_STATE_JSON_KEY, AUTH_STATE_PATH_KEY]);
5084
+ var AUTH_LIKE_KEY_RE = /(^|[_-])(token|cookie|authorization|csrf|session|bearer)([_-]|$)|^(token|cookie|authorization|csrf|session|bearer)$/i;
5085
+ function normalizeKey(key) {
5086
+ return key.replace(/[\s-]/g, "").toLowerCase();
5087
+ }
5088
+ function isBufferLike2(value) {
5089
+ return typeof Buffer !== "undefined" && Buffer.isBuffer(value);
5090
+ }
5091
+ function isRecord(value) {
5092
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !isBufferLike2(value);
5093
+ }
5094
+ function isStorageStateShape(value) {
5095
+ return isRecord(value) && Array.isArray(value.cookies) && Array.isArray(value.origins);
5096
+ }
5097
+ function isRuntimeAuthStateShape(value) {
5098
+ if (!isRecord(value)) return false;
5099
+ return typeof value.storageStatePath === "string" && typeof value.stateName === "string" && typeof value.targetName === "string";
5100
+ }
5101
+ function isAuthStateManagementMetadata(value) {
5102
+ if (!isRecord(value)) return false;
5103
+ if ("storageStatePath" in value || "payloadPath" in value || "metadataPath" in value) return false;
5104
+ return value.kind === "web" && typeof value.target === "string" && typeof value.name === "string" && typeof value.capturedAt === "string";
5105
+ }
5106
+ function isAuthStateManagementConfig(value) {
5107
+ if (!isRecord(value)) return false;
5108
+ const keys = Object.keys(value);
5109
+ return keys.length > 0 && keys.every((key) => key === "dir");
5110
+ }
5111
+ function isAuthLikeCredentialKey(key) {
5112
+ return AUTH_LIKE_KEY_RE.test(key);
5113
+ }
5114
+ function knownSensitiveStrings(context) {
5115
+ const values = /* @__PURE__ */ new Set();
5116
+ const hookStorageStatePath = context.hookStorageStatePath ?? AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH;
5117
+ for (const value of [
5118
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,
5119
+ hookStorageStatePath,
5120
+ context.storageStatePath,
5121
+ context.authState?.storageStatePath,
5122
+ context.hookJsonEnv
5123
+ ]) {
5124
+ if (typeof value === "string" && value.length > 0) values.add(value);
5125
+ }
5126
+ if (context.authState) {
5127
+ const env = buildAuthStateHookEnv(context.authState, hookStorageStatePath);
5128
+ const hookJson = env[AUTH_STATE_HOOK_JSON_ENV];
5129
+ if (hookJson) values.add(hookJson);
5130
+ }
5131
+ return [...values].sort((left, right) => right.length - left.length);
5132
+ }
5133
+ function tryParseJsonObject(value) {
5134
+ try {
5135
+ return JSON.parse(value);
5136
+ } catch {
5137
+ return void 0;
5138
+ }
5139
+ }
5140
+ function looksLikeStorageStateJson(value) {
5141
+ if (!value.includes('"cookies"') || !value.includes('"origins"')) return false;
5142
+ return isStorageStateShape(tryParseJsonObject(value));
5143
+ }
5144
+ function looksLikeAuthStateHookJson(value) {
5145
+ if (!value.includes('"storageStatePath"')) return false;
5146
+ const parsed = tryParseJsonObject(value);
5147
+ return isRecord(parsed) && typeof parsed.storageStatePath === "string" && (typeof parsed.name === "string" || typeof parsed.target === "string" || parsed.kind === "web");
5148
+ }
5149
+ function redactStructuredAuthStateText(value) {
5150
+ return value.replace(
5151
+ /(\bauthState\s*:\s*\n(?:[ \t]+[^\n]*\n)*?[ \t]+name\s*:\s*)[^\n#]+/gi,
5152
+ (_match, prefix) => `${prefix}${AUTH_STATE_REDACTION_MARKER}`
5153
+ ).replace(
5154
+ /(["']?(?:authState|auth_state|storageStatePath|AGENT_QA_AUTH_STATE_JSON|AGENT_QA_AUTH_STATE_STORAGE_STATE_PATH)["']?\s*[:=]\s*)(["'])[^"']*\2/gi,
5155
+ (_match, prefix, quote) => `${prefix}${quote}${AUTH_STATE_REDACTION_MARKER}${quote}`
5156
+ ).replace(
5157
+ /((?:authState|auth_state|storageStatePath|AGENT_QA_AUTH_STATE_JSON|AGENT_QA_AUTH_STATE_STORAGE_STATE_PATH)\s*[:=]\s*)[^\s,}\]]+/gi,
5158
+ (_match, prefix) => `${prefix}${AUTH_STATE_REDACTION_MARKER}`
5159
+ );
5160
+ }
5161
+ function redactStorageStateJsonLines(value) {
5162
+ return value.split(/\r?\n/).map((line) => {
5163
+ const trimmed = line.trim();
5164
+ return looksLikeStorageStateJson(trimmed) || looksLikeAuthStateHookJson(trimmed) ? AUTH_STATE_REDACTION_MARKER : line;
5165
+ }).join("\n");
5166
+ }
5167
+ function redactAuthStateString(value, context = {}) {
5168
+ if (value.includes(AUTH_STATE_HOOK_JSON_ENV) || value.includes(AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV) || looksLikeStorageStateJson(value.trim()) || looksLikeAuthStateHookJson(value.trim())) {
5169
+ return AUTH_STATE_REDACTION_MARKER;
5170
+ }
5171
+ if (value.includes("authState") || value.includes("auth_state")) {
5172
+ const parsed = tryParseJsonObject(value.trim());
5173
+ if (parsed !== void 0) {
5174
+ return JSON.stringify(redactAuthStateOnly(parsed, context));
5175
+ }
5176
+ }
5177
+ let redacted = redactStorageStateJsonLines(value);
5178
+ for (const sensitive of knownSensitiveStrings(context)) {
5179
+ redacted = redacted.split(sensitive).join(AUTH_STATE_REDACTION_MARKER);
5180
+ }
5181
+ return redactStructuredAuthStateText(redacted);
5182
+ }
5183
+ function shouldRedactKeyValue(key, value, context) {
5184
+ const normalized = normalizeKey(key);
5185
+ if (STRUCTURED_PATH_KEYS.has(normalized)) return true;
5186
+ if (STRUCTURED_AUTH_STATE_KEYS.has(normalized)) {
5187
+ if (typeof value === "string") return true;
5188
+ if (isAuthStateManagementConfig(value) || isAuthStateManagementMetadata(value)) return false;
5189
+ return true;
5190
+ }
5191
+ if (typeof value === "string" && value.startsWith("[secret")) return false;
5192
+ return context.redactAuthLikeKeys !== false && isAuthLikeCredentialKey(key);
5193
+ }
5194
+ function redactAuthStateOnly(value, context) {
5195
+ if (typeof value === "string") {
5196
+ return redactAuthStateString(value, context);
5197
+ }
5198
+ if (Array.isArray(value)) {
5199
+ return value.map((item) => redactAuthStateOnly(item, context));
5200
+ }
5201
+ if (isBufferLike2(value)) {
5202
+ return value;
5203
+ }
5204
+ if (value instanceof Error) {
5205
+ const redacted = new Error(redactAuthStateString(value.message, context));
5206
+ redacted.name = value.name;
5207
+ redacted.stack = value.stack ? redactAuthStateString(value.stack, context) : void 0;
5208
+ return redacted;
5209
+ }
5210
+ if (!isRecord(value)) {
5211
+ return value;
5212
+ }
5213
+ if (isStorageStateShape(value) || isRuntimeAuthStateShape(value)) {
5214
+ return AUTH_STATE_REDACTION_MARKER;
5215
+ }
5216
+ const result = {};
5217
+ for (const [key, item] of Object.entries(value)) {
5218
+ if (shouldRedactKeyValue(key, item, context)) {
5219
+ result[key] = AUTH_STATE_REDACTION_MARKER;
5220
+ } else {
5221
+ result[key] = redactAuthStateOnly(item, context);
5222
+ }
5223
+ }
5224
+ return result;
5225
+ }
5226
+ function redactAuthStateValue(value, context = {}) {
5227
+ return redactAuthStateOnly(redactSecretValue(value, context.secretRedactor), context);
5228
+ }
5229
+
4965
5230
  // src/hooks/sandbox-runner.ts
4966
5231
  var DEFAULT_DOCKER_BIN = "docker";
4967
5232
  function getHookCommand(runtime, entryFile) {
@@ -5005,12 +5270,18 @@ async function runHookInSandbox(hook, options = {}) {
5005
5270
  if (hook.packageFile) {
5006
5271
  await (0, import_promises4.cp)(hook.packageFile, (0, import_node_path4.join)(workDir, (0, import_node_path4.basename)(hook.packageFile)));
5007
5272
  }
5273
+ if (options.authState) {
5274
+ const authStateDir = (0, import_node_path4.join)(workDir, AUTH_STATE_HOOK_WORKSPACE_DIR);
5275
+ await (0, import_promises4.mkdir)(authStateDir, { recursive: true });
5276
+ await (0, import_promises4.cp)(options.authState.storageStatePath, (0, import_node_path4.join)(authStateDir, AUTH_STATE_HOOK_STORAGE_STATE_FILENAME));
5277
+ }
5008
5278
  const args = buildDockerArgs({
5009
5279
  image,
5010
5280
  workDir,
5011
5281
  hook,
5012
5282
  envVars: options.envVars,
5013
- secretStore: options.secretStore
5283
+ secretStore: options.secretStore,
5284
+ authState: options.authState
5014
5285
  });
5015
5286
  const cmd = getHookCommand(hook.runtime, (0, import_node_path4.basename)(hook.file));
5016
5287
  args.push(...cmd);
@@ -5021,9 +5292,15 @@ async function runHookInSandbox(hook, options = {}) {
5021
5292
  variables = parseEnvFile(envContent);
5022
5293
  } catch {
5023
5294
  }
5024
- variables = filterSecretVariables(variables, options.secretStore);
5025
- const redactedStdout = redactSecretValue(stdout, options.secretRedactor);
5026
- const redactedStderr = redactSecretValue(stderr, options.secretRedactor);
5295
+ variables = stripReservedAuthStateHookEnv(filterSecretVariables(variables, options.secretStore));
5296
+ const redactedStdout = redactAuthStateValue(stdout, {
5297
+ secretRedactor: options.secretRedactor,
5298
+ authState: options.authState
5299
+ });
5300
+ const redactedStderr = redactAuthStateValue(stderr, {
5301
+ secretRedactor: options.secretRedactor,
5302
+ authState: options.authState
5303
+ });
5027
5304
  const output = redactedStdout.trim();
5028
5305
  return {
5029
5306
  success: exitCode === 0,
@@ -5032,7 +5309,10 @@ async function runHookInSandbox(hook, options = {}) {
5032
5309
  stdout: redactedStdout,
5033
5310
  stderr: redactedStderr,
5034
5311
  duration: Date.now() - start,
5035
- error: exitCode !== 0 ? redactSecretValue(`Hook exited with code ${exitCode}: ${stderr}`, options.secretRedactor) : void 0
5312
+ error: exitCode !== 0 ? redactAuthStateValue(`Hook exited with code ${exitCode}: ${stderr}`, {
5313
+ secretRedactor: options.secretRedactor,
5314
+ authState: options.authState
5315
+ }) : void 0
5036
5316
  };
5037
5317
  } catch (err) {
5038
5318
  return {
@@ -5042,7 +5322,10 @@ async function runHookInSandbox(hook, options = {}) {
5042
5322
  stdout: "",
5043
5323
  stderr: "",
5044
5324
  duration: Date.now() - start,
5045
- error: redactSecretValue(err.message, options.secretRedactor)
5325
+ error: redactAuthStateValue(err.message, {
5326
+ secretRedactor: options.secretRedactor,
5327
+ authState: options.authState
5328
+ })
5046
5329
  };
5047
5330
  } finally {
5048
5331
  if (workDir) {
@@ -5077,6 +5360,10 @@ function buildDockerArgs(input) {
5077
5360
  input.secretStore?.forEachSecret((name, value) => {
5078
5361
  envVars[name] = value;
5079
5362
  });
5363
+ Object.assign(envVars, buildAuthStateHookEnv(
5364
+ input.authState,
5365
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH
5366
+ ));
5080
5367
  for (const [k, v] of Object.entries(envVars)) {
5081
5368
  args.push("-e", `${k}=${v}`);
5082
5369
  }
@@ -5742,7 +6029,9 @@ ${errorLines.join("\n")}`;
5742
6029
  videoPath,
5743
6030
  failureSummary: failureSummary || void 0
5744
6031
  };
5745
- await reporter?.onTestEnd(testResult);
6032
+ if (config.skipReporterOnTestEnd !== true) {
6033
+ await reporter?.onTestEnd(testResult);
6034
+ }
5746
6035
  return testResult;
5747
6036
  }
5748
6037
  function createTimeoutStepResult(name, scopeLabel, timeoutMs) {
@@ -7228,46 +7517,261 @@ function formatAppiumInstallGuidance() {
7228
7517
  return "Install Appium locally with `npm install -D appium` (or `pnpm add -D appium` / `yarn add -D appium`). If you prefer a machine-wide setup, use `npm install -g appium`.";
7229
7518
  }
7230
7519
 
7231
- // src/auth/store.ts
7520
+ // src/auth-state/resolver.ts
7521
+ var import_node_path9 = __toESM(require("path"), 1);
7522
+
7523
+ // src/runtime-paths.ts
7524
+ var DEFAULT_AGENT_QA_RUNTIME_DIR = ".agent-qa";
7525
+ var DEFAULT_AGENT_QA_ARTIFACTS_DIR = ".agent-qa/artifacts";
7526
+ var DEFAULT_AGENT_QA_CACHE_DIR = ".agent-qa/cache";
7527
+ var DEFAULT_AGENT_QA_AUTH_STATES_DIR = ".agent-qa/auth-states";
7528
+ var DEFAULT_AGENT_QA_SCREENSHOTS_DIR = ".agent-qa/artifacts/screenshots";
7529
+ var DEFAULT_AGENT_QA_VIDEOS_DIR = ".agent-qa/artifacts/videos";
7530
+ var DEFAULT_AGENT_QA_RUNS_DB_PATH = ".agent-qa/runs.db";
7531
+ var LEGACY_AGENT_QA_DASHBOARD_DB_PATH = ".agent-qa/dashboard.db";
7532
+
7533
+ // src/auth-state/resolver.ts
7534
+ var MOBILE_AUTH_STATE_ERROR = [
7535
+ "auth state is only supported for web targets.",
7536
+ "For native mobile, use use.mobile.appState: preserve when keeping app data between sessions.",
7537
+ "App-state preservation is broader than auth and does not export generic secure-storage/keychain tokens."
7538
+ ].join(" ");
7539
+ function assertInsideRoot(rootDir, filePath) {
7540
+ const relativePath = import_node_path9.default.relative(rootDir, filePath);
7541
+ if (!relativePath || relativePath.startsWith("..") || import_node_path9.default.isAbsolute(relativePath)) {
7542
+ throw new Error(`Resolved auth-state path escapes auth-state directory: ${filePath}`);
7543
+ }
7544
+ }
7545
+ function resolveAuthStateRoot(input) {
7546
+ const { configDir, authStateDir } = input;
7547
+ const configuredDir = authStateDir ?? DEFAULT_AGENT_QA_AUTH_STATES_DIR;
7548
+ if (configuredDir.trim().length === 0) {
7549
+ throw new Error("authState.dir must be a non-empty path");
7550
+ }
7551
+ return import_node_path9.default.isAbsolute(configuredDir) ? import_node_path9.default.resolve(configuredDir) : import_node_path9.default.resolve(configDir, configuredDir);
7552
+ }
7553
+ function resolveAuthStatePaths(input) {
7554
+ const targetName = TargetNameSchema.parse(input.targetName);
7555
+ const stateName = AuthStateNameSchema.parse(input.stateName);
7556
+ const platform = input.target?.platform ?? input.platform;
7557
+ if (platform !== "web") {
7558
+ throw new Error(MOBILE_AUTH_STATE_ERROR);
7559
+ }
7560
+ const rootDir = resolveAuthStateRoot({
7561
+ configDir: input.configDir,
7562
+ authStateDir: input.authStateDir
7563
+ });
7564
+ const targetDir = import_node_path9.default.join(rootDir, targetName);
7565
+ const payloadPath = import_node_path9.default.join(targetDir, `${stateName}.json`);
7566
+ const metadataPath = import_node_path9.default.join(targetDir, `${stateName}.meta.json`);
7567
+ assertInsideRoot(rootDir, payloadPath);
7568
+ assertInsideRoot(rootDir, metadataPath);
7569
+ return {
7570
+ targetName,
7571
+ stateName,
7572
+ rootDir,
7573
+ targetDir,
7574
+ payloadPath,
7575
+ metadataPath
7576
+ };
7577
+ }
7578
+
7579
+ // src/auth-state/store.ts
7580
+ var import_node_crypto3 = require("crypto");
7232
7581
  var import_promises7 = require("fs/promises");
7233
- var import_node_path9 = require("path");
7582
+ var import_node_path10 = __toESM(require("path"), 1);
7583
+ function assertMetadataMatches(paths, metadata) {
7584
+ if (metadata.target !== paths.targetName) {
7585
+ throw new Error(`Auth-state metadata target "${metadata.target}" does not match resolved target "${paths.targetName}"`);
7586
+ }
7587
+ if (metadata.name !== paths.stateName) {
7588
+ throw new Error(`Auth-state metadata name "${metadata.name}" does not match resolved state "${paths.stateName}"`);
7589
+ }
7590
+ }
7591
+ async function writeJsonAtomic(filePath, value) {
7592
+ const serialized = `${JSON.stringify(value, null, 2)}
7593
+ `;
7594
+ const directory = import_node_path10.default.dirname(filePath);
7595
+ const tempPath = import_node_path10.default.join(directory, `.${import_node_path10.default.basename(filePath)}.${process.pid}.${(0, import_node_crypto3.randomUUID)()}.tmp`);
7596
+ await (0, import_promises7.mkdir)(directory, { recursive: true });
7597
+ try {
7598
+ await (0, import_promises7.writeFile)(tempPath, serialized, { mode: 384 });
7599
+ await (0, import_promises7.rename)(tempPath, filePath);
7600
+ } catch (error) {
7601
+ await (0, import_promises7.rm)(tempPath, { force: true }).catch(() => void 0);
7602
+ throw error;
7603
+ }
7604
+ }
7605
+ async function readAuthStateMetadata(paths) {
7606
+ let raw;
7607
+ try {
7608
+ raw = await (0, import_promises7.readFile)(paths.metadataPath, "utf-8");
7609
+ } catch (error) {
7610
+ if (error.code === "ENOENT") {
7611
+ throw new Error(`Auth-state metadata not found: ${paths.metadataPath}`);
7612
+ }
7613
+ throw error;
7614
+ }
7615
+ let parsed;
7616
+ try {
7617
+ parsed = JSON.parse(raw);
7618
+ } catch {
7619
+ throw new Error(`Invalid auth-state metadata JSON: ${paths.metadataPath}`);
7620
+ }
7621
+ const result = AuthStateMetadataSchema.safeParse(parsed);
7622
+ if (!result.success) {
7623
+ throw new Error(`Invalid auth-state metadata: ${result.error.issues.map((issue) => issue.message).join("; ")}`);
7624
+ }
7625
+ assertMetadataMatches(paths, result.data);
7626
+ return result.data;
7627
+ }
7628
+ async function writeAuthStateFiles(paths, input) {
7629
+ const metadata = AuthStateMetadataSchema.parse(input.metadata);
7630
+ assertMetadataMatches(paths, metadata);
7631
+ await writeJsonAtomic(paths.payloadPath, input.payload);
7632
+ await writeJsonAtomic(paths.metadataPath, metadata);
7633
+ }
7634
+ async function listAuthStateMetadata(input) {
7635
+ const rootDir = resolveAuthStateRoot({
7636
+ configDir: input.configDir,
7637
+ authStateDir: input.authStateDir
7638
+ });
7639
+ const targetFilter = input.targetName ? TargetNameSchema.parse(input.targetName) : void 0;
7640
+ let targetEntries;
7641
+ try {
7642
+ targetEntries = await (0, import_promises7.readdir)(rootDir, { withFileTypes: true });
7643
+ } catch (error) {
7644
+ if (error.code === "ENOENT") {
7645
+ return [];
7646
+ }
7647
+ throw error;
7648
+ }
7649
+ const metadata = [];
7650
+ for (const targetEntry of targetEntries) {
7651
+ if (!targetEntry.isDirectory()) continue;
7652
+ const targetNameResult = TargetNameSchema.safeParse(targetEntry.name);
7653
+ if (!targetNameResult.success) continue;
7654
+ const targetName = targetNameResult.data;
7655
+ if (targetFilter && targetName !== targetFilter) continue;
7656
+ let stateEntries;
7657
+ const targetDir = import_node_path10.default.join(rootDir, targetName);
7658
+ try {
7659
+ stateEntries = await (0, import_promises7.readdir)(targetDir, { withFileTypes: true });
7660
+ } catch {
7661
+ continue;
7662
+ }
7663
+ for (const stateEntry of stateEntries) {
7664
+ if (!stateEntry.isFile() || !stateEntry.name.endsWith(".meta.json")) continue;
7665
+ const stateName = stateEntry.name.slice(0, -".meta.json".length);
7666
+ const paths = (() => {
7667
+ try {
7668
+ return resolveAuthStatePaths({
7669
+ configDir: input.configDir,
7670
+ authStateDir: input.authStateDir,
7671
+ targetName,
7672
+ stateName,
7673
+ platform: "web"
7674
+ });
7675
+ } catch {
7676
+ return null;
7677
+ }
7678
+ })();
7679
+ if (!paths) continue;
7680
+ try {
7681
+ const entry = await readAuthStateMetadata(paths);
7682
+ metadata.push(entry);
7683
+ } catch {
7684
+ continue;
7685
+ }
7686
+ }
7687
+ }
7688
+ return metadata.sort((a, b) => {
7689
+ const targetOrder = a.target.localeCompare(b.target);
7690
+ return targetOrder === 0 ? a.name.localeCompare(b.name) : targetOrder;
7691
+ });
7692
+ }
7693
+ async function removeAuthStateFiles(input) {
7694
+ const paths = resolveAuthStatePaths(input);
7695
+ await (0, import_promises7.rm)(paths.payloadPath, { force: true });
7696
+ await (0, import_promises7.rm)(paths.metadataPath, { force: true });
7697
+ }
7698
+ async function removeAuthStateTarget(input) {
7699
+ const paths = resolveAuthStatePaths({
7700
+ ...input,
7701
+ stateName: "placeholder"
7702
+ });
7703
+ await (0, import_promises7.rm)(paths.targetDir, { recursive: true, force: true });
7704
+ }
7705
+
7706
+ // src/auth-state/runtime.ts
7707
+ var import_promises8 = require("fs/promises");
7708
+ function createAuthStateReadError(targetName, stateName) {
7709
+ return new Error(
7710
+ `Auth state "${stateName}" for target "${targetName}" was not found or could not be read. Run agent-qa auth-state capture --target ${targetName} --name ${stateName}.`
7711
+ );
7712
+ }
7713
+ async function assertPayloadReadable(paths) {
7714
+ const raw = await (0, import_promises8.readFile)(paths.payloadPath, "utf-8");
7715
+ JSON.parse(raw);
7716
+ }
7717
+ async function resolveAuthStateForRun(input) {
7718
+ const paths = resolveAuthStatePaths(input);
7719
+ try {
7720
+ const metadata = await readAuthStateMetadata(paths);
7721
+ await assertPayloadReadable(paths);
7722
+ return {
7723
+ version: metadata.version,
7724
+ kind: metadata.kind,
7725
+ targetName: metadata.target,
7726
+ stateName: metadata.name,
7727
+ capturedAt: metadata.capturedAt,
7728
+ storageStatePath: paths.payloadPath
7729
+ };
7730
+ } catch {
7731
+ throw createAuthStateReadError(paths.targetName, paths.stateName);
7732
+ }
7733
+ }
7734
+
7735
+ // src/auth/store.ts
7736
+ var import_promises9 = require("fs/promises");
7737
+ var import_node_path11 = require("path");
7234
7738
  var import_node_os2 = require("os");
7235
7739
  function getAuthPath() {
7236
7740
  const xdg = process.env.XDG_DATA_HOME;
7237
- if (xdg) return (0, import_node_path9.join)(xdg, "agent-qa", "auth.json");
7238
- return (0, import_node_path9.join)((0, import_node_os2.homedir)(), ".agent-qa", "auth.json");
7741
+ if (xdg) return (0, import_node_path11.join)(xdg, "agent-qa", "auth.json");
7742
+ return (0, import_node_path11.join)((0, import_node_os2.homedir)(), ".agent-qa", "auth.json");
7239
7743
  }
7240
- async function readAuth(path5) {
7241
- const authPath = path5 ?? getAuthPath();
7744
+ async function readAuth(path7) {
7745
+ const authPath = path7 ?? getAuthPath();
7242
7746
  try {
7243
- const data = await (0, import_promises7.readFile)(authPath, "utf-8");
7747
+ const data = await (0, import_promises9.readFile)(authPath, "utf-8");
7244
7748
  return JSON.parse(data);
7245
7749
  } catch {
7246
7750
  return {};
7247
7751
  }
7248
7752
  }
7249
- async function writeAuth(provider, credential, path5) {
7250
- const authPath = path5 ?? getAuthPath();
7753
+ async function writeAuth(provider, credential, path7) {
7754
+ const authPath = path7 ?? getAuthPath();
7251
7755
  const store = await readAuth(authPath);
7252
7756
  store[provider] = credential;
7253
- await (0, import_promises7.mkdir)((0, import_node_path9.dirname)(authPath), { recursive: true });
7254
- await (0, import_promises7.writeFile)(authPath, JSON.stringify(store, null, 2), { mode: 384 });
7757
+ await (0, import_promises9.mkdir)((0, import_node_path11.dirname)(authPath), { recursive: true });
7758
+ await (0, import_promises9.writeFile)(authPath, JSON.stringify(store, null, 2), { mode: 384 });
7255
7759
  }
7256
- async function removeAuth(provider, path5) {
7257
- const authPath = path5 ?? getAuthPath();
7760
+ async function removeAuth(provider, path7) {
7761
+ const authPath = path7 ?? getAuthPath();
7258
7762
  const store = await readAuth(authPath);
7259
7763
  delete store[provider];
7260
7764
  if (Object.keys(store).length === 0) {
7261
7765
  try {
7262
- await (0, import_promises7.unlink)(authPath);
7766
+ await (0, import_promises9.unlink)(authPath);
7263
7767
  } catch {
7264
7768
  }
7265
7769
  return;
7266
7770
  }
7267
- await (0, import_promises7.writeFile)(authPath, JSON.stringify(store, null, 2), { mode: 384 });
7771
+ await (0, import_promises9.writeFile)(authPath, JSON.stringify(store, null, 2), { mode: 384 });
7268
7772
  }
7269
- async function getCredential(provider, path5) {
7270
- const store = await readAuth(path5);
7773
+ async function getCredential(provider, path7) {
7774
+ const store = await readAuth(path7);
7271
7775
  return store[provider] ?? null;
7272
7776
  }
7273
7777
 
@@ -7429,16 +7933,16 @@ async function resolveLLMAuth(configName, llmConfig, authPath) {
7429
7933
  // src/auth/plugin-loader.ts
7430
7934
  var import_node_module = require("module");
7431
7935
  var import_node_fs3 = require("fs");
7432
- var import_node_path10 = require("path");
7936
+ var import_node_path12 = require("path");
7433
7937
  var import_node_url = require("url");
7434
7938
  var import_meta = {};
7435
7939
  var loadedDeclarations = /* @__PURE__ */ new Set();
7436
7940
  function findPackageJson(packageName, baseDir) {
7437
- let current = (0, import_node_path10.resolve)(baseDir);
7941
+ let current = (0, import_node_path12.resolve)(baseDir);
7438
7942
  while (true) {
7439
- const candidate = (0, import_node_path10.resolve)(current, "node_modules", ...packageName.split("/"), "package.json");
7943
+ const candidate = (0, import_node_path12.resolve)(current, "node_modules", ...packageName.split("/"), "package.json");
7440
7944
  if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
7441
- const parent = (0, import_node_path10.dirname)(current);
7945
+ const parent = (0, import_node_path12.dirname)(current);
7442
7946
  if (parent === current) return null;
7443
7947
  current = parent;
7444
7948
  }
@@ -7466,7 +7970,7 @@ function resolvePackageImportFromBase(packageName, baseDir) {
7466
7970
  const pkg = JSON.parse((0, import_node_fs3.readFileSync)(packageJsonPath, "utf-8"));
7467
7971
  const target = exportTargetFromPackageJson(pkg);
7468
7972
  if (!target || !target.startsWith(".")) return null;
7469
- return (0, import_node_url.pathToFileURL)((0, import_node_path10.resolve)((0, import_node_path10.dirname)(packageJsonPath), target)).href;
7973
+ return (0, import_node_url.pathToFileURL)((0, import_node_path12.resolve)((0, import_node_path12.dirname)(packageJsonPath), target)).href;
7470
7974
  }
7471
7975
  function packageDeclarationValue(declaration) {
7472
7976
  return "package" in declaration && typeof declaration.package === "string" ? declaration.package.trim() : "";
@@ -7477,24 +7981,24 @@ function pathDeclarationValue(declaration) {
7477
7981
  function declarationKey(declaration, baseDir) {
7478
7982
  const packageName = packageDeclarationValue(declaration);
7479
7983
  if (packageName) return `package:${packageName}`;
7480
- return `path:${(0, import_node_path10.resolve)(baseDir, pathDeclarationValue(declaration))}`;
7984
+ return `path:${(0, import_node_path12.resolve)(baseDir, pathDeclarationValue(declaration))}`;
7481
7985
  }
7482
7986
  function resolveModuleSpecifier(declaration, baseDir) {
7483
7987
  const packageName = packageDeclarationValue(declaration);
7484
7988
  if (packageName) {
7485
7989
  const packageImport = resolvePackageImportFromBase(packageName, baseDir);
7486
7990
  if (packageImport) return packageImport;
7487
- const parentUrl = (0, import_node_url.pathToFileURL)((0, import_node_path10.resolve)(baseDir, "agent-qa.config.yaml")).href;
7991
+ const parentUrl = (0, import_node_url.pathToFileURL)((0, import_node_path12.resolve)(baseDir, "agent-qa.config.yaml")).href;
7488
7992
  try {
7489
7993
  const resolveImport = import_meta.resolve;
7490
7994
  return resolveImport(packageName, parentUrl);
7491
7995
  } catch {
7492
- const require4 = (0, import_node_module.createRequire)((0, import_node_path10.resolve)(baseDir, "agent-qa.config.yaml"));
7996
+ const require4 = (0, import_node_module.createRequire)((0, import_node_path12.resolve)(baseDir, "agent-qa.config.yaml"));
7493
7997
  return (0, import_node_url.pathToFileURL)(require4.resolve(packageName)).href;
7494
7998
  }
7495
7999
  }
7496
8000
  const pluginPath = pathDeclarationValue(declaration);
7497
- const absolutePath = (0, import_node_path10.isAbsolute)(pluginPath) ? pluginPath : (0, import_node_path10.resolve)(baseDir, pluginPath);
8001
+ const absolutePath = (0, import_node_path12.isAbsolute)(pluginPath) ? pluginPath : (0, import_node_path12.resolve)(baseDir, pluginPath);
7498
8002
  return (0, import_node_url.pathToFileURL)(absolutePath).href;
7499
8003
  }
7500
8004
  async function resolvePluginBundle(module2, source) {
@@ -7556,14 +8060,14 @@ function clearLoadedLLMAuthPluginModules() {
7556
8060
  }
7557
8061
 
7558
8062
  // src/auth/pkce.ts
7559
- var import_node_crypto3 = require("crypto");
8063
+ var import_node_crypto4 = require("crypto");
7560
8064
  function generatePKCE() {
7561
- const verifier = (0, import_node_crypto3.randomBytes)(32).toString("base64url");
7562
- const challenge = (0, import_node_crypto3.createHash)("sha256").update(verifier).digest("base64url");
8065
+ const verifier = (0, import_node_crypto4.randomBytes)(32).toString("base64url");
8066
+ const challenge = (0, import_node_crypto4.createHash)("sha256").update(verifier).digest("base64url");
7563
8067
  return { verifier, challenge };
7564
8068
  }
7565
8069
  function generateState() {
7566
- return (0, import_node_crypto3.randomBytes)(16).toString("hex");
8070
+ return (0, import_node_crypto4.randomBytes)(16).toString("hex");
7567
8071
  }
7568
8072
 
7569
8073
  // src/auth/fetch-wrapper.ts
@@ -7626,7 +8130,7 @@ function createAuthFetch(options) {
7626
8130
  }
7627
8131
 
7628
8132
  // src/logging/types.ts
7629
- var import_zod17 = require("zod");
8133
+ var import_zod18 = require("zod");
7630
8134
  var LOG_LEVEL_PRIORITY = {
7631
8135
  silent: 0,
7632
8136
  error: 1,
@@ -7634,53 +8138,53 @@ var LOG_LEVEL_PRIORITY = {
7634
8138
  info: 3,
7635
8139
  debug: 4
7636
8140
  };
7637
- var AgentLogDataSchema = import_zod17.z.object({
7638
- extractDom: import_zod17.z.boolean().optional(),
7639
- hasScreenshot: import_zod17.z.boolean().optional(),
7640
- duration: import_zod17.z.number().optional(),
7641
- elementCount: import_zod17.z.number().optional()
8141
+ var AgentLogDataSchema = import_zod18.z.object({
8142
+ extractDom: import_zod18.z.boolean().optional(),
8143
+ hasScreenshot: import_zod18.z.boolean().optional(),
8144
+ duration: import_zod18.z.number().optional(),
8145
+ elementCount: import_zod18.z.number().optional()
7642
8146
  });
7643
- var AdapterLogDataSchema = import_zod17.z.object({
7644
- actionType: import_zod17.z.string().optional(),
7645
- selector: import_zod17.z.string().optional(),
7646
- coordinates: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional(),
7647
- elementProperties: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional(),
7648
- duration: import_zod17.z.number().optional()
8147
+ var AdapterLogDataSchema = import_zod18.z.object({
8148
+ actionType: import_zod18.z.string().optional(),
8149
+ selector: import_zod18.z.string().optional(),
8150
+ coordinates: import_zod18.z.object({ x: import_zod18.z.number(), y: import_zod18.z.number() }).optional(),
8151
+ elementProperties: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional(),
8152
+ duration: import_zod18.z.number().optional()
7649
8153
  });
7650
- var CacheLogDataSchema = import_zod17.z.object({
7651
- operation: import_zod17.z.enum(["get", "set", "invalidate", "bypass", "batch-purge"]),
7652
- stepHash: import_zod17.z.string().optional(),
7653
- screenHash: import_zod17.z.string().optional(),
7654
- hit: import_zod17.z.boolean().optional(),
7655
- age: import_zod17.z.number().optional(),
7656
- entriesDeleted: import_zod17.z.number().optional()
8154
+ var CacheLogDataSchema = import_zod18.z.object({
8155
+ operation: import_zod18.z.enum(["get", "set", "invalidate", "bypass", "batch-purge"]),
8156
+ stepHash: import_zod18.z.string().optional(),
8157
+ screenHash: import_zod18.z.string().optional(),
8158
+ hit: import_zod18.z.boolean().optional(),
8159
+ age: import_zod18.z.number().optional(),
8160
+ entriesDeleted: import_zod18.z.number().optional()
7657
8161
  });
7658
- var PlannerLogDataSchema = import_zod17.z.object({
7659
- model: import_zod17.z.string().optional(),
7660
- promptTokens: import_zod17.z.number().optional(),
7661
- completionTokens: import_zod17.z.number().optional(),
7662
- latencyMs: import_zod17.z.number().optional(),
7663
- confidence: import_zod17.z.number().optional(),
7664
- actionType: import_zod17.z.string().optional()
8162
+ var PlannerLogDataSchema = import_zod18.z.object({
8163
+ model: import_zod18.z.string().optional(),
8164
+ promptTokens: import_zod18.z.number().optional(),
8165
+ completionTokens: import_zod18.z.number().optional(),
8166
+ latencyMs: import_zod18.z.number().optional(),
8167
+ confidence: import_zod18.z.number().optional(),
8168
+ actionType: import_zod18.z.string().optional()
7665
8169
  });
7666
- var HealerLogDataSchema = import_zod17.z.object({
7667
- strategy: import_zod17.z.string().optional(),
7668
- attempt: import_zod17.z.number().optional(),
7669
- maxAttempts: import_zod17.z.number().optional(),
7670
- stateDiffDetected: import_zod17.z.boolean().optional(),
7671
- success: import_zod17.z.boolean().optional()
8170
+ var HealerLogDataSchema = import_zod18.z.object({
8171
+ strategy: import_zod18.z.string().optional(),
8172
+ attempt: import_zod18.z.number().optional(),
8173
+ maxAttempts: import_zod18.z.number().optional(),
8174
+ stateDiffDetected: import_zod18.z.boolean().optional(),
8175
+ success: import_zod18.z.boolean().optional()
7672
8176
  });
7673
- var HookLogDataSchema = import_zod17.z.object({
7674
- hookName: import_zod17.z.string().optional(),
7675
- phase: import_zod17.z.enum(["setup", "teardown"]).optional(),
7676
- duration: import_zod17.z.number().optional(),
7677
- success: import_zod17.z.boolean().optional()
8177
+ var HookLogDataSchema = import_zod18.z.object({
8178
+ hookName: import_zod18.z.string().optional(),
8179
+ phase: import_zod18.z.enum(["setup", "teardown"]).optional(),
8180
+ duration: import_zod18.z.number().optional(),
8181
+ success: import_zod18.z.boolean().optional()
7678
8182
  });
7679
- var RunnerLogDataSchema = import_zod17.z.object({
7680
- stepIndex: import_zod17.z.number().optional(),
7681
- totalSteps: import_zod17.z.number().optional(),
7682
- testName: import_zod17.z.string().optional(),
7683
- variablesCaptured: import_zod17.z.number().optional()
8183
+ var RunnerLogDataSchema = import_zod18.z.object({
8184
+ stepIndex: import_zod18.z.number().optional(),
8185
+ totalSteps: import_zod18.z.number().optional(),
8186
+ testName: import_zod18.z.string().optional(),
8187
+ variablesCaptured: import_zod18.z.number().optional()
7684
8188
  });
7685
8189
  var LogSourceDataSchemas = {
7686
8190
  agent: AgentLogDataSchema,
@@ -7693,7 +8197,7 @@ var LogSourceDataSchemas = {
7693
8197
  };
7694
8198
 
7695
8199
  // src/logging/log-manager.ts
7696
- var import_node_crypto4 = require("crypto");
8200
+ var import_node_crypto5 = require("crypto");
7697
8201
 
7698
8202
  // src/logging/cli-formatter.ts
7699
8203
  var import_picocolors3 = __toESM(require("picocolors"), 1);
@@ -7735,13 +8239,13 @@ var LogManager = class {
7735
8239
  }
7736
8240
  log(level, source, message, data) {
7737
8241
  const entry = {
7738
- id: (0, import_node_crypto4.randomUUID)(),
8242
+ id: (0, import_node_crypto5.randomUUID)(),
7739
8243
  stepId: this.currentStepId,
7740
8244
  runId: this.runId,
7741
8245
  level,
7742
8246
  source,
7743
- message: redactSecretValue(message, this.redactor),
7744
- data: redactSecretValue(data ?? {}, this.redactor),
8247
+ message: redactAuthStateValue(message, { secretRedactor: this.redactor }),
8248
+ data: redactAuthStateValue(data ?? {}, { secretRedactor: this.redactor }),
7745
8249
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7746
8250
  };
7747
8251
  this.buffer.push(entry);
@@ -7885,7 +8389,7 @@ function mapMobileCapabilities(match, platform, credentials, opts) {
7885
8389
 
7886
8390
  // src/farm/browserstack.ts
7887
8391
  var import_node_fs4 = require("fs");
7888
- var import_node_path11 = require("path");
8392
+ var import_node_path13 = require("path");
7889
8393
  function isAbsoluteAppValue(value) {
7890
8394
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
7891
8395
  }
@@ -7904,7 +8408,7 @@ async function resolveBrowserStackApp(config) {
7904
8408
  });
7905
8409
  }
7906
8410
  const appBaseDir = config.appBaseDir ?? process.cwd();
7907
- const resolvedPath = (0, import_node_path11.resolve)(appBaseDir, config.app);
8411
+ const resolvedPath = (0, import_node_path13.resolve)(appBaseDir, config.app);
7908
8412
  const mustExist = isExplicitRelativePath(config.app);
7909
8413
  if (!(0, import_node_fs4.existsSync)(resolvedPath)) {
7910
8414
  if (mustExist) {
@@ -7920,7 +8424,7 @@ async function resolveBrowserStackApp(config) {
7920
8424
  }
7921
8425
  const auth = Buffer.from(`${config.credentials.username}:${config.credentials.accessKey}`).toString("base64");
7922
8426
  const form = new FormData();
7923
- form.append("file", new Blob([(0, import_node_fs4.readFileSync)(resolvedPath)]), (0, import_node_path11.basename)(resolvedPath));
8427
+ form.append("file", new Blob([(0, import_node_fs4.readFileSync)(resolvedPath)]), (0, import_node_path13.basename)(resolvedPath));
7924
8428
  let res;
7925
8429
  try {
7926
8430
  res = await fetch("https://api-cloud.browserstack.com/app-automate/upload", {
@@ -8057,8 +8561,8 @@ function registerAllProviders() {
8057
8561
  }
8058
8562
 
8059
8563
  // src/suite/runner.ts
8060
- var import_node_crypto5 = require("crypto");
8061
- var import_promises10 = require("fs/promises");
8564
+ var import_node_crypto6 = require("crypto");
8565
+ var import_promises12 = require("fs/promises");
8062
8566
 
8063
8567
  // src/hooks/orchestrator.ts
8064
8568
  async function runHooks(hooks, options = {}) {
@@ -8070,7 +8574,7 @@ async function runHooks(hooks, options = {}) {
8070
8574
  const result = await runHookInSandbox(hook, { ...options, envVars });
8071
8575
  results.set(hook.name, result);
8072
8576
  if (result.success) {
8073
- Object.assign(mergedVars, result.variables);
8577
+ Object.assign(mergedVars, stripReservedAuthStateHookEnv(result.variables));
8074
8578
  } else {
8075
8579
  for (const remaining of hooks.slice(hooks.indexOf(hook) + 1)) {
8076
8580
  results.set(remaining.name, {
@@ -8096,9 +8600,9 @@ async function runHooks(hooks, options = {}) {
8096
8600
 
8097
8601
  // src/memory/curator.ts
8098
8602
  var import_ai7 = require("ai");
8099
- var import_zod19 = require("zod");
8100
- var import_node_path13 = require("path");
8101
- var import_promises9 = require("fs/promises");
8603
+ var import_zod20 = require("zod");
8604
+ var import_node_path15 = require("path");
8605
+ var import_promises11 = require("fs/promises");
8102
8606
  init_observation_io();
8103
8607
 
8104
8608
  // src/memory/observation-id.ts
@@ -8106,31 +8610,31 @@ var import_agent_qa_ids6 = require("@vostride/agent-qa-ids");
8106
8610
 
8107
8611
  // src/memory/curator.ts
8108
8612
  init_security_scanner();
8109
- var CuratorActionSchema = import_zod19.z.discriminatedUnion("action", [
8110
- import_zod19.z.object({
8111
- action: import_zod19.z.literal("add"),
8112
- title: import_zod19.z.string().min(1),
8113
- content: import_zod19.z.string().min(1),
8114
- scope: import_zod19.z.enum(["product", "suite", "test"]).describe('Use "suite" only if a suite context was provided'),
8115
- reasoning: import_zod19.z.string()
8613
+ var CuratorActionSchema = import_zod20.z.discriminatedUnion("action", [
8614
+ import_zod20.z.object({
8615
+ action: import_zod20.z.literal("add"),
8616
+ title: import_zod20.z.string().min(1),
8617
+ content: import_zod20.z.string().min(1),
8618
+ scope: import_zod20.z.enum(["product", "suite", "test"]).describe('Use "suite" only if a suite context was provided'),
8619
+ reasoning: import_zod20.z.string()
8116
8620
  }),
8117
- import_zod19.z.object({
8118
- action: import_zod19.z.literal("update"),
8119
- observationId: import_zod19.z.string(),
8120
- reasoning: import_zod19.z.string()
8621
+ import_zod20.z.object({
8622
+ action: import_zod20.z.literal("update"),
8623
+ observationId: import_zod20.z.string(),
8624
+ reasoning: import_zod20.z.string()
8121
8625
  }),
8122
- import_zod19.z.object({
8123
- action: import_zod19.z.literal("deprecate"),
8124
- observationId: import_zod19.z.string(),
8125
- reasoning: import_zod19.z.string()
8626
+ import_zod20.z.object({
8627
+ action: import_zod20.z.literal("deprecate"),
8628
+ observationId: import_zod20.z.string(),
8629
+ reasoning: import_zod20.z.string()
8126
8630
  }),
8127
- import_zod19.z.object({
8128
- action: import_zod19.z.literal("noop"),
8129
- reasoning: import_zod19.z.string()
8631
+ import_zod20.z.object({
8632
+ action: import_zod20.z.literal("noop"),
8633
+ reasoning: import_zod20.z.string()
8130
8634
  })
8131
8635
  ]);
8132
- var CuratorResponseSchema = import_zod19.z.object({
8133
- decisions: import_zod19.z.array(CuratorActionSchema)
8636
+ var CuratorResponseSchema = import_zod20.z.object({
8637
+ decisions: import_zod20.z.array(CuratorActionSchema)
8134
8638
  });
8135
8639
  function emptyLog() {
8136
8640
  return { added: 0, confirmed: 0, deprecated: 0, deleted: 0, deltas: [], errors: [], curatorDuration: 0 };
@@ -8246,17 +8750,17 @@ function collectKnownObservationIds(injectedObservationIds, dedupMatches) {
8246
8750
  async function findObservationFile(memoryRoot, id) {
8247
8751
  const tiers = ["products", "suites", "tests"];
8248
8752
  for (const tier of tiers) {
8249
- const tierDir = (0, import_node_path13.join)(memoryRoot, tier);
8753
+ const tierDir = (0, import_node_path15.join)(memoryRoot, tier);
8250
8754
  let scopes;
8251
8755
  try {
8252
- scopes = await (0, import_promises9.readdir)(tierDir);
8756
+ scopes = await (0, import_promises11.readdir)(tierDir);
8253
8757
  } catch {
8254
8758
  continue;
8255
8759
  }
8256
8760
  for (const scope of scopes) {
8257
- const filePath = (0, import_node_path13.join)(tierDir, scope, `${id}.md`);
8761
+ const filePath = (0, import_node_path15.join)(tierDir, scope, `${id}.md`);
8258
8762
  try {
8259
- await (0, import_promises9.access)(filePath);
8763
+ await (0, import_promises11.access)(filePath);
8260
8764
  return { tier, scope, filePath };
8261
8765
  } catch {
8262
8766
  continue;
@@ -8267,7 +8771,7 @@ async function findObservationFile(memoryRoot, id) {
8267
8771
  }
8268
8772
  async function readAndParseObservation(filePath, id) {
8269
8773
  try {
8270
- const raw = await (0, import_promises9.readFile)(filePath, "utf-8");
8774
+ const raw = await (0, import_promises11.readFile)(filePath, "utf-8");
8271
8775
  const { data, error } = parseObservation(raw, `${id}.md`);
8272
8776
  if (!data || error) return null;
8273
8777
  return { data, raw };
@@ -8483,12 +8987,12 @@ ${userMessage}`;
8483
8987
  }
8484
8988
  if (ctx.suiteId && ctx.suiteContext) {
8485
8989
  try {
8486
- const suiteDir = (0, import_node_path13.join)(ctx.memoryRoot, "suites", ctx.suiteId);
8990
+ const suiteDir = (0, import_node_path15.join)(ctx.memoryRoot, "suites", ctx.suiteId);
8487
8991
  const files = await listObservations(suiteDir);
8488
8992
  for (const file of files) {
8489
8993
  try {
8490
- const filePath = (0, import_node_path13.join)(suiteDir, file);
8491
- const raw = await (0, import_promises9.readFile)(filePath, "utf-8");
8994
+ const filePath = (0, import_node_path15.join)(suiteDir, file);
8995
+ const raw = await (0, import_promises11.readFile)(filePath, "utf-8");
8492
8996
  const { data } = parseObservation(raw, file);
8493
8997
  if (!data || !("suite_snapshot" in data)) continue;
8494
8998
  const suiteObs = data;
@@ -8690,6 +9194,7 @@ async function runSuite(suite, testEntries, config) {
8690
9194
  const results = [];
8691
9195
  const reporter = config.reporters?.length ? new MultiReporter(config.reporters) : void 0;
8692
9196
  const suiteRunId = config.runId ?? process.env.AGENT_QA_SUITE_QUEUE_ID ?? generateRunId();
9197
+ let suiteSandboxOptions = config.sandboxOptions && config.platformConfig.authState ? { ...config.sandboxOptions, authState: config.platformConfig.authState } : config.sandboxOptions;
8693
9198
  const suiteArtifact = config.artifactContext?.artifact ?? config.artifactContext;
8694
9199
  await reporter?.onSuiteStart(suite, {
8695
9200
  runId: suiteRunId,
@@ -8725,7 +9230,7 @@ async function runSuite(suite, testEntries, config) {
8725
9230
  return { runId: suiteRunId, name: suite.name, status: "failed", tests: earlyResults, duration: duration2, failedAt: 0 };
8726
9231
  };
8727
9232
  let suiteHookVars = {};
8728
- if (suite.setup?.length && config.resolvedHooks && config.sandboxOptions) {
9233
+ if (suite.setup?.length && config.resolvedHooks && suiteSandboxOptions) {
8729
9234
  const hookDefs = [];
8730
9235
  let hookMissing = false;
8731
9236
  for (const hookId of suite.setup) {
@@ -8744,14 +9249,14 @@ async function runSuite(suite, testEntries, config) {
8744
9249
  if (config.inlineVars) Object.assign(envVars, config.inlineVars);
8745
9250
  if (config.cliVars) Object.assign(envVars, config.cliVars);
8746
9251
  const result = await runHooks(hookDefs, {
8747
- ...config.sandboxOptions,
9252
+ ...suiteSandboxOptions,
8748
9253
  secretStore: config.secretStore,
8749
9254
  secretRedactor: config.secretRedactor,
8750
- envVars: { ...config.sandboxOptions.envVars, ...envVars }
9255
+ envVars: { ...suiteSandboxOptions.envVars, ...envVars }
8751
9256
  });
8752
9257
  for (const [name, hr] of result.results) {
8753
9258
  const hookDef = hookDefs.find((hook) => hook.name === name);
8754
- const hookExecId = (0, import_node_crypto5.randomUUID)();
9259
+ const hookExecId = (0, import_node_crypto6.randomUUID)();
8755
9260
  await reporter?.onHookStart?.({ hookId: hookDef?.id, hookName: name, phase: "setup", hookExecutionId: hookExecId, runId: suiteRunId });
8756
9261
  await reporter?.onHookEnd?.({
8757
9262
  hookId: hookDef?.id,
@@ -8847,7 +9352,7 @@ async function runSuite(suite, testEntries, config) {
8847
9352
  });
8848
9353
  let perTestHookVars = {};
8849
9354
  let perTestSetupFailed = false;
8850
- if (patched.setup?.length && config.resolvedHooks && config.sandboxOptions) {
9355
+ if (patched.setup?.length && config.resolvedHooks && suiteSandboxOptions) {
8851
9356
  const hookDefs = [];
8852
9357
  let hookMissing = false;
8853
9358
  for (const hookId of patched.setup) {
@@ -8865,13 +9370,13 @@ async function runSuite(suite, testEntries, config) {
8865
9370
  if (config.cliVars) Object.assign(allVars, config.cliVars);
8866
9371
  Object.assign(allVars, suiteHookVars);
8867
9372
  for (const hookDef of hookDefs) {
8868
- const hookExecId = (0, import_node_crypto5.randomUUID)();
9373
+ const hookExecId = (0, import_node_crypto6.randomUUID)();
8869
9374
  await reporter?.onHookStart?.({ hookId: hookDef.id, hookName: hookDef.name, phase: "setup", hookExecutionId: hookExecId, runId: childRunId });
8870
9375
  const hookResult = await runHooks([hookDef], {
8871
- ...config.sandboxOptions,
9376
+ ...suiteSandboxOptions,
8872
9377
  secretStore: config.secretStore,
8873
9378
  secretRedactor: config.secretRedactor,
8874
- envVars: { ...config.sandboxOptions.envVars, ...allVars, ...perTestHookVars }
9379
+ envVars: { ...suiteSandboxOptions.envVars, ...allVars, ...perTestHookVars }
8875
9380
  });
8876
9381
  const hr = hookResult.results.get(hookDef.name);
8877
9382
  await reporter?.onHookEnd?.({
@@ -8913,7 +9418,7 @@ async function runSuite(suite, testEntries, config) {
8913
9418
  }
8914
9419
  let testFileContent = "";
8915
9420
  try {
8916
- testFileContent = await (0, import_promises10.readFile)(filePath, "utf-8");
9421
+ testFileContent = await (0, import_promises12.readFile)(filePath, "utf-8");
8917
9422
  } catch {
8918
9423
  }
8919
9424
  const memoryInitParams = memoryEnabled ? {
@@ -8948,7 +9453,7 @@ async function runSuite(suite, testEntries, config) {
8948
9453
  cliVars: config.cliVars,
8949
9454
  hookSetupVars: perTestHookVars,
8950
9455
  inlineHookDefs: config.resolvedHooks,
8951
- inlineHookSandboxOptions: config.sandboxOptions,
9456
+ inlineHookSandboxOptions: suiteSandboxOptions,
8952
9457
  secretStore: config.secretStore,
8953
9458
  secretRedactor: config.secretRedactor,
8954
9459
  accessibility: config.accessibility,
@@ -8964,11 +9469,11 @@ async function runSuite(suite, testEntries, config) {
8964
9469
  parentRunId: suiteRunId
8965
9470
  }, filePath);
8966
9471
  if (!result.runId) result.runId = childRunId;
8967
- if (patched.teardown?.length && config.resolvedHooks && config.sandboxOptions) {
9472
+ if (patched.teardown?.length && config.resolvedHooks && suiteSandboxOptions) {
8968
9473
  for (const hookId of patched.teardown) {
8969
9474
  const hook = config.resolvedHooks.get(hookId);
8970
9475
  if (!hook) continue;
8971
- const hookExecId = (0, import_node_crypto5.randomUUID)();
9476
+ const hookExecId = (0, import_node_crypto6.randomUUID)();
8972
9477
  try {
8973
9478
  await reporter?.onHookStart?.({ hookId: hook.id, hookName: hook.name, phase: "teardown", hookExecutionId: hookExecId, runId: childRunId });
8974
9479
  const teardownVars = {};
@@ -8976,10 +9481,10 @@ async function runSuite(suite, testEntries, config) {
8976
9481
  if (config.cliVars) Object.assign(teardownVars, config.cliVars);
8977
9482
  Object.assign(teardownVars, suiteHookVars, perTestHookVars);
8978
9483
  const hookResult = await runHooks([hook], {
8979
- ...config.sandboxOptions,
9484
+ ...suiteSandboxOptions,
8980
9485
  secretStore: config.secretStore,
8981
9486
  secretRedactor: config.secretRedactor,
8982
- envVars: { ...config.sandboxOptions.envVars, ...teardownVars }
9487
+ envVars: { ...suiteSandboxOptions.envVars, ...teardownVars }
8983
9488
  });
8984
9489
  const hr = hookResult.results.get(hook.name);
8985
9490
  await reporter?.onHookEnd?.({
@@ -9116,8 +9621,27 @@ async function runSuite(suite, testEntries, config) {
9116
9621
  }
9117
9622
  }
9118
9623
  }
9624
+ if (config.authStateCapture && results.length > 0 && results.every((result) => result.status === "passed")) {
9625
+ try {
9626
+ const capturedAuthState = await config.authStateCapture.capture();
9627
+ suiteSandboxOptions = config.sandboxOptions ? { ...config.sandboxOptions, authState: capturedAuthState } : config.sandboxOptions;
9628
+ } catch {
9629
+ const captureFailureResult = {
9630
+ runId: suiteRunId,
9631
+ name: "Auth state capture",
9632
+ filePath: "",
9633
+ status: "failed",
9634
+ steps: [],
9635
+ duration: 0,
9636
+ failureSummary: config.authStateCapture.failureSummary,
9637
+ metadata: { phase: "auth-state-capture" }
9638
+ };
9639
+ results.push(captureFailureResult);
9640
+ await reporter?.onTestEnd(captureFailureResult);
9641
+ }
9642
+ }
9119
9643
  } finally {
9120
- if (suite.teardown?.length && config.resolvedHooks && config.sandboxOptions) {
9644
+ if (suite.teardown?.length && config.resolvedHooks && suiteSandboxOptions) {
9121
9645
  const teardownVars = {};
9122
9646
  if (config.envFileVars) Object.assign(teardownVars, config.envFileVars);
9123
9647
  if (config.inlineVars) Object.assign(teardownVars, config.inlineVars);
@@ -9126,14 +9650,14 @@ async function runSuite(suite, testEntries, config) {
9126
9650
  for (const hookId of suite.teardown) {
9127
9651
  const hook = config.resolvedHooks.get(hookId);
9128
9652
  if (!hook) continue;
9129
- const hookExecId = (0, import_node_crypto5.randomUUID)();
9653
+ const hookExecId = (0, import_node_crypto6.randomUUID)();
9130
9654
  try {
9131
9655
  await reporter?.onHookStart?.({ hookId: hook.id, hookName: hook.name, phase: "teardown", hookExecutionId: hookExecId, runId: suiteRunId });
9132
9656
  const hookResult = await runHooks([hook], {
9133
- ...config.sandboxOptions,
9657
+ ...suiteSandboxOptions,
9134
9658
  secretStore: config.secretStore,
9135
9659
  secretRedactor: config.secretRedactor,
9136
- envVars: { ...config.sandboxOptions.envVars, ...teardownVars }
9660
+ envVars: { ...suiteSandboxOptions.envVars, ...teardownVars }
9137
9661
  });
9138
9662
  const hr = hookResult.results.get(hook.name);
9139
9663
  await reporter?.onHookEnd?.({
@@ -9192,20 +9716,20 @@ async function runSuite(suite, testEntries, config) {
9192
9716
  }
9193
9717
 
9194
9718
  // src/validation/validate.ts
9195
- var import_promises12 = require("fs/promises");
9719
+ var import_promises14 = require("fs/promises");
9196
9720
  var import_node_fs6 = require("fs");
9197
- var import_node_path17 = __toESM(require("path"), 1);
9721
+ var import_node_path19 = __toESM(require("path"), 1);
9198
9722
  var import_yaml5 = require("yaml");
9199
9723
  var import_glob2 = require("glob");
9200
9724
 
9201
9725
  // src/hooks/parser.ts
9202
- var import_promises11 = require("fs/promises");
9203
- var import_node_path14 = require("path");
9726
+ var import_promises13 = require("fs/promises");
9727
+ var import_node_path16 = require("path");
9204
9728
  var import_yaml4 = require("yaml");
9205
9729
  async function parseHooksFile(filePath) {
9206
9730
  let raw;
9207
9731
  try {
9208
- raw = await (0, import_promises11.readFile)(filePath, "utf-8");
9732
+ raw = await (0, import_promises13.readFile)(filePath, "utf-8");
9209
9733
  } catch (err) {
9210
9734
  return { hooks: [], errors: [`Failed to read hooks file: ${err.message}`] };
9211
9735
  }
@@ -9222,31 +9746,31 @@ async function parseHooksFile(filePath) {
9222
9746
  );
9223
9747
  return { hooks: [], errors };
9224
9748
  }
9225
- const dir = (0, import_node_path14.dirname)(filePath);
9749
+ const dir = (0, import_node_path16.dirname)(filePath);
9226
9750
  const hooks = result.data.hooks.map((h) => ({
9227
9751
  ...h,
9228
- file: (0, import_node_path14.resolve)(dir, h.file),
9229
- deps: h.deps.map((d) => (0, import_node_path14.resolve)(dir, d)),
9230
- packageFile: h.packageFile ? (0, import_node_path14.resolve)(dir, h.packageFile) : void 0
9752
+ file: (0, import_node_path16.resolve)(dir, h.file),
9753
+ deps: h.deps.map((d) => (0, import_node_path16.resolve)(dir, d)),
9754
+ packageFile: h.packageFile ? (0, import_node_path16.resolve)(dir, h.packageFile) : void 0
9231
9755
  }));
9232
9756
  return { hooks, errors: [] };
9233
9757
  }
9234
9758
 
9235
9759
  // src/utils/path-validation.ts
9236
- var import_node_path15 = __toESM(require("path"), 1);
9760
+ var import_node_path17 = __toESM(require("path"), 1);
9237
9761
  function isPathInsideDir(childPath, parentDir) {
9238
9762
  if (!childPath) return false;
9239
- const resolved = import_node_path15.default.resolve(parentDir, childPath);
9240
- const relative2 = import_node_path15.default.relative(parentDir, resolved);
9241
- return !!relative2 && !relative2.startsWith("..") && !import_node_path15.default.isAbsolute(relative2);
9763
+ const resolved = import_node_path17.default.resolve(parentDir, childPath);
9764
+ const relative2 = import_node_path17.default.relative(parentDir, resolved);
9765
+ return !!relative2 && !relative2.startsWith("..") && !import_node_path17.default.isAbsolute(relative2);
9242
9766
  }
9243
9767
 
9244
9768
  // src/workspace/workspace-paths.ts
9245
9769
  var import_node_fs5 = require("fs");
9246
- var import_node_path16 = __toESM(require("path"), 1);
9770
+ var import_node_path18 = __toESM(require("path"), 1);
9247
9771
  var import_glob = require("glob");
9248
9772
  function toForwardSlash(value) {
9249
- return value.split(import_node_path16.default.sep).join("/");
9773
+ return value.split(import_node_path18.default.sep).join("/");
9250
9774
  }
9251
9775
  function trimLeadingCurrentDir(value) {
9252
9776
  return toForwardSlash(value).replace(/^\.\//, "");
@@ -9265,16 +9789,16 @@ function assertNonEmptyString(value, key) {
9265
9789
  }
9266
9790
  function resolveWorkspaceScalar(configDir, key, configuredPath) {
9267
9791
  const value = assertNonEmptyString(configuredPath, key);
9268
- const absolutePath = import_node_path16.default.isAbsolute(value) ? import_node_path16.default.resolve(value) : import_node_path16.default.resolve(configDir, value);
9792
+ const absolutePath = import_node_path18.default.isAbsolute(value) ? import_node_path18.default.resolve(value) : import_node_path18.default.resolve(configDir, value);
9269
9793
  return {
9270
9794
  configuredPath: value,
9271
9795
  absolutePath,
9272
- workspaceRelativePath: trimLeadingCurrentDir(import_node_path16.default.relative(configDir, absolutePath))
9796
+ workspaceRelativePath: trimLeadingCurrentDir(import_node_path18.default.relative(configDir, absolutePath))
9273
9797
  };
9274
9798
  }
9275
9799
  function assertInsideWorkspace(configDir, absolutePath, filePath) {
9276
- const relativePath = import_node_path16.default.relative(configDir, absolutePath);
9277
- if (!relativePath || relativePath.startsWith("..") || import_node_path16.default.isAbsolute(relativePath)) {
9800
+ const relativePath = import_node_path18.default.relative(configDir, absolutePath);
9801
+ if (!relativePath || relativePath.startsWith("..") || import_node_path18.default.isAbsolute(relativePath)) {
9278
9802
  throw new Error(`Workspace file path escapes config directory: ${filePath}`);
9279
9803
  }
9280
9804
  return trimLeadingCurrentDir(relativePath);
@@ -9331,8 +9855,8 @@ function isIgnored(workspace, workspaceRelativePath) {
9331
9855
  return workspace.testPathIgnore.length > 0 && matchesAnyPattern(workspaceRelativePath, workspace.testPathIgnore);
9332
9856
  }
9333
9857
  function resolveWorkspacePaths(input) {
9334
- const configPath = import_node_path16.default.resolve(input.configPath);
9335
- const configDir = import_node_path16.default.dirname(configPath);
9858
+ const configPath = import_node_path18.default.resolve(input.configPath);
9859
+ const configDir = import_node_path18.default.dirname(configPath);
9336
9860
  const workspace = input.config.workspace;
9337
9861
  if (!workspace) {
9338
9862
  throw new Error("Missing required workspace config key: workspace");
@@ -9370,14 +9894,14 @@ async function discoverWorkspaceFiles(input) {
9370
9894
  absolute: true,
9371
9895
  nodir: true
9372
9896
  });
9373
- return matches.map((match) => import_node_path16.default.resolve(match)).map((absolutePath) => ({
9897
+ return matches.map((match) => import_node_path18.default.resolve(match)).map((absolutePath) => ({
9374
9898
  kind: input.kind,
9375
9899
  absolutePath,
9376
- workspaceRelativePath: trimLeadingCurrentDir(import_node_path16.default.relative(input.workspace.configDir, absolutePath))
9900
+ workspaceRelativePath: trimLeadingCurrentDir(import_node_path18.default.relative(input.workspace.configDir, absolutePath))
9377
9901
  })).sort((a, b) => a.workspaceRelativePath.localeCompare(b.workspaceRelativePath));
9378
9902
  }
9379
9903
  async function resolveWorkspaceFileTarget(input) {
9380
- const absolutePath = import_node_path16.default.isAbsolute(input.filePath) ? import_node_path16.default.resolve(input.filePath) : import_node_path16.default.resolve(input.workspace.configDir, input.filePath);
9904
+ const absolutePath = import_node_path18.default.isAbsolute(input.filePath) ? import_node_path18.default.resolve(input.filePath) : import_node_path18.default.resolve(input.workspace.configDir, input.filePath);
9381
9905
  const workspaceRelativePath = assertInsideWorkspace(input.workspace.configDir, absolutePath, input.filePath);
9382
9906
  if (!isWorkspacePathMatch({
9383
9907
  workspace: input.workspace,
@@ -9405,7 +9929,7 @@ async function validateConfig(configPath) {
9405
9929
  const diagnostics = [];
9406
9930
  let content;
9407
9931
  try {
9408
- content = await (0, import_promises12.readFile)(configPath, "utf-8");
9932
+ content = await (0, import_promises14.readFile)(configPath, "utf-8");
9409
9933
  } catch (err) {
9410
9934
  diagnostics.push({
9411
9935
  file: configPath,
@@ -9507,7 +10031,7 @@ function validateSuiteFile(filePath, content, basedir) {
9507
10031
  });
9508
10032
  continue;
9509
10033
  }
9510
- const resolved = import_node_path17.default.resolve(basedir, testPath);
10034
+ const resolved = import_node_path19.default.resolve(basedir, testPath);
9511
10035
  if (!(0, import_node_fs6.existsSync)(resolved)) {
9512
10036
  let line = 1;
9513
10037
  let column = 1;
@@ -9529,7 +10053,7 @@ function validateSuiteFile(filePath, content, basedir) {
9529
10053
  return diagnostics;
9530
10054
  }
9531
10055
  function validateFilename(filePath) {
9532
- const basename3 = import_node_path17.default.basename(filePath);
10056
+ const basename3 = import_node_path19.default.basename(filePath);
9533
10057
  if (!VALID_FILENAME_RE.test(basename3)) {
9534
10058
  return [{
9535
10059
  file: filePath,
@@ -9636,7 +10160,7 @@ async function validateFiles(filePaths, configPath, options = {}) {
9636
10160
  diagnostics.push(...validateFilename(filePath));
9637
10161
  let content;
9638
10162
  try {
9639
- content = await (0, import_promises12.readFile)(filePath, "utf-8");
10163
+ content = await (0, import_promises14.readFile)(filePath, "utf-8");
9640
10164
  } catch (err) {
9641
10165
  diagnostics.push({
9642
10166
  file: filePath,
@@ -9716,7 +10240,7 @@ async function validateProject(options = {}) {
9716
10240
  }
9717
10241
  filePaths = resolvedFiles;
9718
10242
  } else if (options.files && options.files.length > 0) {
9719
- filePaths = options.files.map((f) => import_node_path17.default.resolve(f));
10243
+ filePaths = options.files.map((f) => import_node_path19.default.resolve(f));
9720
10244
  } else if (options.workspace) {
9721
10245
  const [testFiles, suiteFiles] = await Promise.all([
9722
10246
  discoverWorkspaceFiles({ workspace: options.workspace, kind: "test" }),
@@ -9763,11 +10287,11 @@ async function validateProject(options = {}) {
9763
10287
  const { hooks } = await parseHooksFile(hooksFilePath);
9764
10288
  const hookIds = new Set(hooks.map((h) => h.id));
9765
10289
  for (const filePath of filePaths) {
9766
- const workspaceRelativePath = options.workspace ? import_node_path17.default.relative(options.workspace.configDir, filePath).split(import_node_path17.default.sep).join("/") : filePath;
10290
+ const workspaceRelativePath = options.workspace ? import_node_path19.default.relative(options.workspace.configDir, filePath).split(import_node_path19.default.sep).join("/") : filePath;
9767
10291
  const isWorkspaceFile = options.workspace ? isWorkspacePathMatch({ workspace: options.workspace, kind: isSuiteFile(filePath) ? "suite" : "test", workspaceRelativePath }) : true;
9768
10292
  if (!isWorkspaceFile) continue;
9769
10293
  try {
9770
- const content = await (0, import_promises12.readFile)(filePath, "utf-8");
10294
+ const content = await (0, import_promises14.readFile)(filePath, "utf-8");
9771
10295
  const parsed = (0, import_yaml5.parse)(content);
9772
10296
  if (parsed && typeof parsed === "object") {
9773
10297
  const setup = parsed.setup;
@@ -9864,27 +10388,27 @@ function warnIfOutOfBounds(coords, viewport, actionType) {
9864
10388
  }
9865
10389
 
9866
10390
  // src/hooks/migrate-hook-refs.ts
9867
- var import_promises13 = require("fs/promises");
9868
- var import_node_path18 = require("path");
10391
+ var import_promises15 = require("fs/promises");
10392
+ var import_node_path20 = require("path");
9869
10393
  var import_yaml6 = require("yaml");
9870
- var import_zod20 = require("zod");
10394
+ var import_zod21 = require("zod");
9871
10395
  var import_agent_qa_ids8 = require("@vostride/agent-qa-ids");
9872
10396
  var DEFAULT_CLEANUP_TARGETS = [
9873
10397
  ".agent-qa"
9874
10398
  ];
9875
10399
  var HOOK_INLINE_RE = /\{\{runHook:"([^"]+)"\}\}/g;
9876
- var MigratableHookDefinitionSchema = import_zod20.z.object({
9877
- id: import_zod20.z.string().optional(),
9878
- name: import_zod20.z.string().min(1),
9879
- runtime: import_zod20.z.enum(["node", "bun", "python", "bash"]),
9880
- file: import_zod20.z.string().min(1),
9881
- deps: import_zod20.z.array(import_zod20.z.string()).optional(),
9882
- packageFile: import_zod20.z.string().optional(),
9883
- timeout: import_zod20.z.string().min(1),
9884
- network: import_zod20.z.boolean().optional()
10400
+ var MigratableHookDefinitionSchema = import_zod21.z.object({
10401
+ id: import_zod21.z.string().optional(),
10402
+ name: import_zod21.z.string().min(1),
10403
+ runtime: import_zod21.z.enum(["node", "bun", "python", "bash"]),
10404
+ file: import_zod21.z.string().min(1),
10405
+ deps: import_zod21.z.array(import_zod21.z.string()).optional(),
10406
+ packageFile: import_zod21.z.string().optional(),
10407
+ timeout: import_zod21.z.string().min(1),
10408
+ network: import_zod21.z.boolean().optional()
9885
10409
  }).strict();
9886
- var MigratableHooksFileSchema = import_zod20.z.object({
9887
- hooks: import_zod20.z.array(MigratableHookDefinitionSchema).min(1)
10410
+ var MigratableHooksFileSchema = import_zod21.z.object({
10411
+ hooks: import_zod21.z.array(MigratableHookDefinitionSchema).min(1)
9888
10412
  }).strict();
9889
10413
  var HookReferenceMigrationError = class extends Error {
9890
10414
  errors;
@@ -9971,8 +10495,8 @@ function rewriteSteps(owner, filePath, hookNameToId, hookIds, errors) {
9971
10495
  return changed;
9972
10496
  }
9973
10497
  async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9974
- const resolvedConfigPath = configPath ? (0, import_node_path18.resolve)(configPath) : (0, import_node_path18.resolve)(workspaceDir, "agent-qa.config.yaml");
9975
- const rawConfig = await (0, import_promises13.readFile)(resolvedConfigPath, "utf-8");
10498
+ const resolvedConfigPath = configPath ? (0, import_node_path20.resolve)(configPath) : (0, import_node_path20.resolve)(workspaceDir, "agent-qa.config.yaml");
10499
+ const rawConfig = await (0, import_promises15.readFile)(resolvedConfigPath, "utf-8");
9976
10500
  const parsedConfig = (0, import_yaml6.parse)(rawConfig);
9977
10501
  const configResult = AgentQaConfigSchema.safeParse(parsedConfig);
9978
10502
  if (!configResult.success) {
@@ -9998,7 +10522,7 @@ async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9998
10522
  };
9999
10523
  }
10000
10524
  async function auditWorkspaceHookReferenceMigration(options) {
10001
- const workspaceDir = (0, import_node_path18.resolve)(options.workspaceDir);
10525
+ const workspaceDir = (0, import_node_path20.resolve)(options.workspaceDir);
10002
10526
  const errors = [];
10003
10527
  let context;
10004
10528
  try {
@@ -10016,7 +10540,7 @@ async function auditWorkspaceHookReferenceMigration(options) {
10016
10540
  }
10017
10541
  let parsedHooksFile;
10018
10542
  try {
10019
- parsedHooksFile = (0, import_yaml6.parse)(await (0, import_promises13.readFile)(context.hooksFilePath, "utf-8"));
10543
+ parsedHooksFile = (0, import_yaml6.parse)(await (0, import_promises15.readFile)(context.hooksFilePath, "utf-8"));
10020
10544
  } catch (error) {
10021
10545
  return {
10022
10546
  ok: false,
@@ -10061,15 +10585,15 @@ async function auditWorkspaceHookReferenceMigration(options) {
10061
10585
  const hookIds = new Set(Object.values(hookNameToId));
10062
10586
  if (hooksChanged) {
10063
10587
  rewriteFiles.push({
10064
- path: (0, import_node_path18.relative)(context.configDir, context.hooksFilePath),
10588
+ path: (0, import_node_path20.relative)(context.configDir, context.hooksFilePath),
10065
10589
  content: (0, import_yaml6.stringify)({ hooks: normalizedHooks })
10066
10590
  });
10067
10591
  }
10068
10592
  for (const relativePath of context.targetFiles) {
10069
- const absolutePath = (0, import_node_path18.resolve)(context.configDir, relativePath);
10593
+ const absolutePath = (0, import_node_path20.resolve)(context.configDir, relativePath);
10070
10594
  let parsedFile;
10071
10595
  try {
10072
- parsedFile = (0, import_yaml6.parse)(await (0, import_promises13.readFile)(absolutePath, "utf-8"));
10596
+ parsedFile = (0, import_yaml6.parse)(await (0, import_promises15.readFile)(absolutePath, "utf-8"));
10073
10597
  } catch (error) {
10074
10598
  errors.push(`${relativePath}: ${error.message}`);
10075
10599
  continue;
@@ -10107,14 +10631,14 @@ async function applyWorkspaceHookReferenceMigration(options) {
10107
10631
  if (!audit.ok) {
10108
10632
  throw new HookReferenceMigrationError(audit.errors);
10109
10633
  }
10110
- const workspaceDir = options.configPath ? (0, import_node_path18.dirname)((0, import_node_path18.resolve)(options.configPath)) : (0, import_node_path18.resolve)(options.workspaceDir);
10634
+ const workspaceDir = options.configPath ? (0, import_node_path20.dirname)((0, import_node_path20.resolve)(options.configPath)) : (0, import_node_path20.resolve)(options.workspaceDir);
10111
10635
  for (const rewrite of audit.rewriteFiles) {
10112
- const outputPath = (0, import_node_path18.resolve)(workspaceDir, rewrite.path);
10113
- await (0, import_promises13.mkdir)((0, import_node_path18.dirname)(outputPath), { recursive: true });
10114
- await (0, import_promises13.writeFile)(outputPath, rewrite.content, "utf-8");
10636
+ const outputPath = (0, import_node_path20.resolve)(workspaceDir, rewrite.path);
10637
+ await (0, import_promises15.mkdir)((0, import_node_path20.dirname)(outputPath), { recursive: true });
10638
+ await (0, import_promises15.writeFile)(outputPath, rewrite.content, "utf-8");
10115
10639
  }
10116
10640
  for (const cleanupTarget of audit.cleanupTargets) {
10117
- await (0, import_promises13.rm)((0, import_node_path18.resolve)(workspaceDir, cleanupTarget), { recursive: true, force: true });
10641
+ await (0, import_promises15.rm)((0, import_node_path20.resolve)(workspaceDir, cleanupTarget), { recursive: true, force: true });
10118
10642
  }
10119
10643
  return audit;
10120
10644
  }
@@ -10183,14 +10707,14 @@ var CircuitBreaker = class {
10183
10707
  var RUN_ARTIFACT_SCHEMA_VERSION = 1;
10184
10708
 
10185
10709
  // src/analytics/identity.ts
10186
- var import_promises17 = require("fs/promises");
10710
+ var import_promises19 = require("fs/promises");
10187
10711
  var import_node_os4 = require("os");
10188
- var import_node_path23 = require("path");
10712
+ var import_node_path25 = require("path");
10189
10713
  var import_id_agent = require("id-agent");
10190
10714
  var LOCAL_ANALYTICS_ID_PATTERN = /^u_([a-z]+-){9}[a-z]+$/;
10191
10715
  function getAnalyticsIdentityPath(env = process.env, homeDir = (0, import_node_os4.homedir)()) {
10192
- if (env.XDG_DATA_HOME) return (0, import_node_path23.join)(env.XDG_DATA_HOME, "agent-qa", "analytics.json");
10193
- return (0, import_node_path23.join)(homeDir, ".agent-qa", "analytics.json");
10716
+ if (env.XDG_DATA_HOME) return (0, import_node_path25.join)(env.XDG_DATA_HOME, "agent-qa", "analytics.json");
10717
+ return (0, import_node_path25.join)(homeDir, ".agent-qa", "analytics.json");
10194
10718
  }
10195
10719
  function generateAnalyticsUserId() {
10196
10720
  return (0, import_id_agent.idAgent)({ prefix: "u", words: 10 });
@@ -10206,28 +10730,28 @@ function parseAnalyticsIdentityStore(value) {
10206
10730
  needsMigration: typeof rawIsInternal !== "boolean"
10207
10731
  };
10208
10732
  }
10209
- async function readAnalyticsIdentityStore(path5) {
10210
- const identityPath = path5 ?? getAnalyticsIdentityPath();
10733
+ async function readAnalyticsIdentityStore(path7) {
10734
+ const identityPath = path7 ?? getAnalyticsIdentityPath();
10211
10735
  try {
10212
- const data = await (0, import_promises17.readFile)(identityPath, "utf-8");
10736
+ const data = await (0, import_promises19.readFile)(identityPath, "utf-8");
10213
10737
  const parsed = JSON.parse(data);
10214
10738
  return parseAnalyticsIdentityStore(parsed);
10215
10739
  } catch {
10216
10740
  return null;
10217
10741
  }
10218
10742
  }
10219
- async function readAnalyticsIdentity(path5) {
10220
- const parsed = await readAnalyticsIdentityStore(path5);
10743
+ async function readAnalyticsIdentity(path7) {
10744
+ const parsed = await readAnalyticsIdentityStore(path7);
10221
10745
  return parsed ? { distinctId: parsed.distinctId, is_internal: parsed.is_internal } : null;
10222
10746
  }
10223
- async function writeAnalyticsIdentity(distinctId, path5, isInternal = false) {
10224
- const identityPath = path5 ?? getAnalyticsIdentityPath();
10225
- await (0, import_promises17.mkdir)((0, import_node_path23.dirname)(identityPath), { recursive: true });
10226
- await (0, import_promises17.writeFile)(identityPath, JSON.stringify({
10747
+ async function writeAnalyticsIdentity(distinctId, path7, isInternal = false) {
10748
+ const identityPath = path7 ?? getAnalyticsIdentityPath();
10749
+ await (0, import_promises19.mkdir)((0, import_node_path25.dirname)(identityPath), { recursive: true });
10750
+ await (0, import_promises19.writeFile)(identityPath, JSON.stringify({
10227
10751
  distinctId,
10228
10752
  is_internal: isInternal
10229
10753
  }, null, 2), { mode: 384 });
10230
- await (0, import_promises17.chmod)(identityPath, 384);
10754
+ await (0, import_promises19.chmod)(identityPath, 384);
10231
10755
  }
10232
10756
  function resolveAnalyticsAgentProduct(env = process.env) {
10233
10757
  if (env.CLAUDECODE !== void 0 || env.CLAUDE_CODE_ENTRYPOINT !== void 0) return "claude_code";
@@ -10436,7 +10960,7 @@ async function flushAnalytics(options) {
10436
10960
  }
10437
10961
 
10438
10962
  // src/analytics/events.ts
10439
- var import_zod21 = require("zod");
10963
+ var import_zod22 = require("zod");
10440
10964
  var ANALYTICS_EVENT_NAMES = [
10441
10965
  "agent-qa.analytics.initialized",
10442
10966
  "agent-qa.analytics.test_event",
@@ -10513,34 +11037,34 @@ var ANALYTICS_FAILURE_CATEGORIES = [
10513
11037
  "unknown"
10514
11038
  ];
10515
11039
  var ANALYTICS_SUITE_EXECUTION_MODES = ["sequential", "parallel", "unknown"];
10516
- var AnalyticsEventNameSchema = import_zod21.z.enum(ANALYTICS_EVENT_NAMES);
10517
- var NonNegativeIntegerSchema = import_zod21.z.number().int().min(0);
10518
- var NonNegativeNumberSchema = import_zod21.z.number().min(0);
10519
- var AnalyticsBasePropertiesSchema = import_zod21.z.object({
10520
- agent_qa_version: import_zod21.z.string().min(1).optional(),
10521
- surface: import_zod21.z.enum(ANALYTICS_SURFACES).optional(),
10522
- runtime_context: import_zod21.z.enum(ANALYTICS_RUNTIME_CONTEXTS).optional(),
10523
- agent_product: import_zod21.z.enum(ANALYTICS_AGENT_PRODUCTS).optional(),
10524
- transport: import_zod21.z.enum(ANALYTICS_TRANSPORT_KINDS).optional(),
10525
- privacy_enabled: import_zod21.z.boolean().optional(),
10526
- posthog_key_present: import_zod21.z.boolean().optional(),
10527
- $process_person_profile: import_zod21.z.literal(false).optional()
11040
+ var AnalyticsEventNameSchema = import_zod22.z.enum(ANALYTICS_EVENT_NAMES);
11041
+ var NonNegativeIntegerSchema = import_zod22.z.number().int().min(0);
11042
+ var NonNegativeNumberSchema = import_zod22.z.number().min(0);
11043
+ var AnalyticsBasePropertiesSchema = import_zod22.z.object({
11044
+ agent_qa_version: import_zod22.z.string().min(1).optional(),
11045
+ surface: import_zod22.z.enum(ANALYTICS_SURFACES).optional(),
11046
+ runtime_context: import_zod22.z.enum(ANALYTICS_RUNTIME_CONTEXTS).optional(),
11047
+ agent_product: import_zod22.z.enum(ANALYTICS_AGENT_PRODUCTS).optional(),
11048
+ transport: import_zod22.z.enum(ANALYTICS_TRANSPORT_KINDS).optional(),
11049
+ privacy_enabled: import_zod22.z.boolean().optional(),
11050
+ posthog_key_present: import_zod22.z.boolean().optional(),
11051
+ $process_person_profile: import_zod22.z.literal(false).optional()
10528
11052
  }).strip();
10529
11053
  var AnalyticsRunPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10530
- trigger_source: import_zod21.z.enum(ANALYTICS_TRIGGER_SOURCES).optional(),
10531
- runner: import_zod21.z.enum(ANALYTICS_RUNNERS).optional(),
10532
- platform: import_zod21.z.enum(ANALYTICS_PLATFORMS).optional(),
10533
- status: import_zod21.z.enum(ANALYTICS_RUN_STATUSES).optional(),
11054
+ trigger_source: import_zod22.z.enum(ANALYTICS_TRIGGER_SOURCES).optional(),
11055
+ runner: import_zod22.z.enum(ANALYTICS_RUNNERS).optional(),
11056
+ platform: import_zod22.z.enum(ANALYTICS_PLATFORMS).optional(),
11057
+ status: import_zod22.z.enum(ANALYTICS_RUN_STATUSES).optional(),
10534
11058
  duration_ms: NonNegativeNumberSchema.optional(),
10535
- run_id: import_zod21.z.string().min(1).optional(),
10536
- parent_run_id: import_zod21.z.string().min(1).optional(),
10537
- test_id: import_zod21.z.string().min(1).optional(),
10538
- suite_id: import_zod21.z.string().min(1).optional(),
10539
- model_name: import_zod21.z.string().min(1).optional(),
10540
- provider: import_zod21.z.string().min(1).optional(),
10541
- provider_mode: import_zod21.z.string().min(1).optional(),
10542
- planner_model: import_zod21.z.string().min(1).optional(),
10543
- verifier_model: import_zod21.z.string().min(1).optional(),
11059
+ run_id: import_zod22.z.string().min(1).optional(),
11060
+ parent_run_id: import_zod22.z.string().min(1).optional(),
11061
+ test_id: import_zod22.z.string().min(1).optional(),
11062
+ suite_id: import_zod22.z.string().min(1).optional(),
11063
+ model_name: import_zod22.z.string().min(1).optional(),
11064
+ provider: import_zod22.z.string().min(1).optional(),
11065
+ provider_mode: import_zod22.z.string().min(1).optional(),
11066
+ planner_model: import_zod22.z.string().min(1).optional(),
11067
+ verifier_model: import_zod22.z.string().min(1).optional(),
10544
11068
  input_tokens: NonNegativeIntegerSchema.optional(),
10545
11069
  output_tokens: NonNegativeIntegerSchema.optional(),
10546
11070
  total_tokens: NonNegativeIntegerSchema.optional(),
@@ -10557,16 +11081,16 @@ var AnalyticsRunPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10557
11081
  hook_count: NonNegativeIntegerSchema.optional(),
10558
11082
  failed_hook_count: NonNegativeIntegerSchema.optional(),
10559
11083
  retry_count: NonNegativeIntegerSchema.optional(),
10560
- is_flaky: import_zod21.z.boolean().optional(),
10561
- cancelled: import_zod21.z.boolean().optional(),
10562
- timed_out: import_zod21.z.boolean().optional(),
10563
- failure_category: import_zod21.z.enum(ANALYTICS_FAILURE_CATEGORIES).optional(),
10564
- browser_name: import_zod21.z.string().min(1).optional(),
10565
- mobile_transport: import_zod21.z.string().min(1).optional(),
10566
- mobile_provider: import_zod21.z.string().min(1).optional(),
10567
- app_state: import_zod21.z.string().min(1).optional(),
10568
- execution_destination: import_zod21.z.string().min(1).optional(),
10569
- memory_enabled: import_zod21.z.boolean().optional(),
11084
+ is_flaky: import_zod22.z.boolean().optional(),
11085
+ cancelled: import_zod22.z.boolean().optional(),
11086
+ timed_out: import_zod22.z.boolean().optional(),
11087
+ failure_category: import_zod22.z.enum(ANALYTICS_FAILURE_CATEGORIES).optional(),
11088
+ browser_name: import_zod22.z.string().min(1).optional(),
11089
+ mobile_transport: import_zod22.z.string().min(1).optional(),
11090
+ mobile_provider: import_zod22.z.string().min(1).optional(),
11091
+ app_state: import_zod22.z.string().min(1).optional(),
11092
+ execution_destination: import_zod22.z.string().min(1).optional(),
11093
+ memory_enabled: import_zod22.z.boolean().optional(),
10570
11094
  memory_injected_observation_count: NonNegativeIntegerSchema.optional(),
10571
11095
  memory_curator_input_tokens: NonNegativeIntegerSchema.optional(),
10572
11096
  memory_curator_output_tokens: NonNegativeIntegerSchema.optional(),
@@ -10580,33 +11104,33 @@ var AnalyticsRunPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10580
11104
  suite_passed_count: NonNegativeIntegerSchema.optional(),
10581
11105
  suite_failed_count: NonNegativeIntegerSchema.optional(),
10582
11106
  suite_skipped_count: NonNegativeIntegerSchema.optional(),
10583
- suite_execution_mode: import_zod21.z.enum(ANALYTICS_SUITE_EXECUTION_MODES).optional(),
11107
+ suite_execution_mode: import_zod22.z.enum(ANALYTICS_SUITE_EXECUTION_MODES).optional(),
10584
11108
  mcp_tool_count: NonNegativeIntegerSchema.optional()
10585
11109
  }).strip();
10586
11110
  var AnalyticsDashboardOpenedPropertiesSchema = AnalyticsBasePropertiesSchema;
10587
11111
  var AnalyticsDashboardLiveModeStartedPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10588
- platform: import_zod21.z.enum(ANALYTICS_PLATFORMS).optional(),
10589
- entity_type: import_zod21.z.enum(["test", "suite", "unknown"]).optional()
11112
+ platform: import_zod22.z.enum(ANALYTICS_PLATFORMS).optional(),
11113
+ entity_type: import_zod22.z.enum(["test", "suite", "unknown"]).optional()
10590
11114
  }).strip();
10591
11115
  var AnalyticsDashboardEntityCreatedPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10592
- entity_type: import_zod21.z.enum(["test", "suite", "hook"]).optional(),
10593
- outcome: import_zod21.z.enum(ANALYTICS_DASHBOARD_OUTCOMES).optional()
11116
+ entity_type: import_zod22.z.enum(["test", "suite", "hook"]).optional(),
11117
+ outcome: import_zod22.z.enum(ANALYTICS_DASHBOARD_OUTCOMES).optional()
10594
11118
  }).strip();
10595
11119
  var AnalyticsMcpServerLifecyclePropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10596
- mcp_server_state: import_zod21.z.enum(ANALYTICS_MCP_SERVER_STATES).optional(),
10597
- mcp_transport: import_zod21.z.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
10598
- mcp_host_kind: import_zod21.z.enum(ANALYTICS_MCP_HOST_KINDS).optional(),
10599
- mcp_port_kind: import_zod21.z.enum(ANALYTICS_MCP_PORT_KINDS).optional(),
10600
- mcp_path_kind: import_zod21.z.enum(ANALYTICS_MCP_PATH_KINDS).optional()
11120
+ mcp_server_state: import_zod22.z.enum(ANALYTICS_MCP_SERVER_STATES).optional(),
11121
+ mcp_transport: import_zod22.z.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
11122
+ mcp_host_kind: import_zod22.z.enum(ANALYTICS_MCP_HOST_KINDS).optional(),
11123
+ mcp_port_kind: import_zod22.z.enum(ANALYTICS_MCP_PORT_KINDS).optional(),
11124
+ mcp_path_kind: import_zod22.z.enum(ANALYTICS_MCP_PATH_KINDS).optional()
10601
11125
  }).strip();
10602
11126
  var AnalyticsMcpToolInvokedPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10603
- tool_name: import_zod21.z.string().min(1).optional(),
10604
- mcp_tool_category: import_zod21.z.enum(ANALYTICS_MCP_TOOL_CATEGORIES).optional(),
10605
- mcp_tool_status: import_zod21.z.enum(ANALYTICS_MCP_TOOL_STATUSES).optional(),
11127
+ tool_name: import_zod22.z.string().min(1).optional(),
11128
+ mcp_tool_category: import_zod22.z.enum(ANALYTICS_MCP_TOOL_CATEGORIES).optional(),
11129
+ mcp_tool_status: import_zod22.z.enum(ANALYTICS_MCP_TOOL_STATUSES).optional(),
10606
11130
  duration_ms: NonNegativeNumberSchema.optional(),
10607
- mcp_error_category: import_zod21.z.enum(ANALYTICS_MCP_ERROR_CATEGORIES).optional(),
10608
- mcp_transport: import_zod21.z.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
10609
- run_id: import_zod21.z.string().min(1).optional()
11131
+ mcp_error_category: import_zod22.z.enum(ANALYTICS_MCP_ERROR_CATEGORIES).optional(),
11132
+ mcp_transport: import_zod22.z.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
11133
+ run_id: import_zod22.z.string().min(1).optional()
10610
11134
  }).strip();
10611
11135
  var AnalyticsEventPropertiesSchemaByName = {
10612
11136
  "agent-qa.analytics.initialized": AnalyticsRunPropertiesSchema,
@@ -10774,7 +11298,7 @@ function formatRunAttributesBlock(attributes) {
10774
11298
  }
10775
11299
 
10776
11300
  // src/analytics/run-reporter.ts
10777
- function isRecord(value) {
11301
+ function isRecord2(value) {
10778
11302
  return typeof value === "object" && value !== null && !Array.isArray(value);
10779
11303
  }
10780
11304
  function readString(value) {
@@ -10787,9 +11311,9 @@ function readBoolean(value) {
10787
11311
  return typeof value === "boolean" ? value : void 0;
10788
11312
  }
10789
11313
  function readNestedRecord(source, key) {
10790
- if (!isRecord(source)) return void 0;
11314
+ if (!isRecord2(source)) return void 0;
10791
11315
  const value = source[key];
10792
- return isRecord(value) ? value : void 0;
11316
+ return isRecord2(value) ? value : void 0;
10793
11317
  }
10794
11318
  function readAttributes(value) {
10795
11319
  try {
@@ -10833,13 +11357,13 @@ function normalizeSuiteExecutionMode(value) {
10833
11357
  return void 0;
10834
11358
  }
10835
11359
  function readArtifactSource(context) {
10836
- return isRecord(context?.artifact?.source) ? context?.artifact?.source : void 0;
11360
+ return isRecord2(context?.artifact?.source) ? context?.artifact?.source : void 0;
10837
11361
  }
10838
11362
  function readArtifactConfig(context) {
10839
- return isRecord(context?.artifact?.config) ? context?.artifact?.config : void 0;
11363
+ return isRecord2(context?.artifact?.config) ? context?.artifact?.config : void 0;
10840
11364
  }
10841
11365
  function readArtifactRuntime(context) {
10842
- const artifactRuntime = isRecord(context?.artifact?.runtime) ? context?.artifact?.runtime : void 0;
11366
+ const artifactRuntime = isRecord2(context?.artifact?.runtime) ? context?.artifact?.runtime : void 0;
10843
11367
  const configRuntime = readNestedRecord(readArtifactConfig(context), "runtime");
10844
11368
  return {
10845
11369
  ...configRuntime ?? {},
@@ -10947,14 +11471,14 @@ function collectMemoryMetrics(result, state) {
10947
11471
  if (state?.memoryInjectedObservationCount !== void 0) {
10948
11472
  properties.memory_injected_observation_count = state.memoryInjectedObservationCount;
10949
11473
  }
10950
- if (!isRecord(log)) return properties;
11474
+ if (!isRecord2(log)) return properties;
10951
11475
  properties.memory_enabled = properties.memory_enabled ?? true;
10952
11476
  properties.memory_added_count = readNumber(log.added);
10953
11477
  properties.memory_confirmed_count = readNumber(log.confirmed);
10954
11478
  properties.memory_deprecated_count = readNumber(log.deprecated);
10955
11479
  properties.memory_deleted_count = readNumber(log.deleted);
10956
11480
  properties.memory_error_count = Array.isArray(log.errors) ? log.errors.length : void 0;
10957
- const tokenUsage = isRecord(log.tokenUsage) ? log.tokenUsage : void 0;
11481
+ const tokenUsage = isRecord2(log.tokenUsage) ? log.tokenUsage : void 0;
10958
11482
  properties.memory_curator_input_tokens = readNumber(tokenUsage?.promptTokens);
10959
11483
  properties.memory_curator_output_tokens = readNumber(tokenUsage?.completionTokens);
10960
11484
  properties.memory_curator_total_tokens = readNumber(tokenUsage?.totalTokens);
@@ -11011,7 +11535,7 @@ var AnalyticsRunReporter = class {
11011
11535
  if (this.disabled) return;
11012
11536
  const runId = context?.runId ?? readString(context?.artifact?.runtime?.runId);
11013
11537
  if (!runId) return;
11014
- const runtime = isRecord(context?.artifact?.runtime) ? context?.artifact?.runtime : {};
11538
+ const runtime = isRecord2(context?.artifact?.runtime) ? context?.artifact?.runtime : {};
11015
11539
  this.suiteStates.set(runId, {
11016
11540
  runId,
11017
11541
  suiteId: readSuiteId(suite, context),
@@ -11057,7 +11581,7 @@ var AnalyticsRunReporter = class {
11057
11581
  }
11058
11582
  async captureTestResult(result) {
11059
11583
  const state = this.findStateForResult(result);
11060
- const resultMetadata = isRecord(result.metadata) ? result.metadata : void 0;
11584
+ const resultMetadata = isRecord2(result.metadata) ? result.metadata : void 0;
11061
11585
  const resultRuntime = readNestedRecord(resultMetadata, "runtime");
11062
11586
  const resultAttributes = readAttributes(resultMetadata?.attributes);
11063
11587
  const retryCount = typeof result.retryCount === "number" && result.retryCount >= 0 ? result.retryCount : void 0;
@@ -11137,15 +11661,6 @@ function createAnalyticsRunReporter(options = {}) {
11137
11661
  // src/index.ts
11138
11662
  init_sqlite();
11139
11663
 
11140
- // src/runtime-paths.ts
11141
- var DEFAULT_AGENT_QA_RUNTIME_DIR = ".agent-qa";
11142
- var DEFAULT_AGENT_QA_ARTIFACTS_DIR = ".agent-qa/artifacts";
11143
- var DEFAULT_AGENT_QA_CACHE_DIR = ".agent-qa/cache";
11144
- var DEFAULT_AGENT_QA_SCREENSHOTS_DIR = ".agent-qa/artifacts/screenshots";
11145
- var DEFAULT_AGENT_QA_VIDEOS_DIR = ".agent-qa/artifacts/videos";
11146
- var DEFAULT_AGENT_QA_RUNS_DB_PATH = ".agent-qa/runs.db";
11147
- var LEGACY_AGENT_QA_DASHBOARD_DB_PATH = ".agent-qa/dashboard.db";
11148
-
11149
11664
  // src/screenshot/align.ts
11150
11665
  var import_sharp3 = __toESM(require("sharp"), 1);
11151
11666
  async function alignToWindow(buffer, opts) {
@@ -11199,6 +11714,14 @@ function isMacPlatform() {
11199
11714
  ANDROID_ROLE_MAP,
11200
11715
  ATTR_RUNNER,
11201
11716
  ATTR_TRIGGER,
11717
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,
11718
+ AUTH_STATE_HOOK_JSON_ENV,
11719
+ AUTH_STATE_HOOK_STORAGE_STATE_FILENAME,
11720
+ AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV,
11721
+ AUTH_STATE_HOOK_WORKSPACE_DIR,
11722
+ AUTH_STATE_REDACTION_MARKER,
11723
+ AUTH_STATE_SCHEMA_VERSION,
11724
+ AUTH_STATE_SLUG_PATTERN,
11202
11725
  AccessibilityConfigSchema,
11203
11726
  ActionPlanSchema,
11204
11727
  AdapterLogDataSchema,
@@ -11209,6 +11732,10 @@ function isMacPlatform() {
11209
11732
  AssertionEvaluator,
11210
11733
  AssertionResultSchema,
11211
11734
  AuthPluginDeclarationSchema,
11735
+ AuthStateConfigSchema,
11736
+ AuthStateMetadataSchema,
11737
+ AuthStateNameSchema,
11738
+ AuthStateUseSchema,
11212
11739
  BaseObservationSchema,
11213
11740
  BrowserConfigSchema,
11214
11741
  CACHE_SCHEMA_VERSION,
@@ -11219,6 +11746,7 @@ function isMacPlatform() {
11219
11746
  ConsoleReporter,
11220
11747
  CuratorResponseSchema,
11221
11748
  DEFAULT_AGENT_QA_ARTIFACTS_DIR,
11749
+ DEFAULT_AGENT_QA_AUTH_STATES_DIR,
11222
11750
  DEFAULT_AGENT_QA_CACHE_DIR,
11223
11751
  DEFAULT_AGENT_QA_RUNS_DB_PATH,
11224
11752
  DEFAULT_AGENT_QA_RUNTIME_DIR,
@@ -11289,6 +11817,7 @@ function isMacPlatform() {
11289
11817
  SuiteDefinitionSchema,
11290
11818
  SuiteObservationSchema,
11291
11819
  SuiteTestEntrySchema,
11820
+ TargetNameSchema,
11292
11821
  TargetSchema,
11293
11822
  TestDefinitionSchema,
11294
11823
  TestMetaSchema,
@@ -11307,6 +11836,7 @@ function isMacPlatform() {
11307
11836
  browserstackProvider,
11308
11837
  buildAnalyticsEvent,
11309
11838
  buildAssertionPrompt,
11839
+ buildAuthStateHookEnv,
11310
11840
  buildExtractionPrompt,
11311
11841
  buildInternalRunAttributes,
11312
11842
  buildMemoryIndex,
@@ -11377,7 +11907,9 @@ function isMacPlatform() {
11377
11907
  isBetterSqlite3NodeGypSymlinkConflict,
11378
11908
  isMacPlatform,
11379
11909
  isPathInsideDir,
11910
+ isReservedAuthStateHookEnvKey,
11380
11911
  isWorkspacePathMatch,
11912
+ listAuthStateMetadata,
11381
11913
  listLLMAuthProviderPlugins,
11382
11914
  listObservations,
11383
11915
  listProviders,
@@ -11386,6 +11918,7 @@ function isMacPlatform() {
11386
11918
  mapMobileCapabilities,
11387
11919
  mapWebCapabilities,
11388
11920
  mergeRunAttributes,
11921
+ normalizeAuthStateUse,
11389
11922
  normalizeRole,
11390
11923
  parseAllTests,
11391
11924
  parseEnvFile,
@@ -11399,17 +11932,25 @@ function isMacPlatform() {
11399
11932
  parseTestFile,
11400
11933
  readAnalyticsIdentity,
11401
11934
  readAuth,
11935
+ readAuthStateMetadata,
11936
+ redactAuthStateString,
11937
+ redactAuthStateValue,
11402
11938
  redactSecretValue,
11403
11939
  registerAllProviders,
11404
11940
  registerLLMAuthProviderPlugin,
11405
11941
  registerLLMAuthProviderPlugins,
11406
11942
  registerProvider,
11407
11943
  removeAuth,
11944
+ removeAuthStateFiles,
11945
+ removeAuthStateTarget,
11408
11946
  resetAnalyticsServiceForTests,
11409
11947
  resolveAnalyticsAgentProduct,
11410
11948
  resolveAnalyticsIdentity,
11411
11949
  resolveAnalyticsStandardProperties,
11412
11950
  resolveAppiumExecutable,
11951
+ resolveAuthStateForRun,
11952
+ resolveAuthStatePaths,
11953
+ resolveAuthStateRoot,
11413
11954
  resolveBetterSqliteRebuildCommand,
11414
11955
  resolveFarmCredentials,
11415
11956
  resolveFileReferences,
@@ -11430,6 +11971,7 @@ function isMacPlatform() {
11430
11971
  shouldAblate,
11431
11972
  sortRunAttributesForDisplay,
11432
11973
  stripHookInline,
11974
+ stripReservedAuthStateHookEnv,
11433
11975
  toolCallToActionPlan,
11434
11976
  toolSchemaMiddleware,
11435
11977
  truncateScreenState,
@@ -11444,6 +11986,7 @@ function isMacPlatform() {
11444
11986
  warnIfOutOfBounds,
11445
11987
  writeAnalyticsIdentity,
11446
11988
  writeAuth,
11989
+ writeAuthStateFiles,
11447
11990
  writeObservation
11448
11991
  });
11449
11992
  //# sourceMappingURL=index.cjs.map