@vostride/agent-qa-core 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -67,20 +67,20 @@ var init_schema = __esm({
67
67
  // src/memory/observation-io.ts
68
68
  import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
69
69
  import { mkdir as mkdir5, writeFile as writeFile5, readdir as readdir2 } from "fs/promises";
70
- import { join as join4, resolve as resolve3, sep } from "path";
70
+ import { join as join5, resolve as resolve4, sep } from "path";
71
71
  function toObservationFrontmatter(data) {
72
72
  const { content, ...frontmatter } = data;
73
73
  return frontmatter;
74
74
  }
75
75
  async function ensureMemoryDirs(root) {
76
76
  await Promise.all(
77
- MEMORY_TIERS.map((tier) => mkdir5(join4(root, tier), { recursive: true }))
77
+ MEMORY_TIERS.map((tier) => mkdir5(join5(root, tier), { recursive: true }))
78
78
  );
79
79
  }
80
80
  async function writeObservation(root, tier, scope, data) {
81
- const dir = join4(root, tier, scope);
82
- const resolved = resolve3(dir);
83
- const boundary = resolve3(root);
81
+ const dir = join5(root, tier, scope);
82
+ const resolved = resolve4(dir);
83
+ const boundary = resolve4(root);
84
84
  if (!resolved.startsWith(boundary + sep)) {
85
85
  throw new Error(`Scope "${scope}" escapes memory root`);
86
86
  }
@@ -92,7 +92,7 @@ async function writeObservation(root, tier, scope, data) {
92
92
  ${stringifyYaml({ ...frontmatter }, { lineWidth: 0 })}---
93
93
  ${validated.content}
94
94
  `;
95
- const filePath = join4(dir, `${data.id}.md`);
95
+ const filePath = join5(dir, `${data.id}.md`);
96
96
  await writeFile5(filePath, content, "utf-8");
97
97
  return filePath;
98
98
  }
@@ -198,11 +198,11 @@ var init_security_scanner = __esm({
198
198
 
199
199
  // src/sqlite.ts
200
200
  import { execFileSync } from "child_process";
201
- import { existsSync as existsSync6, mkdirSync, rmSync, writeFileSync } from "fs";
201
+ import { existsSync as existsSync7, mkdirSync, rmSync, writeFileSync } from "fs";
202
202
  import { createHash as createHash3 } from "crypto";
203
203
  import { createRequire as createRequire3 } from "module";
204
204
  import { tmpdir as tmpdir2 } from "os";
205
- import { dirname as dirname10, join as join6 } from "path";
205
+ import { dirname as dirname11, join as join7 } from "path";
206
206
  function getBetterSqlite3ErrorMessage(error) {
207
207
  return error instanceof Error ? error.message : String(error);
208
208
  }
@@ -222,14 +222,14 @@ function isBetterSqlite3NodeGypSymlinkConflict(error) {
222
222
  return message.includes("node_gyp_bins/python3") && message.includes("EEXIST");
223
223
  }
224
224
  function resolveCurrentRuntimeNpmCliPath() {
225
- const nodeInstallRoot = dirname10(dirname10(process.execPath));
226
- const npmCliPath = join6(nodeInstallRoot, "lib", "node_modules", "npm", "bin", "npm-cli.js");
227
- return existsSync6(npmCliPath) ? npmCliPath : null;
225
+ const nodeInstallRoot = dirname11(dirname11(process.execPath));
226
+ const npmCliPath = join7(nodeInstallRoot, "lib", "node_modules", "npm", "bin", "npm-cli.js");
227
+ return existsSync7(npmCliPath) ? npmCliPath : null;
228
228
  }
229
229
  function resolveCurrentRuntimeNodeDir() {
230
- const nodeInstallRoot = dirname10(dirname10(process.execPath));
231
- const nodeHeaderPath = join6(nodeInstallRoot, "include", "node", "node.h");
232
- return existsSync6(nodeHeaderPath) ? nodeInstallRoot : null;
230
+ const nodeInstallRoot = dirname11(dirname11(process.execPath));
231
+ const nodeHeaderPath = join7(nodeInstallRoot, "include", "node", "node.h");
232
+ return existsSync7(nodeHeaderPath) ? nodeInstallRoot : null;
233
233
  }
234
234
  function resolveBetterSqliteRebuildCommand() {
235
235
  const npmCliPath = resolveCurrentRuntimeNpmCliPath();
@@ -250,26 +250,26 @@ function sleepSync(milliseconds) {
250
250
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
251
251
  }
252
252
  function waitForBetterSqlite3BuildOutput(installRoot, timeoutMs = 3e4) {
253
- const bindingPath = join6(installRoot, "build", "Release", "better_sqlite3.node");
253
+ const bindingPath = join7(installRoot, "build", "Release", "better_sqlite3.node");
254
254
  const deadline = Date.now() + timeoutMs;
255
255
  while (Date.now() < deadline) {
256
- if (existsSync6(bindingPath)) {
256
+ if (existsSync7(bindingPath)) {
257
257
  return true;
258
258
  }
259
259
  sleepSync(200);
260
260
  }
261
- return existsSync6(bindingPath);
261
+ return existsSync7(bindingPath);
262
262
  }
263
263
  function acquireBetterSqlite3RebuildLock(installRoot) {
264
- const lockRoot = join6(tmpdir2(), "agent-qa-better-sqlite3-rebuild-locks");
264
+ const lockRoot = join7(tmpdir2(), "agent-qa-better-sqlite3-rebuild-locks");
265
265
  const lockKey = createHash3("sha256").update(`${installRoot}\0${process.version}`).digest("hex");
266
- const lockDir = join6(lockRoot, lockKey);
266
+ const lockDir = join7(lockRoot, lockKey);
267
267
  const deadline = Date.now() + 12e4;
268
268
  mkdirSync(lockRoot, { recursive: true });
269
269
  while (true) {
270
270
  try {
271
271
  mkdirSync(lockDir);
272
- writeFileSync(join6(lockDir, "owner"), `${process.pid}
272
+ writeFileSync(join7(lockDir, "owner"), `${process.pid}
273
273
  ${(/* @__PURE__ */ new Date()).toISOString()}
274
274
  ${installRoot}
275
275
  `);
@@ -298,13 +298,13 @@ function rebuildBetterSqlite3ForCurrentRuntime(originalError) {
298
298
  }
299
299
  rebuildAttempted = true;
300
300
  const packageJsonPath = require2.resolve("better-sqlite3/package.json");
301
- const installRoot = dirname10(packageJsonPath);
301
+ const installRoot = dirname11(packageJsonPath);
302
302
  const rebuildCommand = resolveBetterSqliteRebuildCommand();
303
- const nodeGypDevDir = join6(tmpdir2(), "agent-qa-node-gyp", process.version.replace(/^v/, ""));
304
- const npmCacheDir = join6(tmpdir2(), "agent-qa-npm-cache");
303
+ const nodeGypDevDir = join7(tmpdir2(), "agent-qa-node-gyp", process.version.replace(/^v/, ""));
304
+ const npmCacheDir = join7(tmpdir2(), "agent-qa-npm-cache");
305
305
  const nodeDir = resolveCurrentRuntimeNodeDir();
306
- const nodeGypBinsPath = join6(installRoot, "build", "node_gyp_bins");
307
- const buildRoot = join6(installRoot, "build");
306
+ const nodeGypBinsPath = join7(installRoot, "build", "node_gyp_bins");
307
+ const buildRoot = join7(installRoot, "build");
308
308
  const releaseLock = acquireBetterSqlite3RebuildLock(installRoot);
309
309
  try {
310
310
  clearBetterSqlite3Cache();
@@ -387,7 +387,7 @@ var init_sqlite = __esm({
387
387
 
388
388
  // src/memory/memory-index.ts
389
389
  import { readFile as readFile12 } from "fs/promises";
390
- import { join as join7 } from "path";
390
+ import { join as join8 } from "path";
391
391
  function validatePathComponent(value) {
392
392
  return !/\.\./.test(value) && !/[/\\]/.test(value) && !/\0/.test(value);
393
393
  }
@@ -409,13 +409,13 @@ async function buildMemoryIndex(params) {
409
409
  const insert = db.prepare("INSERT INTO observations(title, content, id, trust) VALUES (?, ?, ?, ?)");
410
410
  const dirs = [];
411
411
  if (validatePathComponent(params.product)) {
412
- dirs.push({ path: join7(params.memoryRoot, "products", params.product), isSuite: false });
412
+ dirs.push({ path: join8(params.memoryRoot, "products", params.product), isSuite: false });
413
413
  }
414
414
  if (params.suiteId && validatePathComponent(params.suiteId)) {
415
- dirs.push({ path: join7(params.memoryRoot, "suites", params.suiteId), isSuite: true });
415
+ dirs.push({ path: join8(params.memoryRoot, "suites", params.suiteId), isSuite: true });
416
416
  }
417
417
  if (validatePathComponent(params.testId)) {
418
- dirs.push({ path: join7(params.memoryRoot, "tests", params.testId), isSuite: false });
418
+ dirs.push({ path: join8(params.memoryRoot, "tests", params.testId), isSuite: false });
419
419
  }
420
420
  if (dirs.length === 0) {
421
421
  console.warn("[memory-index] All path components failed validation", {
@@ -434,7 +434,7 @@ async function buildMemoryIndex(params) {
434
434
  for (const { path: dirPath, isSuite } of dirs) {
435
435
  const filenames = await listObservations(dirPath);
436
436
  for (const filename of filenames) {
437
- const filePath = join7(dirPath, filename);
437
+ const filePath = join8(dirPath, filename);
438
438
  let raw;
439
439
  try {
440
440
  raw = await readFile12(filePath, "utf-8");
@@ -485,7 +485,7 @@ var init_xml_escape = __esm({
485
485
 
486
486
  // src/memory/lock-manager.ts
487
487
  import { writeFile as writeFile7, readFile as readFile13, unlink as unlink3, mkdir as mkdir7 } from "fs/promises";
488
- import { dirname as dirname11 } from "path";
488
+ import { dirname as dirname12 } from "path";
489
489
  var LockManager;
490
490
  var init_lock_manager = __esm({
491
491
  "src/memory/lock-manager.ts"() {
@@ -498,7 +498,7 @@ var init_lock_manager = __esm({
498
498
  this.timeout = timeout;
499
499
  }
500
500
  async acquire() {
501
- await mkdir7(dirname11(this.lockPath), { recursive: true });
501
+ await mkdir7(dirname12(this.lockPath), { recursive: true });
502
502
  const deadline = Date.now() + this.timeout;
503
503
  while (Date.now() < deadline) {
504
504
  try {
@@ -630,7 +630,7 @@ var local_provider_exports = {};
630
630
  __export(local_provider_exports, {
631
631
  LocalMemoryProvider: () => LocalMemoryProvider
632
632
  });
633
- import { join as join8, resolve as resolve6, sep as sep2 } from "path";
633
+ import { join as join9, resolve as resolve7, sep as sep2 } from "path";
634
634
  import { readdirSync, readFileSync as readFileSync3 } from "fs";
635
635
  import { unlink as unlink4 } from "fs/promises";
636
636
  var LocalMemoryProvider;
@@ -657,7 +657,7 @@ var init_local_provider = __esm({
657
657
  this.minTrust = opts?.minTrust ?? 0.3;
658
658
  this.maxInjections = opts?.maxInjections ?? 3;
659
659
  this.lockManager = new LockManager(
660
- join8(this.memoryRoot, ".curator.lock"),
660
+ join9(this.memoryRoot, ".curator.lock"),
661
661
  opts?.curatorLockTimeout ?? 12e4
662
662
  );
663
663
  }
@@ -727,9 +727,9 @@ ${lines.join("\n")}
727
727
  return writeObservation(this.memoryRoot, tier, scope, data);
728
728
  }
729
729
  async deleteObservation(tier, scope, id) {
730
- const filePath = join8(this.memoryRoot, tier, scope, `${id}.md`);
731
- const resolved = resolve6(filePath);
732
- if (!resolved.startsWith(resolve6(this.memoryRoot) + sep2)) {
730
+ const filePath = join9(this.memoryRoot, tier, scope, `${id}.md`);
731
+ const resolved = resolve7(filePath);
732
+ if (!resolved.startsWith(resolve7(this.memoryRoot) + sep2)) {
733
733
  throw new Error("Path escapes memory root");
734
734
  }
735
735
  try {
@@ -746,7 +746,7 @@ ${lines.join("\n")}
746
746
  const results = [];
747
747
  const tiers = ["products", "suites", "tests"];
748
748
  for (const tier of tiers) {
749
- const tierDir = join8(this.memoryRoot, tier);
749
+ const tierDir = join9(this.memoryRoot, tier);
750
750
  let scopes;
751
751
  try {
752
752
  scopes = readdirSync(tierDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -754,7 +754,7 @@ ${lines.join("\n")}
754
754
  continue;
755
755
  }
756
756
  for (const scope of scopes) {
757
- const scopeDir = join8(tierDir, scope);
757
+ const scopeDir = join9(tierDir, scope);
758
758
  let files;
759
759
  try {
760
760
  files = readdirSync(scopeDir).filter((f) => f.startsWith("obs_") && f.endsWith(".md"));
@@ -764,7 +764,7 @@ ${lines.join("\n")}
764
764
  for (const file of files) {
765
765
  let raw;
766
766
  try {
767
- raw = readFileSync3(join8(scopeDir, file), "utf-8");
767
+ raw = readFileSync3(join9(scopeDir, file), "utf-8");
768
768
  } catch {
769
769
  continue;
770
770
  }
@@ -799,7 +799,7 @@ ${lines.join("\n")}
799
799
  const tiers = ["products", "suites", "tests"];
800
800
  const toInsert = [];
801
801
  for (const tier of tiers) {
802
- const tierDir = join8(this.memoryRoot, tier);
802
+ const tierDir = join9(this.memoryRoot, tier);
803
803
  let scopes;
804
804
  try {
805
805
  scopes = readdirSync(tierDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -807,7 +807,7 @@ ${lines.join("\n")}
807
807
  continue;
808
808
  }
809
809
  for (const scope of scopes) {
810
- const scopeDir = join8(tierDir, scope);
810
+ const scopeDir = join9(tierDir, scope);
811
811
  let files;
812
812
  try {
813
813
  files = readdirSync(scopeDir).filter((f) => f.startsWith("obs_") && f.endsWith(".md"));
@@ -817,7 +817,7 @@ ${lines.join("\n")}
817
817
  for (const file of files) {
818
818
  let raw;
819
819
  try {
820
- raw = readFileSync3(join8(scopeDir, file), "utf-8");
820
+ raw = readFileSync3(join9(scopeDir, file), "utf-8");
821
821
  } catch {
822
822
  continue;
823
823
  }
@@ -4674,9 +4674,9 @@ function getHookCommand(runtime, entryFile) {
4674
4674
  }
4675
4675
  }
4676
4676
  async function checkDockerAvailable(dockerBin = DEFAULT_DOCKER_BIN) {
4677
- return new Promise((resolve7) => {
4677
+ return new Promise((resolve8) => {
4678
4678
  execFile(dockerBin, ["info", "--format", "{{.ID}}"], { timeout: 5e3 }, (err) => {
4679
- resolve7(!err);
4679
+ resolve8(!err);
4680
4680
  });
4681
4681
  });
4682
4682
  }
@@ -4789,22 +4789,22 @@ function filterSecretVariables(variables, secretStore) {
4789
4789
  );
4790
4790
  }
4791
4791
  function imageExists(dockerBin, image) {
4792
- return new Promise((resolve7) => {
4792
+ return new Promise((resolve8) => {
4793
4793
  execFile(dockerBin, ["image", "inspect", image], { timeout: 1e4 }, (err) => {
4794
- resolve7(!err);
4794
+ resolve8(!err);
4795
4795
  });
4796
4796
  });
4797
4797
  }
4798
4798
  function pullImage(dockerBin, image) {
4799
- return new Promise((resolve7, reject) => {
4799
+ return new Promise((resolve8, reject) => {
4800
4800
  execFile(dockerBin, ["pull", image], { timeout: 12e4 }, (err) => {
4801
4801
  if (err) reject(new Error(`Failed to pull image ${image}: ${err.message}`));
4802
- else resolve7();
4802
+ else resolve8();
4803
4803
  });
4804
4804
  });
4805
4805
  }
4806
4806
  function execDocker(dockerBin, args, timeout) {
4807
- return new Promise((resolve7, reject) => {
4807
+ return new Promise((resolve8, reject) => {
4808
4808
  let stdout = "";
4809
4809
  let stderr = "";
4810
4810
  let resolved = false;
@@ -4814,11 +4814,11 @@ function execDocker(dockerBin, args, timeout) {
4814
4814
  stdout = out ?? "";
4815
4815
  stderr = errOut ?? "";
4816
4816
  if (err && "killed" in err && err.killed) {
4817
- resolve7({ stdout, stderr: `Hook timed out after ${timeout}ms`, exitCode: 124 });
4817
+ resolve8({ stdout, stderr: `Hook timed out after ${timeout}ms`, exitCode: 124 });
4818
4818
  return;
4819
4819
  }
4820
4820
  const exitCode = err?.code ?? 0;
4821
- resolve7({ stdout, stderr, exitCode: typeof exitCode === "number" ? exitCode : 1 });
4821
+ resolve8({ stdout, stderr, exitCode: typeof exitCode === "number" ? exitCode : 1 });
4822
4822
  });
4823
4823
  });
4824
4824
  }
@@ -6894,14 +6894,41 @@ function resolveMobileRunConfig(input) {
6894
6894
  };
6895
6895
  }
6896
6896
 
6897
+ // src/mobile/appium-executable.ts
6898
+ import { existsSync as existsSync2 } from "fs";
6899
+ import { dirname as dirname6, join as join3, parse, resolve as resolve2 } from "path";
6900
+ function localAppiumBinaryNames(platform = process.platform) {
6901
+ return platform === "win32" ? ["appium.cmd", "appium.exe", "appium"] : ["appium"];
6902
+ }
6903
+ function resolveAppiumExecutable(opts = {}) {
6904
+ const exists = opts.exists ?? existsSync2;
6905
+ const names = localAppiumBinaryNames(opts.platform ?? process.platform);
6906
+ let current = resolve2(opts.cwd ?? process.cwd());
6907
+ const root = parse(current).root;
6908
+ while (true) {
6909
+ for (const name of names) {
6910
+ const candidate = join3(current, "node_modules", ".bin", name);
6911
+ if (exists(candidate)) {
6912
+ return { command: candidate, source: "local" };
6913
+ }
6914
+ }
6915
+ if (current === root) break;
6916
+ current = dirname6(current);
6917
+ }
6918
+ return { command: "appium", source: "path" };
6919
+ }
6920
+ function formatAppiumInstallGuidance() {
6921
+ 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`.";
6922
+ }
6923
+
6897
6924
  // src/auth/store.ts
6898
6925
  import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir4, unlink as unlink2 } from "fs/promises";
6899
- import { dirname as dirname6, join as join3 } from "path";
6926
+ import { dirname as dirname7, join as join4 } from "path";
6900
6927
  import { homedir } from "os";
6901
6928
  function getAuthPath() {
6902
6929
  const xdg = process.env.XDG_DATA_HOME;
6903
- if (xdg) return join3(xdg, "agent-qa", "auth.json");
6904
- return join3(homedir(), ".agent-qa", "auth.json");
6930
+ if (xdg) return join4(xdg, "agent-qa", "auth.json");
6931
+ return join4(homedir(), ".agent-qa", "auth.json");
6905
6932
  }
6906
6933
  async function readAuth(path5) {
6907
6934
  const authPath = path5 ?? getAuthPath();
@@ -6916,7 +6943,7 @@ async function writeAuth(provider, credential, path5) {
6916
6943
  const authPath = path5 ?? getAuthPath();
6917
6944
  const store = await readAuth(authPath);
6918
6945
  store[provider] = credential;
6919
- await mkdir4(dirname6(authPath), { recursive: true });
6946
+ await mkdir4(dirname7(authPath), { recursive: true });
6920
6947
  await writeFile4(authPath, JSON.stringify(store, null, 2), { mode: 384 });
6921
6948
  }
6922
6949
  async function removeAuth(provider, path5) {
@@ -7094,16 +7121,16 @@ async function resolveLLMAuth(configName, llmConfig, authPath) {
7094
7121
 
7095
7122
  // src/auth/plugin-loader.ts
7096
7123
  import { createRequire } from "module";
7097
- import { existsSync as existsSync2, readFileSync } from "fs";
7098
- import { dirname as dirname7, isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
7124
+ import { existsSync as existsSync3, readFileSync } from "fs";
7125
+ import { dirname as dirname8, isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
7099
7126
  import { pathToFileURL } from "url";
7100
7127
  var loadedDeclarations = /* @__PURE__ */ new Set();
7101
7128
  function findPackageJson(packageName, baseDir) {
7102
- let current = resolve2(baseDir);
7129
+ let current = resolve3(baseDir);
7103
7130
  while (true) {
7104
- const candidate = resolve2(current, "node_modules", ...packageName.split("/"), "package.json");
7105
- if (existsSync2(candidate)) return candidate;
7106
- const parent = dirname7(current);
7131
+ const candidate = resolve3(current, "node_modules", ...packageName.split("/"), "package.json");
7132
+ if (existsSync3(candidate)) return candidate;
7133
+ const parent = dirname8(current);
7107
7134
  if (parent === current) return null;
7108
7135
  current = parent;
7109
7136
  }
@@ -7131,7 +7158,7 @@ function resolvePackageImportFromBase(packageName, baseDir) {
7131
7158
  const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
7132
7159
  const target = exportTargetFromPackageJson(pkg);
7133
7160
  if (!target || !target.startsWith(".")) return null;
7134
- return pathToFileURL(resolve2(dirname7(packageJsonPath), target)).href;
7161
+ return pathToFileURL(resolve3(dirname8(packageJsonPath), target)).href;
7135
7162
  }
7136
7163
  function packageDeclarationValue(declaration) {
7137
7164
  return "package" in declaration && typeof declaration.package === "string" ? declaration.package.trim() : "";
@@ -7142,24 +7169,24 @@ function pathDeclarationValue(declaration) {
7142
7169
  function declarationKey(declaration, baseDir) {
7143
7170
  const packageName = packageDeclarationValue(declaration);
7144
7171
  if (packageName) return `package:${packageName}`;
7145
- return `path:${resolve2(baseDir, pathDeclarationValue(declaration))}`;
7172
+ return `path:${resolve3(baseDir, pathDeclarationValue(declaration))}`;
7146
7173
  }
7147
7174
  function resolveModuleSpecifier(declaration, baseDir) {
7148
7175
  const packageName = packageDeclarationValue(declaration);
7149
7176
  if (packageName) {
7150
7177
  const packageImport = resolvePackageImportFromBase(packageName, baseDir);
7151
7178
  if (packageImport) return packageImport;
7152
- const parentUrl = pathToFileURL(resolve2(baseDir, "agent-qa.config.yaml")).href;
7179
+ const parentUrl = pathToFileURL(resolve3(baseDir, "agent-qa.config.yaml")).href;
7153
7180
  try {
7154
7181
  const resolveImport = import.meta.resolve;
7155
7182
  return resolveImport(packageName, parentUrl);
7156
7183
  } catch {
7157
- const require3 = createRequire(resolve2(baseDir, "agent-qa.config.yaml"));
7184
+ const require3 = createRequire(resolve3(baseDir, "agent-qa.config.yaml"));
7158
7185
  return pathToFileURL(require3.resolve(packageName)).href;
7159
7186
  }
7160
7187
  }
7161
7188
  const pluginPath = pathDeclarationValue(declaration);
7162
- const absolutePath = isAbsolute2(pluginPath) ? pluginPath : resolve2(baseDir, pluginPath);
7189
+ const absolutePath = isAbsolute2(pluginPath) ? pluginPath : resolve3(baseDir, pluginPath);
7163
7190
  return pathToFileURL(absolutePath).href;
7164
7191
  }
7165
7192
  async function resolvePluginBundle(module, source) {
@@ -7548,7 +7575,7 @@ function mapMobileCapabilities(match, platform, credentials, opts) {
7548
7575
  }
7549
7576
 
7550
7577
  // src/farm/browserstack.ts
7551
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
7578
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
7552
7579
  import { basename as basename2, resolve as resolvePath3 } from "path";
7553
7580
  function isAbsoluteAppValue(value) {
7554
7581
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
@@ -7570,7 +7597,7 @@ async function resolveBrowserStackApp(config) {
7570
7597
  const appBaseDir = config.appBaseDir ?? process.cwd();
7571
7598
  const resolvedPath = resolvePath3(appBaseDir, config.app);
7572
7599
  const mustExist = isExplicitRelativePath(config.app);
7573
- if (!existsSync3(resolvedPath)) {
7600
+ if (!existsSync4(resolvedPath)) {
7574
7601
  if (mustExist) {
7575
7602
  throw new MobileSetupError({
7576
7603
  category: "app-install",
@@ -7762,7 +7789,7 @@ async function runHooks(hooks, options = {}) {
7762
7789
  init_observation_io();
7763
7790
  import { generateText as generateText5, Output as Output4 } from "ai";
7764
7791
  import { z as z19 } from "zod";
7765
- import { join as join5 } from "path";
7792
+ import { join as join6 } from "path";
7766
7793
  import { access as access2, readFile as readFile7, readdir as readdir3 } from "fs/promises";
7767
7794
 
7768
7795
  // src/memory/observation-id.ts
@@ -7910,7 +7937,7 @@ function collectKnownObservationIds(injectedObservationIds, dedupMatches) {
7910
7937
  async function findObservationFile(memoryRoot, id) {
7911
7938
  const tiers = ["products", "suites", "tests"];
7912
7939
  for (const tier of tiers) {
7913
- const tierDir = join5(memoryRoot, tier);
7940
+ const tierDir = join6(memoryRoot, tier);
7914
7941
  let scopes;
7915
7942
  try {
7916
7943
  scopes = await readdir3(tierDir);
@@ -7918,7 +7945,7 @@ async function findObservationFile(memoryRoot, id) {
7918
7945
  continue;
7919
7946
  }
7920
7947
  for (const scope of scopes) {
7921
- const filePath = join5(tierDir, scope, `${id}.md`);
7948
+ const filePath = join6(tierDir, scope, `${id}.md`);
7922
7949
  try {
7923
7950
  await access2(filePath);
7924
7951
  return { tier, scope, filePath };
@@ -8147,11 +8174,11 @@ ${userMessage}`;
8147
8174
  }
8148
8175
  if (ctx.suiteId && ctx.suiteContext) {
8149
8176
  try {
8150
- const suiteDir = join5(ctx.memoryRoot, "suites", ctx.suiteId);
8177
+ const suiteDir = join6(ctx.memoryRoot, "suites", ctx.suiteId);
8151
8178
  const files = await listObservations(suiteDir);
8152
8179
  for (const file of files) {
8153
8180
  try {
8154
- const filePath = join5(suiteDir, file);
8181
+ const filePath = join6(suiteDir, file);
8155
8182
  const raw = await readFile7(filePath, "utf-8");
8156
8183
  const { data } = parseObservation(raw, file);
8157
8184
  if (!data || !("suite_snapshot" in data)) continue;
@@ -8615,6 +8642,7 @@ async function runSuite(suite, testEntries, config) {
8615
8642
  inlineHookSandboxOptions: config.sandboxOptions,
8616
8643
  secretStore: config.secretStore,
8617
8644
  secretRedactor: config.secretRedactor,
8645
+ accessibility: config.accessibility,
8618
8646
  logCapture: config.logCapture,
8619
8647
  screenshotSize: config.screenshotSize,
8620
8648
  effectiveResolution: config.effectiveResolution,
@@ -8682,7 +8710,8 @@ async function runSuite(suite, testEntries, config) {
8682
8710
  timeouts: config.timeouts,
8683
8711
  logger: config.logger,
8684
8712
  secretStore: config.secretStore,
8685
- secretRedactor: config.secretRedactor
8713
+ secretRedactor: config.secretRedactor,
8714
+ accessibility: config.accessibility
8686
8715
  }, filePath);
8687
8716
  if (config.circuitBreaker) {
8688
8717
  config.circuitBreaker.record({ withMemory: false, passed: ablationResult.status === "passed" });
@@ -8853,14 +8882,14 @@ async function runSuite(suite, testEntries, config) {
8853
8882
 
8854
8883
  // src/validation/validate.ts
8855
8884
  import { readFile as readFile10 } from "fs/promises";
8856
- import { existsSync as existsSync5 } from "fs";
8885
+ import { existsSync as existsSync6 } from "fs";
8857
8886
  import path4 from "path";
8858
8887
  import { parse as parseYaml4, LineCounter as LineCounter2, parseDocument } from "yaml";
8859
8888
  import { glob as glob2 } from "glob";
8860
8889
 
8861
8890
  // src/hooks/parser.ts
8862
8891
  import { readFile as readFile9 } from "fs/promises";
8863
- import { dirname as dirname8, resolve as resolve4 } from "path";
8892
+ import { dirname as dirname9, resolve as resolve5 } from "path";
8864
8893
  import { parse as parseYaml3 } from "yaml";
8865
8894
  async function parseHooksFile(filePath) {
8866
8895
  let raw;
@@ -8882,12 +8911,12 @@ async function parseHooksFile(filePath) {
8882
8911
  );
8883
8912
  return { hooks: [], errors };
8884
8913
  }
8885
- const dir = dirname8(filePath);
8914
+ const dir = dirname9(filePath);
8886
8915
  const hooks = result.data.hooks.map((h) => ({
8887
8916
  ...h,
8888
- file: resolve4(dir, h.file),
8889
- deps: h.deps.map((d) => resolve4(dir, d)),
8890
- packageFile: h.packageFile ? resolve4(dir, h.packageFile) : void 0
8917
+ file: resolve5(dir, h.file),
8918
+ deps: h.deps.map((d) => resolve5(dir, d)),
8919
+ packageFile: h.packageFile ? resolve5(dir, h.packageFile) : void 0
8891
8920
  }));
8892
8921
  return { hooks, errors: [] };
8893
8922
  }
@@ -8902,7 +8931,7 @@ function isPathInsideDir(childPath, parentDir) {
8902
8931
  }
8903
8932
 
8904
8933
  // src/workspace/workspace-paths.ts
8905
- import { existsSync as existsSync4 } from "fs";
8934
+ import { existsSync as existsSync5 } from "fs";
8906
8935
  import path3 from "path";
8907
8936
  import { glob } from "glob";
8908
8937
  function toForwardSlash(value) {
@@ -9015,7 +9044,7 @@ function resolveWorkspacePaths(input) {
9015
9044
  ["workspace.envFile", resolved.envFile],
9016
9045
  ["workspace.secretsFile", resolved.secretsFile]
9017
9046
  ]) {
9018
- if (!existsSync4(file.absolutePath)) {
9047
+ if (!existsSync5(file.absolutePath)) {
9019
9048
  throw new Error(`Configured workspace file not found: ${key} -> ${file.absolutePath}`);
9020
9049
  }
9021
9050
  }
@@ -9046,7 +9075,7 @@ async function resolveWorkspaceFileTarget(input) {
9046
9075
  })) {
9047
9076
  throw new Error(`Workspace ${input.kind} file is not matched by configured workspace patterns: ${workspaceRelativePath}`);
9048
9077
  }
9049
- if (input.requireExisting && !existsSync4(absolutePath)) {
9078
+ if (input.requireExisting && !existsSync5(absolutePath)) {
9050
9079
  throw new Error(`Workspace ${input.kind} file not found: ${workspaceRelativePath}`);
9051
9080
  }
9052
9081
  return {
@@ -9168,7 +9197,7 @@ function validateSuiteFile(filePath, content, basedir) {
9168
9197
  continue;
9169
9198
  }
9170
9199
  const resolved = path4.resolve(basedir, testPath);
9171
- if (!existsSync5(resolved)) {
9200
+ if (!existsSync6(resolved)) {
9172
9201
  let line = 1;
9173
9202
  let column = 1;
9174
9203
  const seqNode = testsNode;
@@ -9203,7 +9232,7 @@ function validateFilename(filePath) {
9203
9232
  }
9204
9233
  async function validateHooksFile(hooksFilePath, options = {}) {
9205
9234
  const diagnostics = [];
9206
- if (!existsSync5(hooksFilePath)) {
9235
+ if (!existsSync6(hooksFilePath)) {
9207
9236
  if (options.required) {
9208
9237
  return [buildDiagnostic(hooksFilePath, `Configured hooks file not found: ${hooksFilePath}`)];
9209
9238
  }
@@ -9223,7 +9252,7 @@ async function validateHooksFile(hooksFilePath, options = {}) {
9223
9252
  return diagnostics;
9224
9253
  }
9225
9254
  for (const hook of hooks) {
9226
- if (!existsSync5(hook.file)) {
9255
+ if (!existsSync6(hook.file)) {
9227
9256
  diagnostics.push({
9228
9257
  file: hooksFilePath,
9229
9258
  line: 1,
@@ -9233,7 +9262,7 @@ async function validateHooksFile(hooksFilePath, options = {}) {
9233
9262
  });
9234
9263
  }
9235
9264
  for (const dep of hook.deps) {
9236
- if (!existsSync5(dep)) {
9265
+ if (!existsSync6(dep)) {
9237
9266
  diagnostics.push({
9238
9267
  file: hooksFilePath,
9239
9268
  line: 1,
@@ -9243,7 +9272,7 @@ async function validateHooksFile(hooksFilePath, options = {}) {
9243
9272
  });
9244
9273
  }
9245
9274
  }
9246
- if (hook.packageFile && !existsSync5(hook.packageFile)) {
9275
+ if (hook.packageFile && !existsSync6(hook.packageFile)) {
9247
9276
  diagnostics.push({
9248
9277
  file: hooksFilePath,
9249
9278
  line: 1,
@@ -9358,7 +9387,7 @@ function validateRequiredWorkspaceFiles(workspace) {
9358
9387
  ["workspace.envFile", workspace.envFile],
9359
9388
  ["workspace.secretsFile", workspace.secretsFile]
9360
9389
  ]) {
9361
- if (!existsSync5(file.absolutePath)) {
9390
+ if (!existsSync6(file.absolutePath)) {
9362
9391
  diagnostics.push(buildDiagnostic(file.absolutePath, `Configured workspace file not found: ${key} -> ${file.absolutePath}`));
9363
9392
  }
9364
9393
  }
@@ -9419,7 +9448,7 @@ async function validateProject(options = {}) {
9419
9448
  if (d.severity === "error") result.errorCount++;
9420
9449
  else result.warningCount++;
9421
9450
  }
9422
- if (hooksFilePath && hooksDiags.length === 0 && existsSync5(hooksFilePath)) {
9451
+ if (hooksFilePath && hooksDiags.length === 0 && existsSync6(hooksFilePath)) {
9423
9452
  const { hooks } = await parseHooksFile(hooksFilePath);
9424
9453
  const hookIds = new Set(hooks.map((h) => h.id));
9425
9454
  for (const filePath of filePaths) {
@@ -9525,7 +9554,7 @@ function warnIfOutOfBounds(coords, viewport, actionType) {
9525
9554
 
9526
9555
  // src/hooks/migrate-hook-refs.ts
9527
9556
  import { mkdir as mkdir6, readFile as readFile11, rm as rm2, writeFile as writeFile6 } from "fs/promises";
9528
- import { dirname as dirname9, relative, resolve as resolve5 } from "path";
9557
+ import { dirname as dirname10, relative, resolve as resolve6 } from "path";
9529
9558
  import { parse as parseYaml5, stringify as stringifyYaml2 } from "yaml";
9530
9559
  import { z as z20 } from "zod";
9531
9560
  import { generateHookId, isCanonicalHookId as isCanonicalHookId5 } from "@vostride/agent-qa-ids";
@@ -9631,7 +9660,7 @@ function rewriteSteps(owner, filePath, hookNameToId, hookIds, errors) {
9631
9660
  return changed;
9632
9661
  }
9633
9662
  async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9634
- const resolvedConfigPath = configPath ? resolve5(configPath) : resolve5(workspaceDir, "agent-qa.config.yaml");
9663
+ const resolvedConfigPath = configPath ? resolve6(configPath) : resolve6(workspaceDir, "agent-qa.config.yaml");
9635
9664
  const rawConfig = await readFile11(resolvedConfigPath, "utf-8");
9636
9665
  const parsedConfig = parseYaml5(rawConfig);
9637
9666
  const configResult = AgentQaConfigSchema.safeParse(parsedConfig);
@@ -9658,7 +9687,7 @@ async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9658
9687
  };
9659
9688
  }
9660
9689
  async function auditWorkspaceHookReferenceMigration(options) {
9661
- const workspaceDir = resolve5(options.workspaceDir);
9690
+ const workspaceDir = resolve6(options.workspaceDir);
9662
9691
  const errors = [];
9663
9692
  let context;
9664
9693
  try {
@@ -9726,7 +9755,7 @@ async function auditWorkspaceHookReferenceMigration(options) {
9726
9755
  });
9727
9756
  }
9728
9757
  for (const relativePath of context.targetFiles) {
9729
- const absolutePath = resolve5(context.configDir, relativePath);
9758
+ const absolutePath = resolve6(context.configDir, relativePath);
9730
9759
  let parsedFile;
9731
9760
  try {
9732
9761
  parsedFile = parseYaml5(await readFile11(absolutePath, "utf-8"));
@@ -9767,14 +9796,14 @@ async function applyWorkspaceHookReferenceMigration(options) {
9767
9796
  if (!audit.ok) {
9768
9797
  throw new HookReferenceMigrationError(audit.errors);
9769
9798
  }
9770
- const workspaceDir = options.configPath ? dirname9(resolve5(options.configPath)) : resolve5(options.workspaceDir);
9799
+ const workspaceDir = options.configPath ? dirname10(resolve6(options.configPath)) : resolve6(options.workspaceDir);
9771
9800
  for (const rewrite of audit.rewriteFiles) {
9772
- const outputPath = resolve5(workspaceDir, rewrite.path);
9773
- await mkdir6(dirname9(outputPath), { recursive: true });
9801
+ const outputPath = resolve6(workspaceDir, rewrite.path);
9802
+ await mkdir6(dirname10(outputPath), { recursive: true });
9774
9803
  await writeFile6(outputPath, rewrite.content, "utf-8");
9775
9804
  }
9776
9805
  for (const cleanupTarget of audit.cleanupTargets) {
9777
- await rm2(resolve5(workspaceDir, cleanupTarget), { recursive: true, force: true });
9806
+ await rm2(resolve6(workspaceDir, cleanupTarget), { recursive: true, force: true });
9778
9807
  }
9779
9808
  return audit;
9780
9809
  }
@@ -9845,12 +9874,12 @@ var RUN_ARTIFACT_SCHEMA_VERSION = 1;
9845
9874
  // src/analytics/identity.ts
9846
9875
  import { chmod, mkdir as mkdir8, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
9847
9876
  import { homedir as homedir2 } from "os";
9848
- import { dirname as dirname12, join as join9 } from "path";
9877
+ import { dirname as dirname13, join as join10 } from "path";
9849
9878
  import { idAgent } from "id-agent";
9850
9879
  var LOCAL_ANALYTICS_ID_PATTERN = /^u_([a-z]+-){9}[a-z]+$/;
9851
9880
  function getAnalyticsIdentityPath(env = process.env, homeDir = homedir2()) {
9852
- if (env.XDG_DATA_HOME) return join9(env.XDG_DATA_HOME, "agent-qa", "analytics.json");
9853
- return join9(homeDir, ".agent-qa", "analytics.json");
9881
+ if (env.XDG_DATA_HOME) return join10(env.XDG_DATA_HOME, "agent-qa", "analytics.json");
9882
+ return join10(homeDir, ".agent-qa", "analytics.json");
9854
9883
  }
9855
9884
  function generateAnalyticsUserId() {
9856
9885
  return idAgent({ prefix: "u", words: 10 });
@@ -9882,7 +9911,7 @@ async function readAnalyticsIdentity(path5) {
9882
9911
  }
9883
9912
  async function writeAnalyticsIdentity(distinctId, path5, isInternal = false) {
9884
9913
  const identityPath = path5 ?? getAnalyticsIdentityPath();
9885
- await mkdir8(dirname12(identityPath), { recursive: true });
9914
+ await mkdir8(dirname13(identityPath), { recursive: true });
9886
9915
  await writeFile8(identityPath, JSON.stringify({
9887
9916
  distinctId,
9888
9917
  is_internal: isInternal
@@ -10992,6 +11021,7 @@ export {
10992
11021
  findSecretTemplates,
10993
11022
  findUnresolvedTemplates,
10994
11023
  flushAnalytics,
11024
+ formatAppiumInstallGuidance,
10995
11025
  formatDiagnostics,
10996
11026
  formatDiagnosticsPlain,
10997
11027
  formatLogEntry,
@@ -11026,6 +11056,7 @@ export {
11026
11056
  listObservations,
11027
11057
  listProviders,
11028
11058
  loadLLMAuthPlugins,
11059
+ localAppiumBinaryNames,
11029
11060
  mapMobileCapabilities,
11030
11061
  mapWebCapabilities,
11031
11062
  mergeRunAttributes,
@@ -11052,6 +11083,7 @@ export {
11052
11083
  resolveAnalyticsAgentProduct,
11053
11084
  resolveAnalyticsIdentity,
11054
11085
  resolveAnalyticsStandardProperties,
11086
+ resolveAppiumExecutable,
11055
11087
  resolveBetterSqliteRebuildCommand,
11056
11088
  resolveFarmCredentials,
11057
11089
  resolveFileReferences,