@vostride/agent-qa-core 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -23,50 +23,50 @@ var init_config = __esm({
23
23
  });
24
24
 
25
25
  // src/memory/schema.ts
26
- import { z as z18 } from "zod";
26
+ import { z as z19 } from "zod";
27
27
  import { isCanonicalObservationId, isObservationId } from "@vostride/agent-qa-ids";
28
28
  var ObservationIdSchema, CanonicalObservationIdSchema, ObservationSuiteSnapshotEntrySchema, BaseObservationSchema, SuiteObservationSchema, BaseObservationWriteSchema, SuiteObservationWriteSchema;
29
29
  var init_schema = __esm({
30
30
  "src/memory/schema.ts"() {
31
31
  "use strict";
32
- ObservationIdSchema = z18.string().refine((value) => isObservationId(value), {
32
+ ObservationIdSchema = z19.string().refine((value) => isObservationId(value), {
33
33
  message: "Observation ID must be obs_ followed by either 10 canonical words or a legacy 6-word body"
34
34
  });
35
- CanonicalObservationIdSchema = z18.string().refine((value) => isCanonicalObservationId(value), {
35
+ CanonicalObservationIdSchema = z19.string().refine((value) => isCanonicalObservationId(value), {
36
36
  message: "Observation ID must be obs_ followed by 10 id-agent words"
37
37
  });
38
- ObservationSuiteSnapshotEntrySchema = z18.object({
39
- test: z18.string(),
40
- id: z18.string()
38
+ ObservationSuiteSnapshotEntrySchema = z19.object({
39
+ test: z19.string(),
40
+ id: z19.string()
41
41
  }).strict();
42
- BaseObservationSchema = z18.object({
42
+ BaseObservationSchema = z19.object({
43
43
  id: ObservationIdSchema,
44
- title: z18.string().min(1),
45
- content: z18.string().min(1),
46
- trust: z18.number().min(0).max(1),
47
- created: z18.string().datetime(),
48
- last_confirmed: z18.string().datetime(),
49
- confirmed_count: z18.number().int().min(0),
50
- contradicted_count: z18.number().int().min(0),
51
- source_test: z18.string().min(1)
44
+ title: z19.string().min(1),
45
+ content: z19.string().min(1),
46
+ trust: z19.number().min(0).max(1),
47
+ created: z19.string().datetime(),
48
+ last_confirmed: z19.string().datetime(),
49
+ confirmed_count: z19.number().int().min(0),
50
+ contradicted_count: z19.number().int().min(0),
51
+ source_test: z19.string().min(1)
52
52
  }).strip();
53
53
  SuiteObservationSchema = BaseObservationSchema.extend({
54
- position: z18.number().int().min(0),
55
- suite_snapshot: z18.array(ObservationSuiteSnapshotEntrySchema).min(1)
54
+ position: z19.number().int().min(0),
55
+ suite_snapshot: z19.array(ObservationSuiteSnapshotEntrySchema).min(1)
56
56
  }).strip();
57
57
  BaseObservationWriteSchema = BaseObservationSchema.extend({
58
58
  id: CanonicalObservationIdSchema
59
59
  }).strip();
60
60
  SuiteObservationWriteSchema = BaseObservationWriteSchema.extend({
61
- position: z18.number().int().min(0),
62
- suite_snapshot: z18.array(ObservationSuiteSnapshotEntrySchema).min(1)
61
+ position: z19.number().int().min(0),
62
+ suite_snapshot: z19.array(ObservationSuiteSnapshotEntrySchema).min(1)
63
63
  }).strip();
64
64
  }
65
65
  });
66
66
 
67
67
  // src/memory/observation-io.ts
68
68
  import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
69
- import { mkdir as mkdir5, writeFile as writeFile5, readdir as readdir2 } from "fs/promises";
69
+ import { mkdir as mkdir6, writeFile as writeFile6, readdir as readdir3 } from "fs/promises";
70
70
  import { join as join5, resolve as resolve4, sep } from "path";
71
71
  function toObservationFrontmatter(data) {
72
72
  const { content, ...frontmatter } = data;
@@ -74,7 +74,7 @@ function toObservationFrontmatter(data) {
74
74
  }
75
75
  async function ensureMemoryDirs(root) {
76
76
  await Promise.all(
77
- MEMORY_TIERS.map((tier) => mkdir5(join5(root, tier), { recursive: true }))
77
+ MEMORY_TIERS.map((tier) => mkdir6(join5(root, tier), { recursive: true }))
78
78
  );
79
79
  }
80
80
  async function writeObservation(root, tier, scope, data) {
@@ -87,13 +87,13 @@ async function writeObservation(root, tier, scope, data) {
87
87
  const schema = "position" in data ? SuiteObservationWriteSchema : BaseObservationWriteSchema;
88
88
  const validated = schema.parse(data);
89
89
  const frontmatter = toObservationFrontmatter(validated);
90
- await mkdir5(dir, { recursive: true });
90
+ await mkdir6(dir, { recursive: true });
91
91
  const content = `---
92
92
  ${stringifyYaml({ ...frontmatter }, { lineWidth: 0 })}---
93
93
  ${validated.content}
94
94
  `;
95
95
  const filePath = join5(dir, `${data.id}.md`);
96
- await writeFile5(filePath, content, "utf-8");
96
+ await writeFile6(filePath, content, "utf-8");
97
97
  return filePath;
98
98
  }
99
99
  function parseObservation(content, filename) {
@@ -130,7 +130,7 @@ function parseObservation(content, filename) {
130
130
  async function listObservations(dir) {
131
131
  let entries;
132
132
  try {
133
- entries = await readdir2(dir);
133
+ entries = await readdir3(dir);
134
134
  } catch (e) {
135
135
  if (e instanceof Error && "code" in e && e.code === "ENOENT") {
136
136
  return [];
@@ -359,19 +359,19 @@ function loadBetterSqlite3() {
359
359
  sqliteConstructor = require2("better-sqlite3");
360
360
  return sqliteConstructor;
361
361
  }
362
- function openBetterSqlite3Database(path5) {
362
+ function openBetterSqlite3Database(path7) {
363
363
  const Database = loadBetterSqlite3();
364
- return new Database(path5);
364
+ return new Database(path7);
365
365
  }
366
- function createBetterSqlite3Database(path5) {
366
+ function createBetterSqlite3Database(path7) {
367
367
  try {
368
- return openBetterSqlite3Database(path5);
368
+ return openBetterSqlite3Database(path7);
369
369
  } catch (error) {
370
370
  if (!isBetterSqlite3NativeModuleError(error)) {
371
371
  throw error;
372
372
  }
373
373
  rebuildBetterSqlite3ForCurrentRuntime(error);
374
- return openBetterSqlite3Database(path5);
374
+ return openBetterSqlite3Database(path7);
375
375
  }
376
376
  }
377
377
  var require2, sqliteConstructor, rebuildAttempted, rebuildFailureMessage;
@@ -386,7 +386,7 @@ var init_sqlite = __esm({
386
386
  });
387
387
 
388
388
  // src/memory/memory-index.ts
389
- import { readFile as readFile12 } from "fs/promises";
389
+ import { readFile as readFile14 } from "fs/promises";
390
390
  import { join as join8 } from "path";
391
391
  function validatePathComponent(value) {
392
392
  return !/\.\./.test(value) && !/[/\\]/.test(value) && !/\0/.test(value);
@@ -437,7 +437,7 @@ async function buildMemoryIndex(params) {
437
437
  const filePath = join8(dirPath, filename);
438
438
  let raw;
439
439
  try {
440
- raw = await readFile12(filePath, "utf-8");
440
+ raw = await readFile14(filePath, "utf-8");
441
441
  } catch {
442
442
  continue;
443
443
  }
@@ -484,7 +484,7 @@ var init_xml_escape = __esm({
484
484
  });
485
485
 
486
486
  // src/memory/lock-manager.ts
487
- import { writeFile as writeFile7, readFile as readFile13, unlink as unlink3, mkdir as mkdir7 } from "fs/promises";
487
+ import { writeFile as writeFile8, readFile as readFile15, unlink as unlink3, mkdir as mkdir8 } from "fs/promises";
488
488
  import { dirname as dirname12 } from "path";
489
489
  var LockManager;
490
490
  var init_lock_manager = __esm({
@@ -498,17 +498,17 @@ var init_lock_manager = __esm({
498
498
  this.timeout = timeout;
499
499
  }
500
500
  async acquire() {
501
- await mkdir7(dirname12(this.lockPath), { recursive: true });
501
+ await mkdir8(dirname12(this.lockPath), { recursive: true });
502
502
  const deadline = Date.now() + this.timeout;
503
503
  while (Date.now() < deadline) {
504
504
  try {
505
- await writeFile7(
505
+ await writeFile8(
506
506
  this.lockPath,
507
507
  JSON.stringify({ pid: process.pid, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
508
508
  { flag: "wx" }
509
509
  );
510
510
  try {
511
- const raw = await readFile13(this.lockPath, "utf-8");
511
+ const raw = await readFile15(this.lockPath, "utf-8");
512
512
  const { pid } = JSON.parse(raw);
513
513
  if (pid === process.pid) return;
514
514
  } catch {
@@ -532,7 +532,7 @@ var init_lock_manager = __esm({
532
532
  async release() {
533
533
  let raw;
534
534
  try {
535
- raw = await readFile13(this.lockPath, "utf-8");
535
+ raw = await readFile15(this.lockPath, "utf-8");
536
536
  } catch (err) {
537
537
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
538
538
  return;
@@ -555,7 +555,7 @@ var init_lock_manager = __esm({
555
555
  async isStale() {
556
556
  let raw;
557
557
  try {
558
- raw = await readFile13(this.lockPath, "utf-8");
558
+ raw = await readFile15(this.lockPath, "utf-8");
559
559
  } catch (err) {
560
560
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
561
561
  return true;
@@ -867,7 +867,7 @@ ${lines.join("\n")}
867
867
  });
868
868
 
869
869
  // src/schema/config-schema.ts
870
- import { z as z7 } from "zod";
870
+ import { z as z8 } from "zod";
871
871
 
872
872
  // src/schema/workspace-schema.ts
873
873
  import { z } from "zod";
@@ -1037,6 +1037,9 @@ var CacheConfigSchema = z3.object({
1037
1037
  dir: z3.string(),
1038
1038
  ttl: DurationString
1039
1039
  }).strict();
1040
+ var AuthStateConfigSchema = z3.object({
1041
+ dir: z3.string().trim().min(1)
1042
+ }).strict();
1040
1043
  var LoggingConfigSchema = z3.object({
1041
1044
  level: z3.enum(["silent", "error", "warn", "info", "debug"])
1042
1045
  }).strict();
@@ -1071,6 +1074,7 @@ var ServicesSchema = z3.object({
1071
1074
  dashboard: DashboardConfigSchema.optional(),
1072
1075
  mcp: McpConfigSchema.optional(),
1073
1076
  cache: CacheConfigSchema.optional(),
1077
+ authState: AuthStateConfigSchema.optional(),
1074
1078
  logging: LoggingConfigSchema.optional(),
1075
1079
  recording: RecordingConfigSchema.optional(),
1076
1080
  accessibility: AccessibilityConfigSchema.optional(),
@@ -1078,34 +1082,56 @@ var ServicesSchema = z3.object({
1078
1082
  }).strict();
1079
1083
 
1080
1084
  // src/schema/registry-schema.ts
1085
+ import { z as z5 } from "zod";
1086
+
1087
+ // src/auth-state/schema.ts
1081
1088
  import { z as z4 } from "zod";
1089
+ var AUTH_STATE_SCHEMA_VERSION = 1;
1090
+ var AUTH_STATE_SLUG_PATTERN = /^[a-z][a-z0-9-]*[a-z0-9]$/;
1091
+ var AuthStateNameSchema = z4.string().regex(
1092
+ AUTH_STATE_SLUG_PATTERN,
1093
+ "Auth state name must match ^[a-z][a-z0-9-]*[a-z0-9]$"
1094
+ );
1095
+ var TargetNameSchema = z4.string().regex(
1096
+ AUTH_STATE_SLUG_PATTERN,
1097
+ "Target name must match ^[a-z][a-z0-9-]*[a-z0-9]$"
1098
+ );
1099
+ var AuthStateMetadataSchema = z4.object({
1100
+ version: z4.literal(AUTH_STATE_SCHEMA_VERSION),
1101
+ kind: z4.literal("web"),
1102
+ target: TargetNameSchema,
1103
+ name: AuthStateNameSchema,
1104
+ capturedAt: z4.string().datetime()
1105
+ }).strict();
1106
+
1107
+ // src/schema/registry-schema.ts
1082
1108
  function isAbsoluteAppPath(value) {
1083
1109
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
1084
1110
  }
1085
- var AppInstallSchema = z4.object({
1086
- path: z4.string().refine((v) => !isAbsoluteAppPath(v), { message: "app.path must be relative" }).optional(),
1087
- browserstack: z4.string().optional()
1111
+ var AppInstallSchema = z5.object({
1112
+ path: z5.string().refine((v) => !isAbsoluteAppPath(v), { message: "app.path must be relative" }).optional(),
1113
+ browserstack: z5.string().optional()
1088
1114
  }).strict();
1089
- var TargetSchema = z4.object({
1090
- product: z4.string().refine(
1115
+ var TargetSchema = z5.object({
1116
+ product: z5.string().refine(
1091
1117
  (v) => !/\.\./.test(v) && !/[/\\]/.test(v) && !/\0/.test(v),
1092
1118
  { message: 'product must not contain "..", "/", "\\", or null bytes' }
1093
1119
  ).optional(),
1094
- platform: z4.enum(["web", "android", "ios"]),
1095
- bundleId: z4.string().optional(),
1096
- appPackage: z4.string().optional(),
1097
- appActivity: z4.string().optional(),
1120
+ platform: z5.enum(["web", "android", "ios"]),
1121
+ bundleId: z5.string().optional(),
1122
+ appPackage: z5.string().optional(),
1123
+ appActivity: z5.string().optional(),
1098
1124
  app: AppInstallSchema.optional(),
1099
- url: z4.string().optional()
1125
+ url: z5.string().optional()
1100
1126
  }).strict().superRefine((val, ctx) => {
1101
1127
  if (val.platform === "web" && !val.url) {
1102
- ctx.addIssue({ code: z4.ZodIssueCode.custom, message: "Web targets must have a url" });
1128
+ ctx.addIssue({ code: z5.ZodIssueCode.custom, message: "Web targets must have a url" });
1103
1129
  }
1104
1130
  });
1105
- var DeviceProfileSchema = z4.object({
1106
- platform: z4.enum(["android", "ios"]),
1131
+ var DeviceProfileSchema = z5.object({
1132
+ platform: z5.enum(["android", "ios"]),
1107
1133
  transport: TransportSchema,
1108
- match: z4.record(z4.string(), z4.unknown()).optional().default({})
1134
+ match: z5.record(z5.string(), z5.unknown()).optional().default({})
1109
1135
  }).strict().superRefine((val, ctx) => {
1110
1136
  if (val.transport === "local") {
1111
1137
  const androidOnly = ["avd", "serial", "appPackage", "appActivity", "automationName", "browserName", "platformVersion"];
@@ -1114,7 +1140,7 @@ var DeviceProfileSchema = z4.object({
1114
1140
  for (const key of Object.keys(val.match)) {
1115
1141
  if (!allowed.includes(key)) {
1116
1142
  ctx.addIssue({
1117
- code: z4.ZodIssueCode.custom,
1143
+ code: z5.ZodIssueCode.custom,
1118
1144
  path: ["match", key],
1119
1145
  message: `Match field "${key}" is not valid for ${val.platform} local transport. Allowed: ${allowed.join(", ")}`
1120
1146
  });
@@ -1122,94 +1148,119 @@ var DeviceProfileSchema = z4.object({
1122
1148
  }
1123
1149
  }
1124
1150
  });
1125
- var ProviderConfigSchema = z4.record(z4.string(), z4.unknown());
1126
- var RegistrySchema = z4.object({
1127
- llms: z4.array(NamedLLMConfigSchema).optional().default([]),
1128
- targets: z4.record(z4.string(), TargetSchema).optional(),
1129
- devices: z4.record(z4.string(), DeviceProfileSchema).optional(),
1130
- providers: z4.record(z4.string(), ProviderConfigSchema).optional()
1151
+ var ProviderConfigSchema = z5.record(z5.string(), z5.unknown());
1152
+ var RegistrySchema = z5.object({
1153
+ llms: z5.array(NamedLLMConfigSchema).optional().default([]),
1154
+ targets: z5.record(TargetNameSchema, TargetSchema).optional(),
1155
+ devices: z5.record(z5.string(), DeviceProfileSchema).optional(),
1156
+ providers: z5.record(z5.string(), ProviderConfigSchema).optional()
1131
1157
  }).strict();
1132
1158
 
1133
1159
  // src/schema/use-schema.ts
1134
- import { z as z5 } from "zod";
1135
- var MobileAppStateSchema = z5.enum(["preserve", "reset"]);
1136
- var MobileUseSchema = z5.object({
1160
+ import { z as z6 } from "zod";
1161
+ var MobileAppStateSchema = z6.enum(["preserve", "reset"]);
1162
+ var MobileUseSchema = z6.object({
1137
1163
  appState: MobileAppStateSchema
1138
1164
  }).strict();
1139
- var MobileUseOverrideSchema = z5.object({
1165
+ var MobileUseOverrideSchema = z6.object({
1140
1166
  appState: MobileAppStateSchema.optional()
1141
1167
  }).strict();
1142
- var UseSchema = z5.object({
1168
+ var AuthStateUseSchema = z6.union([
1169
+ AuthStateNameSchema,
1170
+ z6.object({
1171
+ name: AuthStateNameSchema,
1172
+ load: z6.boolean().optional(),
1173
+ capture: z6.boolean().optional()
1174
+ }).strict()
1175
+ ]);
1176
+ function normalizeAuthStateUse(use) {
1177
+ const parsed = AuthStateUseSchema.safeParse(use?.authState);
1178
+ if (!parsed.success) return void 0;
1179
+ if (typeof parsed.data === "string") {
1180
+ return {
1181
+ name: parsed.data,
1182
+ load: true,
1183
+ capture: false
1184
+ };
1185
+ }
1186
+ return {
1187
+ name: parsed.data.name,
1188
+ load: parsed.data.load ?? true,
1189
+ capture: parsed.data.capture ?? false
1190
+ };
1191
+ }
1192
+ var UseSchema = z6.object({
1143
1193
  browser: BrowserConfigSchema.optional(),
1144
1194
  mobile: MobileUseSchema.optional(),
1145
1195
  timeout: TimeoutConfigSchema.optional(),
1146
1196
  healing: HealingConfigSchema.optional(),
1147
1197
  planner: PlannerConfigSchema.optional(),
1148
1198
  logCapture: LogCaptureConfigSchema.optional(),
1149
- cache: z5.boolean().optional(),
1150
- llm: z5.string().optional(),
1151
- parallel: z5.boolean().optional()
1199
+ cache: z6.boolean().optional(),
1200
+ llm: z6.string().optional(),
1201
+ parallel: z6.boolean().optional()
1152
1202
  }).strict();
1153
- var UseOverrideSchema = z5.object({
1154
- browser: z5.object({
1155
- name: z5.enum(["chromium", "firefox", "webkit"]).optional(),
1156
- headless: z5.boolean().optional(),
1157
- viewport: z5.object({
1158
- width: z5.number().optional(),
1159
- height: z5.number().optional()
1203
+ var UseOverrideSchema = z6.object({
1204
+ browser: z6.object({
1205
+ name: z6.enum(["chromium", "firefox", "webkit"]).optional(),
1206
+ headless: z6.boolean().optional(),
1207
+ viewport: z6.object({
1208
+ width: z6.number().optional(),
1209
+ height: z6.number().optional()
1160
1210
  }).strict().optional()
1161
1211
  }).strict().optional(),
1162
- timeout: z5.object({
1212
+ timeout: z6.object({
1163
1213
  step: DurationString.optional(),
1164
1214
  test: DurationString.optional(),
1165
1215
  navigation: DurationString.optional()
1166
1216
  }).strict().optional(),
1167
- healing: z5.object({
1168
- maxAttempts: z5.number().optional()
1217
+ healing: z6.object({
1218
+ maxAttempts: z6.number().optional()
1169
1219
  }).strict().optional(),
1170
- planner: z5.object({
1171
- maxSubActions: z5.number().optional(),
1172
- previousStepCount: z5.number().optional()
1220
+ planner: z6.object({
1221
+ maxSubActions: z6.number().optional(),
1222
+ previousStepCount: z6.number().optional()
1173
1223
  }).strict().optional(),
1174
- logCapture: z5.object({
1175
- console: z5.boolean().optional(),
1176
- network: z5.boolean().optional()
1224
+ logCapture: z6.object({
1225
+ console: z6.boolean().optional(),
1226
+ network: z6.boolean().optional()
1177
1227
  }).strict().optional(),
1178
- cache: z5.boolean().optional(),
1228
+ cache: z6.boolean().optional(),
1229
+ authState: AuthStateUseSchema.optional(),
1179
1230
  mobile: MobileUseOverrideSchema.optional(),
1180
- llm: z5.string().optional(),
1181
- parallel: z5.boolean().optional(),
1182
- device: z5.string().optional()
1231
+ llm: z6.string().optional(),
1232
+ parallel: z6.boolean().optional(),
1233
+ device: z6.string().optional()
1183
1234
  }).strict();
1184
1235
 
1185
1236
  // src/schema/analytics-schema.ts
1186
- import { z as z6 } from "zod";
1187
- var AttributePredicateSchema = z6.union([
1188
- z6.string(),
1189
- z6.object({
1190
- regex: z6.string().min(1)
1237
+ import { z as z7 } from "zod";
1238
+ var AttributePredicateSchema = z7.union([
1239
+ z7.string(),
1240
+ z7.object({
1241
+ regex: z7.string().min(1)
1191
1242
  }).strict()
1192
1243
  ]);
1193
- var AnalyticsSchema = z6.object({
1194
- privacy: z6.literal(true).optional(),
1195
- passRateScope: z6.object({
1196
- attributes: z6.record(z6.string(), AttributePredicateSchema).optional()
1244
+ var AnalyticsSchema = z7.object({
1245
+ privacy: z7.literal(true).optional(),
1246
+ passRateScope: z7.object({
1247
+ attributes: z7.record(z7.string(), AttributePredicateSchema).optional()
1197
1248
  }).strict().optional()
1198
1249
  }).strict();
1199
1250
 
1200
1251
  // src/schema/config-schema.ts
1201
- var AuthPluginDeclarationSchema = z7.union([
1202
- z7.object({
1203
- package: z7.string().trim().min(1)
1252
+ var AuthPluginDeclarationSchema = z8.union([
1253
+ z8.object({
1254
+ package: z8.string().trim().min(1)
1204
1255
  }).strict(),
1205
- z7.object({
1206
- path: z7.string().trim().min(1)
1256
+ z8.object({
1257
+ path: z8.string().trim().min(1)
1207
1258
  }).strict()
1208
1259
  ]);
1209
- var PluginsSchema = z7.object({
1210
- auth: z7.array(AuthPluginDeclarationSchema).optional().default([])
1260
+ var PluginsSchema = z8.object({
1261
+ auth: z8.array(AuthPluginDeclarationSchema).optional().default([])
1211
1262
  }).strict();
1212
- var AgentQaConfigSchema = z7.object({
1263
+ var AgentQaConfigSchema = z8.object({
1213
1264
  workspace: WorkspaceSchema,
1214
1265
  services: ServicesSchema.optional(),
1215
1266
  registry: RegistrySchema.optional(),
@@ -1222,28 +1273,28 @@ var AgentQaConfigSchema = z7.object({
1222
1273
  const dupes = names.filter((n, i) => names.indexOf(n) !== i);
1223
1274
  for (const dupe of new Set(dupes)) {
1224
1275
  ctx.addIssue({
1225
- code: z7.ZodIssueCode.custom,
1276
+ code: z8.ZodIssueCode.custom,
1226
1277
  path: ["registry", "llms"],
1227
1278
  message: `Duplicate LLM config name: "${dupe}"`
1228
1279
  });
1229
1280
  }
1230
1281
  if (val.use?.platform) {
1231
1282
  ctx.addIssue({
1232
- code: z7.ZodIssueCode.custom,
1283
+ code: z8.ZodIssueCode.custom,
1233
1284
  path: ["use", "platform"],
1234
1285
  message: "use.platform cannot be set at global config level. Set platform in test or suite YAML instead."
1235
1286
  });
1236
1287
  }
1237
1288
  if (val.use?.llm && !names.includes(val.use.llm)) {
1238
1289
  ctx.addIssue({
1239
- code: z7.ZodIssueCode.custom,
1290
+ code: z8.ZodIssueCode.custom,
1240
1291
  path: ["use", "llm"],
1241
1292
  message: `use.llm "${val.use.llm}" does not match any name in registry.llms`
1242
1293
  });
1243
1294
  }
1244
1295
  if (!MobileAppStateSchema.safeParse(val.use?.mobile?.appState).success) {
1245
1296
  ctx.addIssue({
1246
- code: z7.ZodIssueCode.custom,
1297
+ code: z8.ZodIssueCode.custom,
1247
1298
  path: ["use", "mobile", "appState"],
1248
1299
  message: "use.mobile.appState is required and must be one of: preserve | reset"
1249
1300
  });
@@ -1251,123 +1302,123 @@ var AgentQaConfigSchema = z7.object({
1251
1302
  });
1252
1303
 
1253
1304
  // src/schema/test-schema.ts
1254
- import { z as z8 } from "zod";
1305
+ import { z as z9 } from "zod";
1255
1306
  import ms2 from "ms";
1256
1307
  import { isCanonicalHookId, isCanonicalTestId } from "@vostride/agent-qa-ids";
1257
- var OptionalDuration = z8.string().refine((v) => ms2(v) !== void 0, {
1308
+ var OptionalDuration = z9.string().refine((v) => ms2(v) !== void 0, {
1258
1309
  message: 'Invalid duration format (e.g., "30s", "5m", "1h")'
1259
1310
  }).transform((v) => ms2(v)).optional();
1260
- var CaptureConfigSchema = z8.object({
1261
- variable: z8.string(),
1262
- method: z8.enum(["regex", "selector", "ai"]),
1263
- pattern: z8.string().optional(),
1264
- selector: z8.string().optional(),
1265
- description: z8.string().optional()
1311
+ var CaptureConfigSchema = z9.object({
1312
+ variable: z9.string(),
1313
+ method: z9.enum(["regex", "selector", "ai"]),
1314
+ pattern: z9.string().optional(),
1315
+ selector: z9.string().optional(),
1316
+ description: z9.string().optional()
1266
1317
  }).strict();
1267
- var TestStepSchema = z8.union([
1268
- z8.string(),
1269
- z8.object({
1270
- step: z8.string(),
1318
+ var TestStepSchema = z9.union([
1319
+ z9.string(),
1320
+ z9.object({
1321
+ step: z9.string(),
1271
1322
  timeout: OptionalDuration,
1272
- retries: z8.number().optional(),
1273
- screenshot: z8.boolean().optional(),
1323
+ retries: z9.number().optional(),
1324
+ screenshot: z9.boolean().optional(),
1274
1325
  capture: CaptureConfigSchema.optional(),
1275
- maxAttempts: z8.number().optional()
1326
+ maxAttempts: z9.number().optional()
1276
1327
  }).strict()
1277
1328
  ]);
1278
- var TestMetaSchema = z8.object({
1329
+ var TestMetaSchema = z9.object({
1279
1330
  timeout: OptionalDuration,
1280
- retries: z8.number().optional(),
1281
- record: z8.boolean().optional()
1331
+ retries: z9.number().optional(),
1332
+ record: z9.boolean().optional()
1282
1333
  }).strict();
1283
- var HookIdSchema = z8.string().refine((value) => isCanonicalHookId(value), {
1334
+ var HookIdSchema = z9.string().refine((value) => isCanonicalHookId(value), {
1284
1335
  message: "Hook ID must be h_ followed by 10 id-agent words"
1285
1336
  });
1286
- var TestDefinitionSchema = z8.object({
1287
- "test-id": z8.string().refine((value) => isCanonicalTestId(value), {
1337
+ var TestDefinitionSchema = z9.object({
1338
+ "test-id": z9.string().refine((value) => isCanonicalTestId(value), {
1288
1339
  message: "Test ID must be t_ followed by 10 id-agent words"
1289
1340
  }),
1290
- name: z8.string(),
1291
- target: z8.string(),
1292
- context: z8.string().optional(),
1341
+ name: z9.string(),
1342
+ target: z9.string(),
1343
+ context: z9.string().optional(),
1293
1344
  use: UseOverrideSchema.optional(),
1294
1345
  meta: TestMetaSchema.optional(),
1295
- setup: z8.array(HookIdSchema).optional(),
1296
- teardown: z8.array(HookIdSchema).optional(),
1297
- steps: z8.array(TestStepSchema).min(1)
1346
+ setup: z9.array(HookIdSchema).optional(),
1347
+ teardown: z9.array(HookIdSchema).optional(),
1348
+ steps: z9.array(TestStepSchema).min(1)
1298
1349
  }).strict();
1299
1350
 
1300
1351
  // src/schema/action-schema.ts
1301
- import { z as z9 } from "zod";
1302
- var ActionPlanSchema = z9.object({
1303
- reasoning: z9.string().describe("Brief explanation of why this action was chosen"),
1304
- action: z9.object({ type: z9.string() }).passthrough(),
1305
- confidence: z9.number().describe("Confidence level from 0 to 1"),
1306
- stepComplete: z9.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."),
1307
- stepFailed: z9.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.")
1352
+ import { z as z10 } from "zod";
1353
+ var ActionPlanSchema = z10.object({
1354
+ reasoning: z10.string().describe("Brief explanation of why this action was chosen"),
1355
+ action: z10.object({ type: z10.string() }).passthrough(),
1356
+ confidence: z10.number().describe("Confidence level from 0 to 1"),
1357
+ stepComplete: z10.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."),
1358
+ stepFailed: z10.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.")
1308
1359
  });
1309
1360
 
1310
1361
  // src/schema/suite-schema.ts
1311
- import { z as z10 } from "zod";
1362
+ import { z as z11 } from "zod";
1312
1363
  import { isCanonicalHookId as isCanonicalHookId2, isCanonicalSuiteId, isCanonicalTestId as isCanonicalTestId2 } from "@vostride/agent-qa-ids";
1313
- var SuiteTestEntrySchema = z10.object({
1314
- test: z10.string(),
1315
- id: z10.string().refine((value) => isCanonicalTestId2(value), {
1364
+ var SuiteTestEntrySchema = z11.object({
1365
+ test: z11.string(),
1366
+ id: z11.string().refine((value) => isCanonicalTestId2(value), {
1316
1367
  message: "Test ID must be t_ followed by 10 id-agent words"
1317
1368
  })
1318
1369
  }).strict();
1319
- var HookIdSchema2 = z10.string().refine((value) => isCanonicalHookId2(value), {
1370
+ var HookIdSchema2 = z11.string().refine((value) => isCanonicalHookId2(value), {
1320
1371
  message: "Hook ID must be h_ followed by 10 id-agent words"
1321
1372
  });
1322
- var SuiteDefinitionSchema = z10.object({
1323
- "suite-id": z10.string().refine((value) => isCanonicalSuiteId(value), {
1373
+ var SuiteDefinitionSchema = z11.object({
1374
+ "suite-id": z11.string().refine((value) => isCanonicalSuiteId(value), {
1324
1375
  message: "Suite ID must be s_ followed by 10 id-agent words"
1325
1376
  }).optional(),
1326
- name: z10.string(),
1327
- target: z10.string(),
1328
- context: z10.string().optional(),
1329
- setup: z10.array(HookIdSchema2).optional(),
1330
- teardown: z10.array(HookIdSchema2).optional(),
1331
- tests: z10.array(SuiteTestEntrySchema).min(1),
1377
+ name: z11.string(),
1378
+ target: z11.string(),
1379
+ context: z11.string().optional(),
1380
+ setup: z11.array(HookIdSchema2).optional(),
1381
+ teardown: z11.array(HookIdSchema2).optional(),
1382
+ tests: z11.array(SuiteTestEntrySchema).min(1),
1332
1383
  use: UseOverrideSchema.optional()
1333
1384
  }).strict();
1334
1385
 
1335
1386
  // src/hooks/schema.ts
1336
- import { z as z11 } from "zod";
1387
+ import { z as z12 } from "zod";
1337
1388
  import ms3 from "ms";
1338
1389
  import { isCanonicalHookId as isCanonicalHookId3 } from "@vostride/agent-qa-ids";
1339
- var HookDurationString = z11.string().refine((v) => ms3(v) !== void 0, {
1390
+ var HookDurationString = z12.string().refine((v) => ms3(v) !== void 0, {
1340
1391
  message: 'Invalid duration format (e.g., "30s", "2m", "1h")'
1341
1392
  }).transform((v) => ms3(v));
1342
1393
  var HOOK_ID_MESSAGE = "Hook ID must be h_ followed by 10 id-agent words";
1343
- var HookDefinitionSchema = z11.object({
1344
- id: z11.string().refine((value) => isCanonicalHookId3(value), {
1394
+ var HookDefinitionSchema = z12.object({
1395
+ id: z12.string().refine((value) => isCanonicalHookId3(value), {
1345
1396
  message: HOOK_ID_MESSAGE
1346
1397
  }),
1347
- name: z11.string().min(1),
1348
- runtime: z11.enum(["node", "bun", "python", "bash"]),
1349
- file: z11.string().min(1),
1350
- deps: z11.array(z11.string()).optional().default([]),
1351
- packageFile: z11.string().optional(),
1398
+ name: z12.string().min(1),
1399
+ runtime: z12.enum(["node", "bun", "python", "bash"]),
1400
+ file: z12.string().min(1),
1401
+ deps: z12.array(z12.string()).optional().default([]),
1402
+ packageFile: z12.string().optional(),
1352
1403
  timeout: HookDurationString,
1353
- network: z11.boolean().optional().default(true)
1404
+ network: z12.boolean().optional().default(true)
1354
1405
  });
1355
- var HooksFileSchema = z11.object({
1356
- hooks: z11.array(HookDefinitionSchema)
1406
+ var HooksFileSchema = z12.object({
1407
+ hooks: z12.array(HookDefinitionSchema)
1357
1408
  }).superRefine((val, ctx) => {
1358
1409
  const ids = /* @__PURE__ */ new Set();
1359
1410
  const names = /* @__PURE__ */ new Set();
1360
1411
  for (let i = 0; i < val.hooks.length; i++) {
1361
1412
  if (ids.has(val.hooks[i].id)) {
1362
1413
  ctx.addIssue({
1363
- code: z11.ZodIssueCode.custom,
1414
+ code: z12.ZodIssueCode.custom,
1364
1415
  path: ["hooks", i, "id"],
1365
1416
  message: `Duplicate hook id: "${val.hooks[i].id}"`
1366
1417
  });
1367
1418
  }
1368
1419
  if (names.has(val.hooks[i].name)) {
1369
1420
  ctx.addIssue({
1370
- code: z11.ZodIssueCode.custom,
1421
+ code: z12.ZodIssueCode.custom,
1371
1422
  path: ["hooks", i, "name"],
1372
1423
  message: `Duplicate hook name: "${val.hooks[i].name}"`
1373
1424
  });
@@ -1433,8 +1484,8 @@ function formatYamlError(err, linePos, content, filePath) {
1433
1484
  suggestion: void 0
1434
1485
  };
1435
1486
  }
1436
- function zodPathToSuggestion(code, path5, message) {
1437
- const field = path5[path5.length - 1];
1487
+ function zodPathToSuggestion(code, path7, message) {
1488
+ const field = path7[path7.length - 1];
1438
1489
  if (code === "invalid_type") {
1439
1490
  if (typeof field === "string") {
1440
1491
  return `check that '${field}' has the correct type`;
@@ -1458,10 +1509,10 @@ function zodPathToSuggestion(code, path5, message) {
1458
1509
  }
1459
1510
  return void 0;
1460
1511
  }
1461
- function resolveNodeAtPath(doc, path5) {
1512
+ function resolveNodeAtPath(doc, path7) {
1462
1513
  let current = doc.contents;
1463
1514
  if (!current) return null;
1464
- for (const segment of path5) {
1515
+ for (const segment of path7) {
1465
1516
  if (!current) return null;
1466
1517
  if (typeof segment === "number") {
1467
1518
  const items = current.items;
@@ -1524,7 +1575,7 @@ function formatZodErrors(zodError, doc, lineCounter, content, filePath) {
1524
1575
 
1525
1576
  // src/agent/variables.ts
1526
1577
  import { generateText, Output } from "ai";
1527
- import { z as z14 } from "zod";
1578
+ import { z as z15 } from "zod";
1528
1579
 
1529
1580
  // src/agent/observation.ts
1530
1581
  import { createHash } from "crypto";
@@ -1661,12 +1712,12 @@ function getPlatformFilter(name) {
1661
1712
 
1662
1713
  // src/tools/builder.ts
1663
1714
  import { tool } from "ai";
1664
- import { z as z12 } from "zod";
1715
+ import { z as z13 } from "zod";
1665
1716
  var PLAN_FIELDS = {
1666
- reasoning: z12.string().describe("Brief explanation of why this action was chosen"),
1667
- confidence: z12.number().describe("Confidence level from 0 to 1"),
1668
- stepComplete: z12.boolean().describe("Whether this action completes the step goal"),
1669
- stepFailed: z12.boolean().optional().describe("Set true when the step goal cannot be achieved")
1717
+ reasoning: z13.string().describe("Brief explanation of why this action was chosen"),
1718
+ confidence: z13.number().describe("Confidence level from 0 to 1"),
1719
+ stepComplete: z13.boolean().describe("Whether this action completes the step goal"),
1720
+ stepFailed: z13.boolean().optional().describe("Set true when the step goal cannot be achieved")
1670
1721
  };
1671
1722
  var ToolValidationError = class extends Error {
1672
1723
  toolName;
@@ -1684,7 +1735,7 @@ function buildTools(registry, options) {
1684
1735
  const actionShape = def.schema.shape;
1685
1736
  tools[def.name] = tool({
1686
1737
  description: def.description,
1687
- inputSchema: z12.object({ ...PLAN_FIELDS, ...actionShape })
1738
+ inputSchema: z13.object({ ...PLAN_FIELDS, ...actionShape })
1688
1739
  });
1689
1740
  }
1690
1741
  return tools;
@@ -1706,7 +1757,7 @@ function toolCallToActionPlan(toolName, args, registry) {
1706
1757
  }
1707
1758
 
1708
1759
  // src/tools/actions/index.ts
1709
- import { z as z13 } from "zod";
1760
+ import { z as z14 } from "zod";
1710
1761
  function action(name, description, schema) {
1711
1762
  return {
1712
1763
  name,
@@ -1717,204 +1768,204 @@ function action(name, description, schema) {
1717
1768
  };
1718
1769
  }
1719
1770
  var ACTION_DEFINITIONS = [
1720
- action("click", "Click an element", z13.object({
1721
- ref: z13.string().describe("Element reference from the screen state"),
1722
- clickDelay: z13.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
1771
+ action("click", "Click an element", z14.object({
1772
+ ref: z14.string().describe("Element reference from the screen state"),
1773
+ clickDelay: z14.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
1723
1774
  })),
1724
- action("fill", "Fill text into an input field", z13.object({
1725
- ref: z13.string().describe("Element reference for the input field"),
1726
- value: z13.string().describe("Text value to fill into the input")
1775
+ action("fill", "Fill text into an input field", z14.object({
1776
+ ref: z14.string().describe("Element reference for the input field"),
1777
+ value: z14.string().describe("Text value to fill into the input")
1727
1778
  })),
1728
- action("select", "Select an option from a dropdown", z13.object({
1729
- ref: z13.string().describe("Element reference for the select/dropdown"),
1730
- value: z13.string().describe("Option value to select")
1779
+ action("select", "Select an option from a dropdown", z14.object({
1780
+ ref: z14.string().describe("Element reference for the select/dropdown"),
1781
+ value: z14.string().describe("Option value to select")
1731
1782
  })),
1732
- action("nativeSelect", "Select a value from a native mobile picker, picker wheel, spinner, or dropdown/list control", z13.object({
1733
- ref: z13.string().describe("Element reference for the native picker/dropdown control"),
1734
- value: z13.string().describe("Visible text/value to select")
1783
+ action("nativeSelect", "Select a value from a native mobile picker, picker wheel, spinner, or dropdown/list control", z14.object({
1784
+ ref: z14.string().describe("Element reference for the native picker/dropdown control"),
1785
+ value: z14.string().describe("Visible text/value to select")
1735
1786
  })),
1736
- action("navigate", "Navigate to a URL", z13.object({
1737
- url: z13.string().describe("URL to navigate to")
1787
+ action("navigate", "Navigate to a URL", z14.object({
1788
+ url: z14.string().describe("URL to navigate to")
1738
1789
  })),
1739
- action("scroll", "Scroll the page or a specific element", z13.object({
1740
- scrollType: z13.enum(["vertical", "horizontal"]).describe("Scroll axis: vertical (up/down) or horizontal (left/right)"),
1741
- value: z13.number().describe("Scroll distance in pixels. Positive = down/right, negative = up/left"),
1742
- ref: z13.string().optional().describe("Optional element to scroll within"),
1743
- duration: z13.number().optional().describe("Scroll duration in ms (mobile only \u2014 web ignores this)")
1790
+ action("scroll", "Scroll the page or a specific element", z14.object({
1791
+ scrollType: z14.enum(["vertical", "horizontal"]).describe("Scroll axis: vertical (up/down) or horizontal (left/right)"),
1792
+ value: z14.number().describe("Scroll distance in pixels. Positive = down/right, negative = up/left"),
1793
+ ref: z14.string().optional().describe("Optional element to scroll within"),
1794
+ duration: z14.number().optional().describe("Scroll duration in ms (mobile only \u2014 web ignores this)")
1744
1795
  })),
1745
- 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).', z13.object({
1746
- ms: z13.number().describe("Duration in milliseconds")
1796
+ 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).', z14.object({
1797
+ ms: z14.number().describe("Duration in milliseconds")
1747
1798
  })),
1748
- action("waitFor", "Wait for a condition to be met (text content match or selector)", z13.object({
1749
- condition: z13.string().describe("Condition to wait for \u2014 either visible text content or a CSS selector"),
1750
- timeout: z13.number().optional().describe("Maximum wait time in ms (default: 5000)")
1799
+ action("waitFor", "Wait for a condition to be met (text content match or selector)", z14.object({
1800
+ condition: z14.string().describe("Condition to wait for \u2014 either visible text content or a CSS selector"),
1801
+ timeout: z14.number().optional().describe("Maximum wait time in ms (default: 5000)")
1751
1802
  })),
1752
- action("assert", "Assert a condition on the current page state", z13.object({
1753
- condition: z13.string().describe("Assertion condition to check"),
1754
- expected: z13.string().optional().describe("Expected value for comparison"),
1755
- visual: z13.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.")
1803
+ action("assert", "Assert a condition on the current page state", z14.object({
1804
+ condition: z14.string().describe("Assertion condition to check"),
1805
+ expected: z14.string().optional().describe("Expected value for comparison"),
1806
+ visual: z14.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.")
1756
1807
  })),
1757
- action("keypress", "Press one or more keyboard keys/combos in sequence", z13.object({
1758
- keys: z13.array(z13.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.'),
1759
- convertPlatformKeys: z13.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.')
1808
+ action("keypress", "Press one or more keyboard keys/combos in sequence", z14.object({
1809
+ keys: z14.array(z14.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.'),
1810
+ convertPlatformKeys: z14.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.')
1760
1811
  })),
1761
- action("hover", "Hover over an element", z13.object({
1762
- ref: z13.string().describe("Element reference to hover over")
1812
+ action("hover", "Hover over an element", z14.object({
1813
+ ref: z14.string().describe("Element reference to hover over")
1763
1814
  })),
1764
- action("paste", "Paste text into an element via clipboard paste event", z13.object({
1765
- ref: z13.string().describe("Element reference for the target element"),
1766
- value: z13.string().describe("Text value to paste")
1815
+ action("paste", "Paste text into an element via clipboard paste event", z14.object({
1816
+ ref: z14.string().describe("Element reference for the target element"),
1817
+ value: z14.string().describe("Text value to paste")
1767
1818
  })),
1768
- action("keyDown", "Hold down a key (for modifier combos like Shift+Click)", z13.object({
1769
- key: z13.string().describe("Key to hold down (e.g., Shift, Control, Alt, Meta)")
1819
+ action("keyDown", "Hold down a key (for modifier combos like Shift+Click)", z14.object({
1820
+ key: z14.string().describe("Key to hold down (e.g., Shift, Control, Alt, Meta)")
1770
1821
  })),
1771
- action("keyUp", "Release a held key", z13.object({
1772
- key: z13.string().describe("Key to release (e.g., Shift, Control, Alt, Meta)")
1822
+ action("keyUp", "Release a held key", z14.object({
1823
+ key: z14.string().describe("Key to release (e.g., Shift, Control, Alt, Meta)")
1773
1824
  })),
1774
- action("refresh", "Refresh the current page", z13.object({})),
1775
- action("navigateHistory", "Navigate browser history (back or forward)", z13.object({
1776
- direction: z13.enum(["back", "forward"]).describe("Navigation direction in browser history")
1825
+ action("refresh", "Refresh the current page", z14.object({})),
1826
+ action("navigateHistory", "Navigate browser history (back or forward)", z14.object({
1827
+ direction: z14.enum(["back", "forward"]).describe("Navigation direction in browser history")
1777
1828
  })),
1778
- action("readConsoleLogs", "Read console log entries from the browser", z13.object({
1779
- level: z13.enum(["log", "info", "warn", "error"]).optional().describe("Filter by log level. Omit to get all levels."),
1780
- tab: z13.object({
1781
- index: z13.number().optional().describe("0-based tab index"),
1782
- title: z13.string().optional().describe("Substring match on page title"),
1783
- url: z13.string().optional().describe("Substring match on page URL")
1829
+ action("readConsoleLogs", "Read console log entries from the browser", z14.object({
1830
+ level: z14.enum(["log", "info", "warn", "error"]).optional().describe("Filter by log level. Omit to get all levels."),
1831
+ tab: z14.object({
1832
+ index: z14.number().optional().describe("0-based tab index"),
1833
+ title: z14.string().optional().describe("Substring match on page title"),
1834
+ url: z14.string().optional().describe("Substring match on page URL")
1784
1835
  }).optional().describe("Target a specific tab. Omit to read logs from all tabs.")
1785
1836
  })),
1786
- action("readNetworkLogs", "Read network request/response log entries", z13.object({
1787
- urlPattern: z13.string().optional().describe("Filter by URL substring match. Omit to get all requests."),
1788
- tab: z13.object({
1789
- index: z13.number().optional().describe("0-based tab index"),
1790
- title: z13.string().optional().describe("Substring match on page title"),
1791
- url: z13.string().optional().describe("Substring match on page URL")
1837
+ action("readNetworkLogs", "Read network request/response log entries", z14.object({
1838
+ urlPattern: z14.string().optional().describe("Filter by URL substring match. Omit to get all requests."),
1839
+ tab: z14.object({
1840
+ index: z14.number().optional().describe("0-based tab index"),
1841
+ title: z14.string().optional().describe("Substring match on page title"),
1842
+ url: z14.string().optional().describe("Substring match on page URL")
1792
1843
  }).optional().describe("Target a specific tab. Omit to read logs from all tabs.")
1793
1844
  })),
1794
- action("readCookies", "Read browser cookies", z13.object({
1795
- name: z13.string().optional().describe("Cookie name to read. Omit to get all cookies.")
1845
+ action("readCookies", "Read browser cookies", z14.object({
1846
+ name: z14.string().optional().describe("Cookie name to read. Omit to get all cookies.")
1796
1847
  })),
1797
- action("setCookies", "Set browser cookies", z13.object({
1798
- cookies: z13.array(z13.object({
1799
- name: z13.string().describe("Cookie name"),
1800
- value: z13.string().describe("Cookie value"),
1801
- domain: z13.string().optional().describe("Cookie domain"),
1802
- path: z13.string().optional().describe("Cookie path"),
1803
- httpOnly: z13.boolean().optional().describe("HTTP only flag"),
1804
- secure: z13.boolean().optional().describe("Secure flag"),
1805
- sameSite: z13.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute"),
1806
- expires: z13.number().optional().describe("Expiry as Unix timestamp in seconds")
1848
+ action("setCookies", "Set browser cookies", z14.object({
1849
+ cookies: z14.array(z14.object({
1850
+ name: z14.string().describe("Cookie name"),
1851
+ value: z14.string().describe("Cookie value"),
1852
+ domain: z14.string().optional().describe("Cookie domain"),
1853
+ path: z14.string().optional().describe("Cookie path"),
1854
+ httpOnly: z14.boolean().optional().describe("HTTP only flag"),
1855
+ secure: z14.boolean().optional().describe("Secure flag"),
1856
+ sameSite: z14.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute"),
1857
+ expires: z14.number().optional().describe("Expiry as Unix timestamp in seconds")
1807
1858
  })).describe("Array of cookies to set")
1808
1859
  })),
1809
- action("readLocalStorage", "Read local storage entries", z13.object({
1810
- key: z13.string().optional().describe("Storage key to read. Omit to get all entries.")
1860
+ action("readLocalStorage", "Read local storage entries", z14.object({
1861
+ key: z14.string().optional().describe("Storage key to read. Omit to get all entries.")
1811
1862
  })),
1812
- action("setLocalStorage", "Set local storage entries", z13.object({
1813
- entries: z13.array(z13.object({
1814
- key: z13.string().describe("Storage key"),
1815
- value: z13.string().describe("Storage value")
1863
+ action("setLocalStorage", "Set local storage entries", z14.object({
1864
+ entries: z14.array(z14.object({
1865
+ key: z14.string().describe("Storage key"),
1866
+ value: z14.string().describe("Storage value")
1816
1867
  })).describe("Array of key-value pairs to set")
1817
1868
  })),
1818
- action("tap", "Tap an element on a mobile device", z13.object({
1819
- ref: z13.string().describe("Element reference to tap")
1869
+ action("tap", "Tap an element on a mobile device", z14.object({
1870
+ ref: z14.string().describe("Element reference to tap")
1820
1871
  })),
1821
- action("swipe", "Swipe gesture on a mobile device", z13.object({
1822
- direction: z13.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
1823
- ref: z13.string().optional().describe("Optional element to swipe within"),
1824
- startX: z13.number().optional().describe("Start X coordinate (overrides direction-based calculation)"),
1825
- startY: z13.number().optional().describe("Start Y coordinate (overrides direction-based calculation)"),
1826
- endX: z13.number().optional().describe("End X coordinate (overrides direction-based calculation)"),
1827
- endY: z13.number().optional().describe("End Y coordinate (overrides direction-based calculation)"),
1828
- duration: z13.number().optional().describe("Swipe duration in ms (default: 300)")
1872
+ action("swipe", "Swipe gesture on a mobile device", z14.object({
1873
+ direction: z14.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
1874
+ ref: z14.string().optional().describe("Optional element to swipe within"),
1875
+ startX: z14.number().optional().describe("Start X coordinate (overrides direction-based calculation)"),
1876
+ startY: z14.number().optional().describe("Start Y coordinate (overrides direction-based calculation)"),
1877
+ endX: z14.number().optional().describe("End X coordinate (overrides direction-based calculation)"),
1878
+ endY: z14.number().optional().describe("End Y coordinate (overrides direction-based calculation)"),
1879
+ duration: z14.number().optional().describe("Swipe duration in ms (default: 300)")
1829
1880
  })),
1830
- action("longpress", "Long-press an element on a mobile device", z13.object({
1831
- ref: z13.string().describe("Element reference to long-press"),
1832
- duration: z13.number().optional().describe("Long-press duration in ms")
1881
+ action("longpress", "Long-press an element on a mobile device", z14.object({
1882
+ ref: z14.string().describe("Element reference to long-press"),
1883
+ duration: z14.number().optional().describe("Long-press duration in ms")
1833
1884
  })),
1834
- action("hideKeyboard", "Dismiss the on-screen keyboard (mobile only, no-op on web)", z13.object({})),
1835
- action("clearText", "Clear all text from an input field without typing new text", z13.object({
1836
- ref: z13.string().describe("Element reference for the input field to clear")
1885
+ action("hideKeyboard", "Dismiss the on-screen keyboard (mobile only, no-op on web)", z14.object({})),
1886
+ action("clearText", "Clear all text from an input field without typing new text", z14.object({
1887
+ ref: z14.string().describe("Element reference for the input field to clear")
1837
1888
  })),
1838
- action("openLink", "Open a deep link in a mobile app \u2014 use navigate for web URLs", z13.object({
1839
- url: z13.string().describe("Deep link URL to open (e.g. myapp://screen, intent://...)"),
1840
- appId: z13.string().optional().describe("Generic mobile app identifier. Android uses package name; iOS uses bundle ID."),
1841
- bundleId: z13.string().optional().describe("iOS bundle ID to open the link in"),
1842
- appPackage: z13.string().optional().describe("Android package name to open the link in"),
1843
- waitForLaunch: z13.boolean().optional().describe("Whether to wait for the app to launch after opening the link")
1889
+ action("openLink", "Open a deep link in a mobile app \u2014 use navigate for web URLs", z14.object({
1890
+ url: z14.string().describe("Deep link URL to open (e.g. myapp://screen, intent://...)"),
1891
+ appId: z14.string().optional().describe("Generic mobile app identifier. Android uses package name; iOS uses bundle ID."),
1892
+ bundleId: z14.string().optional().describe("iOS bundle ID to open the link in"),
1893
+ appPackage: z14.string().optional().describe("Android package name to open the link in"),
1894
+ waitForLaunch: z14.boolean().optional().describe("Whether to wait for the app to launch after opening the link")
1844
1895
  })),
1845
- action("drag", "Drag an element to another element (reorder lists, sliders)", z13.object({
1846
- fromRef: z13.string().describe("Element reference to drag from"),
1847
- toRef: z13.string().describe("Element reference to drag to")
1896
+ action("drag", "Drag an element to another element (reorder lists, sliders)", z14.object({
1897
+ fromRef: z14.string().describe("Element reference to drag from"),
1898
+ toRef: z14.string().describe("Element reference to drag to")
1848
1899
  })),
1849
- action("doubleTap", "Double-tap an element (text selection, zoom)", z13.object({
1850
- ref: z13.string().describe("Element reference to double-tap")
1900
+ action("doubleTap", "Double-tap an element (text selection, zoom)", z14.object({
1901
+ ref: z14.string().describe("Element reference to double-tap")
1851
1902
  })),
1852
- action("launchApp", "Launch or bring an app to the foreground", z13.object({
1853
- bundleId: z13.string().describe("App bundle ID (iOS) or package name (Android)")
1903
+ action("launchApp", "Launch or bring an app to the foreground", z14.object({
1904
+ bundleId: z14.string().describe("App bundle ID (iOS) or package name (Android)")
1854
1905
  })),
1855
- action("stopApp", "Terminate a running app", z13.object({
1856
- bundleId: z13.string().describe("App bundle ID (iOS) or package name (Android)")
1906
+ action("stopApp", "Terminate a running app", z14.object({
1907
+ bundleId: z14.string().describe("App bundle ID (iOS) or package name (Android)")
1857
1908
  })),
1858
- action("setOrientation", "Set the device orientation (mobile only)", z13.object({
1859
- orientation: z13.enum(["portrait", "landscape"]).describe("Device orientation")
1909
+ action("setOrientation", "Set the device orientation (mobile only)", z14.object({
1910
+ orientation: z14.enum(["portrait", "landscape"]).describe("Device orientation")
1860
1911
  })),
1861
- action("pinch", "Pinch zoom gesture on a mobile device (mobile only)", z13.object({
1862
- scale: z13.number().describe("Scale factor: >1 to zoom in (spread fingers), <1 to zoom out (pinch fingers)"),
1863
- x: z13.number().optional().describe("Center X coordinate for pinch gesture"),
1864
- y: z13.number().optional().describe("Center Y coordinate for pinch gesture"),
1865
- ref: z13.string().optional().describe("Optional element to center the pinch on")
1912
+ action("pinch", "Pinch zoom gesture on a mobile device (mobile only)", z14.object({
1913
+ scale: z14.number().describe("Scale factor: >1 to zoom in (spread fingers), <1 to zoom out (pinch fingers)"),
1914
+ x: z14.number().optional().describe("Center X coordinate for pinch gesture"),
1915
+ y: z14.number().optional().describe("Center Y coordinate for pinch gesture"),
1916
+ ref: z14.string().optional().describe("Optional element to center the pinch on")
1866
1917
  })),
1867
- action("multiTap", "Multi-finger tap gesture on a mobile device (mobile only)", z13.object({
1868
- fingers: z13.number().describe("Number of fingers (2 or 3)"),
1869
- x: z13.number().optional().describe("Center X coordinate for multi-finger tap"),
1870
- y: z13.number().optional().describe("Center Y coordinate for multi-finger tap"),
1871
- ref: z13.string().optional().describe("Optional element to center the tap on")
1918
+ action("multiTap", "Multi-finger tap gesture on a mobile device (mobile only)", z14.object({
1919
+ fingers: z14.number().describe("Number of fingers (2 or 3)"),
1920
+ x: z14.number().optional().describe("Center X coordinate for multi-finger tap"),
1921
+ y: z14.number().optional().describe("Center Y coordinate for multi-finger tap"),
1922
+ ref: z14.string().optional().describe("Optional element to center the tap on")
1872
1923
  })),
1873
- action("tapCoordinate", "Tap at specific pixel coordinates \u2014 use when target element has no ref in accessibility tree", z13.object({
1874
- x: z13.number().describe("X coordinate in pixels"),
1875
- y: z13.number().describe("Y coordinate in pixels")
1924
+ action("tapCoordinate", "Tap at specific pixel coordinates \u2014 use when target element has no ref in accessibility tree", z14.object({
1925
+ x: z14.number().describe("X coordinate in pixels"),
1926
+ y: z14.number().describe("Y coordinate in pixels")
1876
1927
  })),
1877
- action("executeScript", "Execute an Appium script command (mobile only)", z13.object({
1878
- command: z13.string().describe('Appium command name (e.g., "mobile: enrollBiometric", "mobile: terminateApp")'),
1879
- args: z13.any().optional().describe("Command arguments \u2014 object with key-value pairs, or array for some commands")
1928
+ action("executeScript", "Execute an Appium script command (mobile only)", z14.object({
1929
+ command: z14.string().describe('Appium command name (e.g., "mobile: enrollBiometric", "mobile: terminateApp")'),
1930
+ args: z14.any().optional().describe("Command arguments \u2014 object with key-value pairs, or array for some commands")
1880
1931
  })),
1881
- action("setVariable", "Set a runtime environment variable for use in subsequent steps", z13.object({
1882
- name: z13.string().describe("Variable name (will be accessible via {{env:varName}})"),
1883
- value: z13.string().describe("Variable value to store")
1932
+ action("setVariable", "Set a runtime environment variable for use in subsequent steps", z14.object({
1933
+ name: z14.string().describe("Variable name (will be accessible via {{env:varName}})"),
1934
+ value: z14.string().describe("Variable value to store")
1884
1935
  })),
1885
- action("newTab", "Open a URL in a new browser tab and switch to it", z13.object({
1886
- url: z13.string().describe("URL to open in the new tab")
1936
+ action("newTab", "Open a URL in a new browser tab and switch to it", z14.object({
1937
+ url: z14.string().describe("URL to open in the new tab")
1887
1938
  })),
1888
- action("switchTab", "Switch to an open browser tab", z13.object({
1889
- index: z13.number().optional().describe("0-based tab index to switch to"),
1890
- title: z13.string().optional().describe("Substring match on page title"),
1891
- url: z13.string().optional().describe("Substring match on page URL")
1939
+ action("switchTab", "Switch to an open browser tab", z14.object({
1940
+ index: z14.number().optional().describe("0-based tab index to switch to"),
1941
+ title: z14.string().optional().describe("Substring match on page title"),
1942
+ url: z14.string().optional().describe("Substring match on page URL")
1892
1943
  })),
1893
- action("doubleClick", "Double-click an element (text selection, expand, web-only)", z13.object({
1894
- ref: z13.string().describe("Element reference from the screen state"),
1895
- relativePosition: z13.object({
1896
- x: z13.number().describe("X offset in pixels from element top-left"),
1897
- y: z13.number().describe("Y offset in pixels from element top-left")
1944
+ action("doubleClick", "Double-click an element (text selection, expand, web-only)", z14.object({
1945
+ ref: z14.string().describe("Element reference from the screen state"),
1946
+ relativePosition: z14.object({
1947
+ x: z14.number().describe("X offset in pixels from element top-left"),
1948
+ y: z14.number().describe("Y offset in pixels from element top-left")
1898
1949
  }).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."),
1899
- clickDelay: z13.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
1950
+ clickDelay: z14.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
1900
1951
  })),
1901
- action("rightClick", "Right-click an element to open context menu (web-only)", z13.object({
1902
- ref: z13.string().describe("Element reference from the screen state"),
1903
- relativePosition: z13.object({
1904
- x: z13.number().describe("X offset in pixels from element top-left"),
1905
- y: z13.number().describe("Y offset in pixels from element top-left")
1952
+ action("rightClick", "Right-click an element to open context menu (web-only)", z14.object({
1953
+ ref: z14.string().describe("Element reference from the screen state"),
1954
+ relativePosition: z14.object({
1955
+ x: z14.number().describe("X offset in pixels from element top-left"),
1956
+ y: z14.number().describe("Y offset in pixels from element top-left")
1906
1957
  }).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."),
1907
- clickDelay: z13.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
1958
+ clickDelay: z14.number().optional().describe("Omit when there is no requested delay. Only provide a positive value when the user explicitly asks for a delay.")
1908
1959
  })),
1909
- action("waitForUrl", "Wait for the page URL to match a glob pattern (web only)", z13.object({
1910
- pattern: z13.string().describe('URL glob pattern. Use "**" for substring matching (e.g., "**/dashboard**"). Plain strings WITHOUT wildcards require EXACT URL match, not substring.')
1960
+ action("waitForUrl", "Wait for the page URL to match a glob pattern (web only)", z14.object({
1961
+ pattern: z14.string().describe('URL glob pattern. Use "**" for substring matching (e.g., "**/dashboard**"). Plain strings WITHOUT wildcards require EXACT URL match, not substring.')
1911
1962
  })),
1912
- action("fileUpload", "Upload one or more files to a file input element (web only)", z13.object({
1913
- ref: z13.string().describe("Element reference for the file input"),
1914
- files: z13.array(z13.string()).min(1).describe("Paths to files \u2014 relative to the test YAML file, or absolute paths. Missing files fail the action.")
1963
+ action("fileUpload", "Upload one or more files to a file input element (web only)", z14.object({
1964
+ ref: z14.string().describe("Element reference for the file input"),
1965
+ files: z14.array(z14.string()).min(1).describe("Paths to files \u2014 relative to the test YAML file, or absolute paths. Missing files fail the action.")
1915
1966
  })),
1916
- action("copy", "Copy the text content of an element to the system clipboard (web only, chromium only)", z13.object({
1917
- ref: z13.string().describe("Element reference whose text content to copy")
1967
+ action("copy", "Copy the text content of an element to the system clipboard (web only, chromium only)", z14.object({
1968
+ ref: z14.string().describe("Element reference whose text content to copy")
1918
1969
  }))
1919
1970
  ];
1920
1971
  function registerAllActions(registry) {
@@ -2328,9 +2379,9 @@ function buildExtractionPrompt(input, screenState) {
2328
2379
  }
2329
2380
 
2330
2381
  // src/agent/variables.ts
2331
- var ExtractionResultSchema = z14.object({
2332
- value: z14.string(),
2333
- reasoning: z14.string()
2382
+ var ExtractionResultSchema = z15.object({
2383
+ value: z15.string(),
2384
+ reasoning: z15.string()
2334
2385
  });
2335
2386
  var VariableStore = class {
2336
2387
  storage = /* @__PURE__ */ new Map();
@@ -2830,11 +2881,11 @@ var LLMPlanner = class {
2830
2881
 
2831
2882
  // src/agent/verifier.ts
2832
2883
  import { generateText as generateText3, Output as Output2 } from "ai";
2833
- import { z as z15 } from "zod";
2834
- var VerificationResultSchema = z15.object({
2835
- success: z15.boolean().describe("Whether the step goal was accomplished"),
2836
- reasoning: z15.string().describe("Explanation of why the step succeeded or failed"),
2837
- isAppError: z15.boolean().describe(
2884
+ import { z as z16 } from "zod";
2885
+ var VerificationResultSchema = z16.object({
2886
+ success: z16.boolean().describe("Whether the step goal was accomplished"),
2887
+ reasoning: z16.string().describe("Explanation of why the step succeeded or failed"),
2888
+ isAppError: z16.boolean().describe(
2838
2889
  "Whether the page shows an application error (HTTP error, error toast, crash) vs the agent simply not accomplishing the goal"
2839
2890
  )
2840
2891
  });
@@ -3026,11 +3077,11 @@ async function createOpenAICompatibleModel(config) {
3026
3077
 
3027
3078
  // src/agent/asserter.ts
3028
3079
  import { generateText as generateText4, Output as Output3 } from "ai";
3029
- import { z as z16 } from "zod";
3030
- var AssertionResultSchema = z16.object({
3031
- passed: z16.boolean(),
3032
- reasoning: z16.string(),
3033
- evidence: z16.string()
3080
+ import { z as z17 } from "zod";
3081
+ var AssertionResultSchema = z17.object({
3082
+ passed: z17.boolean(),
3083
+ reasoning: z17.string(),
3084
+ evidence: z17.string()
3034
3085
  });
3035
3086
  var AssertionEvaluator = class {
3036
3087
  async evaluate(assertion, screenState) {
@@ -4659,6 +4710,192 @@ var RUNTIME_IMAGE_MAP = {
4659
4710
  bash: "vostride/agent-qa-hook-runner-bash"
4660
4711
  };
4661
4712
 
4713
+ // src/auth-state/hook-env.ts
4714
+ var AUTH_STATE_HOOK_JSON_ENV = "AGENT_QA_AUTH_STATE_JSON";
4715
+ var AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV = "AGENT_QA_AUTH_STATE_STORAGE_STATE_PATH";
4716
+ var AUTH_STATE_HOOK_WORKSPACE_DIR = ".agent-qa-auth-state";
4717
+ var AUTH_STATE_HOOK_STORAGE_STATE_FILENAME = "storage-state.json";
4718
+ var AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH = `/workspace/${AUTH_STATE_HOOK_WORKSPACE_DIR}/${AUTH_STATE_HOOK_STORAGE_STATE_FILENAME}`;
4719
+ var RESERVED_AUTH_STATE_HOOK_ENV_KEYS = /* @__PURE__ */ new Set([
4720
+ AUTH_STATE_HOOK_JSON_ENV,
4721
+ AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV
4722
+ ]);
4723
+ function isReservedAuthStateHookEnvKey(key) {
4724
+ return RESERVED_AUTH_STATE_HOOK_ENV_KEYS.has(key);
4725
+ }
4726
+ function stripReservedAuthStateHookEnv(variables) {
4727
+ return Object.fromEntries(
4728
+ Object.entries(variables).filter(([key]) => !isReservedAuthStateHookEnvKey(key))
4729
+ );
4730
+ }
4731
+ function buildAuthStateHookEnv(authState, storageStatePath = AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH) {
4732
+ if (!authState) return {};
4733
+ const metadata = {
4734
+ version: authState.version,
4735
+ kind: authState.kind,
4736
+ target: authState.targetName,
4737
+ name: authState.stateName,
4738
+ capturedAt: authState.capturedAt,
4739
+ storageStatePath
4740
+ };
4741
+ return {
4742
+ [AUTH_STATE_HOOK_JSON_ENV]: JSON.stringify(metadata),
4743
+ [AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV]: storageStatePath
4744
+ };
4745
+ }
4746
+
4747
+ // src/auth-state/redaction.ts
4748
+ var AUTH_STATE_REDACTION_MARKER = "[auth state redacted]";
4749
+ var AUTH_STATE_JSON_KEY = normalizeKey(AUTH_STATE_HOOK_JSON_ENV);
4750
+ var AUTH_STATE_PATH_KEY = normalizeKey(AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV);
4751
+ var STRUCTURED_AUTH_STATE_KEYS = /* @__PURE__ */ new Set(["authstate", "auth_state"]);
4752
+ var STRUCTURED_PATH_KEYS = /* @__PURE__ */ new Set(["storagestatepath", AUTH_STATE_JSON_KEY, AUTH_STATE_PATH_KEY]);
4753
+ var AUTH_LIKE_KEY_RE = /(^|[_-])(token|cookie|authorization|csrf|session|bearer)([_-]|$)|^(token|cookie|authorization|csrf|session|bearer)$/i;
4754
+ function normalizeKey(key) {
4755
+ return key.replace(/[\s-]/g, "").toLowerCase();
4756
+ }
4757
+ function isBufferLike2(value) {
4758
+ return typeof Buffer !== "undefined" && Buffer.isBuffer(value);
4759
+ }
4760
+ function isRecord(value) {
4761
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !isBufferLike2(value);
4762
+ }
4763
+ function isStorageStateShape(value) {
4764
+ return isRecord(value) && Array.isArray(value.cookies) && Array.isArray(value.origins);
4765
+ }
4766
+ function isRuntimeAuthStateShape(value) {
4767
+ if (!isRecord(value)) return false;
4768
+ return typeof value.storageStatePath === "string" && typeof value.stateName === "string" && typeof value.targetName === "string";
4769
+ }
4770
+ function isAuthStateManagementMetadata(value) {
4771
+ if (!isRecord(value)) return false;
4772
+ if ("storageStatePath" in value || "payloadPath" in value || "metadataPath" in value) return false;
4773
+ return value.kind === "web" && typeof value.target === "string" && typeof value.name === "string" && typeof value.capturedAt === "string";
4774
+ }
4775
+ function isAuthStateManagementConfig(value) {
4776
+ if (!isRecord(value)) return false;
4777
+ const keys = Object.keys(value);
4778
+ return keys.length > 0 && keys.every((key) => key === "dir");
4779
+ }
4780
+ function isAuthLikeCredentialKey(key) {
4781
+ return AUTH_LIKE_KEY_RE.test(key);
4782
+ }
4783
+ function knownSensitiveStrings(context) {
4784
+ const values = /* @__PURE__ */ new Set();
4785
+ const hookStorageStatePath = context.hookStorageStatePath ?? AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH;
4786
+ for (const value of [
4787
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,
4788
+ hookStorageStatePath,
4789
+ context.storageStatePath,
4790
+ context.authState?.storageStatePath,
4791
+ context.hookJsonEnv
4792
+ ]) {
4793
+ if (typeof value === "string" && value.length > 0) values.add(value);
4794
+ }
4795
+ if (context.authState) {
4796
+ const env = buildAuthStateHookEnv(context.authState, hookStorageStatePath);
4797
+ const hookJson = env[AUTH_STATE_HOOK_JSON_ENV];
4798
+ if (hookJson) values.add(hookJson);
4799
+ }
4800
+ return [...values].sort((left, right) => right.length - left.length);
4801
+ }
4802
+ function tryParseJsonObject(value) {
4803
+ try {
4804
+ return JSON.parse(value);
4805
+ } catch {
4806
+ return void 0;
4807
+ }
4808
+ }
4809
+ function looksLikeStorageStateJson(value) {
4810
+ if (!value.includes('"cookies"') || !value.includes('"origins"')) return false;
4811
+ return isStorageStateShape(tryParseJsonObject(value));
4812
+ }
4813
+ function looksLikeAuthStateHookJson(value) {
4814
+ if (!value.includes('"storageStatePath"')) return false;
4815
+ const parsed = tryParseJsonObject(value);
4816
+ return isRecord(parsed) && typeof parsed.storageStatePath === "string" && (typeof parsed.name === "string" || typeof parsed.target === "string" || parsed.kind === "web");
4817
+ }
4818
+ function redactStructuredAuthStateText(value) {
4819
+ return value.replace(
4820
+ /(\bauthState\s*:\s*\n(?:[ \t]+[^\n]*\n)*?[ \t]+name\s*:\s*)[^\n#]+/gi,
4821
+ (_match, prefix) => `${prefix}${AUTH_STATE_REDACTION_MARKER}`
4822
+ ).replace(
4823
+ /(["']?(?:authState|auth_state|storageStatePath|AGENT_QA_AUTH_STATE_JSON|AGENT_QA_AUTH_STATE_STORAGE_STATE_PATH)["']?\s*[:=]\s*)(["'])[^"']*\2/gi,
4824
+ (_match, prefix, quote) => `${prefix}${quote}${AUTH_STATE_REDACTION_MARKER}${quote}`
4825
+ ).replace(
4826
+ /((?:authState|auth_state|storageStatePath|AGENT_QA_AUTH_STATE_JSON|AGENT_QA_AUTH_STATE_STORAGE_STATE_PATH)\s*[:=]\s*)[^\s,}\]]+/gi,
4827
+ (_match, prefix) => `${prefix}${AUTH_STATE_REDACTION_MARKER}`
4828
+ );
4829
+ }
4830
+ function redactStorageStateJsonLines(value) {
4831
+ return value.split(/\r?\n/).map((line) => {
4832
+ const trimmed = line.trim();
4833
+ return looksLikeStorageStateJson(trimmed) || looksLikeAuthStateHookJson(trimmed) ? AUTH_STATE_REDACTION_MARKER : line;
4834
+ }).join("\n");
4835
+ }
4836
+ function redactAuthStateString(value, context = {}) {
4837
+ if (value.includes(AUTH_STATE_HOOK_JSON_ENV) || value.includes(AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV) || looksLikeStorageStateJson(value.trim()) || looksLikeAuthStateHookJson(value.trim())) {
4838
+ return AUTH_STATE_REDACTION_MARKER;
4839
+ }
4840
+ if (value.includes("authState") || value.includes("auth_state")) {
4841
+ const parsed = tryParseJsonObject(value.trim());
4842
+ if (parsed !== void 0) {
4843
+ return JSON.stringify(redactAuthStateOnly(parsed, context));
4844
+ }
4845
+ }
4846
+ let redacted = redactStorageStateJsonLines(value);
4847
+ for (const sensitive of knownSensitiveStrings(context)) {
4848
+ redacted = redacted.split(sensitive).join(AUTH_STATE_REDACTION_MARKER);
4849
+ }
4850
+ return redactStructuredAuthStateText(redacted);
4851
+ }
4852
+ function shouldRedactKeyValue(key, value, context) {
4853
+ const normalized = normalizeKey(key);
4854
+ if (STRUCTURED_PATH_KEYS.has(normalized)) return true;
4855
+ if (STRUCTURED_AUTH_STATE_KEYS.has(normalized)) {
4856
+ if (typeof value === "string") return true;
4857
+ if (isAuthStateManagementConfig(value) || isAuthStateManagementMetadata(value)) return false;
4858
+ return true;
4859
+ }
4860
+ if (typeof value === "string" && value.startsWith("[secret")) return false;
4861
+ return context.redactAuthLikeKeys !== false && isAuthLikeCredentialKey(key);
4862
+ }
4863
+ function redactAuthStateOnly(value, context) {
4864
+ if (typeof value === "string") {
4865
+ return redactAuthStateString(value, context);
4866
+ }
4867
+ if (Array.isArray(value)) {
4868
+ return value.map((item) => redactAuthStateOnly(item, context));
4869
+ }
4870
+ if (isBufferLike2(value)) {
4871
+ return value;
4872
+ }
4873
+ if (value instanceof Error) {
4874
+ const redacted = new Error(redactAuthStateString(value.message, context));
4875
+ redacted.name = value.name;
4876
+ redacted.stack = value.stack ? redactAuthStateString(value.stack, context) : void 0;
4877
+ return redacted;
4878
+ }
4879
+ if (!isRecord(value)) {
4880
+ return value;
4881
+ }
4882
+ if (isStorageStateShape(value) || isRuntimeAuthStateShape(value)) {
4883
+ return AUTH_STATE_REDACTION_MARKER;
4884
+ }
4885
+ const result = {};
4886
+ for (const [key, item] of Object.entries(value)) {
4887
+ if (shouldRedactKeyValue(key, item, context)) {
4888
+ result[key] = AUTH_STATE_REDACTION_MARKER;
4889
+ } else {
4890
+ result[key] = redactAuthStateOnly(item, context);
4891
+ }
4892
+ }
4893
+ return result;
4894
+ }
4895
+ function redactAuthStateValue(value, context = {}) {
4896
+ return redactAuthStateOnly(redactSecretValue(value, context.secretRedactor), context);
4897
+ }
4898
+
4662
4899
  // src/hooks/sandbox-runner.ts
4663
4900
  var DEFAULT_DOCKER_BIN = "docker";
4664
4901
  function getHookCommand(runtime, entryFile) {
@@ -4702,12 +4939,18 @@ async function runHookInSandbox(hook, options = {}) {
4702
4939
  if (hook.packageFile) {
4703
4940
  await cp(hook.packageFile, join(workDir, basename(hook.packageFile)));
4704
4941
  }
4942
+ if (options.authState) {
4943
+ const authStateDir = join(workDir, AUTH_STATE_HOOK_WORKSPACE_DIR);
4944
+ await mkdir(authStateDir, { recursive: true });
4945
+ await cp(options.authState.storageStatePath, join(authStateDir, AUTH_STATE_HOOK_STORAGE_STATE_FILENAME));
4946
+ }
4705
4947
  const args = buildDockerArgs({
4706
4948
  image,
4707
4949
  workDir,
4708
4950
  hook,
4709
4951
  envVars: options.envVars,
4710
- secretStore: options.secretStore
4952
+ secretStore: options.secretStore,
4953
+ authState: options.authState
4711
4954
  });
4712
4955
  const cmd = getHookCommand(hook.runtime, basename(hook.file));
4713
4956
  args.push(...cmd);
@@ -4718,9 +4961,15 @@ async function runHookInSandbox(hook, options = {}) {
4718
4961
  variables = parseEnvFile(envContent);
4719
4962
  } catch {
4720
4963
  }
4721
- variables = filterSecretVariables(variables, options.secretStore);
4722
- const redactedStdout = redactSecretValue(stdout, options.secretRedactor);
4723
- const redactedStderr = redactSecretValue(stderr, options.secretRedactor);
4964
+ variables = stripReservedAuthStateHookEnv(filterSecretVariables(variables, options.secretStore));
4965
+ const redactedStdout = redactAuthStateValue(stdout, {
4966
+ secretRedactor: options.secretRedactor,
4967
+ authState: options.authState
4968
+ });
4969
+ const redactedStderr = redactAuthStateValue(stderr, {
4970
+ secretRedactor: options.secretRedactor,
4971
+ authState: options.authState
4972
+ });
4724
4973
  const output = redactedStdout.trim();
4725
4974
  return {
4726
4975
  success: exitCode === 0,
@@ -4729,7 +4978,10 @@ async function runHookInSandbox(hook, options = {}) {
4729
4978
  stdout: redactedStdout,
4730
4979
  stderr: redactedStderr,
4731
4980
  duration: Date.now() - start,
4732
- error: exitCode !== 0 ? redactSecretValue(`Hook exited with code ${exitCode}: ${stderr}`, options.secretRedactor) : void 0
4981
+ error: exitCode !== 0 ? redactAuthStateValue(`Hook exited with code ${exitCode}: ${stderr}`, {
4982
+ secretRedactor: options.secretRedactor,
4983
+ authState: options.authState
4984
+ }) : void 0
4733
4985
  };
4734
4986
  } catch (err) {
4735
4987
  return {
@@ -4739,7 +4991,10 @@ async function runHookInSandbox(hook, options = {}) {
4739
4991
  stdout: "",
4740
4992
  stderr: "",
4741
4993
  duration: Date.now() - start,
4742
- error: redactSecretValue(err.message, options.secretRedactor)
4994
+ error: redactAuthStateValue(err.message, {
4995
+ secretRedactor: options.secretRedactor,
4996
+ authState: options.authState
4997
+ })
4743
4998
  };
4744
4999
  } finally {
4745
5000
  if (workDir) {
@@ -4774,6 +5029,10 @@ function buildDockerArgs(input) {
4774
5029
  input.secretStore?.forEachSecret((name, value) => {
4775
5030
  envVars[name] = value;
4776
5031
  });
5032
+ Object.assign(envVars, buildAuthStateHookEnv(
5033
+ input.authState,
5034
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH
5035
+ ));
4777
5036
  for (const [k, v] of Object.entries(envVars)) {
4778
5037
  args.push("-e", `${k}=${v}`);
4779
5038
  }
@@ -5439,7 +5698,9 @@ ${errorLines.join("\n")}`;
5439
5698
  videoPath,
5440
5699
  failureSummary: failureSummary || void 0
5441
5700
  };
5442
- await reporter?.onTestEnd(testResult);
5701
+ if (config.skipReporterOnTestEnd !== true) {
5702
+ await reporter?.onTestEnd(testResult);
5703
+ }
5443
5704
  return testResult;
5444
5705
  }
5445
5706
  function createTimeoutStepResult(name, scopeLabel, timeoutMs) {
@@ -6925,8 +7186,223 @@ function formatAppiumInstallGuidance() {
6925
7186
  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`.";
6926
7187
  }
6927
7188
 
7189
+ // src/auth-state/resolver.ts
7190
+ import path2 from "path";
7191
+
7192
+ // src/runtime-paths.ts
7193
+ var DEFAULT_AGENT_QA_RUNTIME_DIR = ".agent-qa";
7194
+ var DEFAULT_AGENT_QA_ARTIFACTS_DIR = ".agent-qa/artifacts";
7195
+ var DEFAULT_AGENT_QA_CACHE_DIR = ".agent-qa/cache";
7196
+ var DEFAULT_AGENT_QA_AUTH_STATES_DIR = ".agent-qa/auth-states";
7197
+ var DEFAULT_AGENT_QA_SCREENSHOTS_DIR = ".agent-qa/artifacts/screenshots";
7198
+ var DEFAULT_AGENT_QA_VIDEOS_DIR = ".agent-qa/artifacts/videos";
7199
+ var DEFAULT_AGENT_QA_RUNS_DB_PATH = ".agent-qa/runs.db";
7200
+ var LEGACY_AGENT_QA_DASHBOARD_DB_PATH = ".agent-qa/dashboard.db";
7201
+
7202
+ // src/auth-state/resolver.ts
7203
+ var MOBILE_AUTH_STATE_ERROR = [
7204
+ "auth state is only supported for web targets.",
7205
+ "For native mobile, use use.mobile.appState: preserve when keeping app data between sessions.",
7206
+ "App-state preservation is broader than auth and does not export generic secure-storage/keychain tokens."
7207
+ ].join(" ");
7208
+ function assertInsideRoot(rootDir, filePath) {
7209
+ const relativePath = path2.relative(rootDir, filePath);
7210
+ if (!relativePath || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
7211
+ throw new Error(`Resolved auth-state path escapes auth-state directory: ${filePath}`);
7212
+ }
7213
+ }
7214
+ function resolveAuthStateRoot(input) {
7215
+ const { configDir, authStateDir } = input;
7216
+ const configuredDir = authStateDir ?? DEFAULT_AGENT_QA_AUTH_STATES_DIR;
7217
+ if (configuredDir.trim().length === 0) {
7218
+ throw new Error("authState.dir must be a non-empty path");
7219
+ }
7220
+ return path2.isAbsolute(configuredDir) ? path2.resolve(configuredDir) : path2.resolve(configDir, configuredDir);
7221
+ }
7222
+ function resolveAuthStatePaths(input) {
7223
+ const targetName = TargetNameSchema.parse(input.targetName);
7224
+ const stateName = AuthStateNameSchema.parse(input.stateName);
7225
+ const platform = input.target?.platform ?? input.platform;
7226
+ if (platform !== "web") {
7227
+ throw new Error(MOBILE_AUTH_STATE_ERROR);
7228
+ }
7229
+ const rootDir = resolveAuthStateRoot({
7230
+ configDir: input.configDir,
7231
+ authStateDir: input.authStateDir
7232
+ });
7233
+ const targetDir = path2.join(rootDir, targetName);
7234
+ const payloadPath = path2.join(targetDir, `${stateName}.json`);
7235
+ const metadataPath = path2.join(targetDir, `${stateName}.meta.json`);
7236
+ assertInsideRoot(rootDir, payloadPath);
7237
+ assertInsideRoot(rootDir, metadataPath);
7238
+ return {
7239
+ targetName,
7240
+ stateName,
7241
+ rootDir,
7242
+ targetDir,
7243
+ payloadPath,
7244
+ metadataPath
7245
+ };
7246
+ }
7247
+
7248
+ // src/auth-state/store.ts
7249
+ import { randomUUID as randomUUID2 } from "crypto";
7250
+ import { mkdir as mkdir4, readdir as readdir2, readFile as readFile6, rename, rm as rm2, writeFile as writeFile4 } from "fs/promises";
7251
+ import path3 from "path";
7252
+ function assertMetadataMatches(paths, metadata) {
7253
+ if (metadata.target !== paths.targetName) {
7254
+ throw new Error(`Auth-state metadata target "${metadata.target}" does not match resolved target "${paths.targetName}"`);
7255
+ }
7256
+ if (metadata.name !== paths.stateName) {
7257
+ throw new Error(`Auth-state metadata name "${metadata.name}" does not match resolved state "${paths.stateName}"`);
7258
+ }
7259
+ }
7260
+ async function writeJsonAtomic(filePath, value) {
7261
+ const serialized = `${JSON.stringify(value, null, 2)}
7262
+ `;
7263
+ const directory = path3.dirname(filePath);
7264
+ const tempPath = path3.join(directory, `.${path3.basename(filePath)}.${process.pid}.${randomUUID2()}.tmp`);
7265
+ await mkdir4(directory, { recursive: true });
7266
+ try {
7267
+ await writeFile4(tempPath, serialized, { mode: 384 });
7268
+ await rename(tempPath, filePath);
7269
+ } catch (error) {
7270
+ await rm2(tempPath, { force: true }).catch(() => void 0);
7271
+ throw error;
7272
+ }
7273
+ }
7274
+ async function readAuthStateMetadata(paths) {
7275
+ let raw;
7276
+ try {
7277
+ raw = await readFile6(paths.metadataPath, "utf-8");
7278
+ } catch (error) {
7279
+ if (error.code === "ENOENT") {
7280
+ throw new Error(`Auth-state metadata not found: ${paths.metadataPath}`);
7281
+ }
7282
+ throw error;
7283
+ }
7284
+ let parsed;
7285
+ try {
7286
+ parsed = JSON.parse(raw);
7287
+ } catch {
7288
+ throw new Error(`Invalid auth-state metadata JSON: ${paths.metadataPath}`);
7289
+ }
7290
+ const result = AuthStateMetadataSchema.safeParse(parsed);
7291
+ if (!result.success) {
7292
+ throw new Error(`Invalid auth-state metadata: ${result.error.issues.map((issue) => issue.message).join("; ")}`);
7293
+ }
7294
+ assertMetadataMatches(paths, result.data);
7295
+ return result.data;
7296
+ }
7297
+ async function writeAuthStateFiles(paths, input) {
7298
+ const metadata = AuthStateMetadataSchema.parse(input.metadata);
7299
+ assertMetadataMatches(paths, metadata);
7300
+ await writeJsonAtomic(paths.payloadPath, input.payload);
7301
+ await writeJsonAtomic(paths.metadataPath, metadata);
7302
+ }
7303
+ async function listAuthStateMetadata(input) {
7304
+ const rootDir = resolveAuthStateRoot({
7305
+ configDir: input.configDir,
7306
+ authStateDir: input.authStateDir
7307
+ });
7308
+ const targetFilter = input.targetName ? TargetNameSchema.parse(input.targetName) : void 0;
7309
+ let targetEntries;
7310
+ try {
7311
+ targetEntries = await readdir2(rootDir, { withFileTypes: true });
7312
+ } catch (error) {
7313
+ if (error.code === "ENOENT") {
7314
+ return [];
7315
+ }
7316
+ throw error;
7317
+ }
7318
+ const metadata = [];
7319
+ for (const targetEntry of targetEntries) {
7320
+ if (!targetEntry.isDirectory()) continue;
7321
+ const targetNameResult = TargetNameSchema.safeParse(targetEntry.name);
7322
+ if (!targetNameResult.success) continue;
7323
+ const targetName = targetNameResult.data;
7324
+ if (targetFilter && targetName !== targetFilter) continue;
7325
+ let stateEntries;
7326
+ const targetDir = path3.join(rootDir, targetName);
7327
+ try {
7328
+ stateEntries = await readdir2(targetDir, { withFileTypes: true });
7329
+ } catch {
7330
+ continue;
7331
+ }
7332
+ for (const stateEntry of stateEntries) {
7333
+ if (!stateEntry.isFile() || !stateEntry.name.endsWith(".meta.json")) continue;
7334
+ const stateName = stateEntry.name.slice(0, -".meta.json".length);
7335
+ const paths = (() => {
7336
+ try {
7337
+ return resolveAuthStatePaths({
7338
+ configDir: input.configDir,
7339
+ authStateDir: input.authStateDir,
7340
+ targetName,
7341
+ stateName,
7342
+ platform: "web"
7343
+ });
7344
+ } catch {
7345
+ return null;
7346
+ }
7347
+ })();
7348
+ if (!paths) continue;
7349
+ try {
7350
+ const entry = await readAuthStateMetadata(paths);
7351
+ metadata.push(entry);
7352
+ } catch {
7353
+ continue;
7354
+ }
7355
+ }
7356
+ }
7357
+ return metadata.sort((a, b) => {
7358
+ const targetOrder = a.target.localeCompare(b.target);
7359
+ return targetOrder === 0 ? a.name.localeCompare(b.name) : targetOrder;
7360
+ });
7361
+ }
7362
+ async function removeAuthStateFiles(input) {
7363
+ const paths = resolveAuthStatePaths(input);
7364
+ await rm2(paths.payloadPath, { force: true });
7365
+ await rm2(paths.metadataPath, { force: true });
7366
+ }
7367
+ async function removeAuthStateTarget(input) {
7368
+ const paths = resolveAuthStatePaths({
7369
+ ...input,
7370
+ stateName: "placeholder"
7371
+ });
7372
+ await rm2(paths.targetDir, { recursive: true, force: true });
7373
+ }
7374
+
7375
+ // src/auth-state/runtime.ts
7376
+ import { readFile as readFile7 } from "fs/promises";
7377
+ function createAuthStateReadError(targetName, stateName) {
7378
+ return new Error(
7379
+ `Auth state "${stateName}" for target "${targetName}" was not found or could not be read. Run agent-qa auth-state capture --target ${targetName} --name ${stateName}.`
7380
+ );
7381
+ }
7382
+ async function assertPayloadReadable(paths) {
7383
+ const raw = await readFile7(paths.payloadPath, "utf-8");
7384
+ JSON.parse(raw);
7385
+ }
7386
+ async function resolveAuthStateForRun(input) {
7387
+ const paths = resolveAuthStatePaths(input);
7388
+ try {
7389
+ const metadata = await readAuthStateMetadata(paths);
7390
+ await assertPayloadReadable(paths);
7391
+ return {
7392
+ version: metadata.version,
7393
+ kind: metadata.kind,
7394
+ targetName: metadata.target,
7395
+ stateName: metadata.name,
7396
+ capturedAt: metadata.capturedAt,
7397
+ storageStatePath: paths.payloadPath
7398
+ };
7399
+ } catch {
7400
+ throw createAuthStateReadError(paths.targetName, paths.stateName);
7401
+ }
7402
+ }
7403
+
6928
7404
  // src/auth/store.ts
6929
- import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir4, unlink as unlink2 } from "fs/promises";
7405
+ import { readFile as readFile8, writeFile as writeFile5, mkdir as mkdir5, unlink as unlink2 } from "fs/promises";
6930
7406
  import { dirname as dirname7, join as join4 } from "path";
6931
7407
  import { homedir } from "os";
6932
7408
  function getAuthPath() {
@@ -6934,24 +7410,24 @@ function getAuthPath() {
6934
7410
  if (xdg) return join4(xdg, "agent-qa", "auth.json");
6935
7411
  return join4(homedir(), ".agent-qa", "auth.json");
6936
7412
  }
6937
- async function readAuth(path5) {
6938
- const authPath = path5 ?? getAuthPath();
7413
+ async function readAuth(path7) {
7414
+ const authPath = path7 ?? getAuthPath();
6939
7415
  try {
6940
- const data = await readFile6(authPath, "utf-8");
7416
+ const data = await readFile8(authPath, "utf-8");
6941
7417
  return JSON.parse(data);
6942
7418
  } catch {
6943
7419
  return {};
6944
7420
  }
6945
7421
  }
6946
- async function writeAuth(provider, credential, path5) {
6947
- const authPath = path5 ?? getAuthPath();
7422
+ async function writeAuth(provider, credential, path7) {
7423
+ const authPath = path7 ?? getAuthPath();
6948
7424
  const store = await readAuth(authPath);
6949
7425
  store[provider] = credential;
6950
- await mkdir4(dirname7(authPath), { recursive: true });
6951
- await writeFile4(authPath, JSON.stringify(store, null, 2), { mode: 384 });
7426
+ await mkdir5(dirname7(authPath), { recursive: true });
7427
+ await writeFile5(authPath, JSON.stringify(store, null, 2), { mode: 384 });
6952
7428
  }
6953
- async function removeAuth(provider, path5) {
6954
- const authPath = path5 ?? getAuthPath();
7429
+ async function removeAuth(provider, path7) {
7430
+ const authPath = path7 ?? getAuthPath();
6955
7431
  const store = await readAuth(authPath);
6956
7432
  delete store[provider];
6957
7433
  if (Object.keys(store).length === 0) {
@@ -6961,10 +7437,10 @@ async function removeAuth(provider, path5) {
6961
7437
  }
6962
7438
  return;
6963
7439
  }
6964
- await writeFile4(authPath, JSON.stringify(store, null, 2), { mode: 384 });
7440
+ await writeFile5(authPath, JSON.stringify(store, null, 2), { mode: 384 });
6965
7441
  }
6966
- async function getCredential(provider, path5) {
6967
- const store = await readAuth(path5);
7442
+ async function getCredential(provider, path7) {
7443
+ const store = await readAuth(path7);
6968
7444
  return store[provider] ?? null;
6969
7445
  }
6970
7446
 
@@ -7322,7 +7798,7 @@ function createAuthFetch(options) {
7322
7798
  }
7323
7799
 
7324
7800
  // src/logging/types.ts
7325
- import { z as z17 } from "zod";
7801
+ import { z as z18 } from "zod";
7326
7802
  var LOG_LEVEL_PRIORITY = {
7327
7803
  silent: 0,
7328
7804
  error: 1,
@@ -7330,53 +7806,53 @@ var LOG_LEVEL_PRIORITY = {
7330
7806
  info: 3,
7331
7807
  debug: 4
7332
7808
  };
7333
- var AgentLogDataSchema = z17.object({
7334
- extractDom: z17.boolean().optional(),
7335
- hasScreenshot: z17.boolean().optional(),
7336
- duration: z17.number().optional(),
7337
- elementCount: z17.number().optional()
7809
+ var AgentLogDataSchema = z18.object({
7810
+ extractDom: z18.boolean().optional(),
7811
+ hasScreenshot: z18.boolean().optional(),
7812
+ duration: z18.number().optional(),
7813
+ elementCount: z18.number().optional()
7338
7814
  });
7339
- var AdapterLogDataSchema = z17.object({
7340
- actionType: z17.string().optional(),
7341
- selector: z17.string().optional(),
7342
- coordinates: z17.object({ x: z17.number(), y: z17.number() }).optional(),
7343
- elementProperties: z17.record(z17.string(), z17.unknown()).optional(),
7344
- duration: z17.number().optional()
7815
+ var AdapterLogDataSchema = z18.object({
7816
+ actionType: z18.string().optional(),
7817
+ selector: z18.string().optional(),
7818
+ coordinates: z18.object({ x: z18.number(), y: z18.number() }).optional(),
7819
+ elementProperties: z18.record(z18.string(), z18.unknown()).optional(),
7820
+ duration: z18.number().optional()
7345
7821
  });
7346
- var CacheLogDataSchema = z17.object({
7347
- operation: z17.enum(["get", "set", "invalidate", "bypass", "batch-purge"]),
7348
- stepHash: z17.string().optional(),
7349
- screenHash: z17.string().optional(),
7350
- hit: z17.boolean().optional(),
7351
- age: z17.number().optional(),
7352
- entriesDeleted: z17.number().optional()
7822
+ var CacheLogDataSchema = z18.object({
7823
+ operation: z18.enum(["get", "set", "invalidate", "bypass", "batch-purge"]),
7824
+ stepHash: z18.string().optional(),
7825
+ screenHash: z18.string().optional(),
7826
+ hit: z18.boolean().optional(),
7827
+ age: z18.number().optional(),
7828
+ entriesDeleted: z18.number().optional()
7353
7829
  });
7354
- var PlannerLogDataSchema = z17.object({
7355
- model: z17.string().optional(),
7356
- promptTokens: z17.number().optional(),
7357
- completionTokens: z17.number().optional(),
7358
- latencyMs: z17.number().optional(),
7359
- confidence: z17.number().optional(),
7360
- actionType: z17.string().optional()
7830
+ var PlannerLogDataSchema = z18.object({
7831
+ model: z18.string().optional(),
7832
+ promptTokens: z18.number().optional(),
7833
+ completionTokens: z18.number().optional(),
7834
+ latencyMs: z18.number().optional(),
7835
+ confidence: z18.number().optional(),
7836
+ actionType: z18.string().optional()
7361
7837
  });
7362
- var HealerLogDataSchema = z17.object({
7363
- strategy: z17.string().optional(),
7364
- attempt: z17.number().optional(),
7365
- maxAttempts: z17.number().optional(),
7366
- stateDiffDetected: z17.boolean().optional(),
7367
- success: z17.boolean().optional()
7838
+ var HealerLogDataSchema = z18.object({
7839
+ strategy: z18.string().optional(),
7840
+ attempt: z18.number().optional(),
7841
+ maxAttempts: z18.number().optional(),
7842
+ stateDiffDetected: z18.boolean().optional(),
7843
+ success: z18.boolean().optional()
7368
7844
  });
7369
- var HookLogDataSchema = z17.object({
7370
- hookName: z17.string().optional(),
7371
- phase: z17.enum(["setup", "teardown"]).optional(),
7372
- duration: z17.number().optional(),
7373
- success: z17.boolean().optional()
7845
+ var HookLogDataSchema = z18.object({
7846
+ hookName: z18.string().optional(),
7847
+ phase: z18.enum(["setup", "teardown"]).optional(),
7848
+ duration: z18.number().optional(),
7849
+ success: z18.boolean().optional()
7374
7850
  });
7375
- var RunnerLogDataSchema = z17.object({
7376
- stepIndex: z17.number().optional(),
7377
- totalSteps: z17.number().optional(),
7378
- testName: z17.string().optional(),
7379
- variablesCaptured: z17.number().optional()
7851
+ var RunnerLogDataSchema = z18.object({
7852
+ stepIndex: z18.number().optional(),
7853
+ totalSteps: z18.number().optional(),
7854
+ testName: z18.string().optional(),
7855
+ variablesCaptured: z18.number().optional()
7380
7856
  });
7381
7857
  var LogSourceDataSchemas = {
7382
7858
  agent: AgentLogDataSchema,
@@ -7389,7 +7865,7 @@ var LogSourceDataSchemas = {
7389
7865
  };
7390
7866
 
7391
7867
  // src/logging/log-manager.ts
7392
- import { randomUUID as randomUUID2 } from "crypto";
7868
+ import { randomUUID as randomUUID3 } from "crypto";
7393
7869
 
7394
7870
  // src/logging/cli-formatter.ts
7395
7871
  import pc3 from "picocolors";
@@ -7431,13 +7907,13 @@ var LogManager = class {
7431
7907
  }
7432
7908
  log(level, source, message, data) {
7433
7909
  const entry = {
7434
- id: randomUUID2(),
7910
+ id: randomUUID3(),
7435
7911
  stepId: this.currentStepId,
7436
7912
  runId: this.runId,
7437
7913
  level,
7438
7914
  source,
7439
- message: redactSecretValue(message, this.redactor),
7440
- data: redactSecretValue(data ?? {}, this.redactor),
7915
+ message: redactAuthStateValue(message, { secretRedactor: this.redactor }),
7916
+ data: redactAuthStateValue(data ?? {}, { secretRedactor: this.redactor }),
7441
7917
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7442
7918
  };
7443
7919
  this.buffer.push(entry);
@@ -7752,8 +8228,8 @@ function registerAllProviders() {
7752
8228
  }
7753
8229
 
7754
8230
  // src/suite/runner.ts
7755
- import { randomUUID as randomUUID3 } from "crypto";
7756
- import { readFile as readFile8 } from "fs/promises";
8231
+ import { randomUUID as randomUUID4 } from "crypto";
8232
+ import { readFile as readFile10 } from "fs/promises";
7757
8233
 
7758
8234
  // src/hooks/orchestrator.ts
7759
8235
  async function runHooks(hooks, options = {}) {
@@ -7765,7 +8241,7 @@ async function runHooks(hooks, options = {}) {
7765
8241
  const result = await runHookInSandbox(hook, { ...options, envVars });
7766
8242
  results.set(hook.name, result);
7767
8243
  if (result.success) {
7768
- Object.assign(mergedVars, result.variables);
8244
+ Object.assign(mergedVars, stripReservedAuthStateHookEnv(result.variables));
7769
8245
  } else {
7770
8246
  for (const remaining of hooks.slice(hooks.indexOf(hook) + 1)) {
7771
8247
  results.set(remaining.name, {
@@ -7792,40 +8268,40 @@ async function runHooks(hooks, options = {}) {
7792
8268
  // src/memory/curator.ts
7793
8269
  init_observation_io();
7794
8270
  import { generateText as generateText5, Output as Output4 } from "ai";
7795
- import { z as z19 } from "zod";
8271
+ import { z as z20 } from "zod";
7796
8272
  import { join as join6 } from "path";
7797
- import { access as access2, readFile as readFile7, readdir as readdir3 } from "fs/promises";
8273
+ import { access as access2, readFile as readFile9, readdir as readdir4 } from "fs/promises";
7798
8274
 
7799
8275
  // src/memory/observation-id.ts
7800
8276
  import { generateObservationId } from "@vostride/agent-qa-ids";
7801
8277
 
7802
8278
  // src/memory/curator.ts
7803
8279
  init_security_scanner();
7804
- var CuratorActionSchema = z19.discriminatedUnion("action", [
7805
- z19.object({
7806
- action: z19.literal("add"),
7807
- title: z19.string().min(1),
7808
- content: z19.string().min(1),
7809
- scope: z19.enum(["product", "suite", "test"]).describe('Use "suite" only if a suite context was provided'),
7810
- reasoning: z19.string()
8280
+ var CuratorActionSchema = z20.discriminatedUnion("action", [
8281
+ z20.object({
8282
+ action: z20.literal("add"),
8283
+ title: z20.string().min(1),
8284
+ content: z20.string().min(1),
8285
+ scope: z20.enum(["product", "suite", "test"]).describe('Use "suite" only if a suite context was provided'),
8286
+ reasoning: z20.string()
7811
8287
  }),
7812
- z19.object({
7813
- action: z19.literal("update"),
7814
- observationId: z19.string(),
7815
- reasoning: z19.string()
8288
+ z20.object({
8289
+ action: z20.literal("update"),
8290
+ observationId: z20.string(),
8291
+ reasoning: z20.string()
7816
8292
  }),
7817
- z19.object({
7818
- action: z19.literal("deprecate"),
7819
- observationId: z19.string(),
7820
- reasoning: z19.string()
8293
+ z20.object({
8294
+ action: z20.literal("deprecate"),
8295
+ observationId: z20.string(),
8296
+ reasoning: z20.string()
7821
8297
  }),
7822
- z19.object({
7823
- action: z19.literal("noop"),
7824
- reasoning: z19.string()
8298
+ z20.object({
8299
+ action: z20.literal("noop"),
8300
+ reasoning: z20.string()
7825
8301
  })
7826
8302
  ]);
7827
- var CuratorResponseSchema = z19.object({
7828
- decisions: z19.array(CuratorActionSchema)
8303
+ var CuratorResponseSchema = z20.object({
8304
+ decisions: z20.array(CuratorActionSchema)
7829
8305
  });
7830
8306
  function emptyLog() {
7831
8307
  return { added: 0, confirmed: 0, deprecated: 0, deleted: 0, deltas: [], errors: [], curatorDuration: 0 };
@@ -7944,7 +8420,7 @@ async function findObservationFile(memoryRoot, id) {
7944
8420
  const tierDir = join6(memoryRoot, tier);
7945
8421
  let scopes;
7946
8422
  try {
7947
- scopes = await readdir3(tierDir);
8423
+ scopes = await readdir4(tierDir);
7948
8424
  } catch {
7949
8425
  continue;
7950
8426
  }
@@ -7962,7 +8438,7 @@ async function findObservationFile(memoryRoot, id) {
7962
8438
  }
7963
8439
  async function readAndParseObservation(filePath, id) {
7964
8440
  try {
7965
- const raw = await readFile7(filePath, "utf-8");
8441
+ const raw = await readFile9(filePath, "utf-8");
7966
8442
  const { data, error } = parseObservation(raw, `${id}.md`);
7967
8443
  if (!data || error) return null;
7968
8444
  return { data, raw };
@@ -8183,7 +8659,7 @@ ${userMessage}`;
8183
8659
  for (const file of files) {
8184
8660
  try {
8185
8661
  const filePath = join6(suiteDir, file);
8186
- const raw = await readFile7(filePath, "utf-8");
8662
+ const raw = await readFile9(filePath, "utf-8");
8187
8663
  const { data } = parseObservation(raw, file);
8188
8664
  if (!data || !("suite_snapshot" in data)) continue;
8189
8665
  const suiteObs = data;
@@ -8385,6 +8861,7 @@ async function runSuite(suite, testEntries, config) {
8385
8861
  const results = [];
8386
8862
  const reporter = config.reporters?.length ? new MultiReporter(config.reporters) : void 0;
8387
8863
  const suiteRunId = config.runId ?? process.env.AGENT_QA_SUITE_QUEUE_ID ?? generateRunId();
8864
+ let suiteSandboxOptions = config.sandboxOptions && config.platformConfig.authState ? { ...config.sandboxOptions, authState: config.platformConfig.authState } : config.sandboxOptions;
8388
8865
  const suiteArtifact = config.artifactContext?.artifact ?? config.artifactContext;
8389
8866
  await reporter?.onSuiteStart(suite, {
8390
8867
  runId: suiteRunId,
@@ -8420,7 +8897,7 @@ async function runSuite(suite, testEntries, config) {
8420
8897
  return { runId: suiteRunId, name: suite.name, status: "failed", tests: earlyResults, duration: duration2, failedAt: 0 };
8421
8898
  };
8422
8899
  let suiteHookVars = {};
8423
- if (suite.setup?.length && config.resolvedHooks && config.sandboxOptions) {
8900
+ if (suite.setup?.length && config.resolvedHooks && suiteSandboxOptions) {
8424
8901
  const hookDefs = [];
8425
8902
  let hookMissing = false;
8426
8903
  for (const hookId of suite.setup) {
@@ -8439,14 +8916,14 @@ async function runSuite(suite, testEntries, config) {
8439
8916
  if (config.inlineVars) Object.assign(envVars, config.inlineVars);
8440
8917
  if (config.cliVars) Object.assign(envVars, config.cliVars);
8441
8918
  const result = await runHooks(hookDefs, {
8442
- ...config.sandboxOptions,
8919
+ ...suiteSandboxOptions,
8443
8920
  secretStore: config.secretStore,
8444
8921
  secretRedactor: config.secretRedactor,
8445
- envVars: { ...config.sandboxOptions.envVars, ...envVars }
8922
+ envVars: { ...suiteSandboxOptions.envVars, ...envVars }
8446
8923
  });
8447
8924
  for (const [name, hr] of result.results) {
8448
8925
  const hookDef = hookDefs.find((hook) => hook.name === name);
8449
- const hookExecId = randomUUID3();
8926
+ const hookExecId = randomUUID4();
8450
8927
  await reporter?.onHookStart?.({ hookId: hookDef?.id, hookName: name, phase: "setup", hookExecutionId: hookExecId, runId: suiteRunId });
8451
8928
  await reporter?.onHookEnd?.({
8452
8929
  hookId: hookDef?.id,
@@ -8542,7 +9019,7 @@ async function runSuite(suite, testEntries, config) {
8542
9019
  });
8543
9020
  let perTestHookVars = {};
8544
9021
  let perTestSetupFailed = false;
8545
- if (patched.setup?.length && config.resolvedHooks && config.sandboxOptions) {
9022
+ if (patched.setup?.length && config.resolvedHooks && suiteSandboxOptions) {
8546
9023
  const hookDefs = [];
8547
9024
  let hookMissing = false;
8548
9025
  for (const hookId of patched.setup) {
@@ -8560,13 +9037,13 @@ async function runSuite(suite, testEntries, config) {
8560
9037
  if (config.cliVars) Object.assign(allVars, config.cliVars);
8561
9038
  Object.assign(allVars, suiteHookVars);
8562
9039
  for (const hookDef of hookDefs) {
8563
- const hookExecId = randomUUID3();
9040
+ const hookExecId = randomUUID4();
8564
9041
  await reporter?.onHookStart?.({ hookId: hookDef.id, hookName: hookDef.name, phase: "setup", hookExecutionId: hookExecId, runId: childRunId });
8565
9042
  const hookResult = await runHooks([hookDef], {
8566
- ...config.sandboxOptions,
9043
+ ...suiteSandboxOptions,
8567
9044
  secretStore: config.secretStore,
8568
9045
  secretRedactor: config.secretRedactor,
8569
- envVars: { ...config.sandboxOptions.envVars, ...allVars, ...perTestHookVars }
9046
+ envVars: { ...suiteSandboxOptions.envVars, ...allVars, ...perTestHookVars }
8570
9047
  });
8571
9048
  const hr = hookResult.results.get(hookDef.name);
8572
9049
  await reporter?.onHookEnd?.({
@@ -8608,7 +9085,7 @@ async function runSuite(suite, testEntries, config) {
8608
9085
  }
8609
9086
  let testFileContent = "";
8610
9087
  try {
8611
- testFileContent = await readFile8(filePath, "utf-8");
9088
+ testFileContent = await readFile10(filePath, "utf-8");
8612
9089
  } catch {
8613
9090
  }
8614
9091
  const memoryInitParams = memoryEnabled ? {
@@ -8643,7 +9120,7 @@ async function runSuite(suite, testEntries, config) {
8643
9120
  cliVars: config.cliVars,
8644
9121
  hookSetupVars: perTestHookVars,
8645
9122
  inlineHookDefs: config.resolvedHooks,
8646
- inlineHookSandboxOptions: config.sandboxOptions,
9123
+ inlineHookSandboxOptions: suiteSandboxOptions,
8647
9124
  secretStore: config.secretStore,
8648
9125
  secretRedactor: config.secretRedactor,
8649
9126
  accessibility: config.accessibility,
@@ -8659,11 +9136,11 @@ async function runSuite(suite, testEntries, config) {
8659
9136
  parentRunId: suiteRunId
8660
9137
  }, filePath);
8661
9138
  if (!result.runId) result.runId = childRunId;
8662
- if (patched.teardown?.length && config.resolvedHooks && config.sandboxOptions) {
9139
+ if (patched.teardown?.length && config.resolvedHooks && suiteSandboxOptions) {
8663
9140
  for (const hookId of patched.teardown) {
8664
9141
  const hook = config.resolvedHooks.get(hookId);
8665
9142
  if (!hook) continue;
8666
- const hookExecId = randomUUID3();
9143
+ const hookExecId = randomUUID4();
8667
9144
  try {
8668
9145
  await reporter?.onHookStart?.({ hookId: hook.id, hookName: hook.name, phase: "teardown", hookExecutionId: hookExecId, runId: childRunId });
8669
9146
  const teardownVars = {};
@@ -8671,10 +9148,10 @@ async function runSuite(suite, testEntries, config) {
8671
9148
  if (config.cliVars) Object.assign(teardownVars, config.cliVars);
8672
9149
  Object.assign(teardownVars, suiteHookVars, perTestHookVars);
8673
9150
  const hookResult = await runHooks([hook], {
8674
- ...config.sandboxOptions,
9151
+ ...suiteSandboxOptions,
8675
9152
  secretStore: config.secretStore,
8676
9153
  secretRedactor: config.secretRedactor,
8677
- envVars: { ...config.sandboxOptions.envVars, ...teardownVars }
9154
+ envVars: { ...suiteSandboxOptions.envVars, ...teardownVars }
8678
9155
  });
8679
9156
  const hr = hookResult.results.get(hook.name);
8680
9157
  await reporter?.onHookEnd?.({
@@ -8811,8 +9288,27 @@ async function runSuite(suite, testEntries, config) {
8811
9288
  }
8812
9289
  }
8813
9290
  }
9291
+ if (config.authStateCapture && results.length > 0 && results.every((result) => result.status === "passed")) {
9292
+ try {
9293
+ const capturedAuthState = await config.authStateCapture.capture();
9294
+ suiteSandboxOptions = config.sandboxOptions ? { ...config.sandboxOptions, authState: capturedAuthState } : config.sandboxOptions;
9295
+ } catch {
9296
+ const captureFailureResult = {
9297
+ runId: suiteRunId,
9298
+ name: "Auth state capture",
9299
+ filePath: "",
9300
+ status: "failed",
9301
+ steps: [],
9302
+ duration: 0,
9303
+ failureSummary: config.authStateCapture.failureSummary,
9304
+ metadata: { phase: "auth-state-capture" }
9305
+ };
9306
+ results.push(captureFailureResult);
9307
+ await reporter?.onTestEnd(captureFailureResult);
9308
+ }
9309
+ }
8814
9310
  } finally {
8815
- if (suite.teardown?.length && config.resolvedHooks && config.sandboxOptions) {
9311
+ if (suite.teardown?.length && config.resolvedHooks && suiteSandboxOptions) {
8816
9312
  const teardownVars = {};
8817
9313
  if (config.envFileVars) Object.assign(teardownVars, config.envFileVars);
8818
9314
  if (config.inlineVars) Object.assign(teardownVars, config.inlineVars);
@@ -8821,14 +9317,14 @@ async function runSuite(suite, testEntries, config) {
8821
9317
  for (const hookId of suite.teardown) {
8822
9318
  const hook = config.resolvedHooks.get(hookId);
8823
9319
  if (!hook) continue;
8824
- const hookExecId = randomUUID3();
9320
+ const hookExecId = randomUUID4();
8825
9321
  try {
8826
9322
  await reporter?.onHookStart?.({ hookId: hook.id, hookName: hook.name, phase: "teardown", hookExecutionId: hookExecId, runId: suiteRunId });
8827
9323
  const hookResult = await runHooks([hook], {
8828
- ...config.sandboxOptions,
9324
+ ...suiteSandboxOptions,
8829
9325
  secretStore: config.secretStore,
8830
9326
  secretRedactor: config.secretRedactor,
8831
- envVars: { ...config.sandboxOptions.envVars, ...teardownVars }
9327
+ envVars: { ...suiteSandboxOptions.envVars, ...teardownVars }
8832
9328
  });
8833
9329
  const hr = hookResult.results.get(hook.name);
8834
9330
  await reporter?.onHookEnd?.({
@@ -8887,20 +9383,20 @@ async function runSuite(suite, testEntries, config) {
8887
9383
  }
8888
9384
 
8889
9385
  // src/validation/validate.ts
8890
- import { readFile as readFile10 } from "fs/promises";
9386
+ import { readFile as readFile12 } from "fs/promises";
8891
9387
  import { existsSync as existsSync6 } from "fs";
8892
- import path4 from "path";
9388
+ import path6 from "path";
8893
9389
  import { parse as parseYaml4, LineCounter as LineCounter2, parseDocument } from "yaml";
8894
9390
  import { glob as glob2 } from "glob";
8895
9391
 
8896
9392
  // src/hooks/parser.ts
8897
- import { readFile as readFile9 } from "fs/promises";
9393
+ import { readFile as readFile11 } from "fs/promises";
8898
9394
  import { dirname as dirname9, resolve as resolve5 } from "path";
8899
9395
  import { parse as parseYaml3 } from "yaml";
8900
9396
  async function parseHooksFile(filePath) {
8901
9397
  let raw;
8902
9398
  try {
8903
- raw = await readFile9(filePath, "utf-8");
9399
+ raw = await readFile11(filePath, "utf-8");
8904
9400
  } catch (err) {
8905
9401
  return { hooks: [], errors: [`Failed to read hooks file: ${err.message}`] };
8906
9402
  }
@@ -8928,20 +9424,20 @@ async function parseHooksFile(filePath) {
8928
9424
  }
8929
9425
 
8930
9426
  // src/utils/path-validation.ts
8931
- import path2 from "path";
9427
+ import path4 from "path";
8932
9428
  function isPathInsideDir(childPath, parentDir) {
8933
9429
  if (!childPath) return false;
8934
- const resolved = path2.resolve(parentDir, childPath);
8935
- const relative2 = path2.relative(parentDir, resolved);
8936
- return !!relative2 && !relative2.startsWith("..") && !path2.isAbsolute(relative2);
9430
+ const resolved = path4.resolve(parentDir, childPath);
9431
+ const relative2 = path4.relative(parentDir, resolved);
9432
+ return !!relative2 && !relative2.startsWith("..") && !path4.isAbsolute(relative2);
8937
9433
  }
8938
9434
 
8939
9435
  // src/workspace/workspace-paths.ts
8940
9436
  import { existsSync as existsSync5 } from "fs";
8941
- import path3 from "path";
9437
+ import path5 from "path";
8942
9438
  import { glob } from "glob";
8943
9439
  function toForwardSlash(value) {
8944
- return value.split(path3.sep).join("/");
9440
+ return value.split(path5.sep).join("/");
8945
9441
  }
8946
9442
  function trimLeadingCurrentDir(value) {
8947
9443
  return toForwardSlash(value).replace(/^\.\//, "");
@@ -8960,16 +9456,16 @@ function assertNonEmptyString(value, key) {
8960
9456
  }
8961
9457
  function resolveWorkspaceScalar(configDir, key, configuredPath) {
8962
9458
  const value = assertNonEmptyString(configuredPath, key);
8963
- const absolutePath = path3.isAbsolute(value) ? path3.resolve(value) : path3.resolve(configDir, value);
9459
+ const absolutePath = path5.isAbsolute(value) ? path5.resolve(value) : path5.resolve(configDir, value);
8964
9460
  return {
8965
9461
  configuredPath: value,
8966
9462
  absolutePath,
8967
- workspaceRelativePath: trimLeadingCurrentDir(path3.relative(configDir, absolutePath))
9463
+ workspaceRelativePath: trimLeadingCurrentDir(path5.relative(configDir, absolutePath))
8968
9464
  };
8969
9465
  }
8970
9466
  function assertInsideWorkspace(configDir, absolutePath, filePath) {
8971
- const relativePath = path3.relative(configDir, absolutePath);
8972
- if (!relativePath || relativePath.startsWith("..") || path3.isAbsolute(relativePath)) {
9467
+ const relativePath = path5.relative(configDir, absolutePath);
9468
+ if (!relativePath || relativePath.startsWith("..") || path5.isAbsolute(relativePath)) {
8973
9469
  throw new Error(`Workspace file path escapes config directory: ${filePath}`);
8974
9470
  }
8975
9471
  return trimLeadingCurrentDir(relativePath);
@@ -9026,8 +9522,8 @@ function isIgnored(workspace, workspaceRelativePath) {
9026
9522
  return workspace.testPathIgnore.length > 0 && matchesAnyPattern(workspaceRelativePath, workspace.testPathIgnore);
9027
9523
  }
9028
9524
  function resolveWorkspacePaths(input) {
9029
- const configPath = path3.resolve(input.configPath);
9030
- const configDir = path3.dirname(configPath);
9525
+ const configPath = path5.resolve(input.configPath);
9526
+ const configDir = path5.dirname(configPath);
9031
9527
  const workspace = input.config.workspace;
9032
9528
  if (!workspace) {
9033
9529
  throw new Error("Missing required workspace config key: workspace");
@@ -9065,14 +9561,14 @@ async function discoverWorkspaceFiles(input) {
9065
9561
  absolute: true,
9066
9562
  nodir: true
9067
9563
  });
9068
- return matches.map((match) => path3.resolve(match)).map((absolutePath) => ({
9564
+ return matches.map((match) => path5.resolve(match)).map((absolutePath) => ({
9069
9565
  kind: input.kind,
9070
9566
  absolutePath,
9071
- workspaceRelativePath: trimLeadingCurrentDir(path3.relative(input.workspace.configDir, absolutePath))
9567
+ workspaceRelativePath: trimLeadingCurrentDir(path5.relative(input.workspace.configDir, absolutePath))
9072
9568
  })).sort((a, b) => a.workspaceRelativePath.localeCompare(b.workspaceRelativePath));
9073
9569
  }
9074
9570
  async function resolveWorkspaceFileTarget(input) {
9075
- const absolutePath = path3.isAbsolute(input.filePath) ? path3.resolve(input.filePath) : path3.resolve(input.workspace.configDir, input.filePath);
9571
+ const absolutePath = path5.isAbsolute(input.filePath) ? path5.resolve(input.filePath) : path5.resolve(input.workspace.configDir, input.filePath);
9076
9572
  const workspaceRelativePath = assertInsideWorkspace(input.workspace.configDir, absolutePath, input.filePath);
9077
9573
  if (!isWorkspacePathMatch({
9078
9574
  workspace: input.workspace,
@@ -9100,7 +9596,7 @@ async function validateConfig(configPath) {
9100
9596
  const diagnostics = [];
9101
9597
  let content;
9102
9598
  try {
9103
- content = await readFile10(configPath, "utf-8");
9599
+ content = await readFile12(configPath, "utf-8");
9104
9600
  } catch (err) {
9105
9601
  diagnostics.push({
9106
9602
  file: configPath,
@@ -9202,7 +9698,7 @@ function validateSuiteFile(filePath, content, basedir) {
9202
9698
  });
9203
9699
  continue;
9204
9700
  }
9205
- const resolved = path4.resolve(basedir, testPath);
9701
+ const resolved = path6.resolve(basedir, testPath);
9206
9702
  if (!existsSync6(resolved)) {
9207
9703
  let line = 1;
9208
9704
  let column = 1;
@@ -9224,7 +9720,7 @@ function validateSuiteFile(filePath, content, basedir) {
9224
9720
  return diagnostics;
9225
9721
  }
9226
9722
  function validateFilename(filePath) {
9227
- const basename3 = path4.basename(filePath);
9723
+ const basename3 = path6.basename(filePath);
9228
9724
  if (!VALID_FILENAME_RE.test(basename3)) {
9229
9725
  return [{
9230
9726
  file: filePath,
@@ -9331,7 +9827,7 @@ async function validateFiles(filePaths, configPath, options = {}) {
9331
9827
  diagnostics.push(...validateFilename(filePath));
9332
9828
  let content;
9333
9829
  try {
9334
- content = await readFile10(filePath, "utf-8");
9830
+ content = await readFile12(filePath, "utf-8");
9335
9831
  } catch (err) {
9336
9832
  diagnostics.push({
9337
9833
  file: filePath,
@@ -9411,7 +9907,7 @@ async function validateProject(options = {}) {
9411
9907
  }
9412
9908
  filePaths = resolvedFiles;
9413
9909
  } else if (options.files && options.files.length > 0) {
9414
- filePaths = options.files.map((f) => path4.resolve(f));
9910
+ filePaths = options.files.map((f) => path6.resolve(f));
9415
9911
  } else if (options.workspace) {
9416
9912
  const [testFiles, suiteFiles] = await Promise.all([
9417
9913
  discoverWorkspaceFiles({ workspace: options.workspace, kind: "test" }),
@@ -9458,11 +9954,11 @@ async function validateProject(options = {}) {
9458
9954
  const { hooks } = await parseHooksFile(hooksFilePath);
9459
9955
  const hookIds = new Set(hooks.map((h) => h.id));
9460
9956
  for (const filePath of filePaths) {
9461
- const workspaceRelativePath = options.workspace ? path4.relative(options.workspace.configDir, filePath).split(path4.sep).join("/") : filePath;
9957
+ const workspaceRelativePath = options.workspace ? path6.relative(options.workspace.configDir, filePath).split(path6.sep).join("/") : filePath;
9462
9958
  const isWorkspaceFile = options.workspace ? isWorkspacePathMatch({ workspace: options.workspace, kind: isSuiteFile(filePath) ? "suite" : "test", workspaceRelativePath }) : true;
9463
9959
  if (!isWorkspaceFile) continue;
9464
9960
  try {
9465
- const content = await readFile10(filePath, "utf-8");
9961
+ const content = await readFile12(filePath, "utf-8");
9466
9962
  const parsed = parseYaml4(content);
9467
9963
  if (parsed && typeof parsed === "object") {
9468
9964
  const setup = parsed.setup;
@@ -9559,27 +10055,27 @@ function warnIfOutOfBounds(coords, viewport, actionType) {
9559
10055
  }
9560
10056
 
9561
10057
  // src/hooks/migrate-hook-refs.ts
9562
- import { mkdir as mkdir6, readFile as readFile11, rm as rm2, writeFile as writeFile6 } from "fs/promises";
10058
+ import { mkdir as mkdir7, readFile as readFile13, rm as rm3, writeFile as writeFile7 } from "fs/promises";
9563
10059
  import { dirname as dirname10, relative, resolve as resolve6 } from "path";
9564
10060
  import { parse as parseYaml5, stringify as stringifyYaml2 } from "yaml";
9565
- import { z as z20 } from "zod";
10061
+ import { z as z21 } from "zod";
9566
10062
  import { generateHookId, isCanonicalHookId as isCanonicalHookId5 } from "@vostride/agent-qa-ids";
9567
10063
  var DEFAULT_CLEANUP_TARGETS = [
9568
10064
  ".agent-qa"
9569
10065
  ];
9570
10066
  var HOOK_INLINE_RE = /\{\{runHook:"([^"]+)"\}\}/g;
9571
- var MigratableHookDefinitionSchema = z20.object({
9572
- id: z20.string().optional(),
9573
- name: z20.string().min(1),
9574
- runtime: z20.enum(["node", "bun", "python", "bash"]),
9575
- file: z20.string().min(1),
9576
- deps: z20.array(z20.string()).optional(),
9577
- packageFile: z20.string().optional(),
9578
- timeout: z20.string().min(1),
9579
- network: z20.boolean().optional()
10067
+ var MigratableHookDefinitionSchema = z21.object({
10068
+ id: z21.string().optional(),
10069
+ name: z21.string().min(1),
10070
+ runtime: z21.enum(["node", "bun", "python", "bash"]),
10071
+ file: z21.string().min(1),
10072
+ deps: z21.array(z21.string()).optional(),
10073
+ packageFile: z21.string().optional(),
10074
+ timeout: z21.string().min(1),
10075
+ network: z21.boolean().optional()
9580
10076
  }).strict();
9581
- var MigratableHooksFileSchema = z20.object({
9582
- hooks: z20.array(MigratableHookDefinitionSchema).min(1)
10077
+ var MigratableHooksFileSchema = z21.object({
10078
+ hooks: z21.array(MigratableHookDefinitionSchema).min(1)
9583
10079
  }).strict();
9584
10080
  var HookReferenceMigrationError = class extends Error {
9585
10081
  errors;
@@ -9667,7 +10163,7 @@ function rewriteSteps(owner, filePath, hookNameToId, hookIds, errors) {
9667
10163
  }
9668
10164
  async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9669
10165
  const resolvedConfigPath = configPath ? resolve6(configPath) : resolve6(workspaceDir, "agent-qa.config.yaml");
9670
- const rawConfig = await readFile11(resolvedConfigPath, "utf-8");
10166
+ const rawConfig = await readFile13(resolvedConfigPath, "utf-8");
9671
10167
  const parsedConfig = parseYaml5(rawConfig);
9672
10168
  const configResult = AgentQaConfigSchema.safeParse(parsedConfig);
9673
10169
  if (!configResult.success) {
@@ -9711,7 +10207,7 @@ async function auditWorkspaceHookReferenceMigration(options) {
9711
10207
  }
9712
10208
  let parsedHooksFile;
9713
10209
  try {
9714
- parsedHooksFile = parseYaml5(await readFile11(context.hooksFilePath, "utf-8"));
10210
+ parsedHooksFile = parseYaml5(await readFile13(context.hooksFilePath, "utf-8"));
9715
10211
  } catch (error) {
9716
10212
  return {
9717
10213
  ok: false,
@@ -9764,7 +10260,7 @@ async function auditWorkspaceHookReferenceMigration(options) {
9764
10260
  const absolutePath = resolve6(context.configDir, relativePath);
9765
10261
  let parsedFile;
9766
10262
  try {
9767
- parsedFile = parseYaml5(await readFile11(absolutePath, "utf-8"));
10263
+ parsedFile = parseYaml5(await readFile13(absolutePath, "utf-8"));
9768
10264
  } catch (error) {
9769
10265
  errors.push(`${relativePath}: ${error.message}`);
9770
10266
  continue;
@@ -9805,11 +10301,11 @@ async function applyWorkspaceHookReferenceMigration(options) {
9805
10301
  const workspaceDir = options.configPath ? dirname10(resolve6(options.configPath)) : resolve6(options.workspaceDir);
9806
10302
  for (const rewrite of audit.rewriteFiles) {
9807
10303
  const outputPath = resolve6(workspaceDir, rewrite.path);
9808
- await mkdir6(dirname10(outputPath), { recursive: true });
9809
- await writeFile6(outputPath, rewrite.content, "utf-8");
10304
+ await mkdir7(dirname10(outputPath), { recursive: true });
10305
+ await writeFile7(outputPath, rewrite.content, "utf-8");
9810
10306
  }
9811
10307
  for (const cleanupTarget of audit.cleanupTargets) {
9812
- await rm2(resolve6(workspaceDir, cleanupTarget), { recursive: true, force: true });
10308
+ await rm3(resolve6(workspaceDir, cleanupTarget), { recursive: true, force: true });
9813
10309
  }
9814
10310
  return audit;
9815
10311
  }
@@ -9878,7 +10374,7 @@ var CircuitBreaker = class {
9878
10374
  var RUN_ARTIFACT_SCHEMA_VERSION = 1;
9879
10375
 
9880
10376
  // src/analytics/identity.ts
9881
- import { chmod, mkdir as mkdir8, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
10377
+ import { chmod, mkdir as mkdir9, readFile as readFile17, writeFile as writeFile9 } from "fs/promises";
9882
10378
  import { homedir as homedir2 } from "os";
9883
10379
  import { dirname as dirname13, join as join10 } from "path";
9884
10380
  import { idAgent } from "id-agent";
@@ -9901,24 +10397,24 @@ function parseAnalyticsIdentityStore(value) {
9901
10397
  needsMigration: typeof rawIsInternal !== "boolean"
9902
10398
  };
9903
10399
  }
9904
- async function readAnalyticsIdentityStore(path5) {
9905
- const identityPath = path5 ?? getAnalyticsIdentityPath();
10400
+ async function readAnalyticsIdentityStore(path7) {
10401
+ const identityPath = path7 ?? getAnalyticsIdentityPath();
9906
10402
  try {
9907
- const data = await readFile15(identityPath, "utf-8");
10403
+ const data = await readFile17(identityPath, "utf-8");
9908
10404
  const parsed = JSON.parse(data);
9909
10405
  return parseAnalyticsIdentityStore(parsed);
9910
10406
  } catch {
9911
10407
  return null;
9912
10408
  }
9913
10409
  }
9914
- async function readAnalyticsIdentity(path5) {
9915
- const parsed = await readAnalyticsIdentityStore(path5);
10410
+ async function readAnalyticsIdentity(path7) {
10411
+ const parsed = await readAnalyticsIdentityStore(path7);
9916
10412
  return parsed ? { distinctId: parsed.distinctId, is_internal: parsed.is_internal } : null;
9917
10413
  }
9918
- async function writeAnalyticsIdentity(distinctId, path5, isInternal = false) {
9919
- const identityPath = path5 ?? getAnalyticsIdentityPath();
9920
- await mkdir8(dirname13(identityPath), { recursive: true });
9921
- await writeFile8(identityPath, JSON.stringify({
10414
+ async function writeAnalyticsIdentity(distinctId, path7, isInternal = false) {
10415
+ const identityPath = path7 ?? getAnalyticsIdentityPath();
10416
+ await mkdir9(dirname13(identityPath), { recursive: true });
10417
+ await writeFile9(identityPath, JSON.stringify({
9922
10418
  distinctId,
9923
10419
  is_internal: isInternal
9924
10420
  }, null, 2), { mode: 384 });
@@ -10130,7 +10626,7 @@ async function flushAnalytics(options) {
10130
10626
  }
10131
10627
 
10132
10628
  // src/analytics/events.ts
10133
- import { z as z21 } from "zod";
10629
+ import { z as z22 } from "zod";
10134
10630
  var ANALYTICS_EVENT_NAMES = [
10135
10631
  "agent-qa.analytics.initialized",
10136
10632
  "agent-qa.analytics.test_event",
@@ -10207,34 +10703,34 @@ var ANALYTICS_FAILURE_CATEGORIES = [
10207
10703
  "unknown"
10208
10704
  ];
10209
10705
  var ANALYTICS_SUITE_EXECUTION_MODES = ["sequential", "parallel", "unknown"];
10210
- var AnalyticsEventNameSchema = z21.enum(ANALYTICS_EVENT_NAMES);
10211
- var NonNegativeIntegerSchema = z21.number().int().min(0);
10212
- var NonNegativeNumberSchema = z21.number().min(0);
10213
- var AnalyticsBasePropertiesSchema = z21.object({
10214
- agent_qa_version: z21.string().min(1).optional(),
10215
- surface: z21.enum(ANALYTICS_SURFACES).optional(),
10216
- runtime_context: z21.enum(ANALYTICS_RUNTIME_CONTEXTS).optional(),
10217
- agent_product: z21.enum(ANALYTICS_AGENT_PRODUCTS).optional(),
10218
- transport: z21.enum(ANALYTICS_TRANSPORT_KINDS).optional(),
10219
- privacy_enabled: z21.boolean().optional(),
10220
- posthog_key_present: z21.boolean().optional(),
10221
- $process_person_profile: z21.literal(false).optional()
10706
+ var AnalyticsEventNameSchema = z22.enum(ANALYTICS_EVENT_NAMES);
10707
+ var NonNegativeIntegerSchema = z22.number().int().min(0);
10708
+ var NonNegativeNumberSchema = z22.number().min(0);
10709
+ var AnalyticsBasePropertiesSchema = z22.object({
10710
+ agent_qa_version: z22.string().min(1).optional(),
10711
+ surface: z22.enum(ANALYTICS_SURFACES).optional(),
10712
+ runtime_context: z22.enum(ANALYTICS_RUNTIME_CONTEXTS).optional(),
10713
+ agent_product: z22.enum(ANALYTICS_AGENT_PRODUCTS).optional(),
10714
+ transport: z22.enum(ANALYTICS_TRANSPORT_KINDS).optional(),
10715
+ privacy_enabled: z22.boolean().optional(),
10716
+ posthog_key_present: z22.boolean().optional(),
10717
+ $process_person_profile: z22.literal(false).optional()
10222
10718
  }).strip();
10223
10719
  var AnalyticsRunPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10224
- trigger_source: z21.enum(ANALYTICS_TRIGGER_SOURCES).optional(),
10225
- runner: z21.enum(ANALYTICS_RUNNERS).optional(),
10226
- platform: z21.enum(ANALYTICS_PLATFORMS).optional(),
10227
- status: z21.enum(ANALYTICS_RUN_STATUSES).optional(),
10720
+ trigger_source: z22.enum(ANALYTICS_TRIGGER_SOURCES).optional(),
10721
+ runner: z22.enum(ANALYTICS_RUNNERS).optional(),
10722
+ platform: z22.enum(ANALYTICS_PLATFORMS).optional(),
10723
+ status: z22.enum(ANALYTICS_RUN_STATUSES).optional(),
10228
10724
  duration_ms: NonNegativeNumberSchema.optional(),
10229
- run_id: z21.string().min(1).optional(),
10230
- parent_run_id: z21.string().min(1).optional(),
10231
- test_id: z21.string().min(1).optional(),
10232
- suite_id: z21.string().min(1).optional(),
10233
- model_name: z21.string().min(1).optional(),
10234
- provider: z21.string().min(1).optional(),
10235
- provider_mode: z21.string().min(1).optional(),
10236
- planner_model: z21.string().min(1).optional(),
10237
- verifier_model: z21.string().min(1).optional(),
10725
+ run_id: z22.string().min(1).optional(),
10726
+ parent_run_id: z22.string().min(1).optional(),
10727
+ test_id: z22.string().min(1).optional(),
10728
+ suite_id: z22.string().min(1).optional(),
10729
+ model_name: z22.string().min(1).optional(),
10730
+ provider: z22.string().min(1).optional(),
10731
+ provider_mode: z22.string().min(1).optional(),
10732
+ planner_model: z22.string().min(1).optional(),
10733
+ verifier_model: z22.string().min(1).optional(),
10238
10734
  input_tokens: NonNegativeIntegerSchema.optional(),
10239
10735
  output_tokens: NonNegativeIntegerSchema.optional(),
10240
10736
  total_tokens: NonNegativeIntegerSchema.optional(),
@@ -10251,16 +10747,16 @@ var AnalyticsRunPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10251
10747
  hook_count: NonNegativeIntegerSchema.optional(),
10252
10748
  failed_hook_count: NonNegativeIntegerSchema.optional(),
10253
10749
  retry_count: NonNegativeIntegerSchema.optional(),
10254
- is_flaky: z21.boolean().optional(),
10255
- cancelled: z21.boolean().optional(),
10256
- timed_out: z21.boolean().optional(),
10257
- failure_category: z21.enum(ANALYTICS_FAILURE_CATEGORIES).optional(),
10258
- browser_name: z21.string().min(1).optional(),
10259
- mobile_transport: z21.string().min(1).optional(),
10260
- mobile_provider: z21.string().min(1).optional(),
10261
- app_state: z21.string().min(1).optional(),
10262
- execution_destination: z21.string().min(1).optional(),
10263
- memory_enabled: z21.boolean().optional(),
10750
+ is_flaky: z22.boolean().optional(),
10751
+ cancelled: z22.boolean().optional(),
10752
+ timed_out: z22.boolean().optional(),
10753
+ failure_category: z22.enum(ANALYTICS_FAILURE_CATEGORIES).optional(),
10754
+ browser_name: z22.string().min(1).optional(),
10755
+ mobile_transport: z22.string().min(1).optional(),
10756
+ mobile_provider: z22.string().min(1).optional(),
10757
+ app_state: z22.string().min(1).optional(),
10758
+ execution_destination: z22.string().min(1).optional(),
10759
+ memory_enabled: z22.boolean().optional(),
10264
10760
  memory_injected_observation_count: NonNegativeIntegerSchema.optional(),
10265
10761
  memory_curator_input_tokens: NonNegativeIntegerSchema.optional(),
10266
10762
  memory_curator_output_tokens: NonNegativeIntegerSchema.optional(),
@@ -10274,33 +10770,33 @@ var AnalyticsRunPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10274
10770
  suite_passed_count: NonNegativeIntegerSchema.optional(),
10275
10771
  suite_failed_count: NonNegativeIntegerSchema.optional(),
10276
10772
  suite_skipped_count: NonNegativeIntegerSchema.optional(),
10277
- suite_execution_mode: z21.enum(ANALYTICS_SUITE_EXECUTION_MODES).optional(),
10773
+ suite_execution_mode: z22.enum(ANALYTICS_SUITE_EXECUTION_MODES).optional(),
10278
10774
  mcp_tool_count: NonNegativeIntegerSchema.optional()
10279
10775
  }).strip();
10280
10776
  var AnalyticsDashboardOpenedPropertiesSchema = AnalyticsBasePropertiesSchema;
10281
10777
  var AnalyticsDashboardLiveModeStartedPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10282
- platform: z21.enum(ANALYTICS_PLATFORMS).optional(),
10283
- entity_type: z21.enum(["test", "suite", "unknown"]).optional()
10778
+ platform: z22.enum(ANALYTICS_PLATFORMS).optional(),
10779
+ entity_type: z22.enum(["test", "suite", "unknown"]).optional()
10284
10780
  }).strip();
10285
10781
  var AnalyticsDashboardEntityCreatedPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10286
- entity_type: z21.enum(["test", "suite", "hook"]).optional(),
10287
- outcome: z21.enum(ANALYTICS_DASHBOARD_OUTCOMES).optional()
10782
+ entity_type: z22.enum(["test", "suite", "hook"]).optional(),
10783
+ outcome: z22.enum(ANALYTICS_DASHBOARD_OUTCOMES).optional()
10288
10784
  }).strip();
10289
10785
  var AnalyticsMcpServerLifecyclePropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10290
- mcp_server_state: z21.enum(ANALYTICS_MCP_SERVER_STATES).optional(),
10291
- mcp_transport: z21.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
10292
- mcp_host_kind: z21.enum(ANALYTICS_MCP_HOST_KINDS).optional(),
10293
- mcp_port_kind: z21.enum(ANALYTICS_MCP_PORT_KINDS).optional(),
10294
- mcp_path_kind: z21.enum(ANALYTICS_MCP_PATH_KINDS).optional()
10786
+ mcp_server_state: z22.enum(ANALYTICS_MCP_SERVER_STATES).optional(),
10787
+ mcp_transport: z22.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
10788
+ mcp_host_kind: z22.enum(ANALYTICS_MCP_HOST_KINDS).optional(),
10789
+ mcp_port_kind: z22.enum(ANALYTICS_MCP_PORT_KINDS).optional(),
10790
+ mcp_path_kind: z22.enum(ANALYTICS_MCP_PATH_KINDS).optional()
10295
10791
  }).strip();
10296
10792
  var AnalyticsMcpToolInvokedPropertiesSchema = AnalyticsBasePropertiesSchema.extend({
10297
- tool_name: z21.string().min(1).optional(),
10298
- mcp_tool_category: z21.enum(ANALYTICS_MCP_TOOL_CATEGORIES).optional(),
10299
- mcp_tool_status: z21.enum(ANALYTICS_MCP_TOOL_STATUSES).optional(),
10793
+ tool_name: z22.string().min(1).optional(),
10794
+ mcp_tool_category: z22.enum(ANALYTICS_MCP_TOOL_CATEGORIES).optional(),
10795
+ mcp_tool_status: z22.enum(ANALYTICS_MCP_TOOL_STATUSES).optional(),
10300
10796
  duration_ms: NonNegativeNumberSchema.optional(),
10301
- mcp_error_category: z21.enum(ANALYTICS_MCP_ERROR_CATEGORIES).optional(),
10302
- mcp_transport: z21.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
10303
- run_id: z21.string().min(1).optional()
10797
+ mcp_error_category: z22.enum(ANALYTICS_MCP_ERROR_CATEGORIES).optional(),
10798
+ mcp_transport: z22.enum(ANALYTICS_MCP_TRANSPORTS).optional(),
10799
+ run_id: z22.string().min(1).optional()
10304
10800
  }).strip();
10305
10801
  var AnalyticsEventPropertiesSchemaByName = {
10306
10802
  "agent-qa.analytics.initialized": AnalyticsRunPropertiesSchema,
@@ -10468,7 +10964,7 @@ function formatRunAttributesBlock(attributes) {
10468
10964
  }
10469
10965
 
10470
10966
  // src/analytics/run-reporter.ts
10471
- function isRecord(value) {
10967
+ function isRecord2(value) {
10472
10968
  return typeof value === "object" && value !== null && !Array.isArray(value);
10473
10969
  }
10474
10970
  function readString(value) {
@@ -10481,9 +10977,9 @@ function readBoolean(value) {
10481
10977
  return typeof value === "boolean" ? value : void 0;
10482
10978
  }
10483
10979
  function readNestedRecord(source, key) {
10484
- if (!isRecord(source)) return void 0;
10980
+ if (!isRecord2(source)) return void 0;
10485
10981
  const value = source[key];
10486
- return isRecord(value) ? value : void 0;
10982
+ return isRecord2(value) ? value : void 0;
10487
10983
  }
10488
10984
  function readAttributes(value) {
10489
10985
  try {
@@ -10527,13 +11023,13 @@ function normalizeSuiteExecutionMode(value) {
10527
11023
  return void 0;
10528
11024
  }
10529
11025
  function readArtifactSource(context) {
10530
- return isRecord(context?.artifact?.source) ? context?.artifact?.source : void 0;
11026
+ return isRecord2(context?.artifact?.source) ? context?.artifact?.source : void 0;
10531
11027
  }
10532
11028
  function readArtifactConfig(context) {
10533
- return isRecord(context?.artifact?.config) ? context?.artifact?.config : void 0;
11029
+ return isRecord2(context?.artifact?.config) ? context?.artifact?.config : void 0;
10534
11030
  }
10535
11031
  function readArtifactRuntime(context) {
10536
- const artifactRuntime = isRecord(context?.artifact?.runtime) ? context?.artifact?.runtime : void 0;
11032
+ const artifactRuntime = isRecord2(context?.artifact?.runtime) ? context?.artifact?.runtime : void 0;
10537
11033
  const configRuntime = readNestedRecord(readArtifactConfig(context), "runtime");
10538
11034
  return {
10539
11035
  ...configRuntime ?? {},
@@ -10641,14 +11137,14 @@ function collectMemoryMetrics(result, state) {
10641
11137
  if (state?.memoryInjectedObservationCount !== void 0) {
10642
11138
  properties.memory_injected_observation_count = state.memoryInjectedObservationCount;
10643
11139
  }
10644
- if (!isRecord(log)) return properties;
11140
+ if (!isRecord2(log)) return properties;
10645
11141
  properties.memory_enabled = properties.memory_enabled ?? true;
10646
11142
  properties.memory_added_count = readNumber(log.added);
10647
11143
  properties.memory_confirmed_count = readNumber(log.confirmed);
10648
11144
  properties.memory_deprecated_count = readNumber(log.deprecated);
10649
11145
  properties.memory_deleted_count = readNumber(log.deleted);
10650
11146
  properties.memory_error_count = Array.isArray(log.errors) ? log.errors.length : void 0;
10651
- const tokenUsage = isRecord(log.tokenUsage) ? log.tokenUsage : void 0;
11147
+ const tokenUsage = isRecord2(log.tokenUsage) ? log.tokenUsage : void 0;
10652
11148
  properties.memory_curator_input_tokens = readNumber(tokenUsage?.promptTokens);
10653
11149
  properties.memory_curator_output_tokens = readNumber(tokenUsage?.completionTokens);
10654
11150
  properties.memory_curator_total_tokens = readNumber(tokenUsage?.totalTokens);
@@ -10705,7 +11201,7 @@ var AnalyticsRunReporter = class {
10705
11201
  if (this.disabled) return;
10706
11202
  const runId = context?.runId ?? readString(context?.artifact?.runtime?.runId);
10707
11203
  if (!runId) return;
10708
- const runtime = isRecord(context?.artifact?.runtime) ? context?.artifact?.runtime : {};
11204
+ const runtime = isRecord2(context?.artifact?.runtime) ? context?.artifact?.runtime : {};
10709
11205
  this.suiteStates.set(runId, {
10710
11206
  runId,
10711
11207
  suiteId: readSuiteId(suite, context),
@@ -10751,7 +11247,7 @@ var AnalyticsRunReporter = class {
10751
11247
  }
10752
11248
  async captureTestResult(result) {
10753
11249
  const state = this.findStateForResult(result);
10754
- const resultMetadata = isRecord(result.metadata) ? result.metadata : void 0;
11250
+ const resultMetadata = isRecord2(result.metadata) ? result.metadata : void 0;
10755
11251
  const resultRuntime = readNestedRecord(resultMetadata, "runtime");
10756
11252
  const resultAttributes = readAttributes(resultMetadata?.attributes);
10757
11253
  const retryCount = typeof result.retryCount === "number" && result.retryCount >= 0 ? result.retryCount : void 0;
@@ -10831,15 +11327,6 @@ function createAnalyticsRunReporter(options = {}) {
10831
11327
  // src/index.ts
10832
11328
  init_sqlite();
10833
11329
 
10834
- // src/runtime-paths.ts
10835
- var DEFAULT_AGENT_QA_RUNTIME_DIR = ".agent-qa";
10836
- var DEFAULT_AGENT_QA_ARTIFACTS_DIR = ".agent-qa/artifacts";
10837
- var DEFAULT_AGENT_QA_CACHE_DIR = ".agent-qa/cache";
10838
- var DEFAULT_AGENT_QA_SCREENSHOTS_DIR = ".agent-qa/artifacts/screenshots";
10839
- var DEFAULT_AGENT_QA_VIDEOS_DIR = ".agent-qa/artifacts/videos";
10840
- var DEFAULT_AGENT_QA_RUNS_DB_PATH = ".agent-qa/runs.db";
10841
- var LEGACY_AGENT_QA_DASHBOARD_DB_PATH = ".agent-qa/dashboard.db";
10842
-
10843
11330
  // src/screenshot/align.ts
10844
11331
  import sharp3 from "sharp";
10845
11332
  async function alignToWindow(buffer, opts) {
@@ -10892,6 +11379,14 @@ export {
10892
11379
  ANDROID_ROLE_MAP,
10893
11380
  ATTR_RUNNER,
10894
11381
  ATTR_TRIGGER,
11382
+ AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,
11383
+ AUTH_STATE_HOOK_JSON_ENV,
11384
+ AUTH_STATE_HOOK_STORAGE_STATE_FILENAME,
11385
+ AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV,
11386
+ AUTH_STATE_HOOK_WORKSPACE_DIR,
11387
+ AUTH_STATE_REDACTION_MARKER,
11388
+ AUTH_STATE_SCHEMA_VERSION,
11389
+ AUTH_STATE_SLUG_PATTERN,
10895
11390
  AccessibilityConfigSchema,
10896
11391
  ActionPlanSchema,
10897
11392
  AdapterLogDataSchema,
@@ -10902,6 +11397,10 @@ export {
10902
11397
  AssertionEvaluator,
10903
11398
  AssertionResultSchema,
10904
11399
  AuthPluginDeclarationSchema,
11400
+ AuthStateConfigSchema,
11401
+ AuthStateMetadataSchema,
11402
+ AuthStateNameSchema,
11403
+ AuthStateUseSchema,
10905
11404
  BaseObservationSchema,
10906
11405
  BrowserConfigSchema,
10907
11406
  CACHE_SCHEMA_VERSION,
@@ -10912,6 +11411,7 @@ export {
10912
11411
  ConsoleReporter,
10913
11412
  CuratorResponseSchema,
10914
11413
  DEFAULT_AGENT_QA_ARTIFACTS_DIR,
11414
+ DEFAULT_AGENT_QA_AUTH_STATES_DIR,
10915
11415
  DEFAULT_AGENT_QA_CACHE_DIR,
10916
11416
  DEFAULT_AGENT_QA_RUNS_DB_PATH,
10917
11417
  DEFAULT_AGENT_QA_RUNTIME_DIR,
@@ -10982,6 +11482,7 @@ export {
10982
11482
  SuiteDefinitionSchema,
10983
11483
  SuiteObservationSchema,
10984
11484
  SuiteTestEntrySchema,
11485
+ TargetNameSchema,
10985
11486
  TargetSchema,
10986
11487
  TestDefinitionSchema,
10987
11488
  TestMetaSchema,
@@ -11000,6 +11501,7 @@ export {
11000
11501
  browserstackProvider,
11001
11502
  buildAnalyticsEvent,
11002
11503
  buildAssertionPrompt,
11504
+ buildAuthStateHookEnv,
11003
11505
  buildExtractionPrompt,
11004
11506
  buildInternalRunAttributes,
11005
11507
  buildMemoryIndex,
@@ -11070,7 +11572,9 @@ export {
11070
11572
  isBetterSqlite3NodeGypSymlinkConflict,
11071
11573
  isMacPlatform,
11072
11574
  isPathInsideDir,
11575
+ isReservedAuthStateHookEnvKey,
11073
11576
  isWorkspacePathMatch,
11577
+ listAuthStateMetadata,
11074
11578
  listLLMAuthProviderPlugins,
11075
11579
  listObservations,
11076
11580
  listProviders,
@@ -11079,6 +11583,7 @@ export {
11079
11583
  mapMobileCapabilities,
11080
11584
  mapWebCapabilities,
11081
11585
  mergeRunAttributes,
11586
+ normalizeAuthStateUse,
11082
11587
  normalizeRole,
11083
11588
  parseAllTests,
11084
11589
  parseEnvFile,
@@ -11092,17 +11597,25 @@ export {
11092
11597
  parseTestFile,
11093
11598
  readAnalyticsIdentity,
11094
11599
  readAuth,
11600
+ readAuthStateMetadata,
11601
+ redactAuthStateString,
11602
+ redactAuthStateValue,
11095
11603
  redactSecretValue,
11096
11604
  registerAllProviders,
11097
11605
  registerLLMAuthProviderPlugin,
11098
11606
  registerLLMAuthProviderPlugins,
11099
11607
  registerProvider,
11100
11608
  removeAuth,
11609
+ removeAuthStateFiles,
11610
+ removeAuthStateTarget,
11101
11611
  resetAnalyticsServiceForTests,
11102
11612
  resolveAnalyticsAgentProduct,
11103
11613
  resolveAnalyticsIdentity,
11104
11614
  resolveAnalyticsStandardProperties,
11105
11615
  resolveAppiumExecutable,
11616
+ resolveAuthStateForRun,
11617
+ resolveAuthStatePaths,
11618
+ resolveAuthStateRoot,
11106
11619
  resolveBetterSqliteRebuildCommand,
11107
11620
  resolveFarmCredentials,
11108
11621
  resolveFileReferences,
@@ -11123,6 +11636,7 @@ export {
11123
11636
  shouldAblate,
11124
11637
  sortRunAttributesForDisplay,
11125
11638
  stripHookInline,
11639
+ stripReservedAuthStateHookEnv,
11126
11640
  toolCallToActionPlan,
11127
11641
  toolSchemaMiddleware,
11128
11642
  truncateScreenState,
@@ -11137,6 +11651,7 @@ export {
11137
11651
  warnIfOutOfBounds,
11138
11652
  writeAnalyticsIdentity,
11139
11653
  writeAuth,
11654
+ writeAuthStateFiles,
11140
11655
  writeObservation
11141
11656
  };
11142
11657
  //# sourceMappingURL=index.js.map