@hasna/testers 0.0.25 → 0.0.26
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 +1 -1
- package/dist/mcp/index.js +16 -103
- package/dist/server/index.js +19 -0
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -27119,7 +27119,7 @@ import chalk6 from "chalk";
|
|
|
27119
27119
|
// package.json
|
|
27120
27120
|
var package_default = {
|
|
27121
27121
|
name: "@hasna/testers",
|
|
27122
|
-
version: "0.0.
|
|
27122
|
+
version: "0.0.26",
|
|
27123
27123
|
description: "AI-powered QA testing CLI \u2014 spawns cheap AI agents to test web apps with headless browsers",
|
|
27124
27124
|
type: "module",
|
|
27125
27125
|
main: "dist/index.js",
|
package/dist/mcp/index.js
CHANGED
|
@@ -22994,6 +22994,22 @@ async function runApiChecksByFilter(filter) {
|
|
|
22994
22994
|
// src/mcp/index.ts
|
|
22995
22995
|
init_personas();
|
|
22996
22996
|
init_paths();
|
|
22997
|
+
var cliArgs = new Set(process.argv.slice(2));
|
|
22998
|
+
if (cliArgs.has("--help") || cliArgs.has("-h")) {
|
|
22999
|
+
console.log(`Usage: testers-mcp [options]
|
|
23000
|
+
|
|
23001
|
+
Open Testers MCP server (stdio transport)
|
|
23002
|
+
|
|
23003
|
+
Options:
|
|
23004
|
+
-h, --help Show this help message
|
|
23005
|
+
-V, --version Show version
|
|
23006
|
+
`);
|
|
23007
|
+
process.exit(0);
|
|
23008
|
+
}
|
|
23009
|
+
if (cliArgs.has("--version") || cliArgs.has("-V")) {
|
|
23010
|
+
console.log("0.0.1");
|
|
23011
|
+
process.exit(0);
|
|
23012
|
+
}
|
|
22997
23013
|
function json(data) {
|
|
22998
23014
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
22999
23015
|
}
|
|
@@ -23285,18 +23301,6 @@ server.tool("list_agents", "List all registered agents", {}, async () => {
|
|
|
23285
23301
|
return errorResponse(error);
|
|
23286
23302
|
}
|
|
23287
23303
|
});
|
|
23288
|
-
server.tool("import_from_todos", "Import test scenarios from the todos database", {
|
|
23289
|
-
projectName: exports_external.string().optional().describe("Todos project name to filter by"),
|
|
23290
|
-
tags: exports_external.array(exports_external.string()).optional().describe("Tags to filter todos tasks"),
|
|
23291
|
-
projectId: exports_external.string().optional().describe("Target project ID for imported scenarios")
|
|
23292
|
-
}, async ({ projectName, tags, projectId }) => {
|
|
23293
|
-
try {
|
|
23294
|
-
const result = importFromTodos({ projectName, tags, projectId });
|
|
23295
|
-
return json(result);
|
|
23296
|
-
} catch (error) {
|
|
23297
|
-
return errorResponse(error);
|
|
23298
|
-
}
|
|
23299
|
-
});
|
|
23300
23304
|
server.tool("get_status", "Get system status: DB path, API key, scenario and run counts", {}, async () => {
|
|
23301
23305
|
try {
|
|
23302
23306
|
const config = loadConfig();
|
|
@@ -23327,97 +23331,6 @@ server.tool("scenario_exists", "Check whether a scenario with the given name exi
|
|
|
23327
23331
|
return errorResponse(error);
|
|
23328
23332
|
}
|
|
23329
23333
|
});
|
|
23330
|
-
server.tool("create_schedule", {
|
|
23331
|
-
name: exports_external.string().describe("Schedule name"),
|
|
23332
|
-
cronExpression: exports_external.string().describe("Cron expression (5-field)"),
|
|
23333
|
-
url: exports_external.string().describe("Target URL to test"),
|
|
23334
|
-
tags: exports_external.array(exports_external.string()).optional().describe("Filter scenarios by tags"),
|
|
23335
|
-
priority: exports_external.string().optional().describe("Filter scenarios by priority"),
|
|
23336
|
-
model: exports_external.string().optional().describe(MODEL_DESC),
|
|
23337
|
-
headed: exports_external.boolean().optional().describe("Run headed"),
|
|
23338
|
-
parallel: exports_external.number().optional().describe("Parallel count"),
|
|
23339
|
-
projectId: exports_external.string().optional().describe("Project ID")
|
|
23340
|
-
}, async (params) => {
|
|
23341
|
-
try {
|
|
23342
|
-
const schedule = createSchedule({
|
|
23343
|
-
name: params.name,
|
|
23344
|
-
cronExpression: params.cronExpression,
|
|
23345
|
-
url: params.url,
|
|
23346
|
-
scenarioFilter: { tags: params.tags, priority: params.priority },
|
|
23347
|
-
model: params.model,
|
|
23348
|
-
headed: params.headed,
|
|
23349
|
-
parallel: params.parallel,
|
|
23350
|
-
projectId: params.projectId
|
|
23351
|
-
});
|
|
23352
|
-
const nextRun = getNextRunTime(schedule.cronExpression);
|
|
23353
|
-
return json({ ...schedule, nextRunAt: nextRun.toISOString() });
|
|
23354
|
-
} catch (e) {
|
|
23355
|
-
return errorResponse(e);
|
|
23356
|
-
}
|
|
23357
|
-
});
|
|
23358
|
-
server.tool("list_schedules", {
|
|
23359
|
-
projectId: exports_external.string().optional(),
|
|
23360
|
-
enabled: exports_external.boolean().optional(),
|
|
23361
|
-
limit: exports_external.number().optional()
|
|
23362
|
-
}, async (params) => {
|
|
23363
|
-
try {
|
|
23364
|
-
const schedules = listSchedules({ projectId: params.projectId, enabled: params.enabled, limit: params.limit });
|
|
23365
|
-
return json({ items: schedules, total: schedules.length });
|
|
23366
|
-
} catch (e) {
|
|
23367
|
-
return errorResponse(e);
|
|
23368
|
-
}
|
|
23369
|
-
});
|
|
23370
|
-
server.tool("enable_schedule", { id: exports_external.string().describe("Schedule ID") }, async (params) => {
|
|
23371
|
-
try {
|
|
23372
|
-
const schedule = updateSchedule(params.id, { enabled: true });
|
|
23373
|
-
return json(schedule);
|
|
23374
|
-
} catch (e) {
|
|
23375
|
-
return errorResponse(e);
|
|
23376
|
-
}
|
|
23377
|
-
});
|
|
23378
|
-
server.tool("disable_schedule", { id: exports_external.string().describe("Schedule ID") }, async (params) => {
|
|
23379
|
-
try {
|
|
23380
|
-
const schedule = updateSchedule(params.id, { enabled: false });
|
|
23381
|
-
return json(schedule);
|
|
23382
|
-
} catch (e) {
|
|
23383
|
-
return errorResponse(e);
|
|
23384
|
-
}
|
|
23385
|
-
});
|
|
23386
|
-
server.tool("delete_schedule", { id: exports_external.string().describe("Schedule ID") }, async (params) => {
|
|
23387
|
-
try {
|
|
23388
|
-
const deleted = deleteSchedule(params.id);
|
|
23389
|
-
if (!deleted)
|
|
23390
|
-
return errorResponse(notFoundErr(params.id, "Schedule"));
|
|
23391
|
-
return json({ deleted: true, id: params.id });
|
|
23392
|
-
} catch (e) {
|
|
23393
|
-
return errorResponse(e);
|
|
23394
|
-
}
|
|
23395
|
-
});
|
|
23396
|
-
server.tool("wait_for_run", "Poll a run until it reaches a terminal status (passed, failed, error, or cancelled). Blocks until done or timeout.", {
|
|
23397
|
-
runId: exports_external.string().describe("Run ID to wait for"),
|
|
23398
|
-
timeoutMs: exports_external.number().optional().describe("Max wait time in ms (default 300000)"),
|
|
23399
|
-
pollIntervalMs: exports_external.number().optional().describe("Poll interval in ms (default 3000)")
|
|
23400
|
-
}, async ({ runId, timeoutMs = 300000, pollIntervalMs = 3000 }) => {
|
|
23401
|
-
try {
|
|
23402
|
-
const terminalStatuses = new Set(["passed", "failed", "error", "cancelled"]);
|
|
23403
|
-
const deadline = Date.now() + timeoutMs;
|
|
23404
|
-
while (Date.now() < deadline) {
|
|
23405
|
-
const run = getRun(runId);
|
|
23406
|
-
if (!run)
|
|
23407
|
-
return errorResponse(notFoundErr(runId, "Run"));
|
|
23408
|
-
if (terminalStatuses.has(run.status)) {
|
|
23409
|
-
const results = getResultsByRun(runId);
|
|
23410
|
-
const passed = results.filter((r) => r.status === "passed").length;
|
|
23411
|
-
const failed = results.filter((r) => r.status === "failed" || r.status === "error").length;
|
|
23412
|
-
return json({ ...run, passedCount: passed, failedCount: failed });
|
|
23413
|
-
}
|
|
23414
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
23415
|
-
}
|
|
23416
|
-
return errorResponse(Object.assign(new Error(`Run ${runId} did not complete within ${timeoutMs}ms`), { name: "TimeoutError" }));
|
|
23417
|
-
} catch (error) {
|
|
23418
|
-
return errorResponse(error);
|
|
23419
|
-
}
|
|
23420
|
-
});
|
|
23421
23334
|
server.tool("get_run_stats", "Get aggregate statistics for a run: pass rate, cost, token usage, duration", {
|
|
23422
23335
|
runId: exports_external.string().describe("Run ID")
|
|
23423
23336
|
}, async ({ runId }) => {
|
package/dist/server/index.js
CHANGED
|
@@ -20020,6 +20020,25 @@ function listEnvironments(projectId) {
|
|
|
20020
20020
|
|
|
20021
20021
|
// src/server/index.ts
|
|
20022
20022
|
init_types();
|
|
20023
|
+
var cliArgs = new Set(process.argv.slice(2));
|
|
20024
|
+
if (cliArgs.has("--help") || cliArgs.has("-h")) {
|
|
20025
|
+
console.log(`Usage: testers-serve [options]
|
|
20026
|
+
|
|
20027
|
+
Open Testers HTTP server
|
|
20028
|
+
|
|
20029
|
+
Options:
|
|
20030
|
+
-h, --help Show this help message
|
|
20031
|
+
-V, --version Show version
|
|
20032
|
+
|
|
20033
|
+
Environment:
|
|
20034
|
+
TESTERS_PORT Port to bind (default: 19450)
|
|
20035
|
+
`);
|
|
20036
|
+
process.exit(0);
|
|
20037
|
+
}
|
|
20038
|
+
if (cliArgs.has("--version") || cliArgs.has("-V")) {
|
|
20039
|
+
console.log("0.0.1");
|
|
20040
|
+
process.exit(0);
|
|
20041
|
+
}
|
|
20023
20042
|
function parseUrl(req) {
|
|
20024
20043
|
const url = new URL(req.url);
|
|
20025
20044
|
return { pathname: url.pathname, searchParams: url.searchParams };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/testers",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.26",
|
|
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",
|
|
@@ -79,4 +79,4 @@
|
|
|
79
79
|
"cli",
|
|
80
80
|
"mcp"
|
|
81
81
|
]
|
|
82
|
-
}
|
|
82
|
+
}
|