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.
Files changed (3) hide show
  1. package/README.md +263 -83
  2. package/dist/cli.js +375 -71
  3. 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, refine, heal, and document your tests — all driven by LLM agents.
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 run individual steps
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
- ## CLI Usage
39
+ ---
44
40
 
45
- ### Global Options
41
+ ## Environment Variables
46
42
 
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
- ```
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
- ### Commands
51
+ ---
57
52
 
58
- #### `levante init`
53
+ ## Commands
59
54
 
60
- Initialize levante in your project. Creates `.qai/levante/` with config, agents, and workflow guide.
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
- #### `levante record [session]`
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
- Launch Playwright codegen with optional audio narration capture.
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
- #### `levante transcribe [session]`
83
+ | Option | Description |
84
+ |--------|-------------|
85
+ | `--no-companion` | Disable companion UI (voice recording only) |
86
+ | `--no-voice` | Disable voice recording entirely |
77
87
 
78
- Transcribe `.wav` voice recording via OpenAI Whisper.
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
- #### `levante scenario [session]`
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
- #### `levante generate [scenario]`
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
- #### `levante refine [test]`
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
- Refactor a generated test with AI — replaces raw selectors, adds best practices.
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
- #### `levante test [test]`
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/video/screenshot capture.
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
- #### `levante heal [test]`
156
+ **Output:** Test execution logs, trace files in `e2e/traces/`
117
157
 
118
- Self-heal a failing test (up to 3 retries). Diagnoses failures and patches automatically.
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
- #### `levante qa [test]`
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
- Generate QA documentation (markdown and/or Zephyr XML).
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
- #### `levante run [session]`
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>` | Skip comma-separated 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
- ## MCP Server
209
+ **Steps (in order):** `record` → `transcribe` → `scenario` → `generate` → `refine` → `test` → `heal` → `qa`
148
210
 
149
- Levante includes an MCP server for use with AI coding assistants.
211
+ ---
150
212
 
151
- ### Claude Code
213
+ ### `levante auth`
214
+
215
+ Manage authentication with QA Intelligence.
152
216
 
153
217
  ```bash
154
- claude mcp add levante -- npx levante-mcp
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
- ### Manual Configuration
224
+ ---
225
+
226
+ ### `levante jira`
227
+
228
+ Interactive Jira integration for issue discovery and workflow launch.
158
229
 
159
- Add to your MCP client config (e.g., `claude_desktop_config.json`):
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
- ### Available MCP Tools
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` | Get the full 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/config';
335
+ import { defineConfig } from 'levante';
194
336
 
195
337
  export default defineConfig({
196
- inputSource: 'jira', // 'none' | 'jira' | 'linear'
197
- outputTarget: 'both', // 'markdown' | 'zephyr' | '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', // 'openai' | 'anthropic'
202
- model: 'gpt-4o', // Override default model
203
- agentModels: { // Per-agent overrides
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
- traceMode: 'on',
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://your-api.com/qa-map',
378
+ apiUrl: 'https://qaligent.space/api',
230
379
  apiKey: 'your-key',
231
380
  },
232
381
  });
