agent-qa 0.1.18 → 0.1.19

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/cli.cjs CHANGED
@@ -612,10 +612,14 @@ function buildExampleTest(platform, variant) {
612
612
  const expectedUrl = variant === "pass" ? "https://www.iana.org/help/example-domains" : "https://www.iana.org/example-domains";
613
613
  const testId = variant === "pass" ? "t_amber-birch-coral-delta-ember-falcon-garden-harbor-island-jungle" : "t_bronze-cedar-dune-ember-fjord-glade-harbor-ivory-jade-kelp";
614
614
  const name = variant === "pass" ? "Example passing test" : "Example failing test";
615
+ const browserOverride = variant === "fail" && hasWeb(platform) ? `use:
616
+ browser:
617
+ headless: false
618
+ ` : "";
615
619
  return `test-id: ${testId}
616
620
  name: ${name}
617
621
  target: ${defaultExampleTargetName(platform)}
618
- steps:
622
+ ${browserOverride}steps:
619
623
  - Verify the page says "Example Domain"
620
624
  - Click on "Learn More"
621
625
  - Verify the page url is "${expectedUrl}"
@@ -2117,12 +2121,12 @@ function createDoctorCommand() {
2117
2121
 
2118
2122
  // src/commands/run.ts
2119
2123
  var import_node_crypto = require("crypto");
2120
- var import_node_path9 = require("path");
2124
+ var import_node_path10 = require("path");
2121
2125
  var import_commander6 = require("commander");
2122
- var import_picocolors7 = __toESM(require("picocolors"), 1);
2126
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
2123
2127
  init_config();
2124
- var import_agent_qa_core7 = require("@vostride/agent-qa-core");
2125
2128
  var import_agent_qa_core8 = require("@vostride/agent-qa-core");
2129
+ var import_agent_qa_core9 = require("@vostride/agent-qa-core");
2126
2130
 
2127
2131
  // src/devices.ts
2128
2132
  var import_node_fs3 = require("fs");
@@ -2215,10 +2219,92 @@ function resolveProviderCredentials(transport, localBindings) {
2215
2219
 
2216
2220
  // src/commands/run.ts
2217
2221
  init_llm_utils();
2218
- var import_agent_qa_core9 = require("@vostride/agent-qa-core");
2219
- var RUNTIME_ARTIFACTS_DIR = import_agent_qa_core7.DEFAULT_AGENT_QA_ARTIFACTS_DIR || ".agent-qa/artifacts";
2220
- var RUNTIME_CACHE_DIR = import_agent_qa_core7.DEFAULT_AGENT_QA_CACHE_DIR || ".agent-qa/cache";
2221
- var RUNTIME_VIDEOS_DIR = import_agent_qa_core7.DEFAULT_AGENT_QA_VIDEOS_DIR || ".agent-qa/artifacts/videos";
2222
+ var import_agent_qa_core10 = require("@vostride/agent-qa-core");
2223
+
2224
+ // src/version-notice.ts
2225
+ var import_node_fs4 = require("fs");
2226
+ var import_node_path9 = require("path");
2227
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
2228
+ var import_agent_qa_core7 = require("@vostride/agent-qa-core");
2229
+ var RELEASES_URL = "https://github.com/vostride/agent-qa/releases";
2230
+ var UPDATE_COMMANDS = {
2231
+ pnpm: "pnpm add -D agent-qa@latest",
2232
+ npm: "npm install --save-dev agent-qa@latest",
2233
+ yarn: "yarn add --dev agent-qa@latest",
2234
+ bun: "bun add --dev agent-qa@latest"
2235
+ };
2236
+ var LOCKFILES = [
2237
+ { file: "pnpm-lock.yaml", packageManager: "pnpm" },
2238
+ { file: "package-lock.json", packageManager: "npm" },
2239
+ { file: "npm-shrinkwrap.json", packageManager: "npm" },
2240
+ { file: "yarn.lock", packageManager: "yarn" },
2241
+ { file: "bun.lock", packageManager: "bun" },
2242
+ { file: "bun.lockb", packageManager: "bun" }
2243
+ ];
2244
+ function shouldPrintAgentQaUpdateNotice(context) {
2245
+ return Boolean(
2246
+ context.reporterSelection.console && !context.reporterSelection.stdoutLive && context.liveEvents !== "true" && context.effectiveLogLevel !== "quiet" && context.effectiveLogLevel !== "silent"
2247
+ );
2248
+ }
2249
+ function inferAgentQaDevDependencyUpdateCommand(cwd = process.cwd()) {
2250
+ try {
2251
+ const packageJsonPath = (0, import_node_path9.join)(cwd, "package.json");
2252
+ if (!(0, import_node_fs4.existsSync)(packageJsonPath)) return void 0;
2253
+ const manifest = JSON.parse((0, import_node_fs4.readFileSync)(packageJsonPath, "utf-8"));
2254
+ if (!isRecord(manifest) || !hasAgentQaDevDependency(manifest)) return void 0;
2255
+ const packageManager = inferPackageManager(manifest, cwd);
2256
+ return packageManager ? UPDATE_COMMANDS[packageManager] : void 0;
2257
+ } catch {
2258
+ return void 0;
2259
+ }
2260
+ }
2261
+ async function printAgentQaUpdateNoticeIfNeeded(context) {
2262
+ try {
2263
+ if (!shouldPrintAgentQaUpdateNotice(context)) return;
2264
+ const status = await (0, import_agent_qa_core7.getAgentQaUpdateStatus)();
2265
+ const installedVersion = status.installedVersion.trim();
2266
+ const latestVersion = typeof status.latestVersion === "string" ? status.latestVersion.trim() : "";
2267
+ if (!status.updateAvailable || !latestVersion) return;
2268
+ const command = inferAgentQaDevDependencyUpdateCommand(context.cwd);
2269
+ const log = context.log ?? console.log;
2270
+ log();
2271
+ log(`${import_picocolors7.default.bold("Update available:")} agent-qa v${latestVersion}`);
2272
+ if (installedVersion) {
2273
+ log(import_picocolors7.default.dim(`Current version: v${installedVersion}`));
2274
+ }
2275
+ log(`Releases: ${import_picocolors7.default.cyan(RELEASES_URL)}`);
2276
+ if (command) {
2277
+ log(`Update: ${import_picocolors7.default.cyan(command)}`);
2278
+ }
2279
+ } catch {
2280
+ }
2281
+ }
2282
+ function hasAgentQaDevDependency(manifest) {
2283
+ const devDependencies = manifest.devDependencies;
2284
+ return isRecord(devDependencies) && Object.prototype.hasOwnProperty.call(devDependencies, "agent-qa");
2285
+ }
2286
+ function inferPackageManager(manifest, cwd) {
2287
+ if (typeof manifest.packageManager === "string") {
2288
+ return packageManagerFromSpecifier(manifest.packageManager);
2289
+ }
2290
+ const matchingLockfiles = LOCKFILES.filter(({ file }) => (0, import_node_fs4.existsSync)((0, import_node_path9.join)(cwd, file)));
2291
+ return matchingLockfiles.length === 1 ? matchingLockfiles[0].packageManager : void 0;
2292
+ }
2293
+ function packageManagerFromSpecifier(specifier) {
2294
+ const name = specifier.split("@")[0];
2295
+ if (name === "pnpm" || name === "npm" || name === "yarn" || name === "bun") {
2296
+ return name;
2297
+ }
2298
+ return void 0;
2299
+ }
2300
+ function isRecord(value) {
2301
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2302
+ }
2303
+
2304
+ // src/commands/run.ts
2305
+ var RUNTIME_ARTIFACTS_DIR = import_agent_qa_core8.DEFAULT_AGENT_QA_ARTIFACTS_DIR || ".agent-qa/artifacts";
2306
+ var RUNTIME_CACHE_DIR = import_agent_qa_core8.DEFAULT_AGENT_QA_CACHE_DIR || ".agent-qa/cache";
2307
+ var RUNTIME_VIDEOS_DIR = import_agent_qa_core8.DEFAULT_AGENT_QA_VIDEOS_DIR || ".agent-qa/artifacts/videos";
2222
2308
  var _appiumManager = null;
2223
2309
  async function acquireAppium(logLevel) {
2224
2310
  if (process.env.AGENT_QA_APPIUM_URL) return process.env.AGENT_QA_APPIUM_URL;
@@ -2347,13 +2433,13 @@ function resolveDashboardVideoDir(config, configDir, dashboardEnabled) {
2347
2433
  const recordingCfg = config.services?.recording;
2348
2434
  const configuredVideoDir = recordingCfg?.videoDir;
2349
2435
  if (configuredVideoDir) {
2350
- return (0, import_node_path9.resolve)(configDir, configuredVideoDir);
2436
+ return (0, import_node_path10.resolve)(configDir, configuredVideoDir);
2351
2437
  }
2352
2438
  if (dashboardEnabled) {
2353
2439
  const dashArtifactsDir = config.services?.dashboard?.artifactsDir;
2354
- return (0, import_node_path9.resolve)(configDir, dashArtifactsDir ?? RUNTIME_ARTIFACTS_DIR, "videos");
2440
+ return (0, import_node_path10.resolve)(configDir, dashArtifactsDir ?? RUNTIME_ARTIFACTS_DIR, "videos");
2355
2441
  }
2356
- return (0, import_node_path9.resolve)(configDir, RUNTIME_VIDEOS_DIR);
2442
+ return (0, import_node_path10.resolve)(configDir, RUNTIME_VIDEOS_DIR);
2357
2443
  }
2358
2444
  var SUPPORTED_REPORTERS = ["console", "junit", "stdout-live", "dashboard"];
2359
2445
  function parseVarFlags(flags) {
@@ -2373,8 +2459,8 @@ function resolveRunnerAttribute(transport) {
2373
2459
  return transport === "browserstack" ? "browserstack" : "local";
2374
2460
  }
2375
2461
  function buildCliRunAttributes(userAttributes, runner) {
2376
- return (0, import_agent_qa_core7.mergeRunAttributes)(
2377
- (0, import_agent_qa_core7.buildInternalRunAttributes)({ trigger: "cli", runner }),
2462
+ return (0, import_agent_qa_core8.mergeRunAttributes)(
2463
+ (0, import_agent_qa_core8.buildInternalRunAttributes)({ trigger: "cli", runner }),
2378
2464
  userAttributes
2379
2465
  );
2380
2466
  }
@@ -2387,17 +2473,17 @@ function readRunAttributesFromEnv() {
2387
2473
  } catch {
2388
2474
  throw new Error("inherited run attributes: AGENT_QA_RUN_ATTRIBUTES_JSON must contain valid run attributes JSON");
2389
2475
  }
2390
- const attributes = (0, import_agent_qa_core7.validateTrustedRunAttributes)(parsed, "inherited run attributes");
2476
+ const attributes = (0, import_agent_qa_core8.validateTrustedRunAttributes)(parsed, "inherited run attributes");
2391
2477
  return Object.keys(attributes).length > 0 ? attributes : void 0;
2392
2478
  }
2393
2479
  function resolveCliRunAttributes(userAttributes, runner, inheritedAttributes) {
2394
2480
  if (!inheritedAttributes) return buildCliRunAttributes(userAttributes, runner);
2395
- const trigger = inheritedAttributes[import_agent_qa_core7.ATTR_TRIGGER];
2481
+ const trigger = inheritedAttributes[import_agent_qa_core8.ATTR_TRIGGER];
2396
2482
  const inheritedUserAttributes = Object.fromEntries(
2397
- Object.entries(inheritedAttributes).filter(([key]) => key !== import_agent_qa_core7.ATTR_TRIGGER && key !== import_agent_qa_core7.ATTR_RUNNER)
2483
+ Object.entries(inheritedAttributes).filter(([key]) => key !== import_agent_qa_core8.ATTR_TRIGGER && key !== import_agent_qa_core8.ATTR_RUNNER)
2398
2484
  );
2399
- return (0, import_agent_qa_core7.mergeRunAttributes)(
2400
- (0, import_agent_qa_core7.buildInternalRunAttributes)({ trigger: trigger ?? "cli", runner }),
2485
+ return (0, import_agent_qa_core8.mergeRunAttributes)(
2486
+ (0, import_agent_qa_core8.buildInternalRunAttributes)({ trigger: trigger ?? "cli", runner }),
2401
2487
  inheritedUserAttributes
2402
2488
  );
2403
2489
  }
@@ -2406,7 +2492,7 @@ function writeRunAttributesToEnv(attributes) {
2406
2492
  }
2407
2493
  function printRunAttributes(attributes) {
2408
2494
  if (!attributes || Object.keys(attributes).length === 0) return;
2409
- const block = (0, import_agent_qa_core7.formatRunAttributesBlock)(attributes);
2495
+ const block = (0, import_agent_qa_core8.formatRunAttributesBlock)(attributes);
2410
2496
  if (block) console.log(block);
2411
2497
  }
2412
2498
  function resolveReporterSelection(opts, dashboardConfigured) {
@@ -2447,6 +2533,13 @@ async function flushAnalyticsRunReporter(reporter) {
2447
2533
  } catch {
2448
2534
  }
2449
2535
  }
2536
+ async function maybePrintPostRunUpdateNotice(context) {
2537
+ try {
2538
+ if (!shouldPrintAgentQaUpdateNotice(context)) return;
2539
+ await printAgentQaUpdateNoticeIfNeeded(context);
2540
+ } catch {
2541
+ }
2542
+ }
2450
2543
  async function captureSingleAnalyticsResult(reporter, result) {
2451
2544
  if (!reporter?.onRunEnd) {
2452
2545
  await flushAnalyticsRunReporter(reporter);
@@ -2467,37 +2560,37 @@ async function captureSingleAnalyticsResult(reporter, result) {
2467
2560
  function formatParseErrors(errors) {
2468
2561
  for (const err of errors) {
2469
2562
  const location = `${err.file}:${err.line}:${err.column}`;
2470
- const severity = err.severity === "error" ? import_picocolors7.default.red("error") : import_picocolors7.default.yellow("warning");
2563
+ const severity = err.severity === "error" ? import_picocolors8.default.red("error") : import_picocolors8.default.yellow("warning");
2471
2564
  console.error(`${severity}: ${err.message}`);
2472
- console.error(` ${import_picocolors7.default.blue("-->")} ${location}`);
2565
+ console.error(` ${import_picocolors8.default.blue("-->")} ${location}`);
2473
2566
  if (err.source) {
2474
- console.error(` ${import_picocolors7.default.blue("|")} ${err.source}`);
2567
+ console.error(` ${import_picocolors8.default.blue("|")} ${err.source}`);
2475
2568
  }
2476
2569
  if (err.suggestion) {
2477
- console.error(` ${import_picocolors7.default.blue("=")} ${import_picocolors7.default.bold("help")}: ${err.suggestion}`);
2570
+ console.error(` ${import_picocolors8.default.blue("=")} ${import_picocolors8.default.bold("help")}: ${err.suggestion}`);
2478
2571
  }
2479
2572
  console.error();
2480
2573
  }
2481
2574
  }
2482
2575
  function createTestRunId() {
2483
- return process.env.AGENT_QA_RUN_ID ?? (0, import_agent_qa_core7.generateRunId)();
2576
+ return process.env.AGENT_QA_RUN_ID ?? (0, import_agent_qa_core8.generateRunId)();
2484
2577
  }
2485
2578
  function createSuiteRunId() {
2486
- return process.env.AGENT_QA_SUITE_QUEUE_ID ?? process.env.AGENT_QA_RUN_ID ?? (0, import_agent_qa_core7.generateRunId)();
2579
+ return process.env.AGENT_QA_SUITE_QUEUE_ID ?? process.env.AGENT_QA_RUN_ID ?? (0, import_agent_qa_core8.generateRunId)();
2487
2580
  }
2488
2581
  function printRunId(runId) {
2489
2582
  if (runId) console.log(`Run ID: ${runId}`);
2490
2583
  }
2491
2584
  function printMemoryStatus(log) {
2492
2585
  const parts = [];
2493
- if (log.added > 0) parts.push(import_picocolors7.default.green(`${log.added} added`));
2586
+ if (log.added > 0) parts.push(import_picocolors8.default.green(`${log.added} added`));
2494
2587
  if (log.confirmed > 0) parts.push(`${log.confirmed} confirmed`);
2495
- if (log.deprecated > 0) parts.push(import_picocolors7.default.yellow(`${log.deprecated} deprecated`));
2588
+ if (log.deprecated > 0) parts.push(import_picocolors8.default.yellow(`${log.deprecated} deprecated`));
2496
2589
  if (parts.length === 0) parts.push("no changes");
2497
2590
  const secs = log.curatorDuration >= 1e3 ? `${Math.round(log.curatorDuration / 1e3)}s` : `${log.curatorDuration}ms`;
2498
- console.log(` ${import_picocolors7.default.dim("Memory:")} ${parts.join(", ")} ${import_picocolors7.default.dim(`(${secs})`)}`);
2591
+ console.log(` ${import_picocolors8.default.dim("Memory:")} ${parts.join(", ")} ${import_picocolors8.default.dim(`(${secs})`)}`);
2499
2592
  for (const err of log.errors) {
2500
- console.log(` ${import_picocolors7.default.dim("Memory:")} ${import_picocolors7.default.yellow(`warning -- ${err}`)}`);
2593
+ console.log(` ${import_picocolors8.default.dim("Memory:")} ${import_picocolors8.default.yellow(`warning -- ${err}`)}`);
2501
2594
  }
2502
2595
  }
2503
2596
  function isGlobLikePattern(value) {
@@ -2512,15 +2605,15 @@ function matchesCliWorkspacePattern(workspace, kind, pattern, record) {
2512
2605
  testMatch: kind === "test" ? [pattern] : workspace.testMatch,
2513
2606
  suiteMatch: kind === "suite" ? [pattern] : workspace.suiteMatch
2514
2607
  };
2515
- return (0, import_agent_qa_core8.isWorkspacePathMatch)({
2608
+ return (0, import_agent_qa_core9.isWorkspacePathMatch)({
2516
2609
  workspace: patternWorkspace,
2517
2610
  kind,
2518
2611
  workspaceRelativePath: record.workspaceRelativePath
2519
2612
  });
2520
2613
  }
2521
2614
  async function discoverFilesForCliPatterns(workspace, patterns) {
2522
- const testRecords = await (0, import_agent_qa_core8.discoverWorkspaceFiles)({ workspace, kind: "test" });
2523
- const suiteRecords = await (0, import_agent_qa_core8.discoverWorkspaceFiles)({ workspace, kind: "suite" });
2615
+ const testRecords = await (0, import_agent_qa_core9.discoverWorkspaceFiles)({ workspace, kind: "test" });
2616
+ const suiteRecords = await (0, import_agent_qa_core9.discoverWorkspaceFiles)({ workspace, kind: "suite" });
2524
2617
  const discoveredByKind = {
2525
2618
  test: testRecords,
2526
2619
  suite: suiteRecords
@@ -2541,7 +2634,7 @@ async function discoverFilesForCliPatterns(workspace, patterns) {
2541
2634
  }
2542
2635
  continue;
2543
2636
  }
2544
- const record = await (0, import_agent_qa_core8.resolveWorkspaceFileTarget)({
2637
+ const record = await (0, import_agent_qa_core9.resolveWorkspaceFileTarget)({
2545
2638
  workspace,
2546
2639
  kind,
2547
2640
  filePath: pattern,
@@ -2569,21 +2662,21 @@ function buildHooksArtifact(hooks) {
2569
2662
  async function loadRuntimeSecrets(input3) {
2570
2663
  const configuredSecretsFile = input3.config.workspace?.secretsFile;
2571
2664
  if (typeof configuredSecretsFile !== "string" || configuredSecretsFile.trim().length === 0) {
2572
- console.error(import_picocolors7.default.red("Error: workspace.secretsFile is required. Run `agent-qa init` or set it in agent-qa.config.yaml."));
2665
+ console.error(import_picocolors8.default.red("Error: workspace.secretsFile is required. Run `agent-qa init` or set it in agent-qa.config.yaml."));
2573
2666
  process.exit(1);
2574
2667
  }
2575
- const secretsPath = input3.secretsFilePath ?? (0, import_node_path9.resolve)(input3.configDir, configuredSecretsFile);
2668
+ const secretsPath = input3.secretsFilePath ?? (0, import_node_path10.resolve)(input3.configDir, configuredSecretsFile);
2576
2669
  if (!input3.existsSync(secretsPath)) {
2577
- console.error(import_picocolors7.default.red(`Error: Secrets file not found: ${secretsPath}`));
2578
- console.error(import_picocolors7.default.dim("Create the file before running tests. It may be empty, but it must exist."));
2670
+ console.error(import_picocolors8.default.red(`Error: Secrets file not found: ${secretsPath}`));
2671
+ console.error(import_picocolors8.default.dim("Create the file before running tests. It may be empty, but it must exist."));
2579
2672
  process.exit(1);
2580
2673
  }
2581
2674
  let secretsContent;
2582
2675
  try {
2583
2676
  secretsContent = input3.readFileSync(secretsPath, "utf-8");
2584
2677
  } catch {
2585
- console.error(import_picocolors7.default.red(`Error: Secrets file could not be read: ${secretsPath}`));
2586
- console.error(import_picocolors7.default.dim("Check the path and file permissions before running tests."));
2678
+ console.error(import_picocolors8.default.red(`Error: Secrets file could not be read: ${secretsPath}`));
2679
+ console.error(import_picocolors8.default.dim("Check the path and file permissions before running tests."));
2587
2680
  process.exit(1);
2588
2681
  }
2589
2682
  try {
@@ -2600,12 +2693,12 @@ async function loadRuntimeSecrets(input3) {
2600
2693
  };
2601
2694
  } catch (err) {
2602
2695
  const message = err instanceof Error ? err.message : String(err);
2603
- console.error(import_picocolors7.default.red(`Error: Secrets file is invalid: ${message}`));
2696
+ console.error(import_picocolors8.default.red(`Error: Secrets file is invalid: ${message}`));
2604
2697
  process.exit(1);
2605
2698
  }
2606
2699
  }
2607
2700
  function buildRunArtifactContext(input3) {
2608
- return (0, import_agent_qa_core7.redactAuthStateValue)({
2701
+ return (0, import_agent_qa_core8.redactAuthStateValue)({
2609
2702
  artifact: {
2610
2703
  kind: input3.kind,
2611
2704
  config: {
@@ -2657,7 +2750,7 @@ async function resolveDeviceAndFarmSession(config, deviceName, testPlatform, tes
2657
2750
  }
2658
2751
  const browserstackApp = mobileResolved?.app.install?.browserstack;
2659
2752
  if (!browserstackApp && hasNativeAppIdentity(mobileResolved) && !isBrowserMode(resolved.match)) {
2660
- throw new import_agent_qa_core7.MobileSetupError({
2753
+ throw new import_agent_qa_core8.MobileSetupError({
2661
2754
  category: "app-install",
2662
2755
  message: `BrowserStack native app target "${mobileResolved?.targetName ?? "unknown"}" requires app.browserstack; app.path is local-only and is not used as a BrowserStack fallback.`,
2663
2756
  platform: resolved.platform,
@@ -2681,9 +2774,9 @@ async function resolveDeviceAndFarmSession(config, deviceName, testPlatform, tes
2681
2774
  appSourceTrace: mobileResolved?.sourceTrace
2682
2775
  });
2683
2776
  } catch (err) {
2684
- if (err instanceof import_agent_qa_core7.MobileSetupError) throw err;
2777
+ if (err instanceof import_agent_qa_core8.MobileSetupError) throw err;
2685
2778
  if (browserstackApp) {
2686
- throw new import_agent_qa_core7.MobileSetupError({
2779
+ throw new import_agent_qa_core8.MobileSetupError({
2687
2780
  category: "app-install",
2688
2781
  message: `Failed to resolve BrowserStack app reference: ${err instanceof Error ? err.message : String(err)}`,
2689
2782
  platform: resolved.platform,
@@ -2705,25 +2798,25 @@ function hasNativeAppIdentity(mobileResolved) {
2705
2798
  return Boolean(app?.bundleId || app?.appPackage || app?.appActivity || app?.deepLinkAppId);
2706
2799
  }
2707
2800
  function wrapMobileSetupError(err) {
2708
- if (err instanceof import_agent_qa_core7.MobileSetupError) {
2801
+ if (err instanceof import_agent_qa_core8.MobileSetupError) {
2709
2802
  throw new Error(`${err.category}: ${err.message}`);
2710
2803
  }
2711
2804
  throw err;
2712
2805
  }
2713
2806
  function resolveMobileRunOrThrow(input3) {
2714
2807
  try {
2715
- return (0, import_agent_qa_core7.resolveMobileRunConfig)(input3);
2808
+ return (0, import_agent_qa_core8.resolveMobileRunConfig)(input3);
2716
2809
  } catch (err) {
2717
2810
  wrapMobileSetupError(err);
2718
2811
  }
2719
2812
  }
2720
2813
  function getSelectedAuthStateUse(use) {
2721
- return (0, import_agent_qa_core7.normalizeAuthStateUse)(use);
2814
+ return (0, import_agent_qa_core8.normalizeAuthStateUse)(use);
2722
2815
  }
2723
2816
  async function resolveSelectedAuthStateForRun(input3) {
2724
2817
  if (!input3.authState || input3.authState.load === false) return void 0;
2725
2818
  try {
2726
- return await (0, import_agent_qa_core7.resolveAuthStateForRun)({
2819
+ return await (0, import_agent_qa_core8.resolveAuthStateForRun)({
2727
2820
  configDir: input3.configDir,
2728
2821
  authStateDir: input3.config.services?.authState?.dir,
2729
2822
  targetName: input3.resolvedTarget.name,
@@ -2731,14 +2824,14 @@ async function resolveSelectedAuthStateForRun(input3) {
2731
2824
  target: { platform: input3.resolvedTarget.platform }
2732
2825
  });
2733
2826
  } catch (err) {
2734
- console.error(import_picocolors7.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2827
+ console.error(import_picocolors8.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2735
2828
  process.exit(2);
2736
2829
  }
2737
2830
  }
2738
2831
  function resolveAuthStateCapturePathsForRun(input3) {
2739
2832
  if (input3.authState?.capture !== true) return void 0;
2740
2833
  try {
2741
- return (0, import_agent_qa_core7.resolveAuthStatePaths)({
2834
+ return (0, import_agent_qa_core8.resolveAuthStatePaths)({
2742
2835
  configDir: input3.configDir,
2743
2836
  authStateDir: input3.config.services?.authState?.dir,
2744
2837
  targetName: input3.resolvedTarget.name,
@@ -2746,7 +2839,7 @@ function resolveAuthStateCapturePathsForRun(input3) {
2746
2839
  target: { platform: input3.resolvedTarget.platform }
2747
2840
  });
2748
2841
  } catch (err) {
2749
- console.error(import_picocolors7.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2842
+ console.error(import_picocolors8.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2750
2843
  process.exit(2);
2751
2844
  }
2752
2845
  }
@@ -2776,7 +2869,7 @@ async function captureAuthStateForRun(input3) {
2776
2869
  const payload = await context.storageState({ indexedDB: true });
2777
2870
  const capturedAt = (/* @__PURE__ */ new Date()).toISOString();
2778
2871
  const metadata = {
2779
- version: import_agent_qa_core7.AUTH_STATE_SCHEMA_VERSION,
2872
+ version: import_agent_qa_core8.AUTH_STATE_SCHEMA_VERSION,
2780
2873
  kind: "web",
2781
2874
  target: input3.paths.targetName,
2782
2875
  name: input3.paths.stateName,
@@ -2839,7 +2932,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2839
2932
  const dashboardCfg = config.services?.dashboard;
2840
2933
  const reporterSelectionResult = resolveReporterSelection(opts, Boolean(dashboardCfg));
2841
2934
  if (reporterSelectionResult.error) {
2842
- console.error(import_picocolors7.default.red(`Error: ${reporterSelectionResult.error}`));
2935
+ console.error(import_picocolors8.default.red(`Error: ${reporterSelectionResult.error}`));
2843
2936
  process.exit(2);
2844
2937
  }
2845
2938
  const reporterSelection = reporterSelectionResult.selection;
@@ -2855,7 +2948,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2855
2948
  activeSuiteDbs.add(dashboardDb);
2856
2949
  return { dashboardDb, logStorage: dashboardDb };
2857
2950
  } catch (err) {
2858
- console.warn(import_picocolors7.default.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
2951
+ console.warn(import_picocolors8.default.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
2859
2952
  return {};
2860
2953
  }
2861
2954
  };
@@ -2903,8 +2996,8 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2903
2996
  const testEntries = [];
2904
2997
  const suiteMembers = [];
2905
2998
  for (const { test: relativePath, id: suiteEntryId } of suite.tests) {
2906
- if (!(0, import_agent_qa_core9.isPathInsideDir)(relativePath, configDir)) {
2907
- console.error(import_picocolors7.default.red(`Path traversal rejected: ${relativePath}`));
2999
+ if (!(0, import_agent_qa_core10.isPathInsideDir)(relativePath, configDir)) {
3000
+ console.error(import_picocolors8.default.red(`Path traversal rejected: ${relativePath}`));
2908
3001
  const runId = createSuiteRunId();
2909
3002
  if (dashboardDb) {
2910
3003
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2942,7 +3035,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2942
3035
  const fileContent = await readFile5(absolutePath, "utf-8");
2943
3036
  const parseResult = parseTestFile2(fileContent, absolutePath);
2944
3037
  if (parseResult.errors.length > 0) {
2945
- console.error(import_picocolors7.default.red(`Parse errors in ${relativePath}:`));
3038
+ console.error(import_picocolors8.default.red(`Parse errors in ${relativePath}:`));
2946
3039
  formatParseErrors(parseResult.errors);
2947
3040
  const runId = createSuiteRunId();
2948
3041
  if (dashboardDb) {
@@ -2984,7 +3077,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2984
3077
  process.exit(2);
2985
3078
  }
2986
3079
  if (parseResult.tests.length === 0) {
2987
- console.error(import_picocolors7.default.red(`No test definition found in ${relativePath}`));
3080
+ console.error(import_picocolors8.default.red(`No test definition found in ${relativePath}`));
2988
3081
  const runId = createSuiteRunId();
2989
3082
  if (dashboardDb) {
2990
3083
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -3021,12 +3114,12 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3021
3114
  const testDef = parseResult.tests[0];
3022
3115
  const childAuthStateUse = getSelectedAuthStateUse(testDef.use);
3023
3116
  if (suiteAuthStateUse && childAuthStateUse && childAuthStateUse.name !== suiteAuthStateUse.name) {
3024
- console.error(import_picocolors7.default.red(`Suite auth state "${suiteAuthStateUse.name}" conflicts with child test auth state "${childAuthStateUse.name}". Use one primary auth state per suite.`));
3117
+ console.error(import_picocolors8.default.red(`Suite auth state "${suiteAuthStateUse.name}" conflicts with child test auth state "${childAuthStateUse.name}". Use one primary auth state per suite.`));
3025
3118
  process.exit(2);
3026
3119
  }
3027
3120
  if (testDef["test-id"] && testDef["test-id"] !== suiteEntryId) {
3028
3121
  const mismatchMsg = `ID mismatch in suite "${suite.name}": test file ${relativePath} has test-id "${testDef["test-id"]}" but suite entry specifies id "${suiteEntryId}"`;
3029
- console.error(import_picocolors7.default.red(mismatchMsg));
3122
+ console.error(import_picocolors8.default.red(mismatchMsg));
3030
3123
  const runId = createSuiteRunId();
3031
3124
  if (dashboardDb) {
3032
3125
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -3155,7 +3248,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3155
3248
  mobileResolved = { ...mobileResolved, appium: { url: appiumUrl, managed: !process.env.AGENT_QA_APPIUM_URL } };
3156
3249
  }
3157
3250
  } catch (err) {
3158
- throw new import_agent_qa_core7.MobileSetupError({
3251
+ throw new import_agent_qa_core8.MobileSetupError({
3159
3252
  category: "appium-startup",
3160
3253
  message: `Could not auto-start Appium: ${err instanceof Error ? err.message : String(err)}`,
3161
3254
  platform: suitePlatform,
@@ -3267,7 +3360,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3267
3360
  let suiteMemoryProvider;
3268
3361
  let suiteCircuitBreaker;
3269
3362
  const suiteMemoryConfig = config.services?.memory;
3270
- const suiteMemoryRoot = (0, import_agent_qa_core7.resolveMemoryRoot)(config, configDir);
3363
+ const suiteMemoryRoot = (0, import_agent_qa_core8.resolveMemoryRoot)(config, configDir);
3271
3364
  if (opts.memory !== false && suiteMemoryConfig?.enabled !== false) {
3272
3365
  try {
3273
3366
  const { createMemoryProvider } = await import("@vostride/agent-qa-core");
@@ -3277,7 +3370,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3277
3370
  curatorLockTimeout: suiteMemoryConfig?.curatorLockTimeout
3278
3371
  });
3279
3372
  } catch (err) {
3280
- console.warn(` ${import_picocolors7.default.dim("Memory:")} init error -- ${err.message}`);
3373
+ console.warn(` ${import_picocolors8.default.dim("Memory:")} init error -- ${err.message}`);
3281
3374
  }
3282
3375
  if (suiteMemoryConfig?.circuitBreakerEnabled !== false) {
3283
3376
  const { CircuitBreaker } = await import("@vostride/agent-qa-core");
@@ -3422,19 +3515,19 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3422
3515
  const batchOutcome = await flushSuiteParents();
3423
3516
  if (batchOutcome.cancelled || shutdownRequested) break;
3424
3517
  if (opts.bail && batchOutcome.failed) {
3425
- console.log(import_picocolors7.default.yellow("\nBailing out \u2014 stopping after first failed suite"));
3518
+ console.log(import_picocolors8.default.yellow("\nBailing out \u2014 stopping after first failed suite"));
3426
3519
  break;
3427
3520
  }
3428
3521
  const outcome = await runOneSuiteFile(suiteFile, suite);
3429
3522
  if (outcome.cancelled || shutdownRequested) break;
3430
3523
  if (opts.bail && outcome.failed) {
3431
- console.log(import_picocolors7.default.yellow("\nBailing out \u2014 stopping after first failed suite"));
3524
+ console.log(import_picocolors8.default.yellow("\nBailing out \u2014 stopping after first failed suite"));
3432
3525
  break;
3433
3526
  }
3434
3527
  }
3435
3528
  const finalBatchOutcome = await flushSuiteParents();
3436
3529
  if (opts.bail && finalBatchOutcome.failed) {
3437
- console.log(import_picocolors7.default.yellow("\nBailing out \u2014 stopping after first failed suite"));
3530
+ console.log(import_picocolors8.default.yellow("\nBailing out \u2014 stopping after first failed suite"));
3438
3531
  }
3439
3532
  process.removeListener("SIGINT", handleShutdown);
3440
3533
  process.removeListener("SIGTERM", handleShutdown);
@@ -3447,7 +3540,7 @@ function createRunCommand() {
3447
3540
  try {
3448
3541
  const modeFlags = [opts.test, opts.suite, opts.all].filter(Boolean).length;
3449
3542
  if (modeFlags > 1) {
3450
- console.error(import_picocolors7.default.red("Error: --test, --suite, and --all are mutually exclusive."));
3543
+ console.error(import_picocolors8.default.red("Error: --test, --suite, and --all are mutually exclusive."));
3451
3544
  process.exit(1);
3452
3545
  }
3453
3546
  const program2 = command.parent;
@@ -3463,8 +3556,8 @@ function createRunCommand() {
3463
3556
  flags: flagOverrides,
3464
3557
  loadAuthPlugins: !(opts.dryRun || opts.listTests)
3465
3558
  });
3466
- const configFilePath = (0, import_node_path9.resolve)(globalOpts.config ?? "agent-qa.config.yaml");
3467
- const workspacePaths = (0, import_agent_qa_core8.resolveWorkspacePaths)({
3559
+ const configFilePath = (0, import_node_path10.resolve)(globalOpts.config ?? "agent-qa.config.yaml");
3560
+ const workspacePaths = (0, import_agent_qa_core9.resolveWorkspacePaths)({
3468
3561
  config,
3469
3562
  configPath: configFilePath
3470
3563
  });
@@ -3475,20 +3568,20 @@ function createRunCommand() {
3475
3568
  } catch {
3476
3569
  }
3477
3570
  const { parseEnvFile } = await import("@vostride/agent-qa-core");
3478
- const { readFileSync: readFileSync5, existsSync: existsSync8 } = await import("fs");
3571
+ const { readFileSync: readFileSync6, existsSync: existsSync9 } = await import("fs");
3479
3572
  const configDir = workspacePaths.configDir;
3480
3573
  const cliVars = parseVarFlags(opts.var);
3481
3574
  const inheritedContextRunId = process.env.AGENT_QA_RUN_ID ?? process.env.AGENT_QA_SUITE_QUEUE_ID ?? process.env.AGENT_QA_PARENT_RUN_ID;
3482
3575
  const inheritedRunAttributes = inheritedContextRunId ? readRunAttributesFromEnv() : void 0;
3483
3576
  let userRunAttributes;
3484
3577
  try {
3485
- const parsedRunAttrs = (0, import_agent_qa_core7.parseRunAttrFlags)(opts.runAttr);
3578
+ const parsedRunAttrs = (0, import_agent_qa_core8.parseRunAttrFlags)(opts.runAttr);
3486
3579
  userRunAttributes = parsedRunAttrs.attributes;
3487
3580
  for (const duplicateKey of parsedRunAttrs.duplicateKeys) {
3488
3581
  console.warn(`Warning: duplicate --run-attr key "${duplicateKey}"; using last value`);
3489
3582
  }
3490
3583
  } catch (err) {
3491
- console.error(import_picocolors7.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3584
+ console.error(import_picocolors8.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3492
3585
  process.exit(2);
3493
3586
  }
3494
3587
  const inlineVars = {};
@@ -3496,37 +3589,37 @@ function createRunCommand() {
3496
3589
  config,
3497
3590
  configDir,
3498
3591
  secretsFilePath: workspacePaths.secretsFile.absolutePath,
3499
- readFileSync: readFileSync5,
3500
- existsSync: existsSync8
3592
+ readFileSync: readFileSync6,
3593
+ existsSync: existsSync9
3501
3594
  });
3502
3595
  let envFileVars = {};
3503
3596
  let rawEnvFileContent = null;
3504
3597
  let resolvedEnvFilePath = null;
3505
3598
  resolvedEnvFilePath = workspacePaths.envFile.absolutePath;
3506
- if (!existsSync8(workspacePaths.envFile.absolutePath)) {
3507
- console.error(import_picocolors7.default.red(`Error: Env file not found: ${workspacePaths.envFile.absolutePath}`));
3599
+ if (!existsSync9(workspacePaths.envFile.absolutePath)) {
3600
+ console.error(import_picocolors8.default.red(`Error: Env file not found: ${workspacePaths.envFile.absolutePath}`));
3508
3601
  process.exit(1);
3509
3602
  }
3510
3603
  try {
3511
- rawEnvFileContent = readFileSync5(workspacePaths.envFile.absolutePath, "utf-8");
3604
+ rawEnvFileContent = readFileSync6(workspacePaths.envFile.absolutePath, "utf-8");
3512
3605
  envFileVars = parseEnvFile(rawEnvFileContent);
3513
3606
  } catch {
3514
- console.error(import_picocolors7.default.red(`Error: Env file could not be read: ${workspacePaths.envFile.absolutePath}`));
3607
+ console.error(import_picocolors8.default.red(`Error: Env file could not be read: ${workspacePaths.envFile.absolutePath}`));
3515
3608
  process.exit(1);
3516
3609
  }
3517
3610
  let resolvedHooks;
3518
3611
  let sandboxOptions;
3519
3612
  const hooksFilePath = workspacePaths.hooksFile.absolutePath;
3520
- if (!existsSync8(hooksFilePath)) {
3521
- console.error(import_picocolors7.default.red(`Error: Hooks file not found: ${hooksFilePath}`));
3613
+ if (!existsSync9(hooksFilePath)) {
3614
+ console.error(import_picocolors8.default.red(`Error: Hooks file not found: ${hooksFilePath}`));
3522
3615
  process.exit(1);
3523
3616
  }
3524
3617
  try {
3525
3618
  const { parseHooksFile } = await import("@vostride/agent-qa-core");
3526
3619
  const { hooks, errors } = await parseHooksFile(hooksFilePath);
3527
3620
  if (errors.length > 0) {
3528
- console.error(import_picocolors7.default.red("Hooks configuration errors:"));
3529
- for (const err of errors) console.error(import_picocolors7.default.red(` - ${err}`));
3621
+ console.error(import_picocolors8.default.red("Hooks configuration errors:"));
3622
+ for (const err of errors) console.error(import_picocolors8.default.red(` - ${err}`));
3530
3623
  process.exit(1);
3531
3624
  }
3532
3625
  resolvedHooks = new Map(hooks.map((h) => [h.id, h]));
@@ -3535,8 +3628,8 @@ function createRunCommand() {
3535
3628
  secretRedactor: runtimeSecrets.secretRedactor
3536
3629
  };
3537
3630
  } catch (err) {
3538
- console.error(import_picocolors7.default.red(`Error: Hooks file could not be read: ${hooksFilePath}`));
3539
- if (err instanceof Error && err.message) console.error(import_picocolors7.default.dim(err.message));
3631
+ console.error(import_picocolors8.default.red(`Error: Hooks file could not be read: ${hooksFilePath}`));
3632
+ if (err instanceof Error && err.message) console.error(import_picocolors8.default.dim(err.message));
3540
3633
  process.exit(1);
3541
3634
  }
3542
3635
  let agentRulesContent;
@@ -3544,7 +3637,7 @@ function createRunCommand() {
3544
3637
  try {
3545
3638
  agentRulesContent = await readFileAsync(workspacePaths.agentRules.absolutePath, "utf-8");
3546
3639
  } catch {
3547
- console.error(import_picocolors7.default.red(`Error: Agent rules file not found: ${workspacePaths.agentRules.absolutePath}`));
3640
+ console.error(import_picocolors8.default.red(`Error: Agent rules file not found: ${workspacePaths.agentRules.absolutePath}`));
3548
3641
  process.exit(1);
3549
3642
  }
3550
3643
  const effectiveLogLevel = globalOpts.logLevel ?? (globalOpts.verbose ? "debug" : void 0) ?? (globalOpts.quiet ? "silent" : void 0) ?? config.services?.logging?.level ?? "warn";
@@ -3556,48 +3649,58 @@ function createRunCommand() {
3556
3649
  discoveredTestFiles = selected.tests;
3557
3650
  discoveredSuiteFiles = selected.suites;
3558
3651
  } catch (err) {
3559
- console.error(import_picocolors7.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3652
+ console.error(import_picocolors8.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3560
3653
  process.exit(1);
3561
3654
  }
3562
3655
  if (discoveredTestFiles.length === 0 && discoveredSuiteFiles.length === 0) {
3563
3656
  const patternKind = patterns.every((pattern) => classifyRunPattern(pattern) === "suite") ? "suite" : "test";
3564
- console.error(import_picocolors7.default.red(`Error: No ${patternKind} files found matching patterns:`));
3565
- for (const p of patterns) console.error(import_picocolors7.default.red(` ${p}`));
3657
+ console.error(import_picocolors8.default.red(`Error: No ${patternKind} files found matching patterns:`));
3658
+ for (const p of patterns) console.error(import_picocolors8.default.red(` ${p}`));
3566
3659
  process.exit(2);
3567
3660
  }
3568
3661
  } else if (opts.suite) {
3569
- discoveredSuiteFiles = (await (0, import_agent_qa_core8.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "suite" })).map((record) => record.absolutePath);
3662
+ discoveredSuiteFiles = (await (0, import_agent_qa_core9.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "suite" })).map((record) => record.absolutePath);
3570
3663
  if (discoveredSuiteFiles.length === 0) {
3571
- console.error(import_picocolors7.default.red("Error: No suite files found matching workspace.suiteMatch"));
3664
+ console.error(import_picocolors8.default.red("Error: No suite files found matching workspace.suiteMatch"));
3572
3665
  for (const p of workspacePaths.suiteMatch) {
3573
- console.error(import_picocolors7.default.red(` ${p}`));
3666
+ console.error(import_picocolors8.default.red(` ${p}`));
3574
3667
  }
3575
3668
  process.exit(2);
3576
3669
  }
3577
3670
  } else if (opts.all) {
3578
- discoveredTestFiles = (await (0, import_agent_qa_core8.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "test" })).map((record) => record.absolutePath);
3579
- discoveredSuiteFiles = (await (0, import_agent_qa_core8.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "suite" })).map((record) => record.absolutePath);
3671
+ discoveredTestFiles = (await (0, import_agent_qa_core9.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "test" })).map((record) => record.absolutePath);
3672
+ discoveredSuiteFiles = (await (0, import_agent_qa_core9.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "suite" })).map((record) => record.absolutePath);
3580
3673
  if (discoveredTestFiles.length === 0 && discoveredSuiteFiles.length === 0) {
3581
- console.error(import_picocolors7.default.red("Error: No test or suite files found. Check workspace.testMatch and workspace.suiteMatch in agent-qa.config.yaml"));
3674
+ console.error(import_picocolors8.default.red("Error: No test or suite files found. Check workspace.testMatch and workspace.suiteMatch in agent-qa.config.yaml"));
3582
3675
  process.exit(2);
3583
3676
  }
3584
3677
  } else {
3585
3678
  if (!workspacePaths.testMatch || workspacePaths.testMatch.length === 0) {
3586
- console.error(import_picocolors7.default.red("Error: No testMatch patterns in config. Add workspace.testMatch to agent-qa.config.yaml."));
3679
+ console.error(import_picocolors8.default.red("Error: No testMatch patterns in config. Add workspace.testMatch to agent-qa.config.yaml."));
3587
3680
  process.exit(2);
3588
3681
  }
3589
- discoveredTestFiles = (await (0, import_agent_qa_core8.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "test" })).map((record) => record.absolutePath);
3682
+ discoveredTestFiles = (await (0, import_agent_qa_core9.discoverWorkspaceFiles)({ workspace: workspacePaths, kind: "test" })).map((record) => record.absolutePath);
3590
3683
  if (discoveredTestFiles.length === 0) {
3591
- console.error(import_picocolors7.default.red("Error: No test files found matching workspace.testMatch"));
3684
+ console.error(import_picocolors8.default.red("Error: No test files found matching workspace.testMatch"));
3592
3685
  for (const p of workspacePaths.testMatch) {
3593
- console.error(import_picocolors7.default.red(` ${p}`));
3686
+ console.error(import_picocolors8.default.red(` ${p}`));
3594
3687
  }
3595
3688
  process.exit(2);
3596
3689
  }
3597
3690
  }
3598
3691
  if (discoveredSuiteFiles.length > 0 && discoveredTestFiles.length === 0) {
3599
3692
  const hasFailed2 = await executeSuites(discoveredSuiteFiles, opts, config, globalOpts, configContent, effectiveLogLevel, { envFileVars, inlineVars, cliVars, rawEnvFileContent, resolvedEnvFilePath, userRunAttributes, inheritedRunAttributes, ...runtimeSecrets }, resolvedHooks && sandboxOptions ? { resolvedHooks, sandboxOptions } : void 0);
3600
- process.exit(hasFailed2 ? 1 : 0);
3693
+ const exitCode2 = hasFailed2 ? 1 : 0;
3694
+ const suiteReporterSelection = resolveReporterSelection(opts, Boolean(config.services?.dashboard)).selection;
3695
+ if (suiteReporterSelection) {
3696
+ await maybePrintPostRunUpdateNotice({
3697
+ reporterSelection: suiteReporterSelection,
3698
+ effectiveLogLevel,
3699
+ liveEvents: process.env.AGENT_QA_LIVE_EVENTS,
3700
+ cwd: process.cwd()
3701
+ });
3702
+ }
3703
+ process.exit(exitCode2);
3601
3704
  }
3602
3705
  let suitesFailed = false;
3603
3706
  if (discoveredSuiteFiles.length > 0 && discoveredTestFiles.length > 0) {
@@ -3605,7 +3708,7 @@ function createRunCommand() {
3605
3708
  }
3606
3709
  const files = discoveredTestFiles;
3607
3710
  if (opts.listTests) {
3608
- console.log(import_picocolors7.default.bold(`
3711
+ console.log(import_picocolors8.default.bold(`
3609
3712
  Discovered ${files.length} test file(s):
3610
3713
  `));
3611
3714
  for (const file of files) {
@@ -3617,7 +3720,7 @@ Discovered ${files.length} test file(s):
3617
3720
  const dashboardCfg2 = config.services?.dashboard;
3618
3721
  const reporterSelectionResult = resolveReporterSelection(opts, Boolean(dashboardCfg2));
3619
3722
  if (reporterSelectionResult.error) {
3620
- console.error(import_picocolors7.default.red(`Error: ${reporterSelectionResult.error}`));
3723
+ console.error(import_picocolors8.default.red(`Error: ${reporterSelectionResult.error}`));
3621
3724
  process.exit(2);
3622
3725
  }
3623
3726
  const reporterSelection = reporterSelectionResult.selection;
@@ -3634,13 +3737,13 @@ Discovered ${files.length} test file(s):
3634
3737
  logStorage = dashboardDb;
3635
3738
  _crashDb = dashboardDb;
3636
3739
  } catch (err) {
3637
- console.warn(import_picocolors7.default.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3740
+ console.warn(import_picocolors8.default.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3638
3741
  }
3639
3742
  }
3640
3743
  const { parseAllTests, formatParseError } = await import("@vostride/agent-qa-core");
3641
3744
  const parseResult = await parseAllTests(files);
3642
3745
  if (parseResult.errors.length > 0) {
3643
- console.error(import_picocolors7.default.red(`Found ${parseResult.errors.length} parse error(s):
3746
+ console.error(import_picocolors8.default.red(`Found ${parseResult.errors.length} parse error(s):
3644
3747
  `));
3645
3748
  for (const err of parseResult.errors) {
3646
3749
  console.error(formatParseError(err));
@@ -3651,8 +3754,8 @@ Discovered ${files.length} test file(s):
3651
3754
  const now = (/* @__PURE__ */ new Date()).toISOString();
3652
3755
  const { basename: basename2 } = await import("path");
3653
3756
  const errorText = parseResult.errors.map((e) => formatParseError(e)).join("\n").replace(/\x1b\[[0-9;]*m/g, "");
3654
- const { readFileSync: readFileSync6 } = await import("fs");
3655
- const rawContent = readFileSync6(files[0], "utf-8");
3757
+ const { readFileSync: readFileSync7 } = await import("fs");
3758
+ const rawContent = readFileSync7(files[0], "utf-8");
3656
3759
  const nameMatch = rawContent.match(/^\s*name:\s*(.+)$/m);
3657
3760
  const targetMatch = rawContent.match(/^\s*target:\s*(.+)$/m);
3658
3761
  let detectedPlatform = "web";
@@ -3694,7 +3797,7 @@ Discovered ${files.length} test file(s):
3694
3797
  dashboardDb.insertRunArtifact({
3695
3798
  runId: artifactRunId,
3696
3799
  kind: "test",
3697
- payload: (0, import_agent_qa_core7.redactAuthStateValue)({
3800
+ payload: (0, import_agent_qa_core8.redactAuthStateValue)({
3698
3801
  config: {
3699
3802
  rawConfigContent: configContent,
3700
3803
  parsedConfig: config,
@@ -3736,17 +3839,17 @@ Discovered ${files.length} test file(s):
3736
3839
  }
3737
3840
  const filtered = parseResult.tests;
3738
3841
  if (filtered.length === 0) {
3739
- console.log(import_picocolors7.default.yellow("No tests match filters"));
3842
+ console.log(import_picocolors8.default.yellow("No tests match filters"));
3740
3843
  process.exit(0);
3741
3844
  }
3742
3845
  if (opts.dryRun) {
3743
- console.log(import_picocolors7.default.bold(`
3846
+ console.log(import_picocolors8.default.bold(`
3744
3847
  Found ${filtered.length} test(s):
3745
3848
  `));
3746
3849
  for (const test of filtered) {
3747
- console.log(` ${import_picocolors7.default.green("\u25CF")} ${test.name}`);
3850
+ console.log(` ${import_picocolors8.default.green("\u25CF")} ${test.name}`);
3748
3851
  if (opts.configDebug) {
3749
- console.log(import_picocolors7.default.bold(`
3852
+ console.log(import_picocolors8.default.bold(`
3750
3853
  Config for: ${test.name}`));
3751
3854
  console.log(formatConfigDebug(config, test.use, flagOverrides));
3752
3855
  console.log();
@@ -3796,7 +3899,7 @@ Found ${filtered.length} test(s):
3796
3899
  }
3797
3900
  }));
3798
3901
  } catch (err) {
3799
- console.warn(import_picocolors7.default.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3902
+ console.warn(import_picocolors8.default.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3800
3903
  }
3801
3904
  }
3802
3905
  const analyticsReporter = createAnalyticsRunReporter({ config, surface: "cli" });
@@ -3825,7 +3928,7 @@ Found ${filtered.length} test(s):
3825
3928
  let circuitBreaker;
3826
3929
  let circuitBreakerTripped = false;
3827
3930
  const memoryGlobalConfig = config.services?.memory;
3828
- const runtimeMemoryRoot = (0, import_agent_qa_core7.resolveMemoryRoot)(config, configDir);
3931
+ const runtimeMemoryRoot = (0, import_agent_qa_core8.resolveMemoryRoot)(config, configDir);
3829
3932
  if (opts.memory !== false && memoryGlobalConfig?.circuitBreakerEnabled !== false && memoryGlobalConfig?.enabled !== false) {
3830
3933
  const { CircuitBreaker } = await import("@vostride/agent-qa-core");
3831
3934
  circuitBreaker = new CircuitBreaker({
@@ -3865,7 +3968,7 @@ Found ${filtered.length} test(s):
3865
3968
  (f) => parseResult.tests.some((t) => t.name === test.name)
3866
3969
  ) ?? "unknown";
3867
3970
  analyticsFilePath = filePath;
3868
- const runId = process.env.AGENT_QA_RUN_ID ?? (0, import_agent_qa_core7.generateRunId)();
3971
+ const runId = process.env.AGENT_QA_RUN_ID ?? (0, import_agent_qa_core8.generateRunId)();
3869
3972
  analyticsRunId = runId;
3870
3973
  analyticsStartedAt = Date.now();
3871
3974
  currentRunId = runId;
@@ -3890,7 +3993,7 @@ Found ${filtered.length} test(s):
3890
3993
  const testMergedConfig = { ...config, use: mergedUse };
3891
3994
  const effectiveCacheEnabled = opts.cache !== false && mergedUse.cache !== false;
3892
3995
  if (opts.configDebug) {
3893
- console.log(import_picocolors7.default.bold(`
3996
+ console.log(import_picocolors8.default.bold(`
3894
3997
  Config for: ${test.name}`));
3895
3998
  console.log(formatConfigDebug(config, test.use, testFlagOverrides));
3896
3999
  console.log();
@@ -3931,7 +4034,7 @@ Config for: ${test.name}`));
3931
4034
  useDeviceName: testMergedUse.device,
3932
4035
  appState: testMergedUse.mobile?.appState,
3933
4036
  localBindings: testLocalBindings,
3934
- configFilePath: (0, import_node_path9.resolve)(configFilePath),
4037
+ configFilePath: (0, import_node_path10.resolve)(configFilePath),
3935
4038
  localConfigFilePath: testLocalBindings?.filePath,
3936
4039
  appiumUrl: process.env.AGENT_QA_APPIUM_URL
3937
4040
  });
@@ -3977,7 +4080,7 @@ Config for: ${test.name}`));
3977
4080
  testMobileResolved = { ...testMobileResolved, appium: { url: appiumUrl, managed: !process.env.AGENT_QA_APPIUM_URL } };
3978
4081
  }
3979
4082
  } catch (err) {
3980
- throw new import_agent_qa_core7.MobileSetupError({
4083
+ throw new import_agent_qa_core8.MobileSetupError({
3981
4084
  category: "appium-startup",
3982
4085
  message: `Could not auto-start Appium: ${err instanceof Error ? err.message : String(err)}`,
3983
4086
  platform: testPlatform,
@@ -4015,7 +4118,7 @@ Config for: ${test.name}`));
4015
4118
  });
4016
4119
  }
4017
4120
  if (effectiveLogLevel === "debug") {
4018
- console.log(import_picocolors7.default.dim(` Platform: ${testPlatform}${useFarm ? ` (farm: ${testResolvedDevice?.transport})` : ""}${testPlatform !== "web" ? " (adapter re-created)" : ""}`));
4121
+ console.log(import_picocolors8.default.dim(` Platform: ${testPlatform}${useFarm ? ` (farm: ${testResolvedDevice?.transport})` : ""}${testPlatform !== "web" ? " (adapter re-created)" : ""}`));
4019
4122
  }
4020
4123
  }
4021
4124
  const mergedForLLM = { registry: config.registry, use: testMergedConfig.use ?? config.use };
@@ -4026,7 +4129,7 @@ Config for: ${test.name}`));
4026
4129
  process.env.AGENT_QA_LLM_MODEL = plannerCfg.model;
4027
4130
  process.env.AGENT_QA_LLM_PROVIDER = plannerCfg.provider;
4028
4131
  if (effectiveLogLevel === "debug") {
4029
- console.log(import_picocolors7.default.dim(` Model: ${plannerCfg.model} (${plannerCfg.provider})`));
4132
+ console.log(import_picocolors8.default.dim(` Model: ${plannerCfg.model} (${plannerCfg.provider})`));
4030
4133
  }
4031
4134
  const plannerModel = await createModel(plannerModelConfig);
4032
4135
  const verifierModel = await createModel(verifierModelConfig);
@@ -4193,7 +4296,7 @@ Config for: ${test.name}`));
4193
4296
  const testId = testDef["test-id"] ?? testDef.name;
4194
4297
  memoryInitParams = { product, testId, memoryRoot };
4195
4298
  } catch (err) {
4196
- console.warn(` ${import_picocolors7.default.dim("Memory:")} init error -- ${err.message}`);
4299
+ console.warn(` ${import_picocolors8.default.dim("Memory:")} init error -- ${err.message}`);
4197
4300
  }
4198
4301
  }
4199
4302
  const result = await runTestWithRetry(testDef, {
@@ -4307,7 +4410,7 @@ Config for: ${test.name}`));
4307
4410
  try {
4308
4411
  const { shouldAblate, collectAllInjectedIds, deprecateOnFailure } = await import("@vostride/agent-qa-core");
4309
4412
  if (shouldAblate(result, memoryProvider)) {
4310
- console.log(` ${import_picocolors7.default.dim("Memory:")} ablation retry -- re-running without memory...`);
4413
+ console.log(` ${import_picocolors8.default.dim("Memory:")} ablation retry -- re-running without memory...`);
4311
4414
  const ablationAdapter = await createPlatformAdapter(testPlatform);
4312
4415
  const mergedBrowser = mergedUse.browser;
4313
4416
  const ablationPlatformConfig = buildPlatformConfig(testPlatform, testResolvedDevice, testTimeoutsForSetup, mergedBrowser ?? config.use?.browser, testMergedConfig.use?.logCapture ?? config.use?.logCapture, testFarmSession, testMobileResolved);
@@ -4355,7 +4458,7 @@ Config for: ${test.name}`));
4355
4458
  circuitBreaker.record({ withMemory: false, passed: ablationResult.status === "passed" });
4356
4459
  }
4357
4460
  if (ablationResult.status === "passed") {
4358
- console.log(` ${import_picocolors7.default.dim("Memory:")} ablation confirmed memory caused failure -- penalizing observations`);
4461
+ console.log(` ${import_picocolors8.default.dim("Memory:")} ablation confirmed memory caused failure -- penalizing observations`);
4359
4462
  const injectedMap = collectAllInjectedIds(result, memoryProvider);
4360
4463
  await deprecateOnFailure({
4361
4464
  testResult: result,
@@ -4366,14 +4469,14 @@ Config for: ${test.name}`));
4366
4469
  });
4367
4470
  ablationHandledDeprecation = true;
4368
4471
  } else {
4369
- console.log(` ${import_picocolors7.default.dim("Memory:")} ablation retry also failed -- memory not the cause`);
4472
+ console.log(` ${import_picocolors8.default.dim("Memory:")} ablation retry also failed -- memory not the cause`);
4370
4473
  }
4371
4474
  } finally {
4372
4475
  await ablationAdapter.cleanup();
4373
4476
  }
4374
4477
  }
4375
4478
  } catch (err) {
4376
- console.warn(` ${import_picocolors7.default.dim("Memory:")} ablation error -- ${err.message}`);
4479
+ console.warn(` ${import_picocolors8.default.dim("Memory:")} ablation error -- ${err.message}`);
4377
4480
  }
