@vostride/agent-qa-core 0.1.9 → 0.1.10

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;
@@ -8853,14 +8880,14 @@ async function runSuite(suite, testEntries, config) {
8853
8880
 
8854
8881
  // src/validation/validate.ts
8855
8882
  import { readFile as readFile10 } from "fs/promises";
8856
- import { existsSync as existsSync5 } from "fs";
8883
+ import { existsSync as existsSync6 } from "fs";
8857
8884
  import path4 from "path";
8858
8885
  import { parse as parseYaml4, LineCounter as LineCounter2, parseDocument } from "yaml";
8859
8886
  import { glob as glob2 } from "glob";
8860
8887
 
8861
8888
  // src/hooks/parser.ts
8862
8889
  import { readFile as readFile9 } from "fs/promises";
8863
- import { dirname as dirname8, resolve as resolve4 } from "path";
8890
+ import { dirname as dirname9, resolve as resolve5 } from "path";
8864
8891
  import { parse as parseYaml3 } from "yaml";
8865
8892
  async function parseHooksFile(filePath) {
8866
8893
  let raw;
@@ -8882,12 +8909,12 @@ async function parseHooksFile(filePath) {
8882
8909
  );
8883
8910
  return { hooks: [], errors };
8884
8911
  }
8885
- const dir = dirname8(filePath);
8912
+ const dir = dirname9(filePath);
8886
8913
  const hooks = result.data.hooks.map((h) => ({
8887
8914
  ...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
8915
+ file: resolve5(dir, h.file),
8916
+ deps: h.deps.map((d) => resolve5(dir, d)),
8917
+ packageFile: h.packageFile ? resolve5(dir, h.packageFile) : void 0
8891
8918
  }));
8892
8919
  return { hooks, errors: [] };
8893
8920
  }
@@ -8902,7 +8929,7 @@ function isPathInsideDir(childPath, parentDir) {
8902
8929
  }
8903
8930
 
8904
8931
  // src/workspace/workspace-paths.ts
8905
- import { existsSync as existsSync4 } from "fs";
8932
+ import { existsSync as existsSync5 } from "fs";
8906
8933
  import path3 from "path";
8907
8934
  import { glob } from "glob";
8908
8935
  function toForwardSlash(value) {
@@ -9015,7 +9042,7 @@ function resolveWorkspacePaths(input) {
9015
9042
  ["workspace.envFile", resolved.envFile],
9016
9043
  ["workspace.secretsFile", resolved.secretsFile]
9017
9044
  ]) {
9018
- if (!existsSync4(file.absolutePath)) {
9045
+ if (!existsSync5(file.absolutePath)) {
9019
9046
  throw new Error(`Configured workspace file not found: ${key} -> ${file.absolutePath}`);
9020
9047
  }
9021
9048
  }
@@ -9046,7 +9073,7 @@ async function resolveWorkspaceFileTarget(input) {
9046
9073
  })) {
9047
9074
  throw new Error(`Workspace ${input.kind} file is not matched by configured workspace patterns: ${workspaceRelativePath}`);
9048
9075
  }
