@hasna/testers 0.0.61 → 0.0.63

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/index.js CHANGED
@@ -13997,14 +13997,15 @@ async function launchBrowserEngine(engine, config) {
13997
13997
  }
13998
13998
  return launchPlaywright({ headless: config.headless, viewport: config.viewport });
13999
13999
  }
14000
- async function installBrowser(engine) {
14000
+ async function installBrowser(engine, options = {}) {
14001
14001
  if (engine === "lightpanda") {
14002
14002
  const { installLightpanda: installLightpanda2 } = await Promise.resolve().then(() => (init_browser_lightpanda(), exports_browser_lightpanda));
14003
14003
  return installLightpanda2();
14004
14004
  }
14005
14005
  const browserName = engine === "playwright-firefox" ? "firefox" : engine === "playwright-webkit" ? "webkit" : "chromium";
14006
+ const dependencyFlag = options.withDeps ? " --with-deps" : "";
14006
14007
  try {
14007
- execSync(`bunx playwright install ${browserName}`, {
14008
+ execSync(`bunx playwright install${dependencyFlag} ${browserName}`, {
14008
14009
  stdio: "inherit"
14009
14010
  });
14010
14011
  } catch (error) {
@@ -27430,7 +27431,8 @@ function buildSandboxCommand(input) {
27430
27431
  input.packageSpec,
27431
27432
  "install-browser",
27432
27433
  "--engine",
27433
- "playwright"
27434
+ "playwright",
27435
+ "--with-deps"
27434
27436
  ];
27435
27437
  return [
27436
27438
  "set -euo pipefail",
@@ -60780,6 +60782,9 @@ function resolveWorkflowFanoutSelection(options) {
60780
60782
  async function checkWorkflowFanoutReadiness(workflows, dependencies = {}) {
60781
60783
  const checks = [];
60782
60784
  const env = dependencies.env ?? process.env;
60785
+ const model = resolveModel(dependencies.model ?? loadConfig().defaultModel);
60786
+ const modelProvider = detectProvider(model);
60787
+ const modelEnvKey = MODEL_PROVIDER_ENV_KEYS[modelProvider];
60783
60788
  for (const [provider, providerWorkflows] of groupWorkflowsByProvider(workflows)) {
60784
60789
  const envKey = PROVIDER_ENV_KEYS[provider];
60785
60790
  if (!envKey) {
@@ -60855,6 +60860,37 @@ async function checkWorkflowFanoutReadiness(workflows, dependencies = {}) {
60855
60860
  details: { missing: optionalMissing }
60856
60861
  });
60857
60862
  }
60863
+ const modelCredentialResolution = collectModelCredentialReadiness(workflows, modelProvider, modelEnvKey, env, dependencies.credentialResolver);
60864
+ checks.push({
60865
+ name: `model:${modelProvider}`,
60866
+ ok: modelCredentialResolution.missing.length === 0,
60867
+ required: true,
60868
+ message: modelCredentialResolution.missing.length === 0 ? `Model provider "${modelProvider}" credential is available for ${workflows.length} workflow(s)` : `Missing sandbox model credential for "${modelProvider}". Add ${modelEnvKey} to workflow sandbox env or choose a model for a provider with credentials`,
60869
+ workflows: modelCredentialResolution.missing.length > 0 ? [...new Set(modelCredentialResolution.missing.map((item) => item.workflowName))] : workflows.map((workflow) => workflow.name),
60870
+ details: {
60871
+ provider: modelProvider,
60872
+ model,
60873
+ envKey: modelEnvKey,
60874
+ ...modelCredentialResolution.missing.length > 0 ? { missing: modelCredentialResolution.missing } : {}
60875
+ }
60876
+ });
60877
+ if (dependencies.validateModelCredentials && modelCredentialResolution.available.length > 0) {
60878
+ const validator = dependencies.modelCredentialValidator ?? defaultModelCredentialValidator;
60879
+ const sample = modelCredentialResolution.available[0];
60880
+ const validation = await validator({ provider: modelProvider, model, apiKey: sample.apiKey });
60881
+ checks.push({
60882
+ name: `model:${modelProvider}:live`,
60883
+ ok: validation.ok,
60884
+ required: true,
60885
+ message: validation.ok ? `Model provider "${modelProvider}" credential passed live validation` : `Model provider "${modelProvider}" credential failed live validation${validation.status ? ` (${validation.status})` : ""}: ${validation.message ?? "provider rejected the credential"}`,
60886
+ workflows: workflows.map((workflow) => workflow.name),
60887
+ details: {
60888
+ provider: modelProvider,
60889
+ model,
60890
+ status: validation.status
60891
+ }
60892
+ });
60893
+ }
60858
60894
  return {
60859
60895
  ok: checks.every((check) => check.ok || !check.required),
60860
60896
  checks
@@ -60887,6 +60923,9 @@ async function runWorkflowFanout(options, dependencies = {}) {
60887
60923
  } = dependencies;
60888
60924
  const preflight = preflightOverride ? await preflightOverride(workflows) : await checkWorkflowFanoutReadiness(workflows, {
60889
60925
  providerApiKeyResolver,
60926
+ model: options.model,
60927
+ validateModelCredentials: options.validateModelCredentials,
60928
+ modelCredentialValidator: dependencies.modelCredentialValidator,
60890
60929
  commandExists,
60891
60930
  credentialResolver,
60892
60931
  env
@@ -61068,6 +61107,28 @@ function collectMissingSandboxEnvRefs(workflows, env, credentialResolver) {
61068
61107
  }
61069
61108
  return { requiredMissing, optionalMissing };
61070
61109
  }
61110
+ function collectModelCredentialReadiness(workflows, provider, envKey, env, credentialResolver) {
61111
+ const missing = [];
61112
+ const available = [];
61113
+ for (const workflow of workflows) {
61114
+ const reference = workflow.execution.env?.[envKey];
61115
+ if (!reference) {
61116
+ missing.push({ workflowId: workflow.id, workflowName: workflow.name, provider, key: envKey });
61117
+ continue;
61118
+ }
61119
+ const resolved = reference.startsWith("$?") ? resolveOptionalSandboxEnvReference(reference, env) : isResolvableEnvReference(reference) ? resolveSandboxEnvReference(reference, env, credentialResolver) : reference;
61120
+ if (!resolved) {
61121
+ missing.push({ workflowId: workflow.id, workflowName: workflow.name, provider, key: envKey, reference });
61122
+ continue;
61123
+ }
61124
+ available.push({ workflowId: workflow.id, workflowName: workflow.name, provider, key: envKey, apiKey: resolved });
61125
+ }
61126
+ return { missing, available };
61127
+ }
61128
+ function resolveOptionalSandboxEnvReference(value, env) {
61129
+ const varName = value.slice(2).trim();
61130
+ return varName ? env[varName] ?? null : null;
61131
+ }
61071
61132
  function isResolvableEnvReference(value) {
61072
61133
  return value.startsWith("$") || value.startsWith("@secrets:");
61073
61134
  }
@@ -61078,20 +61139,99 @@ function resolveSandboxEnvReference(value, env, credentialResolver) {
61078
61139
  }
61079
61140
  return (credentialResolver ?? resolveCredential)(value);
61080
61141
  }
61142
+ async function defaultModelCredentialValidator(input) {
61143
+ const endpoint = getModelCredentialValidationEndpoint(input.provider);
61144
+ if (!endpoint) {
61145
+ return { ok: true, message: `No live validation endpoint configured for provider ${input.provider}` };
61146
+ }
61147
+ try {
61148
+ const response = await fetch(endpoint.url, {
61149
+ headers: endpoint.headers(input.apiKey)
61150
+ });
61151
+ if (response.ok)
61152
+ return { ok: true, status: response.status };
61153
+ const text = await response.text().catch(() => "");
61154
+ return {
61155
+ ok: false,
61156
+ status: response.status,
61157
+ message: summarizeModelCredentialValidationError(text) ?? response.statusText
61158
+ };
61159
+ } catch (error) {
61160
+ return {
61161
+ ok: false,
61162
+ message: error instanceof Error ? error.message : String(error)
61163
+ };
61164
+ }
61165
+ }
61166
+ function getModelCredentialValidationEndpoint(provider) {
61167
+ if (provider === "anthropic") {
61168
+ return {
61169
+ url: "https://api.anthropic.com/v1/models",
61170
+ headers: (apiKey) => ({
61171
+ "x-api-key": apiKey,
61172
+ "anthropic-version": "2023-06-01"
61173
+ })
61174
+ };
61175
+ }
61176
+ if (provider === "openai") {
61177
+ return {
61178
+ url: "https://api.openai.com/v1/models",
61179
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
61180
+ };
61181
+ }
61182
+ if (provider === "cerebras") {
61183
+ return {
61184
+ url: "https://api.cerebras.ai/v1/models",
61185
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
61186
+ };
61187
+ }
61188
+ if (provider === "zai") {
61189
+ return {
61190
+ url: "https://api.z.ai/api/paas/v4/models",
61191
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
61192
+ };
61193
+ }
61194
+ if (provider === "google") {
61195
+ return {
61196
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/models",
61197
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
61198
+ };
61199
+ }
61200
+ return null;
61201
+ }
61202
+ function summarizeModelCredentialValidationError(text) {
61203
+ if (!text.trim())
61204
+ return;
61205
+ try {
61206
+ const parsed = JSON.parse(text);
61207
+ return parsed.error?.type ?? parsed.error?.code ?? parsed.error?.message ?? parsed.message;
61208
+ } catch {
61209
+ return text.trim().slice(0, 200);
61210
+ }
61211
+ }
61081
61212
  function summarizePreflightFailures(preflight) {
61082
61213
  const requiredFailures = preflight.checks.filter((check) => !check.ok && check.required);
61083
61214
  return requiredFailures.length > 0 ? requiredFailures.map((check) => check.message).join("; ") : "required checks did not pass";
61084
61215
  }
61085
- var PROVIDER_ENV_KEYS;
61216
+ var PROVIDER_ENV_KEYS, MODEL_PROVIDER_ENV_KEYS;
61086
61217
  var init_workflow_fanout = __esm(() => {
61087
61218
  init_workflows();
61088
61219
  init_workflow_runner();
61089
61220
  init_secrets_resolver();
61221
+ init_ai_client();
61222
+ init_config2();
61090
61223
  PROVIDER_ENV_KEYS = {
61091
61224
  e2b: "E2B_API_KEY",
61092
61225
  daytona: "DAYTONA_API_KEY",
61093
61226
  modal: "MODAL_TOKEN_ID"
61094
61227
  };
61228
+ MODEL_PROVIDER_ENV_KEYS = {
61229
+ anthropic: "ANTHROPIC_API_KEY",
61230
+ openai: "OPENAI_API_KEY",
61231
+ google: "GOOGLE_API_KEY",
61232
+ cerebras: "CEREBRAS_API_KEY",
61233
+ zai: "ZAI_API_KEY"
61234
+ };
61095
61235
  });
61096
61236
 
61097
61237
  // node_modules/@ai-sdk/provider/dist/index.mjs
@@ -95751,7 +95891,7 @@ import chalk6 from "chalk";
95751
95891
  // package.json
95752
95892
  var package_default = {
95753
95893
  name: "@hasna/testers",
95754
- version: "0.0.61",
95894
+ version: "0.0.63",
95755
95895
  description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
95756
95896
  type: "module",
95757
95897
  main: "dist/index.js",
@@ -99966,11 +100106,11 @@ program2.command("status").description("Show database and auth status").action((
99966
100106
  process.exit(1);
99967
100107
  }
99968
100108
  });
99969
- program2.command("install-browser").description("Install browser engine").option("--engine <engine>", "Engine to install: playwright, lightpanda, or all", "playwright").action(async (opts) => {
100109
+ program2.command("install-browser").description("Install browser engine").option("--engine <engine>", "Engine to install: playwright, lightpanda, or all", "playwright").option("--with-deps", "Install Playwright OS dependencies for fresh Linux sandboxes", false).action(async (opts) => {
99970
100110
  try {
99971
100111
  if (opts.engine === "all" || opts.engine === "playwright") {
99972
100112
  log(chalk6.blue("Installing Playwright Chromium..."));
99973
- await installBrowser("playwright");
100113
+ await installBrowser("playwright", { withDeps: opts.withDeps });
99974
100114
  log(chalk6.green("Playwright Chromium installed."));
99975
100115
  }
99976
100116
  if (opts.engine === "all" || opts.engine === "lightpanda") {
@@ -102536,7 +102676,7 @@ workflowCmd.command("run <id>").description("Run a saved testing workflow").requ
102536
102676
  workflowCmd.command("fanout [ids...]").description("Run multiple saved sandbox workflows concurrently").requiredOption("-u, --url <url>", "Target URL").option("--project <id>", "Project ID").option("--tag <tag>", "Workflow scenario tag filter (repeatable)", (val, acc) => {
102537
102677
  acc.push(val);
102538
102678
  return acc;
102539
- }, []).option("--all", "Include disabled workflows when selecting by project/tag", false).option("--workers <n>", "Concurrent sandboxes, 1-12 (default: 6)", "6").option("--batch-size <n>", "Limit this run to a batch of selected workflows").option("--batch <n>", "1-based batch number to run with --batch-size").option("--offset <n>", "0-based selected-workflow offset for staged fanout").option("--all-batches", "Run all selected workflow batches sequentially with --batch-size", false).option("--from-batch <n>", "First batch to run when using --all-batches").option("--to-batch <n>", "Last batch to run when using --all-batches").option("--continue-on-failure", "Continue later batches after a failed batch", false).option("-m, --model <model>", "AI model").option("--headed", "Run headed", false).option("--parallel <n>", "Parallel browser workers inside each sandbox").option("--timeout <ms>", "Override workflow timeout").option("--dry-run", "Print resolved sandbox plans without spawning sandboxes", false).option("--json", "Output as JSON", false).action(async (ids, opts) => {
102679
+ }, []).option("--all", "Include disabled workflows when selecting by project/tag", false).option("--workers <n>", "Concurrent sandboxes, 1-12 (default: 6)", "6").option("--batch-size <n>", "Limit this run to a batch of selected workflows").option("--batch <n>", "1-based batch number to run with --batch-size").option("--offset <n>", "0-based selected-workflow offset for staged fanout").option("--all-batches", "Run all selected workflow batches sequentially with --batch-size", false).option("--from-batch <n>", "First batch to run when using --all-batches").option("--to-batch <n>", "Last batch to run when using --all-batches").option("--continue-on-failure", "Continue later batches after a failed batch", false).option("-m, --model <model>", "AI model").option("--headed", "Run headed", false).option("--parallel <n>", "Parallel browser workers inside each sandbox").option("--timeout <ms>", "Override workflow timeout").option("--validate-model-credentials", "Call model provider auth endpoints during fanout preflight", false).option("--dry-run", "Print resolved sandbox plans without spawning sandboxes", false).option("--json", "Output as JSON", false).action(async (ids, opts) => {
102540
102680
  try {
102541
102681
  const fanoutOptions = {
102542
102682
  workflowIds: ids,
@@ -102555,6 +102695,7 @@ workflowCmd.command("fanout [ids...]").description("Run multiple saved sandbox w
102555
102695
  headed: opts.headed,
102556
102696
  parallel: opts.parallel ? parseInt(opts.parallel, 10) : undefined,
102557
102697
  timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,
102698
+ validateModelCredentials: opts.validateModelCredentials,
102558
102699
  dryRun: opts.dryRun
102559
102700
  };
102560
102701
  const runAllBatches = opts.allBatches || opts.fromBatch !== undefined || opts.toBatch !== undefined;
package/dist/index.js CHANGED
@@ -11546,14 +11546,15 @@ async function launchBrowserEngine(engine, config) {
11546
11546
  }
11547
11547
  return launchPlaywright({ headless: config.headless, viewport: config.viewport });
11548
11548
  }
11549
- async function installBrowser(engine) {
11549
+ async function installBrowser(engine, options = {}) {
11550
11550
  if (engine === "lightpanda") {
11551
11551
  const { installLightpanda: installLightpanda2 } = await Promise.resolve().then(() => (init_browser_lightpanda(), exports_browser_lightpanda));
11552
11552
  return installLightpanda2();
11553
11553
  }
11554
11554
  const browserName = engine === "playwright-firefox" ? "firefox" : engine === "playwright-webkit" ? "webkit" : "chromium";
11555
+ const dependencyFlag = options.withDeps ? " --with-deps" : "";
11555
11556
  try {
11556
- execSync(`bunx playwright install ${browserName}`, {
11557
+ execSync(`bunx playwright install${dependencyFlag} ${browserName}`, {
11557
11558
  stdio: "inherit"
11558
11559
  });
11559
11560
  } catch (error) {
@@ -17546,7 +17547,8 @@ function buildSandboxCommand(input) {
17546
17547
  input.packageSpec,
17547
17548
  "install-browser",
17548
17549
  "--engine",
17549
- "playwright"
17550
+ "playwright",
17551
+ "--with-deps"
17550
17552
  ];
17551
17553
  return [
17552
17554
  "set -euo pipefail",
@@ -73,6 +73,8 @@ export declare function launchBrowserEngine(engine: import("../types/index.js").
73
73
  /**
74
74
  * Installs Chromium for Playwright using bunx.
75
75
  */
76
- export declare function installBrowser(engine?: import("../types/index.js").BrowserEngine): Promise<void>;
76
+ export declare function installBrowser(engine?: import("../types/index.js").BrowserEngine, options?: {
77
+ withDeps?: boolean;
78
+ }): Promise<void>;
77
79
  export {};
78
80
  //# sourceMappingURL=browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/lib/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAYhD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAC;CACpD;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAoE7E;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAA;CAAE,GAC7E,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBtH;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IAExC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAGjE,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAA;KAAE;IAQ/G;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IAqC1D;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAO/B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAShC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,OAAO,mBAAmB,EAAE,aAAa,EACjD,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBtG"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/lib/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAYhD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAC;CACpD;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAoE7E;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAA;CAAE,GAC7E,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBtH;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IAExC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAGjE,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,CAAA;KAAE;IAQ/G;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC;IAqC1D;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAO/B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAShC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,OAAO,mBAAmB,EAAE,aAAa,EACjD,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,aAAa,EAClD,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GACnC,OAAO,CAAC,IAAI,CAAC,CAiBf"}
@@ -1,4 +1,5 @@
1
1
  import { runTestingWorkflow, type WorkflowRunOptions, type WorkflowRunnerDependencies } from "./workflow-runner.js";
2
+ import { type AIProvider } from "./ai-client.js";
2
3
  import type { TestingWorkflow } from "../types/index.js";
3
4
  export interface WorkflowFanoutOptions extends WorkflowRunOptions {
4
5
  workflowIds?: string[];
@@ -12,6 +13,7 @@ export interface WorkflowFanoutOptions extends WorkflowRunOptions {
12
13
  batchStart?: number;
13
14
  batchEnd?: number;
14
15
  continueOnFailure?: boolean;
16
+ validateModelCredentials?: boolean;
15
17
  }
16
18
  export interface WorkflowFanoutItem {
17
19
  workflowId: string;
@@ -53,6 +55,7 @@ export interface WorkflowFanoutDependencies extends WorkflowRunnerDependencies {
53
55
  runTestingWorkflow?: typeof runTestingWorkflow;
54
56
  preflight?: (workflows: TestingWorkflow[]) => WorkflowFanoutPreflightResult | Promise<WorkflowFanoutPreflightResult>;
55
57
  providerApiKeyResolver?: (provider: string, env: Record<string, string | undefined>) => string | undefined | Promise<string | undefined>;
58
+ modelCredentialValidator?: (input: WorkflowFanoutModelCredentialValidationInput) => Promise<WorkflowFanoutModelCredentialValidationResult>;
56
59
  commandExists?: (command: string) => boolean;
57
60
  credentialResolver?: (value: string) => string | null;
58
61
  env?: Record<string, string | undefined>;
@@ -79,10 +82,23 @@ export interface WorkflowFanoutSelection {
79
82
  }
80
83
  interface WorkflowFanoutPreflightDependencies {
81
84
  providerApiKeyResolver?: WorkflowFanoutDependencies["providerApiKeyResolver"];
85
+ model?: string;
86
+ validateModelCredentials?: boolean;
87
+ modelCredentialValidator?: WorkflowFanoutDependencies["modelCredentialValidator"];
82
88
  commandExists?: WorkflowFanoutDependencies["commandExists"];
83
89
  credentialResolver?: WorkflowFanoutDependencies["credentialResolver"];
84
90
  env?: Record<string, string | undefined>;
85
91
  }
92
+ export interface WorkflowFanoutModelCredentialValidationInput {
93
+ provider: AIProvider;
94
+ model: string;
95
+ apiKey: string;
96
+ }
97
+ export interface WorkflowFanoutModelCredentialValidationResult {
98
+ ok: boolean;
99
+ status?: number;
100
+ message?: string;
101
+ }
86
102
  export declare function normalizeFanoutWorkerCount(value: number | undefined): number;
87
103
  export declare function resolveWorkflowFanoutBatch(workflows: TestingWorkflow[], options?: Pick<WorkflowFanoutOptions, "batchSize" | "batch" | "offset">): {
88
104
  workflows: TestingWorkflow[];
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-fanout.d.ts","sourceRoot":"","sources":["../../src/lib/workflow-fanout.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-fanout.d.ts","sourceRoot":"","sources":["../../src/lib/workflow-fanout.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,KAAK,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEpH,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,uBAAuB,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,6BAA6B,CAAC;CAC3C;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,0BAA2B,SAAQ,0BAA0B;IAC5E,kBAAkB,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC/C,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,KAAK,6BAA6B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACrH,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACzI,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,4CAA4C,KAAK,OAAO,CAAC,6CAA6C,CAAC,CAAC;IAC3I,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,6BAA6B;IAC5C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,4BAA4B,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,mCAAmC;IAC3C,sBAAsB,CAAC,EAAE,0BAA0B,CAAC,wBAAwB,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,wBAAwB,CAAC,EAAE,0BAA0B,CAAC,0BAA0B,CAAC,CAAC;IAClF,aAAa,CAAC,EAAE,0BAA0B,CAAC,eAAe,CAAC,CAAC;IAC5D,kBAAkB,CAAC,EAAE,0BAA0B,CAAC,oBAAoB,CAAC,CAAC;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AAgBD,MAAM,WAAW,4CAA4C;IAC3D,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,6CAA6C;IAC5D,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AASD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAM5E;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,eAAe,EAAE,EAC5B,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAM,GAC1E;IAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,uBAAuB,CAAA;CAAE,CAgCtE;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,WAAW,GAAG,YAAY,GAAG,UAAU,CAAC,GAC5E;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAwBnF;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,iBAAiB,CAAC,GAAG,eAAe,EAAE,CA8BhK;AAED,wBAAsB,4BAA4B,CAChD,SAAS,EAAE,eAAe,EAAE,EAC5B,YAAY,GAAE,mCAAwC,GACrD,OAAO,CAAC,6BAA6B,CAAC,CAiJxC;AAuBD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,EAC9B,YAAY,GAAE,0BAA+B,GAC5C,OAAO,CAAC,oBAAoB,CAAC,CAkG/B;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,qBAAqB,EAC9B,YAAY,GAAE,0BAA+B,GAC5C,OAAO,CAAC,2BAA2B,CAAC,CA+CtC"}
package/dist/mcp/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "@hasna/testers",
55
- version: "0.0.61",
55
+ version: "0.0.63",
56
56
  description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
57
57
  type: "module",
58
58
  main: "dist/index.js",
@@ -16592,14 +16592,15 @@ async function launchBrowserEngine(engine, config) {
16592
16592
  }
16593
16593
  return launchPlaywright({ headless: config.headless, viewport: config.viewport });
16594
16594
  }
16595
- async function installBrowser(engine) {
16595
+ async function installBrowser(engine, options = {}) {
16596
16596
  if (engine === "lightpanda") {
16597
16597
  const { installLightpanda: installLightpanda2 } = await Promise.resolve().then(() => (init_browser_lightpanda(), exports_browser_lightpanda));
16598
16598
  return installLightpanda2();
16599
16599
  }
16600
16600
  const browserName = engine === "playwright-firefox" ? "firefox" : engine === "playwright-webkit" ? "webkit" : "chromium";
16601
+ const dependencyFlag = options.withDeps ? " --with-deps" : "";
16601
16602
  try {
16602
- execSync(`bunx playwright install ${browserName}`, {
16603
+ execSync(`bunx playwright install${dependencyFlag} ${browserName}`, {
16603
16604
  stdio: "inherit"
16604
16605
  });
16605
16606
  } catch (error) {
@@ -23821,7 +23822,8 @@ function buildSandboxCommand(input) {
23821
23822
  input.packageSpec,
23822
23823
  "install-browser",
23823
23824
  "--engine",
23824
- "playwright"
23825
+ "playwright",
23826
+ "--with-deps"
23825
23827
  ];
23826
23828
  return [
23827
23829
  "set -euo pipefail",
@@ -15306,14 +15306,15 @@ async function launchBrowserEngine(engine, config) {
15306
15306
  }
15307
15307
  return launchPlaywright({ headless: config.headless, viewport: config.viewport });
15308
15308
  }
15309
- async function installBrowser(engine) {
15309
+ async function installBrowser(engine, options = {}) {
15310
15310
  if (engine === "lightpanda") {
15311
15311
  const { installLightpanda: installLightpanda2 } = await Promise.resolve().then(() => (init_browser_lightpanda(), exports_browser_lightpanda));
15312
15312
  return installLightpanda2();
15313
15313
  }
15314
15314
  const browserName = engine === "playwright-firefox" ? "firefox" : engine === "playwright-webkit" ? "webkit" : "chromium";
15315
+ const dependencyFlag = options.withDeps ? " --with-deps" : "";
15315
15316
  try {
15316
- execSync(`bunx playwright install ${browserName}`, {
15317
+ execSync(`bunx playwright install${dependencyFlag} ${browserName}`, {
15317
15318
  stdio: "inherit"
15318
15319
  });
15319
15320
  } catch (error) {
@@ -47090,7 +47091,7 @@ import { join as join14 } from "path";
47090
47091
  // package.json
47091
47092
  var package_default = {
47092
47093
  name: "@hasna/testers",
47093
- version: "0.0.61",
47094
+ version: "0.0.63",
47094
47095
  description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
47095
47096
  type: "module",
47096
47097
  main: "dist/index.js",
@@ -51662,7 +51663,8 @@ function buildSandboxCommand(input) {
51662
51663
  input.packageSpec,
51663
51664
  "install-browser",
51664
51665
  "--engine",
51665
- "playwright"
51666
+ "playwright",
51667
+ "--with-deps"
51666
51668
  ];
51667
51669
  return [
51668
51670
  "set -euo pipefail",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/testers",
3
- "version": "0.0.61",
3
+ "version": "0.0.63",
4
4
  "description": "AI-powered QA testing CLI — spawns cheap AI agents to test web apps with headless browsers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",