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.
Files changed (3) hide show
  1. package/README.md +256 -0
  2. package/dist/cli.js +6 -6
  3. 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 readdirSync3, readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
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, cpSync } from "node:fs";
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 '@qai/levante/config'");
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 '@qai/levante/config';`,
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 = readdirSync3(sourceDir).filter((f) => f.endsWith(".md"));
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 = readdirSync3(targetDir).filter((f) => f.endsWith(".md"));
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`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "levante",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "levante": "./dist/cli.js",