agent-qa 0.1.17 → 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.js CHANGED
@@ -598,10 +598,14 @@ function buildExampleTest(platform, variant) {
598
598
  const expectedUrl = variant === "pass" ? "https://www.iana.org/help/example-domains" : "https://www.iana.org/example-domains";
599
599
  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";
600
600
  const name = variant === "pass" ? "Example passing test" : "Example failing test";
601
+ const browserOverride = variant === "fail" && hasWeb(platform) ? `use:
602
+ browser:
603
+ headless: false
604
+ ` : "";
601
605
  return `test-id: ${testId}
602
606
  name: ${name}
603
607
  target: ${defaultExampleTargetName(platform)}
604
- steps:
608
+ ${browserOverride}steps:
605
609
  - Verify the page says "Example Domain"
606
610
  - Click on "Learn More"
607
611
  - Verify the page url is "${expectedUrl}"
@@ -2113,7 +2117,7 @@ init_config();
2113
2117
  import { randomUUID } from "crypto";
2114
2118
  import { resolve as resolvePath3 } from "path";
2115
2119
  import { Command as Command6 } from "commander";
2116
- import pc7 from "picocolors";
2120
+ import pc8 from "picocolors";
2117
2121
  import { ATTR_RUNNER, ATTR_TRIGGER, AUTH_STATE_SCHEMA_VERSION, buildInternalRunAttributes, DEFAULT_AGENT_QA_ARTIFACTS_DIR, DEFAULT_AGENT_QA_CACHE_DIR as DEFAULT_AGENT_QA_CACHE_DIR3, DEFAULT_AGENT_QA_VIDEOS_DIR, formatRunAttributesBlock, generateRunId, mergeRunAttributes, MobileSetupError, normalizeAuthStateUse, parseRunAttrFlags, redactAuthStateValue, resolveAuthStateForRun, resolveAuthStatePaths, resolveMemoryRoot, resolveMobileRunConfig, validateTrustedRunAttributes } from "@vostride/agent-qa-core";
2118
2122
  import { discoverWorkspaceFiles as discoverWorkspaceFiles2, isWorkspacePathMatch, resolveWorkspaceFileTarget, resolveWorkspacePaths as resolveWorkspacePaths2 } from "@vostride/agent-qa-core";
2119
2123
 
@@ -2209,6 +2213,88 @@ function resolveProviderCredentials(transport, localBindings) {
2209
2213
  // src/commands/run.ts
2210
2214
  init_llm_utils();
2211
2215
  import { isPathInsideDir } from "@vostride/agent-qa-core";
2216
+
2217
+ // src/version-notice.ts
2218
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
2219
+ import { join as join5 } from "path";
2220
+ import pc7 from "picocolors";
2221
+ import { getAgentQaUpdateStatus } from "@vostride/agent-qa-core";
2222
+ var RELEASES_URL = "https://github.com/vostride/agent-qa/releases";
2223
+ var UPDATE_COMMANDS = {
2224
+ pnpm: "pnpm add -D agent-qa@latest",
2225
+ npm: "npm install --save-dev agent-qa@latest",
2226
+ yarn: "yarn add --dev agent-qa@latest",
2227
+ bun: "bun add --dev agent-qa@latest"
2228
+ };
2229
+ var LOCKFILES = [
2230
+ { file: "pnpm-lock.yaml", packageManager: "pnpm" },
2231
+ { file: "package-lock.json", packageManager: "npm" },
2232
+ { file: "npm-shrinkwrap.json", packageManager: "npm" },
2233
+ { file: "yarn.lock", packageManager: "yarn" },
2234
+ { file: "bun.lock", packageManager: "bun" },
2235
+ { file: "bun.lockb", packageManager: "bun" }
2236
+ ];
2237
+ function shouldPrintAgentQaUpdateNotice(context) {
2238
+ return Boolean(
2239
+ context.reporterSelection.console && !context.reporterSelection.stdoutLive && context.liveEvents !== "true" && context.effectiveLogLevel !== "quiet" && context.effectiveLogLevel !== "silent"
2240
+ );
2241
+ }
2242
+ function inferAgentQaDevDependencyUpdateCommand(cwd = process.cwd()) {
2243
+ try {
2244
+ const packageJsonPath = join5(cwd, "package.json");
2245
+ if (!existsSync3(packageJsonPath)) return void 0;
2246
+ const manifest = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
2247
+ if (!isRecord(manifest) || !hasAgentQaDevDependency(manifest)) return void 0;
2248
+ const packageManager = inferPackageManager(manifest, cwd);
2249
+ return packageManager ? UPDATE_COMMANDS[packageManager] : void 0;
2250
+ } catch {
2251
+ return void 0;
2252
+ }
2253
+ }
2254
+ async function printAgentQaUpdateNoticeIfNeeded(context) {
2255
+ try {
2256
+ if (!shouldPrintAgentQaUpdateNotice(context)) return;
2257
+ const status = await getAgentQaUpdateStatus();
2258
+ const installedVersion = status.installedVersion.trim();
2259
+ const latestVersion = typeof status.latestVersion === "string" ? status.latestVersion.trim() : "";
2260
+ if (!status.updateAvailable || !latestVersion) return;
2261
+ const command = inferAgentQaDevDependencyUpdateCommand(context.cwd);
2262
+ const log = context.log ?? console.log;
2263
+ log();
2264
+ log(`${pc7.bold("Update available:")} agent-qa v${latestVersion}`);
2265
+ if (installedVersion) {
2266
+ log(pc7.dim(`Current version: v${installedVersion}`));
2267
+ }
2268
+ log(`Releases: ${pc7.cyan(RELEASES_URL)}`);
2269
+ if (command) {
2270
+ log(`Update: ${pc7.cyan(command)}`);
2271
+ }
2272
+ } catch {
2273
+ }
2274
+ }
2275
+ function hasAgentQaDevDependency(manifest) {
2276
+ const devDependencies = manifest.devDependencies;
2277
+ return isRecord(devDependencies) && Object.prototype.hasOwnProperty.call(devDependencies, "agent-qa");
2278
+ }
2279
+ function inferPackageManager(manifest, cwd) {
2280
+ if (typeof manifest.packageManager === "string") {
2281
+ return packageManagerFromSpecifier(manifest.packageManager);
2282
+ }
2283
+ const matchingLockfiles = LOCKFILES.filter(({ file }) => existsSync3(join5(cwd, file)));
2284
+ return matchingLockfiles.length === 1 ? matchingLockfiles[0].packageManager : void 0;
2285
+ }
2286
+ function packageManagerFromSpecifier(specifier) {
2287
+ const name = specifier.split("@")[0];
2288
+ if (name === "pnpm" || name === "npm" || name === "yarn" || name === "bun") {
2289
+ return name;
2290
+ }
2291
+ return void 0;
2292
+ }
2293
+ function isRecord(value) {
2294
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2295
+ }
2296
+
2297
+ // src/commands/run.ts
2212
2298
  var RUNTIME_ARTIFACTS_DIR = DEFAULT_AGENT_QA_ARTIFACTS_DIR || ".agent-qa/artifacts";
2213
2299
  var RUNTIME_CACHE_DIR = DEFAULT_AGENT_QA_CACHE_DIR3 || ".agent-qa/cache";
2214
2300
  var RUNTIME_VIDEOS_DIR = DEFAULT_AGENT_QA_VIDEOS_DIR || ".agent-qa/artifacts/videos";
@@ -2440,6 +2526,13 @@ async function flushAnalyticsRunReporter(reporter) {
2440
2526
  } catch {
2441
2527
  }
2442
2528
  }
2529
+ async function maybePrintPostRunUpdateNotice(context) {
2530
+ try {
2531
+ if (!shouldPrintAgentQaUpdateNotice(context)) return;
2532
+ await printAgentQaUpdateNoticeIfNeeded(context);
2533
+ } catch {
2534
+ }
2535
+ }
2443
2536
  async function captureSingleAnalyticsResult(reporter, result) {
2444
2537
  if (!reporter?.onRunEnd) {
2445
2538
  await flushAnalyticsRunReporter(reporter);
@@ -2460,14 +2553,14 @@ async function captureSingleAnalyticsResult(reporter, result) {
2460
2553
  function formatParseErrors(errors) {
2461
2554
  for (const err of errors) {
2462
2555
  const location = `${err.file}:${err.line}:${err.column}`;
2463
- const severity = err.severity === "error" ? pc7.red("error") : pc7.yellow("warning");
2556
+ const severity = err.severity === "error" ? pc8.red("error") : pc8.yellow("warning");
2464
2557
  console.error(`${severity}: ${err.message}`);
2465
- console.error(` ${pc7.blue("-->")} ${location}`);
2558
+ console.error(` ${pc8.blue("-->")} ${location}`);
2466
2559
  if (err.source) {
2467
- console.error(` ${pc7.blue("|")} ${err.source}`);
2560
+ console.error(` ${pc8.blue("|")} ${err.source}`);
2468
2561
  }
2469
2562
  if (err.suggestion) {
2470
- console.error(` ${pc7.blue("=")} ${pc7.bold("help")}: ${err.suggestion}`);
2563
+ console.error(` ${pc8.blue("=")} ${pc8.bold("help")}: ${err.suggestion}`);
2471
2564
  }
2472
2565
  console.error();
2473
2566
  }
@@ -2483,14 +2576,14 @@ function printRunId(runId) {
2483
2576
  }
2484
2577
  function printMemoryStatus(log) {
2485
2578
  const parts = [];
2486
- if (log.added > 0) parts.push(pc7.green(`${log.added} added`));
2579
+ if (log.added > 0) parts.push(pc8.green(`${log.added} added`));
2487
2580
  if (log.confirmed > 0) parts.push(`${log.confirmed} confirmed`);
2488
- if (log.deprecated > 0) parts.push(pc7.yellow(`${log.deprecated} deprecated`));
2581
+ if (log.deprecated > 0) parts.push(pc8.yellow(`${log.deprecated} deprecated`));
2489
2582
  if (parts.length === 0) parts.push("no changes");
2490
2583
  const secs = log.curatorDuration >= 1e3 ? `${Math.round(log.curatorDuration / 1e3)}s` : `${log.curatorDuration}ms`;
2491
- console.log(` ${pc7.dim("Memory:")} ${parts.join(", ")} ${pc7.dim(`(${secs})`)}`);
2584
+ console.log(` ${pc8.dim("Memory:")} ${parts.join(", ")} ${pc8.dim(`(${secs})`)}`);
2492
2585
  for (const err of log.errors) {
2493
- console.log(` ${pc7.dim("Memory:")} ${pc7.yellow(`warning -- ${err}`)}`);
2586
+ console.log(` ${pc8.dim("Memory:")} ${pc8.yellow(`warning -- ${err}`)}`);
2494
2587
  }
2495
2588
  }
2496
2589
  function isGlobLikePattern(value) {
@@ -2562,21 +2655,21 @@ function buildHooksArtifact(hooks) {
2562
2655
  async function loadRuntimeSecrets(input3) {
2563
2656
  const configuredSecretsFile = input3.config.workspace?.secretsFile;
2564
2657
  if (typeof configuredSecretsFile !== "string" || configuredSecretsFile.trim().length === 0) {
2565
- console.error(pc7.red("Error: workspace.secretsFile is required. Run `agent-qa init` or set it in agent-qa.config.yaml."));
2658
+ console.error(pc8.red("Error: workspace.secretsFile is required. Run `agent-qa init` or set it in agent-qa.config.yaml."));
2566
2659
  process.exit(1);
2567
2660
  }
2568
2661
  const secretsPath = input3.secretsFilePath ?? resolvePath3(input3.configDir, configuredSecretsFile);
2569
2662
  if (!input3.existsSync(secretsPath)) {
2570
- console.error(pc7.red(`Error: Secrets file not found: ${secretsPath}`));
2571
- console.error(pc7.dim("Create the file before running tests. It may be empty, but it must exist."));
2663
+ console.error(pc8.red(`Error: Secrets file not found: ${secretsPath}`));
2664
+ console.error(pc8.dim("Create the file before running tests. It may be empty, but it must exist."));
2572
2665
  process.exit(1);
2573
2666
  }
2574
2667
  let secretsContent;
2575
2668
  try {
2576
2669
  secretsContent = input3.readFileSync(secretsPath, "utf-8");
2577
2670
  } catch {
2578
- console.error(pc7.red(`Error: Secrets file could not be read: ${secretsPath}`));
2579
- console.error(pc7.dim("Check the path and file permissions before running tests."));
2671
+ console.error(pc8.red(`Error: Secrets file could not be read: ${secretsPath}`));
2672
+ console.error(pc8.dim("Check the path and file permissions before running tests."));
2580
2673
  process.exit(1);
2581
2674
  }
2582
2675
  try {
@@ -2593,7 +2686,7 @@ async function loadRuntimeSecrets(input3) {
2593
2686
  };
2594
2687
  } catch (err) {
2595
2688
  const message = err instanceof Error ? err.message : String(err);
2596
- console.error(pc7.red(`Error: Secrets file is invalid: ${message}`));
2689
+ console.error(pc8.red(`Error: Secrets file is invalid: ${message}`));
2597
2690
  process.exit(1);
2598
2691
  }
2599
2692
  }
@@ -2724,7 +2817,7 @@ async function resolveSelectedAuthStateForRun(input3) {
2724
2817
  target: { platform: input3.resolvedTarget.platform }
2725
2818
  });
2726
2819
  } catch (err) {
2727
- console.error(pc7.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2820
+ console.error(pc8.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2728
2821
  process.exit(2);
2729
2822
  }
2730
2823
  }
@@ -2739,7 +2832,7 @@ function resolveAuthStateCapturePathsForRun(input3) {
2739
2832
  target: { platform: input3.resolvedTarget.platform }
2740
2833
  });
2741
2834
  } catch (err) {
2742
- console.error(pc7.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2835
+ console.error(pc8.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
2743
2836
  process.exit(2);
2744
2837
  }
2745
2838
  }
@@ -2832,7 +2925,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2832
2925
  const dashboardCfg = config.services?.dashboard;
2833
2926
  const reporterSelectionResult = resolveReporterSelection(opts, Boolean(dashboardCfg));
2834
2927
  if (reporterSelectionResult.error) {
2835
- console.error(pc7.red(`Error: ${reporterSelectionResult.error}`));
2928
+ console.error(pc8.red(`Error: ${reporterSelectionResult.error}`));
2836
2929
  process.exit(2);
2837
2930
  }
2838
2931
  const reporterSelection = reporterSelectionResult.selection;
@@ -2848,7 +2941,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2848
2941
  activeSuiteDbs.add(dashboardDb);
2849
2942
  return { dashboardDb, logStorage: dashboardDb };
2850
2943
  } catch (err) {
2851
- console.warn(pc7.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
2944
+ console.warn(pc8.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
2852
2945
  return {};
2853
2946
  }
2854
2947
  };
@@ -2897,7 +2990,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2897
2990
  const suiteMembers = [];
2898
2991
  for (const { test: relativePath, id: suiteEntryId } of suite.tests) {
2899
2992
  if (!isPathInsideDir(relativePath, configDir)) {
2900
- console.error(pc7.red(`Path traversal rejected: ${relativePath}`));
2993
+ console.error(pc8.red(`Path traversal rejected: ${relativePath}`));
2901
2994
  const runId = createSuiteRunId();
2902
2995
  if (dashboardDb) {
2903
2996
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2935,7 +3028,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2935
3028
  const fileContent = await readFile5(absolutePath, "utf-8");
2936
3029
  const parseResult = parseTestFile2(fileContent, absolutePath);
2937
3030
  if (parseResult.errors.length > 0) {
2938
- console.error(pc7.red(`Parse errors in ${relativePath}:`));
3031
+ console.error(pc8.red(`Parse errors in ${relativePath}:`));
2939
3032
  formatParseErrors(parseResult.errors);
2940
3033
  const runId = createSuiteRunId();
2941
3034
  if (dashboardDb) {
@@ -2977,7 +3070,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
2977
3070
  process.exit(2);
2978
3071
  }
2979
3072
  if (parseResult.tests.length === 0) {
2980
- console.error(pc7.red(`No test definition found in ${relativePath}`));
3073
+ console.error(pc8.red(`No test definition found in ${relativePath}`));
2981
3074
  const runId = createSuiteRunId();
2982
3075
  if (dashboardDb) {
2983
3076
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -3014,12 +3107,12 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3014
3107
  const testDef = parseResult.tests[0];
3015
3108
  const childAuthStateUse = getSelectedAuthStateUse(testDef.use);
3016
3109
  if (suiteAuthStateUse && childAuthStateUse && childAuthStateUse.name !== suiteAuthStateUse.name) {
3017
- console.error(pc7.red(`Suite auth state "${suiteAuthStateUse.name}" conflicts with child test auth state "${childAuthStateUse.name}". Use one primary auth state per suite.`));
3110
+ console.error(pc8.red(`Suite auth state "${suiteAuthStateUse.name}" conflicts with child test auth state "${childAuthStateUse.name}". Use one primary auth state per suite.`));
3018
3111
  process.exit(2);
3019
3112
  }
3020
3113
  if (testDef["test-id"] && testDef["test-id"] !== suiteEntryId) {
3021
3114
  const mismatchMsg = `ID mismatch in suite "${suite.name}": test file ${relativePath} has test-id "${testDef["test-id"]}" but suite entry specifies id "${suiteEntryId}"`;
3022
- console.error(pc7.red(mismatchMsg));
3115
+ console.error(pc8.red(mismatchMsg));
3023
3116
  const runId = createSuiteRunId();
3024
3117
  if (dashboardDb) {
3025
3118
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -3270,7 +3363,7 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3270
3363
  curatorLockTimeout: suiteMemoryConfig?.curatorLockTimeout
3271
3364
  });
3272
3365
  } catch (err) {
3273
- console.warn(` ${pc7.dim("Memory:")} init error -- ${err.message}`);
3366
+ console.warn(` ${pc8.dim("Memory:")} init error -- ${err.message}`);
3274
3367
  }
3275
3368
  if (suiteMemoryConfig?.circuitBreakerEnabled !== false) {
3276
3369
  const { CircuitBreaker } = await import("@vostride/agent-qa-core");
@@ -3415,19 +3508,19 @@ async function executeSuites(suiteFiles, opts, config, globalOpts, configContent
3415
3508
  const batchOutcome = await flushSuiteParents();
3416
3509
  if (batchOutcome.cancelled || shutdownRequested) break;
3417
3510
  if (opts.bail && batchOutcome.failed) {
3418
- console.log(pc7.yellow("\nBailing out \u2014 stopping after first failed suite"));
3511
+ console.log(pc8.yellow("\nBailing out \u2014 stopping after first failed suite"));
3419
3512
  break;
3420
3513
  }
3421
3514
  const outcome = await runOneSuiteFile(suiteFile, suite);
3422
3515
  if (outcome.cancelled || shutdownRequested) break;
3423
3516
  if (opts.bail && outcome.failed) {
3424
- console.log(pc7.yellow("\nBailing out \u2014 stopping after first failed suite"));
3517
+ console.log(pc8.yellow("\nBailing out \u2014 stopping after first failed suite"));
3425
3518
  break;
3426
3519
  }
3427
3520
  }
3428
3521
  const finalBatchOutcome = await flushSuiteParents();
3429
3522
  if (opts.bail && finalBatchOutcome.failed) {
3430
- console.log(pc7.yellow("\nBailing out \u2014 stopping after first failed suite"));
3523
+ console.log(pc8.yellow("\nBailing out \u2014 stopping after first failed suite"));
3431
3524
  }
3432
3525
  process.removeListener("SIGINT", handleShutdown);
3433
3526
  process.removeListener("SIGTERM", handleShutdown);
@@ -3440,7 +3533,7 @@ function createRunCommand() {
3440
3533
  try {
3441
3534
  const modeFlags = [opts.test, opts.suite, opts.all].filter(Boolean).length;
3442
3535
  if (modeFlags > 1) {
3443
- console.error(pc7.red("Error: --test, --suite, and --all are mutually exclusive."));
3536
+ console.error(pc8.red("Error: --test, --suite, and --all are mutually exclusive."));
3444
3537
  process.exit(1);
3445
3538
  }
3446
3539
  const program2 = command.parent;
@@ -3468,7 +3561,7 @@ function createRunCommand() {
3468
3561
  } catch {
3469
3562
  }
3470
3563
  const { parseEnvFile } = await import("@vostride/agent-qa-core");
3471
- const { readFileSync: readFileSync5, existsSync: existsSync8 } = await import("fs");
3564
+ const { readFileSync: readFileSync6, existsSync: existsSync9 } = await import("fs");
3472
3565
  const configDir = workspacePaths.configDir;
3473
3566
  const cliVars = parseVarFlags(opts.var);
3474
3567
  const inheritedContextRunId = process.env.AGENT_QA_RUN_ID ?? process.env.AGENT_QA_SUITE_QUEUE_ID ?? process.env.AGENT_QA_PARENT_RUN_ID;
@@ -3481,7 +3574,7 @@ function createRunCommand() {
3481
3574
  console.warn(`Warning: duplicate --run-attr key "${duplicateKey}"; using last value`);
3482
3575
  }
3483
3576
  } catch (err) {
3484
- console.error(pc7.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3577
+ console.error(pc8.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3485
3578
  process.exit(2);
3486
3579
  }
3487
3580
  const inlineVars = {};
@@ -3489,37 +3582,37 @@ function createRunCommand() {
3489
3582
  config,
3490
3583
  configDir,
3491
3584
  secretsFilePath: workspacePaths.secretsFile.absolutePath,
3492
- readFileSync: readFileSync5,
3493
- existsSync: existsSync8
3585
+ readFileSync: readFileSync6,
3586
+ existsSync: existsSync9
3494
3587
  });
3495
3588
  let envFileVars = {};
3496
3589
  let rawEnvFileContent = null;
3497
3590
  let resolvedEnvFilePath = null;
3498
3591
  resolvedEnvFilePath = workspacePaths.envFile.absolutePath;
3499
- if (!existsSync8(workspacePaths.envFile.absolutePath)) {
3500
- console.error(pc7.red(`Error: Env file not found: ${workspacePaths.envFile.absolutePath}`));
3592
+ if (!existsSync9(workspacePaths.envFile.absolutePath)) {
3593
+ console.error(pc8.red(`Error: Env file not found: ${workspacePaths.envFile.absolutePath}`));
3501
3594
  process.exit(1);
3502
3595
  }
3503
3596
  try {
3504
- rawEnvFileContent = readFileSync5(workspacePaths.envFile.absolutePath, "utf-8");
3597
+ rawEnvFileContent = readFileSync6(workspacePaths.envFile.absolutePath, "utf-8");
3505
3598
  envFileVars = parseEnvFile(rawEnvFileContent);
3506
3599
  } catch {
3507
- console.error(pc7.red(`Error: Env file could not be read: ${workspacePaths.envFile.absolutePath}`));
3600
+ console.error(pc8.red(`Error: Env file could not be read: ${workspacePaths.envFile.absolutePath}`));
3508
3601
  process.exit(1);
3509
3602
  }
3510
3603
  let resolvedHooks;
3511
3604
  let sandboxOptions;
3512
3605
  const hooksFilePath = workspacePaths.hooksFile.absolutePath;
3513
- if (!existsSync8(hooksFilePath)) {
3514
- console.error(pc7.red(`Error: Hooks file not found: ${hooksFilePath}`));
3606
+ if (!existsSync9(hooksFilePath)) {
3607
+ console.error(pc8.red(`Error: Hooks file not found: ${hooksFilePath}`));
3515
3608
  process.exit(1);
3516
3609
  }
3517
3610
  try {
3518
3611
  const { parseHooksFile } = await import("@vostride/agent-qa-core");
3519
3612
  const { hooks, errors } = await parseHooksFile(hooksFilePath);
3520
3613
  if (errors.length > 0) {
3521
- console.error(pc7.red("Hooks configuration errors:"));
3522
- for (const err of errors) console.error(pc7.red(` - ${err}`));
3614
+ console.error(pc8.red("Hooks configuration errors:"));
3615
+ for (const err of errors) console.error(pc8.red(` - ${err}`));
3523
3616
  process.exit(1);
3524
3617
  }
3525
3618
  resolvedHooks = new Map(hooks.map((h) => [h.id, h]));
@@ -3528,8 +3621,8 @@ function createRunCommand() {
3528
3621
  secretRedactor: runtimeSecrets.secretRedactor
3529
3622
  };
3530
3623
  } catch (err) {
3531
- console.error(pc7.red(`Error: Hooks file could not be read: ${hooksFilePath}`));
3532
- if (err instanceof Error && err.message) console.error(pc7.dim(err.message));
3624
+ console.error(pc8.red(`Error: Hooks file could not be read: ${hooksFilePath}`));
3625
+ if (err instanceof Error && err.message) console.error(pc8.dim(err.message));
3533
3626
  process.exit(1);
3534
3627
  }
3535
3628
  let agentRulesContent;
@@ -3537,7 +3630,7 @@ function createRunCommand() {
3537
3630
  try {
3538
3631
  agentRulesContent = await readFileAsync(workspacePaths.agentRules.absolutePath, "utf-8");
3539
3632
  } catch {
3540
- console.error(pc7.red(`Error: Agent rules file not found: ${workspacePaths.agentRules.absolutePath}`));
3633
+ console.error(pc8.red(`Error: Agent rules file not found: ${workspacePaths.agentRules.absolutePath}`));
3541
3634
  process.exit(1);
3542
3635
  }
3543
3636
  const effectiveLogLevel = globalOpts.logLevel ?? (globalOpts.verbose ? "debug" : void 0) ?? (globalOpts.quiet ? "silent" : void 0) ?? config.services?.logging?.level ?? "warn";
@@ -3549,21 +3642,21 @@ function createRunCommand() {
3549
3642
  discoveredTestFiles = selected.tests;
3550
3643
  discoveredSuiteFiles = selected.suites;
3551
3644
  } catch (err) {
3552
- console.error(pc7.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3645
+ console.error(pc8.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
3553
3646
  process.exit(1);
3554
3647
  }
3555
3648
  if (discoveredTestFiles.length === 0 && discoveredSuiteFiles.length === 0) {
3556
3649
  const patternKind = patterns.every((pattern) => classifyRunPattern(pattern) === "suite") ? "suite" : "test";
3557
- console.error(pc7.red(`Error: No ${patternKind} files found matching patterns:`));
3558
- for (const p of patterns) console.error(pc7.red(` ${p}`));
3650
+ console.error(pc8.red(`Error: No ${patternKind} files found matching patterns:`));
3651
+ for (const p of patterns) console.error(pc8.red(` ${p}`));
3559
3652
  process.exit(2);
3560
3653
  }
3561
3654
  } else if (opts.suite) {
3562
3655
  discoveredSuiteFiles = (await discoverWorkspaceFiles2({ workspace: workspacePaths, kind: "suite" })).map((record) => record.absolutePath);
3563
3656
  if (discoveredSuiteFiles.length === 0) {
3564
- console.error(pc7.red("Error: No suite files found matching workspace.suiteMatch"));
3657
+ console.error(pc8.red("Error: No suite files found matching workspace.suiteMatch"));
3565
3658
  for (const p of workspacePaths.suiteMatch) {
3566
- console.error(pc7.red(` ${p}`));
3659
+ console.error(pc8.red(` ${p}`));
3567
3660
  }
3568
3661
  process.exit(2);
3569
3662
  }
@@ -3571,26 +3664,36 @@ function createRunCommand() {
3571
3664
  discoveredTestFiles = (await discoverWorkspaceFiles2({ workspace: workspacePaths, kind: "test" })).map((record) => record.absolutePath);
3572
3665
  discoveredSuiteFiles = (await discoverWorkspaceFiles2({ workspace: workspacePaths, kind: "suite" })).map((record) => record.absolutePath);
3573
3666
  if (discoveredTestFiles.length === 0 && discoveredSuiteFiles.length === 0) {
3574
- console.error(pc7.red("Error: No test or suite files found. Check workspace.testMatch and workspace.suiteMatch in agent-qa.config.yaml"));
3667
+ console.error(pc8.red("Error: No test or suite files found. Check workspace.testMatch and workspace.suiteMatch in agent-qa.config.yaml"));
3575
3668
  process.exit(2);
3576
3669
  }
3577
3670
  } else {
3578
3671
  if (!workspacePaths.testMatch || workspacePaths.testMatch.length === 0) {
3579
- console.error(pc7.red("Error: No testMatch patterns in config. Add workspace.testMatch to agent-qa.config.yaml."));
3672
+ console.error(pc8.red("Error: No testMatch patterns in config. Add workspace.testMatch to agent-qa.config.yaml."));
3580
3673
  process.exit(2);
3581
3674
  }
3582
3675
  discoveredTestFiles = (await discoverWorkspaceFiles2({ workspace: workspacePaths, kind: "test" })).map((record) => record.absolutePath);
3583
3676
  if (discoveredTestFiles.length === 0) {
3584
- console.error(pc7.red("Error: No test files found matching workspace.testMatch"));
3677
+ console.error(pc8.red("Error: No test files found matching workspace.testMatch"));
3585
3678
  for (const p of workspacePaths.testMatch) {
3586
- console.error(pc7.red(` ${p}`));
3679
+ console.error(pc8.red(` ${p}`));
3587
3680
  }
3588
3681
  process.exit(2);
3589
3682
  }
3590
3683
  }
3591
3684
  if (discoveredSuiteFiles.length > 0 && discoveredTestFiles.length === 0) {
3592
3685
  const hasFailed2 = await executeSuites(discoveredSuiteFiles, opts, config, globalOpts, configContent, effectiveLogLevel, { envFileVars, inlineVars, cliVars, rawEnvFileContent, resolvedEnvFilePath, userRunAttributes, inheritedRunAttributes, ...runtimeSecrets }, resolvedHooks && sandboxOptions ? { resolvedHooks, sandboxOptions } : void 0);
3593
- process.exit(hasFailed2 ? 1 : 0);
3686
+ const exitCode2 = hasFailed2 ? 1 : 0;
3687
+ const suiteReporterSelection = resolveReporterSelection(opts, Boolean(config.services?.dashboard)).selection;
3688
+ if (suiteReporterSelection) {
3689
+ await maybePrintPostRunUpdateNotice({
3690
+ reporterSelection: suiteReporterSelection,
3691
+ effectiveLogLevel,
3692
+ liveEvents: process.env.AGENT_QA_LIVE_EVENTS,
3693
+ cwd: process.cwd()
3694
+ });
3695
+ }
3696
+ process.exit(exitCode2);
3594
3697
  }
3595
3698
  let suitesFailed = false;
3596
3699
  if (discoveredSuiteFiles.length > 0 && discoveredTestFiles.length > 0) {
@@ -3598,7 +3701,7 @@ function createRunCommand() {
3598
3701
  }
3599
3702
  const files = discoveredTestFiles;
3600
3703
  if (opts.listTests) {
3601
- console.log(pc7.bold(`
3704
+ console.log(pc8.bold(`
3602
3705
  Discovered ${files.length} test file(s):
3603
3706
  `));
3604
3707
  for (const file of files) {
@@ -3610,7 +3713,7 @@ Discovered ${files.length} test file(s):
3610
3713
  const dashboardCfg2 = config.services?.dashboard;
3611
3714
  const reporterSelectionResult = resolveReporterSelection(opts, Boolean(dashboardCfg2));
3612
3715
  if (reporterSelectionResult.error) {
3613
- console.error(pc7.red(`Error: ${reporterSelectionResult.error}`));
3716
+ console.error(pc8.red(`Error: ${reporterSelectionResult.error}`));
3614
3717
  process.exit(2);
3615
3718
  }
3616
3719
  const reporterSelection = reporterSelectionResult.selection;
@@ -3627,13 +3730,13 @@ Discovered ${files.length} test file(s):
3627
3730
  logStorage = dashboardDb;
3628
3731
  _crashDb = dashboardDb;
3629
3732
  } catch (err) {
3630
- console.warn(pc7.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3733
+ console.warn(pc8.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3631
3734
  }
3632
3735
  }
3633
3736
  const { parseAllTests, formatParseError } = await import("@vostride/agent-qa-core");
3634
3737
  const parseResult = await parseAllTests(files);
3635
3738
  if (parseResult.errors.length > 0) {
3636
- console.error(pc7.red(`Found ${parseResult.errors.length} parse error(s):
3739
+ console.error(pc8.red(`Found ${parseResult.errors.length} parse error(s):
3637
3740
  `));
3638
3741
  for (const err of parseResult.errors) {
3639
3742
  console.error(formatParseError(err));
@@ -3644,8 +3747,8 @@ Discovered ${files.length} test file(s):
3644
3747
  const now = (/* @__PURE__ */ new Date()).toISOString();
3645
3748
  const { basename: basename2 } = await import("path");
3646
3749
  const errorText = parseResult.errors.map((e) => formatParseError(e)).join("\n").replace(/\x1b\[[0-9;]*m/g, "");
3647
- const { readFileSync: readFileSync6 } = await import("fs");
3648
- const rawContent = readFileSync6(files[0], "utf-8");
3750
+ const { readFileSync: readFileSync7 } = await import("fs");
3751
+ const rawContent = readFileSync7(files[0], "utf-8");
3649
3752
  const nameMatch = rawContent.match(/^\s*name:\s*(.+)$/m);
3650
3753
  const targetMatch = rawContent.match(/^\s*target:\s*(.+)$/m);
3651
3754
  let detectedPlatform = "web";
@@ -3729,17 +3832,17 @@ Discovered ${files.length} test file(s):
3729
3832
  }
3730
3833
  const filtered = parseResult.tests;
3731
3834
  if (filtered.length === 0) {
3732
- console.log(pc7.yellow("No tests match filters"));
3835
+ console.log(pc8.yellow("No tests match filters"));
3733
3836
  process.exit(0);
3734
3837
  }
3735
3838
  if (opts.dryRun) {
3736
- console.log(pc7.bold(`
3839
+ console.log(pc8.bold(`
3737
3840
  Found ${filtered.length} test(s):
3738
3841
  `));
3739
3842
  for (const test of filtered) {
3740
- console.log(` ${pc7.green("\u25CF")} ${test.name}`);
3843
+ console.log(` ${pc8.green("\u25CF")} ${test.name}`);
3741
3844
  if (opts.configDebug) {
3742
- console.log(pc7.bold(`
3845
+ console.log(pc8.bold(`
3743
3846
  Config for: ${test.name}`));
3744
3847
  console.log(formatConfigDebug(config, test.use, flagOverrides));
3745
3848
  console.log();
@@ -3789,7 +3892,7 @@ Found ${filtered.length} test(s):
3789
3892
  }
3790
3893
  }));
3791
3894
  } catch (err) {
3792
- console.warn(pc7.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3895
+ console.warn(pc8.yellow(`Warning: Could not load dashboard reporter: ${err instanceof Error ? err.message : String(err)}`));
3793
3896
  }
3794
3897
  }
3795
3898
  const analyticsReporter = createAnalyticsRunReporter({ config, surface: "cli" });
@@ -3883,7 +3986,7 @@ Found ${filtered.length} test(s):
3883
3986
  const testMergedConfig = { ...config, use: mergedUse };
3884
3987
  const effectiveCacheEnabled = opts.cache !== false && mergedUse.cache !== false;
3885
3988
  if (opts.configDebug) {
3886
- console.log(pc7.bold(`
3989
+ console.log(pc8.bold(`
3887
3990
  Config for: ${test.name}`));
3888
3991
  console.log(formatConfigDebug(config, test.use, testFlagOverrides));
3889
3992
  console.log();
@@ -4008,7 +4111,7 @@ Config for: ${test.name}`));
4008
4111
  });
4009
4112
  }
4010
4113
  if (effectiveLogLevel === "debug") {
4011
- console.log(pc7.dim(` Platform: ${testPlatform}${useFarm ? ` (farm: ${testResolvedDevice?.transport})` : ""}${testPlatform !== "web" ? " (adapter re-created)" : ""}`));
4114
+ console.log(pc8.dim(` Platform: ${testPlatform}${useFarm ? ` (farm: ${testResolvedDevice?.transport})` : ""}${testPlatform !== "web" ? " (adapter re-created)" : ""}`));
4012
4115
  }
4013
4116
  }
4014
4117
  const mergedForLLM = { registry: config.registry, use: testMergedConfig.use ?? config.use };
@@ -4019,7 +4122,7 @@ Config for: ${test.name}`));
4019
4122
  process.env.AGENT_QA_LLM_MODEL = plannerCfg.model;
4020
4123
  process.env.AGENT_QA_LLM_PROVIDER = plannerCfg.provider;
4021
4124
  if (effectiveLogLevel === "debug") {
4022
- console.log(pc7.dim(` Model: ${plannerCfg.model} (${plannerCfg.provider})`));
4125
+ console.log(pc8.dim(` Model: ${plannerCfg.model} (${plannerCfg.provider})`));
4023
4126
  }
4024
4127
  const plannerModel = await createModel(plannerModelConfig);
4025
4128
  const verifierModel = await createModel(verifierModelConfig);
@@ -4186,7 +4289,7 @@ Config for: ${test.name}`));
4186
4289
  const testId = testDef["test-id"] ?? testDef.name;
4187
4290
  memoryInitParams = { product, testId, memoryRoot };
4188
4291
  } catch (err) {
4189
- console.warn(` ${pc7.dim("Memory:")} init error -- ${err.message}`);
4292
+ console.warn(` ${pc8.dim("Memory:")} init error -- ${err.message}`);
4190
4293
  }
4191
4294
  }
4192
4295
  const result = await runTestWithRetry(testDef, {
@@ -4300,7 +4403,7 @@ Config for: ${test.name}`));
4300
4403
  try {
4301
4404
  const { shouldAblate, collectAllInjectedIds, deprecateOnFailure } = await import("@vostride/agent-qa-core");
4302
4405
  if (shouldAblate(result, memoryProvider)) {
4303
- console.log(` ${pc7.dim("Memory:")} ablation retry -- re-running without memory...`);
4406
+ console.log(` ${pc8.dim("Memory:")} ablation retry -- re-running without memory...`);
4304
4407
  const ablationAdapter = await createPlatformAdapter(testPlatform);
4305
4408
  const mergedBrowser = mergedUse.browser;
4306
4409
  const ablationPlatformConfig = buildPlatformConfig(testPlatform, testResolvedDevice, testTimeoutsForSetup, mergedBrowser ?? config.use?.browser, testMergedConfig.use?.logCapture ?? config.use?.logCapture, testFarmSession, testMobileResolved);
@@ -4348,7 +4451,7 @@ Config for: ${test.name}`));
4348
4451
  circuitBreaker.record({ withMemory: false, passed: ablationResult.status === "passed" });
4349
4452
  }
4350
4453
  if (ablationResult.status === "passed") {
4351
- console.log(` ${pc7.dim("Memory:")} ablation confirmed memory caused failure -- penalizing observations`);
4454
+ console.log(` ${pc8.dim("Memory:")} ablation confirmed memory caused failure -- penalizing observations`);
4352
4455
  const injectedMap = collectAllInjectedIds(result, memoryProvider);
4353
4456
  await deprecateOnFailure({
4354
4457
  testResult: result,
@@ -4359,14 +4462,14 @@ Config for: ${test.name}`));
4359
4462
  });
4360
4463
  ablationHandledDeprecation = true;
4361
4464
  } else {
4362
- console.log(` ${pc7.dim("Memory:")} ablation retry also failed -- memory not the cause`);
4465
+ console.log(` ${pc8.dim("Memory:")} ablation retry also failed -- memory not the cause`);
4363
4466
  }
4364
4467
  } finally {
4365
4468
  await ablationAdapter.cleanup();
4366
4469
  }
4367
4470
  }
