levante 0.3.4 → 0.3.6
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 +263 -83
- package/dist/cli.js +375 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Levante
|
|
2
2
|
|
|
3
|
-
AI-powered end-to-end test pipeline for Playwright. Record, transcribe, generate
|
|
3
|
+
AI-powered end-to-end test pipeline for Playwright. Record interactions, transcribe narration, generate Playwright tests, self-heal failures, and produce QA documentation — all driven by LLM agents.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g levante
|
|
9
|
+
# or
|
|
10
|
+
bun add -g levante
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
Levante requires Playwright as a peer dependency:
|
|
@@ -14,82 +16,109 @@ Levante requires Playwright as a peer dependency:
|
|
|
14
16
|
npm install -D @playwright/test
|
|
15
17
|
```
|
|
16
18
|
|
|
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
19
|
## Quick Start
|
|
27
20
|
|
|
28
21
|
```bash
|
|
29
|
-
# Initialize config and agents
|
|
22
|
+
# 1. Initialize config and agents
|
|
30
23
|
levante init
|
|
31
24
|
|
|
32
|
-
# Run full pipeline for a test case
|
|
25
|
+
# 2. Run full pipeline for a test case
|
|
33
26
|
levante run --key PROJ-101
|
|
34
27
|
|
|
35
|
-
# Or
|
|
28
|
+
# Or step by step
|
|
36
29
|
levante record --key PROJ-101
|
|
37
30
|
levante transcribe --key PROJ-101
|
|
38
31
|
levante scenario --key PROJ-101
|
|
39
32
|
levante generate --key PROJ-101
|
|
33
|
+
levante refine --key PROJ-101
|
|
40
34
|
levante test --key PROJ-101
|
|
35
|
+
levante heal --key PROJ-101 # only if test fails
|
|
36
|
+
levante qa --key PROJ-101
|
|
41
37
|
```
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
---
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
## Environment Variables
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```
|
|
43
|
+
| Variable | Description |
|
|
44
|
+
|----------|-------------|
|
|
45
|
+
| `OPENAI_API_KEY` | OpenAI API key |
|
|
46
|
+
| `ANTHROPIC_API_KEY` | Anthropic API key |
|
|
47
|
+
| `QAI_BASE_URL` | QA Intelligence API base URL |
|
|
48
|
+
| `QAI_API_URL` | Full push endpoint (overrides base URL) |
|
|
49
|
+
| `QAI_API_KEY` | API key for authenticated push |
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
---
|
|
57
52
|
|
|
58
|
-
|
|
53
|
+
## Commands
|
|
59
54
|
|
|
60
|
-
|
|
55
|
+
### `levante init`
|
|
56
|
+
|
|
57
|
+
Initialize levante in your project. Generates `.qai/levante/config.ts`, copies agent templates, and optionally connects to QA Intelligence.
|
|
61
58
|
|
|
62
59
|
```bash
|
|
63
60
|
levante init
|
|
64
|
-
levante init --non-interactive
|
|
61
|
+
levante init --non-interactive # skip prompts, use defaults
|
|
65
62
|
```
|
|
66
63
|
|
|
67
|
-
|
|
64
|
+
On re-run, preserves your existing config and context, and only updates agents.
|
|
65
|
+
|
|
66
|
+
**After init:**
|
|
67
|
+
1. Generate `.qai/levante/context.md` using the `init-agent` prompt in your AI tool, or via MCP (`levante_scan_codebase`)
|
|
68
|
+
2. Review the generated context
|
|
69
|
+
3. Start recording: `levante record --key PROJ-101`
|
|
70
|
+
|
|
71
|
+
---
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
### `levante record [session]`
|
|
74
|
+
|
|
75
|
+
Launch Playwright codegen with optional voice narration recording.
|
|
70
76
|
|
|
71
77
|
```bash
|
|
72
78
|
levante record --key PROJ-101
|
|
73
|
-
levante record --key PROJ-101 --no-voice
|
|
79
|
+
levante record --key PROJ-101 --no-companion # voice only, no companion UI
|
|
80
|
+
levante record --key PROJ-101 --no-voice # codegen only, no audio
|
|
74
81
|
```
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
| Option | Description |
|
|
84
|
+
|--------|-------------|
|
|
85
|
+
| `--no-companion` | Disable companion UI (voice recording only) |
|
|
86
|
+
| `--no-voice` | Disable voice recording entirely |
|
|
77
87
|
|
|
78
|
-
|
|
88
|
+
**Output:** codegen TypeScript file + `.wav` audio (if voice enabled)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### `levante transcribe [session]`
|
|
93
|
+
|
|
94
|
+
Transcribe the `.wav` voice recording via OpenAI Whisper. If a live transcript from the recording session exists, Whisper is skipped.
|
|
79
95
|
|
|
80
96
|
```bash
|
|
81
97
|
levante transcribe --key PROJ-101
|
|
98
|
+
levante transcribe --key PROJ-101 --force # re-transcribe even if transcript exists
|
|
82
99
|
```
|
|
83
100
|
|
|
84
|
-
|
|
101
|
+
Merges voice annotations (with timestamps) back into the codegen file as inline comments.
|
|
102
|
+
|
|
103
|
+
**Output:** `*-transcript.json`, `*-transcript.md`, annotated codegen file
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### `levante scenario [session]`
|
|
85
108
|
|
|
86
|
-
Generate a structured YAML scenario from codegen output and transcript.
|
|
109
|
+
Generate a structured YAML scenario from codegen output and voice transcript.
|
|
87
110
|
|
|
88
111
|
```bash
|
|
89
112
|
levante scenario --key PROJ-101
|
|
90
113
|
```
|
|
91
114
|
|
|
92
|
-
|
|
115
|
+
Uses `transcript-agent` (if transcript available) to extract narrative and action intents, then `scenario-agent` to produce a YAML scenario with title, precondition, steps, and postcondition. Jira/Linear issue context is included automatically if `--key` is set.
|
|
116
|
+
|
|
117
|
+
**Output:** `.yaml` scenario file in `e2e/tests/[key]/`
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### `levante generate [scenario]`
|
|
93
122
|
|
|
94
123
|
Generate a Playwright `.test.ts` file from a YAML scenario.
|
|
95
124
|
|
|
@@ -97,118 +126,238 @@ Generate a Playwright `.test.ts` file from a YAML scenario.
|
|
|
97
126
|
levante generate --key PROJ-101
|
|
98
127
|
```
|
|
99
128
|
|
|
100
|
-
|
|
129
|
+
Uses `playwright-generator-agent` with scenario + project context. If Zephyr is configured, also generates a Zephyr test case export.
|
|
130
|
+
|
|
131
|
+
**Output:** `[key].test.ts` in `e2e/tests/[key]/`
|
|
132
|
+
|
|
133
|
+
---
|
|
101
134
|
|
|
102
|
-
|
|
135
|
+
### `levante refine [test]`
|
|
136
|
+
|
|
137
|
+
Refactor a generated test with AI — replaces raw selectors, improves structure, applies project patterns.
|
|
103
138
|
|
|
104
139
|
```bash
|
|
105
140
|
levante refine --key PROJ-101
|
|
106
141
|
```
|
|
107
142
|
|
|
108
|
-
|
|
143
|
+
Uses `refactor-agent`. Rewrites the test file in-place.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
### `levante test [test]`
|
|
109
148
|
|
|
110
|
-
Run the Playwright test with trace
|
|
149
|
+
Run the Playwright test with trace, video, and screenshot capture.
|
|
111
150
|
|
|
112
151
|
```bash
|
|
113
152
|
levante test --key PROJ-101
|
|
153
|
+
levante test --key PROJ-101 --no-trace
|
|
114
154
|
```
|
|
115
155
|
|
|
116
|
-
|
|
156
|
+
**Output:** Test execution logs, trace files in `e2e/traces/`
|
|
117
157
|
|
|
118
|
-
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### `levante heal [test]`
|
|
161
|
+
|
|
162
|
+
Self-heal a failing test. Diagnoses the failure, patches the test, and re-runs — up to 3 retries.
|
|
119
163
|
|
|
120
164
|
```bash
|
|
121
165
|
levante heal --key PROJ-101
|
|
122
166
|
```
|
|
123
167
|
|
|
124
|
-
|
|
168
|
+
Each attempt uses `self-healing-agent` with test content + error output + trace data to produce:
|
|
169
|
+
- `diagnosis` (failure type, root cause, confidence)
|
|
170
|
+
- `patchedTest` (updated test file)
|
|
171
|
+
- `changes` (summary of what was fixed)
|
|
172
|
+
|
|
173
|
+
Exits with error if all 3 attempts fail.
|
|
125
174
|
|
|
126
|
-
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### `levante qa [test]`
|
|
178
|
+
|
|
179
|
+
Generate QA documentation from the test and scenario.
|
|
127
180
|
|
|
128
181
|
```bash
|
|
129
182
|
levante qa --key PROJ-101
|
|
130
183
|
```
|
|
131
184
|
|
|
132
|
-
|
|
185
|
+
Uses `qa-testcase-agent` with test + scenario + Jira context. Produces markdown and/or Zephyr export depending on `outputTarget`.
|
|
186
|
+
|
|
187
|
+
**Output:** `qa/[testId].md` and/or Zephyr JSON
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### `levante run [session]`
|
|
133
192
|
|
|
134
|
-
Run the full pipeline: record → transcribe → scenario → generate → refine → test → heal → qa
|
|
193
|
+
Run the full pipeline: `record → transcribe → scenario → generate → refine → test → heal → qa`.
|
|
135
194
|
|
|
136
195
|
```bash
|
|
137
196
|
levante run --key PROJ-101
|
|
138
|
-
levante run --key PROJ-101 --from generate
|
|
197
|
+
levante run --key PROJ-101 --from generate # resume from a specific step
|
|
139
198
|
levante run --key PROJ-101 --skip transcribe,heal
|
|
199
|
+
levante run --key PROJ-101 --no-voice # skip recording + transcription
|
|
140
200
|
```
|
|
141
201
|
|
|
142
202
|
| Option | Description |
|
|
143
203
|
|--------|-------------|
|
|
144
|
-
| `--from <step>` | Start from a specific step |
|
|
145
|
-
| `--skip <steps>` |
|
|
204
|
+
| `--from <step>` | Start from a specific step (skips earlier steps) |
|
|
205
|
+
| `--skip <steps>` | Comma-separated step names to skip |
|
|
206
|
+
| `--no-voice` | Disable voice recording (skips transcription too) |
|
|
207
|
+
| `--no-trace` | Disable trace capture |
|
|
146
208
|
|
|
147
|
-
|
|
209
|
+
**Steps (in order):** `record` → `transcribe` → `scenario` → `generate` → `refine` → `test` → `heal` → `qa`
|
|
148
210
|
|
|
149
|
-
|
|
211
|
+
---
|
|
150
212
|
|
|
151
|
-
###
|
|
213
|
+
### `levante auth`
|
|
214
|
+
|
|
215
|
+
Manage authentication with QA Intelligence.
|
|
152
216
|
|
|
153
217
|
```bash
|
|
154
|
-
|
|
218
|
+
levante auth login # open browser for OAuth sign-in
|
|
219
|
+
levante auth logout # revoke CLI token
|
|
220
|
+
levante auth status # show current auth status
|
|
221
|
+
levante auth switch # re-authenticate with a different org/project/app
|
|
155
222
|
```
|
|
156
223
|
|
|
157
|
-
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### `levante jira`
|
|
227
|
+
|
|
228
|
+
Interactive Jira integration for issue discovery and workflow launch.
|
|
158
229
|
|
|
159
|
-
|
|
230
|
+
#### `levante jira browse`
|
|
160
231
|
|
|
232
|
+
Interactive browser — search, view, and select Jira issues to start a test workflow.
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
levante jira browse
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Select an issue to:
|
|
239
|
+
- **run** — save context and launch `levante run --key <KEY>`
|
|
240
|
+
- **save** — save issue context without running
|
|
241
|
+
- **view** — display full issue details
|
|
242
|
+
|
|
243
|
+
#### `levante jira search <query>`
|
|
244
|
+
|
|
245
|
+
Search Jira issues by text or raw JQL.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
levante jira search "login flow"
|
|
249
|
+
levante jira search --jql "project = QA AND status = 'In Progress'"
|
|
250
|
+
levante jira search "dashboard" --max 10
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
| Option | Description |
|
|
254
|
+
|--------|-------------|
|
|
255
|
+
| `<query>` | Text search query |
|
|
256
|
+
| `--jql <jql>` | Use raw JQL instead of text search |
|
|
257
|
+
| `--max <n>` | Maximum results to return (default: 20) |
|
|
258
|
+
|
|
259
|
+
#### `levante jira show <issueKey>`
|
|
260
|
+
|
|
261
|
+
Display full details for a Jira issue.
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
levante jira show PROJ-101
|
|
265
|
+
levante jira show PROJ-101 --save # also save context for pipeline use
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
| Option | Description |
|
|
269
|
+
|--------|-------------|
|
|
270
|
+
| `--save` | Save issue context to `.qai/levante/issues/[KEY].json` |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
### `levante mcp`
|
|
275
|
+
|
|
276
|
+
Print MCP server setup instructions.
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
levante mcp
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Claude Code:**
|
|
283
|
+
```bash
|
|
284
|
+
claude mcp add levante -- levante-mcp # project-scoped
|
|
285
|
+
claude mcp add levante -s user -- levante-mcp # global
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Claude Desktop / other clients:**
|
|
161
289
|
```json
|
|
162
290
|
{
|
|
163
291
|
"mcpServers": {
|
|
164
|
-
"levante": {
|
|
165
|
-
"command": "npx",
|
|
166
|
-
"args": ["levante-mcp"]
|
|
167
|
-
}
|
|
292
|
+
"levante": { "command": "levante-mcp" }
|
|
168
293
|
}
|
|
169
294
|
}
|
|
170
295
|
```
|
|
171
296
|
|
|
172
|
-
|
|
297
|
+
**Available MCP tools:**
|
|
173
298
|
|
|
174
299
|
| Tool | Description |
|
|
175
300
|
|------|-------------|
|
|
176
301
|
| `levante_plan_workflow` | Get ordered step list with prerequisite checks |
|
|
177
302
|
| `levante_execute_step` | Execute a single pipeline step |
|
|
178
|
-
| `levante_get_workflow_guide` |
|
|
303
|
+
| `levante_get_workflow_guide` | Read the full workflow guide |
|
|
179
304
|
| `levante_scan_codebase` | Scan project for test infrastructure |
|
|
180
305
|
| `levante_validate_context` | Validate context.md completeness |
|
|
181
306
|
| `levante_read_agent` | Load an agent prompt by name |
|
|
182
|
-
| `levante_get_example` | Get example context.md template |
|
|
307
|
+
| `levante_get_example` | Get an example context.md template |
|
|
183
308
|
| `levante_scan_ast` | Run AST scanner |
|
|
184
309
|
| `levante_scan_ast_detail` | Drill into routes/components/hooks |
|
|
185
310
|
| `levante_build_qa_map` | Build and validate QA map |
|
|
186
311
|
| `levante_read_qa_map` | Load existing QA map |
|
|
187
312
|
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Global Options
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
-k, --key <KEY> Issue key (e.g. PROJ-101, LIN-42)
|
|
319
|
+
--provider <provider> LLM provider: openai | anthropic
|
|
320
|
+
--model <model> LLM model override
|
|
321
|
+
--verbose Verbose output
|
|
322
|
+
--no-voice Disable voice recording
|
|
323
|
+
--no-trace Disable trace capture
|
|
324
|
+
-v, --version Show version
|
|
325
|
+
-h, --help Show help
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
188
330
|
## Configuration
|
|
189
331
|
|
|
190
|
-
Configuration lives in `.qai/levante/config.ts
|
|
332
|
+
Configuration lives in `.qai/levante/config.ts` (generated by `levante init`):
|
|
191
333
|
|
|
192
334
|
```typescript
|
|
193
|
-
import { defineConfig } from 'levante
|
|
335
|
+
import { defineConfig } from 'levante';
|
|
194
336
|
|
|
195
337
|
export default defineConfig({
|
|
196
|
-
inputSource: 'jira',
|
|
197
|
-
outputTarget: 'both',
|
|
338
|
+
inputSource: 'jira', // 'none' | 'jira' | 'linear'
|
|
339
|
+
outputTarget: 'both', // 'markdown' | 'zephyr' | 'both'
|
|
198
340
|
baseUrl: 'http://localhost:3000',
|
|
199
341
|
|
|
200
342
|
llm: {
|
|
201
|
-
provider: 'openai',
|
|
202
|
-
model: 'gpt-4o',
|
|
203
|
-
agentModels: {
|
|
343
|
+
provider: 'openai', // 'openai' | 'anthropic'
|
|
344
|
+
model: 'gpt-4o',
|
|
345
|
+
agentModels: { // per-agent model overrides
|
|
204
346
|
'scenario-agent': 'claude-sonnet-4-20250514',
|
|
205
347
|
},
|
|
206
348
|
},
|
|
207
349
|
|
|
208
350
|
playwright: {
|
|
209
|
-
browser: 'chromium',
|
|
351
|
+
browser: 'chromium', // 'chromium' | 'firefox' | 'webkit'
|
|
210
352
|
timeout: 120_000,
|
|
211
|
-
|
|
353
|
+
retries: 0,
|
|
354
|
+
traceMode: 'on', // 'on' | 'off' | 'retain-on-failure'
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
voice: {
|
|
358
|
+
enabled: true,
|
|
359
|
+
engine: 'webspeech', // 'webspeech' | 'whisper'
|
|
360
|
+
language: 'en-US',
|
|
212
361
|
},
|
|
213
362
|
|
|
214
363
|
paths: {
|
|
@@ -221,36 +370,67 @@ export default defineConfig({
|
|
|
221
370
|
},
|
|
222
371
|
|
|
223
372
|
integrations: {
|
|
224
|
-
jira: { /*
|
|
373
|
+
jira: { /* Jira config */ },
|
|
225
374
|
zephyr: { titlePrefix: 'UI Automation' },
|
|
226
375
|
},
|
|
227
376
|
|
|
228
377
|
push: {
|
|
229
|
-
apiUrl: 'https://
|
|
378
|
+
apiUrl: 'https://qaligent.space/api',
|
|
230
379
|
apiKey: 'your-key',
|
|
231
380
|
},
|
|
232
381
|
});
|
|
233
382
|
```
|
|
234
383
|
|
|
235
|
-
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## AI Agents
|
|
387
|
+
|
|
388
|
+
Levante ships with agents copied to `.qai/levante/agents/` on `init`. Edit them to tune AI behavior for your project.
|
|
236
389
|
|
|
237
|
-
|
|
390
|
+
| Agent | Purpose |
|
|
391
|
+
|-------|---------|
|
|
392
|
+
| `0.init-agent` | Generate project `context.md` |
|
|
393
|
+
| `1_1.transcript-agent` | Analyze voice transcript + codegen into narrative |
|
|
394
|
+
| `1_2.scenario-agent` | Generate YAML scenario from narrative and actions |
|
|
395
|
+
| `2.playwright-generator-agent` | Generate Playwright test from YAML scenario |
|
|
396
|
+
| `3.refactor-agent` | Refactor test code for quality and conventions |
|
|
397
|
+
| `4.self-healing-agent` | Diagnose and patch failing tests |
|
|
398
|
+
| `5.qa-testcase-agent` | Generate QA documentation and Zephyr export |
|
|
399
|
+
|
|
400
|
+
Add `.qai/levante/context.md` to inject project-specific context into every agent call.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Project Structure
|
|
238
405
|
|
|
239
406
|
```
|
|
240
407
|
your-project/
|
|
241
408
|
.qai/levante/
|
|
242
|
-
config.ts
|
|
243
|
-
context.md
|
|
244
|
-
agents/
|
|
245
|
-
workflow.md
|
|
409
|
+
config.ts # Configuration
|
|
410
|
+
context.md # Project context for AI agents
|
|
411
|
+
agents/ # Agent prompts (customizable)
|
|
412
|
+
workflow.md # Pipeline workflow guide
|
|
413
|
+
issues/ # Saved Jira issue contexts
|
|
246
414
|
e2e/
|
|
247
|
-
tests/{key}/
|
|
248
|
-
recordings/
|
|
249
|
-
transcripts/
|
|
250
|
-
traces/
|
|
251
|
-
qa/
|
|
415
|
+
tests/{key}/ # Generated test files + scenario YAML
|
|
416
|
+
recordings/ # Codegen + voice recordings
|
|
417
|
+
transcripts/ # Transcription output
|
|
418
|
+
traces/ # Playwright traces
|
|
419
|
+
qa/ # QA documentation output
|
|
252
420
|
```
|
|
253
421
|
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Interactive TUI
|
|
425
|
+
|
|
426
|
+
Running `levante` with no arguments launches an interactive terminal UI (requires TTY, ≥ 60×20).
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
levante
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
254
434
|
## License
|
|
255
435
|
|
|
256
436
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -56844,7 +56844,7 @@ var init_build3 = __esm(async () => {
|
|
|
56844
56844
|
|
|
56845
56845
|
// src/tui/CommandInspect.tsx
|
|
56846
56846
|
function CommandInspect({ theme, cliName, command, globalOptions, onRun, onBack }) {
|
|
56847
|
-
const allOptions = [...command.options, ...globalOptions];
|
|
56847
|
+
const allOptions = command.hideGlobalOptions ? [...command.options] : [...command.options, ...globalOptions];
|
|
56848
56848
|
const [fields, setFields] = import_react25.useState(() => ({
|
|
56849
56849
|
args: Object.fromEntries(command.args.map((a) => [a.name, ""])),
|
|
56850
56850
|
booleans: Object.fromEntries(allOptions.filter((o) => o.type === "boolean").map((o) => [o.flags, false])),
|
|
@@ -56859,12 +56859,14 @@ function CommandInspect({ theme, cliName, command, globalOptions, onRun, onBack
|
|
|
56859
56859
|
use_input_default((input, key) => {
|
|
56860
56860
|
if (key.escape)
|
|
56861
56861
|
return onBack();
|
|
56862
|
+
if (command.InlineView)
|
|
56863
|
+
return;
|
|
56862
56864
|
if (key.tab) {
|
|
56863
56865
|
setFocusIndex((i) => (i + 1) % Math.max(focusableFields.length, 1));
|
|
56864
56866
|
return;
|
|
56865
56867
|
}
|
|
56866
56868
|
if (key.return) {
|
|
56867
|
-
const argv = [command.name];
|
|
56869
|
+
const argv = [...command.baseArgv ?? [command.name]];
|
|
56868
56870
|
for (const arg of command.args) {
|
|
56869
56871
|
const val = fields.args[arg.name]?.trim();
|
|
56870
56872
|
if (val)
|
|
@@ -56900,6 +56902,60 @@ function CommandInspect({ theme, cliName, command, globalOptions, onRun, onBack
|
|
|
56900
56902
|
}
|
|
56901
56903
|
if (allOptions.length > 0)
|
|
56902
56904
|
usageParts.push("[options]");
|
|
56905
|
+
if (command.InlineView) {
|
|
56906
|
+
return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
56907
|
+
flexDirection: "column",
|
|
56908
|
+
paddingX: 1,
|
|
56909
|
+
children: [
|
|
56910
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
56911
|
+
justifyContent: "space-between",
|
|
56912
|
+
marginBottom: 1,
|
|
56913
|
+
children: [
|
|
56914
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
56915
|
+
dimColor: true,
|
|
56916
|
+
children: "← esc"
|
|
56917
|
+
}, undefined, false, undefined, this),
|
|
56918
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
56919
|
+
color: theme.accent,
|
|
56920
|
+
bold: true,
|
|
56921
|
+
children: [
|
|
56922
|
+
cliName,
|
|
56923
|
+
" ",
|
|
56924
|
+
command.name
|
|
56925
|
+
]
|
|
56926
|
+
}, undefined, true, undefined, this)
|
|
56927
|
+
]
|
|
56928
|
+
}, undefined, true, undefined, this),
|
|
56929
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(command.InlineView, {
|
|
56930
|
+
theme
|
|
56931
|
+
}, undefined, false, undefined, this),
|
|
56932
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
56933
|
+
marginTop: 1,
|
|
56934
|
+
children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
56935
|
+
dimColor: true,
|
|
56936
|
+
children: "esc back"
|
|
56937
|
+
}, undefined, false, undefined, this)
|
|
56938
|
+
}, undefined, false, undefined, this)
|
|
56939
|
+
]
|
|
56940
|
+
}, undefined, true, undefined, this);
|
|
56941
|
+
}
|
|
56942
|
+
const previewArgv = [cliName, ...command.baseArgv ?? [command.name]];
|
|
56943
|
+
for (const arg of command.args) {
|
|
56944
|
+
const val = fields.args[arg.name]?.trim();
|
|
56945
|
+
if (val)
|
|
56946
|
+
previewArgv.push(val);
|
|
56947
|
+
}
|
|
56948
|
+
for (const opt of allOptions) {
|
|
56949
|
+
if (opt.type === "boolean" && fields.booleans[opt.flags]) {
|
|
56950
|
+
previewArgv.push(opt.flags);
|
|
56951
|
+
}
|
|
56952
|
+
if (opt.type === "string") {
|
|
56953
|
+
const val = fields.strings[opt.flags]?.trim();
|
|
56954
|
+
if (val)
|
|
56955
|
+
previewArgv.push(opt.flags, val);
|
|
56956
|
+
}
|
|
56957
|
+
}
|
|
56958
|
+
const previewCommand = previewArgv.join(" ");
|
|
56903
56959
|
const renderOption = (opt) => {
|
|
56904
56960
|
const isFocused = currentFocus === `opt:${opt.flags}`;
|
|
56905
56961
|
if (opt.type === "boolean") {
|
|
@@ -56998,6 +57054,7 @@ function CommandInspect({ theme, cliName, command, globalOptions, onRun, onBack
|
|
|
56998
57054
|
children: "USAGE"
|
|
56999
57055
|
}, undefined, false, undefined, this),
|
|
57000
57056
|
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
57057
|
+
dimColor: true,
|
|
57001
57058
|
children: [
|
|
57002
57059
|
" ",
|
|
57003
57060
|
usageParts.join(" ")
|
|
@@ -57005,6 +57062,24 @@ function CommandInspect({ theme, cliName, command, globalOptions, onRun, onBack
|
|
|
57005
57062
|
}, undefined, true, undefined, this)
|
|
57006
57063
|
]
|
|
57007
57064
|
}, undefined, true, undefined, this),
|
|
57065
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
57066
|
+
flexDirection: "column",
|
|
57067
|
+
marginBottom: 1,
|
|
57068
|
+
children: [
|
|
57069
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
57070
|
+
dimColor: true,
|
|
57071
|
+
bold: true,
|
|
57072
|
+
children: "COMMAND"
|
|
57073
|
+
}, undefined, false, undefined, this),
|
|
57074
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
|
|
57075
|
+
color: theme.accent,
|
|
57076
|
+
children: [
|
|
57077
|
+
" $ ",
|
|
57078
|
+
previewCommand
|
|
57079
|
+
]
|
|
57080
|
+
}, undefined, true, undefined, this)
|
|
57081
|
+
]
|
|
57082
|
+
}, undefined, true, undefined, this),
|
|
57008
57083
|
command.args.length > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
57009
57084
|
flexDirection: "column",
|
|
57010
57085
|
marginBottom: 1,
|
|
@@ -57051,7 +57126,7 @@ function CommandInspect({ theme, cliName, command, globalOptions, onRun, onBack
|
|
|
57051
57126
|
command.options.map(renderOption)
|
|
57052
57127
|
]
|
|
57053
57128
|
}, undefined, true, undefined, this),
|
|
57054
|
-
globalOptions.length > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
57129
|
+
!command.hideGlobalOptions && globalOptions.length > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
57055
57130
|
flexDirection: "column",
|
|
57056
57131
|
marginBottom: 1,
|
|
57057
57132
|
children: [
|
|
@@ -57095,9 +57170,108 @@ var init_theme2 = __esm(() => {
|
|
|
57095
57170
|
};
|
|
57096
57171
|
});
|
|
57097
57172
|
|
|
57173
|
+
// src/tui/McpInline.tsx
|
|
57174
|
+
function McpInline({ theme: theme2 }) {
|
|
57175
|
+
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
57176
|
+
flexDirection: "column",
|
|
57177
|
+
gap: 1,
|
|
57178
|
+
children: [
|
|
57179
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
57180
|
+
flexDirection: "column",
|
|
57181
|
+
children: [
|
|
57182
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57183
|
+
bold: true,
|
|
57184
|
+
children: "Claude Code — add to project"
|
|
57185
|
+
}, undefined, false, undefined, this),
|
|
57186
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57187
|
+
color: theme2.accent,
|
|
57188
|
+
children: " claude mcp add levante -- levante-mcp"
|
|
57189
|
+
}, undefined, false, undefined, this)
|
|
57190
|
+
]
|
|
57191
|
+
}, undefined, true, undefined, this),
|
|
57192
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
57193
|
+
flexDirection: "column",
|
|
57194
|
+
children: [
|
|
57195
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57196
|
+
bold: true,
|
|
57197
|
+
children: "Claude Code — add globally"
|
|
57198
|
+
}, undefined, false, undefined, this),
|
|
57199
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57200
|
+
color: theme2.accent,
|
|
57201
|
+
children: " claude mcp add levante -s user -- levante-mcp"
|
|
57202
|
+
}, undefined, false, undefined, this)
|
|
57203
|
+
]
|
|
57204
|
+
}, undefined, true, undefined, this),
|
|
57205
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
57206
|
+
flexDirection: "column",
|
|
57207
|
+
children: [
|
|
57208
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57209
|
+
bold: true,
|
|
57210
|
+
children: "Claude Desktop / other clients"
|
|
57211
|
+
}, undefined, false, undefined, this),
|
|
57212
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57213
|
+
dimColor: true,
|
|
57214
|
+
children: " ~/.config/claude/claude_desktop_config.json"
|
|
57215
|
+
}, undefined, false, undefined, this),
|
|
57216
|
+
CONFIG.split(`
|
|
57217
|
+
`).map((line, i) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57218
|
+
color: theme2.accent,
|
|
57219
|
+
children: [
|
|
57220
|
+
" ",
|
|
57221
|
+
line
|
|
57222
|
+
]
|
|
57223
|
+
}, i, true, undefined, this))
|
|
57224
|
+
]
|
|
57225
|
+
}, undefined, true, undefined, this),
|
|
57226
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
57227
|
+
flexDirection: "column",
|
|
57228
|
+
children: [
|
|
57229
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57230
|
+
bold: true,
|
|
57231
|
+
children: "Available tools"
|
|
57232
|
+
}, undefined, false, undefined, this),
|
|
57233
|
+
TOOLS2.map((t) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57234
|
+
dimColor: true,
|
|
57235
|
+
children: [
|
|
57236
|
+
" · ",
|
|
57237
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
57238
|
+
color: theme2.accentSecondary,
|
|
57239
|
+
children: t
|
|
57240
|
+
}, undefined, false, undefined, this)
|
|
57241
|
+
]
|
|
57242
|
+
}, t, true, undefined, this))
|
|
57243
|
+
]
|
|
57244
|
+
}, undefined, true, undefined, this)
|
|
57245
|
+
]
|
|
57246
|
+
}, undefined, true, undefined, this);
|
|
57247
|
+
}
|
|
57248
|
+
var jsx_dev_runtime4, CONFIG = `{
|
|
57249
|
+
"mcpServers": {
|
|
57250
|
+
"levante": {
|
|
57251
|
+
"command": "levante-mcp"
|
|
57252
|
+
}
|
|
57253
|
+
}
|
|
57254
|
+
}`, TOOLS2;
|
|
57255
|
+
var init_McpInline = __esm(async () => {
|
|
57256
|
+
await init_build2();
|
|
57257
|
+
jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
|
|
57258
|
+
TOOLS2 = [
|
|
57259
|
+
"levante_plan_workflow",
|
|
57260
|
+
"levante_execute_step",
|
|
57261
|
+
"levante_scan_codebase",
|
|
57262
|
+
"levante_read_agent",
|
|
57263
|
+
"levante_scan_ast",
|
|
57264
|
+
"levante_scan_ast_detail",
|
|
57265
|
+
"levante_build_qa_map",
|
|
57266
|
+
"levante_read_qa_map",
|
|
57267
|
+
"levante_get_workflow_guide"
|
|
57268
|
+
];
|
|
57269
|
+
});
|
|
57270
|
+
|
|
57098
57271
|
// src/tui/commands.ts
|
|
57099
57272
|
var commandGroups;
|
|
57100
|
-
var init_commands = __esm(() => {
|
|
57273
|
+
var init_commands = __esm(async () => {
|
|
57274
|
+
await init_McpInline();
|
|
57101
57275
|
commandGroups = [
|
|
57102
57276
|
{
|
|
57103
57277
|
label: "⚡ PIPELINE",
|
|
@@ -57182,16 +57356,73 @@ var init_commands = __esm(() => {
|
|
|
57182
57356
|
label: "\uD83D\uDD17 INTEGRATIONS",
|
|
57183
57357
|
commands: [
|
|
57184
57358
|
{
|
|
57185
|
-
name: "auth",
|
|
57359
|
+
name: "auth login",
|
|
57360
|
+
baseArgv: ["auth", "login"],
|
|
57186
57361
|
args: [],
|
|
57187
|
-
description: "
|
|
57188
|
-
options: []
|
|
57362
|
+
description: "Authenticate with QA Intelligence — opens browser for sign-in",
|
|
57363
|
+
options: [],
|
|
57364
|
+
hideGlobalOptions: true
|
|
57189
57365
|
},
|
|
57190
57366
|
{
|
|
57191
|
-
name: "
|
|
57367
|
+
name: "auth logout",
|
|
57368
|
+
baseArgv: ["auth", "logout"],
|
|
57192
57369
|
args: [],
|
|
57193
|
-
description: "
|
|
57194
|
-
options: []
|
|
57370
|
+
description: "Sign out and revoke CLI token",
|
|
57371
|
+
options: [],
|
|
57372
|
+
hideGlobalOptions: true
|
|
57373
|
+
},
|
|
57374
|
+
{
|
|
57375
|
+
name: "auth status",
|
|
57376
|
+
baseArgv: ["auth", "status"],
|
|
57377
|
+
args: [],
|
|
57378
|
+
description: "Show current authentication status",
|
|
57379
|
+
options: [],
|
|
57380
|
+
hideGlobalOptions: true
|
|
57381
|
+
},
|
|
57382
|
+
{
|
|
57383
|
+
name: "auth switch",
|
|
57384
|
+
baseArgv: ["auth", "switch"],
|
|
57385
|
+
args: [],
|
|
57386
|
+
description: "Switch scope — re-authenticate with a different org/project/app",
|
|
57387
|
+
options: [],
|
|
57388
|
+
hideGlobalOptions: true
|
|
57389
|
+
},
|
|
57390
|
+
{
|
|
57391
|
+
name: "mcp",
|
|
57392
|
+
args: [],
|
|
57393
|
+
description: "Show MCP server setup instructions for Claude",
|
|
57394
|
+
options: [],
|
|
57395
|
+
hideGlobalOptions: true,
|
|
57396
|
+
InlineView: McpInline
|
|
57397
|
+
},
|
|
57398
|
+
{
|
|
57399
|
+
name: "jira browse",
|
|
57400
|
+
baseArgv: ["jira", "browse"],
|
|
57401
|
+
args: [],
|
|
57402
|
+
description: "Interactive Jira issue browser — search, select, and start test workflow",
|
|
57403
|
+
options: [],
|
|
57404
|
+
hideGlobalOptions: true
|
|
57405
|
+
},
|
|
57406
|
+
{
|
|
57407
|
+
name: "jira search",
|
|
57408
|
+
baseArgv: ["jira", "search"],
|
|
57409
|
+
args: [{ name: "query", required: true, description: "Text search query" }],
|
|
57410
|
+
description: "Search Jira issues by text or raw JQL",
|
|
57411
|
+
options: [
|
|
57412
|
+
{ flags: "--jql", description: "Use raw JQL instead of text search", type: "string", placeholder: "jql" },
|
|
57413
|
+
{ flags: "--max", description: "Maximum results to return", type: "string", placeholder: "n", default: "20" }
|
|
57414
|
+
],
|
|
57415
|
+
hideGlobalOptions: true
|
|
57416
|
+
},
|
|
57417
|
+
{
|
|
57418
|
+
name: "jira show",
|
|
57419
|
+
baseArgv: ["jira", "show"],
|
|
57420
|
+
args: [{ name: "issueKey", required: true, description: "Issue key (e.g. PROJ-101)" }],
|
|
57421
|
+
description: "Show full Jira issue details",
|
|
57422
|
+
options: [
|
|
57423
|
+
{ flags: "--save", description: "Save issue context for pipeline use", type: "boolean" }
|
|
57424
|
+
],
|
|
57425
|
+
hideGlobalOptions: true
|
|
57195
57426
|
}
|
|
57196
57427
|
]
|
|
57197
57428
|
}
|
|
@@ -57225,22 +57456,22 @@ function App2({ version: version2, onRunCommand, onQuit }) {
|
|
|
57225
57456
|
exit();
|
|
57226
57457
|
onRunCommand(argv);
|
|
57227
57458
|
}, [exit, onRunCommand]);
|
|
57228
|
-
return /* @__PURE__ */
|
|
57459
|
+
return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
|
|
57229
57460
|
flexDirection: "column",
|
|
57230
57461
|
children: [
|
|
57231
|
-
screen === "banner" && /* @__PURE__ */
|
|
57462
|
+
screen === "banner" && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Banner, {
|
|
57232
57463
|
theme,
|
|
57233
57464
|
version: version2,
|
|
57234
57465
|
onComplete: handleBannerComplete
|
|
57235
57466
|
}, undefined, false, undefined, this),
|
|
57236
|
-
screen === "browser" && /* @__PURE__ */
|
|
57467
|
+
screen === "browser" && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(CommandBrowser, {
|
|
57237
57468
|
theme,
|
|
57238
57469
|
version: version2,
|
|
57239
57470
|
groups: commandGroups,
|
|
57240
57471
|
onSelect: handleSelect,
|
|
57241
57472
|
onQuit: handleQuit
|
|
57242
57473
|
}, undefined, false, undefined, this),
|
|
57243
|
-
screen === "inspect" && inspectCommand && /* @__PURE__ */
|
|
57474
|
+
screen === "inspect" && inspectCommand && /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(CommandInspect, {
|
|
57244
57475
|
theme,
|
|
57245
57476
|
cliName: "levante",
|
|
57246
57477
|
command: inspectCommand,
|
|
@@ -57253,7 +57484,7 @@ function App2({ version: version2, onRunCommand, onQuit }) {
|
|
|
57253
57484
|
}
|
|
57254
57485
|
async function launchTui(program2) {
|
|
57255
57486
|
const version2 = program2.version() || "0.0.0";
|
|
57256
|
-
return new Promise((resolve2
|
|
57487
|
+
return new Promise((resolve2) => {
|
|
57257
57488
|
let resolved = false;
|
|
57258
57489
|
const done = () => {
|
|
57259
57490
|
if (!resolved) {
|
|
@@ -57261,35 +57492,49 @@ async function launchTui(program2) {
|
|
|
57261
57492
|
resolve2();
|
|
57262
57493
|
}
|
|
57263
57494
|
};
|
|
57264
|
-
|
|
57495
|
+
let runningCommand = false;
|
|
57496
|
+
const instance = render_default(/* @__PURE__ */ jsx_dev_runtime5.jsxDEV(App2, {
|
|
57265
57497
|
version: version2,
|
|
57266
57498
|
onRunCommand: (argv) => {
|
|
57499
|
+
runningCommand = true;
|
|
57267
57500
|
instance.waitUntilExit().then(() => {
|
|
57268
|
-
|
|
57269
|
-
|
|
57270
|
-
|
|
57501
|
+
setTimeout(async () => {
|
|
57502
|
+
process.stdin.resume();
|
|
57503
|
+
process.stdin.ref();
|
|
57504
|
+
process.stdout.write(`
|
|
57505
|
+
$ levante ${argv.join(" ")}
|
|
57506
|
+
|
|
57507
|
+
`);
|
|
57508
|
+
try {
|
|
57509
|
+
await program2.parseAsync(argv, { from: "user" });
|
|
57510
|
+
} catch (err) {
|
|
57511
|
+
if (err?.name !== "ExitPromptError")
|
|
57512
|
+
throw err;
|
|
57271
57513
|
}
|
|
57272
|
-
|
|
57273
|
-
});
|
|
57514
|
+
done();
|
|
57515
|
+
}, 50);
|
|
57274
57516
|
});
|
|
57275
57517
|
},
|
|
57276
57518
|
onQuit: done
|
|
57277
57519
|
}, undefined, false, undefined, this));
|
|
57278
|
-
instance.waitUntilExit().then(
|
|
57520
|
+
instance.waitUntilExit().then(() => {
|
|
57521
|
+
if (!runningCommand)
|
|
57522
|
+
done();
|
|
57523
|
+
});
|
|
57279
57524
|
});
|
|
57280
57525
|
}
|
|
57281
|
-
var import_react26,
|
|
57526
|
+
var import_react26, jsx_dev_runtime5, globalOptions;
|
|
57282
57527
|
var init_App2 = __esm(async () => {
|
|
57283
57528
|
init_theme2();
|
|
57284
|
-
init_commands();
|
|
57285
57529
|
await __promiseAll([
|
|
57286
57530
|
init_build2(),
|
|
57287
57531
|
init_Banner(),
|
|
57288
57532
|
init_CommandBrowser(),
|
|
57289
|
-
init_CommandInspect()
|
|
57533
|
+
init_CommandInspect(),
|
|
57534
|
+
init_commands()
|
|
57290
57535
|
]);
|
|
57291
57536
|
import_react26 = __toESM(require_react(), 1);
|
|
57292
|
-
|
|
57537
|
+
jsx_dev_runtime5 = __toESM(require_jsx_dev_runtime(), 1);
|
|
57293
57538
|
globalOptions = [
|
|
57294
57539
|
{ flags: "--key", description: "Issue key (e.g., PROJ-101, LIN-42)", type: "string", placeholder: "KEY" },
|
|
57295
57540
|
{ flags: "--provider", description: "LLM provider (openai|anthropic)", type: "string", placeholder: "provider" },
|
|
@@ -75265,54 +75510,61 @@ async function migrateFromLegacy(projectRoot, nonInteractive) {
|
|
|
75265
75510
|
// src/commands/init.ts
|
|
75266
75511
|
function registerInit(program2) {
|
|
75267
75512
|
program2.command("init").description("Initialize levante configuration for your project").option("--non-interactive", "Skip interactive prompts, use defaults").action(async (cmdOpts) => {
|
|
75268
|
-
|
|
75269
|
-
|
|
75270
|
-
|
|
75271
|
-
|
|
75272
|
-
|
|
75273
|
-
|
|
75274
|
-
|
|
75275
|
-
|
|
75276
|
-
|
|
75513
|
+
try {
|
|
75514
|
+
const projectRoot = getProjectRoot();
|
|
75515
|
+
const nonInteractive = !!cmdOpts?.nonInteractive;
|
|
75516
|
+
header("levante init");
|
|
75517
|
+
await migrateFromLegacy(projectRoot, nonInteractive);
|
|
75518
|
+
const qaiDir = join17(projectRoot, CONFIG_DIR);
|
|
75519
|
+
const configPath = join17(qaiDir, "config.ts");
|
|
75520
|
+
const isReInit = fileExists(configPath);
|
|
75521
|
+
if (isReInit) {
|
|
75522
|
+
info(`Existing ${CONFIG_DIR}/ detected — preserving config and context.
|
|
75277
75523
|
`);
|
|
75278
|
-
|
|
75279
|
-
|
|
75280
|
-
|
|
75281
|
-
|
|
75282
|
-
|
|
75283
|
-
|
|
75284
|
-
|
|
75285
|
-
|
|
75286
|
-
|
|
75287
|
-
|
|
75288
|
-
|
|
75289
|
-
|
|
75290
|
-
|
|
75291
|
-
|
|
75292
|
-
|
|
75293
|
-
|
|
75294
|
-
|
|
75295
|
-
|
|
75296
|
-
|
|
75297
|
-
|
|
75298
|
-
|
|
75299
|
-
|
|
75300
|
-
|
|
75301
|
-
|
|
75524
|
+
await copyAgentsToLocal(projectRoot, nonInteractive);
|
|
75525
|
+
await copyWorkflowGuide(projectRoot, nonInteractive);
|
|
75526
|
+
} else {
|
|
75527
|
+
const answers = nonInteractive ? getDefaultAnswers() : await askConfigQuestions();
|
|
75528
|
+
const config2 = buildConfigFromAnswers(answers);
|
|
75529
|
+
writeFile(configPath, generateConfigFile(config2));
|
|
75530
|
+
success2(`Config written: ${configPath}`);
|
|
75531
|
+
await copyAgentsToLocal(projectRoot, nonInteractive);
|
|
75532
|
+
await copyWorkflowGuide(projectRoot, nonInteractive);
|
|
75533
|
+
}
|
|
75534
|
+
if (!nonInteractive) {
|
|
75535
|
+
const { confirm: confirmPrompt } = await Promise.resolve().then(() => (init_dist9(), exports_dist));
|
|
75536
|
+
const connectAuth = await confirmPrompt({
|
|
75537
|
+
message: "Connect to QA Intelligence?",
|
|
75538
|
+
default: false
|
|
75539
|
+
});
|
|
75540
|
+
if (connectAuth) {
|
|
75541
|
+
try {
|
|
75542
|
+
const { login: login2 } = await Promise.resolve().then(() => (init_dist10(), exports_dist2));
|
|
75543
|
+
const session = await login2({ webappUrl: "https://qaligent.space" });
|
|
75544
|
+
success2(`Authenticated as ${session.user.email}`);
|
|
75545
|
+
success2(`Linked to: ${session.scope.orgSlug} / ${session.scope.projectSlug} / ${session.scope.appSlug}`);
|
|
75546
|
+
} catch (err) {
|
|
75547
|
+
warn(`Authentication skipped: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
75548
|
+
}
|
|
75302
75549
|
}
|
|
75303
75550
|
}
|
|
75304
|
-
|
|
75305
|
-
|
|
75306
|
-
success2(`Initialization complete!
|
|
75551
|
+
console.log("");
|
|
75552
|
+
success2(`Initialization complete!
|
|
75307
75553
|
`);
|
|
75308
|
-
|
|
75309
|
-
|
|
75310
|
-
|
|
75311
|
-
|
|
75312
|
-
|
|
75313
|
-
|
|
75314
|
-
|
|
75315
|
-
|
|
75554
|
+
if (!isReInit) {
|
|
75555
|
+
console.log(import_picocolors5.default.bold("Next steps:"));
|
|
75556
|
+
console.log(` 1. Use the ${import_picocolors5.default.cyan("init-agent")} in your AI tool to generate ${import_picocolors5.default.cyan(`${CONFIG_DIR}/context.md`)}`);
|
|
75557
|
+
console.log(` (or use the MCP server: ${import_picocolors5.default.cyan("levante_scan_codebase")} + ${import_picocolors5.default.cyan("levante_read_agent")})`);
|
|
75558
|
+
console.log(` 2. Review the generated ${import_picocolors5.default.cyan(`${CONFIG_DIR}/context.md`)}`);
|
|
75559
|
+
console.log(` 3. Run: ${import_picocolors5.default.cyan("levante run --key PROJ-101")}`);
|
|
75560
|
+
} else {
|
|
75561
|
+
console.log(import_picocolors5.default.dim("Config and context.md were preserved. Only agents and workflow were checked."));
|
|
75562
|
+
}
|
|
75563
|
+
} catch (err) {
|
|
75564
|
+
if (err?.name === "ExitPromptError") {
|
|
75565
|
+
process.exit(0);
|
|
75566
|
+
}
|
|
75567
|
+
throw err;
|
|
75316
75568
|
}
|
|
75317
75569
|
});
|
|
75318
75570
|
}
|
|
@@ -75474,7 +75726,7 @@ async function copyWorkflowGuide(projectRoot, nonInteractive) {
|
|
|
75474
75726
|
// src/commands/auth.ts
|
|
75475
75727
|
init_dist10();
|
|
75476
75728
|
function registerAuth(program2) {
|
|
75477
|
-
registerAuthCommands(program2
|
|
75729
|
+
registerAuthCommands(program2);
|
|
75478
75730
|
}
|
|
75479
75731
|
|
|
75480
75732
|
// src/commands/jira.ts
|
|
@@ -75735,6 +75987,57 @@ function registerJira(program2) {
|
|
|
75735
75987
|
});
|
|
75736
75988
|
}
|
|
75737
75989
|
|
|
75990
|
+
// src/commands/mcp.ts
|
|
75991
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
75992
|
+
var TOOLS = [
|
|
75993
|
+
"levante_plan_workflow",
|
|
75994
|
+
"levante_execute_step",
|
|
75995
|
+
"levante_scan_codebase",
|
|
75996
|
+
"levante_validate_context",
|
|
75997
|
+
"levante_read_agent",
|
|
75998
|
+
"levante_get_example",
|
|
75999
|
+
"levante_get_workflow_guide",
|
|
76000
|
+
"levante_scan_ast",
|
|
76001
|
+
"levante_scan_ast_detail",
|
|
76002
|
+
"levante_build_qa_map",
|
|
76003
|
+
"levante_read_qa_map"
|
|
76004
|
+
];
|
|
76005
|
+
var DESKTOP_CONFIG = JSON.stringify({
|
|
76006
|
+
mcpServers: {
|
|
76007
|
+
levante: {
|
|
76008
|
+
command: "levante-mcp"
|
|
76009
|
+
}
|
|
76010
|
+
}
|
|
76011
|
+
}, null, 2);
|
|
76012
|
+
function registerMcp(program2) {
|
|
76013
|
+
program2.command("mcp").description("Show MCP server setup instructions for Claude").action(() => {
|
|
76014
|
+
console.log("");
|
|
76015
|
+
console.log(import_picocolors7.default.bold(import_picocolors7.default.cyan(" Levante MCP Server")));
|
|
76016
|
+
console.log(import_picocolors7.default.dim(" " + "─".repeat(42)));
|
|
76017
|
+
console.log("");
|
|
76018
|
+
console.log(import_picocolors7.default.bold(" Claude Code — add to project:"));
|
|
76019
|
+
console.log(import_picocolors7.default.cyan(" claude mcp add levante -- levante-mcp"));
|
|
76020
|
+
console.log("");
|
|
76021
|
+
console.log(import_picocolors7.default.bold(" Claude Code — add globally:"));
|
|
76022
|
+
console.log(import_picocolors7.default.cyan(" claude mcp add levante -s user -- levante-mcp"));
|
|
76023
|
+
console.log("");
|
|
76024
|
+
console.log(import_picocolors7.default.bold(" Claude Desktop / other clients"));
|
|
76025
|
+
console.log(import_picocolors7.default.dim(" ~/.config/claude/claude_desktop_config.json"));
|
|
76026
|
+
console.log("");
|
|
76027
|
+
const configLines = DESKTOP_CONFIG.split(`
|
|
76028
|
+
`);
|
|
76029
|
+
for (const line of configLines) {
|
|
76030
|
+
console.log(import_picocolors7.default.cyan(" " + line));
|
|
76031
|
+
}
|
|
76032
|
+
console.log("");
|
|
76033
|
+
console.log(import_picocolors7.default.bold(" Available tools:"));
|
|
76034
|
+
for (const tool of TOOLS) {
|
|
76035
|
+
console.log(import_picocolors7.default.dim(" · ") + tool);
|
|
76036
|
+
}
|
|
76037
|
+
console.log("");
|
|
76038
|
+
});
|
|
76039
|
+
}
|
|
76040
|
+
|
|
75738
76041
|
// src/cli.ts
|
|
75739
76042
|
var require2 = createRequire2(import.meta.url);
|
|
75740
76043
|
var { version: version2 } = require2("../package.json");
|
|
@@ -75759,6 +76062,7 @@ registerQa(program2);
|
|
|
75759
76062
|
registerRun(program2);
|
|
75760
76063
|
registerAuth(program2);
|
|
75761
76064
|
registerJira(program2);
|
|
76065
|
+
registerMcp(program2);
|
|
75762
76066
|
var userArgs = process.argv.slice(2);
|
|
75763
76067
|
var commandNames = program2.commands.map((c) => c.name());
|
|
75764
76068
|
var hasCommand = userArgs.some((a) => commandNames.includes(a));
|