@vostride/agent-qa-core 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1217 -674
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -1
- package/dist/index.d.ts +164 -1
- package/dist/index.js +1097 -582
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
39
|
-
test:
|
|
40
|
-
id:
|
|
38
|
+
ObservationSuiteSnapshotEntrySchema = z19.object({
|
|
39
|
+
test: z19.string(),
|
|
40
|
+
id: z19.string()
|
|
41
41
|
}).strict();
|
|
42
|
-
BaseObservationSchema =
|
|
42
|
+
BaseObservationSchema = z19.object({
|
|
43
43
|
id: ObservationIdSchema,
|
|
44
|
-
title:
|
|
45
|
-
content:
|
|
46
|
-
trust:
|
|
47
|
-
created:
|
|
48
|
-
last_confirmed:
|
|
49
|
-
confirmed_count:
|
|
50
|
-
contradicted_count:
|
|
51
|
-
source_test:
|
|
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:
|
|
55
|
-
suite_snapshot:
|
|
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:
|
|
62
|
-
suite_snapshot:
|
|
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
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
362
|
+
function openBetterSqlite3Database(path7) {
|
|
363
363
|
const Database = loadBetterSqlite3();
|
|
364
|
-
return new Database(
|
|
364
|
+
return new Database(path7);
|
|
365
365
|
}
|
|
366
|
-
function createBetterSqlite3Database(
|
|
366
|
+
function createBetterSqlite3Database(path7) {
|
|
367
367
|
try {
|
|
368
|
-
return openBetterSqlite3Database(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
1086
|
-
path:
|
|
1087
|
-
browserstack:
|
|
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 =
|
|
1090
|
-
product:
|
|
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:
|
|
1095
|
-
bundleId:
|
|
1096
|
-
appPackage:
|
|
1097
|
-
appActivity:
|
|
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:
|
|
1125
|
+
url: z5.string().optional()
|
|
1100
1126
|
}).strict().superRefine((val, ctx) => {
|
|
1101
1127
|
if (val.platform === "web" && !val.url) {
|
|
1102
|
-
ctx.addIssue({ code:
|
|
1128
|
+
ctx.addIssue({ code: z5.ZodIssueCode.custom, message: "Web targets must have a url" });
|
|
1103
1129
|
}
|
|
1104
1130
|
});
|
|
1105
|
-
var DeviceProfileSchema =
|
|
1106
|
-
platform:
|
|
1131
|
+
var DeviceProfileSchema = z5.object({
|
|
1132
|
+
platform: z5.enum(["android", "ios"]),
|
|
1107
1133
|
transport: TransportSchema,
|
|
1108
|
-
match:
|
|
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:
|
|
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 =
|
|
1126
|
-
var RegistrySchema =
|
|
1127
|
-
llms:
|
|
1128
|
-
targets:
|
|
1129
|
-
devices:
|
|
1130
|
-
providers:
|
|
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
|
|
1135
|
-
var MobileAppStateSchema =
|
|
1136
|
-
var MobileUseSchema =
|
|
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 =
|
|
1165
|
+
var MobileUseOverrideSchema = z6.object({
|
|
1140
1166
|
appState: MobileAppStateSchema.optional()
|
|
1141
1167
|
}).strict();
|
|
1142
|
-
var
|
|
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:
|
|
1150
|
-
llm:
|
|
1151
|
-
parallel:
|
|
1199
|
+
cache: z6.boolean().optional(),
|
|
1200
|
+
llm: z6.string().optional(),
|
|
1201
|
+
parallel: z6.boolean().optional()
|
|
1152
1202
|
}).strict();
|
|
1153
|
-
var UseOverrideSchema =
|
|
1154
|
-
browser:
|
|
1155
|
-
name:
|
|
1156
|
-
headless:
|
|
1157
|
-
viewport:
|
|
1158
|
-
width:
|
|
1159
|
-
height:
|
|
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:
|
|
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:
|
|
1168
|
-
maxAttempts:
|
|
1217
|
+
healing: z6.object({
|
|
1218
|
+
maxAttempts: z6.number().optional()
|
|
1169
1219
|
}).strict().optional(),
|
|
1170
|
-
planner:
|
|
1171
|
-
maxSubActions:
|
|
1172
|
-
previousStepCount:
|
|
1220
|
+
planner: z6.object({
|
|
1221
|
+
maxSubActions: z6.number().optional(),
|
|
1222
|
+
previousStepCount: z6.number().optional()
|
|
1173
1223
|
}).strict().optional(),
|
|
1174
|
-
logCapture:
|
|
1175
|
-
console:
|
|
1176
|
-
network:
|
|
1224
|
+
logCapture: z6.object({
|
|
1225
|
+
console: z6.boolean().optional(),
|
|
1226
|
+
network: z6.boolean().optional()
|
|
1177
1227
|
}).strict().optional(),
|
|
1178
|
-
cache:
|
|
1228
|
+
cache: z6.boolean().optional(),
|
|
1229
|
+
authState: AuthStateUseSchema.optional(),
|
|
1179
1230
|
mobile: MobileUseOverrideSchema.optional(),
|
|
1180
|
-
llm:
|
|
1181
|
-
parallel:
|
|
1182
|
-
device:
|
|
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
|
|
1187
|
-
var AttributePredicateSchema =
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
regex:
|
|
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 =
|
|
1194
|
-
privacy:
|
|
1195
|
-
passRateScope:
|
|
1196
|
-
attributes:
|
|
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 =
|
|
1202
|
-
|
|
1203
|
-
package:
|
|
1252
|
+
var AuthPluginDeclarationSchema = z8.union([
|
|
1253
|
+
z8.object({
|
|
1254
|
+
package: z8.string().trim().min(1)
|
|
1204
1255
|
}).strict(),
|
|
1205
|
-
|
|
1206
|
-
path:
|
|
1256
|
+
z8.object({
|
|
1257
|
+
path: z8.string().trim().min(1)
|
|
1207
1258
|
}).strict()
|
|
1208
1259
|
]);
|
|
1209
|
-
var PluginsSchema =
|
|
1210
|
-
auth:
|
|
1260
|
+
var PluginsSchema = z8.object({
|
|
1261
|
+
auth: z8.array(AuthPluginDeclarationSchema).optional().default([])
|
|
1211
1262
|
}).strict();
|
|
1212
|
-
var AgentQaConfigSchema =
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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 =
|
|
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 =
|
|
1261
|
-
variable:
|
|
1262
|
-
method:
|
|
1263
|
-
pattern:
|
|
1264
|
-
selector:
|
|
1265
|
-
description:
|
|
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 =
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
step:
|
|
1318
|
+
var TestStepSchema = z9.union([
|
|
1319
|
+
z9.string(),
|
|
1320
|
+
z9.object({
|
|
1321
|
+
step: z9.string(),
|
|
1271
1322
|
timeout: OptionalDuration,
|
|
1272
|
-
retries:
|
|
1273
|
-
screenshot:
|
|
1323
|
+
retries: z9.number().optional(),
|
|
1324
|
+
screenshot: z9.boolean().optional(),
|
|
1274
1325
|
capture: CaptureConfigSchema.optional(),
|
|
1275
|
-
maxAttempts:
|
|
1326
|
+
maxAttempts: z9.number().optional()
|
|
1276
1327
|
}).strict()
|
|
1277
1328
|
]);
|
|
1278
|
-
var TestMetaSchema =
|
|
1329
|
+
var TestMetaSchema = z9.object({
|
|
1279
1330
|
timeout: OptionalDuration,
|
|
1280
|
-
retries:
|
|
1281
|
-
record:
|
|
1331
|
+
retries: z9.number().optional(),
|
|
1332
|
+
record: z9.boolean().optional()
|
|
1282
1333
|
}).strict();
|
|
1283
|
-
var HookIdSchema =
|
|
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 =
|
|
1287
|
-
"test-id":
|
|
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:
|
|
1291
|
-
target:
|
|
1292
|
-
context:
|
|
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:
|
|
1296
|
-
teardown:
|
|
1297
|
-
steps:
|
|
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
|
|
1302
|
-
var ActionPlanSchema =
|
|
1303
|
-
reasoning:
|
|
1304
|
-
action:
|
|
1305
|
-
confidence:
|
|
1306
|
-
stepComplete:
|
|
1307
|
-
stepFailed:
|
|
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
|
|
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 =
|
|
1314
|
-
test:
|
|
1315
|
-
id:
|
|
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 =
|
|
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 =
|
|
1323
|
-
"suite-id":
|
|
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:
|
|
1327
|
-
target:
|
|
1328
|
-
context:
|
|
1329
|
-
setup:
|
|
1330
|
-
teardown:
|
|
1331
|
-
tests:
|
|
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
|
|
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 =
|
|
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 =
|
|
1344
|
-
id:
|
|
1394
|
+
var HookDefinitionSchema = z12.object({
|
|
1395
|
+
id: z12.string().refine((value) => isCanonicalHookId3(value), {
|
|
1345
1396
|
message: HOOK_ID_MESSAGE
|
|
1346
1397
|
}),
|
|
1347
|
-
name:
|
|
1348
|
-
runtime:
|
|
1349
|
-
file:
|
|
1350
|
-
deps:
|
|
1351
|
-
packageFile:
|
|
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:
|
|
1404
|
+
network: z12.boolean().optional().default(true)
|
|
1354
1405
|
});
|
|
1355
|
-
var HooksFileSchema =
|
|
1356
|
-
hooks:
|
|
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:
|
|
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:
|
|
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,
|
|
1437
|
-
const field =
|
|
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,
|
|
1512
|
+
function resolveNodeAtPath(doc, path7) {
|
|
1462
1513
|
let current = doc.contents;
|
|
1463
1514
|
if (!current) return null;
|
|
1464
|
-
for (const segment of
|
|
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
|
|
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
|
|
1715
|
+
import { z as z13 } from "zod";
|
|
1665
1716
|
var PLAN_FIELDS = {
|
|
1666
|
-
reasoning:
|
|
1667
|
-
confidence:
|
|
1668
|
-
stepComplete:
|
|
1669
|
-
stepFailed:
|
|
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:
|
|
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
|
|
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",
|
|
1721
|
-
ref:
|
|
1722
|
-
clickDelay:
|
|
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",
|
|
1725
|
-
ref:
|
|
1726
|
-
value:
|
|
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",
|
|
1729
|
-
ref:
|
|
1730
|
-
value:
|
|
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",
|
|
1733
|
-
ref:
|
|
1734
|
-
value:
|
|
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",
|
|
1737
|
-
url:
|
|
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",
|
|
1740
|
-
scrollType:
|
|
1741
|
-
value:
|
|
1742
|
-
ref:
|
|
1743
|
-
duration:
|
|
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).',
|
|
1746
|
-
ms:
|
|
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)",
|
|
1749
|
-
condition:
|
|
1750
|
-
timeout:
|
|
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",
|
|
1753
|
-
condition:
|
|
1754
|
-
expected:
|
|
1755
|
-
visual:
|
|
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",
|
|
1758
|
-
keys:
|
|
1759
|
-
convertPlatformKeys:
|
|
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",
|
|
1762
|
-
ref:
|
|
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",
|
|
1765
|
-
ref:
|
|
1766
|
-
value:
|
|
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)",
|
|
1769
|
-
key:
|
|
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",
|
|
1772
|
-
key:
|
|
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",
|
|
1775
|
-
action("navigateHistory", "Navigate browser history (back or forward)",
|
|
1776
|
-
direction:
|
|
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",
|
|
1779
|
-
level:
|
|
1780
|
-
tab:
|
|
1781
|
-
index:
|
|
1782
|
-
title:
|
|
1783
|
-
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",
|
|
1787
|
-
urlPattern:
|
|
1788
|
-
tab:
|
|
1789
|
-
index:
|
|
1790
|
-
title:
|
|
1791
|
-
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",
|
|
1795
|
-
name:
|
|
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",
|
|
1798
|
-
cookies:
|
|
1799
|
-
name:
|
|
1800
|
-
value:
|
|
1801
|
-
domain:
|
|
1802
|
-
path:
|
|
1803
|
-
httpOnly:
|
|
1804
|
-
secure:
|
|
1805
|
-
sameSite:
|
|
1806
|
-
expires:
|
|
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",
|
|
1810
|
-
key:
|
|
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",
|
|
1813
|
-
entries:
|
|
1814
|
-
key:
|
|
1815
|
-
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",
|
|
1819
|
-
ref:
|
|
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",
|
|
1822
|
-
direction:
|
|
1823
|
-
ref:
|
|
1824
|
-
startX:
|
|
1825
|
-
startY:
|
|
1826
|
-
endX:
|
|
1827
|
-
endY:
|
|
1828
|
-
duration:
|
|
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",
|
|
1831
|
-
ref:
|
|
1832
|
-
duration:
|
|
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)",
|
|
1835
|
-
action("clearText", "Clear all text from an input field without typing new text",
|
|
1836
|
-
ref:
|
|
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",
|
|
1839
|
-
url:
|
|
1840
|
-
appId:
|
|
1841
|
-
bundleId:
|
|
1842
|
-
appPackage:
|
|
1843
|
-
waitForLaunch:
|
|
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)",
|
|
1846
|
-
fromRef:
|
|
1847
|
-
toRef:
|
|
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)",
|
|
1850
|
-
ref:
|
|
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",
|
|
1853
|
-
bundleId:
|
|
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",
|
|
1856
|
-
bundleId:
|
|
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)",
|
|
1859
|
-
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)",
|
|
1862
|
-
scale:
|
|
1863
|
-
x:
|
|
1864
|
-
y:
|
|
1865
|
-
ref:
|
|
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)",
|
|
1868
|
-
fingers:
|
|
1869
|
-
x:
|
|
1870
|
-
y:
|
|
1871
|
-
ref:
|
|
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",
|
|
1874
|
-
x:
|
|
1875
|
-
y:
|
|
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)",
|
|
1878
|
-
command:
|
|
1879
|
-
args:
|
|
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",
|
|
1882
|
-
name:
|
|
1883
|
-
value:
|
|
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",
|
|
1886
|
-
url:
|
|
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",
|
|
1889
|
-
index:
|
|
1890
|
-
title:
|
|
1891
|
-
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)",
|
|
1894
|
-
ref:
|
|
1895
|
-
relativePosition:
|
|
1896
|
-
x:
|
|
1897
|
-
y:
|
|
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:
|
|
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)",
|
|
1902
|
-
ref:
|
|
1903
|
-
relativePosition:
|
|
1904
|
-
x:
|
|
1905
|
-
y:
|
|
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:
|
|
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)",
|
|
1910
|
-
pattern:
|
|
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)",
|
|
1913
|
-
ref:
|
|
1914
|
-
files:
|
|
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)",
|
|
1917
|
-
ref:
|
|
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 =
|
|
2332
|
-
value:
|
|
2333
|
-
reasoning:
|
|
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
|
|
2834
|
-
var VerificationResultSchema =
|
|
2835
|
-
success:
|
|
2836
|
-
reasoning:
|
|
2837
|
-
isAppError:
|
|
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
|
|
3030
|
-
var AssertionResultSchema =
|
|
3031
|
-
passed:
|
|
3032
|
-
reasoning:
|
|
3033
|
-
evidence:
|
|
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 =
|
|
4723
|
-
|
|
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 ?
|
|
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:
|
|
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
|
-
|
|
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
|
|
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(
|
|
6938
|
-
const authPath =
|
|
7413
|
+
async function readAuth(path7) {
|
|
7414
|
+
const authPath = path7 ?? getAuthPath();
|
|
6939
7415
|
try {
|
|
6940
|
-
const data = await
|
|
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,
|
|
6947
|
-
const authPath =
|
|
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
|
|
6951
|
-
await
|
|
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,
|
|
6954
|
-
const authPath =
|
|
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
|
|
7440
|
+
await writeFile5(authPath, JSON.stringify(store, null, 2), { mode: 384 });
|
|
6965
7441
|
}
|
|
6966
|
-
async function getCredential(provider,
|
|
6967
|
-
const store = await readAuth(
|
|
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
|
|
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 =
|
|
7334
|
-
extractDom:
|
|
7335
|
-
hasScreenshot:
|
|
7336
|
-
duration:
|
|
7337
|
-
elementCount:
|
|
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 =
|
|
7340
|
-
actionType:
|
|
7341
|
-
selector:
|
|
7342
|
-
coordinates:
|
|
7343
|
-
elementProperties:
|
|
7344
|
-
duration:
|
|
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 =
|
|
7347
|
-
operation:
|
|
7348
|
-
stepHash:
|
|
7349
|
-
screenHash:
|
|
7350
|
-
hit:
|
|
7351
|
-
age:
|
|
7352
|
-
entriesDeleted:
|
|
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 =
|
|
7355
|
-
model:
|
|
7356
|
-
promptTokens:
|
|
7357
|
-
completionTokens:
|
|
7358
|
-
latencyMs:
|
|
7359
|
-
confidence:
|
|
7360
|
-
actionType:
|
|
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 =
|
|
7363
|
-
strategy:
|
|
7364
|
-
attempt:
|
|
7365
|
-
maxAttempts:
|
|
7366
|
-
stateDiffDetected:
|
|
7367
|
-
success:
|
|
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 =
|
|
7370
|
-
hookName:
|
|
7371
|
-
phase:
|
|
7372
|
-
duration:
|
|
7373
|
-
success:
|
|
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 =
|
|
7376
|
-
stepIndex:
|
|
7377
|
-
totalSteps:
|
|
7378
|
-
testName:
|
|
7379
|
-
variablesCaptured:
|
|
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
|
|
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:
|
|
7910
|
+
id: randomUUID3(),
|
|
7435
7911
|
stepId: this.currentStepId,
|
|
7436
7912
|
runId: this.runId,
|
|
7437
7913
|
level,
|
|
7438
7914
|
source,
|
|
7439
|
-
message:
|
|
7440
|
-
data:
|
|
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
|
|
7756
|
-
import { readFile as
|
|
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
|
|
8271
|
+
import { z as z20 } from "zod";
|
|
7796
8272
|
import { join as join6 } from "path";
|
|
7797
|
-
import { access as access2, readFile as
|
|
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 =
|
|
7805
|
-
|
|
7806
|
-
action:
|
|
7807
|
-
title:
|
|
7808
|
-
content:
|
|
7809
|
-
scope:
|
|
7810
|
-
reasoning:
|
|
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
|
-
|
|
7813
|
-
action:
|
|
7814
|
-
observationId:
|
|
7815
|
-
reasoning:
|
|
8288
|
+
z20.object({
|
|
8289
|
+
action: z20.literal("update"),
|
|
8290
|
+
observationId: z20.string(),
|
|
8291
|
+
reasoning: z20.string()
|
|
7816
8292
|
}),
|
|
7817
|
-
|
|
7818
|
-
action:
|
|
7819
|
-
observationId:
|
|
7820
|
-
reasoning:
|
|
8293
|
+
z20.object({
|
|
8294
|
+
action: z20.literal("deprecate"),
|
|
8295
|
+
observationId: z20.string(),
|
|
8296
|
+
reasoning: z20.string()
|
|
7821
8297
|
}),
|
|
7822
|
-
|
|
7823
|
-
action:
|
|
7824
|
-
reasoning:
|
|
8298
|
+
z20.object({
|
|
8299
|
+
action: z20.literal("noop"),
|
|
8300
|
+
reasoning: z20.string()
|
|
7825
8301
|
})
|
|
7826
8302
|
]);
|
|
7827
|
-
var CuratorResponseSchema =
|
|
7828
|
-
decisions:
|
|
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
|
|
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
|
|
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
|
|
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 &&
|
|
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
|
-
...
|
|
8919
|
+
...suiteSandboxOptions,
|
|
8443
8920
|
secretStore: config.secretStore,
|
|
8444
8921
|
secretRedactor: config.secretRedactor,
|
|
8445
|
-
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 =
|
|
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 &&
|
|
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 =
|
|
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
|
-
...
|
|
9043
|
+
...suiteSandboxOptions,
|
|
8567
9044
|
secretStore: config.secretStore,
|
|
8568
9045
|
secretRedactor: config.secretRedactor,
|
|
8569
|
-
envVars: { ...
|
|
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
|
|
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:
|
|
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 &&
|
|
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 =
|
|
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
|
-
...
|
|
9151
|
+
...suiteSandboxOptions,
|
|
8675
9152
|
secretStore: config.secretStore,
|
|
8676
9153
|
secretRedactor: config.secretRedactor,
|
|
8677
|
-
envVars: { ...
|
|
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 &&
|
|
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 =
|
|
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
|
-
...
|
|
9324
|
+
...suiteSandboxOptions,
|
|
8829
9325
|
secretStore: config.secretStore,
|
|
8830
9326
|
secretRedactor: config.secretRedactor,
|
|
8831
|
-
envVars: { ...
|
|
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
|
|
9386
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
8891
9387
|
import { existsSync as existsSync6 } from "fs";
|
|
8892
|
-
import
|
|
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
|
|
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
|
|
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
|
|
9427
|
+
import path4 from "path";
|
|
8932
9428
|
function isPathInsideDir(childPath, parentDir) {
|
|
8933
9429
|
if (!childPath) return false;
|
|
8934
|
-
const resolved =
|
|
8935
|
-
const relative2 =
|
|
8936
|
-
return !!relative2 && !relative2.startsWith("..") && !
|
|
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
|
|
9437
|
+
import path5 from "path";
|
|
8942
9438
|
import { glob } from "glob";
|
|
8943
9439
|
function toForwardSlash(value) {
|
|
8944
|
-
return value.split(
|
|
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 =
|
|
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(
|
|
9463
|
+
workspaceRelativePath: trimLeadingCurrentDir(path5.relative(configDir, absolutePath))
|
|
8968
9464
|
};
|
|
8969
9465
|
}
|
|
8970
9466
|
function assertInsideWorkspace(configDir, absolutePath, filePath) {
|
|
8971
|
-
const relativePath =
|
|
8972
|
-
if (!relativePath || relativePath.startsWith("..") ||
|
|
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 =
|
|
9030
|
-
const configDir =
|
|
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) =>
|
|
9564
|
+
return matches.map((match) => path5.resolve(match)).map((absolutePath) => ({
|
|
9069
9565
|
kind: input.kind,
|
|
9070
9566
|
absolutePath,
|
|
9071
|
-
workspaceRelativePath: trimLeadingCurrentDir(
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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) =>
|
|
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 ?
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
9572
|
-
id:
|
|
9573
|
-
name:
|
|
9574
|
-
runtime:
|
|
9575
|
-
file:
|
|
9576
|
-
deps:
|
|
9577
|
-
packageFile:
|
|
9578
|
-
timeout:
|
|
9579
|
-
network:
|
|
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 =
|
|
9582
|
-
hooks:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
9809
|
-
await
|
|
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
|
|
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
|
|
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(
|
|
9905
|
-
const identityPath =
|
|
10400
|
+
async function readAnalyticsIdentityStore(path7) {
|
|
10401
|
+
const identityPath = path7 ?? getAnalyticsIdentityPath();
|
|
9906
10402
|
try {
|
|
9907
|
-
const data = await
|
|
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(
|
|
9915
|
-
const parsed = await readAnalyticsIdentityStore(
|
|
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,
|
|
9919
|
-
const identityPath =
|
|
9920
|
-
await
|
|
9921
|
-
await
|
|
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
|
|
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 =
|
|
10211
|
-
var NonNegativeIntegerSchema =
|
|
10212
|
-
var NonNegativeNumberSchema =
|
|
10213
|
-
var AnalyticsBasePropertiesSchema =
|
|
10214
|
-
agent_qa_version:
|
|
10215
|
-
surface:
|
|
10216
|
-
runtime_context:
|
|
10217
|
-
agent_product:
|
|
10218
|
-
transport:
|
|
10219
|
-
privacy_enabled:
|
|
10220
|
-
posthog_key_present:
|
|
10221
|
-
$process_person_profile:
|
|
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:
|
|
10225
|
-
runner:
|
|
10226
|
-
platform:
|
|
10227
|
-
status:
|
|
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:
|
|
10230
|
-
parent_run_id:
|
|
10231
|
-
test_id:
|
|
10232
|
-
suite_id:
|
|
10233
|
-
model_name:
|
|
10234
|
-
provider:
|
|
10235
|
-
provider_mode:
|
|
10236
|
-
planner_model:
|
|
10237
|
-
verifier_model:
|
|
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:
|
|
10255
|
-
cancelled:
|
|
10256
|
-
timed_out:
|
|
10257
|
-
failure_category:
|
|
10258
|
-
browser_name:
|
|
10259
|
-
mobile_transport:
|
|
10260
|
-
mobile_provider:
|
|
10261
|
-
app_state:
|
|
10262
|
-
execution_destination:
|
|
10263
|
-
memory_enabled:
|
|
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:
|
|
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:
|
|
10283
|
-
entity_type:
|
|
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:
|
|
10287
|
-
outcome:
|
|
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:
|
|
10291
|
-
mcp_transport:
|
|
10292
|
-
mcp_host_kind:
|
|
10293
|
-
mcp_port_kind:
|
|
10294
|
-
mcp_path_kind:
|
|
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:
|
|
10298
|
-
mcp_tool_category:
|
|
10299
|
-
mcp_tool_status:
|
|
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:
|
|
10302
|
-
mcp_transport:
|
|
10303
|
-
run_id:
|
|
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
|
|
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 (!
|
|
10980
|
+
if (!isRecord2(source)) return void 0;
|
|
10485
10981
|
const value = source[key];
|
|
10486
|
-
return
|
|
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
|
|
11026
|
+
return isRecord2(context?.artifact?.source) ? context?.artifact?.source : void 0;
|
|
10531
11027
|
}
|
|
10532
11028
|
function readArtifactConfig(context) {
|
|
10533
|
-
return
|
|
11029
|
+
return isRecord2(context?.artifact?.config) ? context?.artifact?.config : void 0;
|
|
10534
11030
|
}
|
|
10535
11031
|
function readArtifactRuntime(context) {
|
|
10536
|
-
const artifactRuntime =
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|