4378
4481
  }
4379
4482
  if (memoryProvider && memoryConfig?.curatorEnabled !== false && !ablationHandledDeprecation) {
@@ -4407,7 +4510,7 @@ Config for: ${test.name}`));
4407
4510
  }
4408
4511
  }
4409
4512
  } catch (err) {
4410
- console.warn(` ${import_picocolors7.default.dim("Memory:")} curator error -- ${err.message}`);
4513
+ console.warn(` ${import_picocolors8.default.dim("Memory:")} curator error -- ${err.message}`);
4411
4514
  }
4412
4515
  }
4413
4516
  if (testAuthStateUse?.capture === true) {
@@ -4421,12 +4524,12 @@ Config for: ${test.name}`));
4421
4524
  }
4422
4525
  if (circuitBreaker?.isTripped() && !circuitBreakerTripped) {
4423
4526
  circuitBreakerTripped = true;
4424
- console.log(` ${import_picocolors7.default.yellow("Memory: circuit breaker tripped -- disabling memory injection for remaining tests")}`);
4527
+ console.log(` ${import_picocolors8.default.yellow("Memory: circuit breaker tripped -- disabling memory injection for remaining tests")}`);
4425
4528
  }
4426
4529
  if (result.status === "failed" && !authStateCaptureFailed && actionCache && effectiveCacheEnabled && result.steps.length > 0) {
4427
4530
  const { hashStepInstruction: hashStepInstruction2 } = await import("@vostride/agent-qa-core");
4428
4531
  const { rm: rm3 } = await import("fs/promises");
4429
- const { resolve: resolve9, join: join8 } = await import("path");
4532
+ const { resolve: resolve9, join: join9 } = await import("path");
4430
4533
  const cacheDir = resolve9(configDir, config.services?.cache?.dir ?? RUNTIME_CACHE_DIR);
4431
4534
  const cacheLog = logger.createScopedLogger("cache");
4432
4535
  let purged = 0;
@@ -4434,7 +4537,7 @@ Config for: ${test.name}`));
4434
4537
  const step = result.steps[i];
4435
4538
  const stepHash = hashStepInstruction2(step.name, testPlatform, configContent, testFileContent, i);
4436
4539
  try {
4437
- await rm3(join8(cacheDir, stepHash), { recursive: true, force: true });
4540
+ await rm3(join9(cacheDir, stepHash), { recursive: true, force: true });
4438
4541
  purged++;
4439
4542
  } catch {
4440
4543
  }
@@ -4506,13 +4609,13 @@ Config for: ${test.name}`));
4506
4609
  }