4368
4471
  } catch (err) {
4369
- console.warn(` ${pc7.dim("Memory:")} ablation error -- ${err.message}`);
4472
+ console.warn(` ${pc8.dim("Memory:")} ablation error -- ${err.message}`);
4370
4473
  }
4371
4474
  }
4372
4475
  if (memoryProvider && memoryConfig?.curatorEnabled !== false && !ablationHandledDeprecation) {
@@ -4400,7 +4503,7 @@ Config for: ${test.name}`));
4400
4503
  }
4401
4504
  }
4402
4505
  } catch (err) {
4403
- console.warn(` ${pc7.dim("Memory:")} curator error -- ${err.message}`);
4506
+ console.warn(` ${pc8.dim("Memory:")} curator error -- ${err.message}`);
4404
4507
  }
4405
4508
  }
4406
4509
  if (testAuthStateUse?.capture === true) {
@@ -4414,12 +4517,12 @@ Config for: ${test.name}`));
4414
4517
  }
4415
4518
  if (circuitBreaker?.isTripped() && !circuitBreakerTripped) {
4416
4519
  circuitBreakerTripped = true;
4417
- console.log(` ${pc7.yellow("Memory: circuit breaker tripped -- disabling memory injection for remaining tests")}`);
4520
+ console.log(` ${pc8.yellow("Memory: circuit breaker tripped -- disabling memory injection for remaining tests")}`);
4418
4521
  }
