levante 0.1.0 → 0.1.2
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 +256 -0
- package/dist/cli.js +6 -6
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Levante
|
|
2
|
+
|
|
3
|
+
AI-powered end-to-end test pipeline for Playwright. Record, transcribe, generate, refine, heal, and document your tests — all driven by LLM agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g levante
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Levante requires Playwright as a peer dependency:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -D @playwright/test
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Environment Variables
|
|
18
|
+
|
|
19
|
+
| Variable | Required | Description |
|
|
20
|
+
|----------|----------|-------------|
|
|
21
|
+
| `OPENAI_API_KEY` | Yes (if using OpenAI) | OpenAI API key |
|
|
22
|
+
| `ANTHROPIC_API_KEY` | Yes (if using Anthropic) | Anthropic API key |
|
|
23
|
+
| `E2E_AI_API_URL` | No | Remote API URL for QA map push |
|
|
24
|
+
| `E2E_AI_API_KEY` | No | API key for push authentication |
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Initialize config and agents
|
|
30
|
+
levante init
|
|
31
|
+
|
|
32
|
+
# Run full pipeline for a test case
|
|
33
|
+
levante run --key PROJ-101
|
|
34
|
+
|
|
35
|
+
# Or run individual steps
|
|
36
|
+
levante record --key PROJ-101
|
|
37
|
+
levante transcribe --key PROJ-101
|
|
38
|
+
levante scenario --key PROJ-101
|
|
39
|
+
levante generate --key PROJ-101
|
|
40
|
+
levante test --key PROJ-101
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## CLI Usage
|
|
44
|
+
|
|
45
|
+
### Global Options
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
-k, --key <KEY> Issue key (e.g., PROJ-101)
|
|
49
|
+
--provider <provider> LLM provider: openai | anthropic
|
|
50
|
+
--model <model> LLM model override
|
|
51
|
+
-v, --verbose Verbose output
|
|
52
|
+
--no-voice Disable voice recording
|
|
53
|
+
--no-trace Disable trace replay
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Commands
|
|
57
|
+
|
|
58
|
+
#### `levante init`
|
|
59
|
+
|
|
60
|
+
Initialize levante in your project. Creates `.qai/levante/` with config, agents, and workflow guide.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
levante init
|
|
64
|
+
levante init --non-interactive
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### `levante record [session]`
|
|
68
|
+
|
|
69
|
+
Launch Playwright codegen with optional audio narration capture.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
levante record --key PROJ-101
|
|
73
|
+
levante record --key PROJ-101 --no-voice
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### `levante transcribe [session]`
|
|
77
|
+
|
|
78
|
+
Transcribe `.wav` voice recording via OpenAI Whisper.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
levante transcribe --key PROJ-101
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### `levante scenario [session]`
|
|
85
|
+
|
|
86
|
+
Generate a structured YAML scenario from codegen output and transcript.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
levante scenario --key PROJ-101
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### `levante generate [scenario]`
|
|
93
|
+
|
|
94
|
+
Generate a Playwright `.test.ts` file from a YAML scenario.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
levante generate --key PROJ-101
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### `levante refine [test]`
|
|
101
|
+
|
|
102
|
+
Refactor a generated test with AI — replaces raw selectors, adds best practices.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
levante refine --key PROJ-101
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### `levante test [test]`
|
|
109
|
+
|
|
110
|
+
Run the Playwright test with trace/video/screenshot capture.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
levante test --key PROJ-101
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### `levante heal [test]`
|
|
117
|
+
|
|
118
|
+
Self-heal a failing test (up to 3 retries). Diagnoses failures and patches automatically.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
levante heal --key PROJ-101
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### `levante qa [test]`
|
|
125
|
+
|
|
126
|
+
Generate QA documentation (markdown and/or Zephyr XML).
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
levante qa --key PROJ-101
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### `levante run [session]`
|
|
133
|
+
|
|
134
|
+
Run the full pipeline: record → transcribe → scenario → generate → refine → test → heal → qa.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
levante run --key PROJ-101
|
|
138
|
+
levante run --key PROJ-101 --from generate
|
|
139
|
+
levante run --key PROJ-101 --skip transcribe,heal
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Option | Description |
|
|
143
|
+
|--------|-------------|
|
|
144
|
+
| `--from <step>` | Start from a specific step |
|
|
145
|
+
| `--skip <steps>` | Skip comma-separated steps |
|
|
146
|
+
|
|
147
|
+
## MCP Server
|
|
148
|
+
|
|
149
|
+
Levante includes an MCP server for use with AI coding assistants.
|
|
150
|
+
|
|
151
|
+
### Claude Code
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
claude mcp add levante -- npx levante-mcp
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Manual Configuration
|
|
158
|
+
|
|
159
|
+
Add to your MCP client config (e.g., `claude_desktop_config.json`):
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"mcpServers": {
|
|
164
|
+
"levante": {
|
|
165
|
+
"command": "npx",
|
|
166
|
+
"args": ["levante-mcp"]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Available MCP Tools
|
|
173
|
+
|
|
174
|
+
| Tool | Description |
|
|
175
|
+
|------|-------------|
|
|
176
|
+
| `e2e_ai_plan_workflow` | Get ordered step list with prerequisite checks |
|
|
177
|
+
| `e2e_ai_execute_step` | Execute a single pipeline step |
|
|
178
|
+
| `e2e_ai_get_workflow_guide` | Get the full workflow guide |
|
|
179
|
+
| `e2e_ai_scan_codebase` | Scan project for test infrastructure |
|
|
180
|
+
| `e2e_ai_validate_context` | Validate context.md completeness |
|
|
181
|
+
| `e2e_ai_read_agent` | Load an agent prompt by name |
|
|
182
|
+
| `e2e_ai_get_example` | Get example context.md template |
|
|
183
|
+
| `e2e_ai_scan_ast` | Run AST scanner |
|
|
184
|
+
| `e2e_ai_scan_ast_detail` | Drill into routes/components/hooks |
|
|
185
|
+
| `e2e_ai_build_qa_map` | Build and validate QA map |
|
|
186
|
+
| `e2e_ai_read_qa_map` | Load existing QA map |
|
|
187
|
+
|
|
188
|
+
## Configuration
|
|
189
|
+
|
|
190
|
+
Configuration lives in `.qai/levante/config.ts`:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { defineConfig } from 'levante/config';
|
|
194
|
+
|
|
195
|
+
export default defineConfig({
|
|
196
|
+
inputSource: 'jira', // 'none' | 'jira' | 'linear'
|
|
197
|
+
outputTarget: 'both', // 'markdown' | 'zephyr' | 'both'
|
|
198
|
+
baseUrl: 'http://localhost:3000',
|
|
199
|
+
|
|
200
|
+
llm: {
|
|
201
|
+
provider: 'openai', // 'openai' | 'anthropic'
|
|
202
|
+
model: 'gpt-4o', // Override default model
|
|
203
|
+
agentModels: { // Per-agent overrides
|
|
204
|
+
'scenario-agent': 'claude-sonnet-4-20250514',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
playwright: {
|
|
209
|
+
browser: 'chromium',
|
|
210
|
+
timeout: 120_000,
|
|
211
|
+
traceMode: 'on',
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
paths: {
|
|
215
|
+
tests: 'e2e/tests',
|
|
216
|
+
scenarios: 'e2e/scenarios',
|
|
217
|
+
recordings: 'e2e/recordings',
|
|
218
|
+
transcripts: 'e2e/transcripts',
|
|
219
|
+
traces: 'e2e/traces',
|
|
220
|
+
qaOutput: 'qa',
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
integrations: {
|
|
224
|
+
jira: { /* ... */ },
|
|
225
|
+
zephyr: { titlePrefix: 'UI Automation' },
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
push: {
|
|
229
|
+
apiUrl: 'https://your-api.com/qa-map',
|
|
230
|
+
apiKey: 'your-key',
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Project Structure
|
|
236
|
+
|
|
237
|
+
After initialization, levante creates:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
your-project/
|
|
241
|
+
.qai/levante/
|
|
242
|
+
config.ts # Configuration
|
|
243
|
+
context.md # Project context for AI agents
|
|
244
|
+
agents/ # Agent prompts (customizable)
|
|
245
|
+
workflow.md # Pipeline workflow guide
|
|
246
|
+
e2e/
|
|
247
|
+
tests/{key}/ # Generated test files
|
|
248
|
+
recordings/ # Codegen + voice recordings
|
|
249
|
+
transcripts/ # Transcription output
|
|
250
|
+
traces/ # Playwright traces
|
|
251
|
+
qa/ # QA documentation output
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## License
|
|
255
|
+
|
|
256
|
+
MIT
|
package/dist/cli.js
CHANGED
|
@@ -7426,7 +7426,7 @@ function buildSteps() {
|
|
|
7426
7426
|
|
|
7427
7427
|
// src/commands/init.ts
|
|
7428
7428
|
import { join as join14 } from "node:path";
|
|
7429
|
-
import { readdirSync as
|
|
7429
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
|
|
7430
7430
|
// ../../node_modules/.bun/@inquirer+core@11.1.5+aab3160543ca59a9/node_modules/@inquirer/core/dist/lib/key.js
|
|
7431
7431
|
var isUpKey = (key, keybindings = []) => key.name === "up" || keybindings.includes("vim") && key.name === "k" || keybindings.includes("emacs") && key.ctrl && key.name === "p";
|
|
7432
7432
|
var isDownKey = (key, keybindings = []) => key.name === "down" || keybindings.includes("vim") && key.name === "j" || keybindings.includes("emacs") && key.ctrl && key.name === "n";
|
|
@@ -8938,7 +8938,7 @@ var dist_default6 = createPrompt((config, done) => {
|
|
|
8938
8938
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
8939
8939
|
|
|
8940
8940
|
// src/config/migrate.ts
|
|
8941
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync
|
|
8941
|
+
import { cpSync, existsSync as existsSync2, readFileSync as readFileSync2, rmSync } from "node:fs";
|
|
8942
8942
|
import { join as join13 } from "node:path";
|
|
8943
8943
|
var LEGACY_DIR = ".e2e-ai";
|
|
8944
8944
|
async function migrateFromLegacy(projectRoot, nonInteractive) {
|
|
@@ -8958,7 +8958,7 @@ async function migrateFromLegacy(projectRoot, nonInteractive) {
|
|
|
8958
8958
|
const src = join13(legacyPath, name);
|
|
8959
8959
|
if (existsSync2(src)) {
|
|
8960
8960
|
let content = readFileSync2(src, "utf-8");
|
|
8961
|
-
content = content.replace(/from\s+['"]e2e-ai\/config['"]/g, "from '
|
|
8961
|
+
content = content.replace(/from\s+['"]e2e-ai\/config['"]/g, "from 'levante/config'");
|
|
8962
8962
|
writeFile(join13(newPath, name), content);
|
|
8963
8963
|
migrated++;
|
|
8964
8964
|
break;
|
|
@@ -9109,7 +9109,7 @@ function buildConfigFromAnswers(answers) {
|
|
|
9109
9109
|
}
|
|
9110
9110
|
function generateConfigFile(config) {
|
|
9111
9111
|
const lines = [
|
|
9112
|
-
`import { defineConfig } from '
|
|
9112
|
+
`import { defineConfig } from 'levante/config';`,
|
|
9113
9113
|
"",
|
|
9114
9114
|
"export default defineConfig({"
|
|
9115
9115
|
];
|
|
@@ -9133,7 +9133,7 @@ async function copyAgentsToLocal(projectRoot, nonInteractive) {
|
|
|
9133
9133
|
const targetDir = join14(projectRoot, CONFIG_DIR, "agents");
|
|
9134
9134
|
let agentFiles;
|
|
9135
9135
|
try {
|
|
9136
|
-
agentFiles =
|
|
9136
|
+
agentFiles = readdirSync2(sourceDir).filter((f) => f.endsWith(".md"));
|
|
9137
9137
|
} catch {
|
|
9138
9138
|
warn("Could not read package agents directory");
|
|
9139
9139
|
return 0;
|
|
@@ -9142,7 +9142,7 @@ async function copyAgentsToLocal(projectRoot, nonInteractive) {
|
|
|
9142
9142
|
return 0;
|
|
9143
9143
|
const targetExists = existsSync3(targetDir);
|
|
9144
9144
|
if (targetExists) {
|
|
9145
|
-
const existingFiles =
|
|
9145
|
+
const existingFiles = readdirSync2(targetDir).filter((f) => f.endsWith(".md"));
|
|
9146
9146
|
if (existingFiles.length > 0) {
|
|
9147
9147
|
if (nonInteractive) {
|
|
9148
9148
|
info(`Agent files already exist in ${CONFIG_DIR}/agents/, skipping`);
|