4507
4610
  const parallelBatchFailed = await flushParallelRuns();
4508
4611
  if (opts.bail && parallelBatchFailed) {
4509
- console.log(import_picocolors7.default.yellow("\nBailing out \u2014 stopping after first failure"));
4612
+ console.log(import_picocolors8.default.yellow("\nBailing out \u2014 stopping after first failure"));
4510
4613
  bailTriggered = true;
4511
4614
  break;
4512
4615
  }
4513
4616
  const outcome = await runOneDirectTest(test);
4514
4617
  if (opts.bail && outcome.failed) {
4515
- console.log(import_picocolors7.default.yellow("\nBailing out \u2014 stopping after first failure"));
4618
+ console.log(import_picocolors8.default.yellow("\nBailing out \u2014 stopping after first failure"));
4516
4619
  bailTriggered = true;
4517
4620
  break;
4518
4621
  }
@@ -4520,7 +4623,7 @@ Config for: ${test.name}`));
4520
4623
  if (!bailTriggered) {
4521
4624
  const parallelBatchFailed = await flushParallelRuns();
4522
4625
  if (opts.bail && parallelBatchFailed) {
4523
- console.log(import_picocolors7.default.yellow("\nBailing out \u2014 stopping after first failure"));
4626
+ console.log(import_picocolors8.default.yellow("\nBailing out \u2014 stopping after first failure"));
4524
4627
  }
4525
4628
  }
4526
4629
  releaseAppium();
@@ -4534,12 +4637,19 @@ Config for: ${test.name}`));
4534
4637
  dashboardDb.close();