4419
4522
  if (result.status === "failed" && !authStateCaptureFailed && actionCache && effectiveCacheEnabled && result.steps.length > 0) {
4420
4523
  const { hashStepInstruction: hashStepInstruction2 } = await import("@vostride/agent-qa-core");
4421
4524
  const { rm: rm3 } = await import("fs/promises");
4422
- const { resolve: resolve9, join: join8 } = await import("path");
4525
+ const { resolve: resolve9, join: join9 } = await import("path");
4423
4526
  const cacheDir = resolve9(configDir, config.services?.cache?.dir ?? RUNTIME_CACHE_DIR);
4424
4527
  const cacheLog = logger.createScopedLogger("cache");
4425
4528
  let purged = 0;
@@ -4427,7 +4530,7 @@ Config for: ${test.name}`));
4427
4530
  const step = result.steps[i];
4428
4531
  const stepHash = hashStepInstruction2(step.name, testPlatform, configContent, testFileContent, i);
4429
4532
  try {
4430
- await rm3(join8(cacheDir, stepHash), { recursive: true, force: true });
4533
+ await rm3(join9(cacheDir, stepHash), { recursive: true, force: true });
4431
4534
  purged++;
4432
4535
  } catch {
4433
4536
  }
@@ -4499,13 +4602,13 @@ Config for: ${test.name}`));
4499
4602
  }
