e2e-ai 1.4.2 → 1.4.3
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 +39 -10
- package/dist/mcp.js +359 -9
- package/package.json +1 -1
- package/templates/workflow.md +25 -0
package/README.md
CHANGED
|
@@ -598,6 +598,16 @@ If e2e-ai is installed globally or as a project dependency, you can use the bina
|
|
|
598
598
|
|
|
599
599
|
### Available Tools
|
|
600
600
|
|
|
601
|
+
#### Orchestration (workflow automation)
|
|
602
|
+
|
|
603
|
+
| Tool | Description | Input |
|
|
604
|
+
|------|-------------|-------|
|
|
605
|
+
| `e2e_ai_plan_workflow` | Plan an automation workflow — returns an ordered todo list of steps | `goal`, `key?`, `from?`, `skip?`, `voice?`, `trace?`, `scanDir?` |
|
|
606
|
+
| `e2e_ai_execute_step` | Execute a single pipeline step | `step`, `key?`, `voice?`, `trace?`, `scanDir?`, `output?`, `extraArgs?` |
|
|
607
|
+
| `e2e_ai_get_workflow_guide` | Get the full workflow guide explaining how the pipeline works | (none) |
|
|
608
|
+
|
|
609
|
+
#### Project setup
|
|
610
|
+
|
|
601
611
|
| Tool | Description | Input |
|
|
602
612
|
|------|-------------|-------|
|
|
603
613
|
| `e2e_ai_scan_codebase` | Scan project for test files, configs, fixtures, path aliases, and sample test content | `projectRoot?` (defaults to cwd) |
|
|
@@ -605,16 +615,35 @@ If e2e-ai is installed globally or as a project dependency, you can use the bina
|
|
|
605
615
|
| `e2e_ai_read_agent` | Load an agent prompt by name — returns system prompt + config | `agentName` (e.g. `scenario-agent`) |
|
|
606
616
|
| `e2e_ai_get_example` | Get the example context markdown template | (none) |
|
|
607
617
|
|
|
608
|
-
###
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
1. **
|
|
613
|
-
2. **
|
|
614
|
-
3. **
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
+
### How AI Orchestration Works
|
|
619
|
+
|
|
620
|
+
The MCP server includes built-in orchestration instructions that teach AI assistants (Claude Code, Cursor, etc.) how to run e2e-ai workflows autonomously. The protocol is:
|
|
621
|
+
|
|
622
|
+
1. **Plan** — The AI calls `e2e_ai_plan_workflow` with your goal. It returns an ordered step list.
|
|
623
|
+
2. **Approve** — The AI presents the plan to you for review. You can adjust steps before proceeding.
|
|
624
|
+
3. **Execute** — The AI runs each step one at a time via `e2e_ai_execute_step`, reporting results between steps. If a step fails, it stops and asks you how to proceed.
|
|
625
|
+
|
|
626
|
+
Each step is executed as a separate job (ideally a subagent) to keep context clean. The AI never runs multiple pipeline steps at once.
|
|
627
|
+
|
|
628
|
+
**Example interaction:**
|
|
629
|
+
|
|
630
|
+
> **You:** "Run the full test pipeline for PROJ-101"
|
|
631
|
+
>
|
|
632
|
+
> **AI:** *Calls `e2e_ai_plan_workflow`*, then presents:
|
|
633
|
+
> 1. `record` — Launch browser codegen + voice recording
|
|
634
|
+
> 2. `transcribe` — Transcribe voice via Whisper
|
|
635
|
+
> 3. `scenario` — Generate YAML test scenario
|
|
636
|
+
> 4. `generate` — Generate Playwright test
|
|
637
|
+
> 5. `refine` — Refactor test with AI
|
|
638
|
+
> 6. `test` — Run Playwright test
|
|
639
|
+
> 7. `heal` — Self-heal if failing (can skip if test passes)
|
|
640
|
+
> 8. `qa` — Generate QA documentation
|
|
641
|
+
>
|
|
642
|
+
> "Does this look right? Ready to start?"
|
|
643
|
+
>
|
|
644
|
+
> **You:** "Skip voice, go ahead"
|
|
645
|
+
>
|
|
646
|
+
> **AI:** *Removes transcribe, executes each step sequentially*
|
|
618
647
|
|
|
619
648
|
## Library API
|
|
620
649
|
|
package/dist/mcp.js
CHANGED
|
@@ -14856,8 +14856,9 @@ class StdioServerTransport {
|
|
|
14856
14856
|
}
|
|
14857
14857
|
|
|
14858
14858
|
// src/mcp.ts
|
|
14859
|
-
import { readFileSync as readFileSync2 } from "node:fs";
|
|
14859
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "node:fs";
|
|
14860
14860
|
import { join as join2 } from "node:path";
|
|
14861
|
+
import { execSync } from "node:child_process";
|
|
14861
14862
|
|
|
14862
14863
|
// src/utils/scan.ts
|
|
14863
14864
|
import { readdirSync, existsSync, readFileSync } from "node:fs";
|
|
@@ -14957,13 +14958,281 @@ function validateContext(content) {
|
|
|
14957
14958
|
}
|
|
14958
14959
|
|
|
14959
14960
|
// src/mcp.ts
|
|
14960
|
-
var
|
|
14961
|
-
|
|
14962
|
-
|
|
14963
|
-
|
|
14961
|
+
var SERVER_INSTRUCTIONS = `
|
|
14962
|
+
# e2e-ai — Orchestration Guide
|
|
14963
|
+
|
|
14964
|
+
You have access to e2e-ai, an AI-powered E2E test automation tool. Follow this protocol when the user asks you to perform any e2e-ai automation.
|
|
14965
|
+
|
|
14966
|
+
## Core Principle: Plan → Approve → Execute Step-by-Step
|
|
14967
|
+
|
|
14968
|
+
NEVER run multiple pipeline steps at once. Each step is a separate job with its own context.
|
|
14969
|
+
|
|
14970
|
+
## Protocol
|
|
14971
|
+
|
|
14972
|
+
1. **Plan first.** Call \`e2e_ai_plan_workflow\` with the user's goal. This returns a structured todo list of steps.
|
|
14973
|
+
2. **Present the plan.** Show the user the ordered step list with descriptions. Ask for confirmation or adjustments before proceeding.
|
|
14974
|
+
3. **Execute one step at a time.** For each step in the approved plan:
|
|
14975
|
+
a. Tell the user which step you're about to run and why.
|
|
14976
|
+
b. Call \`e2e_ai_execute_step\` with the step name and parameters.
|
|
14977
|
+
c. Report the result to the user (success, key output, any warnings).
|
|
14978
|
+
d. If the step fails, stop and discuss with the user before continuing.
|
|
14979
|
+
e. Move to the next step only after the current one succeeds.
|
|
14980
|
+
4. **Use subagents when available.** If your AI platform supports subagents (e.g., Claude Code Agent tool), dispatch each step as a dedicated subagent to preserve context. Each subagent should:
|
|
14981
|
+
- Receive only the context it needs (step name, key, relevant file paths)
|
|
14982
|
+
- Call \`e2e_ai_execute_step\` to do its work
|
|
14983
|
+
- Return the result to the orchestrator
|
|
14984
|
+
|
|
14985
|
+
## Step Dependencies
|
|
14986
|
+
|
|
14987
|
+
Steps produce artifacts that feed into later steps. The pipeline handles this automatically — each step picks up where the previous one left off. Do not skip steps unless the plan says a step can be skipped.
|
|
14988
|
+
|
|
14989
|
+
## Interactive Steps
|
|
14990
|
+
|
|
14991
|
+
The \`record\` step opens a browser and requires user interaction. When the plan includes \`record\`:
|
|
14992
|
+
- Tell the user they need to interact with the browser window
|
|
14993
|
+
- The step will block until they close the codegen window
|
|
14994
|
+
- After recording completes, proceed with the next step
|
|
14995
|
+
|
|
14996
|
+
## When Things Fail
|
|
14997
|
+
|
|
14998
|
+
- If \`test\` fails and \`heal\` is in the plan, that's expected — heal will attempt to fix it
|
|
14999
|
+
- If \`heal\` exhausts all retries, stop and show the user the last error output
|
|
15000
|
+
- For any other failure, stop and ask the user how to proceed
|
|
15001
|
+
|
|
15002
|
+
## Available Workflows
|
|
15003
|
+
|
|
15004
|
+
- **Full test pipeline**: record → transcribe → scenario → generate → refine → test → heal → qa
|
|
15005
|
+
- **From existing recording**: transcribe → scenario → generate → refine → test → heal → qa
|
|
15006
|
+
- **AI-only (no recording)**: scenario → generate → refine → test → heal → qa
|
|
15007
|
+
- **Generate from scenario**: generate → refine → test → heal → qa
|
|
15008
|
+
- **Test + heal loop**: test → heal
|
|
15009
|
+
- **Scanner pipeline**: scan → analyze → push
|
|
15010
|
+
- **Single step**: any individual command
|
|
15011
|
+
|
|
15012
|
+
Always use \`e2e_ai_plan_workflow\` to determine the right steps — don't guess.
|
|
15013
|
+
`.trim();
|
|
15014
|
+
var TEST_PIPELINE_STEPS = [
|
|
15015
|
+
{
|
|
15016
|
+
name: "record",
|
|
15017
|
+
description: "Launch Playwright codegen in the browser. Optionally records voice narration for richer test scenarios.",
|
|
15018
|
+
produces: "codegen .ts file + optional .wav voice recording",
|
|
15019
|
+
requires: "none",
|
|
15020
|
+
interactive: true
|
|
15021
|
+
},
|
|
15022
|
+
{
|
|
15023
|
+
name: "transcribe",
|
|
15024
|
+
description: "Transcribe the voice recording via OpenAI Whisper. Merges timestamped voice comments into the codegen file.",
|
|
15025
|
+
produces: "transcript JSON + annotated codegen file",
|
|
15026
|
+
requires: "voice recording from record step",
|
|
15027
|
+
interactive: false,
|
|
15028
|
+
canSkip: "No voice recording exists or voice is disabled"
|
|
15029
|
+
},
|
|
15030
|
+
{
|
|
15031
|
+
name: "scenario",
|
|
15032
|
+
description: "AI analyzes the codegen + transcript and generates a structured YAML test scenario with semantic steps and expected results.",
|
|
15033
|
+
produces: "YAML test scenario file",
|
|
15034
|
+
requires: "codegen file (+ optional transcript)",
|
|
15035
|
+
interactive: false
|
|
15036
|
+
},
|
|
15037
|
+
{
|
|
15038
|
+
name: "generate",
|
|
15039
|
+
description: "AI converts the YAML scenario into a complete Playwright .test.ts file using project conventions from context.md.",
|
|
15040
|
+
produces: "Playwright .test.ts file",
|
|
15041
|
+
requires: "YAML scenario file",
|
|
15042
|
+
interactive: false
|
|
15043
|
+
},
|
|
15044
|
+
{
|
|
15045
|
+
name: "refine",
|
|
15046
|
+
description: "AI refactors the test: replaces raw selectors with semantic alternatives, adds proper timeouts, uses project helpers.",
|
|
15047
|
+
produces: "improved .test.ts file (in-place)",
|
|
15048
|
+
requires: "Playwright .test.ts file",
|
|
15049
|
+
interactive: false
|
|
15050
|
+
},
|
|
15051
|
+
{
|
|
15052
|
+
name: "test",
|
|
15053
|
+
description: "Run the Playwright test with trace/video/screenshot capture. Reports pass/fail status.",
|
|
15054
|
+
produces: "test results + trace files",
|
|
15055
|
+
requires: "Playwright .test.ts file",
|
|
15056
|
+
interactive: false
|
|
15057
|
+
},
|
|
15058
|
+
{
|
|
15059
|
+
name: "heal",
|
|
15060
|
+
description: "If the test failed, AI diagnoses the failure and patches the test. Retries up to 3 times with different strategies.",
|
|
15061
|
+
produces: "patched .test.ts file (if test was failing)",
|
|
15062
|
+
requires: "failing test + error output",
|
|
15063
|
+
interactive: false,
|
|
15064
|
+
canSkip: "Test already passes"
|
|
15065
|
+
},
|
|
15066
|
+
{
|
|
15067
|
+
name: "qa",
|
|
15068
|
+
description: "Generate formal QA documentation: markdown test case with preconditions, steps table, and optional Zephyr XML export.",
|
|
15069
|
+
produces: "QA markdown + optional Zephyr XML",
|
|
15070
|
+
requires: "Playwright .test.ts file + scenario",
|
|
15071
|
+
interactive: false
|
|
15072
|
+
}
|
|
15073
|
+
];
|
|
15074
|
+
var SCANNER_PIPELINE_STEPS = [
|
|
15075
|
+
{
|
|
15076
|
+
name: "scan",
|
|
15077
|
+
description: "Scan the codebase AST: extract routes, components, hooks, imports, and dependency graph.",
|
|
15078
|
+
produces: "ast-scan.json with full codebase structure",
|
|
15079
|
+
requires: "none",
|
|
15080
|
+
interactive: false
|
|
15081
|
+
},
|
|
15082
|
+
{
|
|
15083
|
+
name: "analyze",
|
|
15084
|
+
description: "AI analyzes the AST scan to identify features, workflows, components, and generate test scenarios.",
|
|
15085
|
+
produces: "qa-map.json with features, workflows, scenarios",
|
|
15086
|
+
requires: "ast-scan.json from scan step",
|
|
15087
|
+
interactive: false
|
|
15088
|
+
},
|
|
15089
|
+
{
|
|
15090
|
+
name: "push",
|
|
15091
|
+
description: "Push the QA map to a remote API endpoint for integration with external tools.",
|
|
15092
|
+
produces: "push confirmation with version info",
|
|
15093
|
+
requires: "qa-map.json from analyze step + API config",
|
|
15094
|
+
interactive: false
|
|
15095
|
+
}
|
|
15096
|
+
];
|
|
15097
|
+
var ALL_STEPS = [...TEST_PIPELINE_STEPS, ...SCANNER_PIPELINE_STEPS];
|
|
15098
|
+
function planWorkflow(goal, options) {
|
|
15099
|
+
const goalLower = goal.toLowerCase();
|
|
15100
|
+
const notes = [];
|
|
15101
|
+
const isScannerGoal = /\b(scan|analyze|qa.?map|feature.?analy|push.?qa|codebase.?scan)\b/.test(goalLower);
|
|
15102
|
+
const isSingleStep = ALL_STEPS.some((s) => goalLower === s.name || goalLower === `run ${s.name}`);
|
|
15103
|
+
let stepDefs;
|
|
15104
|
+
if (isScannerGoal && !isSingleStep) {
|
|
15105
|
+
stepDefs = [...SCANNER_PIPELINE_STEPS];
|
|
15106
|
+
if (!/\bpush\b/.test(goalLower)) {
|
|
15107
|
+
stepDefs = stepDefs.filter((s) => s.name !== "push");
|
|
15108
|
+
notes.push("Push step excluded — add it if you want to upload the QA map to a remote API.");
|
|
15109
|
+
}
|
|
15110
|
+
} else if (isSingleStep) {
|
|
15111
|
+
const stepName = ALL_STEPS.find((s) => goalLower.includes(s.name)).name;
|
|
15112
|
+
stepDefs = ALL_STEPS.filter((s) => s.name === stepName);
|
|
15113
|
+
} else {
|
|
15114
|
+
stepDefs = [...TEST_PIPELINE_STEPS];
|
|
15115
|
+
if (options.from) {
|
|
15116
|
+
const fromIdx = stepDefs.findIndex((s) => s.name === options.from);
|
|
15117
|
+
if (fromIdx > 0) {
|
|
15118
|
+
const skipped = stepDefs.slice(0, fromIdx).map((s) => s.name);
|
|
15119
|
+
stepDefs = stepDefs.slice(fromIdx);
|
|
15120
|
+
notes.push(`Starting from "${options.from}" — skipping: ${skipped.join(", ")}`);
|
|
15121
|
+
}
|
|
15122
|
+
} else {
|
|
15123
|
+
if (/\b(from recording|existing recording|already recorded)\b/.test(goalLower)) {
|
|
15124
|
+
stepDefs = stepDefs.filter((s) => s.name !== "record");
|
|
15125
|
+
notes.push("Skipping record — using existing recording files.");
|
|
15126
|
+
}
|
|
15127
|
+
if (/\b(from scenario|existing scenario|manual scenario|yaml)\b/.test(goalLower)) {
|
|
15128
|
+
stepDefs = stepDefs.filter((s) => !["record", "transcribe", "scenario"].includes(s.name));
|
|
15129
|
+
notes.push("Starting from generate — using existing scenario YAML.");
|
|
15130
|
+
}
|
|
15131
|
+
if (/\b(generate.?only|just.?generate|no.?record)\b/.test(goalLower)) {
|
|
15132
|
+
stepDefs = stepDefs.filter((s) => !["record", "transcribe"].includes(s.name));
|
|
15133
|
+
}
|
|
15134
|
+
if (/\b(test.?and.?heal|test.?heal|heal.?loop|fix.?test|self.?heal)\b/.test(goalLower)) {
|
|
15135
|
+
stepDefs = stepDefs.filter((s) => ["test", "heal"].includes(s.name));
|
|
15136
|
+
}
|
|
15137
|
+
if (/\b(refine|refactor)\b/.test(goalLower) && !/\brun\b/.test(goalLower)) {
|
|
15138
|
+
stepDefs = stepDefs.filter((s) => s.name === "refine");
|
|
15139
|
+
}
|
|
15140
|
+
if (/\bqa\b/.test(goalLower) && /\b(doc|only|generate)\b/.test(goalLower)) {
|
|
15141
|
+
stepDefs = stepDefs.filter((s) => s.name === "qa");
|
|
15142
|
+
}
|
|
15143
|
+
}
|
|
15144
|
+
}
|
|
15145
|
+
if (options.skip?.length) {
|
|
15146
|
+
stepDefs = stepDefs.filter((s) => !options.skip.includes(s.name));
|
|
15147
|
+
notes.push(`Skipping: ${options.skip.join(", ")}`);
|
|
15148
|
+
}
|
|
15149
|
+
if (options.voice === false) {
|
|
15150
|
+
stepDefs = stepDefs.filter((s) => s.name !== "transcribe");
|
|
15151
|
+
notes.push("Voice disabled — transcribe step removed.");
|
|
15152
|
+
}
|
|
15153
|
+
const cliBase = "e2e-ai";
|
|
15154
|
+
const steps = stepDefs.map((s, i) => {
|
|
15155
|
+
const args = [s.name];
|
|
15156
|
+
if (options.key && !["scan", "analyze", "push"].includes(s.name)) {
|
|
15157
|
+
args.push("--key", options.key);
|
|
15158
|
+
}
|
|
15159
|
+
if (s.name === "record") {
|
|
15160
|
+
if (options.voice === false)
|
|
15161
|
+
args.push("--no-voice");
|
|
15162
|
+
if (options.trace === false)
|
|
15163
|
+
args.push("--no-trace");
|
|
15164
|
+
}
|
|
15165
|
+
if (s.name === "scan" && options.scanDir) {
|
|
15166
|
+
args.push("--scan-dir", options.scanDir);
|
|
15167
|
+
}
|
|
15168
|
+
return {
|
|
15169
|
+
order: i + 1,
|
|
15170
|
+
name: s.name,
|
|
15171
|
+
description: s.description,
|
|
15172
|
+
command: `${cliBase} ${args.join(" ")}`,
|
|
15173
|
+
produces: s.produces,
|
|
15174
|
+
interactive: s.interactive,
|
|
15175
|
+
canSkip: s.canSkip
|
|
15176
|
+
};
|
|
15177
|
+
});
|
|
15178
|
+
const pipeline2 = isScannerGoal ? "scanner" : isSingleStep ? "single" : "test";
|
|
15179
|
+
if (!options.key && pipeline2 === "test" && steps.length > 1) {
|
|
15180
|
+
notes.push("No --key provided. Use --key <ISSUE-KEY> to organize files by issue.");
|
|
15181
|
+
}
|
|
15182
|
+
return { goal, pipeline: pipeline2, steps, notes };
|
|
15183
|
+
}
|
|
15184
|
+
function executeStep(stepName, options) {
|
|
15185
|
+
const args = [stepName];
|
|
15186
|
+
if (options.key && !["scan", "analyze", "push"].includes(stepName)) {
|
|
15187
|
+
args.push("--key", options.key);
|
|
15188
|
+
}
|
|
15189
|
+
if (stepName === "record") {
|
|
15190
|
+
if (options.voice === false)
|
|
15191
|
+
args.push("--no-voice");
|
|
15192
|
+
if (options.trace === false)
|
|
15193
|
+
args.push("--no-trace");
|
|
15194
|
+
}
|
|
15195
|
+
if (stepName === "scan" && options.scanDir) {
|
|
15196
|
+
args.push("--scan-dir", options.scanDir);
|
|
15197
|
+
}
|
|
15198
|
+
if (options.output) {
|
|
15199
|
+
args.push("--output", options.output);
|
|
15200
|
+
}
|
|
15201
|
+
if (options.extraArgs?.length) {
|
|
15202
|
+
args.push(...options.extraArgs);
|
|
15203
|
+
}
|
|
15204
|
+
const pkgRoot = getPackageRoot();
|
|
15205
|
+
const cliBin = join2(pkgRoot, "dist", "cli.js");
|
|
15206
|
+
const command = `node ${cliBin} ${args.join(" ")}`;
|
|
15207
|
+
try {
|
|
15208
|
+
const stdout = execSync(command, {
|
|
15209
|
+
cwd: process.cwd(),
|
|
15210
|
+
encoding: "utf-8",
|
|
15211
|
+
timeout: 300000,
|
|
15212
|
+
env: { ...process.env },
|
|
15213
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15214
|
+
});
|
|
15215
|
+
return { success: true, output: stdout, command };
|
|
15216
|
+
} catch (err) {
|
|
15217
|
+
const stderr = err.stderr?.toString() ?? "";
|
|
15218
|
+
const stdout = err.stdout?.toString() ?? "";
|
|
15219
|
+
return {
|
|
15220
|
+
success: false,
|
|
15221
|
+
output: `EXIT CODE: ${err.status ?? "unknown"}
|
|
15222
|
+
|
|
15223
|
+
STDOUT:
|
|
15224
|
+
${stdout}
|
|
15225
|
+
|
|
15226
|
+
STDERR:
|
|
15227
|
+
${stderr}`,
|
|
15228
|
+
command
|
|
15229
|
+
};
|
|
15230
|
+
}
|
|
15231
|
+
}
|
|
15232
|
+
var server = new McpServer({ name: "e2e-ai", version: "1.2.0" }, { instructions: SERVER_INSTRUCTIONS });
|
|
14964
15233
|
server.registerTool("e2e_ai_scan_codebase", {
|
|
14965
15234
|
title: "Scan Codebase",
|
|
14966
|
-
description: "Scan a project directory for test files, configs, fixtures, path aliases, and sample test content",
|
|
15235
|
+
description: "Scan a project directory for test files, configs, fixtures, path aliases, and sample test content. Use this during project setup or to understand test infrastructure.",
|
|
14967
15236
|
inputSchema: exports_external.object({
|
|
14968
15237
|
projectRoot: exports_external.string().optional().describe("Project root directory (defaults to cwd)")
|
|
14969
15238
|
})
|
|
@@ -14976,7 +15245,7 @@ server.registerTool("e2e_ai_scan_codebase", {
|
|
|
14976
15245
|
});
|
|
14977
15246
|
server.registerTool("e2e_ai_validate_context", {
|
|
14978
15247
|
title: "Validate Context",
|
|
14979
|
-
description: "Validate that a context markdown file contains all required sections",
|
|
15248
|
+
description: "Validate that a context markdown file contains all required sections (Application, Test Infrastructure, Feature Methods, Import Conventions, Selector Conventions, Test Structure Template, Utility Patterns).",
|
|
14980
15249
|
inputSchema: exports_external.object({
|
|
14981
15250
|
content: exports_external.string().describe("The markdown content of the context file to validate")
|
|
14982
15251
|
})
|
|
@@ -14988,7 +15257,7 @@ server.registerTool("e2e_ai_validate_context", {
|
|
|
14988
15257
|
});
|
|
14989
15258
|
server.registerTool("e2e_ai_read_agent", {
|
|
14990
15259
|
title: "Read Agent",
|
|
14991
|
-
description: "Read an agent prompt definition by name. Returns the agent
|
|
15260
|
+
description: "Read an agent prompt definition by name. Returns the agent system prompt and config. Agents: transcript-agent, scenario-agent, playwright-generator-agent, refactor-agent, self-healing-agent, qa-testcase-agent, feature-analyzer-agent, scenario-planner-agent, init-agent.",
|
|
14992
15261
|
inputSchema: exports_external.object({
|
|
14993
15262
|
agentName: exports_external.string().describe("Agent name (e.g. scenario-agent, playwright-generator-agent)")
|
|
14994
15263
|
})
|
|
@@ -15014,7 +15283,7 @@ server.registerTool("e2e_ai_read_agent", {
|
|
|
15014
15283
|
});
|
|
15015
15284
|
server.registerTool("e2e_ai_get_example", {
|
|
15016
15285
|
title: "Get Example Context",
|
|
15017
|
-
description: "Returns the full example context markdown file that shows the expected format for .e2e-ai/context.md",
|
|
15286
|
+
description: "Returns the full example context markdown file that shows the expected format for .e2e-ai/context.md.",
|
|
15018
15287
|
inputSchema: exports_external.object({})
|
|
15019
15288
|
}, async () => {
|
|
15020
15289
|
try {
|
|
@@ -15030,6 +15299,87 @@ server.registerTool("e2e_ai_get_example", {
|
|
|
15030
15299
|
};
|
|
15031
15300
|
}
|
|
15032
15301
|
});
|
|
15302
|
+
server.registerTool("e2e_ai_plan_workflow", {
|
|
15303
|
+
title: "Plan Workflow",
|
|
15304
|
+
description: "Plan an e2e-ai automation workflow. Call this FIRST when the user asks to run any automation. " + "Returns an ordered list of steps (todo list) that should be executed one at a time. " + "Present the plan to the user for approval before executing any step.",
|
|
15305
|
+
inputSchema: exports_external.object({
|
|
15306
|
+
goal: exports_external.string().describe('What the user wants to achieve. Examples: "run full pipeline for PROJ-101", ' + '"generate test from existing recording", "scan codebase and analyze features", ' + '"heal failing test PROJ-101", "refactor test PROJ-101"'),
|
|
15307
|
+
key: exports_external.string().optional().describe("Issue key (e.g. PROJ-101, LIN-42)"),
|
|
15308
|
+
from: exports_external.string().optional().describe("Start from a specific step (skip all prior steps)"),
|
|
15309
|
+
skip: exports_external.array(exports_external.string()).optional().describe('Steps to skip (e.g. ["transcribe", "heal"])'),
|
|
15310
|
+
voice: exports_external.boolean().optional().describe("Enable voice recording (default: true)"),
|
|
15311
|
+
trace: exports_external.boolean().optional().describe("Enable trace capture (default: true)"),
|
|
15312
|
+
scanDir: exports_external.string().optional().describe("Directory to scan (for scanner pipeline)")
|
|
15313
|
+
})
|
|
15314
|
+
}, async ({ goal, key, from, skip, voice, trace, scanDir }) => {
|
|
15315
|
+
const plan = planWorkflow(goal, { key, from, skip, voice, trace, scanDir });
|
|
15316
|
+
return {
|
|
15317
|
+
content: [{
|
|
15318
|
+
type: "text",
|
|
15319
|
+
text: JSON.stringify(plan, null, 2)
|
|
15320
|
+
}]
|
|
15321
|
+
};
|
|
15322
|
+
});
|
|
15323
|
+
server.registerTool("e2e_ai_execute_step", {
|
|
15324
|
+
title: "Execute Pipeline Step",
|
|
15325
|
+
description: "Execute a single e2e-ai pipeline step. Call this ONE STEP AT A TIME from an approved plan. " + "Each step produces artifacts consumed by later steps. " + "If your AI platform supports subagents, run each step in a dedicated subagent to preserve context. " + 'The "record" step is interactive and will open a browser window — the user must interact with it.',
|
|
15326
|
+
inputSchema: exports_external.object({
|
|
15327
|
+
step: exports_external.string().describe("Step name: record, transcribe, scenario, generate, refine, test, heal, qa, scan, analyze, push"),
|
|
15328
|
+
key: exports_external.string().optional().describe("Issue key (e.g. PROJ-101)"),
|
|
15329
|
+
voice: exports_external.boolean().optional().describe("Enable voice recording (record step only)"),
|
|
15330
|
+
trace: exports_external.boolean().optional().describe("Enable trace capture (record step only)"),
|
|
15331
|
+
scanDir: exports_external.string().optional().describe("Directory to scan (scan step only)"),
|
|
15332
|
+
output: exports_external.string().optional().describe("Custom output path (scan/analyze steps)"),
|
|
15333
|
+
extraArgs: exports_external.array(exports_external.string()).optional().describe("Additional CLI arguments")
|
|
15334
|
+
})
|
|
15335
|
+
}, async ({ step, key, voice, trace, scanDir, output, extraArgs }) => {
|
|
15336
|
+
const validSteps = ALL_STEPS.map((s) => s.name);
|
|
15337
|
+
if (!validSteps.includes(step)) {
|
|
15338
|
+
return {
|
|
15339
|
+
content: [{
|
|
15340
|
+
type: "text",
|
|
15341
|
+
text: `Error: Unknown step "${step}". Valid steps: ${validSteps.join(", ")}`
|
|
15342
|
+
}],
|
|
15343
|
+
isError: true
|
|
15344
|
+
};
|
|
15345
|
+
}
|
|
15346
|
+
const result = executeStep(step, { key, voice, trace, scanDir, output, extraArgs });
|
|
15347
|
+
return {
|
|
15348
|
+
content: [{
|
|
15349
|
+
type: "text",
|
|
15350
|
+
text: JSON.stringify({
|
|
15351
|
+
step,
|
|
15352
|
+
success: result.success,
|
|
15353
|
+
command: result.command,
|
|
15354
|
+
output: result.output
|
|
15355
|
+
}, null, 2)
|
|
15356
|
+
}]
|
|
15357
|
+
};
|
|
15358
|
+
});
|
|
15359
|
+
server.registerTool("e2e_ai_get_workflow_guide", {
|
|
15360
|
+
title: "Get Workflow Guide",
|
|
15361
|
+
description: "Returns the e2e-ai workflow guide explaining how the pipeline works, step by step. Useful for understanding what each step does and how they connect.",
|
|
15362
|
+
inputSchema: exports_external.object({})
|
|
15363
|
+
}, async () => {
|
|
15364
|
+
try {
|
|
15365
|
+
const guidePath = join2(getPackageRoot(), "templates", "workflow.md");
|
|
15366
|
+
if (!existsSync2(guidePath)) {
|
|
15367
|
+
return {
|
|
15368
|
+
content: [{ type: "text", text: "Error: workflow.md not found in templates" }],
|
|
15369
|
+
isError: true
|
|
15370
|
+
};
|
|
15371
|
+
}
|
|
15372
|
+
const content = readFileSync2(guidePath, "utf-8");
|
|
15373
|
+
return {
|
|
15374
|
+
content: [{ type: "text", text: content }]
|
|
15375
|
+
};
|
|
15376
|
+
} catch (err) {
|
|
15377
|
+
return {
|
|
15378
|
+
content: [{ type: "text", text: `Error: ${err.message}` }],
|
|
15379
|
+
isError: true
|
|
15380
|
+
};
|
|
15381
|
+
}
|
|
15382
|
+
});
|
|
15033
15383
|
async function main() {
|
|
15034
15384
|
const transport = new StdioServerTransport;
|
|
15035
15385
|
await server.connect(transport);
|
package/package.json
CHANGED
package/templates/workflow.md
CHANGED
|
@@ -14,6 +14,10 @@ record → transcribe → scenario → generate → refine → test → heal →
|
|
|
14
14
|
|
|
15
15
|
**In short:** You record yourself testing in the browser (optionally narrating what you're doing), and e2e-ai turns that into a production-ready Playwright test with QA documentation.
|
|
16
16
|
|
|
17
|
+
**Two ways to run it:**
|
|
18
|
+
- **CLI**: Run commands directly (`e2e-ai run --key PROJ-101`)
|
|
19
|
+
- **AI assistant**: Ask your AI tool (Claude Code, Cursor, etc.) — the MCP server guides it through the pipeline step by step, asking for your approval before starting
|
|
20
|
+
|
|
17
21
|
---
|
|
18
22
|
|
|
19
23
|
## Setup
|
|
@@ -198,6 +202,27 @@ This is independent from the test pipeline — use it to get an overview of your
|
|
|
198
202
|
|
|
199
203
|
---
|
|
200
204
|
|
|
205
|
+
## AI-Assisted Workflow (MCP)
|
|
206
|
+
|
|
207
|
+
If you have the e2e-ai MCP server configured, you can ask your AI assistant to run the pipeline for you. The MCP server teaches the AI how to orchestrate the workflow:
|
|
208
|
+
|
|
209
|
+
1. **You say:** "Run the full test pipeline for PROJ-101" (or any variation)
|
|
210
|
+
2. **AI plans:** Calls `e2e_ai_plan_workflow` → gets an ordered step list
|
|
211
|
+
3. **AI shows plan:** Presents the steps and asks for your approval
|
|
212
|
+
4. **You adjust:** "Skip voice" / "Start from generate" / "Looks good, go"
|
|
213
|
+
5. **AI executes:** Runs each step one at a time via `e2e_ai_execute_step`, reporting results between steps
|
|
214
|
+
|
|
215
|
+
Each step runs as a separate subagent (when supported by the AI platform) to keep context clean and focused. If a step fails, the AI stops and asks you what to do.
|
|
216
|
+
|
|
217
|
+
**Example prompts you can give your AI assistant:**
|
|
218
|
+
- "Run the full pipeline for PROJ-101"
|
|
219
|
+
- "Generate a test from the existing recording for PROJ-101, skip voice"
|
|
220
|
+
- "Just run test and heal for PROJ-101"
|
|
221
|
+
- "Scan the codebase and analyze features"
|
|
222
|
+
- "Refactor the test for PROJ-101"
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
201
226
|
## File Structure
|
|
202
227
|
|
|
203
228
|
After running the pipeline for `PROJ-101`:
|