4535
4638
  }
4536
4639
  const hasFailed = results.some((r) => r.status === "failed") || suitesFailed;
4537
- process.exit(hasFailed ? 1 : 0);
4640
+ const exitCode = hasFailed ? 1 : 0;
4641
+ await maybePrintPostRunUpdateNotice({
4642
+ reporterSelection,
4643
+ effectiveLogLevel,
4644
+ liveEvents: process.env.AGENT_QA_LIVE_EVENTS,
4645
+ cwd: process.cwd()
4646
+ });
4647
+ process.exit(exitCode);
4538
4648
  } catch (err) {
4539
4649
  const errMsg = err instanceof Error ? err.message : String(err);
4540
4650
  const errStack = err instanceof Error ? err.stack ?? "" : "";
4541
4651
  const formattedError = formatFrameworkError(errMsg);
4542
- console.error(import_picocolors7.default.red(formattedError.displayMessage));
4652
+ console.error(import_picocolors8.default.red(formattedError.displayMessage));
4543
4653
  if (_crashDb) {
4544
4654
  const fullError = `${errMsg}
4545
4655
  ${errStack}`;
@@ -4554,7 +4664,7 @@ ${errStack}`;
4554
4664
  status: finalStatus,
4555
4665
  duration: run.startedAt ? Date.now() - new Date(run.startedAt).getTime() : 0,
4556
4666
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
4557
- failureSummary: isBrowserClose ? "Browser closed by user" : (0, import_agent_qa_core7.redactAuthStateValue)(formattedError.failureSummary)
4667
+ failureSummary: isBrowserClose ? "Browser closed by user" : (0, import_agent_qa_core8.redactAuthStateValue)(formattedError.failureSummary)
4558
4668
  });
4559
4669
  try {
4560
4670
  const artifact = _crashDb.getRunArtifact(run.id);
@@ -4567,7 +4677,7 @@ ${errStack}`;
4567
4677
  errors: [{
4568
4678
  code: isBrowserClose ? "browser-disconnect" : "process-close",
4569
4679
  phase: "process-close",
4570
- message: isBrowserClose ? "Browser closed by user" : (0, import_agent_qa_core7.redactAuthStateValue)(formattedError.failureSummary)
4680
+ message: isBrowserClose ? "Browser closed by user" : (0, import_agent_qa_core8.redactAuthStateValue)(formattedError.failureSummary)
4571
4681
  }]
4572
4682
  });
4573
4683
  }
@@ -4591,10 +4701,10 @@ ${errStack}`;
4591
4701
 
4592
4702
  // src/commands/dashboard.ts
4593
4703
  var import_commander7 = require("commander");
4594
- var import_node_path10 = require("path");
4704
+ var import_node_path11 = require("path");
4595
4705
  var import_node_module2 = require("module");
4596
- var import_picocolors8 = __toESM(require("picocolors"), 1);
4597
- var import_agent_qa_core10 = require("@vostride/agent-qa-core");
4706
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
4707
+ var import_agent_qa_core11 = require("@vostride/agent-qa-core");
4598
4708
  init_config();
4599
4709
  init_llm_utils();
4600
4710
  init_model_defaults();
@@ -4606,9 +4716,9 @@ async function startDashboardBackedServices(opts, command, labels) {
4606
4716
  const config = await resolveConfig({
4607
4717
  configPath: globalOpts.config
4608
4718
  });
4609
- const configFilePath = (0, import_node_path10.resolve)(globalOpts.config ?? "agent-qa.config.yaml");
4610
- const configDir = (0, import_node_path10.dirname)(configFilePath);
4611
- const workspacePaths = (0, import_agent_qa_core10.resolveWorkspacePaths)({
4719
+ const configFilePath = (0, import_node_path11.resolve)(globalOpts.config ?? "agent-qa.config.yaml");
4720
+ const configDir = (0, import_node_path11.dirname)(configFilePath);
4721
+ const workspacePaths = (0, import_agent_qa_core11.resolveWorkspacePaths)({
4612
4722
  config,
4613
4723
  configPath: configFilePath,
4614
4724
  requireExistingFiles: true
@@ -4647,17 +4757,17 @@ async function startDashboardBackedServices(opts, command, labels) {
4647
4757
  try {
4648
4758
  const require2 = (0, import_node_module2.createRequire)(import_meta3.url);
4649
4759
  const pkgPath = require2.resolve("@vostride/agent-qa-dashboard-ui/package.json");
4650
- uiDir = (0, import_node_path10.resolve)((0, import_node_path10.dirname)(pkgPath), "dist");
4760
+ uiDir = (0, import_node_path11.resolve)((0, import_node_path11.dirname)(pkgPath), "dist");
4651
4761
  } catch {
4652
4762
  if (globalOpts.verbose) {
4653
- console.log(import_picocolors8.default.yellow("Warning: @vostride/agent-qa-dashboard-ui not found \u2014 API-only mode"));
4763
+ console.log(import_picocolors9.default.yellow("Warning: @vostride/agent-qa-dashboard-ui not found \u2014 API-only mode"));
4654
4764
  }
4655
4765
  }
4656
4766
  const { close } = await startServer({
4657
4767
  db,
4658
4768
  port,
4659
4769
  uiDir,
4660
- artifactsDir: (0, import_node_path10.resolve)(configDir, artifactsDir),
4770
+ artifactsDir: (0, import_node_path11.resolve)(configDir, artifactsDir),
4661
4771
  workspacePaths,
4662
4772
  configPath: configFilePath,
4663
4773
  mcp: mcpConfig,
@@ -4673,17 +4783,17 @@ async function startDashboardBackedServices(opts, command, labels) {
4673
4783
  const shutdown = async () => {
4674
4784
  if (shuttingDown) return;
4675
4785
  shuttingDown = true;
4676
- console.log(import_picocolors8.default.dim(`
4786
+ console.log(import_picocolors9.default.dim(`
4677
4787
  Shutting down ${labels.shutdown}...`));
4678
4788
  close();
4679
- await (0, import_agent_qa_core10.flushAnalytics)({ config }).catch(() => {
4789
+ await (0, import_agent_qa_core11.flushAnalytics)({ config }).catch(() => {
4680
4790
  });
4681
4791
  process.exit(0);
4682
4792
  };
4683
4793
  process.on("SIGINT", shutdown);
4684
4794
  process.on("SIGTERM", shutdown);
4685
4795
  } catch (err) {
4686
- console.error(import_picocolors8.default.red(`${labels.error} error: ${err instanceof Error ? err.message : String(err)}`));
4796
+ console.error(import_picocolors9.default.red(`${labels.error} error: ${err instanceof Error ? err.message : String(err)}`));
4687
4797
  process.exit(2);
4688
4798
  }
4689
4799
  }