9049
- if (input.requireExisting && !existsSync4(absolutePath)) {
9076
+ if (input.requireExisting && !existsSync5(absolutePath)) {
9050
9077
  throw new Error(`Workspace ${input.kind} file not found: ${workspaceRelativePath}`);
9051
9078
  }
9052
9079
  return {
@@ -9168,7 +9195,7 @@ function validateSuiteFile(filePath, content, basedir) {
9168
9195
  continue;
9169
9196
  }
9170
9197
  const resolved = path4.resolve(basedir, testPath);
9171
- if (!existsSync5(resolved)) {
9198
+ if (!existsSync6(resolved)) {
9172
9199
  let line = 1;
9173
9200
  let column = 1;
9174
9201
  const seqNode = testsNode;
@@ -9203,7 +9230,7 @@ function validateFilename(filePath) {
9203
9230
  }
9204
9231
  async function validateHooksFile(hooksFilePath, options = {}) {
9205
9232
  const diagnostics = [];
9206
- if (!existsSync5(hooksFilePath)) {
9233
+ if (!existsSync6(hooksFilePath)) {
9207
9234
  if (options.required) {
9208
9235
  return [buildDiagnostic(hooksFilePath, `Configured hooks file not found: ${hooksFilePath}`)];
9209
9236
  }
@@ -9223,7 +9250,7 @@ async function validateHooksFile(hooksFilePath, options = {}) {
9223
9250
  return diagnostics;
9224
9251
  }
9225
9252
  for (const hook of hooks) {
9226
- if (!existsSync5(hook.file)) {
9253
+ if (!existsSync6(hook.file)) {
9227
9254
  diagnostics.push({
9228
9255
  file: hooksFilePath,
9229
9256
  line: 1,
@@ -9233,7 +9260,7 @@ async function validateHooksFile(hooksFilePath, options = {}) {
9233
9260
  });
9234
9261
  }
9235
9262
  for (const dep of hook.deps) {
9236
- if (!existsSync5(dep)) {
9263
+ if (!existsSync6(dep)) {
9237
9264
  diagnostics.push({
9238
9265
  file: hooksFilePath,
9239
9266
  line: 1,
@@ -9243,7 +9270,7 @@ async function validateHooksFile(hooksFilePath, options = {}) {
9243
9270
  });
9244
9271
  }
9245
9272
  }
9246
- if (hook.packageFile && !existsSync5(hook.packageFile)) {
9273
+ if (hook.packageFile && !existsSync6(hook.packageFile)) {
9247
9274
  diagnostics.push({
9248
9275
  file: hooksFilePath,
9249
9276
  line: 1,
@@ -9358,7 +9385,7 @@ function validateRequiredWorkspaceFiles(workspace) {
9358
9385
  ["workspace.envFile", workspace.envFile],
9359
9386
  ["workspace.secretsFile", workspace.secretsFile]
9360
9387
  ]) {
9361
- if (!existsSync5(file.absolutePath)) {
9388
+ if (!existsSync6(file.absolutePath)) {
9362
9389
  diagnostics.push(buildDiagnostic(file.absolutePath, `Configured workspace file not found: ${key} -> ${file.absolutePath}`));
9363
9390
  }
9364
9391
  }
@@ -9419,7 +9446,7 @@ async function validateProject(options = {}) {
9419
9446
  if (d.severity === "error") result.errorCount++;
9420
9447
  else result.warningCount++;
9421
9448
  }
9422
- if (hooksFilePath && hooksDiags.length === 0 && existsSync5(hooksFilePath)) {
9449
+ if (hooksFilePath && hooksDiags.length === 0 && existsSync6(hooksFilePath)) {
9423
9450
  const { hooks } = await parseHooksFile(hooksFilePath);
9424
9451
  const hookIds = new Set(hooks.map((h) => h.id));
9425
9452
  for (const filePath of filePaths) {
@@ -9525,7 +9552,7 @@ function warnIfOutOfBounds(coords, viewport, actionType) {
9525
9552
 
9526
9553
  // src/hooks/migrate-hook-refs.ts
9527
9554
  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";
9555
+ import { dirname as dirname10, relative, resolve as resolve6 } from "path";
9529
9556
  import { parse as parseYaml5, stringify as stringifyYaml2 } from "yaml";
9530
9557
  import { z as z20 } from "zod";
9531
9558
  import { generateHookId, isCanonicalHookId as isCanonicalHookId5 } from "@vostride/agent-qa-ids";
@@ -9631,7 +9658,7 @@ function rewriteSteps(owner, filePath, hookNameToId, hookIds, errors) {
9631
9658
  return changed;
9632
9659
  }
9633
9660
  async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9634
- const resolvedConfigPath = configPath ? resolve5(configPath) : resolve5(workspaceDir, "agent-qa.config.yaml");
9661
+ const resolvedConfigPath = configPath ? resolve6(configPath) : resolve6(workspaceDir, "agent-qa.config.yaml");
9635
9662
  const rawConfig = await readFile11(resolvedConfigPath, "utf-8");
9636
9663
  const parsedConfig = parseYaml5(rawConfig);
9637
9664
  const configResult = AgentQaConfigSchema.safeParse(parsedConfig);
@@ -9658,7 +9685,7 @@ async function resolveWorkspaceMigrationContext(workspaceDir, configPath) {
9658
9685
  };
9659
9686
  }
9660
9687
  async function auditWorkspaceHookReferenceMigration(options) {
9661
- const workspaceDir = resolve5(options.workspaceDir);
9688
+ const workspaceDir = resolve6(options.workspaceDir);
9662
9689
  const errors = [];
9663
9690
  let context;
9664
9691
  try {
@@ -9726,7 +9753,7 @@ async function auditWorkspaceHookReferenceMigration(options) {
9726
9753
  });
9727
9754
  }
9728
9755
  for (const relativePath of context.targetFiles) {
9729
- const absolutePath = resolve5(context.configDir, relativePath);
9756
+ const absolutePath = resolve6(context.configDir, relativePath);
9730
9757
  let parsedFile;
9731
9758
  try {
9732
9759
  parsedFile = parseYaml5(await readFile11(absolutePath, "utf-8"));
@@ -9767,14 +9794,14 @@ async function applyWorkspaceHookReferenceMigration(options) {
9767
9794
  if (!audit.ok) {
9768
9795
  throw new HookReferenceMigrationError(audit.errors);
9769
9796
  }
9770
- const workspaceDir = options.configPath ? dirname9(resolve5(options.configPath)) : resolve5(options.workspaceDir);
9797
+ const workspaceDir = options.configPath ? dirname10(resolve6(options.configPath)) : resolve6(options.workspaceDir);
9771
9798
  for (const rewrite of audit.rewriteFiles) {
9772
- const outputPath = resolve5(workspaceDir, rewrite.path);
9773
- await mkdir6(dirname9(outputPath), { recursive: true });
9799
+ const outputPath = resolve6(workspaceDir, rewrite.path);
9800
+ await mkdir6(dirname10(outputPath), { recursive: true });
9774
9801
  await writeFile6(outputPath, rewrite.content, "utf-8");
9775
9802
  }
9776
9803
  for (const cleanupTarget of audit.cleanupTargets) {
9777
- await rm2(resolve5(workspaceDir, cleanupTarget), { recursive: true, force: true });
9804
+ await rm2(resolve6(workspaceDir, cleanupTarget), { recursive: true, force: true });
9778
9805
  }
9779
9806
  return audit;
9780
9807
  }
@@ -9845,12 +9872,12 @@ var RUN_ARTIFACT_SCHEMA_VERSION = 1;
9845
9872
  // src/analytics/identity.ts
9846
9873
  import { chmod, mkdir as mkdir8, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
9847
9874
  import { homedir as homedir2 } from "os";
9848
- import { dirname as dirname12, join as join9 } from "path";
9875
+ import { dirname as dirname13, join as join10 } from "path";
9849
9876
  import { idAgent } from "id-agent";
9850
9877
  var LOCAL_ANALYTICS_ID_PATTERN = /^u_([a-z]+-){9}[a-z]+$/;
9851
9878
  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");
9879
+ if (env.XDG_DATA_HOME) return join10(env.XDG_DATA_HOME, "agent-qa", "analytics.json");
9880
+ return join10(homeDir, ".agent-qa", "analytics.json");
9854
9881
  }
9855
9882
  function generateAnalyticsUserId() {
9856
9883
  return idAgent({ prefix: "u", words: 10 });
@@ -9882,7 +9909,7 @@ async function readAnalyticsIdentity(path5) {
9882
9909
  }
9883
9910
  async function writeAnalyticsIdentity(distinctId, path5, isInternal = false) {
9884
9911
  const identityPath = path5 ?? getAnalyticsIdentityPath();
9885
- await mkdir8(dirname12(identityPath), { recursive: true });
9912
+ await mkdir8(dirname13(identityPath), { recursive: true });
9886
9913
  await writeFile8(identityPath, JSON.stringify({
9887
9914
  distinctId,
9888
9915
  is_internal: isInternal
@@ -10992,6 +11019,7 @@ export {
10992
11019
  findSecretTemplates,
10993
11020
  findUnresolvedTemplates,
10994
11021
  flushAnalytics,
11022
+ formatAppiumInstallGuidance,
10995
11023
  formatDiagnostics,
10996
11024
  formatDiagnosticsPlain,
10997
11025
  formatLogEntry,
@@ -11026,6 +11054,7 @@ export {
11026
11054
  listObservations,
11027
11055
  listProviders,
11028
11056
  loadLLMAuthPlugins,
11057
+ localAppiumBinaryNames,
11029
11058
  mapMobileCapabilities,
11030
11059
  mapWebCapabilities,
11031
11060
  mergeRunAttributes,
@@ -11052,6 +11081,7 @@ export {
11052
11081
  resolveAnalyticsAgentProduct,
11053
11082
  resolveAnalyticsIdentity,
11054
11083
  resolveAnalyticsStandardProperties,
11084
+ resolveAppiumExecutable,
11055
11085
  resolveBetterSqliteRebuildCommand,
11056
11086
  resolveFarmCredentials,
11057
11087
  resolveFileReferences,