4500
4603
  const parallelBatchFailed = await flushParallelRuns();
4501
4604
  if (opts.bail && parallelBatchFailed) {
4502
- console.log(pc7.yellow("\nBailing out \u2014 stopping after first failure"));
4605
+ console.log(pc8.yellow("\nBailing out \u2014 stopping after first failure"));
4503
4606
  bailTriggered = true;
4504
4607
  break;
4505
4608
  }
4506
4609
  const outcome = await runOneDirectTest(test);
4507
4610
  if (opts.bail && outcome.failed) {
4508
- console.log(pc7.yellow("\nBailing out \u2014 stopping after first failure"));
4611
+ console.log(pc8.yellow("\nBailing out \u2014 stopping after first failure"));
4509
4612
  bailTriggered = true;
4510
4613
  break;
4511
4614
  }
@@ -4513,7 +4616,7 @@ Config for: ${test.name}`));
4513
4616
  if (!bailTriggered) {
4514
4617
  const parallelBatchFailed = await flushParallelRuns();
4515
4618
  if (opts.bail && parallelBatchFailed) {
4516
- console.log(pc7.yellow("\nBailing out \u2014 stopping after first failure"));
4619
+ console.log(pc8.yellow("\nBailing out \u2014 stopping after first failure"));
4517
4620
  }
4518
4621
  }
4519
4622
  releaseAppium();
@@ -4527,12 +4630,19 @@ Config for: ${test.name}`));
4527
4630
  dashboardDb.close();
4528
4631
  }
4529
4632
  const hasFailed = results.some((r) => r.status === "failed") || suitesFailed;