233
382
  ```
234
383
 
235
- ## Project Structure
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
- After initialization, levante creates:
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 # Configuration
243
- context.md # Project context for AI agents
244
- agents/ # Agent prompts (customizable)
245
- workflow.md # Pipeline workflow guide
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}/ # Generated test files
248
- recordings/ # Codegen + voice recordings
249
- transcripts/ # Transcription output
250
- traces/ # Playwright traces
251
- qa/ # QA documentation output
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: "Manage QA Intelligence authentication",
57188
- options: []
57362
+ description: "Authenticate with QA Intelligence — opens browser for sign-in",
57363
+ options: [],
57364
+ hideGlobalOptions: true
57189
57365
  },
57190
57366
  {
57191
- name: "jira",
57367
+ name: "auth logout",
57368
+ baseArgv: ["auth", "logout"],
57192
57369
  args: [],
57193
- description: "Browse and search Jira issues",
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__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
57459
+ return /* @__PURE__ */ jsx_dev_runtime5.jsxDEV(Box_default, {
57229
57460
  flexDirection: "column",
57230
57461
  children: [
57231
- screen === "banner" && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Banner, {
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__ */ jsx_dev_runtime4.jsxDEV(CommandBrowser, {
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__ */ jsx_dev_runtime4.jsxDEV(CommandInspect, {
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, reject2) => {
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
- const instance = render_default(/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(App2, {
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
- program2.parseAsync(argv, { from: "user" }).then(done).catch((err) => {
57269
- if (err?.name === "ExitPromptError") {
57270
- process.exit(0);
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
- reject2(err);
57273
- });
57514
+ done();
57515
+ }, 50);
57274
57516
  });
57275
57517
  },
57276
57518
  onQuit: done
57277
57519
  }, undefined, false, undefined, this));
57278
- instance.waitUntilExit().then(done);
57520
+ instance.waitUntilExit().then(() => {
57521
+ if (!runningCommand)
57522
+ done();
57523
+ });
57279
57524
  });
57280
57525
  }
57281
- var import_react26, jsx_dev_runtime4, globalOptions;
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
- jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
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
- const projectRoot = getProjectRoot();
75269
- const nonInteractive = !!cmdOpts?.nonInteractive;
75270
- header("levante init");
75271
- await migrateFromLegacy(projectRoot, nonInteractive);
75272
- const qaiDir = join17(projectRoot, CONFIG_DIR);
75273
- const configPath = join17(qaiDir, "config.ts");
75274
- const isReInit = fileExists(configPath);
75275
- if (isReInit) {
75276
- info(`Existing ${CONFIG_DIR}/ detected — preserving config and context.
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
- await copyAgentsToLocal(projectRoot, nonInteractive);
75279
- await copyWorkflowGuide(projectRoot, nonInteractive);
75280
- } else {
75281
- const answers = nonInteractive ? getDefaultAnswers() : await askConfigQuestions();
75282
- const config2 = buildConfigFromAnswers(answers);
75283
- writeFile(configPath, generateConfigFile(config2));
75284
- success2(`Config written: ${configPath}`);
75285
- await copyAgentsToLocal(projectRoot, nonInteractive);
75286
- await copyWorkflowGuide(projectRoot, nonInteractive);
75287
- }
75288
- if (!nonInteractive) {
75289
- const { confirm: confirmPrompt } = await Promise.resolve().then(() => (init_dist9(), exports_dist));
75290
- const connectAuth = await confirmPrompt({
75291
- message: "Connect to QA Intelligence?",
75292
- default: false
75293
- });
75294
- if (connectAuth) {
75295
- try {
75296
- const { login: login2 } = await Promise.resolve().then(() => (init_dist10(), exports_dist2));
75297
- const session = await login2({ webappUrl: "https://qaligent.space" });
75298
- success2(`Authenticated as ${session.user.email}`);
75299
- success2(`Linked to: ${session.scope.orgSlug} / ${session.scope.projectSlug} / ${session.scope.appSlug}`);
75300
- } catch (err) {
75301
- warn(`Authentication skipped: ${err instanceof Error ? err.message : "unknown error"}`);
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
- console.log("");
75306
- success2(`Initialization complete!
75551
+ console.log("");
75552
+ success2(`Initialization complete!
75307
75553
  `);
75308
- if (!isReInit) {
75309
- console.log(import_picocolors5.default.bold("Next steps:"));
75310
- 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`)}`);
75311
- console.log(` (or use the MCP server: ${import_picocolors5.default.cyan("levante_scan_codebase")} + ${import_picocolors5.default.cyan("levante_read_agent")})`);
75312
- console.log(` 2. Review the generated ${import_picocolors5.default.cyan(`${CONFIG_DIR}/context.md`)}`);
75313
- console.log(` 3. Run: ${import_picocolors5.default.cyan("levante run --key PROJ-101")}`);
75314
- } else {
75315
- console.log(import_picocolors5.default.dim("Config and context.md were preserved. Only agents and workflow were checked."));
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, { defaultWebappUrl: "https://app.qaligent.dev" });
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));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "levante",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "levante": "./dist/cli.js",