@hasna/testers 0.0.62 → 0.0.64

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
@@ -26847,6 +26847,149 @@ var require_lib3 = __commonJS((exports, module) => {
26847
26847
  module.exports = Sharp;
26848
26848
  });
26849
26849
 
26850
+ // src/lib/model-credentials.ts
26851
+ function resolveModelCredentialReference(reference, env = process.env, credentialResolver = resolveCredential) {
26852
+ if (reference.startsWith("$?")) {
26853
+ const varName = reference.slice(2).trim();
26854
+ return { source: "optional-env", apiKey: varName ? env[varName] ?? null : null };
26855
+ }
26856
+ if (reference.startsWith("$")) {
26857
+ const varName = reference.slice(1).trim();
26858
+ return { source: "env", apiKey: varName ? env[varName] ?? null : null };
26859
+ }
26860
+ if (reference.startsWith("@secrets:")) {
26861
+ return { source: "secret", apiKey: credentialResolver(reference) };
26862
+ }
26863
+ return { source: "literal", apiKey: reference };
26864
+ }
26865
+ function resolveModelCredential(modelOrPreset, options = {}) {
26866
+ const model = resolveModel(modelOrPreset ?? loadConfig().defaultModel);
26867
+ const provider = detectProvider(model);
26868
+ const envKey = MODEL_PROVIDER_ENV_KEYS[provider];
26869
+ const reference = options.reference ?? `$${envKey}`;
26870
+ const resolved = resolveModelCredentialReference(reference, options.env, options.credentialResolver);
26871
+ return {
26872
+ provider,
26873
+ model,
26874
+ envKey,
26875
+ reference,
26876
+ source: resolved.source,
26877
+ apiKey: resolved.apiKey
26878
+ };
26879
+ }
26880
+ async function validateModelCredential(input) {
26881
+ const endpoint = getModelCredentialValidationEndpoint(input.provider);
26882
+ if (!endpoint) {
26883
+ return { ok: true, message: `No live validation endpoint configured for provider ${input.provider}` };
26884
+ }
26885
+ try {
26886
+ const response = await fetch(endpoint.url, {
26887
+ headers: endpoint.headers(input.apiKey)
26888
+ });
26889
+ if (response.ok)
26890
+ return { ok: true, status: response.status };
26891
+ const text = await response.text().catch(() => "");
26892
+ return {
26893
+ ok: false,
26894
+ status: response.status,
26895
+ message: summarizeModelCredentialValidationError(text) ?? response.statusText
26896
+ };
26897
+ } catch (error) {
26898
+ return {
26899
+ ok: false,
26900
+ message: error instanceof Error ? error.message : String(error)
26901
+ };
26902
+ }
26903
+ }
26904
+ async function checkModelCredential(modelOrPreset, options = {}) {
26905
+ const resolved = resolveModelCredential(modelOrPreset, options);
26906
+ if (!resolved.apiKey) {
26907
+ return {
26908
+ provider: resolved.provider,
26909
+ model: resolved.model,
26910
+ envKey: resolved.envKey,
26911
+ reference: resolved.reference,
26912
+ source: resolved.source,
26913
+ ok: false,
26914
+ message: `Missing ${resolved.envKey} for model provider "${resolved.provider}"`
26915
+ };
26916
+ }
26917
+ const validation = await (options.validator ?? validateModelCredential)({
26918
+ provider: resolved.provider,
26919
+ model: resolved.model,
26920
+ apiKey: resolved.apiKey
26921
+ });
26922
+ return {
26923
+ provider: resolved.provider,
26924
+ model: resolved.model,
26925
+ envKey: resolved.envKey,
26926
+ reference: resolved.reference,
26927
+ source: resolved.source,
26928
+ ok: validation.ok,
26929
+ status: validation.status,
26930
+ message: validation.ok ? validation.message : validation.message ?? "provider rejected the credential"
26931
+ };
26932
+ }
26933
+ function getModelCredentialValidationEndpoint(provider) {
26934
+ if (provider === "anthropic") {
26935
+ return {
26936
+ url: "https://api.anthropic.com/v1/models",
26937
+ headers: (apiKey) => ({
26938
+ "x-api-key": apiKey,
26939
+ "anthropic-version": "2023-06-01"
26940
+ })
26941
+ };
26942
+ }
26943
+ if (provider === "openai") {
26944
+ return {
26945
+ url: "https://api.openai.com/v1/models",
26946
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
26947
+ };
26948
+ }
26949
+ if (provider === "cerebras") {
26950
+ return {
26951
+ url: "https://api.cerebras.ai/v1/models",
26952
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
26953
+ };
26954
+ }
26955
+ if (provider === "zai") {
26956
+ return {
26957
+ url: "https://api.z.ai/api/paas/v4/models",
26958
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
26959
+ };
26960
+ }
26961
+ if (provider === "google") {
26962
+ return {
26963
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/models",
26964
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
26965
+ };
26966
+ }
26967
+ return null;
26968
+ }
26969
+ function summarizeModelCredentialValidationError(text) {
26970
+ if (!text.trim())
26971
+ return;
26972
+ try {
26973
+ const parsed = JSON.parse(text);
26974
+ return parsed.error?.type ?? parsed.error?.code ?? parsed.error?.message ?? parsed.message;
26975
+ } catch {
26976
+ return text.trim().slice(0, 200);
26977
+ }
26978
+ }
26979
+ var MODEL_PROVIDER_ENV_KEYS;
26980
+ var init_model_credentials = __esm(() => {
26981
+ init_ai_client();
26982
+ init_config2();
26983
+ init_secrets_resolver();
26984
+ MODEL_PROVIDER_ENV_KEYS = {
26985
+ anthropic: "ANTHROPIC_API_KEY",
26986
+ openai: "OPENAI_API_KEY",
26987
+ google: "GOOGLE_API_KEY",
26988
+ cerebras: "CEREBRAS_API_KEY",
26989
+ zai: "ZAI_API_KEY"
26990
+ };
26991
+ });
26992
+
26850
26993
  // src/db/api-checks.ts
