@hasna/testers 0.0.62 → 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 +142 -3
- package/dist/lib/workflow-fanout.d.ts +16 -0
- package/dist/lib/workflow-fanout.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -60782,6 +60782,9 @@ function resolveWorkflowFanoutSelection(options) {
|
|
|
60782
60782
|
async function checkWorkflowFanoutReadiness(workflows, dependencies = {}) {
|
|
60783
60783
|
const checks = [];
|
|
60784
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];
|
|
60785
60788
|
for (const [provider, providerWorkflows] of groupWorkflowsByProvider(workflows)) {
|
|
60786
60789
|
const envKey = PROVIDER_ENV_KEYS[provider];
|
|
60787
60790
|
if (!envKey) {
|
|
@@ -60857,6 +60860,37 @@ async function checkWorkflowFanoutReadiness(workflows, dependencies = {}) {
|
|
|
60857
60860
|
details: { missing: optionalMissing }
|
|
60858
60861
|
});
|
|
60859
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
|
+
}
|
|
60860
60894
|
return {
|
|
60861
60895
|
ok: checks.every((check) => check.ok || !check.required),
|
|
60862
60896
|
checks
|
|
@@ -60889,6 +60923,9 @@ async function runWorkflowFanout(options, dependencies = {}) {
|
|
|
60889
60923
|
} = dependencies;
|
|
60890
60924
|
const preflight = preflightOverride ? await preflightOverride(workflows) : await checkWorkflowFanoutReadiness(workflows, {
|
|
60891
60925
|
providerApiKeyResolver,
|
|
60926
|
+
model: options.model,
|
|
60927
|
+
validateModelCredentials: options.validateModelCredentials,
|
|
60928
|
+
modelCredentialValidator: dependencies.modelCredentialValidator,
|
|
60892
60929
|
commandExists,
|
|
60893
60930
|
credentialResolver,
|
|
60894
60931
|
env
|
|
@@ -61070,6 +61107,28 @@ function collectMissingSandboxEnvRefs(workflows, env, credentialResolver) {
|
|
|
61070
61107
|
}
|
|
61071
61108
|
return { requiredMissing, optionalMissing };
|
|
61072
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
|
+
}
|
|
61073
61132
|
function isResolvableEnvReference(value) {
|
|
61074
61133
|
return value.startsWith("$") || value.startsWith("@secrets:");
|
|
61075
61134
|
}
|
|
@@ -61080,20 +61139,99 @@ function resolveSandboxEnvReference(value, env, credentialResolver) {
|
|
|
61080
61139
|
}
|
|
61081
61140
|
return (credentialResolver ?? resolveCredential)(value);
|
|
61082
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
|
+
}
|
|
61083
61212
|
function summarizePreflightFailures(preflight) {
|
|
61084
61213
|
const requiredFailures = preflight.checks.filter((check) => !check.ok && check.required);
|
|
61085
61214
|
return requiredFailures.length > 0 ? requiredFailures.map((check) => check.message).join("; ") : "required checks did not pass";
|
|
61086
61215
|
}
|
|
61087
|
-
var PROVIDER_ENV_KEYS;
|
|
61216
|
+
var PROVIDER_ENV_KEYS, MODEL_PROVIDER_ENV_KEYS;
|
|
61088
61217
|
var init_workflow_fanout = __esm(() => {
|
|
61089
61218
|
init_workflows();
|
|
61090
61219
|
init_workflow_runner();
|
|
61091
61220
|
init_secrets_resolver();
|
|
61221
|
+
init_ai_client();
|
|
61222
|
+
init_config2();
|
|
61092
61223
|
PROVIDER_ENV_KEYS = {
|
|
61093
61224
|
e2b: "E2B_API_KEY",
|
|
61094
61225
|
daytona: "DAYTONA_API_KEY",
|
|
61095
61226
|
modal: "MODAL_TOKEN_ID"
|
|
61096
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
|
+
};
|
|
61097
61235
|
});
|
|
61098
61236
|
|
|
61099
61237
|
// node_modules/@ai-sdk/provider/dist/index.mjs
|
|
@@ -95753,7 +95891,7 @@ import chalk6 from "chalk";
|
|
|
95753
95891
|
// package.json
|
|
95754
95892
|
var package_default = {
|
|
95755
95893
|
name: "@hasna/testers",
|
|
95756
|
-
version: "0.0.
|
|
95894
|
+
version: "0.0.63",
|
|
95757
95895
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
95758
95896
|
type: "module",
|
|
95759
95897
|
main: "dist/index.js",
|
|
@@ -102538,7 +102676,7 @@ workflowCmd.command("run <id>").description("Run a saved testing workflow").requ
|
|
|
102538
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) => {
|
|
102539
102677
|
acc.push(val);
|
|
102540
102678
|
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) => {
|
|
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) => {
|
|
102542
102680
|
try {
|
|
102543
102681
|
const fanoutOptions = {
|
|
102544
102682
|
workflowIds: ids,
|
|
@@ -102557,6 +102695,7 @@ workflowCmd.command("fanout [ids...]").description("Run multiple saved sandbox w
|
|
|
102557
102695
|
headed: opts.headed,
|
|
102558
102696
|
parallel: opts.parallel ? parseInt(opts.parallel, 10) : undefined,
|
|
102559
102697
|
timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,
|
|
102698
|
+
validateModelCredentials: opts.validateModelCredentials,
|
|
102560
102699
|
dryRun: opts.dryRun
|
|
102561
102700
|
};
|
|
102562
102701
|
const runAllBatches = opts.allBatches || opts.fromBatch !== undefined || opts.toBatch !== undefined;
|
|
@@ -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":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,KAAK,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEpH,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;
|
|
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.
|
|
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",
|
package/dist/server/index.js
CHANGED
|
@@ -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.
|
|
47094
|
+
version: "0.0.63",
|
|
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",
|