@@ -4708,8 +4818,8 @@ function createServeCommand() {
4708
4818
 
4709
4819
  // src/commands/mcp.ts
4710
4820
  var import_commander8 = require("commander");
4711
- var import_picocolors9 = __toESM(require("picocolors"), 1);
4712
- var import_agent_qa_core11 = require("@vostride/agent-qa-core");
4821
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
4822
+ var import_agent_qa_core12 = require("@vostride/agent-qa-core");
4713
4823
  init_config();
4714
4824
  function createMcpCommand() {
4715
4825
  const cmd = new import_commander8.Command("mcp").description("Start MCP (Model Context Protocol) server over stdio").action(async (command) => {
@@ -4727,11 +4837,11 @@ function createMcpCommand() {
4727
4837
  const startupOptions = { analyticsConfig: config, startupOutput: process.stderr };
4728
4838
  await startMcpServer(startupOptions);
4729
4839
  } finally {
4730
- await (0, import_agent_qa_core11.flushAnalytics)(config ? { config } : void 0).catch(() => {
4840
+ await (0, import_agent_qa_core12.flushAnalytics)(config ? { config } : void 0).catch(() => {
4731
4841
  });
4732
4842
  }
4733
4843
  } catch (err) {
4734
- console.error(import_picocolors9.default.red("Failed to start MCP server:"), err instanceof Error ? err.message : String(err));
4844
+ console.error(import_picocolors10.default.red("Failed to start MCP server:"), err instanceof Error ? err.message : String(err));
4735
4845
  process.exitCode = 1;
4736
4846
  }
4737
4847
  });
@@ -4740,7 +4850,7 @@ function createMcpCommand() {
4740
4850
 
4741
4851
  // src/commands/config.ts
4742
4852
  var import_commander9 = require("commander");
4743
- var import_picocolors10 = __toESM(require("picocolors"), 1);
4853
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
4744
4854
  var import_yaml5 = require("yaml");
4745
4855
  var import_promises3 = require("fs/promises");
4746
4856
  var import_node_readline2 = require("readline");
@@ -4786,14 +4896,14 @@ async function getValue(key, providedValue) {
4786
4896
  }
4787
4897
  async function setAction(key, value) {
4788
4898
  if (isSensitiveKey(key)) {
4789
- console.error(import_picocolors10.default.red("Credential values are not written by config set."));
4899
+ console.error(import_picocolors11.default.red("Credential values are not written by config set."));
4790
4900
  console.error("Use agent-qa auth set --config <name> --type api-key|bearer-token for compatible or Gemini configs.");
4791
4901
  console.error("Use plugins.auth plus the dashboard auth flow for subscription configs.");
4792
4902
  return;
4793
4903
  }
4794
4904
  const resolved = await getValue(key, value);
4795
4905
  if (!resolved) {
4796
- console.error(import_picocolors10.default.red("No value provided."));
4906
+ console.error(import_picocolors11.default.red("No value provided."));
4797
4907
  return;
4798
4908
  }
4799
4909
  const configPath = "agent-qa.config.yaml";
@@ -4810,7 +4920,7 @@ async function setAction(key, value) {
4810
4920
  }
4811
4921
  doc.setIn(key.split("."), resolved);
4812
4922
  await (0, import_promises3.writeFile)(configPath, doc.toString());
4813
- console.log(import_picocolors10.default.green(`\u2713 ${key} = ${resolved} saved to agent-qa.config.yaml`));
4923
+ console.log(import_picocolors11.default.green(`\u2713 ${key} = ${resolved} saved to agent-qa.config.yaml`));
4814
4924
  }
4815
4925
  async function showAction() {
4816
4926
  const fileConfig = await loadConfigFile("agent-qa.config.yaml");
@@ -4818,7 +4928,7 @@ async function showAction() {
4818
4928
  const { mergeConfigs: mergeConfigs2 } = await Promise.resolve().then(() => (init_config(), config_exports));
4819
4929
  const globalConfig = mergeConfigs2(fileConfig, envOverrides, {});
4820
4930
  const table = formatConfigDebug(globalConfig, {}, {});
4821
- console.log(import_picocolors10.default.bold("\nResolved Configuration:\n"));
4931
+ console.log(import_picocolors11.default.bold("\nResolved Configuration:\n"));
4822
4932
  console.log(table);
4823
4933
  console.log();
4824
4934
  }
@@ -4831,7 +4941,7 @@ function createConfigCommand() {
4831
4941
 
4832
4942
  // src/commands/queue.ts
4833
4943
  var import_commander10 = require("commander");
4834
- var import_picocolors11 = __toESM(require("picocolors"), 1);
4944
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
4835
4945
  init_config();
4836
4946
  function timeAgo(dateStr) {
4837
4947
  const diff = Date.now() - new Date(dateStr).getTime();
@@ -4866,13 +4976,13 @@ function createQueueCommand() {
4866
4976
  try {
4867
4977
  const response = await fetch(endpoint);
4868
4978
  if (!response.ok) {
4869
- console.error(import_picocolors11.default.red(`Server returned ${response.status}: ${response.statusText}`));
4979
+ console.error(import_picocolors12.default.red(`Server returned ${response.status}: ${response.statusText}`));
4870
4980
  process.exit(1);
4871
4981
  }
4872
4982
  data = await response.json();
4873
4983
  } catch {
4874
- console.error(import_picocolors11.default.red(`Could not connect to dashboard server at ${serverUrl}`));
4875
- console.error(import_picocolors11.default.dim("Make sure the dashboard is running: agent-qa dashboard"));
4984
+ console.error(import_picocolors12.default.red(`Could not connect to dashboard server at ${serverUrl}`));
4985
+ console.error(import_picocolors12.default.dim("Make sure the dashboard is running: agent-qa dashboard"));
4876
4986
  process.exit(1);
4877
4987
  }
4878
4988
  if (opts.json) {
@@ -4880,19 +4990,19 @@ function createQueueCommand() {
4880
4990
  return;
4881
4991
  }
4882
4992
  console.log();
4883
- console.log(import_picocolors11.default.bold("Queue Status"));
4884
- console.log(` Concurrency: ${import_picocolors11.default.blue(String(data.concurrency))} slots (${import_picocolors11.default.yellow(String(data.activeSlots))} active)`);
4993
+ console.log(import_picocolors12.default.bold("Queue Status"));
4994
+ console.log(` Concurrency: ${import_picocolors12.default.blue(String(data.concurrency))} slots (${import_picocolors12.default.yellow(String(data.activeSlots))} active)`);
4885
4995
  console.log();
4886
4996
  const pending = data.pending?.jobs ?? [];
4887
4997
  const running = data.running?.jobs ?? [];
4888
4998
  if (pending.length === 0 && running.length === 0) {
4889
- console.log(import_picocolors11.default.dim(" Queue is empty \u2014 no pending or running jobs"));
4999
+ console.log(import_picocolors12.default.dim(" Queue is empty \u2014 no pending or running jobs"));
4890
5000
  console.log();
4891
5001
  return;
4892
5002
  }
4893
5003
  if (pending.length > 0) {
4894
- console.log(import_picocolors11.default.bold(`Pending (${pending.length} jobs):`));
4895
- console.log(import_picocolors11.default.dim(" # ID Name Priority Source Queued"));
5004
+ console.log(import_picocolors12.default.bold(`Pending (${pending.length} jobs):`));
5005
+ console.log(import_picocolors12.default.dim(" # ID Name Priority Source Queued"));
4896
5006
  for (let i = 0; i < pending.length; i++) {
4897
5007
  const job = pending[i];
4898
5008
  const num = String(i + 1).padEnd(3);
@@ -4901,37 +5011,37 @@ function createQueueCommand() {
4901
5011
  const priority = String(job.priority ?? 0).padEnd(8);
4902
5012
  const source = (job.source ?? "").padEnd(10);
4903
5013
  const queued = job.createdAt ? timeAgo(job.createdAt) : "";
4904
- console.log(` ${num} ${import_picocolors11.default.dim(id)} ${name} ${priority} ${source} ${import_picocolors11.default.dim(queued)}`);
5014
+ console.log(` ${num} ${import_picocolors12.default.dim(id)} ${name} ${priority} ${source} ${import_picocolors12.default.dim(queued)}`);
4905
5015
  }
4906
5016
  console.log();
4907
5017
  }
4908
5018
  if (running.length > 0) {
4909
- console.log(import_picocolors11.default.bold(`Running (${running.length} jobs):`));
4910
- console.log(import_picocolors11.default.dim(" ID Name Source Started"));
5019
+ console.log(import_picocolors12.default.bold(`Running (${running.length} jobs):`));
5020
+ console.log(import_picocolors12.default.dim(" ID Name Source Started"));
4911
5021
  for (const job of running) {
4912
5022
  const id = (job.id ?? "").slice(0, 12).padEnd(12);
4913
5023
  const name = (job.name ?? "").slice(0, 18).padEnd(18);
4914
5024
  const source = (job.source ?? "").padEnd(10);
4915
5025
  const started = job.startedAt ? timeAgo(job.startedAt) : "";
4916
- console.log(` ${import_picocolors11.default.green(id)} ${name} ${source} ${import_picocolors11.default.dim(started)}`);
5026
+ console.log(` ${import_picocolors12.default.green(id)} ${name} ${source} ${import_picocolors12.default.dim(started)}`);
4917
5027
  }
4918
5028
  console.log();
4919
5029
  }
4920
5030
  if (opts.all && data.recent?.length > 0) {
4921
- console.log(import_picocolors11.default.bold(`Recent (${data.recent.length} jobs):`));
4922
- console.log(import_picocolors11.default.dim(" ID Name Status Duration"));
5031
+ console.log(import_picocolors12.default.bold(`Recent (${data.recent.length} jobs):`));
5032
+ console.log(import_picocolors12.default.dim(" ID Name Status Duration"));
4923
5033
  for (const job of data.recent) {
4924
5034
  const id = (job.id ?? "").slice(0, 12).padEnd(12);
4925
5035
  const name = (job.name ?? "").slice(0, 18).padEnd(18);
4926
5036
  const status = (job.status ?? "").padEnd(8);
4927
5037
  const duration = job.duration ? `${Math.round(job.duration / 1e3)}s` : "";
4928
- const statusColor = job.status === "passed" ? import_picocolors11.default.green : job.status === "failed" ? import_picocolors11.default.red : import_picocolors11.default.dim;
4929
- console.log(` ${import_picocolors11.default.dim(id)} ${name} ${statusColor(status)} ${import_picocolors11.default.dim(duration)}`);
5038
+ const statusColor = job.status === "passed" ? import_picocolors12.default.green : job.status === "failed" ? import_picocolors12.default.red : import_picocolors12.default.dim;
5039
+ console.log(` ${import_picocolors12.default.dim(id)} ${name} ${statusColor(status)} ${import_picocolors12.default.dim(duration)}`);
4930
5040
  }
4931
5041
  console.log();
4932
5042
  }
4933
5043
  } catch (err) {
4934
- console.error(import_picocolors11.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
5044
+ console.error(import_picocolors12.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
4935
5045
  process.exit(1);
4936
5046
  }
4937
5047
  });
@@ -4944,25 +5054,25 @@ function createQueueCommand() {
4944
5054
  try {
4945
5055
  response = await fetch(`${serverUrl}/api/runs/${runId}/cancel`, { method: "POST" });
4946
5056
  } catch {
4947
- console.error(import_picocolors11.default.red(`Could not connect to dashboard server at ${serverUrl}`));
4948
- console.error(import_picocolors11.default.dim("Make sure the dashboard is running: agent-qa dashboard"));
5057
+ console.error(import_picocolors12.default.red(`Could not connect to dashboard server at ${serverUrl}`));
5058
+ console.error(import_picocolors12.default.dim("Make sure the dashboard is running: agent-qa dashboard"));
4949
5059
  process.exit(1);
4950
5060
  }
4951
5061
  if (response.ok) {
4952
5062
  const data = await response.json();
4953
5063
  if (data.cancelled) {
4954
- console.log(import_picocolors11.default.green(`\u2713 Cancelled job ${runId}`));
5064
+ console.log(import_picocolors12.default.green(`\u2713 Cancelled job ${runId}`));
4955
5065
  } else {
4956
- console.log(import_picocolors11.default.red(`Failed to cancel: ${data.error ?? "Unknown error"}`));
5066
+ console.log(import_picocolors12.default.red(`Failed to cancel: ${data.error ?? "Unknown error"}`));
4957
5067
  }
4958
5068
  } else if (response.status === 404) {
4959
- console.log(import_picocolors11.default.red(`Job not found: ${runId}`));
5069
+ console.log(import_picocolors12.default.red(`Job not found: ${runId}`));
4960
5070
  } else {
4961
5071
  const data = await response.json().catch(() => ({}));
4962
- console.log(import_picocolors11.default.red(`Failed to cancel: ${data.error ?? response.statusText}`));
5072
+ console.log(import_picocolors12.default.red(`Failed to cancel: ${data.error ?? response.statusText}`));
4963
5073
  }
4964
5074
  } catch (err) {
4965
- console.error(import_picocolors11.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
5075
+ console.error(import_picocolors12.default.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
4966
5076
  process.exit(1);
4967
5077
  }
4968
5078
  });
@@ -4971,7 +5081,7 @@ function createQueueCommand() {
4971
5081
 
4972
5082
  // src/commands/validate.ts
4973
5083
  var import_commander11 = require("commander");
4974
- var import_agent_qa_core12 = require("@vostride/agent-qa-core");
5084
+ var import_agent_qa_core13 = require("@vostride/agent-qa-core");
4975
5085
  init_config();
4976
5086
  function createValidateCommand() {
4977
5087
  const cmd = new import_commander11.Command("validate").description("Validate config, test files, and suite references").argument("[files...]", "specific files to validate (default: auto-discover all)").action(async (files, command) => {
@@ -4979,15 +5089,15 @@ function createValidateCommand() {
4979
5089
  let workspace;
4980
5090
  try {
4981
5091
  const config = await resolveConfig({ configPath });
4982
- workspace = (0, import_agent_qa_core12.resolveWorkspacePaths)({ config, configPath });
5092
+ workspace = (0, import_agent_qa_core13.resolveWorkspacePaths)({ config, configPath });
4983
5093
  } catch {
4984
5094
  }
4985
- const result = await (0, import_agent_qa_core12.validateProject)({
5095
+ const result = await (0, import_agent_qa_core13.validateProject)({
4986
5096
  configPath,
4987
5097
  files: files.length > 0 ? files : void 0,
4988
5098
  workspace
4989
5099
  });
4990
- const output = (0, import_agent_qa_core12.formatDiagnostics)(result);
5100
+ const output = (0, import_agent_qa_core13.formatDiagnostics)(result);
4991
5101
  process.stdout.write(output);
4992
5102
  if (result.errorCount > 0) {
4993
5103
  process.exitCode = 1;
@@ -4999,7 +5109,7 @@ function createValidateCommand() {
4999
5109
  // src/commands/auth.ts
5000
5110
  var import_commander12 = require("commander");
5001
5111
  var import_node_child_process4 = require("child_process");
5002
- var import_picocolors12 = __toESM(require("picocolors"), 1);
5112
+ var import_picocolors13 = __toESM(require("picocolors"), 1);
5003
5113
  var import_input2 = __toESM(require("@inquirer/input"), 1);
5004
5114
  var import_password = __toESM(require("@inquirer/password"), 1);
5005
5115
  var PROVIDER_LABELS = {
@@ -5034,10 +5144,10 @@ function getGlobalConfigPath2(command) {
5034
5144
  return command.parent?.parent?.opts().config ?? command.parent?.opts().config;
5035
5145
  }
5036
5146
  function printCredentialGuidance(configName, provider) {
5037
- console.log(import_picocolors12.default.red(`Config ${configName} uses ${providerLabel(provider)} credentials.`));
5038
- console.log(import_picocolors12.default.dim("Use agent-qa auth set --config <name> --type api-key"));
5147
+ console.log(import_picocolors13.default.red(`Config ${configName} uses ${providerLabel(provider)} credentials.`));
5148
+ console.log(import_picocolors13.default.dim("Use agent-qa auth set --config <name> --type api-key"));
5039
5149
  if (provider === "anthropic-compatible") {
5040
- console.log(import_picocolors12.default.dim("or --type bearer-token"));
5150
+ console.log(import_picocolors13.default.dim("or --type bearer-token"));
5041
5151
  }
5042
5152
  }
5043
5153
  function applyAuthToModelConfig(llmConfig, auth) {
@@ -5057,15 +5167,15 @@ function applyAuthToModelConfig(llmConfig, auth) {
5057
5167
  function statusForResolvedAuth(auth) {
5058
5168
  switch (auth.kind) {
5059
5169
  case "api-key":
5060
- return import_picocolors12.default.green("Saved API key");
5170
+ return import_picocolors13.default.green("Saved API key");
5061
5171
  case "bearer-token":
5062
- return import_picocolors12.default.green("Saved bearer token");
5172
+ return import_picocolors13.default.green("Saved bearer token");
5063
5173
  case "auth-fetch":
5064
- return Number(auth.expires ?? Date.now() + 1) <= Date.now() ? import_picocolors12.default.red("Expired") : import_picocolors12.default.green("OAuth connected");
5174
+ return Number(auth.expires ?? Date.now() + 1) <= Date.now() ? import_picocolors13.default.red("Expired") : import_picocolors13.default.green("OAuth connected");
5065
5175
  case "unauthenticated":
5066
- return import_picocolors12.default.dim("No credential");
5176
+ return import_picocolors13.default.dim("No credential");
5067
5177
  case "missing":
5068
- return import_picocolors12.default.red("Missing credential");
5178
+ return import_picocolors13.default.red("Missing credential");
5069
5179
  }
5070
5180
  }
5071
5181
  function extractProviderError(err) {
@@ -5096,16 +5206,16 @@ function openAuthorizationUrl(url) {
5096
5206
  });
5097
5207
  }
5098
5208
  function printMissingSubscriptionPluginGuidance(configName, provider) {
5099
- console.log(import_picocolors12.default.red(`Provider "${provider}" is configured for "${configName}", but no auth plugin is registered.`));
5100
- console.log(import_picocolors12.default.dim(`Config: ${configName}`));
5101
- console.log(import_picocolors12.default.dim(`Provider: ${provider}`));
5102
- console.log(import_picocolors12.default.dim("Add the subscription auth plugin to package.json and install with your package manager:"));
5103
- console.log(import_picocolors12.default.dim(' "devDependencies": { "@vostride/agent-qa-subscription-auth": "<agent-qa version>" }'));
5104
- console.log(import_picocolors12.default.dim("Declare it in agent-qa.config.yaml under plugins.auth:"));
5105
- console.log(import_picocolors12.default.dim(" plugins:"));
5106
- console.log(import_picocolors12.default.dim(" auth:"));
5107
- console.log(import_picocolors12.default.dim(" - package: @vostride/agent-qa-subscription-auth"));
5108
- console.log(import_picocolors12.default.dim("Then authenticate from agent-qa dashboard or rerun this command."));
5209
+ console.log(import_picocolors13.default.red(`Provider "${provider}" is configured for "${configName}", but no auth plugin is registered.`));
5210
+ console.log(import_picocolors13.default.dim(`Config: ${configName}`));
5211
+ console.log(import_picocolors13.default.dim(`Provider: ${provider}`));
5212
+ console.log(import_picocolors13.default.dim("Add the subscription auth plugin to package.json and install with your package manager:"));
5213
+ console.log(import_picocolors13.default.dim(' "devDependencies": { "@vostride/agent-qa-subscription-auth": "<agent-qa version>" }'));
5214
+ console.log(import_picocolors13.default.dim("Declare it in agent-qa.config.yaml under plugins.auth:"));
5215
+ console.log(import_picocolors13.default.dim(" plugins:"));
5216
+ console.log(import_picocolors13.default.dim(" auth:"));
5217
+ console.log(import_picocolors13.default.dim(" - package: @vostride/agent-qa-subscription-auth"));
5218
+ console.log(import_picocolors13.default.dim("Then authenticate from agent-qa dashboard or rerun this command."));
5109
5219
  }
5110
5220
  async function readTokensFromPlugin(provider, plugin, started) {
5111
5221
  if (started.waitForTokens) {
@@ -5113,19 +5223,19 @@ async function readTokensFromPlugin(provider, plugin, started) {
5113
5223
  }
5114
5224
  if (plugin.dashboardAuth.mode === "manual-code") {
5115
5225
  if (!plugin.exchangeCode) {
5116
- console.log(import_picocolors12.default.red(`Provider "${provider}" does not support CLI code exchange. Use agent-qa dashboard.`));
5226
+ console.log(import_picocolors13.default.red(`Provider "${provider}" does not support CLI code exchange. Use agent-qa dashboard.`));
5117
5227
  process.exitCode = 1;
5118
5228
  return null;
5119
5229
  }
5120
5230
  const code = (await (0, import_input2.default)({ message: "Authorization code:" })).trim();
5121
5231
  if (!code) {
5122
- console.log(import_picocolors12.default.red("Authorization code is required"));
5232
+ console.log(import_picocolors13.default.red("Authorization code is required"));
5123
5233
  process.exitCode = 1;
5124
5234
  return null;
5125
5235
  }
5126
5236
  return await plugin.exchangeCode({ code, sessionState: started.sessionState });
5127
5237
  }
5128
- console.log(import_picocolors12.default.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5238
+ console.log(import_picocolors13.default.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5129
5239
  process.exitCode = 1;
5130
5240
  return null;
5131
5241
  }
@@ -5138,14 +5248,14 @@ async function runSubscriptionPluginLogin(configName, provider) {
5138
5248
  return;
5139
5249
  }
5140
5250
  if (!plugin.startAuth) {
5141
- console.log(import_picocolors12.default.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5251
+ console.log(import_picocolors13.default.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5142
5252
  process.exitCode = 1;
5143
5253
  return;
5144
5254
  }
5145
5255
  let started;
5146
5256
  try {
5147
5257
  started = await plugin.startAuth({ configName });
5148
- console.log(`Open this URL to authenticate: ${import_picocolors12.default.cyan(started.authorizeUrl)}`);
5258
+ console.log(`Open this URL to authenticate: ${import_picocolors13.default.cyan(started.authorizeUrl)}`);
5149
5259
  openAuthorizationUrl(started.authorizeUrl);
5150
5260
  const tokens = await readTokensFromPlugin(provider, plugin, started);
5151
5261
  if (!tokens) return;
@@ -5154,9 +5264,9 @@ async function runSubscriptionPluginLogin(configName, provider) {
5154
5264
  provider: plugin.credentialProviderId,
5155
5265
  tokens
5156
5266
  });
5157
- console.log(import_picocolors12.default.green(`Authenticated ${configName} with ${plugin.label}`));
5267
+ console.log(import_picocolors13.default.green(`Authenticated ${configName} with ${plugin.label}`));
5158
5268
  } catch (err) {
5159
- console.log(import_picocolors12.default.red(err instanceof Error ? err.message : String(err)));
5269
+ console.log(import_picocolors13.default.red(err instanceof Error ? err.message : String(err)));
5160
5270
  process.exitCode = 1;
5161
5271
  } finally {
5162
5272
  started?.cleanup?.();
@@ -5173,13 +5283,13 @@ function createAuthCommand() {
5173
5283
  try {
5174
5284
  const requestedName = normalizeConfigName(opts.config);
5175
5285
  if (!requestedName) {
5176
- console.log(import_picocolors12.default.red("configName is required"));
5286
+ console.log(import_picocolors13.default.red("configName is required"));
5177
5287
  return;
5178
5288
  }
5179
5289
  const resolved = await resolveNamedConfig2(requestedName, configPath);
5180
5290
  const resolvedName = normalizeConfigName(resolved.config.name);
5181
5291
  if (!resolvedName) {
5182
- console.log(import_picocolors12.default.red("Config name is invalid"));
5292
+ console.log(import_picocolors13.default.red("Config name is invalid"));
5183
5293
  return;
5184
5294
  }
5185
5295
  configName = resolvedName;
@@ -5190,7 +5300,7 @@ function createAuthCommand() {
5190
5300
  }
5191
5301
  provider = configProvider;
5192
5302
  } catch (err) {
5193
- console.log(import_picocolors12.default.red(err instanceof Error ? err.message : String(err)));
5303
+ console.log(import_picocolors13.default.red(err instanceof Error ? err.message : String(err)));
5194
5304
  return;
5195
5305
  }
5196
5306
  await runSubscriptionPluginLogin(configName, provider);
@@ -5200,7 +5310,7 @@ function createAuthCommand() {
5200
5310
  new import_commander12.Command("set").description("Save a credential for a named LLM config").requiredOption("--config <name>", "named LLM config to save a credential for").requiredOption("--type <type>", "credential type: api-key or bearer-token").argument("[secret]", "credential secret; prompted when omitted").action(async (secretArg, opts, command) => {
5201
5311
  const credentialType = opts.type.trim();
5202
5312
  if (credentialType !== "api-key" && credentialType !== "bearer-token") {
5203
- console.log(import_picocolors12.default.red("type must be api-key or bearer-token"));
5313
+ console.log(import_picocolors13.default.red("type must be api-key or bearer-token"));
5204
5314
  return;
5205
5315
  }
5206
5316
  const { resolveNamedConfig: resolveNamedConfig2 } = await Promise.resolve().then(() => (init_llm_utils(), llm_utils_exports));
@@ -5209,35 +5319,35 @@ function createAuthCommand() {
5209
5319
  try {
5210
5320
  resolved = await resolveNamedConfig2(opts.config, configPath);
5211
5321
  } catch (err) {
5212
- console.log(import_picocolors12.default.red(err instanceof Error ? err.message : String(err)));
5322
+ console.log(import_picocolors13.default.red(err instanceof Error ? err.message : String(err)));
5213
5323
  return;
5214
5324
  }
5215
5325
  const configName = resolved.config.name ?? opts.config;
5216
5326
  const provider = resolved.config.provider;
5217
5327
  if (SUBSCRIPTION_PROVIDERS2.has(provider)) {
5218
- console.log(import_picocolors12.default.red("Subscription providers use OAuth login"));
5328
+ console.log(import_picocolors13.default.red("Subscription providers use OAuth login"));
5219
5329
  return;
5220
5330
  }
5221
5331
  if (credentialType === "bearer-token" && provider !== "anthropic-compatible") {
5222
- console.log(import_picocolors12.default.red("bearer-token credentials are only supported for anthropic-compatible configs"));
5332
+ console.log(import_picocolors13.default.red("bearer-token credentials are only supported for anthropic-compatible configs"));
5223
5333
  return;
5224
5334
  }
5225
5335
  if (credentialType === "api-key" && !API_KEY_CREDENTIAL_PROVIDERS.has(provider)) {
5226
- console.log(import_picocolors12.default.red("api-key credentials are not supported for this provider"));
5336
+ console.log(import_picocolors13.default.red("api-key credentials are not supported for this provider"));
5227
5337
  return;
5228
5338
  }
5229
5339
  const secret = (secretArg ?? await (0, import_password.default)({ message: "Secret:" })).trim();
5230
5340
  if (!secret) {
5231
- console.log(import_picocolors12.default.red("Secret is required"));
5341
+ console.log(import_picocolors13.default.red("Secret is required"));
5232
5342
  return;
5233
5343
  }
5234
5344
  const { writeAuth } = await import("@vostride/agent-qa-core");
5235
5345
  if (credentialType === "bearer-token") {
5236
5346
  await writeAuth(configName, { type: "bearer", provider: "anthropic-compatible", token: secret });
5237
- console.log(import_picocolors12.default.green(`Saved bearer token for ${configName}`));
5347
+ console.log(import_picocolors13.default.green(`Saved bearer token for ${configName}`));
5238
5348
  } else {
5239
5349
  await writeAuth(configName, { type: "api", provider, key: secret });
5240
- console.log(import_picocolors12.default.green(`Saved API key for ${configName}`));
5350
+ console.log(import_picocolors13.default.green(`Saved API key for ${configName}`));
5241
5351
  }
5242
5352
  })
5243
5353
  );
@@ -5246,7 +5356,7 @@ function createAuthCommand() {
5246
5356
  const { loadAuthPluginsForRawConfig: loadAuthPluginsForRawConfig2, resolveModelAuth: resolveModelAuth2 } = await Promise.resolve().then(() => (init_llm_utils(), llm_utils_exports));
5247
5357
  const { loadConfigFile: loadConfigFile2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5248
5358
  const configPath = getGlobalConfigPath2(this) ?? "agent-qa.config.yaml";
5249
- console.log(import_picocolors12.default.bold("Auth status:\n"));
5359
+ console.log(import_picocolors13.default.bold("Auth status:\n"));
5250
5360
  let llms;
5251
5361
  let defaultLLM;
5252
5362
  try {
@@ -5257,20 +5367,20 @@ function createAuthCommand() {
5257
5367
  } catch {
5258
5368
  }
5259
5369
  if (!llms?.length) {
5260
- console.log(import_picocolors12.default.dim(" No LLM configs found"));
5370
+ console.log(import_picocolors13.default.dim(" No LLM configs found"));
5261
5371
  return;
5262
5372
  }
5263
5373
  const maxNameLen = Math.max(...llms.map((c) => String(c.name ?? "").length), 4) + 12;
5264
5374
  for (const llm of llms) {
5265
5375
  const name = String(llm.name ?? "");
5266
5376
  const isDefault = name === defaultLLM;
5267
- const label = isDefault ? `${name} ${import_picocolors12.default.dim("(default)")}` : name;
5377
+ const label = isDefault ? `${name} ${import_picocolors13.default.dim("(default)")}` : name;
5268
5378
  const rawLabel = isDefault ? `${name} (default)` : name;
5269
5379
  const padLen = Math.max(0, maxNameLen - rawLabel.length);
5270
5380
  const dots = ".".repeat(padLen + 2);
5271
5381
  const provider = llm.provider;
5272
5382
  const status = statusForResolvedAuth(await resolveModelAuth2(name, llm));
5273
- console.log(` ${label} ${import_picocolors12.default.dim(`[${providerLabel(provider)}]`)} ${import_picocolors12.default.dim(dots)} ${status}`);
5383
+ console.log(` ${label} ${import_picocolors13.default.dim(`[${providerLabel(provider)}]`)} ${import_picocolors13.default.dim(dots)} ${status}`);
5274
5384
  }
5275
5385
  })
5276
5386
  );
@@ -5287,12 +5397,12 @@ function createAuthCommand() {
5287
5397
  const resolved = await resolveNamedConfig2(void 0, configPath);
5288
5398
  storeKey = resolved.config.name;
5289
5399
  } catch {
5290
- console.log(import_picocolors12.default.red("Specify --config <name> or run with a config file"));
5400
+ console.log(import_picocolors13.default.red("Specify --config <name> or run with a config file"));
5291
5401
  return;
5292
5402
  }
5293
5403
  }
5294
5404
  await removeAuth(storeKey);
5295
- console.log(import_picocolors12.default.green(`Logged out from ${storeKey}`));
5405
+ console.log(import_picocolors13.default.green(`Logged out from ${storeKey}`));
5296
5406
  })
5297
5407
  );
5298
5408
  cmd.addCommand(
@@ -5307,19 +5417,19 @@ function createAuthCommand() {
5307
5417
  planner = modelFields;
5308
5418
  configName = name;
5309
5419
  } catch (err) {
5310
- console.log(import_picocolors12.default.red(err instanceof Error ? err.message : String(err)));
5420
+ console.log(import_picocolors13.default.red(err instanceof Error ? err.message : String(err)));
5311
5421
  return;
5312
5422
  }
5313
5423
  if (opts.provider) planner = { ...planner, provider: opts.provider };
5314
5424
  if (opts.model) planner = { ...planner, model: opts.model };
5315
- console.log(import_picocolors12.default.dim(`Testing config: ${configName}...`));
5425
+ console.log(import_picocolors13.default.dim(`Testing config: ${configName}...`));
5316
5426
  const auth = await resolveModelAuth2(configName, planner);
5317
5427
  if (auth.kind === "missing") {
5318
- console.log(import_picocolors12.default.red(auth.message));
5428
+ console.log(import_picocolors13.default.red(auth.message));
5319
5429
  return;
5320
5430
  }
5321
5431
  if (auth.kind === "unauthenticated") {
5322
- console.log(import_picocolors12.default.dim(auth.message));
5432
+ console.log(import_picocolors13.default.dim(auth.message));
5323
5433
  }
5324
5434
  const { createModel, getProviderOptions } = await import("@vostride/agent-qa-core");
5325
5435
  const { generateText } = await import("ai");
@@ -5337,24 +5447,24 @@ function createAuthCommand() {
5337
5447
  ...providerOpts ? { providerOptions: providerOpts } : {}
5338
5448
  });
5339
5449
  const elapsed = Date.now() - start;
5340
- console.log(import_picocolors12.default.green(`Connected to ${planner.provider}/${planner.model} (${elapsed}ms)`));
5450
+ console.log(import_picocolors13.default.green(`Connected to ${planner.provider}/${planner.model} (${elapsed}ms)`));
5341
5451
  } catch (err) {
5342
5452
  const { message, statusCode } = extractProviderError(err);
5343
5453
  const fullContext = `${message} ${statusCode ?? ""}`;
5344
5454
  if (/auth|unauthorized|401|invalid.*key|permission/i.test(fullContext)) {
5345
- console.log(import_picocolors12.default.red("Authentication failed. Check the saved credential for this config."));
5455
+ console.log(import_picocolors13.default.red("Authentication failed. Check the saved credential for this config."));
5346
5456
  } else if (/model.*not.*support|not found|404|does not exist/i.test(fullContext)) {
5347
- console.log(import_picocolors12.default.red("Model not found. Check the model name."));
5457
+ console.log(import_picocolors13.default.red("Model not found. Check the model name."));
5348
5458
  } else if (/rate|429|quota|limit/i.test(fullContext)) {
5349
- console.log(import_picocolors12.default.red("Rate limited. Try again later."));
5459
+ console.log(import_picocolors13.default.red("Rate limited. Try again later."));
5350
5460
  } else if (/ECONNREFUSED|ENOTFOUND|timeout|abort|fetch failed|network/i.test(fullContext)) {
5351
- console.log(import_picocolors12.default.red("Network error. Check the exact base URL and try again."));
5461
+ console.log(import_picocolors13.default.red("Network error. Check the exact base URL and try again."));
5352
5462
  } else if (/invalid_request|400|bad request/i.test(fullContext)) {
5353
- console.log(import_picocolors12.default.red("Invalid request. Check model and provider settings."));
5463
+ console.log(import_picocolors13.default.red("Invalid request. Check model and provider settings."));
5354
5464
  } else {
5355
- console.log(import_picocolors12.default.red(`Connection failed. ${message}`));
5465
+ console.log(import_picocolors13.default.red(`Connection failed. ${message}`));
5356
5466
  }
5357
- console.log(import_picocolors12.default.dim(message));
5467
+ console.log(import_picocolors13.default.dim(message));
5358
5468
  } finally {
5359
5469
  clearTimeout(timeout);
5360
5470
  }
@@ -5365,10 +5475,10 @@ function createAuthCommand() {
5365
5475
 
5366
5476
  // src/commands/auth-state.ts
5367
5477
  var import_promises4 = require("readline/promises");
5368
- var import_node_path11 = require("path");
5478
+ var import_node_path12 = require("path");
5369
5479
  var import_commander13 = require("commander");
5370
- var import_picocolors13 = __toESM(require("picocolors"), 1);
5371
- var import_agent_qa_core13 = require("@vostride/agent-qa-core");
5480
+ var import_picocolors14 = __toESM(require("picocolors"), 1);
5481
+ var import_agent_qa_core14 = require("@vostride/agent-qa-core");
5372
5482
  init_config();
5373
5483
  function getGlobalConfigPath3(command) {
5374
5484
  return command.parent?.parent?.opts().config ?? command.parent?.opts().config;
@@ -5406,7 +5516,7 @@ async function waitForCaptureConfirmation(input3) {
5406
5516
  }
5407
5517
  async function authStateExists(paths) {
5408
5518
  try {
5409
- await (0, import_agent_qa_core13.readAuthStateMetadata)(paths);
5519
+ await (0, import_agent_qa_core14.readAuthStateMetadata)(paths);
5410
5520
  return true;
5411
5521
  } catch {
5412
5522
  return false;
@@ -5418,7 +5528,7 @@ function buildConfirmationMessage(targetName, stateName, exists) {
5418
5528
  }
5419
5529
  async function loadCommandContext(command) {
5420
5530
  const configPath = getGlobalConfigPath3(command) ?? "agent-qa.config.yaml";
5421
- const configDir = (0, import_node_path11.dirname)((0, import_node_path11.resolve)(configPath));
5531
+ const configDir = (0, import_node_path12.dirname)((0, import_node_path12.resolve)(configPath));
5422
5532
  const config = await resolveConfig({ configPath, loadAuthPlugins: false });
5423
5533
  return { configPath, configDir, config };
5424
5534
  }
@@ -5427,10 +5537,10 @@ function isSafeAuthStateError(message) {
5427
5537
  }
5428
5538
  function printSafeAuthStateError(error, fallback) {
5429
5539
  const message = error instanceof Error ? error.message : String(error);
5430
- console.error(import_picocolors13.default.red(isSafeAuthStateError(message) ? message : fallback));
5540
+ console.error(import_picocolors14.default.red(isSafeAuthStateError(message) ? message : fallback));
5431
5541
  }
5432
5542
  function assertWebAuthStateTarget(input3) {
5433
- (0, import_agent_qa_core13.resolveAuthStatePaths)({
5543
+ (0, import_agent_qa_core14.resolveAuthStatePaths)({
5434
5544
  configDir: input3.configDir,
5435
5545
  authStateDir: input3.config.services?.authState?.dir,
5436
5546
  targetName: input3.target.name,
@@ -5467,7 +5577,7 @@ function createAuthStateCommand(deps = {}) {
5467
5577
  assertWebAuthStateTarget({ configDir, config, target });
5468
5578
  targetName = target.name;
5469
5579
  }
5470
- const metadata = await (0, import_agent_qa_core13.listAuthStateMetadata)({
5580
+ const metadata = await (0, import_agent_qa_core14.listAuthStateMetadata)({
5471
5581
  configDir,
5472
5582
  authStateDir: config.services?.authState?.dir,
5473
5583
  targetName
@@ -5487,7 +5597,7 @@ function createAuthStateCommand(deps = {}) {
5487
5597
  const target = resolveTarget(config, opts.target);
5488
5598
  resolvedTargetName = target.name;
5489
5599
  if (opts.name) {
5490
- await (0, import_agent_qa_core13.removeAuthStateFiles)({
5600
+ await (0, import_agent_qa_core14.removeAuthStateFiles)({
5491
5601
  configDir,
5492
5602
  authStateDir: config.services?.authState?.dir,
5493
5603
  targetName: target.name,
@@ -5497,7 +5607,7 @@ function createAuthStateCommand(deps = {}) {
5497
5607
  console.log(`Removed auth state "${opts.name}" for target "${target.name}".`);
5498
5608
  return;
5499
5609
  }
5500
- await (0, import_agent_qa_core13.removeAuthStateTarget)({
5610
+ await (0, import_agent_qa_core14.removeAuthStateTarget)({
5501
5611
  configDir,
5502
5612
  authStateDir: config.services?.authState?.dir,
5503
5613
  targetName: target.name,
@@ -5519,7 +5629,7 @@ function createAuthStateCommand(deps = {}) {
5519
5629
  try {
5520
5630
  const { configDir, config } = await loadCommandContext(command);
5521
5631
  const target = resolveTarget(config, opts.target);
5522
- const paths = (0, import_agent_qa_core13.resolveAuthStatePaths)({
5632
+ const paths = (0, import_agent_qa_core14.resolveAuthStatePaths)({
5523
5633
  configDir,
5524
5634
  authStateDir: config.services?.authState?.dir,
5525
5635
  targetName: target.name,
@@ -5527,7 +5637,7 @@ function createAuthStateCommand(deps = {}) {
5527
5637
  target: { platform: target.platform }
5528
5638
  });
5529
5639
  if (!target.url) {
5530
- console.error(import_picocolors13.default.red(`Target "${target.name}" must define a web URL for auth-state capture.`));
5640
+ console.error(import_picocolors14.default.red(`Target "${target.name}" must define a web URL for auth-state capture.`));
5531
5641
  process.exitCode = 1;
5532
5642
  return;
5533
5643
  }
@@ -5551,16 +5661,16 @@ function createAuthStateCommand(deps = {}) {
5551
5661
  }
5552
5662
  if (confirmation === "browser-closed") {
5553
5663
  await closeBrowser(browser);
5554
- console.error(import_picocolors13.default.red("Browser was closed before auth state was saved."));
5664
+ console.error(import_picocolors14.default.red("Browser was closed before auth state was saved."));
5555
5665
  process.exitCode = 1;
5556
5666
  return;
5557
5667
  }
5558
5668
  const payload = await context.storageState({ indexedDB: true });
5559
5669
  try {
5560
- await (0, import_agent_qa_core13.writeAuthStateFiles)(paths, {
5670
+ await (0, import_agent_qa_core14.writeAuthStateFiles)(paths, {
5561
5671
  payload,
5562
5672
  metadata: {
5563
- version: import_agent_qa_core13.AUTH_STATE_SCHEMA_VERSION,
5673
+ version: import_agent_qa_core14.AUTH_STATE_SCHEMA_VERSION,
5564
5674
  kind: "web",
5565
5675
  target: target.name,
5566
5676
  name: opts.name,
@@ -5569,7 +5679,7 @@ function createAuthStateCommand(deps = {}) {
5569
5679
  });
5570
5680
  } catch {
5571
5681
  await closeBrowser(browser);
5572
- console.error(import_picocolors13.default.red(`Could not save auth state "${opts.name}" for target "${target.name}".`));
5682
+ console.error(import_picocolors14.default.red(`Could not save auth state "${opts.name}" for target "${target.name}".`));
5573
5683
  process.exitCode = 1;
5574
5684
  return;
5575
5685
  }
@@ -5577,7 +5687,7 @@ function createAuthStateCommand(deps = {}) {
5577
5687
  console.log(`Saved auth state "${opts.name}" for target "${target.name}".`);
5578
5688
  } catch (error) {
5579
5689
  await closeBrowser(browser);
5580
- console.error(import_picocolors13.default.red(error instanceof Error ? error.message : String(error)));
5690
+ console.error(import_picocolors14.default.red(error instanceof Error ? error.message : String(error)));
5581
5691
  process.exitCode = 1;
5582
5692
  }
5583
5693
  })
@@ -5588,34 +5698,34 @@ function createAuthStateCommand(deps = {}) {
5588
5698
  // src/commands/devices.ts
5589
5699
  var import_commander14 = require("commander");
5590
5700
  var import_node_child_process5 = require("child_process");
5591
- var import_node_fs4 = require("fs");
5592
- var import_node_path12 = require("path");
5701
+ var import_node_fs5 = require("fs");
5702
+ var import_node_path13 = require("path");
5593
5703
  var import_yaml6 = require("yaml");
5594
- var import_picocolors14 = __toESM(require("picocolors"), 1);
5704
+ var import_picocolors15 = __toESM(require("picocolors"), 1);
5595
5705
  init_config();
5596
5706
  function formatStatus2(transport, localBinding) {
5597
5707
  if (transport !== "local") {
5598
- return import_picocolors14.default.green("Ready") + import_picocolors14.default.dim(" (no local binding required)");
5708
+ return import_picocolors15.default.green("Ready") + import_picocolors15.default.dim(" (no local binding required)");
5599
5709
  }
5600
5710
  if (!localBinding) {
5601
- return import_picocolors14.default.red("UNBOUND") + import_picocolors14.default.yellow(" - run `agent-qa devices init`");
5711
+ return import_picocolors15.default.red("UNBOUND") + import_picocolors15.default.yellow(" - run `agent-qa devices init`");
5602
5712
  }
5603
5713
  const keys = Object.entries(localBinding).slice(0, 2);
5604
5714
  const details = keys.map(([k, v]) => `${k}: ${v}`).join(", ");
5605
- return import_picocolors14.default.green("Bound") + import_picocolors14.default.dim(` (${details})`);
5715
+ return import_picocolors15.default.green("Bound") + import_picocolors15.default.dim(` (${details})`);
5606
5716
  }
5607
5717
  async function listDevices() {
5608
5718
  let config;
5609
5719
  try {
5610
5720
  config = await resolveConfig({});
5611
5721
  } catch (err) {
5612
- console.error(import_picocolors14.default.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
5722
+ console.error(import_picocolors15.default.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
5613
5723
  process.exitCode = 1;
5614
5724
  return;
5615
5725
  }
5616
5726
  const devices = config.registry?.devices;
5617
5727
  if (!devices || Object.keys(devices).length === 0) {
5618
- console.log(import_picocolors14.default.yellow("No devices configured in registry.devices"));
5728
+ console.log(import_picocolors15.default.yellow("No devices configured in registry.devices"));
5619
5729
  return;
5620
5730
  }
5621
5731
  const localBindings = loadLocalBindings();
@@ -5623,13 +5733,13 @@ async function listDevices() {
5623
5733
  const platWidth = 10;
5624
5734
  const transWidth = 14;
5625
5735
  console.log("");
5626
- console.log(import_picocolors14.default.bold(" Configured Devices"));
5736
+ console.log(import_picocolors15.default.bold(" Configured Devices"));
5627
5737
  console.log("");
5628
5738
  console.log(
5629
- ` ${import_picocolors14.default.dim("Name".padEnd(nameWidth))} ${import_picocolors14.default.dim("Platform".padEnd(platWidth))} ${import_picocolors14.default.dim("Transport".padEnd(transWidth))} ${import_picocolors14.default.dim("Status")}`
5739
+ ` ${import_picocolors15.default.dim("Name".padEnd(nameWidth))} ${import_picocolors15.default.dim("Platform".padEnd(platWidth))} ${import_picocolors15.default.dim("Transport".padEnd(transWidth))} ${import_picocolors15.default.dim("Status")}`
5630
5740
  );
5631
5741
  console.log(
5632
- ` ${import_picocolors14.default.dim("\u2500".repeat(nameWidth))} ${import_picocolors14.default.dim("\u2500".repeat(platWidth))} ${import_picocolors14.default.dim("\u2500".repeat(transWidth))} ${import_picocolors14.default.dim("\u2500".repeat(30))}`
5742
+ ` ${import_picocolors15.default.dim("\u2500".repeat(nameWidth))} ${import_picocolors15.default.dim("\u2500".repeat(platWidth))} ${import_picocolors15.default.dim("\u2500".repeat(transWidth))} ${import_picocolors15.default.dim("\u2500".repeat(30))}`
5633
5743
  );
5634
5744
  for (const [name, profile] of Object.entries(devices)) {
5635
5745
  const localBinding = localBindings?.devices?.[name] ?? null;
@@ -5680,41 +5790,41 @@ function scanSimctlDevices() {
5680
5790
  }
5681
5791
  }
5682
5792
  function appendGitignoreEntry(dir, entry) {
5683
- const gitignorePath = (0, import_node_path12.join)(dir, ".gitignore");
5793
+ const gitignorePath = (0, import_node_path13.join)(dir, ".gitignore");
5684
5794
  let existing = "";
5685
- if ((0, import_node_fs4.existsSync)(gitignorePath)) {
5686
- existing = (0, import_node_fs4.readFileSync)(gitignorePath, "utf-8");
5795
+ if ((0, import_node_fs5.existsSync)(gitignorePath)) {
5796
+ existing = (0, import_node_fs5.readFileSync)(gitignorePath, "utf-8");
5687
5797
  }
5688
5798
  if (existing.includes(entry)) return;
5689
5799
  const append = (existing.length > 0 && !existing.endsWith("\n") ? "\n" : "") + entry + "\n";
5690
- (0, import_node_fs4.writeFileSync)(gitignorePath, existing + append);
5800
+ (0, import_node_fs5.writeFileSync)(gitignorePath, existing + append);
5691
5801
  }
5692
5802
  async function initDevices() {
5693
5803
  const dir = process.cwd();
5694
- const localFilePath = (0, import_node_path12.join)(dir, "agent-qa.local.yaml");
5695
- if ((0, import_node_fs4.existsSync)(localFilePath)) {
5696
- console.log(import_picocolors14.default.yellow("agent-qa.local.yaml already exists. Skipping generation."));
5804
+ const localFilePath = (0, import_node_path13.join)(dir, "agent-qa.local.yaml");
5805
+ if ((0, import_node_fs5.existsSync)(localFilePath)) {
5806
+ console.log(import_picocolors15.default.yellow("agent-qa.local.yaml already exists. Skipping generation."));
5697
5807
  return;
5698
5808
  }
5699
- console.log(import_picocolors14.default.bold("\n Scanning for connected devices...\n"));
5809
+ console.log(import_picocolors15.default.bold("\n Scanning for connected devices...\n"));
5700
5810
  const adbDevices = scanAdbDevices();
5701
5811
  const simctlDevices = scanSimctlDevices();
5702
5812
  if (adbDevices.length > 0) {
5703
- console.log(` ${import_picocolors14.default.green("Android:")} found ${adbDevices.length} device(s)`);
5813
+ console.log(` ${import_picocolors15.default.green("Android:")} found ${adbDevices.length} device(s)`);
5704
5814
  for (const d of adbDevices) {
5705
- console.log(` ${import_picocolors14.default.dim("\u2022")} ${d.model} (${d.serial})`);
5815
+ console.log(` ${import_picocolors15.default.dim("\u2022")} ${d.model} (${d.serial})`);
5706
5816
  }
5707
5817
  } else {
5708
- console.log(` ${import_picocolors14.default.dim("Android:")} no devices found (adb not available or no devices connected)`);
5818
+ console.log(` ${import_picocolors15.default.dim("Android:")} no devices found (adb not available or no devices connected)`);
5709
5819
  }
5710
5820
  if (simctlDevices.length > 0) {
5711
5821
  const booted = simctlDevices.filter((d) => d.state === "Booted");
5712
- console.log(` ${import_picocolors14.default.green("iOS:")} found ${simctlDevices.length} simulator(s) (${booted.length} booted)`);
5822
+ console.log(` ${import_picocolors15.default.green("iOS:")} found ${simctlDevices.length} simulator(s) (${booted.length} booted)`);
5713
5823
  for (const d of booted) {
5714
- console.log(` ${import_picocolors14.default.dim("\u2022")} ${d.name} (${d.udid})`);
5824
+ console.log(` ${import_picocolors15.default.dim("\u2022")} ${d.name} (${d.udid})`);
5715
5825
  }
5716
5826
  } else {
5717
- console.log(` ${import_picocolors14.default.dim("iOS:")} no simulators found (simctl not available or none installed)`);
5827
+ console.log(` ${import_picocolors15.default.dim("iOS:")} no simulators found (simctl not available or none installed)`);
5718
5828
  }
5719
5829
  let config;
5720
5830
  try {
@@ -5745,11 +5855,11 @@ async function initDevices() {
5745
5855
  providers: {}
5746
5856
  };
5747
5857
  const yamlContent = "# Generated by agent-qa devices init\n# Edit device bindings for your local machine\n" + (0, import_yaml6.stringify)(localFileContent);
5748
- (0, import_node_fs4.writeFileSync)(localFilePath, yamlContent);
5858
+ (0, import_node_fs5.writeFileSync)(localFilePath, yamlContent);
5749
5859
  appendGitignoreEntry(dir, "agent-qa.local.yaml");
5750
5860
  console.log("");
5751
- console.log(import_picocolors14.default.green(` Generated agent-qa.local.yaml with ${bindCount} device binding(s)`));
5752
- console.log(import_picocolors14.default.dim(" Added agent-qa.local.yaml to .gitignore"));
5861
+ console.log(import_picocolors15.default.green(` Generated agent-qa.local.yaml with ${bindCount} device binding(s)`));
5862
+ console.log(import_picocolors15.default.dim(" Added agent-qa.local.yaml to .gitignore"));
5753
5863
  console.log("");
5754
5864
  }
5755
5865
  function createDevicesCommand() {
@@ -5761,7 +5871,7 @@ function createDevicesCommand() {
5761
5871
 
5762
5872
  // src/commands/ids.ts
5763
5873
  var import_commander15 = require("commander");
5764
- var import_picocolors15 = __toESM(require("picocolors"), 1);
5874
+ var import_picocolors16 = __toESM(require("picocolors"), 1);
5765
5875
  var import_agent_qa_ids = require("@vostride/agent-qa-ids");
5766
5876
  function parseEntityType(value) {
5767
5877
  if (import_agent_qa_ids.ENTITY_ID_TYPES.includes(value)) {
@@ -5782,7 +5892,7 @@ function createIdsCommand() {
5782
5892
  console.log(id);
5783
5893
  }
5784
5894
  } catch (err) {
5785
- console.error(import_picocolors15.default.red(err instanceof Error ? err.message : String(err)));
5895
+ console.error(import_picocolors16.default.red(err instanceof Error ? err.message : String(err)));
5786
5896
  process.exitCode = 1;
5787
5897
  }
5788
5898
  });
@@ -5801,15 +5911,15 @@ function createIdsCommand() {
5801
5911
  if (opts.json) {
5802
5912
  console.log(JSON.stringify(result, null, 2));
5803
5913
  } else if (valid) {
5804
- console.log(import_picocolors15.default.green(result.message));
5914
+ console.log(import_picocolors16.default.green(result.message));
5805
5915
  } else {
5806
- console.error(import_picocolors15.default.red(result.message));
5916
+ console.error(import_picocolors16.default.red(result.message));
5807
5917
  }
5808
5918
  if (!valid) {
5809
5919
  process.exitCode = 1;
5810
5920
  }
5811
5921
  } catch (err) {
5812
- console.error(import_picocolors15.default.red(err instanceof Error ? err.message : String(err)));
5922
+ console.error(import_picocolors16.default.red(err instanceof Error ? err.message : String(err)));
5813
5923
  process.exitCode = 1;
5814
5924
  }
5815
5925
  });
@@ -5821,14 +5931,14 @@ var import_commander16 = require("commander");
5821
5931
  var import_agent_qa_ids2 = require("@vostride/agent-qa-ids");
5822
5932
  var import_yaml7 = require("yaml");
5823
5933
  var import_promises5 = require("fs/promises");
5824
- var import_node_fs5 = require("fs");
5825
- var import_node_path13 = require("path");
5826
- var import_picocolors16 = __toESM(require("picocolors"), 1);
5934
+ var import_node_fs6 = require("fs");
5935
+ var import_node_path14 = require("path");
5936
+ var import_picocolors17 = __toESM(require("picocolors"), 1);
5827
5937
  function createCreateTestCommand() {
5828
5938
  const cmd = new import_commander16.Command("create-test").description("Scaffold a new test YAML file with auto-generated ID").argument("<path>", "output file path for the test YAML").action(async (path) => {
5829
- const resolved = (0, import_node_path13.resolve)(path);
5830
- if ((0, import_node_fs5.existsSync)(resolved)) {
5831
- console.error(import_picocolors16.default.red("Error: File already exists: " + resolved));
5939
+ const resolved = (0, import_node_path14.resolve)(path);
5940
+ if ((0, import_node_fs6.existsSync)(resolved)) {
5941
+ console.error(import_picocolors17.default.red("Error: File already exists: " + resolved));
5832
5942
  process.exitCode = 1;
5833
5943
  return;
5834
5944
  }
@@ -5840,10 +5950,10 @@ function createCreateTestCommand() {
5840
5950
  steps: ["Describe your first test step here"]
5841
5951
  };
5842
5952
  const yamlContent = (0, import_yaml7.stringify)(template);
5843
- await (0, import_promises5.mkdir)((0, import_node_path13.dirname)(resolved), { recursive: true });
5953
+ await (0, import_promises5.mkdir)((0, import_node_path14.dirname)(resolved), { recursive: true });
5844
5954
  await (0, import_promises5.writeFile)(resolved, yamlContent, "utf-8");
5845
- console.log(import_picocolors16.default.green("Created " + resolved));
5846
- console.log(import_picocolors16.default.dim(" test-id: " + testId));
5955
+ console.log(import_picocolors17.default.green("Created " + resolved));
5956
+ console.log(import_picocolors17.default.dim(" test-id: " + testId));
5847
5957
  });
5848
5958
  return cmd;
5849
5959
  }
@@ -5853,14 +5963,14 @@ var import_commander17 = require("commander");
5853
5963
  var import_agent_qa_ids3 = require("@vostride/agent-qa-ids");
5854
5964
  var import_yaml8 = require("yaml");
5855
5965
  var import_promises6 = require("fs/promises");
5856
- var import_node_fs6 = require("fs");
5857
- var import_node_path14 = require("path");
5858
- var import_picocolors17 = __toESM(require("picocolors"), 1);
5966
+ var import_node_fs7 = require("fs");
5967
+ var import_node_path15 = require("path");
5968
+ var import_picocolors18 = __toESM(require("picocolors"), 1);
5859
5969
  function createCreateSuiteCommand() {
5860
5970
  const cmd = new import_commander17.Command("create-suite").description("Scaffold a new suite YAML file with auto-generated ID").argument("<path>", "output file path for the suite YAML").action(async (path) => {
5861
- const resolved = (0, import_node_path14.resolve)(path);
5862
- if ((0, import_node_fs6.existsSync)(resolved)) {
5863
- console.error(import_picocolors17.default.red("Error: File already exists: " + resolved));
5971
+ const resolved = (0, import_node_path15.resolve)(path);
5972
+ if ((0, import_node_fs7.existsSync)(resolved)) {
5973
+ console.error(import_picocolors18.default.red("Error: File already exists: " + resolved));
5864
5974
  process.exitCode = 1;
5865
5975
  return;
5866
5976
  }
@@ -5874,22 +5984,22 @@ function createCreateSuiteCommand() {
5874
5984
  "tests: []",
5875
5985
  "tests: []\n # - test: ./path/to/test.yaml\n # id: my-test-id"
5876
5986
  );
5877
- await (0, import_promises6.mkdir)((0, import_node_path14.dirname)(resolved), { recursive: true });
5987
+ await (0, import_promises6.mkdir)((0, import_node_path15.dirname)(resolved), { recursive: true });
5878
5988
  await (0, import_promises6.writeFile)(resolved, yamlContent, "utf-8");
5879
- console.log(import_picocolors17.default.green("Created " + resolved));
5880
- console.log(import_picocolors17.default.dim(" suite-id: " + suiteId));
5989
+ console.log(import_picocolors18.default.green("Created " + resolved));
5990
+ console.log(import_picocolors18.default.dim(" suite-id: " + suiteId));
5881
5991
  });
5882
5992
  return cmd;
5883
5993
  }
5884
5994
 
5885
5995
  // src/commands/clean-memory.ts
5886
5996
  var import_commander18 = require("commander");
5887
- var import_picocolors18 = __toESM(require("picocolors"), 1);
5997
+ var import_picocolors19 = __toESM(require("picocolors"), 1);
5888
5998
  var import_node_readline3 = require("readline");
5889
5999
  var import_promises7 = require("fs/promises");
5890
- var import_node_fs7 = require("fs");
5891
- var import_node_path15 = require("path");
5892
- var import_agent_qa_core14 = require("@vostride/agent-qa-core");
6000
+ var import_node_fs8 = require("fs");
6001
+ var import_node_path16 = require("path");
6002
+ var import_agent_qa_core15 = require("@vostride/agent-qa-core");
5893
6003
  init_config();
5894
6004
  function formatSize(bytes) {
5895
6005
  if (bytes === 0) return "0 B";
@@ -5897,13 +6007,13 @@ function formatSize(bytes) {
5897
6007
  return `${(bytes / 1048576).toFixed(1)} MB`;
5898
6008
  }
5899
6009
  async function getOrphanInfo(memoryRoot, tier, scope) {
5900
- const scopePath = (0, import_node_path15.join)(memoryRoot, tier, scope);
5901
- const obsFiles = await (0, import_agent_qa_core14.listObservations)(scopePath);
6010
+ const scopePath = (0, import_node_path16.join)(memoryRoot, tier, scope);
6011
+ const obsFiles = await (0, import_agent_qa_core15.listObservations)(scopePath);
5902
6012
  let newest = null;
5903
6013
  for (const filename of obsFiles) {
5904
6014
  try {
5905
- const content = await (0, import_promises7.readFile)((0, import_node_path15.join)(scopePath, filename), "utf-8");
5906
- const { data } = (0, import_agent_qa_core14.parseObservation)(content, filename);
6015
+ const content = await (0, import_promises7.readFile)((0, import_node_path16.join)(scopePath, filename), "utf-8");
6016
+ const { data } = (0, import_agent_qa_core15.parseObservation)(content, filename);
5907
6017
  if (data?.last_confirmed) {
5908
6018
  if (!newest || data.last_confirmed > newest) {
5909
6019
  newest = data.last_confirmed;
@@ -5917,7 +6027,7 @@ async function getOrphanInfo(memoryRoot, tier, scope) {
5917
6027
  const entries = await (0, import_promises7.readdir)(scopePath);
5918
6028
  for (const entry of entries) {
5919
6029
  try {
5920
- const s = await (0, import_promises7.stat)((0, import_node_path15.join)(scopePath, entry));
6030
+ const s = await (0, import_promises7.stat)((0, import_node_path16.join)(scopePath, entry));
5921
6031
  if (s.isFile()) totalSize += s.size;
5922
6032
  } catch {
5923
6033
  }
@@ -5925,7 +6035,7 @@ async function getOrphanInfo(memoryRoot, tier, scope) {
5925
6035
  } catch {
5926
6036
  }
5927
6037
  return {
5928
- path: (0, import_node_path15.join)(tier, scope),
6038
+ path: (0, import_node_path16.join)(tier, scope),
5929
6039
  tier,
5930
6040
  scope,
5931
6041
  fileCount: obsFiles.length,
@@ -5938,17 +6048,17 @@ function createCleanMemoryCommand() {
5938
6048
  const opts = command.opts();
5939
6049
  const configPath = command.parent?.opts()?.config ?? "agent-qa.config.yaml";
5940
6050
  const config = await resolveConfig({ configPath });
5941
- const workspace = (0, import_agent_qa_core14.resolveWorkspacePaths)({ config, configPath });
6051
+ const workspace = (0, import_agent_qa_core15.resolveWorkspacePaths)({ config, configPath });
5942
6052
  const expectedProducts = /* @__PURE__ */ new Set();
5943
6053
  const targets = config.registry?.targets ?? {};
5944
6054
  for (const [name, entry] of Object.entries(targets)) {
5945
6055
  expectedProducts.add(entry?.product ?? name);
5946
6056
  }
5947
6057
  const expectedTests = /* @__PURE__ */ new Set();
5948
- for (const file of await (0, import_agent_qa_core14.discoverWorkspaceFiles)({ workspace, kind: "test" })) {
6058
+ for (const file of await (0, import_agent_qa_core15.discoverWorkspaceFiles)({ workspace, kind: "test" })) {
5949
6059
  try {
5950
6060
  const content = await (0, import_promises7.readFile)(file.absolutePath, "utf-8");
5951
- const result = (0, import_agent_qa_core14.parseTestFile)(content, file.workspaceRelativePath);
6061
+ const result = (0, import_agent_qa_core15.parseTestFile)(content, file.workspaceRelativePath);
5952
6062
  for (const t of result.tests) {
5953
6063
  if (t["test-id"]) expectedTests.add(t["test-id"]);
5954
6064
  expectedTests.add(t.name);
@@ -5957,17 +6067,17 @@ function createCleanMemoryCommand() {
5957
6067
  }
5958
6068
  }
5959
6069
  const expectedSuites = /* @__PURE__ */ new Set();
5960
- for (const file of await (0, import_agent_qa_core14.discoverWorkspaceFiles)({ workspace, kind: "suite" })) {
6070
+ for (const file of await (0, import_agent_qa_core15.discoverWorkspaceFiles)({ workspace, kind: "suite" })) {
5961
6071
  try {
5962
- const suite = await (0, import_agent_qa_core14.parseSuiteFile)(file.absolutePath);
6072
+ const suite = await (0, import_agent_qa_core15.parseSuiteFile)(file.absolutePath);
5963
6073
  if (suite["suite-id"]) expectedSuites.add(suite["suite-id"]);
5964
6074
  expectedSuites.add(suite.name);
5965
6075
  } catch {
5966
6076
  }
5967
6077
  }
5968
- const memoryRoot = (0, import_agent_qa_core14.resolveMemoryRoot)(config, workspace.configDir);
5969
- if (!(0, import_node_fs7.existsSync)(memoryRoot)) {
5970
- console.log(import_picocolors18.default.dim("No memory directory found."));
6078
+ const memoryRoot = (0, import_agent_qa_core15.resolveMemoryRoot)(config, workspace.configDir);
6079
+ if (!(0, import_node_fs8.existsSync)(memoryRoot)) {
6080
+ console.log(import_picocolors19.default.dim("No memory directory found."));
5971
6081
  return;
5972
6082
  }
5973
6083
  const TIERS = [
@@ -5977,7 +6087,7 @@ function createCleanMemoryCommand() {
5977
6087
  ];
5978
6088
  const orphans = [];
5979
6089
  for (const tier of TIERS) {
5980
- const tierPath = (0, import_node_path15.join)(memoryRoot, tier.dir);
6090
+ const tierPath = (0, import_node_path16.join)(memoryRoot, tier.dir);
5981
6091
  let entries;
5982
6092
  try {
5983
6093
  entries = await (0, import_promises7.readdir)(tierPath);
@@ -5986,7 +6096,7 @@ function createCleanMemoryCommand() {
5986
6096
  }
5987
6097
  for (const entry of entries) {
5988
6098
  try {
5989
- const s = await (0, import_promises7.stat)((0, import_node_path15.join)(tierPath, entry));
6099
+ const s = await (0, import_promises7.stat)((0, import_node_path16.join)(tierPath, entry));
5990
6100
  if (!s.isDirectory()) continue;
5991
6101
  } catch {
5992
6102
  continue;
@@ -5997,17 +6107,17 @@ function createCleanMemoryCommand() {
5997
6107
  }
5998
6108
  }
5999
6109
  if (orphans.length === 0) {
6000
- console.log(import_picocolors18.default.dim("No orphaned memory directories found."));
6110
+ console.log(import_picocolors19.default.dim("No orphaned memory directories found."));
6001
6111
  return;
6002
6112
  }
6003
6113
  const maxPathLen = Math.max("Path".length, ...orphans.map((o) => o.path.length));
6004
6114
  console.log("");
6005
- console.log(import_picocolors18.default.bold("Orphaned memory directories:"));
6115
+ console.log(import_picocolors19.default.bold("Orphaned memory directories:"));
6006
6116
  console.log("");
6007
- console.log(" " + import_picocolors18.default.dim("Path".padEnd(maxPathLen + 2) + "Files".padStart(7) + " " + "Last Confirmed".padEnd(20) + "Size".padStart(10)));
6008
- console.log(" " + import_picocolors18.default.dim("-".repeat(maxPathLen + 2 + 7 + 2 + 20 + 10)));
6117
+ console.log(" " + import_picocolors19.default.dim("Path".padEnd(maxPathLen + 2) + "Files".padStart(7) + " " + "Last Confirmed".padEnd(20) + "Size".padStart(10)));
6118
+ console.log(" " + import_picocolors19.default.dim("-".repeat(maxPathLen + 2 + 7 + 2 + 20 + 10)));
6009
6119
  for (const o of orphans) {
6010
- const confirmed = o.lastConfirmed ?? import_picocolors18.default.dim("never");
6120
+ const confirmed = o.lastConfirmed ?? import_picocolors19.default.dim("never");
6011
6121
  console.log(" " + o.path.padEnd(maxPathLen + 2) + String(o.fileCount).padStart(7) + " " + String(confirmed).padEnd(20) + formatSize(o.size).padStart(10));
6012
6122
  }
6013
6123
  console.log("");
@@ -6023,78 +6133,78 @@ function createCleanMemoryCommand() {
6023
6133
  }
6024
6134
  }
6025
6135
  for (const orphan of orphans) {
6026
- await (0, import_promises7.rm)((0, import_node_path15.join)(memoryRoot, orphan.tier, orphan.scope), { recursive: true, force: true });
6136
+ await (0, import_promises7.rm)((0, import_node_path16.join)(memoryRoot, orphan.tier, orphan.scope), { recursive: true, force: true });
6027
6137
  }
6028
- console.log(import_picocolors18.default.green(`Deleted ${orphans.length} orphaned director${orphans.length === 1 ? "y" : "ies"}.`));
6138
+ console.log(import_picocolors19.default.green(`Deleted ${orphans.length} orphaned director${orphans.length === 1 ? "y" : "ies"}.`));
6029
6139
  });
6030
6140
  return cmd;
6031
6141
  }
6032
6142
 
6033
6143
  // src/commands/skills.ts
6034
6144
  var import_commander19 = require("commander");
6035
- var import_node_fs8 = require("fs");
6036
- var import_node_path16 = require("path");
6145
+ var import_node_fs9 = require("fs");
6146
+ var import_node_path17 = require("path");
6037
6147
  var import_node_url = require("url");
6038
6148
  var import_meta4 = {};
6039
6149
  function findPackageRoot(startDir) {
6040
- let current = (0, import_node_path16.resolve)(startDir);
6150
+ let current = (0, import_node_path17.resolve)(startDir);
6041
6151
  while (true) {
6042
- const packagePath = (0, import_node_path16.join)(current, "package.json");
6043
- if ((0, import_node_fs8.existsSync)(packagePath)) {
6152
+ const packagePath = (0, import_node_path17.join)(current, "package.json");
6153
+ if ((0, import_node_fs9.existsSync)(packagePath)) {
6044
6154
  try {
6045
- const pkg = JSON.parse((0, import_node_fs8.readFileSync)(packagePath, "utf-8"));
6155
+ const pkg = JSON.parse((0, import_node_fs9.readFileSync)(packagePath, "utf-8"));
6046
6156
  if (pkg.name === "agent-qa") {
6047
6157
  return current;
6048
6158
  }
6049
6159
  } catch {
6050
6160
  }
6051
6161
  }
6052
- const parent = (0, import_node_path16.dirname)(current);
6162
+ const parent = (0, import_node_path17.dirname)(current);
6053
6163
  if (parent === current) {
6054
- return (0, import_node_path16.resolve)(startDir);
6164
+ return (0, import_node_path17.resolve)(startDir);
6055
6165
  }
6056
6166
  current = parent;
6057
6167
  }
6058
6168
  }
6059
6169
  function hasSkillDirectories(dir) {
6060
- if (!(0, import_node_fs8.existsSync)(dir)) return false;
6170
+ if (!(0, import_node_fs9.existsSync)(dir)) return false;
6061
6171
  try {
6062
- return (0, import_node_fs8.readdirSync)(dir).some((entry) => {
6063
- const skillDir = (0, import_node_path16.join)(dir, entry);
6064
- return (0, import_node_fs8.statSync)(skillDir).isDirectory() && (0, import_node_fs8.existsSync)((0, import_node_path16.join)(skillDir, "SKILL.md"));
6172
+ return (0, import_node_fs9.readdirSync)(dir).some((entry) => {
6173
+ const skillDir = (0, import_node_path17.join)(dir, entry);
6174
+ return (0, import_node_fs9.statSync)(skillDir).isDirectory() && (0, import_node_fs9.existsSync)((0, import_node_path17.join)(skillDir, "SKILL.md"));
6065
6175
  });
6066
6176
  } catch {
6067
6177
  return false;
6068
6178
  }
6069
6179
  }
6070
- function resolveAgentQaSkillsDirectory(startDir = (0, import_node_path16.dirname)((0, import_node_url.fileURLToPath)(import_meta4.url))) {
6180
+ function resolveAgentQaSkillsDirectory(startDir = (0, import_node_path17.dirname)((0, import_node_url.fileURLToPath)(import_meta4.url))) {
6071
6181
  const packageRoot = findPackageRoot(startDir);
6072
- const packagedSkills = (0, import_node_path16.join)(packageRoot, "skills");
6182
+ const packagedSkills = (0, import_node_path17.join)(packageRoot, "skills");
6073
6183
  if (hasSkillDirectories(packagedSkills)) {
6074
6184
  return { path: packagedSkills, source: "package" };
6075
6185
  }
6076
- const sourceSkills = (0, import_node_path16.resolve)(packageRoot, "../..", "skills");
6186
+ const sourceSkills = (0, import_node_path17.resolve)(packageRoot, "../..", "skills");
6077
6187
  if (hasSkillDirectories(sourceSkills)) {
6078
6188
  return { path: sourceSkills, source: "source" };
6079
6189
  }
6080
6190
  return { path: packagedSkills, source: "missing" };
6081
6191
  }
6082
6192
  function parseSkillDescription(skillPath) {
6083
- const body = (0, import_node_fs8.readFileSync)(skillPath, "utf-8");
6193
+ const body = (0, import_node_fs9.readFileSync)(skillPath, "utf-8");
6084
6194
  const description = body.match(/^description:\s*(.+)$/m)?.[1]?.trim();
6085
6195
  return description?.replace(/^["']|["']$/g, "");
6086
6196
  }
6087
6197
  function listAgentQaSkills(skillsDir) {
6088
6198
  if (!hasSkillDirectories(skillsDir)) return [];
6089
- return (0, import_node_fs8.readdirSync)(skillsDir).filter((entry) => {
6090
- const skillDir = (0, import_node_path16.join)(skillsDir, entry);
6091
- return (0, import_node_fs8.statSync)(skillDir).isDirectory() && (0, import_node_fs8.existsSync)((0, import_node_path16.join)(skillDir, "SKILL.md"));
6199
+ return (0, import_node_fs9.readdirSync)(skillsDir).filter((entry) => {
6200
+ const skillDir = (0, import_node_path17.join)(skillsDir, entry);
6201
+ return (0, import_node_fs9.statSync)(skillDir).isDirectory() && (0, import_node_fs9.existsSync)((0, import_node_path17.join)(skillDir, "SKILL.md"));
6092
6202
  }).sort().map((entry) => {
6093
- const skillDir = (0, import_node_path16.join)(skillsDir, entry);
6203
+ const skillDir = (0, import_node_path17.join)(skillsDir, entry);
6094
6204
  return {
6095
6205
  name: entry,
6096
6206
  path: skillDir,
6097
- description: parseSkillDescription((0, import_node_path16.join)(skillDir, "SKILL.md"))
6207
+ description: parseSkillDescription((0, import_node_path17.join)(skillDir, "SKILL.md"))
6098
6208
  };
6099
6209
  });
6100
6210
  }