@aetheros/runner
v0.2.0
Published
Generic flow runner for AetherOS: product packs of API and browser checks run against local or staging apps, with redacted reports, optional AI judging through Aevron and optional GitHub issues.
Readme
@aetheros/runner
Generic flow runner: a product pack describes test accounts and flows; the runner signs in, runs API and browser checks against a local or staging app, and writes plain reports with steps to reproduce. Each product keeps its own pack.
aether run init packs/my-app # starter pack (never overwrites)
aether run packs/my-app # all flows; exit code 1 when any fails
aether run packs/my-app --flow "signed-out visitors are blocked" --out reports/today
aether run packs/my-app --allow-host staging.example.com --github owner/repo # issues need GITHUB_TOKEN
aether run packs/my-app --ai claude # AI exploring and a plain-words review (ANTHROPIC_API_KEY)Pack
pack.json: schemaVersion: 1, name, app.baseUrl (or app.baseUrlEnv), allowedHosts, secrets (environment variable names whose values are redacted from reports), and accounts with login settings (method, path, body, expect, optional token path for bearer tokens; cookies are kept per account). Flows are flows/*.json: {name, description, severity: high|medium|low, steps}.
| Step | Fields |
|---|---|
| login | as (account alias) |
| http | as?, method, path, headers?, body?, expect: {status, json: {"a.b": value}, contains, notContains}, capture: {var: "a.b"} |
| browser | as?, goto, actions ({click}, {fill: {selector, value}}, {select: {selector, value}}, {press: {selector?, key}}, {waitFor}), expectText, expectNoText, screenshot?, viewport? (needs Playwright; skipped otherwise; fails if an action leaves the app) |
| sql | database (alias from pack.databases: {alias: {urlEnv}}), query (one SELECT/WITH only), params, expect: {rows, minRows, maxRows, json: {"0.col": value}}. Runs inside BEGIN READ ONLY and always rolls back; needs the optional pg package; database host must be localhost or allowed |
| log | log (alias from pack.logs: {alias: "path/relative/to/pack"}), expectNo (text or /regex/i). Only lines written during this run are checked |
| explore | goal, start?, as?, maxSteps? (15). An AI (--ai claude or runPack({explorer: {provider}})) uses open/click/fill/read tools confined to the app through Aevron, and reports findings |
Templates: {{var}} (captured values) and {{env.NAME}}. Credentials only ever come from environment variables.
Safety
- Refuses any host except localhost and
allowedHosts(pack) /--allow-host. Never list production. - Steps can only call the pack's own origin; browser actions and AI exploration fail if they leave it. There are no shell steps; database steps are read-only.
- Secret values (listed env vars, database URLs and captured login tokens) are replaced with
***in reports, the AI judge prompt and GitHub issues.
API
runPack(dir, {env, only, outDir, allowHosts, fetchImpl, timeoutMs, browser, judge}) → report. aevronJudge(engine, providerId) adds a plain-words review through any Aevron provider with structured output (only redacted failed flows are sent). fileIssues(report, {repo, token, minSeverity}) opens one issue per failed flow.
Limitations
- Steps run in order; there are no retries or parallel flows.
- Database checks support PostgreSQL only (other drivers via
runPack({connect})). - AI exploration costs API usage and its findings need human review.
- Spoken use is in the voice console (
aether voice).
