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