26851
26994
  function createApiCheck(input) {
26852
26995
  const db2 = getDatabase();
@@ -60782,6 +60925,9 @@ function resolveWorkflowFanoutSelection(options) {
60782
60925
  async function checkWorkflowFanoutReadiness(workflows, dependencies = {}) {
60783
60926
  const checks = [];
60784
60927
  const env = dependencies.env ?? process.env;
60928
+ const model = resolveModel(dependencies.model ?? loadConfig().defaultModel);
60929
+ const modelProvider = detectProvider(model);
60930
+ const modelEnvKey = MODEL_PROVIDER_ENV_KEYS[modelProvider];
60785
60931
  for (const [provider, providerWorkflows] of groupWorkflowsByProvider(workflows)) {
60786
60932
  const envKey = PROVIDER_ENV_KEYS[provider];
60787
60933
  if (!envKey) {
@@ -60857,6 +61003,37 @@ async function checkWorkflowFanoutReadiness(workflows, dependencies = {}) {
60857
61003
  details: { missing: optionalMissing }
60858
61004
  });
60859
61005
  }
61006
+ const modelCredentialResolution = collectModelCredentialReadiness(workflows, modelProvider, modelEnvKey, env, dependencies.credentialResolver);
61007
+ checks.push({
61008
+ name: `model:${modelProvider}`,
61009
+ ok: modelCredentialResolution.missing.length === 0,
61010
+ required: true,
61011
+ 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`,
61012
+ workflows: modelCredentialResolution.missing.length > 0 ? [...new Set(modelCredentialResolution.missing.map((item) => item.workflowName))] : workflows.map((workflow) => workflow.name),
61013
+ details: {
61014
+ provider: modelProvider,
61015
+ model,
61016
+ envKey: modelEnvKey,
61017
+ ...modelCredentialResolution.missing.length > 0 ? { missing: modelCredentialResolution.missing } : {}
61018
+ }
61019
+ });
61020
+ if (dependencies.validateModelCredentials && modelCredentialResolution.available.length > 0) {
61021
+ const validator = dependencies.modelCredentialValidator ?? validateModelCredential;
61022
+ const sample = modelCredentialResolution.available[0];
61023
+ const validation = await validator({ provider: modelProvider, model, apiKey: sample.apiKey });
61024
+ checks.push({
61025
+ name: `model:${modelProvider}:live`,
61026
+ ok: validation.ok,
61027
+ required: true,
61028
+ 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"}`,
61029
+ workflows: workflows.map((workflow) => workflow.name),
61030
+ details: {
61031
+ provider: modelProvider,
61032
+ model,
61033
+ status: validation.status
61034
+ }
61035
+ });
61036
+ }
60860
61037
  return {
60861
61038
  ok: checks.every((check) => check.ok || !check.required),
60862
61039
  checks
@@ -60889,6 +61066,9 @@ async function runWorkflowFanout(options, dependencies = {}) {
60889
61066
  } = dependencies;
60890
61067
  const preflight = preflightOverride ? await preflightOverride(workflows) : await checkWorkflowFanoutReadiness(workflows, {
60891
61068
  providerApiKeyResolver,
61069
+ model: options.model,
61070
+ validateModelCredentials: options.validateModelCredentials,
61071
+ modelCredentialValidator: dependencies.modelCredentialValidator,
60892
61072
  commandExists,
60893
61073
  credentialResolver,
60894
61074
  env
@@ -61070,6 +61250,24 @@ function collectMissingSandboxEnvRefs(workflows, env, credentialResolver) {
61070
61250
  }
61071
61251
  return { requiredMissing, optionalMissing };
61072
61252
  }
61253
+ function collectModelCredentialReadiness(workflows, provider, envKey, env, credentialResolver) {
61254
+ const missing = [];
61255
+ const available = [];
61256
+ for (const workflow of workflows) {
61257
+ const reference = workflow.execution.env?.[envKey];
61258
+ if (!reference) {
61259
+ missing.push({ workflowId: workflow.id, workflowName: workflow.name, provider, key: envKey });
61260
+ continue;
61261
+ }
61262
+ const resolved = resolveModelCredentialReference(reference, env, credentialResolver ?? resolveCredential).apiKey;
61263
+ if (!resolved) {
61264
+ missing.push({ workflowId: workflow.id, workflowName: workflow.name, provider, key: envKey, reference });
61265
+ continue;
61266
+ }
61267
+ available.push({ workflowId: workflow.id, workflowName: workflow.name, provider, key: envKey, apiKey: resolved });
61268
+ }
61269
+ return { missing, available };
61270
+ }
61073
61271
  function isResolvableEnvReference(value) {
61074
61272
  return value.startsWith("$") || value.startsWith("@secrets:");
61075
61273
  }
@@ -61089,6 +61287,9 @@ var init_workflow_fanout = __esm(() => {
61089
61287
  init_workflows();
61090
61288
  init_workflow_runner();
61091
61289
  init_secrets_resolver();
61290
+ init_ai_client();
61291
+ init_config2();
61292
+ init_model_credentials();
61092
61293
  PROVIDER_ENV_KEYS = {
61093
61294
  e2b: "E2B_API_KEY",
61094
61295
  daytona: "DAYTONA_API_KEY",
@@ -95753,7 +95954,7 @@ import chalk6 from "chalk";
95753
95954
  // package.json
95754
95955
  var package_default = {
95755
95956
  name: "@hasna/testers",
95756
- version: "0.0.62",
95957
+ version: "0.0.64",
95757
95958
  description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
95758
95959
  type: "module",
95759
95960
  main: "dist/index.js",
@@ -97515,6 +97716,7 @@ function redactPersonas(personas) {
97515
97716
  }
97516
97717
 
97517
97718
  // src/cli/index.tsx
97719
+ init_model_credentials();
97518
97720
  init_projects();
97519
97721
  init_personas();
97520
97722
  init_api_checks();
@@ -98630,6 +98832,64 @@ function splitCsvOption(value) {
98630
98832
  const items = value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
98631
98833
  return items.length > 0 ? items : undefined;
98632
98834
  }
98835
+ function splitRepeatedValues(values) {
98836
+ return (values ?? []).flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
98837
+ }
98838
+ var MODEL_CREDENTIAL_SAMPLE_MODELS = {
98839
+ anthropic: "quick",
98840
+ openai: "gpt-4o-mini",
98841
+ google: "gemini-2.0-flash",
98842
+ cerebras: "cerebras-fast",
98843
+ zai: "glm-4.6"
98844
+ };
98845
+ function modelCredentialProviderFromTarget(target) {
98846
+ const normalized = target.trim();
98847
+ const providerName = normalized.toLowerCase();
98848
+ const envName = normalized.toUpperCase();
98849
+ for (const provider of Object.keys(MODEL_PROVIDER_ENV_KEYS)) {
98850
+ if (provider === providerName || MODEL_PROVIDER_ENV_KEYS[provider] === envName) {
98851
+ return provider;
98852
+ }
98853
+ }
98854
+ return null;
98855
+ }
98856
+ function parseModelCredentialAssignments(values) {
98857
+ const assignments = {};
98858
+ for (const value of values ?? []) {
98859
+ const separator = value.indexOf("=");
98860
+ if (separator < 0) {
98861
+ throw new Error(`Invalid credential assignment: ${value}. Use provider=reference or ENV_KEY=reference.`);
98862
+ }
98863
+ const target = value.slice(0, separator).trim();
98864
+ const reference = value.slice(separator + 1).trim();
98865
+ if (!reference) {
98866
+ throw new Error(`Invalid credential assignment: ${value}. Reference cannot be empty.`);
98867
+ }
98868
+ const provider = modelCredentialProviderFromTarget(target);
98869
+ if (!provider) {
98870
+ throw new Error(`Unknown model provider or env key: ${target}`);
98871
+ }
98872
+ assignments[provider] = reference;
98873
+ }
98874
+ return assignments;
98875
+ }
98876
+ function sanitizeCredentialReference(reference, source) {
98877
+ if (source === "literal")
98878
+ return "[literal]";
98879
+ return reference;
98880
+ }
98881
+ function toModelCredentialCliItem(check2) {
98882
+ return {
98883
+ provider: check2.provider,
98884
+ model: check2.model,
98885
+ envKey: check2.envKey,
98886
+ reference: sanitizeCredentialReference(check2.reference, check2.source),
98887
+ source: check2.source,
98888
+ ok: check2.ok,
98889
+ ...check2.status !== undefined ? { status: check2.status } : {},
98890
+ ...check2.message ? { message: check2.message } : {}
98891
+ };
98892
+ }
98633
98893
  function describeStoredAssertion(value) {
98634
98894
  if (typeof value === "string")
98635
98895
  return value;
@@ -101328,6 +101588,59 @@ envCmd.command("list").description("List all environments").option("--project <i
101328
101588
  process.exit(1);
101329
101589
  }
101330
101590
  });
101591
+ envCmd.command("validate-models [models...]").description("Validate model provider credentials without launching browser or sandbox runs").option("--model <model>", "Model or preset to validate (repeatable)", (val, acc) => {
101592
+ acc.push(val);
101593
+ return acc;
101594
+ }, []).option("--credential <assignment>", "Credential reference override, e.g. anthropic=@secrets:path or OPENAI_API_KEY=$OPENAI_API_KEY (repeatable)", (val, acc) => {
101595
+ acc.push(val);
101596
+ return acc;
101597
+ }, []).option("--all-providers", "Validate representative models for every supported model provider", false).option("--json", "Output as JSON", false).action(async (models = [], opts) => {
101598
+ try {
101599
+ const requestedModels = splitRepeatedValues([
101600
+ ...models,
101601
+ ...opts.model ?? []
101602
+ ]);
101603
+ const providerSamples = opts.allProviders ? Object.values(MODEL_CREDENTIAL_SAMPLE_MODELS) : [];
101604
+ const modelsToCheck = [...new Set([...providerSamples, ...requestedModels])];
101605
+ const inputs = modelsToCheck.length > 0 ? modelsToCheck : [undefined];
101606
+ const credentialAssignments = parseModelCredentialAssignments(opts.credential);
101607
+ const checks3 = [];
101608
+ for (const modelInput of inputs) {
101609
+ const resolution = resolveModelCredential(modelInput);
101610
+ const reference = credentialAssignments[resolution.provider] ?? `$${resolution.envKey}`;
101611
+ checks3.push(await checkModelCredential(modelInput, { reference }));
101612
+ }
101613
+ const items = checks3.map(toModelCredentialCliItem);
101614
+ const passed = items.filter((item) => item.ok).length;
101615
+ const failed = items.length - passed;
101616
+ const result = {
101617
+ ok: failed === 0,
101618
+ total: items.length,
101619
+ passed,
101620
+ failed,
101621
+ items
101622
+ };
101623
+ if (opts.json) {
101624
+ log(JSON.stringify(result, null, 2));
101625
+ } else {
101626
+ const heading = result.ok ? chalk6.green(`Model credential validation passed: ${passed}/${items.length}`) : chalk6.red(`Model credential validation failed: ${passed}/${items.length}`);
101627
+ log(chalk6.bold(heading));
101628
+ for (const item of items) {
101629
+ const status = item.status !== undefined ? ` status=${item.status}` : "";
101630
+ const message = item.message ? ` ${item.message}` : "";
101631
+ const state = item.ok ? chalk6.green("OK") : chalk6.red("FAIL");
101632
+ log(` ${state} ${item.model} (${item.provider}, ${item.envKey})${status}${message}`);
101633
+ log(chalk6.dim(` reference: ${item.reference} (${item.source})`));
101634
+ }
101635
+ }
101636
+ if (!result.ok) {
101637
+ process.exit(1);
101638
+ }
101639
+ } catch (error40) {
101640
+ logError(chalk6.red(`Error: ${error40 instanceof Error ? error40.message : String(error40)}`));
101641
+ process.exit(1);
101642
+ }
101643
+ });
101331
101644
  envCmd.command("use <name>").description("Set an environment as the default").action((name21) => {
101332
101645
  try {
101333
101646
  setDefaultEnvironment(name21);
@@ -102538,7 +102851,7 @@ workflowCmd.command("run <id>").description("Run a saved testing workflow").requ
102538
102851
  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) => {
102539
102852
  acc.push(val);
102540
102853
  return acc;
102541
- }, []).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) => {
102854
+ }, []).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) => {
102542
102855
  try {
102543
102856
  const fanoutOptions = {
102544
102857
  workflowIds: ids,
@@ -102557,6 +102870,7 @@ workflowCmd.command("fanout [ids...]").description("Run multiple saved sandbox w
102557
102870
  headed: opts.headed,
102558
102871
  parallel: opts.parallel ? parseInt(opts.parallel, 10) : undefined,
102559
102872
  timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,
102873
+ validateModelCredentials: opts.validateModelCredentials,
102560
102874
  dryRun: opts.dryRun
102561
102875
  };
102562
102876
  const runAllBatches = opts.allBatches || opts.fromBatch !== undefined || opts.toBatch !== undefined;
package/dist/index.d.ts CHANGED
@@ -42,6 +42,8 @@ export type { Webhook, WebhookPayload } from "./lib/webhooks.js";
42
42
  export { writeRunMeta, writeScenarioMeta } from "./lib/screenshotter.js";
43
43
  export type { CaptureResult } from "./lib/screenshotter.js";
44
44
  export { resolveCredential, isCredentialReference } from "./lib/secrets-resolver.js";
45
+ export { MODEL_PROVIDER_ENV_KEYS, checkModelCredential, resolveModelCredential, resolveModelCredentialReference, validateModelCredential, } from "./lib/model-credentials.js";
46
+ export type { ModelCredentialCheck, ModelCredentialResolution, ModelCredentialValidationInput, ModelCredentialValidationResult, } from "./lib/model-credentials.js";
45
47
  export { ensurePersonaAuthenticated, loginWithAuthConfig } from "./lib/persona-auth.js";
46
48
  export type { LoginResult } from "./lib/persona-auth.js";
47
49
  export { discoverRepo, clearDiscoveryCache, getDiscoveryCacheInfo, } from "./lib/repo-discovery.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -20349,6 +20349,144 @@ async function startWatcher(options) {
20349
20349
  process.on("SIGTERM", cleanup);
20350
20350
  await new Promise(() => {});
20351
20351
  }
20352
+ // src/lib/model-credentials.ts
20353
+ init_ai_client();
20354
+ init_config2();
20355
+ var MODEL_PROVIDER_ENV_KEYS = {
20356
+ anthropic: "ANTHROPIC_API_KEY",
20357
+ openai: "OPENAI_API_KEY",
20358
+ google: "GOOGLE_API_KEY",
20359
+ cerebras: "CEREBRAS_API_KEY",
20360
+ zai: "ZAI_API_KEY"
20361
+ };
20362
+ function resolveModelCredentialReference(reference, env2 = process.env, credentialResolver = resolveCredential) {
20363
+ if (reference.startsWith("$?")) {
20364
+ const varName = reference.slice(2).trim();
20365
+ return { source: "optional-env", apiKey: varName ? env2[varName] ?? null : null };
20366
+ }
20367
+ if (reference.startsWith("$")) {
20368
+ const varName = reference.slice(1).trim();
20369
+ return { source: "env", apiKey: varName ? env2[varName] ?? null : null };
20370
+ }
20371
+ if (reference.startsWith("@secrets:")) {
20372
+ return { source: "secret", apiKey: credentialResolver(reference) };
20373
+ }
20374
+ return { source: "literal", apiKey: reference };
20375
+ }
20376
+ function resolveModelCredential(modelOrPreset, options = {}) {
20377
+ const model = resolveModel2(modelOrPreset ?? loadConfig().defaultModel);
20378
+ const provider = detectProvider(model);
20379
+ const envKey = MODEL_PROVIDER_ENV_KEYS[provider];
20380
+ const reference = options.reference ?? `$${envKey}`;
20381
+ const resolved = resolveModelCredentialReference(reference, options.env, options.credentialResolver);
20382
+ return {
20383
+ provider,
20384
+ model,
20385
+ envKey,
20386
+ reference,
20387
+ source: resolved.source,
20388
+ apiKey: resolved.apiKey
20389
+ };
20390
+ }
20391
+ async function validateModelCredential(input) {
20392
+ const endpoint = getModelCredentialValidationEndpoint(input.provider);
20393
+ if (!endpoint) {
20394
+ return { ok: true, message: `No live validation endpoint configured for provider ${input.provider}` };
20395
+ }
20396
+ try {
20397
+ const response = await fetch(endpoint.url, {
20398
+ headers: endpoint.headers(input.apiKey)
20399
+ });
20400
+ if (response.ok)
20401
+ return { ok: true, status: response.status };
20402
+ const text = await response.text().catch(() => "");
20403
+ return {
20404
+ ok: false,
20405
+ status: response.status,
20406
+ message: summarizeModelCredentialValidationError(text) ?? response.statusText
20407
+ };
20408
+ } catch (error) {
20409
+ return {
20410
+ ok: false,
20411
+ message: error instanceof Error ? error.message : String(error)
20412
+ };
20413
+ }
20414
+ }
20415
+ async function checkModelCredential(modelOrPreset, options = {}) {
20416
+ const resolved = resolveModelCredential(modelOrPreset, options);
20417
+ if (!resolved.apiKey) {
20418
+ return {
20419
+ provider: resolved.provider,
20420
+ model: resolved.model,
20421
+ envKey: resolved.envKey,
20422
+ reference: resolved.reference,
20423
+ source: resolved.source,
20424
+ ok: false,
20425
+ message: `Missing ${resolved.envKey} for model provider "${resolved.provider}"`
20426
+ };
20427
+ }
20428
+ const validation = await (options.validator ?? validateModelCredential)({
20429
+ provider: resolved.provider,
20430
+ model: resolved.model,
20431
+ apiKey: resolved.apiKey
20432
+ });
20433
+ return {
20434
+ provider: resolved.provider,
20435
+ model: resolved.model,
20436
+ envKey: resolved.envKey,
20437
+ reference: resolved.reference,
20438
+ source: resolved.source,
20439
+ ok: validation.ok,
20440
+ status: validation.status,
20441
+ message: validation.ok ? validation.message : validation.message ?? "provider rejected the credential"
20442
+ };
20443
+ }
20444
+ function getModelCredentialValidationEndpoint(provider) {
20445
+ if (provider === "anthropic") {
20446
+ return {
20447
+ url: "https://api.anthropic.com/v1/models",
20448
+ headers: (apiKey) => ({
20449
+ "x-api-key": apiKey,
20450
+ "anthropic-version": "2023-06-01"
20451
+ })
20452
+ };
20453
+ }
20454
+ if (provider === "openai") {
20455
+ return {
20456
+ url: "https://api.openai.com/v1/models",
20457
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
20458
+ };
20459
+ }
20460
+ if (provider === "cerebras") {
20461
+ return {
20462
+ url: "https://api.cerebras.ai/v1/models",
20463
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
20464
+ };
20465
+ }
20466
+ if (provider === "zai") {
20467
+ return {
20468
+ url: "https://api.z.ai/api/paas/v4/models",
20469
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
20470
+ };
20471
+ }
20472
+ if (provider === "google") {
20473
+ return {
20474
+ url: "https://generativelanguage.googleapis.com/v1beta/openai/models",
20475
+ headers: (apiKey) => ({ Authorization: `Bearer ${apiKey}` })
20476
+ };
20477
+ }
20478
+ return null;
20479
+ }
20480
+ function summarizeModelCredentialValidationError(text) {
20481
+ if (!text.trim())
20482
+ return;
20483
+ try {
20484
+ const parsed = JSON.parse(text);
20485
+ return parsed.error?.type ?? parsed.error?.code ?? parsed.error?.message ?? parsed.message;
20486
+ } catch {
20487
+ return text.trim().slice(0, 200);
20488
+ }
20489
+ }
20352
20490
  // src/lib/repo-discovery.ts
20353
20491
  init_paths();
20354
20492
  import { existsSync as existsSync14, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync as statSync2, writeFileSync as writeFileSync4, mkdirSync as mkdirSync11, unlinkSync } from "fs";
@@ -21592,6 +21730,7 @@ function sessionFromRow(row) {
21592
21730
  export {
21593
21731
  writeScenarioMeta,
21594
21732
  writeRunMeta,
21733
+ validateModelCredential,
21595
21734
  uuid,
21596
21735
  updateTestingWorkflow,
21597
21736
  updateSchedule,
@@ -21625,6 +21764,8 @@ export {
21625
21764
  resolveQuickQaSelection,
21626
21765
  resolvePullRequestNumber,
21627
21766
  resolvePartialId,
21767
+ resolveModelCredentialReference,
21768
+ resolveModelCredential,
21628
21769
  resolveModel as resolveModelConfig,
21629
21770
  resolveModel2 as resolveModel,
21630
21771
  resolveCredential,
@@ -21755,6 +21896,7 @@ export {
21755
21896
  closeDatabase,
21756
21897
  closeBrowser,
21757
21898
  clearDiscoveryCache,
21899
+ checkModelCredential,
21758
21900
  checkBudget,
21759
21901
  buildWorkflowRunPlan,
21760
21902
  buildQuickQaResult,
@@ -21770,6 +21912,7 @@ export {
21770
21912
  RunNotFoundError,
21771
21913
  ResultNotFoundError,
21772
21914
  ProjectNotFoundError,
21915
+ MODEL_PROVIDER_ENV_KEYS,
21773
21916
  MODEL_MAP,
21774
21917
  FlowNotFoundError,
21775
21918
  DependencyCycleError,
@@ -0,0 +1,44 @@
1
+ import { type AIProvider } from "./ai-client.js";
2
+ export declare const MODEL_PROVIDER_ENV_KEYS: Record<AIProvider, string>;
3
+ export interface ModelCredentialValidationInput {
4
+ provider: AIProvider;
5
+ model: string;
6
+ apiKey: string;
7
+ }
8
+ export interface ModelCredentialValidationResult {
9
+ ok: boolean;
10
+ status?: number;
11
+ message?: string;
12
+ }
13
+ export interface ModelCredentialResolution {
14
+ provider: AIProvider;
15
+ model: string;
16
+ envKey: string;
17
+ reference: string;
18
+ source: "env" | "optional-env" | "secret" | "literal";
19
+ apiKey: string | null;
20
+ }
21
+ export interface ModelCredentialCheck {
22
+ provider: AIProvider;
23
+ model: string;
24
+ envKey: string;
25
+ reference: string;
26
+ source: ModelCredentialResolution["source"];
27
+ ok: boolean;
28
+ status?: number;
29
+ message?: string;
30
+ }
31
+ export declare function resolveModelCredentialReference(reference: string, env?: Record<string, string | undefined>, credentialResolver?: (value: string) => string | null): Pick<ModelCredentialResolution, "source" | "apiKey">;
32
+ export declare function resolveModelCredential(modelOrPreset?: string, options?: {
33
+ reference?: string;
34
+ env?: Record<string, string | undefined>;
35
+ credentialResolver?: (value: string) => string | null;
36
+ }): ModelCredentialResolution;
37
+ export declare function validateModelCredential(input: ModelCredentialValidationInput): Promise<ModelCredentialValidationResult>;
38
+ export declare function checkModelCredential(modelOrPreset?: string, options?: {
39
+ reference?: string;
40
+ env?: Record<string, string | undefined>;
41
+ credentialResolver?: (value: string) => string | null;
42
+ validator?: (input: ModelCredentialValidationInput) => Promise<ModelCredentialValidationResult>;
43
+ }): Promise<ModelCredentialCheck>;
44
+ //# sourceMappingURL=model-credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-credentials.d.ts","sourceRoot":"","sources":["../../src/lib/model-credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI/E,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAM9D,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,+BAA+B;IAC9C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAC5C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,EACrD,kBAAkB,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAwB,GACvE,IAAI,CAAC,yBAAyB,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAatD;AAED,wBAAgB,sBAAsB,CACpC,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAClD,GACL,yBAAyB,CAmB3B;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAwB1C;AAED,wBAAsB,oBAAoB,CACxC,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACtD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAC5F,GACL,OAAO,CAAC,oBAAoB,CAAC,CAgC/B"}
@@ -1,4 +1,5 @@
1
1
  import { runTestingWorkflow, type WorkflowRunOptions, type WorkflowRunnerDependencies } from "./workflow-runner.js";
2
+ import { type ModelCredentialValidationInput, type ModelCredentialValidationResult } from "./model-credentials.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,15 @@ 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 type WorkflowFanoutModelCredentialValidationInput = ModelCredentialValidationInput;
93
+ export type WorkflowFanoutModelCredentialValidationResult = ModelCredentialValidationResult;
86
94
  export declare function normalizeFanoutWorkerCount(value: number | undefined): number;
87
95
  export declare function resolveWorkflowFanoutBatch(workflows: TestingWorkflow[], options?: Pick<WorkflowFanoutOptions, "batchSize" | "batch" | "offset">): {
88
96
  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":"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"}
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.62",
55
+ version: "0.0.64",
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",
@@ -47091,7 +47091,7 @@ import { join as join14 } from "path";
47091
47091
  // package.json
47092
47092
  var package_default = {
47093
47093
  name: "@hasna/testers",
47094
- version: "0.0.62",
47094
+ version: "0.0.64",
47095
47095
  description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
47096
47096
  type: "module",
47097
47097
  main: "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/testers",
3
- "version": "0.0.62",
3
+ "version": "0.0.64",
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",