4530
- process.exit(hasFailed ? 1 : 0);
4633
+ const exitCode = hasFailed ? 1 : 0;
4634
+ await maybePrintPostRunUpdateNotice({
4635
+ reporterSelection,
4636
+ effectiveLogLevel,
4637
+ liveEvents: process.env.AGENT_QA_LIVE_EVENTS,
4638
+ cwd: process.cwd()
4639
+ });
4640
+ process.exit(exitCode);
4531
4641
  } catch (err) {
4532
4642
  const errMsg = err instanceof Error ? err.message : String(err);
4533
4643
  const errStack = err instanceof Error ? err.stack ?? "" : "";
4534
4644
  const formattedError = formatFrameworkError(errMsg);
4535
- console.error(pc7.red(formattedError.displayMessage));
4645
+ console.error(pc8.red(formattedError.displayMessage));
4536
4646
  if (_crashDb) {
4537
4647
  const fullError = `${errMsg}
4538
4648
  ${errStack}`;
@@ -4589,7 +4699,7 @@ init_model_defaults();
4589
4699
  import { Command as Command7 } from "commander";
4590
4700
  import { resolve as resolve5, dirname as dirname6 } from "path";
4591
4701
  import { createRequire as createRequire2 } from "module";
4592
- import pc8 from "picocolors";
4702
+ import pc9 from "picocolors";
4593
4703
  import { flushAnalytics, resolveWorkspacePaths as resolveWorkspacePaths3 } from "@vostride/agent-qa-core";
4594
4704
  async function startDashboardBackedServices(opts, command, labels) {
4595
4705
  try {
@@ -4642,7 +4752,7 @@ async function startDashboardBackedServices(opts, command, labels) {
4642
4752
  uiDir = resolve5(dirname6(pkgPath), "dist");
4643
4753
  } catch {
4644
4754
  if (globalOpts.verbose) {
4645
- console.log(pc8.yellow("Warning: @vostride/agent-qa-dashboard-ui not found \u2014 API-only mode"));
4755
+ console.log(pc9.yellow("Warning: @vostride/agent-qa-dashboard-ui not found \u2014 API-only mode"));
4646
4756
  }
4647
4757
  }
4648
4758
  const { close } = await startServer({
@@ -4665,7 +4775,7 @@ async function startDashboardBackedServices(opts, command, labels) {
4665
4775
  const shutdown = async () => {
4666
4776
  if (shuttingDown) return;
4667
4777
  shuttingDown = true;
4668
- console.log(pc8.dim(`
4778
+ console.log(pc9.dim(`
4669
4779
  Shutting down ${labels.shutdown}...`));
4670
4780
  close();
4671
4781
  await flushAnalytics({ config }).catch(() => {
@@ -4675,7 +4785,7 @@ Shutting down ${labels.shutdown}...`));
4675
4785
  process.on("SIGINT", shutdown);
4676
4786
  process.on("SIGTERM", shutdown);
4677
4787
  } catch (err) {
4678
- console.error(pc8.red(`${labels.error} error: ${err instanceof Error ? err.message : String(err)}`));
4788
+ console.error(pc9.red(`${labels.error} error: ${err instanceof Error ? err.message : String(err)}`));
4679
4789
  process.exit(2);
4680
4790
  }
4681
4791
  }
@@ -4701,7 +4811,7 @@ function createServeCommand() {
4701
4811
  // src/commands/mcp.ts
4702
4812
  init_config();
4703
4813
  import { Command as Command8 } from "commander";
4704
- import pc9 from "picocolors";
4814
+ import pc10 from "picocolors";
4705
4815
  import { flushAnalytics as flushAnalytics2 } from "@vostride/agent-qa-core";
4706
4816
  function createMcpCommand() {
4707
4817
  const cmd = new Command8("mcp").description("Start MCP (Model Context Protocol) server over stdio").action(async (command) => {
@@ -4723,7 +4833,7 @@ function createMcpCommand() {
4723
4833
  });
4724
4834
  }
4725
4835
  } catch (err) {
4726
- console.error(pc9.red("Failed to start MCP server:"), err instanceof Error ? err.message : String(err));
4836
+ console.error(pc10.red("Failed to start MCP server:"), err instanceof Error ? err.message : String(err));
4727
4837
  process.exitCode = 1;
4728
4838
  }
4729
4839
  });
@@ -4733,7 +4843,7 @@ function createMcpCommand() {
4733
4843
  // src/commands/config.ts
4734
4844
  init_config();
4735
4845
  import { Command as Command9 } from "commander";
4736
- import pc10 from "picocolors";
4846
+ import pc11 from "picocolors";
4737
4847
  import { parseDocument, Document } from "yaml";
4738
4848
  import { readFile as readFile3, writeFile } from "fs/promises";
4739
4849
  import { createInterface as createInterface2 } from "readline";
@@ -4778,14 +4888,14 @@ async function getValue(key, providedValue) {
4778
4888
  }
4779
4889
  async function setAction(key, value) {
4780
4890
  if (isSensitiveKey(key)) {
4781
- console.error(pc10.red("Credential values are not written by config set."));
4891
+ console.error(pc11.red("Credential values are not written by config set."));
4782
4892
  console.error("Use agent-qa auth set --config <name> --type api-key|bearer-token for compatible or Gemini configs.");
4783
4893
  console.error("Use plugins.auth plus the dashboard auth flow for subscription configs.");
4784
4894
  return;
4785
4895
  }
4786
4896
  const resolved = await getValue(key, value);
4787
4897
  if (!resolved) {
4788
- console.error(pc10.red("No value provided."));
4898
+ console.error(pc11.red("No value provided."));
4789
4899
  return;
4790
4900
  }
4791
4901
  const configPath = "agent-qa.config.yaml";
@@ -4802,7 +4912,7 @@ async function setAction(key, value) {
4802
4912
  }
4803
4913
  doc.setIn(key.split("."), resolved);
4804
4914
  await writeFile(configPath, doc.toString());
4805
- console.log(pc10.green(`\u2713 ${key} = ${resolved} saved to agent-qa.config.yaml`));
4915
+ console.log(pc11.green(`\u2713 ${key} = ${resolved} saved to agent-qa.config.yaml`));
4806
4916
  }
4807
4917
  async function showAction() {
4808
4918
  const fileConfig = await loadConfigFile("agent-qa.config.yaml");
@@ -4810,7 +4920,7 @@ async function showAction() {
4810
4920
  const { mergeConfigs: mergeConfigs2 } = await Promise.resolve().then(() => (init_config(), config_exports));
4811
4921
  const globalConfig = mergeConfigs2(fileConfig, envOverrides, {});
4812
4922
  const table = formatConfigDebug(globalConfig, {}, {});
4813
- console.log(pc10.bold("\nResolved Configuration:\n"));
4923
+ console.log(pc11.bold("\nResolved Configuration:\n"));
4814
4924
  console.log(table);
4815
4925
  console.log();
4816
4926
  }
@@ -4824,7 +4934,7 @@ function createConfigCommand() {
4824
4934
  // src/commands/queue.ts
4825
4935
  init_config();
4826
4936
  import { Command as Command10 } from "commander";
4827
- import pc11 from "picocolors";
4937
+ import pc12 from "picocolors";
4828
4938
  function timeAgo(dateStr) {
4829
4939
  const diff = Date.now() - new Date(dateStr).getTime();
4830
4940
  const seconds = Math.floor(diff / 1e3);
@@ -4858,13 +4968,13 @@ function createQueueCommand() {
4858
4968
  try {
4859
4969
  const response = await fetch(endpoint);
4860
4970
  if (!response.ok) {
4861
- console.error(pc11.red(`Server returned ${response.status}: ${response.statusText}`));
4971
+ console.error(pc12.red(`Server returned ${response.status}: ${response.statusText}`));
4862
4972
  process.exit(1);
4863
4973
  }
4864
4974
  data = await response.json();
4865
4975
  } catch {
4866
- console.error(pc11.red(`Could not connect to dashboard server at ${serverUrl}`));
4867
- console.error(pc11.dim("Make sure the dashboard is running: agent-qa dashboard"));
4976
+ console.error(pc12.red(`Could not connect to dashboard server at ${serverUrl}`));
4977
+ console.error(pc12.dim("Make sure the dashboard is running: agent-qa dashboard"));
4868
4978
  process.exit(1);
4869
4979
  }
4870
4980
  if (opts.json) {
@@ -4872,19 +4982,19 @@ function createQueueCommand() {
4872
4982
  return;
4873
4983
  }
4874
4984
  console.log();
4875
- console.log(pc11.bold("Queue Status"));
4876
- console.log(` Concurrency: ${pc11.blue(String(data.concurrency))} slots (${pc11.yellow(String(data.activeSlots))} active)`);
4985
+ console.log(pc12.bold("Queue Status"));
4986
+ console.log(` Concurrency: ${pc12.blue(String(data.concurrency))} slots (${pc12.yellow(String(data.activeSlots))} active)`);
4877
4987
  console.log();
4878
4988
  const pending = data.pending?.jobs ?? [];
4879
4989
  const running = data.running?.jobs ?? [];
4880
4990
  if (pending.length === 0 && running.length === 0) {
4881
- console.log(pc11.dim(" Queue is empty \u2014 no pending or running jobs"));
4991
+ console.log(pc12.dim(" Queue is empty \u2014 no pending or running jobs"));
4882
4992
  console.log();
4883
4993
  return;
4884
4994
  }
4885
4995
  if (pending.length > 0) {
4886
- console.log(pc11.bold(`Pending (${pending.length} jobs):`));
4887
- console.log(pc11.dim(" # ID Name Priority Source Queued"));
4996
+ console.log(pc12.bold(`Pending (${pending.length} jobs):`));
4997
+ console.log(pc12.dim(" # ID Name Priority Source Queued"));
4888
4998
  for (let i = 0; i < pending.length; i++) {
4889
4999
  const job = pending[i];
4890
5000
  const num = String(i + 1).padEnd(3);
@@ -4893,37 +5003,37 @@ function createQueueCommand() {
4893
5003
  const priority = String(job.priority ?? 0).padEnd(8);
4894
5004
  const source = (job.source ?? "").padEnd(10);
4895
5005
  const queued = job.createdAt ? timeAgo(job.createdAt) : "";
4896
- console.log(` ${num} ${pc11.dim(id)} ${name} ${priority} ${source} ${pc11.dim(queued)}`);
5006
+ console.log(` ${num} ${pc12.dim(id)} ${name} ${priority} ${source} ${pc12.dim(queued)}`);
4897
5007
  }
4898
5008
  console.log();
4899
5009
  }
4900
5010
  if (running.length > 0) {
4901
- console.log(pc11.bold(`Running (${running.length} jobs):`));
4902
- console.log(pc11.dim(" ID Name Source Started"));
5011
+ console.log(pc12.bold(`Running (${running.length} jobs):`));
5012
+ console.log(pc12.dim(" ID Name Source Started"));
4903
5013
  for (const job of running) {
4904
5014
  const id = (job.id ?? "").slice(0, 12).padEnd(12);
4905
5015
  const name = (job.name ?? "").slice(0, 18).padEnd(18);
4906
5016
  const source = (job.source ?? "").padEnd(10);
4907
5017
  const started = job.startedAt ? timeAgo(job.startedAt) : "";
4908
- console.log(` ${pc11.green(id)} ${name} ${source} ${pc11.dim(started)}`);
5018
+ console.log(` ${pc12.green(id)} ${name} ${source} ${pc12.dim(started)}`);
4909
5019
  }
4910
5020
  console.log();
4911
5021
  }
4912
5022
  if (opts.all && data.recent?.length > 0) {
4913
- console.log(pc11.bold(`Recent (${data.recent.length} jobs):`));
4914
- console.log(pc11.dim(" ID Name Status Duration"));
5023
+ console.log(pc12.bold(`Recent (${data.recent.length} jobs):`));
5024
+ console.log(pc12.dim(" ID Name Status Duration"));
4915
5025
  for (const job of data.recent) {
4916
5026
  const id = (job.id ?? "").slice(0, 12).padEnd(12);
4917
5027
  const name = (job.name ?? "").slice(0, 18).padEnd(18);
4918
5028
  const status = (job.status ?? "").padEnd(8);
4919
5029
  const duration = job.duration ? `${Math.round(job.duration / 1e3)}s` : "";
4920
- const statusColor = job.status === "passed" ? pc11.green : job.status === "failed" ? pc11.red : pc11.dim;
4921
- console.log(` ${pc11.dim(id)} ${name} ${statusColor(status)} ${pc11.dim(duration)}`);
5030
+ const statusColor = job.status === "passed" ? pc12.green : job.status === "failed" ? pc12.red : pc12.dim;
5031
+ console.log(` ${pc12.dim(id)} ${name} ${statusColor(status)} ${pc12.dim(duration)}`);
4922
5032
  }
4923
5033
  console.log();
4924
5034
  }
4925
5035
  } catch (err) {
4926
- console.error(pc11.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
5036
+ console.error(pc12.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
4927
5037
  process.exit(1);
4928
5038
  }
4929
5039
  });
@@ -4936,25 +5046,25 @@ function createQueueCommand() {
4936
5046
  try {
4937
5047
  response = await fetch(`${serverUrl}/api/runs/${runId}/cancel`, { method: "POST" });
4938
5048
  } catch {
4939
- console.error(pc11.red(`Could not connect to dashboard server at ${serverUrl}`));
4940
- console.error(pc11.dim("Make sure the dashboard is running: agent-qa dashboard"));
5049
+ console.error(pc12.red(`Could not connect to dashboard server at ${serverUrl}`));
5050
+ console.error(pc12.dim("Make sure the dashboard is running: agent-qa dashboard"));
4941
5051
  process.exit(1);
4942
5052
  }
4943
5053
  if (response.ok) {
4944
5054
  const data = await response.json();
4945
5055
  if (data.cancelled) {
4946
- console.log(pc11.green(`\u2713 Cancelled job ${runId}`));
5056
+ console.log(pc12.green(`\u2713 Cancelled job ${runId}`));
4947
5057
  } else {
4948
- console.log(pc11.red(`Failed to cancel: ${data.error ?? "Unknown error"}`));
5058
+ console.log(pc12.red(`Failed to cancel: ${data.error ?? "Unknown error"}`));
4949
5059
  }
4950
5060
  } else if (response.status === 404) {
4951
- console.log(pc11.red(`Job not found: ${runId}`));
5061
+ console.log(pc12.red(`Job not found: ${runId}`));
4952
5062
  } else {
4953
5063
  const data = await response.json().catch(() => ({}));
4954
- console.log(pc11.red(`Failed to cancel: ${data.error ?? response.statusText}`));
5064
+ console.log(pc12.red(`Failed to cancel: ${data.error ?? response.statusText}`));
4955
5065
  }
4956
5066
  } catch (err) {
4957
- console.error(pc11.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
5067
+ console.error(pc12.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
4958
5068
  process.exit(1);
4959
5069
  }
4960
5070
  });
@@ -4991,7 +5101,7 @@ function createValidateCommand() {
4991
5101
  // src/commands/auth.ts
4992
5102
  import { Command as Command12 } from "commander";
4993
5103
  import { exec } from "child_process";
4994
- import pc12 from "picocolors";
5104
+ import pc13 from "picocolors";
4995
5105
  import input2 from "@inquirer/input";
4996
5106
  import password from "@inquirer/password";
4997
5107
  var PROVIDER_LABELS = {
@@ -5026,10 +5136,10 @@ function getGlobalConfigPath2(command) {
5026
5136
  return command.parent?.parent?.opts().config ?? command.parent?.opts().config;
5027
5137
  }
5028
5138
  function printCredentialGuidance(configName, provider) {
5029
- console.log(pc12.red(`Config ${configName} uses ${providerLabel(provider)} credentials.`));
5030
- console.log(pc12.dim("Use agent-qa auth set --config <name> --type api-key"));
5139
+ console.log(pc13.red(`Config ${configName} uses ${providerLabel(provider)} credentials.`));
5140
+ console.log(pc13.dim("Use agent-qa auth set --config <name> --type api-key"));
5031
5141
  if (provider === "anthropic-compatible") {
5032
- console.log(pc12.dim("or --type bearer-token"));
5142
+ console.log(pc13.dim("or --type bearer-token"));
5033
5143
  }
5034
5144
  }
5035
5145
  function applyAuthToModelConfig(llmConfig, auth) {
@@ -5049,15 +5159,15 @@ function applyAuthToModelConfig(llmConfig, auth) {
5049
5159
  function statusForResolvedAuth(auth) {
5050
5160
  switch (auth.kind) {
5051
5161
  case "api-key":
5052
- return pc12.green("Saved API key");
5162
+ return pc13.green("Saved API key");
5053
5163
  case "bearer-token":
5054
- return pc12.green("Saved bearer token");
5164
+ return pc13.green("Saved bearer token");
5055
5165
  case "auth-fetch":
5056
- return Number(auth.expires ?? Date.now() + 1) <= Date.now() ? pc12.red("Expired") : pc12.green("OAuth connected");
5166
+ return Number(auth.expires ?? Date.now() + 1) <= Date.now() ? pc13.red("Expired") : pc13.green("OAuth connected");
5057
5167
  case "unauthenticated":
5058
- return pc12.dim("No credential");
5168
+ return pc13.dim("No credential");
5059
5169
  case "missing":
5060
- return pc12.red("Missing credential");
5170
+ return pc13.red("Missing credential");
5061
5171
  }
5062
5172
  }
5063
5173
  function extractProviderError(err) {
@@ -5088,16 +5198,16 @@ function openAuthorizationUrl(url) {
5088
5198
  });
5089
5199
  }
5090
5200
  function printMissingSubscriptionPluginGuidance(configName, provider) {
5091
- console.log(pc12.red(`Provider "${provider}" is configured for "${configName}", but no auth plugin is registered.`));
5092
- console.log(pc12.dim(`Config: ${configName}`));
5093
- console.log(pc12.dim(`Provider: ${provider}`));
5094
- console.log(pc12.dim("Add the subscription auth plugin to package.json and install with your package manager:"));
5095
- console.log(pc12.dim(' "devDependencies": { "@vostride/agent-qa-subscription-auth": "<agent-qa version>" }'));
5096
- console.log(pc12.dim("Declare it in agent-qa.config.yaml under plugins.auth:"));
5097
- console.log(pc12.dim(" plugins:"));
5098
- console.log(pc12.dim(" auth:"));
5099
- console.log(pc12.dim(" - package: @vostride/agent-qa-subscription-auth"));
5100
- console.log(pc12.dim("Then authenticate from agent-qa dashboard or rerun this command."));
5201
+ console.log(pc13.red(`Provider "${provider}" is configured for "${configName}", but no auth plugin is registered.`));
5202
+ console.log(pc13.dim(`Config: ${configName}`));
5203
+ console.log(pc13.dim(`Provider: ${provider}`));
5204
+ console.log(pc13.dim("Add the subscription auth plugin to package.json and install with your package manager:"));
5205
+ console.log(pc13.dim(' "devDependencies": { "@vostride/agent-qa-subscription-auth": "<agent-qa version>" }'));
5206
+ console.log(pc13.dim("Declare it in agent-qa.config.yaml under plugins.auth:"));
5207
+ console.log(pc13.dim(" plugins:"));
5208
+ console.log(pc13.dim(" auth:"));
5209
+ console.log(pc13.dim(" - package: @vostride/agent-qa-subscription-auth"));
5210
+ console.log(pc13.dim("Then authenticate from agent-qa dashboard or rerun this command."));
5101
5211
  }
5102
5212
  async function readTokensFromPlugin(provider, plugin, started) {
5103
5213
  if (started.waitForTokens) {
@@ -5105,19 +5215,19 @@ async function readTokensFromPlugin(provider, plugin, started) {
5105
5215
  }
5106
5216
  if (plugin.dashboardAuth.mode === "manual-code") {
5107
5217
  if (!plugin.exchangeCode) {
5108
- console.log(pc12.red(`Provider "${provider}" does not support CLI code exchange. Use agent-qa dashboard.`));
5218
+ console.log(pc13.red(`Provider "${provider}" does not support CLI code exchange. Use agent-qa dashboard.`));
5109
5219
  process.exitCode = 1;
5110
5220
  return null;
5111
5221
  }
5112
5222
  const code = (await input2({ message: "Authorization code:" })).trim();
5113
5223
  if (!code) {
5114
- console.log(pc12.red("Authorization code is required"));
5224
+ console.log(pc13.red("Authorization code is required"));
5115
5225
  process.exitCode = 1;
5116
5226
  return null;
5117
5227
  }
5118
5228
  return await plugin.exchangeCode({ code, sessionState: started.sessionState });
5119
5229
  }
5120
- console.log(pc12.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5230
+ console.log(pc13.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5121
5231
  process.exitCode = 1;
5122
5232
  return null;
5123
5233
  }
@@ -5130,14 +5240,14 @@ async function runSubscriptionPluginLogin(configName, provider) {
5130
5240
  return;
5131
5241
  }
5132
5242
  if (!plugin.startAuth) {
5133
- console.log(pc12.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5243
+ console.log(pc13.red(`Provider "${provider}" does not support CLI auth login. Use agent-qa dashboard.`));
5134
5244
  process.exitCode = 1;
5135
5245
  return;
5136
5246
  }
5137
5247
  let started;
5138
5248
  try {
5139
5249
  started = await plugin.startAuth({ configName });
5140
- console.log(`Open this URL to authenticate: ${pc12.cyan(started.authorizeUrl)}`);
5250
+ console.log(`Open this URL to authenticate: ${pc13.cyan(started.authorizeUrl)}`);
5141
5251
  openAuthorizationUrl(started.authorizeUrl);
5142
5252
  const tokens = await readTokensFromPlugin(provider, plugin, started);
5143
5253
  if (!tokens) return;
@@ -5146,9 +5256,9 @@ async function runSubscriptionPluginLogin(configName, provider) {
5146
5256
  provider: plugin.credentialProviderId,
5147
5257
  tokens
5148
5258
  });
5149
- console.log(pc12.green(`Authenticated ${configName} with ${plugin.label}`));
5259
+ console.log(pc13.green(`Authenticated ${configName} with ${plugin.label}`));
5150
5260
  } catch (err) {
5151
- console.log(pc12.red(err instanceof Error ? err.message : String(err)));
5261
+ console.log(pc13.red(err instanceof Error ? err.message : String(err)));
5152
5262
  process.exitCode = 1;
5153
5263
  } finally {
5154
5264
  started?.cleanup?.();
@@ -5165,13 +5275,13 @@ function createAuthCommand() {
5165
5275
  try {
5166
5276
  const requestedName = normalizeConfigName(opts.config);
5167
5277
  if (!requestedName) {
5168
- console.log(pc12.red("configName is required"));
5278
+ console.log(pc13.red("configName is required"));
5169
5279
  return;
5170
5280
  }
5171
5281
  const resolved = await resolveNamedConfig2(requestedName, configPath);
5172
5282
  const resolvedName = normalizeConfigName(resolved.config.name);
5173
5283
  if (!resolvedName) {
5174
- console.log(pc12.red("Config name is invalid"));
5284
+ console.log(pc13.red("Config name is invalid"));
5175
5285
  return;
5176
5286
  }
5177
5287
  configName = resolvedName;
@@ -5182,7 +5292,7 @@ function createAuthCommand() {
5182
5292
  }
5183
5293
  provider = configProvider;
5184
5294
  } catch (err) {
5185
- console.log(pc12.red(err instanceof Error ? err.message : String(err)));
5295
+ console.log(pc13.red(err instanceof Error ? err.message : String(err)));
5186
5296
  return;
5187
5297
  }
5188
5298
  await runSubscriptionPluginLogin(configName, provider);
@@ -5192,7 +5302,7 @@ function createAuthCommand() {
5192
5302
  new Command12("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) => {
5193
5303
  const credentialType = opts.type.trim();
5194
5304
  if (credentialType !== "api-key" && credentialType !== "bearer-token") {
5195
- console.log(pc12.red("type must be api-key or bearer-token"));
5305
+ console.log(pc13.red("type must be api-key or bearer-token"));
5196
5306
  return;
5197
5307
  }
5198
5308
  const { resolveNamedConfig: resolveNamedConfig2 } = await Promise.resolve().then(() => (init_llm_utils(), llm_utils_exports));
@@ -5201,35 +5311,35 @@ function createAuthCommand() {
5201
5311
  try {
5202
5312
  resolved = await resolveNamedConfig2(opts.config, configPath);
5203
5313
  } catch (err) {
5204
- console.log(pc12.red(err instanceof Error ? err.message : String(err)));
5314
+ console.log(pc13.red(err instanceof Error ? err.message : String(err)));
5205
5315
  return;
5206
5316
  }
5207
5317
  const configName = resolved.config.name ?? opts.config;
5208
5318
  const provider = resolved.config.provider;
5209
5319
  if (SUBSCRIPTION_PROVIDERS2.has(provider)) {
5210
- console.log(pc12.red("Subscription providers use OAuth login"));
5320
+ console.log(pc13.red("Subscription providers use OAuth login"));
5211
5321
  return;
5212
5322
  }
5213
5323
  if (credentialType === "bearer-token" && provider !== "anthropic-compatible") {
5214
- console.log(pc12.red("bearer-token credentials are only supported for anthropic-compatible configs"));
5324
+ console.log(pc13.red("bearer-token credentials are only supported for anthropic-compatible configs"));
5215
5325
  return;
5216
5326
  }
5217
5327
  if (credentialType === "api-key" && !API_KEY_CREDENTIAL_PROVIDERS.has(provider)) {
5218
- console.log(pc12.red("api-key credentials are not supported for this provider"));
5328
+ console.log(pc13.red("api-key credentials are not supported for this provider"));
5219
5329
  return;
5220
5330
  }
5221
5331
  const secret = (secretArg ?? await password({ message: "Secret:" })).trim();
5222
5332
  if (!secret) {
5223
- console.log(pc12.red("Secret is required"));
5333
+ console.log(pc13.red("Secret is required"));
5224
5334
  return;
5225
5335
  }
5226
5336
  const { writeAuth } = await import("@vostride/agent-qa-core");
5227
5337
  if (credentialType === "bearer-token") {
5228
5338
  await writeAuth(configName, { type: "bearer", provider: "anthropic-compatible", token: secret });
5229
- console.log(pc12.green(`Saved bearer token for ${configName}`));
5339
+ console.log(pc13.green(`Saved bearer token for ${configName}`));
5230
5340
  } else {
5231
5341
  await writeAuth(configName, { type: "api", provider, key: secret });
5232
- console.log(pc12.green(`Saved API key for ${configName}`));
5342
+ console.log(pc13.green(`Saved API key for ${configName}`));
5233
5343
  }
5234
5344
  })
5235
5345
  );
@@ -5238,7 +5348,7 @@ function createAuthCommand() {
5238
5348
  const { loadAuthPluginsForRawConfig: loadAuthPluginsForRawConfig2, resolveModelAuth: resolveModelAuth2 } = await Promise.resolve().then(() => (init_llm_utils(), llm_utils_exports));
5239
5349
  const { loadConfigFile: loadConfigFile2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5240
5350
  const configPath = getGlobalConfigPath2(this) ?? "agent-qa.config.yaml";
5241
- console.log(pc12.bold("Auth status:\n"));
5351
+ console.log(pc13.bold("Auth status:\n"));
5242
5352
  let llms;
5243
5353
  let defaultLLM;
5244
5354
  try {
@@ -5249,20 +5359,20 @@ function createAuthCommand() {
5249
5359
  } catch {
5250
5360
  }
5251
5361
  if (!llms?.length) {
5252
- console.log(pc12.dim(" No LLM configs found"));
5362
+ console.log(pc13.dim(" No LLM configs found"));
5253
5363
  return;
5254
5364
  }
5255
5365
  const maxNameLen = Math.max(...llms.map((c) => String(c.name ?? "").length), 4) + 12;
5256
5366
  for (const llm of llms) {
5257
5367
  const name = String(llm.name ?? "");
5258
5368
  const isDefault = name === defaultLLM;
5259
- const label = isDefault ? `${name} ${pc12.dim("(default)")}` : name;
5369
+ const label = isDefault ? `${name} ${pc13.dim("(default)")}` : name;
5260
5370
  const rawLabel = isDefault ? `${name} (default)` : name;
5261
5371
  const padLen = Math.max(0, maxNameLen - rawLabel.length);
5262
5372
  const dots = ".".repeat(padLen + 2);
5263
5373
  const provider = llm.provider;
5264
5374
  const status = statusForResolvedAuth(await resolveModelAuth2(name, llm));
5265
- console.log(` ${label} ${pc12.dim(`[${providerLabel(provider)}]`)} ${pc12.dim(dots)} ${status}`);
5375
+ console.log(` ${label} ${pc13.dim(`[${providerLabel(provider)}]`)} ${pc13.dim(dots)} ${status}`);
5266
5376
  }
5267
5377
  })
5268
5378
  );
@@ -5279,12 +5389,12 @@ function createAuthCommand() {
5279
5389
  const resolved = await resolveNamedConfig2(void 0, configPath);
5280
5390
  storeKey = resolved.config.name;
5281
5391
  } catch {
5282
- console.log(pc12.red("Specify --config <name> or run with a config file"));
5392
+ console.log(pc13.red("Specify --config <name> or run with a config file"));
5283
5393
  return;
5284
5394
  }
5285
5395
  }
5286
5396
  await removeAuth(storeKey);
5287
- console.log(pc12.green(`Logged out from ${storeKey}`));
5397
+ console.log(pc13.green(`Logged out from ${storeKey}`));
5288
5398
  })
5289
5399
  );
5290
5400
  cmd.addCommand(
@@ -5299,19 +5409,19 @@ function createAuthCommand() {
5299
5409
  planner = modelFields;
5300
5410
  configName = name;
5301
5411
  } catch (err) {
5302
- console.log(pc12.red(err instanceof Error ? err.message : String(err)));
5412
+ console.log(pc13.red(err instanceof Error ? err.message : String(err)));
5303
5413
  return;
5304
5414
  }
5305
5415
  if (opts.provider) planner = { ...planner, provider: opts.provider };
5306
5416
  if (opts.model) planner = { ...planner, model: opts.model };
5307
- console.log(pc12.dim(`Testing config: ${configName}...`));
5417
+ console.log(pc13.dim(`Testing config: ${configName}...`));
5308
5418
  const auth = await resolveModelAuth2(configName, planner);
5309
5419
  if (auth.kind === "missing") {
5310
- console.log(pc12.red(auth.message));
5420
+ console.log(pc13.red(auth.message));
5311
5421
  return;
5312
5422
  }
5313
5423
  if (auth.kind === "unauthenticated") {
5314
- console.log(pc12.dim(auth.message));
5424
+ console.log(pc13.dim(auth.message));
5315
5425
  }
5316
5426
  const { createModel, getProviderOptions } = await import("@vostride/agent-qa-core");
5317
5427
  const { generateText } = await import("ai");
@@ -5329,24 +5439,24 @@ function createAuthCommand() {
5329
5439
  ...providerOpts ? { providerOptions: providerOpts } : {}
5330
5440
  });
5331
5441
  const elapsed = Date.now() - start;
5332
- console.log(pc12.green(`Connected to ${planner.provider}/${planner.model} (${elapsed}ms)`));
5442
+ console.log(pc13.green(`Connected to ${planner.provider}/${planner.model} (${elapsed}ms)`));
5333
5443
  } catch (err) {
5334
5444
  const { message, statusCode } = extractProviderError(err);
5335
5445
  const fullContext = `${message} ${statusCode ?? ""}`;
5336
5446
  if (/auth|unauthorized|401|invalid.*key|permission/i.test(fullContext)) {
5337
- console.log(pc12.red("Authentication failed. Check the saved credential for this config."));
5447
+ console.log(pc13.red("Authentication failed. Check the saved credential for this config."));
5338
5448
  } else if (/model.*not.*support|not found|404|does not exist/i.test(fullContext)) {
5339
- console.log(pc12.red("Model not found. Check the model name."));
5449
+ console.log(pc13.red("Model not found. Check the model name."));
5340
5450
  } else if (/rate|429|quota|limit/i.test(fullContext)) {
5341
- console.log(pc12.red("Rate limited. Try again later."));
5451
+ console.log(pc13.red("Rate limited. Try again later."));
5342
5452
  } else if (/ECONNREFUSED|ENOTFOUND|timeout|abort|fetch failed|network/i.test(fullContext)) {
5343
- console.log(pc12.red("Network error. Check the exact base URL and try again."));
5453
+ console.log(pc13.red("Network error. Check the exact base URL and try again."));
5344
5454
  } else if (/invalid_request|400|bad request/i.test(fullContext)) {
5345
- console.log(pc12.red("Invalid request. Check model and provider settings."));
5455
+ console.log(pc13.red("Invalid request. Check model and provider settings."));
5346
5456
  } else {
5347
- console.log(pc12.red(`Connection failed. ${message}`));
5457
+ console.log(pc13.red(`Connection failed. ${message}`));
5348
5458
  }
5349
- console.log(pc12.dim(message));
5459
+ console.log(pc13.dim(message));
5350
5460
  } finally {
5351
5461
  clearTimeout(timeout);
5352
5462
  }
@@ -5360,7 +5470,7 @@ init_config();
5360
5470
  import { createInterface as createInterface3 } from "readline/promises";
5361
5471
  import { dirname as dirname7, resolve as resolvePath4 } from "path";
5362
5472
  import { Command as Command13 } from "commander";
5363
- import pc13 from "picocolors";
5473
+ import pc14 from "picocolors";
5364
5474
  import {
5365
5475
  AUTH_STATE_SCHEMA_VERSION as AUTH_STATE_SCHEMA_VERSION2,
5366
5476
  listAuthStateMetadata,
@@ -5427,7 +5537,7 @@ 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(pc13.red(isSafeAuthStateError(message) ? message : fallback));
5540
+ console.error(pc14.red(isSafeAuthStateError(message) ? message : fallback));
5431
5541
  }
5432
5542
  function assertWebAuthStateTarget(input3) {
5433
5543
  resolveAuthStatePaths2({
@@ -5527,7 +5637,7 @@ function createAuthStateCommand(deps = {}) {
5527
5637
  target: { platform: target.platform }
5528
5638
  });
5529
5639
  if (!target.url) {
5530
- console.error(pc13.red(`Target "${target.name}" must define a web URL for auth-state capture.`));
5640
+ console.error(pc14.red(`Target "${target.name}" must define a web URL for auth-state capture.`));
5531
5641
  process.exitCode = 1;
5532
5642
  return;
5533
5643
  }
@@ -5551,7 +5661,7 @@ function createAuthStateCommand(deps = {}) {
5551
5661
  }
5552
5662
  if (confirmation === "browser-closed") {
5553
5663
  await closeBrowser(browser);
5554
- console.error(pc13.red("Browser was closed before auth state was saved."));
5664
+ console.error(pc14.red("Browser was closed before auth state was saved."));
5555
5665
  process.exitCode = 1;
5556
5666
  return;
5557
5667
  }
@@ -5569,7 +5679,7 @@ function createAuthStateCommand(deps = {}) {
5569
5679
  });
5570
5680
  } catch {
5571
5681
  await closeBrowser(browser);
5572
- console.error(pc13.red(`Could not save auth state "${opts.name}" for target "${target.name}".`));
5682
+ console.error(pc14.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(pc13.red(error instanceof Error ? error.message : String(error)));
5690
+ console.error(pc14.red(error instanceof Error ? error.message : String(error)));
5581
5691
  process.exitCode = 1;
5582
5692
  }
5583
5693
  })
@@ -5589,33 +5699,33 @@ function createAuthStateCommand(deps = {}) {
5589
5699
  init_config();
5590
5700
  import { Command as Command14 } from "commander";
5591
5701
  import { execSync as execSync2 } from "child_process";
5592
- import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
5593
- import { join as join5 } from "path";
5702
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
5703
+ import { join as join6 } from "path";
5594
5704
  import { stringify as stringify2 } from "yaml";
5595
- import pc14 from "picocolors";
5705
+ import pc15 from "picocolors";
5596
5706
  function formatStatus2(transport, localBinding) {
5597
5707
  if (transport !== "local") {
5598
- return pc14.green("Ready") + pc14.dim(" (no local binding required)");
5708
+ return pc15.green("Ready") + pc15.dim(" (no local binding required)");
5599
5709
  }
5600
5710
  if (!localBinding) {
5601
- return pc14.red("UNBOUND") + pc14.yellow(" - run `agent-qa devices init`");
5711
+ return pc15.red("UNBOUND") + pc15.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 pc14.green("Bound") + pc14.dim(` (${details})`);
5715
+ return pc15.green("Bound") + pc15.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(pc14.red(`Config error: ${err instanceof Error ? err.message : String(err)}`));
5722
+ console.error(pc15.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(pc14.yellow("No devices configured in registry.devices"));
5728
+ console.log(pc15.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(pc14.bold(" Configured Devices"));
5736
+ console.log(pc15.bold(" Configured Devices"));
5627
5737
  console.log("");
5628
5738
  console.log(
5629
- ` ${pc14.dim("Name".padEnd(nameWidth))} ${pc14.dim("Platform".padEnd(platWidth))} ${pc14.dim("Transport".padEnd(transWidth))} ${pc14.dim("Status")}`
5739
+ ` ${pc15.dim("Name".padEnd(nameWidth))} ${pc15.dim("Platform".padEnd(platWidth))} ${pc15.dim("Transport".padEnd(transWidth))} ${pc15.dim("Status")}`
5630
5740
  );
5631
5741
  console.log(
5632
- ` ${pc14.dim("\u2500".repeat(nameWidth))} ${pc14.dim("\u2500".repeat(platWidth))} ${pc14.dim("\u2500".repeat(transWidth))} ${pc14.dim("\u2500".repeat(30))}`
5742
+ ` ${pc15.dim("\u2500".repeat(nameWidth))} ${pc15.dim("\u2500".repeat(platWidth))} ${pc15.dim("\u2500".repeat(transWidth))} ${pc15.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,10 +5790,10 @@ function scanSimctlDevices() {
5680
5790
  }
5681
5791
  }
5682
5792
  function appendGitignoreEntry(dir, entry) {
5683
- const gitignorePath = join5(dir, ".gitignore");
5793
+ const gitignorePath = join6(dir, ".gitignore");
5684
5794
  let existing = "";
5685
- if (existsSync3(gitignorePath)) {
5686
- existing = readFileSync3(gitignorePath, "utf-8");
5795
+ if (existsSync4(gitignorePath)) {
5796
+ existing = readFileSync4(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";
@@ -5691,30 +5801,30 @@ function appendGitignoreEntry(dir, entry) {
5691
5801
  }
5692
5802
  async function initDevices() {
5693
5803
  const dir = process.cwd();
5694
- const localFilePath = join5(dir, "agent-qa.local.yaml");
5695
- if (existsSync3(localFilePath)) {
5696
- console.log(pc14.yellow("agent-qa.local.yaml already exists. Skipping generation."));
5804
+ const localFilePath = join6(dir, "agent-qa.local.yaml");
5805
+ if (existsSync4(localFilePath)) {
5806
+ console.log(pc15.yellow("agent-qa.local.yaml already exists. Skipping generation."));
5697
5807
  return;
5698
5808
  }
5699
- console.log(pc14.bold("\n Scanning for connected devices...\n"));
5809
+ console.log(pc15.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(` ${pc14.green("Android:")} found ${adbDevices.length} device(s)`);
5813
+ console.log(` ${pc15.green("Android:")} found ${adbDevices.length} device(s)`);
5704
5814
  for (const d of adbDevices) {
5705
- console.log(` ${pc14.dim("\u2022")} ${d.model} (${d.serial})`);
5815
+ console.log(` ${pc15.dim("\u2022")} ${d.model} (${d.serial})`);
5706
5816
  }
5707
5817
  } else {
5708
- console.log(` ${pc14.dim("Android:")} no devices found (adb not available or no devices connected)`);
5818
+ console.log(` ${pc15.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(` ${pc14.green("iOS:")} found ${simctlDevices.length} simulator(s) (${booted.length} booted)`);
5822
+ console.log(` ${pc15.green("iOS:")} found ${simctlDevices.length} simulator(s) (${booted.length} booted)`);
5713
5823
  for (const d of booted) {
5714
- console.log(` ${pc14.dim("\u2022")} ${d.name} (${d.udid})`);
5824
+ console.log(` ${pc15.dim("\u2022")} ${d.name} (${d.udid})`);
5715
5825
  }
5716
5826
  } else {
5717
- console.log(` ${pc14.dim("iOS:")} no simulators found (simctl not available or none installed)`);
5827
+ console.log(` ${pc15.dim("iOS:")} no simulators found (simctl not available or none installed)`);
5718
5828
  }
5719
5829
  let config;
5720
5830
  try {
@@ -5748,8 +5858,8 @@ async function initDevices() {
5748
5858
  writeFileSync2(localFilePath, yamlContent);
5749
5859
  appendGitignoreEntry(dir, "agent-qa.local.yaml");
5750
5860
  console.log("");
5751
- console.log(pc14.green(` Generated agent-qa.local.yaml with ${bindCount} device binding(s)`));
5752
- console.log(pc14.dim(" Added agent-qa.local.yaml to .gitignore"));
5861
+ console.log(pc15.green(` Generated agent-qa.local.yaml with ${bindCount} device binding(s)`));
5862
+ console.log(pc15.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
  import { Command as Command15 } from "commander";
5764
- import pc15 from "picocolors";
5874
+ import pc16 from "picocolors";
5765
5875
  import {
5766
5876
  ENTITY_ID_TYPES,
5767
5877
  generateCanonicalId,
@@ -5787,7 +5897,7 @@ function createIdsCommand() {
5787
5897
  console.log(id);
5788
5898
  }
5789
5899
  } catch (err) {
5790
- console.error(pc15.red(err instanceof Error ? err.message : String(err)));
5900
+ console.error(pc16.red(err instanceof Error ? err.message : String(err)));
5791
5901
  process.exitCode = 1;
5792
5902
  }
5793
5903
  });
@@ -5806,15 +5916,15 @@ function createIdsCommand() {
5806
5916
  if (opts.json) {
5807
5917
  console.log(JSON.stringify(result, null, 2));
5808
5918
  } else if (valid) {
5809
- console.log(pc15.green(result.message));
5919
+ console.log(pc16.green(result.message));
5810
5920
  } else {
5811
- console.error(pc15.red(result.message));
5921
+ console.error(pc16.red(result.message));
5812
5922
  }
5813
5923
  if (!valid) {
5814
5924
  process.exitCode = 1;
5815
5925
  }
5816
5926
  } catch (err) {
5817
- console.error(pc15.red(err instanceof Error ? err.message : String(err)));
5927
+ console.error(pc16.red(err instanceof Error ? err.message : String(err)));
5818
5928
  process.exitCode = 1;
5819
5929
  }
5820
5930
  });
@@ -5826,14 +5936,14 @@ import { Command as Command16 } from "commander";
5826
5936
  import { generateTestId } from "@vostride/agent-qa-ids";
5827
5937
  import { stringify as stringify3 } from "yaml";
5828
5938
  import { writeFile as writeFile2, mkdir } from "fs/promises";
5829
- import { existsSync as existsSync4 } from "fs";
5939
+ import { existsSync as existsSync5 } from "fs";
5830
5940
  import { resolve as resolve6, dirname as dirname8 } from "path";
5831
- import pc16 from "picocolors";
5941
+ import pc17 from "picocolors";
5832
5942
  function createCreateTestCommand() {
5833
5943
  const cmd = new Command16("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) => {
5834
5944
  const resolved = resolve6(path);
5835
- if (existsSync4(resolved)) {
5836
- console.error(pc16.red("Error: File already exists: " + resolved));
5945
+ if (existsSync5(resolved)) {
5946
+ console.error(pc17.red("Error: File already exists: " + resolved));
5837
5947
  process.exitCode = 1;
5838
5948
  return;
5839
5949
  }
@@ -5847,8 +5957,8 @@ function createCreateTestCommand() {
5847
5957
  const yamlContent = stringify3(template);
5848
5958
  await mkdir(dirname8(resolved), { recursive: true });
5849
5959
  await writeFile2(resolved, yamlContent, "utf-8");
5850
- console.log(pc16.green("Created " + resolved));
5851
- console.log(pc16.dim(" test-id: " + testId));
5960
+ console.log(pc17.green("Created " + resolved));
5961
+ console.log(pc17.dim(" test-id: " + testId));
5852
5962
  });
5853
5963
  return cmd;
5854
5964
  }
@@ -5858,14 +5968,14 @@ import { Command as Command17 } from "commander";
5858
5968
  import { generateSuiteId } from "@vostride/agent-qa-ids";
5859
5969
  import { stringify as stringify4 } from "yaml";
5860
5970
  import { writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
5861
- import { existsSync as existsSync5 } from "fs";
5971
+ import { existsSync as existsSync6 } from "fs";
5862
5972
  import { resolve as resolve7, dirname as dirname9 } from "path";
5863
- import pc17 from "picocolors";
5973
+ import pc18 from "picocolors";
5864
5974
  function createCreateSuiteCommand() {
5865
5975
  const cmd = new Command17("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) => {
5866
5976
  const resolved = resolve7(path);
5867
- if (existsSync5(resolved)) {
5868
- console.error(pc17.red("Error: File already exists: " + resolved));
5977
+ if (existsSync6(resolved)) {
5978
+ console.error(pc18.red("Error: File already exists: " + resolved));
5869
5979
  process.exitCode = 1;
5870
5980
  return;
5871
5981
  }
@@ -5881,8 +5991,8 @@ function createCreateSuiteCommand() {
5881
5991
  );
5882
5992
  await mkdir2(dirname9(resolved), { recursive: true });
5883
5993
  await writeFile3(resolved, yamlContent, "utf-8");
5884
- console.log(pc17.green("Created " + resolved));
5885
- console.log(pc17.dim(" suite-id: " + suiteId));
5994
+ console.log(pc18.green("Created " + resolved));
5995
+ console.log(pc18.dim(" suite-id: " + suiteId));
5886
5996
  });
5887
5997
  return cmd;
5888
5998
  }
@@ -5890,11 +6000,11 @@ function createCreateSuiteCommand() {
5890
6000
  // src/commands/clean-memory.ts
5891
6001
  init_config();
5892
6002
  import { Command as Command18 } from "commander";
5893
- import pc18 from "picocolors";
6003
+ import pc19 from "picocolors";
5894
6004
  import { createInterface as createInterface4 } from "readline";
5895
6005
  import { readFile as readFile4, readdir as readdir2, rm as rm2, stat as stat2 } from "fs/promises";
5896
- import { existsSync as existsSync6 } from "fs";
5897
- import { join as join6 } from "path";
6006
+ import { existsSync as existsSync7 } from "fs";
6007
+ import { join as join7 } from "path";
5898
6008
  import {
5899
6009
  discoverWorkspaceFiles as discoverWorkspaceFiles3,
5900
6010
  parseObservation,
@@ -5910,12 +6020,12 @@ function formatSize(bytes) {
5910
6020
  return `${(bytes / 1048576).toFixed(1)} MB`;
5911
6021
  }
5912
6022
  async function getOrphanInfo(memoryRoot, tier, scope) {
5913
- const scopePath = join6(memoryRoot, tier, scope);
6023
+ const scopePath = join7(memoryRoot, tier, scope);
5914
6024
  const obsFiles = await listObservations(scopePath);
5915
6025
  let newest = null;
5916
6026
  for (const filename of obsFiles) {
5917
6027
  try {
5918
- const content = await readFile4(join6(scopePath, filename), "utf-8");
6028
+ const content = await readFile4(join7(scopePath, filename), "utf-8");
5919
6029
  const { data } = parseObservation(content, filename);
5920
6030
  if (data?.last_confirmed) {
5921
6031
  if (!newest || data.last_confirmed > newest) {
@@ -5930,7 +6040,7 @@ async function getOrphanInfo(memoryRoot, tier, scope) {
5930
6040
  const entries = await readdir2(scopePath);
5931
6041
  for (const entry of entries) {
5932
6042
  try {
5933
- const s = await stat2(join6(scopePath, entry));
6043
+ const s = await stat2(join7(scopePath, entry));
5934
6044
  if (s.isFile()) totalSize += s.size;
5935
6045
  } catch {
5936
6046
  }
@@ -5938,7 +6048,7 @@ async function getOrphanInfo(memoryRoot, tier, scope) {
5938
6048
  } catch {
5939
6049
  }
5940
6050
  return {
5941
- path: join6(tier, scope),
6051
+ path: join7(tier, scope),
5942
6052
  tier,
5943
6053
  scope,
5944
6054
  fileCount: obsFiles.length,
@@ -5979,8 +6089,8 @@ function createCleanMemoryCommand() {
5979
6089
  }
5980
6090
  }
5981
6091
  const memoryRoot = resolveMemoryRoot2(config, workspace.configDir);
5982
- if (!existsSync6(memoryRoot)) {
5983
- console.log(pc18.dim("No memory directory found."));
6092
+ if (!existsSync7(memoryRoot)) {
6093
+ console.log(pc19.dim("No memory directory found."));
5984
6094
  return;
5985
6095
  }
5986
6096
  const TIERS = [
@@ -5990,7 +6100,7 @@ function createCleanMemoryCommand() {
5990
6100
  ];
5991
6101
  const orphans = [];
5992
6102
  for (const tier of TIERS) {
5993
- const tierPath = join6(memoryRoot, tier.dir);
6103
+ const tierPath = join7(memoryRoot, tier.dir);
5994
6104
  let entries;
5995
6105
  try {
5996
6106
  entries = await readdir2(tierPath);
@@ -5999,7 +6109,7 @@ function createCleanMemoryCommand() {
5999
6109
  }
6000
6110
  for (const entry of entries) {
6001
6111
  try {
6002
- const s = await stat2(join6(tierPath, entry));
6112
+ const s = await stat2(join7(tierPath, entry));
6003
6113
  if (!s.isDirectory()) continue;
6004
6114
  } catch {
6005
6115
  continue;
@@ -6010,17 +6120,17 @@ function createCleanMemoryCommand() {
6010
6120
  }
6011
6121
  }
6012
6122
  if (orphans.length === 0) {
6013
- console.log(pc18.dim("No orphaned memory directories found."));
6123
+ console.log(pc19.dim("No orphaned memory directories found."));
6014
6124
  return;
6015
6125
  }
6016
6126
  const maxPathLen = Math.max("Path".length, ...orphans.map((o) => o.path.length));
6017
6127
  console.log("");
6018
- console.log(pc18.bold("Orphaned memory directories:"));
6128
+ console.log(pc19.bold("Orphaned memory directories:"));
6019
6129
  console.log("");
6020
- console.log(" " + pc18.dim("Path".padEnd(maxPathLen + 2) + "Files".padStart(7) + " " + "Last Confirmed".padEnd(20) + "Size".padStart(10)));
6021
- console.log(" " + pc18.dim("-".repeat(maxPathLen + 2 + 7 + 2 + 20 + 10)));
6130
+ console.log(" " + pc19.dim("Path".padEnd(maxPathLen + 2) + "Files".padStart(7) + " " + "Last Confirmed".padEnd(20) + "Size".padStart(10)));
6131
+ console.log(" " + pc19.dim("-".repeat(maxPathLen + 2 + 7 + 2 + 20 + 10)));
6022
6132
  for (const o of orphans) {
6023
- const confirmed = o.lastConfirmed ?? pc18.dim("never");
6133
+ const confirmed = o.lastConfirmed ?? pc19.dim("never");
6024
6134
  console.log(" " + o.path.padEnd(maxPathLen + 2) + String(o.fileCount).padStart(7) + " " + String(confirmed).padEnd(20) + formatSize(o.size).padStart(10));
6025
6135
  }
6026
6136
  console.log("");
@@ -6036,25 +6146,25 @@ function createCleanMemoryCommand() {
6036
6146
  }
6037
6147
  }
6038
6148
  for (const orphan of orphans) {
6039
- await rm2(join6(memoryRoot, orphan.tier, orphan.scope), { recursive: true, force: true });
6149
+ await rm2(join7(memoryRoot, orphan.tier, orphan.scope), { recursive: true, force: true });
6040
6150
  }
6041
- console.log(pc18.green(`Deleted ${orphans.length} orphaned director${orphans.length === 1 ? "y" : "ies"}.`));
6151
+ console.log(pc19.green(`Deleted ${orphans.length} orphaned director${orphans.length === 1 ? "y" : "ies"}.`));
6042
6152
  });
6043
6153
  return cmd;
6044
6154
  }
6045
6155
 
6046
6156
  // src/commands/skills.ts
6047
6157
  import { Command as Command19 } from "commander";
6048
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync4, statSync } from "fs";
6049
- import { dirname as dirname10, join as join7, resolve as resolve8 } from "path";
6158
+ import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync5, statSync } from "fs";
6159
+ import { dirname as dirname10, join as join8, resolve as resolve8 } from "path";
6050
6160
  import { fileURLToPath } from "url";
6051
6161
  function findPackageRoot(startDir) {
6052
6162
  let current = resolve8(startDir);
6053
6163
  while (true) {
6054
- const packagePath = join7(current, "package.json");
6055
- if (existsSync7(packagePath)) {
6164
+ const packagePath = join8(current, "package.json");
6165
+ if (existsSync8(packagePath)) {
6056
6166
  try {
6057
- const pkg = JSON.parse(readFileSync4(packagePath, "utf-8"));
6167
+ const pkg = JSON.parse(readFileSync5(packagePath, "utf-8"));
6058
6168
  if (pkg.name === "agent-qa") {
6059
6169
  return current;
6060
6170
  }
@@ -6069,11 +6179,11 @@ function findPackageRoot(startDir) {
6069
6179
  }
6070
6180
  }
6071
6181
  function hasSkillDirectories(dir) {
6072
- if (!existsSync7(dir)) return false;
6182
+ if (!existsSync8(dir)) return false;
6073
6183
  try {
6074
6184
  return readdirSync(dir).some((entry) => {
6075
- const skillDir = join7(dir, entry);
6076
- return statSync(skillDir).isDirectory() && existsSync7(join7(skillDir, "SKILL.md"));
6185
+ const skillDir = join8(dir, entry);
6186
+ return statSync(skillDir).isDirectory() && existsSync8(join8(skillDir, "SKILL.md"));
6077
6187
  });
6078
6188
  } catch {
6079
6189
  return false;
@@ -6081,7 +6191,7 @@ function hasSkillDirectories(dir) {
6081
6191
  }
6082
6192
  function resolveAgentQaSkillsDirectory(startDir = dirname10(fileURLToPath(import.meta.url))) {
6083
6193
  const packageRoot = findPackageRoot(startDir);
6084
- const packagedSkills = join7(packageRoot, "skills");
6194
+ const packagedSkills = join8(packageRoot, "skills");
6085
6195
  if (hasSkillDirectories(packagedSkills)) {
6086
6196
  return { path: packagedSkills, source: "package" };
6087
6197
  }
@@ -6092,21 +6202,21 @@ function resolveAgentQaSkillsDirectory(startDir = dirname10(fileURLToPath(import
6092
6202
  return { path: packagedSkills, source: "missing" };
6093
6203
  }
6094
6204
  function parseSkillDescription(skillPath) {
6095
- const body = readFileSync4(skillPath, "utf-8");
6205
+ const body = readFileSync5(skillPath, "utf-8");
6096
6206
  const description = body.match(/^description:\s*(.+)$/m)?.[1]?.trim();
6097
6207
  return description?.replace(/^["']|["']$/g, "");
6098
6208
  }
6099
6209
  function listAgentQaSkills(skillsDir) {
6100
6210
  if (!hasSkillDirectories(skillsDir)) return [];
6101
6211
  return readdirSync(skillsDir).filter((entry) => {
6102
- const skillDir = join7(skillsDir, entry);
6103
- return statSync(skillDir).isDirectory() && existsSync7(join7(skillDir, "SKILL.md"));
6212
+ const skillDir = join8(skillsDir, entry);
6213
+ return statSync(skillDir).isDirectory() && existsSync8(join8(skillDir, "SKILL.md"));
6104
6214
  }).sort().map((entry) => {
6105
- const skillDir = join7(skillsDir, entry);
6215
+ const skillDir = join8(skillsDir, entry);
6106
6216
  return {
6107
6217
  name: entry,
6108
6218
  path: skillDir,
6109
- description: parseSkillDescription(join7(skillDir, "SKILL.md"))
6219
+ description: parseSkillDescription(join8(skillDir, "SKILL.md"))
6110
6220
  };
6111
6221
  });
6112
6222
  }
@@ -6196,7 +6306,7 @@ function rejectRemovedCliSurface(input3 = {}) {
6196
6306
  rejectRemovedCliSurface();
6197
6307
  var program = new Command20();
6198
6308
  program.enablePositionalOptions();
6199
- program.name("agent-qa").description("AI-powered testing framework").version(VERSION);
6309
+ program.name("agent-qa").description("The self-improving Agentic QA harness with Memory").version(VERSION);
6200
6310
  program.option("--config <path>", "config file path", "agent-qa.config.yaml").option("--log-level <level>", "log verbosity: silent|error|warn|info|debug").option("--verbose", "shorthand for --log-level debug").option("--quiet", "shorthand for --log-level silent");
6201
6311
  program.addCommand(createRunCommand());
6202
6312
  program.addCommand(createInitCommand());