@pcamarajr/scout 0.3.0 → 0.4.0
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/README.md +49 -11
- package/dist/cli.js +53 -15
- package/dist/cli.js.map +1 -1
- package/dist/engine.js +0 -4
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +13 -9
- package/dist/mcp/server.js.map +1 -1
- package/dist/report.d.ts +4 -2
- package/dist/report.js +25 -16
- package/dist/report.js.map +1 -1
- package/dist/specs.d.ts +33 -0
- package/dist/specs.js +198 -0
- package/dist/specs.js.map +1 -0
- package/dist/store.d.ts +6 -15
- package/dist/store.js +50 -54
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +14 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🔭 Scout
|
|
2
2
|
|
|
3
|
-
Self-healing browser QA. Scenarios written in **natural language
|
|
3
|
+
Self-healing browser QA. Scenarios written in **natural language** as versioned `.scout.md` files, verified by an **AI agent** in a real browser (Playwright), and recorded as a **deterministic script** that runs cheaply and quickly in CI — AI only kicks in when the script breaks.
|
|
4
4
|
|
|
5
5
|
> Status: functional POC.
|
|
6
6
|
|
|
@@ -16,11 +16,11 @@ Self-healing browser QA. Scenarios written in **natural language**, verified by
|
|
|
16
16
|
**Scenario lifecycle:**
|
|
17
17
|
|
|
18
18
|
```
|
|
19
|
-
scout create "Paywall free" -c "Open ep 3 of series X without login; paywall should appear with signup CTA"
|
|
20
|
-
│
|
|
19
|
+
scout create "Paywall free" -f paywall -c "Open ep 3 of series X without login; paywall should appear with signup CTA"
|
|
20
|
+
│ (writes a `## Paywall free` section into .scout/specs/paywall.scout.md)
|
|
21
21
|
▼
|
|
22
22
|
scout go ──── 1st run: AI agent runs in browser, judges (verified/failed/partial/blocked)
|
|
23
|
-
│ and records .scout/scripts/paywall-free.json (deterministic steps + assertions)
|
|
23
|
+
│ and records .scout/scripts/paywall/paywall-free.json (deterministic steps + assertions)
|
|
24
24
|
▼
|
|
25
25
|
CI / subsequent runs: pure Playwright replay, no LLM, seconds per scenario
|
|
26
26
|
│
|
|
@@ -35,8 +35,9 @@ UI changed and replay broke? ── AI re-runs, re-judges, re-records the script
|
|
|
35
35
|
npm install @pcamarajr/scout # or npm link during POC
|
|
36
36
|
npx playwright install chromium # browser engine
|
|
37
37
|
|
|
38
|
-
scout init # creates scout.config.json + .scout/
|
|
38
|
+
scout init # creates scout.config.json + .scout/specs/
|
|
39
39
|
scout create "Login with Google" \
|
|
40
|
+
-f auth \
|
|
40
41
|
-c "On logged-out home, click Sign In; login page should show Google and email/password options" \
|
|
41
42
|
-p anon
|
|
42
43
|
scout go # 1st run = AI (requires Anthropic credentials)
|
|
@@ -50,6 +51,40 @@ scout report # markdown ready to embed in PR body
|
|
|
50
51
|
- **CI/headless:** export `ANTHROPIC_API_KEY`. The SDK is self-contained (Claude Code CLI not required).
|
|
51
52
|
- Deterministic replay **does not use LLM** — in CI without a key, use `scout go --no-heal` (failure becomes ❌ in the report instead of healing).
|
|
52
53
|
|
|
54
|
+
## Scenarios are files (`.scout.md`)
|
|
55
|
+
|
|
56
|
+
Scenarios live as markdown under `.scout/specs/**/*.scout.md` — **one file per feature/component**, versioned and reviewed like the rest of your tests. The markdown is the **source of truth and a pure input**: a run never writes back to it. Status and last-run derive from `.scout/runs/` instead, so the spec diff only ever reflects an intent change, never run noise. The layout mirrors the Playwright Agents test-plan format, with YAML frontmatter as a scout superset.
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
---
|
|
60
|
+
feature: Paywall # optional; defaults to the filename
|
|
61
|
+
profile: anon # default auth profile for scenarios below
|
|
62
|
+
tags: [monetization] # optional
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Free user hits paywall on ep 3
|
|
66
|
+
Open ep 3 of series X without login; paywall appears with a signup CTA.
|
|
67
|
+
|
|
68
|
+
## Subscriber bypasses paywall
|
|
69
|
+
profile: qa # per-scenario override (also: notes, tags)
|
|
70
|
+
|
|
71
|
+
Logged-in subscriber opens ep 3; plays with no paywall.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- Each `##` heading is one scenario; its **logical slug** is `<file>/<scenario>` (e.g. `paywall/free-user-hits-paywall-on-ep-3`), unique across the suite.
|
|
75
|
+
- Optional `profile`/`notes`/`tags` lines right after a heading override the file-level defaults.
|
|
76
|
+
- Author by hand, or via `scout create <name> -f <feature> -c <text>` / the `scout_create_scenario` MCP tool.
|
|
77
|
+
|
|
78
|
+
### Migrating from a legacy `scenarios.json`
|
|
79
|
+
|
|
80
|
+
Older scouts kept a single `.scout/scenarios.json`. Convert it once:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
scout migrate # → one .scout/specs/<slug>.scout.md per scenario, relocates cached scripts, backs up the JSON
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
It's idempotent and preserves cached scripts (so replay still works without re-recording). Re-run `scout go` once afterward to repopulate run status. Review the generated `feature:` frontmatter and delete the `.scout/scenarios.json.bak` when happy.
|
|
87
|
+
|
|
53
88
|
## Auth profiles (storageState)
|
|
54
89
|
|
|
55
90
|
Authenticated flows use sessions captured once per environment:
|
|
@@ -85,7 +120,7 @@ SCOUT_BASE_URL=https://staging.myapp.com scout go --no-heal # against staging
|
|
|
85
120
|
|
|
86
121
|
Precedence: `--base-url` flag (or the `baseUrl` param of the `scout_run` MCP tool) > `SCOUT_BASE_URL` > `baseUrl` in `scout.config.json`. Recorded scripts store navigation **relative to the baseUrl in effect at recording time**, so a script recorded against `:3000` replays unchanged against `:3001` or staging.
|
|
87
122
|
|
|
88
|
-
- `.scout/
|
|
123
|
+
- `.scout/specs/` (the `.scout.md` suite) and `.scout/scripts/` are **committed** — the suite travels with the branch.
|
|
89
124
|
- `.scout/runs/` and `.scout/state/` are **gitignored** — artifacts and sessions are per-machine.
|
|
90
125
|
|
|
91
126
|
## Per-run artifacts
|
|
@@ -140,11 +175,12 @@ With heal in CI: add `ANTHROPIC_API_KEY` and switch to `npx scout go` — when t
|
|
|
140
175
|
## Full CLI
|
|
141
176
|
|
|
142
177
|
```
|
|
143
|
-
scout init # bootstrap in the project
|
|
144
|
-
scout create <name> -c <scenario> [-p profile] [-n notes]
|
|
178
|
+
scout init # bootstrap in the project (.scout/specs/ + config)
|
|
179
|
+
scout create <name> -f <feature> -c <scenario> [-p profile] [-n notes]
|
|
145
180
|
scout list # scenarios + status + 📜 if cached script exists
|
|
146
|
-
scout go [-s
|
|
181
|
+
scout go [-s slug|name] [--ai] [--no-heal] [--headed] [--base-url <url>]
|
|
147
182
|
scout report [--json] [--check] # suite summary (markdown default)
|
|
183
|
+
scout migrate # legacy scenarios.json → .scout.md specs
|
|
148
184
|
scout login <profile> [--base-url <url>] # capture storageState in headed browser
|
|
149
185
|
scout mcp # MCP server stdio
|
|
150
186
|
```
|
|
@@ -165,7 +201,7 @@ scout report --json --check # prints the JSON AND sets the exit code
|
|
|
165
201
|
```jsonc
|
|
166
202
|
{
|
|
167
203
|
"scenarios": [
|
|
168
|
-
{ "
|
|
204
|
+
{ "slug": "paywall/paywall-free", "name": "Paywall free", "feature": "Paywall", "profile": "anon", "status": "verified", "lastRun": "2026-06-10T12:00:00.000Z" }
|
|
169
205
|
],
|
|
170
206
|
"summary": { "total": 4, "verified": 3, "failed": 1, "partial": 0, "blocked": 0, "pending": 0 }
|
|
171
207
|
}
|
|
@@ -204,7 +240,8 @@ src/
|
|
|
204
240
|
├── cli.ts # commander CLI
|
|
205
241
|
├── engine.ts # orchestrates: replay → (failed?) → AI heal → re-record
|
|
206
242
|
├── config.ts # scout.config.json + env overrides
|
|
207
|
-
├──
|
|
243
|
+
├── specs.ts # .scout.md parser + slug model + scenario writer
|
|
244
|
+
├── store.ts # .scout/ (specs, scripts, runs)
|
|
208
245
|
├── report.ts # per-run markdown + suite summary
|
|
209
246
|
├── runner/
|
|
210
247
|
│ ├── browser.ts # Playwright wrapper: snapshot with refs, trace, screenshots,
|
|
@@ -220,6 +257,7 @@ Design decisions:
|
|
|
220
257
|
- **Assertions are tools.** The agent registers each expectation via `browser_assert` — that's what makes the replay a real test, not just a click macro.
|
|
221
258
|
- **Recorded scripts are pruned before caching.** Agent retries (e.g. re-filling the same field) are deduplicated conservatively: an earlier `fill`/`select` is dropped only when a later one targets the same element and nothing in between (click/press/navigate) could have consumed the value. Clicks are never deduplicated.
|
|
222
259
|
- **Trace > video.** Playwright's trace.zip gives per-action screenshots, DOM, network, and console in a single navigable artifact. Raw video stays as an optional enhancement.
|
|
260
|
+
- **Scenarios are versioned source, not database rows.** One `.scout.md` per feature, reviewed in PRs like a `.test.ts`; the spec is a pure input that a run never mutates (status derives from `.scout/runs/`). The recorded JSON script is a derived sidecar — clean diffs, no run noise in history.
|
|
223
261
|
- **No server/dashboard.** State is the filesystem in the target repo; report is markdown. Pluggable into any project with `npm i` + 2 files.
|
|
224
262
|
|
|
225
263
|
## Known POC limitations
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,8 @@ import { Command } from "commander";
|
|
|
6
6
|
import { chromium } from "playwright";
|
|
7
7
|
import { CONFIG_FILE, SCOUT_DIR, loadConfig } from "./config.js";
|
|
8
8
|
import { runScenario } from "./engine.js";
|
|
9
|
-
import { buildReport, renderSummary } from "./report.js";
|
|
9
|
+
import { buildReport, renderSummary, scenarioStatus } from "./report.js";
|
|
10
|
+
import { addScenario, slugify } from "./specs.js";
|
|
10
11
|
import { Store } from "./store.js";
|
|
11
12
|
// Rejeições fora da cadeia de await (SDK/Playwright em subprocesso) não podem
|
|
12
13
|
// derrubar a suíte inteira — logar e deixar o cenário corrente falhar sozinho.
|
|
@@ -43,32 +44,31 @@ program
|
|
|
43
44
|
});
|
|
44
45
|
program
|
|
45
46
|
.command("create <name>")
|
|
46
|
-
.description("
|
|
47
|
+
.description("Adds a scenario to a feature spec (.scout/specs/<feature>.scout.md)")
|
|
48
|
+
.requiredOption("-f, --feature <feature>", "Feature/component — the spec file this scenario goes into")
|
|
47
49
|
.requiredOption("-c, --scenario <text>", "Scenario in natural language: flow + expected behavior")
|
|
48
50
|
.option("-p, --profile <profile>", "Auth profile (from scout.config.json)")
|
|
49
51
|
.option("-n, --notes <notes>", "Extra notes for the agent")
|
|
50
52
|
.action((name, opts) => {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
console.error("Run `scout init` first.");
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
const scenario = store.addScenario({
|
|
53
|
+
const scenario = addScenario({
|
|
54
|
+
feature: opts.feature,
|
|
57
55
|
name,
|
|
58
56
|
scenario: opts.scenario,
|
|
59
57
|
profile: opts.profile,
|
|
60
58
|
notes: opts.notes,
|
|
61
59
|
});
|
|
62
|
-
console.log(`✓ Scenario
|
|
60
|
+
console.log(`✓ Scenario created: ${scenario.slug} (${scenario.file})`);
|
|
63
61
|
});
|
|
64
62
|
program
|
|
65
63
|
.command("list")
|
|
66
64
|
.description("Lists scenarios and status")
|
|
67
65
|
.action(() => {
|
|
68
66
|
const store = new Store();
|
|
67
|
+
const latest = store.latestRuns();
|
|
69
68
|
for (const s of store.listScenarios()) {
|
|
70
69
|
const script = store.loadSteps(s.slug) ? "📜" : " ";
|
|
71
|
-
|
|
70
|
+
const status = scenarioStatus(s.slug, latest);
|
|
71
|
+
console.log(`${script} [${status.padEnd(8)}] ${s.slug} — ${s.name} (${s.profile ?? "anonymous"})`);
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
program
|
|
@@ -84,7 +84,7 @@ program
|
|
|
84
84
|
const config = loadConfig(process.cwd(), { baseUrl: opts.baseUrl });
|
|
85
85
|
const all = store.listScenarios();
|
|
86
86
|
const targets = opts.scenario
|
|
87
|
-
? all.filter((s) => s.
|
|
87
|
+
? all.filter((s) => s.slug === opts.scenario || s.name === opts.scenario)
|
|
88
88
|
: all;
|
|
89
89
|
if (!targets.length) {
|
|
90
90
|
console.error(opts.scenario ? `Scenario "${opts.scenario}" not found.` : "No scenarios. Use `scout create`.");
|
|
@@ -92,7 +92,7 @@ program
|
|
|
92
92
|
}
|
|
93
93
|
let failed = 0;
|
|
94
94
|
for (const scenario of targets) {
|
|
95
|
-
process.stdout.write(`▶
|
|
95
|
+
process.stdout.write(`▶ ${scenario.slug} ... `);
|
|
96
96
|
try {
|
|
97
97
|
const result = await runScenario(store, scenario, config, {
|
|
98
98
|
forceAi: opts.ai,
|
|
@@ -123,15 +123,53 @@ program
|
|
|
123
123
|
.action((opts) => {
|
|
124
124
|
const store = new Store();
|
|
125
125
|
const scenarios = store.listScenarios();
|
|
126
|
+
const latest = store.latestRuns();
|
|
126
127
|
if (opts.json) {
|
|
127
|
-
console.log(JSON.stringify(buildReport(scenarios), null, 2));
|
|
128
|
+
console.log(JSON.stringify(buildReport(scenarios, latest), null, 2));
|
|
128
129
|
}
|
|
129
130
|
else {
|
|
130
|
-
console.log(renderSummary(scenarios,
|
|
131
|
+
console.log(renderSummary(scenarios, latest));
|
|
131
132
|
}
|
|
132
133
|
if (opts.check) {
|
|
133
|
-
process.exit(scenarios.every((s) => s.
|
|
134
|
+
process.exit(scenarios.every((s) => scenarioStatus(s.slug, latest) === "verified") ? 0 : 1);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
program
|
|
138
|
+
.command("migrate")
|
|
139
|
+
.description("Converts a legacy .scout/scenarios.json into .scout/specs/*.scout.md and relocates cached scripts")
|
|
140
|
+
.action(() => {
|
|
141
|
+
const store = new Store();
|
|
142
|
+
const legacy = path.join(process.cwd(), SCOUT_DIR, "scenarios.json");
|
|
143
|
+
if (!fs.existsSync(legacy)) {
|
|
144
|
+
console.log("Nothing to migrate — no .scout/scenarios.json found.");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const old = JSON.parse(fs.readFileSync(legacy, "utf8"));
|
|
148
|
+
const existing = new Set(store.listScenarios().map((s) => s.slug));
|
|
149
|
+
let created = 0;
|
|
150
|
+
let scripts = 0;
|
|
151
|
+
let skipped = 0;
|
|
152
|
+
for (const s of old) {
|
|
153
|
+
const slug = `${slugify(s.slug)}/${slugify(s.name)}`;
|
|
154
|
+
if (existing.has(slug)) {
|
|
155
|
+
skipped++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
// feature = old slug keeps the spec filename == old slug, so the cached
|
|
159
|
+
// script can be relocated deterministically under the new nested path.
|
|
160
|
+
addScenario({ feature: s.slug, name: s.name, scenario: s.scenario, profile: s.profile, notes: s.notes });
|
|
161
|
+
created++;
|
|
162
|
+
const oldScript = path.join(process.cwd(), SCOUT_DIR, "scripts", `${s.slug}.json`);
|
|
163
|
+
if (fs.existsSync(oldScript)) {
|
|
164
|
+
const newScript = store.scriptPath(slug);
|
|
165
|
+
fs.mkdirSync(path.dirname(newScript), { recursive: true });
|
|
166
|
+
fs.renameSync(oldScript, newScript);
|
|
167
|
+
scripts++;
|
|
168
|
+
}
|
|
134
169
|
}
|
|
170
|
+
fs.renameSync(legacy, legacy + ".bak");
|
|
171
|
+
console.log(`✓ Migrated ${created} scenario(s), relocated ${scripts} cached script(s)${skipped ? `, skipped ${skipped} already present` : ""}.`);
|
|
172
|
+
console.log(" Legacy file moved to .scout/scenarios.json.bak — review .scout/specs/ (and the `feature:` frontmatter) then delete the .bak.");
|
|
135
173
|
});
|
|
136
174
|
program
|
|
137
175
|
.command("login <profile>")
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -38,7 +38,6 @@ export async function runScenario(store, scenario, config = loadConfig(), opts =
|
|
|
38
38
|
const trace = await session.close();
|
|
39
39
|
if (replay.passed) {
|
|
40
40
|
result = {
|
|
41
|
-
scenarioId: scenario.id,
|
|
42
41
|
slug: scenario.slug,
|
|
43
42
|
mode: "replay",
|
|
44
43
|
verdict: "verified",
|
|
@@ -64,7 +63,6 @@ export async function runScenario(store, scenario, config = loadConfig(), opts =
|
|
|
64
63
|
}
|
|
65
64
|
else {
|
|
66
65
|
result = {
|
|
67
|
-
scenarioId: scenario.id,
|
|
68
66
|
slug: scenario.slug,
|
|
69
67
|
mode: "replay",
|
|
70
68
|
verdict: "failed",
|
|
@@ -87,7 +85,6 @@ export async function runScenario(store, scenario, config = loadConfig(), opts =
|
|
|
87
85
|
result = { ...aiResult, startedAt, durationMs: Date.now() - start };
|
|
88
86
|
}
|
|
89
87
|
store.saveRunResult(result);
|
|
90
|
-
store.updateScenario(scenario.id, { status: result.verdict, lastRun: result.startedAt });
|
|
91
88
|
fs.writeFileSync(path.join(runDir, "report.md"), renderRunReport(result, scenario, store.loadSteps(scenario.slug)));
|
|
92
89
|
return result;
|
|
93
90
|
}
|
|
@@ -140,7 +137,6 @@ async function runAi(scenario, config, store, runDir, storageState, opts) {
|
|
|
140
137
|
store.saveSteps(scenario.slug, pruneSteps(outcome.steps));
|
|
141
138
|
}
|
|
142
139
|
return {
|
|
143
|
-
scenarioId: scenario.id,
|
|
144
140
|
slug: scenario.slug,
|
|
145
141
|
mode: "ai",
|
|
146
142
|
verdict: outcome.verdict,
|
package/dist/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAoB,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAWtE,SAAS,WAAW;IAClB,OAAO,OAAO,CACZ,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC3B,OAAO,CAAC,GAAG,CAAC,uBAAuB;QACnC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,CAAC,CAAC,CAC9D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAY,EACZ,QAAkB,EAClB,SAAsB,UAAU,EAAE,EAClC,OAAmB,EAAE;IAErB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEzE,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,cAAc,CAAC,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ;QAC/C,YAAY;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM;KACP,CAAC,CAAC;IAEL,IAAI,MAAiB,CAAC;IAEtB,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QAEpC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,GAAG;gBACP,
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { loadConfig, type ConfigOverrides, type ScoutConfig, type ScoutProfile } from "./config.js";
|
|
2
2
|
export { pruneSteps, runAiWithRetry, runScenario, type RunOptions } from "./engine.js";
|
|
3
|
-
export { buildReport, renderRunReport, renderSummary, type ReportData, type ReportScenario } from "./report.js";
|
|
3
|
+
export { buildReport, renderRunReport, renderSummary, scenarioStatus, type ReportData, type ReportScenario } from "./report.js";
|
|
4
4
|
export { describeNoVerdict, relativizeUrl, type QueryEndInfo } from "./runner/ai-runner.js";
|
|
5
|
+
export { addScenario, loadScenarios, parseSpec, slugify, slugToToken, type NewScenarioInput } from "./specs.js";
|
|
5
6
|
export { Store } from "./store.js";
|
|
6
|
-
export type { RunResult, Scenario, Step, Target, Verdict } from "./types.js";
|
|
7
|
+
export type { RunResult, Scenario, ScenarioStatus, Step, Target, Verdict } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { loadConfig } from "./config.js";
|
|
2
2
|
export { pruneSteps, runAiWithRetry, runScenario } from "./engine.js";
|
|
3
|
-
export { buildReport, renderRunReport, renderSummary } from "./report.js";
|
|
3
|
+
export { buildReport, renderRunReport, renderSummary, scenarioStatus } from "./report.js";
|
|
4
4
|
export { describeNoVerdict, relativizeUrl } from "./runner/ai-runner.js";
|
|
5
|
+
export { addScenario, loadScenarios, parseSpec, slugify, slugToToken } from "./specs.js";
|
|
5
6
|
export { Store } from "./store.js";
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA6D,MAAM,aAAa,CAAC;AACpG,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAwC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA6D,MAAM,aAAa,CAAC;AACpG,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAwC,MAAM,aAAa,CAAC;AAChI,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAqB,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAyB,MAAM,YAAY,CAAC;AAChH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -5,7 +5,8 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { loadConfig } from "../config.js";
|
|
7
7
|
import { runScenario } from "../engine.js";
|
|
8
|
-
import { renderSummary } from "../report.js";
|
|
8
|
+
import { renderSummary, scenarioStatus } from "../report.js";
|
|
9
|
+
import { addScenario } from "../specs.js";
|
|
9
10
|
import { Store } from "../store.js";
|
|
10
11
|
/**
|
|
11
12
|
* MCP interface so coding agents (Claude Code local or cloud sessions) can
|
|
@@ -22,33 +23,36 @@ export async function startMcpServer() {
|
|
|
22
23
|
description: "Lista os cenários de QA do projeto com status e se há script cacheado.",
|
|
23
24
|
inputSchema: {},
|
|
24
25
|
}, async () => {
|
|
26
|
+
const latest = store.latestRuns();
|
|
25
27
|
const scenarios = store.listScenarios().map((s) => ({
|
|
26
28
|
...s,
|
|
29
|
+
status: scenarioStatus(s.slug, latest),
|
|
30
|
+
lastRun: latest.get(s.slug)?.startedAt ?? null,
|
|
27
31
|
hasCachedScript: Boolean(store.loadSteps(s.slug)),
|
|
28
32
|
}));
|
|
29
33
|
return { content: [{ type: "text", text: JSON.stringify(scenarios, null, 2) }] };
|
|
30
34
|
});
|
|
31
35
|
server.registerTool("scout_create_scenario", {
|
|
32
|
-
description: "Cria um cenário de verificação em linguagem natural. Descreva o FLUXO (passos do usuário) e o COMPORTAMENTO ESPERADO (o que deve/não deve acontecer). Não escreva seletores nem código — o runner descobre sozinho no browser.",
|
|
36
|
+
description: "Cria um cenário de verificação em linguagem natural num arquivo de feature (.scout/specs/<feature>.scout.md). Descreva o FLUXO (passos do usuário) e o COMPORTAMENTO ESPERADO (o que deve/não deve acontecer). Não escreva seletores nem código — o runner descobre sozinho no browser.",
|
|
33
37
|
inputSchema: {
|
|
34
|
-
|
|
38
|
+
feature: z.string().describe("Feature/component — o arquivo de spec onde o cenário entra (agrupa cenários relacionados)"),
|
|
39
|
+
name: z.string().describe("Nome curto do cenário (vira o heading)"),
|
|
35
40
|
scenario: z.string().describe("Fluxo + expectativas em linguagem natural"),
|
|
36
41
|
profile: z.string().optional().describe("Profile de auth de scout.config.json (omitir = anônimo)"),
|
|
37
42
|
notes: z.string().optional().describe("Contexto extra para o runner"),
|
|
38
43
|
},
|
|
39
|
-
}, async ({ name, scenario, profile, notes }) => {
|
|
40
|
-
|
|
41
|
-
const created = store.addScenario({ name, scenario, profile, notes });
|
|
44
|
+
}, async ({ feature, name, scenario, profile, notes }) => {
|
|
45
|
+
const created = addScenario({ feature, name, scenario, profile, notes });
|
|
42
46
|
return {
|
|
43
47
|
content: [
|
|
44
|
-
{ type: "text", text: `Cenário
|
|
48
|
+
{ type: "text", text: `Cenário ${created.slug} criado em ${created.file}. Rode com scout_run.` },
|
|
45
49
|
],
|
|
46
50
|
};
|
|
47
51
|
});
|
|
48
52
|
server.registerTool("scout_run", {
|
|
49
53
|
description: "Roda a verificação de um cenário (ou todos). Usa o script determinístico cacheado quando existe; cai pro agente AI no primeiro run ou quando o script quebra (self-healing). Retorna veredito + evidências.",
|
|
50
54
|
inputSchema: {
|
|
51
|
-
scenario: z.string().optional().describe("
|
|
55
|
+
scenario: z.string().optional().describe("slug do cenário (<feature>/<cenário>); omitir = todos"),
|
|
52
56
|
forceAi: z.boolean().optional().describe("Ignora o cache e re-grava o script via AI"),
|
|
53
57
|
baseUrl: z
|
|
54
58
|
.string()
|
|
@@ -59,7 +63,7 @@ export async function startMcpServer() {
|
|
|
59
63
|
const config = loadConfig(process.cwd(), { baseUrl });
|
|
60
64
|
const all = store.listScenarios();
|
|
61
65
|
const targets = scenario
|
|
62
|
-
? all.filter((s) => s.
|
|
66
|
+
? all.filter((s) => s.slug === scenario || s.name === scenario)
|
|
63
67
|
: all;
|
|
64
68
|
if (!targets.length) {
|
|
65
69
|
return { content: [{ type: "text", text: `Nenhum cenário encontrado para "${scenario}".` }], isError: true };
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/dist/report.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { RunResult, Scenario, ScenarioStatus, Step } from "./types.js";
|
|
|
2
2
|
/** Per-run report saved at .scout/runs/<id>/report.md */
|
|
3
3
|
export declare function renderRunReport(result: RunResult, scenario: Scenario, steps?: Step[]): string;
|
|
4
4
|
export interface ReportScenario {
|
|
5
|
-
id: number;
|
|
6
5
|
slug: string;
|
|
7
6
|
name: string;
|
|
7
|
+
feature: string;
|
|
8
8
|
profile: string | null;
|
|
9
9
|
status: ScenarioStatus;
|
|
10
10
|
lastRun: string | null;
|
|
@@ -20,7 +20,9 @@ export interface ReportData {
|
|
|
20
20
|
pending: number;
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
/** Status of a scenario derived from its latest run (pure-input specs never store it). */
|
|
24
|
+
export declare function scenarioStatus(slug: string, latest: Map<string, RunResult>): ScenarioStatus;
|
|
23
25
|
/** Structured suite report (the `scout report --json` output) — for CI/PR gates. */
|
|
24
|
-
export declare function buildReport(scenarios: Scenario[]): ReportData;
|
|
26
|
+
export declare function buildReport(scenarios: Scenario[], latest: Map<string, RunResult>): ReportData;
|
|
25
27
|
/** Suite summary — PR-embeddable (the \`scout report\` output). */
|
|
26
28
|
export declare function renderSummary(scenarios: Scenario[], latest: Map<string, RunResult>): string;
|
package/dist/report.js
CHANGED
|
@@ -40,20 +40,25 @@ export function renderRunReport(result, scenario, steps) {
|
|
|
40
40
|
}
|
|
41
41
|
return lines.join("\n") + "\n";
|
|
42
42
|
}
|
|
43
|
+
/** Status of a scenario derived from its latest run (pure-input specs never store it). */
|
|
44
|
+
export function scenarioStatus(slug, latest) {
|
|
45
|
+
return latest.get(slug)?.verdict ?? "pending";
|
|
46
|
+
}
|
|
43
47
|
/** Structured suite report (the `scout report --json` output) — for CI/PR gates. */
|
|
44
|
-
export function buildReport(scenarios) {
|
|
45
|
-
const
|
|
48
|
+
export function buildReport(scenarios, latest) {
|
|
49
|
+
const rows = scenarios.map((s) => ({
|
|
50
|
+
slug: s.slug,
|
|
51
|
+
name: s.name,
|
|
52
|
+
feature: s.feature,
|
|
53
|
+
profile: s.profile ?? null,
|
|
54
|
+
status: scenarioStatus(s.slug, latest),
|
|
55
|
+
lastRun: latest.get(s.slug)?.startedAt ?? null,
|
|
56
|
+
}));
|
|
57
|
+
const count = (status) => rows.filter((r) => r.status === status).length;
|
|
46
58
|
return {
|
|
47
|
-
scenarios:
|
|
48
|
-
id: s.id,
|
|
49
|
-
slug: s.slug,
|
|
50
|
-
name: s.name,
|
|
51
|
-
profile: s.profile ?? null,
|
|
52
|
-
status: s.status,
|
|
53
|
-
lastRun: s.lastRun ?? null,
|
|
54
|
-
})),
|
|
59
|
+
scenarios: rows,
|
|
55
60
|
summary: {
|
|
56
|
-
total:
|
|
61
|
+
total: rows.length,
|
|
57
62
|
verified: count("verified"),
|
|
58
63
|
failed: count("failed"),
|
|
59
64
|
partial: count("partial"),
|
|
@@ -67,15 +72,19 @@ export function renderSummary(scenarios, latest) {
|
|
|
67
72
|
const lines = [
|
|
68
73
|
`## 🔭 Scout — browser verification`,
|
|
69
74
|
``,
|
|
70
|
-
`|
|
|
71
|
-
|
|
75
|
+
`| Feature | Scenario | Profile | Status | Mode | Last run |`,
|
|
76
|
+
`|---------|----------|---------|--------|------|----------|`,
|
|
72
77
|
];
|
|
73
78
|
for (const s of scenarios) {
|
|
74
79
|
const run = latest.get(s.slug);
|
|
80
|
+
const status = scenarioStatus(s.slug, latest);
|
|
75
81
|
const mode = run ? (run.mode === "replay" ? "replay" : run.healed ? "AI (healed)" : "AI") : "—";
|
|
76
|
-
lines.push(`| ${s.
|
|
82
|
+
lines.push(`| ${s.feature} | ${s.name} | ${s.profile ?? "anonymous"} | ${ICON[status]} ${status} | ${mode} | ${run?.startedAt ? run.startedAt.slice(0, 16).replace("T", " ") : "never"} |`);
|
|
77
83
|
}
|
|
78
|
-
const failing = scenarios.filter((s) =>
|
|
84
|
+
const failing = scenarios.filter((s) => {
|
|
85
|
+
const status = scenarioStatus(s.slug, latest);
|
|
86
|
+
return status === "failed" || status === "blocked";
|
|
87
|
+
});
|
|
79
88
|
if (failing.length) {
|
|
80
89
|
lines.push(``, `### Failures`, ``);
|
|
81
90
|
for (const s of failing) {
|
|
@@ -83,7 +92,7 @@ export function renderSummary(scenarios, latest) {
|
|
|
83
92
|
lines.push(`- **${s.name}**: ${run?.reason ?? "no run recorded"}`);
|
|
84
93
|
}
|
|
85
94
|
}
|
|
86
|
-
const verified = scenarios.filter((s) => s.
|
|
95
|
+
const verified = scenarios.filter((s) => scenarioStatus(s.slug, latest) === "verified").length;
|
|
87
96
|
lines.push(``, `**${verified}/${scenarios.length} verified.**`);
|
|
88
97
|
return lines.join("\n") + "\n";
|
|
89
98
|
}
|
package/dist/report.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,MAAM,IAAI,GAAmC;IAC3C,QAAQ,EAAE,GAAG;IACb,MAAM,EAAE,GAAG;IACX,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,GAAG;CACb,CAAC;AAEF,yDAAyD;AACzD,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,QAAkB,EAAE,KAAc;IACnF,MAAM,KAAK,GAAG;QACZ,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE;QAC5C,EAAE;QACF,OAAO;QACP,WAAW;QACX,iBAAiB,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC,EAAE,IAAI;QAC5G,YAAY,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI;QAClH,eAAe,QAAQ,CAAC,OAAO,IAAI,WAAW,IAAI;QAClD,gBAAgB,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;QAC1D,eAAe,MAAM,CAAC,SAAS,IAAI;QACnC,EAAE;QACF,iBAAiB,QAAQ,CAAC,QAAQ,EAAE;QACpC,EAAE;QACF,kBAAkB,MAAM,CAAC,MAAM,EAAE;KAClC,CAAC;IAEF,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,uBAAuB,KAAK,CAAC,MAAM,SAAS,EAAE,EAAE,CAAC,CAAC;QACjE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;QAClC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,GAAG,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CACR,EAAE,EACF,UAAU,EACV,EAAE,EACF,+BAA+B,MAAM,CAAC,KAAK,8EAA8E,CAC1H,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC;AAuBD,
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
|
package/dist/specs.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Scenario } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scenario specs live as markdown files under `.scout/specs/**\/*.scout.md`.
|
|
4
|
+
* One file per feature/component; each `## heading` is one scenario. The
|
|
5
|
+
* markdown is the human-authored source of truth — a *pure input* that is
|
|
6
|
+
* never written back to by a run (status/last-run derive from `.scout/runs/`).
|
|
7
|
+
*
|
|
8
|
+
* The format mirrors the Playwright Agents test-plan layout (feature file with
|
|
9
|
+
* scenario sections) and adds YAML frontmatter as a superset for scout-specific
|
|
10
|
+
* config (profile, tags). Per-scenario overrides may follow a heading as
|
|
11
|
+
* `key: value` lines before the prose.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SPECS_DIR = "specs";
|
|
14
|
+
export declare function slugify(name: string): string;
|
|
15
|
+
/** A logical slug `<file>/<scenario>` → a single filesystem-safe token. */
|
|
16
|
+
export declare function slugToToken(slug: string): string;
|
|
17
|
+
/** Parse a single `.scout.md` file into its scenarios. */
|
|
18
|
+
export declare function parseSpec(specFile: string, root: string, cwd: string): Scenario[];
|
|
19
|
+
/** Load every scenario across all spec files, validating slug uniqueness. */
|
|
20
|
+
export declare function loadScenarios(cwd?: string): Scenario[];
|
|
21
|
+
export interface NewScenarioInput {
|
|
22
|
+
feature: string;
|
|
23
|
+
name: string;
|
|
24
|
+
scenario: string;
|
|
25
|
+
profile?: string;
|
|
26
|
+
notes?: string;
|
|
27
|
+
tags?: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Append a scenario to `.scout/specs/<feature-slug>.scout.md`, creating the
|
|
31
|
+
* file with frontmatter when it does not exist. Returns the logical slug.
|
|
32
|
+
*/
|
|
33
|
+
export declare function addScenario(input: NewScenarioInput, cwd?: string): Scenario;
|
package/dist/specs.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import { SCOUT_DIR } from "./config.js";
|
|
5
|
+
/**
|
|
6
|
+
* Scenario specs live as markdown files under `.scout/specs/**\/*.scout.md`.
|
|
7
|
+
* One file per feature/component; each `## heading` is one scenario. The
|
|
8
|
+
* markdown is the human-authored source of truth — a *pure input* that is
|
|
9
|
+
* never written back to by a run (status/last-run derive from `.scout/runs/`).
|
|
10
|
+
*
|
|
11
|
+
* The format mirrors the Playwright Agents test-plan layout (feature file with
|
|
12
|
+
* scenario sections) and adds YAML frontmatter as a superset for scout-specific
|
|
13
|
+
* config (profile, tags). Per-scenario overrides may follow a heading as
|
|
14
|
+
* `key: value` lines before the prose.
|
|
15
|
+
*/
|
|
16
|
+
export const SPECS_DIR = "specs";
|
|
17
|
+
const SPEC_EXT = ".scout.md";
|
|
18
|
+
/** Per-scenario override keys allowed under a heading. */
|
|
19
|
+
const OVERRIDE_KEYS = new Set(["profile", "notes", "tags"]);
|
|
20
|
+
export function slugify(name) {
|
|
21
|
+
return name
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
.normalize("NFD")
|
|
24
|
+
.replace(/[̀-ͯ]/g, "")
|
|
25
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
26
|
+
.replace(/^-|-$/g, "")
|
|
27
|
+
.slice(0, 60);
|
|
28
|
+
}
|
|
29
|
+
/** A logical slug `<file>/<scenario>` → a single filesystem-safe token. */
|
|
30
|
+
export function slugToToken(slug) {
|
|
31
|
+
return slug.replace(/\//g, "__");
|
|
32
|
+
}
|
|
33
|
+
function specsRoot(cwd) {
|
|
34
|
+
return path.join(cwd, SCOUT_DIR, SPECS_DIR);
|
|
35
|
+
}
|
|
36
|
+
/** All `*.scout.md` under `.scout/specs`, recursively, sorted for stable order. */
|
|
37
|
+
function findSpecFiles(dir) {
|
|
38
|
+
if (!fs.existsSync(dir))
|
|
39
|
+
return [];
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
42
|
+
const full = path.join(dir, entry.name);
|
|
43
|
+
if (entry.isDirectory())
|
|
44
|
+
out.push(...findSpecFiles(full));
|
|
45
|
+
else if (entry.isFile() && entry.name.endsWith(SPEC_EXT))
|
|
46
|
+
out.push(full);
|
|
47
|
+
}
|
|
48
|
+
return out.sort();
|
|
49
|
+
}
|
|
50
|
+
/** `.scout/specs/auth/login.scout.md` → `auth/login` (each segment slugified). */
|
|
51
|
+
function fileSlugFromPath(specFile, root) {
|
|
52
|
+
const rel = path.relative(root, specFile).replace(new RegExp(`${SPEC_EXT.replace(".", "\\.")}$`), "");
|
|
53
|
+
return rel
|
|
54
|
+
.split(path.sep)
|
|
55
|
+
.map((seg) => slugify(seg))
|
|
56
|
+
.join("/");
|
|
57
|
+
}
|
|
58
|
+
function parseTags(raw) {
|
|
59
|
+
if (Array.isArray(raw))
|
|
60
|
+
return raw.map(String);
|
|
61
|
+
if (typeof raw === "string") {
|
|
62
|
+
const inner = raw.trim().replace(/^\[|\]$/g, "");
|
|
63
|
+
const parts = inner.split(",").map((t) => t.trim()).filter(Boolean);
|
|
64
|
+
return parts.length ? parts : undefined;
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Split markdown body into `## ` sections (h1/h3+ and preamble are ignored).
|
|
70
|
+
* Fenced code blocks (``` ... ```) are skipped so a documented `## ` inside a
|
|
71
|
+
* fence is not mistaken for a real scenario heading.
|
|
72
|
+
*/
|
|
73
|
+
function splitSections(content) {
|
|
74
|
+
const sections = [];
|
|
75
|
+
let cur = null;
|
|
76
|
+
let inFence = false;
|
|
77
|
+
for (const line of content.split("\n")) {
|
|
78
|
+
if (/^\s*```/.test(line))
|
|
79
|
+
inFence = !inFence;
|
|
80
|
+
const m = inFence ? null : /^##\s+(.+?)\s*$/.exec(line);
|
|
81
|
+
if (m) {
|
|
82
|
+
cur = { name: m[1].trim(), bodyLines: [] };
|
|
83
|
+
sections.push(cur);
|
|
84
|
+
}
|
|
85
|
+
else if (cur) {
|
|
86
|
+
cur.bodyLines.push(line);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return sections;
|
|
90
|
+
}
|
|
91
|
+
/** Parse a single `.scout.md` file into its scenarios. */
|
|
92
|
+
export function parseSpec(specFile, root, cwd) {
|
|
93
|
+
const fileSlug = fileSlugFromPath(specFile, root);
|
|
94
|
+
const raw = fs.readFileSync(specFile, "utf8");
|
|
95
|
+
const { data, content } = matter(raw);
|
|
96
|
+
const fileFeature = typeof data.feature === "string" ? data.feature : path.basename(specFile).replace(SPEC_EXT, "");
|
|
97
|
+
const fileProfile = typeof data.profile === "string" ? data.profile : undefined;
|
|
98
|
+
const fileTags = parseTags(data.tags);
|
|
99
|
+
const relFile = path.relative(cwd, specFile);
|
|
100
|
+
const sections = splitSections(content);
|
|
101
|
+
const scenarios = [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const section of sections) {
|
|
104
|
+
// Consume optional leading `key: value` overrides, then the prose.
|
|
105
|
+
const lines = section.bodyLines;
|
|
106
|
+
let i = 0;
|
|
107
|
+
while (i < lines.length && lines[i].trim() === "")
|
|
108
|
+
i++;
|
|
109
|
+
const overrides = {};
|
|
110
|
+
while (i < lines.length && lines[i].trim() !== "") {
|
|
111
|
+
const m = /^([a-zA-Z]+):\s*(.+)$/.exec(lines[i].trim());
|
|
112
|
+
if (!m || !OVERRIDE_KEYS.has(m[1]))
|
|
113
|
+
break;
|
|
114
|
+
overrides[m[1]] = m[2].trim();
|
|
115
|
+
i++;
|
|
116
|
+
}
|
|
117
|
+
while (i < lines.length && lines[i].trim() === "")
|
|
118
|
+
i++;
|
|
119
|
+
const text = lines.slice(i).join("\n").trim();
|
|
120
|
+
if (!text) {
|
|
121
|
+
throw new Error(`Scenario "${section.name}" in ${relFile} has no description text.`);
|
|
122
|
+
}
|
|
123
|
+
const scenarioSlug = slugify(section.name);
|
|
124
|
+
if (seen.has(scenarioSlug)) {
|
|
125
|
+
throw new Error(`Duplicate scenario "${section.name}" (slug "${scenarioSlug}") in ${relFile}.`);
|
|
126
|
+
}
|
|
127
|
+
seen.add(scenarioSlug);
|
|
128
|
+
const tags = parseTags(overrides.tags) ?? fileTags;
|
|
129
|
+
scenarios.push({
|
|
130
|
+
slug: `${fileSlug}/${scenarioSlug}`,
|
|
131
|
+
name: section.name,
|
|
132
|
+
scenario: text,
|
|
133
|
+
feature: fileFeature,
|
|
134
|
+
profile: overrides.profile ?? fileProfile,
|
|
135
|
+
notes: overrides.notes,
|
|
136
|
+
tags,
|
|
137
|
+
file: relFile,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return scenarios;
|
|
141
|
+
}
|
|
142
|
+
/** Load every scenario across all spec files, validating slug uniqueness. */
|
|
143
|
+
export function loadScenarios(cwd = process.cwd()) {
|
|
144
|
+
const root = specsRoot(cwd);
|
|
145
|
+
const all = [];
|
|
146
|
+
const bySlug = new Map();
|
|
147
|
+
for (const file of findSpecFiles(root)) {
|
|
148
|
+
for (const scenario of parseSpec(file, root, cwd)) {
|
|
149
|
+
const prev = bySlug.get(scenario.slug);
|
|
150
|
+
if (prev) {
|
|
151
|
+
throw new Error(`Duplicate scenario slug "${scenario.slug}" in ${scenario.file} (also in ${prev}).`);
|
|
152
|
+
}
|
|
153
|
+
bySlug.set(scenario.slug, scenario.file);
|
|
154
|
+
all.push(scenario);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return all;
|
|
158
|
+
}
|
|
159
|
+
/** Render a `## ` section (with optional overrides) for appending to a spec. */
|
|
160
|
+
function renderSection(input) {
|
|
161
|
+
const overrides = [];
|
|
162
|
+
if (input.profile)
|
|
163
|
+
overrides.push(`profile: ${input.profile}`);
|
|
164
|
+
if (input.notes)
|
|
165
|
+
overrides.push(`notes: ${input.notes}`);
|
|
166
|
+
if (input.tags?.length)
|
|
167
|
+
overrides.push(`tags: [${input.tags.join(", ")}]`);
|
|
168
|
+
const head = `## ${input.name}\n`;
|
|
169
|
+
const meta = overrides.length ? overrides.join("\n") + "\n\n" : "";
|
|
170
|
+
return `${head}${meta}${input.scenario.trim()}\n`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Append a scenario to `.scout/specs/<feature-slug>.scout.md`, creating the
|
|
174
|
+
* file with frontmatter when it does not exist. Returns the logical slug.
|
|
175
|
+
*/
|
|
176
|
+
export function addScenario(input, cwd = process.cwd()) {
|
|
177
|
+
const root = specsRoot(cwd);
|
|
178
|
+
const fileSlug = slugify(input.feature);
|
|
179
|
+
const specFile = path.join(root, `${fileSlug}${SPEC_EXT}`);
|
|
180
|
+
fs.mkdirSync(path.dirname(specFile), { recursive: true });
|
|
181
|
+
const section = renderSection(input);
|
|
182
|
+
if (!fs.existsSync(specFile)) {
|
|
183
|
+
const frontmatter = `---\nfeature: ${input.feature}\n---\n\n`;
|
|
184
|
+
fs.writeFileSync(specFile, frontmatter + section);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
const existing = fs.readFileSync(specFile, "utf8").replace(/\s*$/, "");
|
|
188
|
+
fs.writeFileSync(specFile, existing + "\n\n" + section);
|
|
189
|
+
}
|
|
190
|
+
const scenarioSlug = slugify(input.name);
|
|
191
|
+
const slug = `${fileSlug}/${scenarioSlug}`;
|
|
192
|
+
const found = parseSpec(specFile, root, cwd).find((s) => s.slug === slug);
|
|
193
|
+
if (!found) {
|
|
194
|
+
throw new Error(`Failed to round-trip scenario "${input.name}" into ${path.relative(cwd, specFile)}.`);
|
|
195
|
+
}
|
|
196
|
+
return found;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=specs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specs.js","sourceRoot":"","sources":["../src/specs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,MAAM,QAAQ,GAAG,WAAW,CAAC;AAC7B,0DAA0D;AAC1D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAC9C,CAAC;AAED,mFAAmF;AACnF,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;aACrD,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,kFAAkF;AAClF,SAAS,gBAAgB,CAAC,QAAgB,EAAE,IAAY;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IACtG,OAAO,GAAG;SACP,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;SACf,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;SAC1B,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAOD;;;;GAIG;AACH,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,GAAG,GAAmB,IAAI,CAAC;IAC/B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,EAAE,CAAC;YACN,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,GAAG,EAAE,CAAC;YACf,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,IAAY,EAAE,GAAW;IACnE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAEtC,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpH,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAChF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,mEAAmE;QACnE,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,CAAC,EAAE,CAAC;QACvD,MAAM,SAAS,GAA2B,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAClD,MAAM,CAAC,GAAG,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAE,MAAM;YAC1C,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,CAAC,EAAE,CAAC;QACN,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAE9C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,aAAa,OAAO,CAAC,IAAI,QAAQ,OAAO,2BAA2B,CAAC,CAAC;QACvF,CAAC;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,CAAC,IAAI,YAAY,YAAY,SAAS,OAAO,GAAG,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAEvB,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;QACnD,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,GAAG,QAAQ,IAAI,YAAY,EAAE;YACnC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,WAAW;YACzC,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,IAAI;YACJ,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,IAAI,QAAQ,QAAQ,CAAC,IAAI,aAAa,IAAI,IAAI,CAAC,CAAC;YACvG,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YACzC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAWD,gFAAgF;AAChF,SAAS,aAAa,CAAC,KAAuB;IAC5C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,KAAK,CAAC,OAAO;QAAE,SAAS,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/D,IAAI,KAAK,CAAC,KAAK;QAAE,SAAS,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM;QAAE,SAAS,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC;IAClC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACtE,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC3D,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,iBAAiB,KAAK,CAAC,OAAO,WAAW,CAAC;QAC9D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,QAAQ,IAAI,YAAY,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,CAAC,IAAI,UAAU,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzG,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
import type { RunResult, Scenario, Step } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Filesystem store inside the target project:
|
|
4
|
-
* .scout/
|
|
5
|
-
* .scout/scripts/<slug>.json
|
|
6
|
-
* .scout/runs/<runId>/
|
|
7
|
-
* .scout/state/<profile>.json
|
|
4
|
+
* .scout/specs/<feature>.scout.md — committed (the suite; markdown source of truth)
|
|
5
|
+
* .scout/scripts/<slug>.json — committed (cached deterministic steps; `<slug>` is `<file>/<scenario>`)
|
|
6
|
+
* .scout/runs/<runId>/ — gitignored (artifacts per run)
|
|
7
|
+
* .scout/state/<profile>.json — gitignored (auth storageState)
|
|
8
8
|
*/
|
|
9
9
|
export declare class Store {
|
|
10
10
|
readonly root: string;
|
|
11
|
+
readonly cwd: string;
|
|
11
12
|
constructor(cwd?: string);
|
|
12
13
|
init(): void;
|
|
13
|
-
get scenariosFile(): string;
|
|
14
14
|
exists(): boolean;
|
|
15
15
|
listScenarios(): Scenario[];
|
|
16
|
-
|
|
17
|
-
addScenario(input: {
|
|
18
|
-
name: string;
|
|
19
|
-
scenario: string;
|
|
20
|
-
profile?: string;
|
|
21
|
-
notes?: string;
|
|
22
|
-
}): Scenario;
|
|
23
|
-
getScenario(idOrSlug: number | string): Scenario | undefined;
|
|
24
|
-
updateScenario(id: number, patch: Partial<Scenario>): void;
|
|
16
|
+
getScenario(slug: string): Scenario | undefined;
|
|
25
17
|
scriptPath(slug: string): string;
|
|
26
18
|
loadSteps(slug: string): Step[] | undefined;
|
|
27
19
|
saveSteps(slug: string, steps: Step[]): void;
|
|
@@ -30,4 +22,3 @@ export declare class Store {
|
|
|
30
22
|
/** Latest run result per scenario slug (for `scout report`) */
|
|
31
23
|
latestRuns(): Map<string, RunResult>;
|
|
32
24
|
}
|
|
33
|
-
export declare function slugify(name: string): string;
|
package/dist/store.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { SCOUT_DIR } from "./config.js";
|
|
4
|
+
import { SPECS_DIR, loadScenarios, slugToToken } from "./specs.js";
|
|
4
5
|
/**
|
|
5
6
|
* Filesystem store inside the target project:
|
|
6
|
-
* .scout/
|
|
7
|
-
* .scout/scripts/<slug>.json
|
|
8
|
-
* .scout/runs/<runId>/
|
|
9
|
-
* .scout/state/<profile>.json
|
|
7
|
+
* .scout/specs/<feature>.scout.md — committed (the suite; markdown source of truth)
|
|
8
|
+
* .scout/scripts/<slug>.json — committed (cached deterministic steps; `<slug>` is `<file>/<scenario>`)
|
|
9
|
+
* .scout/runs/<runId>/ — gitignored (artifacts per run)
|
|
10
|
+
* .scout/state/<profile>.json — gitignored (auth storageState)
|
|
10
11
|
*/
|
|
11
12
|
export class Store {
|
|
12
13
|
root;
|
|
14
|
+
cwd;
|
|
13
15
|
constructor(cwd = process.cwd()) {
|
|
16
|
+
this.cwd = cwd;
|
|
14
17
|
this.root = path.join(cwd, SCOUT_DIR);
|
|
15
18
|
}
|
|
16
19
|
init() {
|
|
20
|
+
fs.mkdirSync(path.join(this.root, SPECS_DIR), { recursive: true });
|
|
17
21
|
fs.mkdirSync(path.join(this.root, "scripts"), { recursive: true });
|
|
18
22
|
fs.mkdirSync(path.join(this.root, "runs"), { recursive: true });
|
|
19
23
|
fs.mkdirSync(path.join(this.root, "state"), { recursive: true });
|
|
@@ -21,51 +25,19 @@ export class Store {
|
|
|
21
25
|
if (!fs.existsSync(gitignore)) {
|
|
22
26
|
fs.writeFileSync(gitignore, "runs/\nstate/\n");
|
|
23
27
|
}
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
const example = path.join(this.root, SPECS_DIR, "example.scout.md");
|
|
29
|
+
if (!fs.existsSync(example)) {
|
|
30
|
+
fs.writeFileSync(example, EXAMPLE_SPEC);
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
|
-
get scenariosFile() {
|
|
29
|
-
return path.join(this.root, "scenarios.json");
|
|
30
|
-
}
|
|
31
33
|
exists() {
|
|
32
|
-
return fs.existsSync(this.
|
|
34
|
+
return fs.existsSync(this.root);
|
|
33
35
|
}
|
|
34
36
|
listScenarios() {
|
|
35
|
-
|
|
36
|
-
return [];
|
|
37
|
-
return JSON.parse(fs.readFileSync(this.scenariosFile, "utf8"));
|
|
38
|
-
}
|
|
39
|
-
saveScenarios(scenarios) {
|
|
40
|
-
fs.writeFileSync(this.scenariosFile, JSON.stringify(scenarios, null, 2) + "\n");
|
|
41
|
-
}
|
|
42
|
-
addScenario(input) {
|
|
43
|
-
const scenarios = this.listScenarios();
|
|
44
|
-
const id = scenarios.length ? Math.max(...scenarios.map((s) => s.id)) + 1 : 1;
|
|
45
|
-
const scenario = {
|
|
46
|
-
id,
|
|
47
|
-
slug: slugify(input.name),
|
|
48
|
-
name: input.name,
|
|
49
|
-
scenario: input.scenario,
|
|
50
|
-
profile: input.profile,
|
|
51
|
-
notes: input.notes,
|
|
52
|
-
status: "pending",
|
|
53
|
-
createdAt: new Date().toISOString(),
|
|
54
|
-
};
|
|
55
|
-
scenarios.push(scenario);
|
|
56
|
-
this.saveScenarios(scenarios);
|
|
57
|
-
return scenario;
|
|
37
|
+
return loadScenarios(this.cwd);
|
|
58
38
|
}
|
|
59
|
-
getScenario(
|
|
60
|
-
return this.listScenarios().find((s) => s.
|
|
61
|
-
}
|
|
62
|
-
updateScenario(id, patch) {
|
|
63
|
-
const scenarios = this.listScenarios();
|
|
64
|
-
const idx = scenarios.findIndex((s) => s.id === id);
|
|
65
|
-
if (idx === -1)
|
|
66
|
-
throw new Error(`Scenario ${id} not found`);
|
|
67
|
-
scenarios[idx] = { ...scenarios[idx], ...patch };
|
|
68
|
-
this.saveScenarios(scenarios);
|
|
39
|
+
getScenario(slug) {
|
|
40
|
+
return this.listScenarios().find((s) => s.slug === slug);
|
|
69
41
|
}
|
|
70
42
|
// ---- cached deterministic scripts ----
|
|
71
43
|
scriptPath(slug) {
|
|
@@ -78,12 +50,14 @@ export class Store {
|
|
|
78
50
|
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
79
51
|
}
|
|
80
52
|
saveSteps(slug, steps) {
|
|
81
|
-
|
|
53
|
+
const file = this.scriptPath(slug);
|
|
54
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
55
|
+
fs.writeFileSync(file, JSON.stringify(steps, null, 2) + "\n");
|
|
82
56
|
}
|
|
83
57
|
// ---- runs ----
|
|
84
58
|
newRunDir(slug) {
|
|
85
59
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
86
|
-
const dir = path.join(this.root, "runs", `${stamp}-${slug}`);
|
|
60
|
+
const dir = path.join(this.root, "runs", `${stamp}-${slugToToken(slug)}`);
|
|
87
61
|
fs.mkdirSync(dir, { recursive: true });
|
|
88
62
|
return dir;
|
|
89
63
|
}
|
|
@@ -107,13 +81,35 @@ export class Store {
|
|
|
107
81
|
return map;
|
|
108
82
|
}
|
|
109
83
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
84
|
+
// The example sits inside a fenced block so it loads as ZERO scenarios — it
|
|
85
|
+
// documents the format without polluting the suite (or the `--check` gate).
|
|
86
|
+
const EXAMPLE_SPEC = `---
|
|
87
|
+
feature: Example
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
# How to write a scout spec
|
|
91
|
+
|
|
92
|
+
One file per feature/component. File-level frontmatter sets defaults
|
|
93
|
+
(\`feature\`, \`profile\`, \`tags\`). Each \`##\` heading is one scenario; optional
|
|
94
|
+
\`profile\`/\`notes\`/\`tags\` override lines may follow a heading before the prose.
|
|
95
|
+
Write the flow + expected behavior in plain language — no selectors, no code.
|
|
96
|
+
|
|
97
|
+
Copy the block below into a new \`*.scout.md\` file (outside the fence) to start:
|
|
98
|
+
|
|
99
|
+
\`\`\`markdown
|
|
100
|
+
---
|
|
101
|
+
feature: Paywall
|
|
102
|
+
profile: anon
|
|
103
|
+
tags: [monetization]
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Free user hits paywall on ep 3
|
|
107
|
+
Open ep 3 of series X without login; paywall appears with a signup CTA.
|
|
108
|
+
|
|
109
|
+
## Subscriber bypasses paywall
|
|
110
|
+
profile: qa
|
|
111
|
+
|
|
112
|
+
Logged-in subscriber opens ep 3; plays with no paywall.
|
|
113
|
+
\`\`\`
|
|
114
|
+
`;
|
|
119
115
|
//# sourceMappingURL=store.js.map
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -46,21 +46,30 @@ export type Step = {
|
|
|
46
46
|
};
|
|
47
47
|
export type Verdict = "verified" | "failed" | "partial" | "blocked";
|
|
48
48
|
export type ScenarioStatus = Verdict | "pending";
|
|
49
|
+
/**
|
|
50
|
+
* A single verification scenario, parsed from a `.scout/specs/**\/*.scout.md`
|
|
51
|
+
* file. The markdown is the source of truth and a *pure input* — it is never
|
|
52
|
+
* mutated by a run. Status and last-run derive from `.scout/runs/` instead.
|
|
53
|
+
*/
|
|
49
54
|
export interface Scenario {
|
|
50
|
-
|
|
55
|
+
/** Logical identity, unique across the suite: `<file-slug>/<scenario-slug>` */
|
|
51
56
|
slug: string;
|
|
57
|
+
/** Heading text of the scenario section */
|
|
52
58
|
name: string;
|
|
53
59
|
/** Natural-language description of the flow + expected behavior */
|
|
54
60
|
scenario: string;
|
|
61
|
+
/** Feature/group this scenario belongs to (frontmatter `feature` or filename) */
|
|
62
|
+
feature: string;
|
|
55
63
|
/** Auth profile name from scout.config.json (omit = anonymous) */
|
|
56
64
|
profile?: string;
|
|
57
|
-
|
|
58
|
-
createdAt: string;
|
|
59
|
-
lastRun?: string;
|
|
65
|
+
/** Extra context handed to the AI agent */
|
|
60
66
|
notes?: string;
|
|
67
|
+
/** Free-form tags (file-level + per-scenario, merged) */
|
|
68
|
+
tags?: string[];
|
|
69
|
+
/** Source spec file, relative to the project root */
|
|
70
|
+
file: string;
|
|
61
71
|
}
|
|
62
72
|
export interface RunResult {
|
|
63
|
-
scenarioId: number;
|
|
64
73
|
slug: string;
|
|
65
74
|
/** replay = cached deterministic steps; ai = agent-driven run */
|
|
66
75
|
mode: "replay" | "ai";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pcamarajr/scout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Self-healing browser QA: natural-language scenarios verified by an AI agent, replayed deterministically in CI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@anthropic-ai/claude-agent-sdk": "^0.3.0",
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
51
51
|
"commander": "^13.1.0",
|
|
52
|
+
"gray-matter": "^4.0.3",
|
|
52
53
|
"playwright": "^1.52.0",
|
|
53
54
|
"zod": "^4.0.0"
|
|
54
55
|
},
|