@darkrishabh/bench-ai 1.0.0
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 +333 -0
- package/dist/cli/app.d.ts +11 -0
- package/dist/cli/app.d.ts.map +1 -0
- package/dist/cli/app.js +48 -0
- package/dist/cli/app.js.map +1 -0
- package/dist/cli/components/DiffView.d.ts +5 -0
- package/dist/cli/components/DiffView.d.ts.map +1 -0
- package/dist/cli/components/DiffView.js +14 -0
- package/dist/cli/components/DiffView.js.map +1 -0
- package/dist/cli/components/EvalView.d.ts +6 -0
- package/dist/cli/components/EvalView.d.ts.map +1 -0
- package/dist/cli/components/EvalView.js +82 -0
- package/dist/cli/components/EvalView.js.map +1 -0
- package/dist/cli/components/Spinner.d.ts +4 -0
- package/dist/cli/components/Spinner.d.ts.map +1 -0
- package/dist/cli/components/Spinner.js +15 -0
- package/dist/cli/components/Spinner.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +117 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/run-command.d.ts +11 -0
- package/dist/cli/run-command.d.ts.map +1 -0
- package/dist/cli/run-command.js +119 -0
- package/dist/cli/run-command.js.map +1 -0
- package/dist/engine/cost.d.ts +3 -0
- package/dist/engine/cost.d.ts.map +1 -0
- package/dist/engine/cost.js +52 -0
- package/dist/engine/cost.js.map +1 -0
- package/dist/engine/diff.d.ts +6 -0
- package/dist/engine/diff.d.ts.map +1 -0
- package/dist/engine/diff.js +43 -0
- package/dist/engine/diff.js.map +1 -0
- package/dist/engine/eval.d.ts +14 -0
- package/dist/engine/eval.d.ts.map +1 -0
- package/dist/engine/eval.js +194 -0
- package/dist/engine/eval.js.map +1 -0
- package/dist/engine/index.d.ts +15 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +10 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/providers/base.d.ts +7 -0
- package/dist/engine/providers/base.d.ts.map +1 -0
- package/dist/engine/providers/base.js +2 -0
- package/dist/engine/providers/base.js.map +1 -0
- package/dist/engine/providers/claude.d.ts +15 -0
- package/dist/engine/providers/claude.d.ts.map +1 -0
- package/dist/engine/providers/claude.js +53 -0
- package/dist/engine/providers/claude.js.map +1 -0
- package/dist/engine/providers/minimax.d.ts +16 -0
- package/dist/engine/providers/minimax.d.ts.map +1 -0
- package/dist/engine/providers/minimax.js +67 -0
- package/dist/engine/providers/minimax.js.map +1 -0
- package/dist/engine/providers/ollama.d.ts +14 -0
- package/dist/engine/providers/ollama.d.ts.map +1 -0
- package/dist/engine/providers/ollama.js +60 -0
- package/dist/engine/providers/ollama.js.map +1 -0
- package/dist/engine/providers/openai-compatible.d.ts +19 -0
- package/dist/engine/providers/openai-compatible.d.ts.map +1 -0
- package/dist/engine/providers/openai-compatible.js +109 -0
- package/dist/engine/providers/openai-compatible.js.map +1 -0
- package/dist/engine/providers/subprocess.d.ts +55 -0
- package/dist/engine/providers/subprocess.d.ts.map +1 -0
- package/dist/engine/providers/subprocess.js +111 -0
- package/dist/engine/providers/subprocess.js.map +1 -0
- package/dist/engine/suite-loader.d.ts +11 -0
- package/dist/engine/suite-loader.d.ts.map +1 -0
- package/dist/engine/suite-loader.js +75 -0
- package/dist/engine/suite-loader.js.map +1 -0
- package/dist/engine/types.d.ts +104 -0
- package/dist/engine/types.d.ts.map +1 -0
- package/dist/engine/types.js +2 -0
- package/dist/engine/types.js.map +1 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +26 -0
- package/package.json +72 -0
- package/public/icon.svg +14 -0
- package/src/app/api/diff/route.ts +135 -0
- package/src/app/api/models/route.ts +96 -0
- package/src/app/api/suite/route.ts +314 -0
- package/src/app/globals.css +215 -0
- package/src/app/icon.svg +14 -0
- package/src/app/layout.tsx +44 -0
- package/src/app/opengraph-image.tsx +73 -0
- package/src/app/page.tsx +952 -0
- package/src/app/suite/layout.tsx +12 -0
- package/src/app/suite/page.tsx +206 -0
- package/src/app/twitter-image.tsx +1 -0
- package/src/components/BenchAiLogo.tsx +38 -0
- package/src/components/ComparePanel.tsx +643 -0
- package/src/components/ConfigPanel.tsx +809 -0
- package/src/components/MarkdownOutput.tsx +16 -0
- package/src/components/ModelResponseCard.tsx +313 -0
- package/src/components/QuickComparisonBar.tsx +184 -0
- package/src/components/ResponsesLineDiff.tsx +149 -0
- package/src/components/SettingsPanel.tsx +591 -0
- package/src/components/SuitePanel.tsx +875 -0
- package/src/lib/brand.ts +4 -0
- package/src/lib/config-yaml.ts +70 -0
- package/src/lib/consume-suite-sse.ts +70 -0
- package/src/lib/describe-judge.ts +23 -0
- package/src/lib/model-chip-palette.ts +9 -0
- package/src/lib/openai-model-list.ts +33 -0
- package/src/lib/provider-ui.ts +30 -0
- package/src/lib/resolve-credentials.ts +80 -0
- package/src/lib/run-history.ts +66 -0
- package/src/lib/simple-line-diff.ts +50 -0
- package/src/lib/storage.ts +100 -0
- package/src/lib/suite-judge-meta.ts +13 -0
- package/src/lib/suite-run-history.ts +81 -0
- package/src/types.ts +170 -0
- package/vercel.json +5 -0
package/README.md
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://raw.githubusercontent.com/darkrishabh/bench-ai/master/docs/cover.png" alt="Bench AI cover" width="100%" />
|
|
4
|
+
|
|
5
|
+
<br />
|
|
6
|
+
<br />
|
|
7
|
+
|
|
8
|
+
<h1>Bench AI</h1>
|
|
9
|
+
|
|
10
|
+
<p>One prompt, many models — compare quality, speed, and cost.</p>
|
|
11
|
+
|
|
12
|
+
<br />
|
|
13
|
+
|
|
14
|
+
[](https://www.npmjs.com/package/@darkrishabh/bench-ai)
|
|
15
|
+
[](./LICENSE)
|
|
16
|
+
[](https://nodejs.org)
|
|
17
|
+
[](https://bench-ai-web.vercel.app/)
|
|
18
|
+
[](https://github.com/darkrishabh/bench-ai)
|
|
19
|
+
|
|
20
|
+
<br />
|
|
21
|
+
|
|
22
|
+
[**Live demo →**](https://bench-ai-web.vercel.app/) · [Quick start](#quick-start) · [Web UI](#web-ui) · [CLI](#cli-usage) · [Providers](#providers) · [Eval suites](#eval-suites-yaml) · [Architecture](#architecture)
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
**Bench AI** runs **one prompt against many LLMs** and lines up answers, latency, tokens, and cost in a single npm package: a **CLI** (binary **`bench-ai`**), a **Next.js web UI** (`bench-ai web`), and a **programmatic API** (`import { … } from "@darkrishabh/bench-ai"`).
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx @darkrishabh/bench-ai "Explain the CAP theorem in one paragraph" --models claude,ollama
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Works on **macOS**, **Linux**, and **Windows** with **Node.js 18+**.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Table of contents
|
|
39
|
+
|
|
40
|
+
- [Why Bench AI?](#why-bench-ai)
|
|
41
|
+
- [Features](#features)
|
|
42
|
+
- [Quick start](#quick-start)
|
|
43
|
+
- [Providers](#providers)
|
|
44
|
+
- [Configuration](#configuration)
|
|
45
|
+
- [Eval suites (YAML)](#eval-suites-yaml)
|
|
46
|
+
- [Web UI](#web-ui)
|
|
47
|
+
- [CLI usage](#cli-usage)
|
|
48
|
+
- [Architecture](#architecture)
|
|
49
|
+
- [Contributing](#contributing)
|
|
50
|
+
- [License](#license)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Why Bench AI?
|
|
55
|
+
|
|
56
|
+
Picking the right model shouldn't mean mentally mapping *which output came from where*. Bench AI keeps every model's answer and metrics in one place so you can decide with data.
|
|
57
|
+
|
|
58
|
+
> **Tip:** Use the **CLI** in CI and scripts (`--output json`). Use **`bench-ai web`** or the **hosted app** when you want a polished compare view, YAML test suites, and judge-backed rubrics — without restarting the server when you change models.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
| | |
|
|
65
|
+
|---|---|
|
|
66
|
+
| **Side-by-side compare** | Same prompt, every enabled model — outputs, errors, and metrics in one grid. |
|
|
67
|
+
| **YAML eval suites** | Prompt templates × variable matrices × assertions (`contains`, `latency`, `cost`, `llm-rubric`). |
|
|
68
|
+
| **Live suite logs** | Streamed run log in the web UI so you see each LLM and judge call as it happens. |
|
|
69
|
+
| **OpenAI model list** | With an API key, the UI loads chat models from OpenAI's `/v1/models` (plus presets & "Other"). |
|
|
70
|
+
| **Secrets & judge** | Web settings for secret variables, Anthropic/Ollama judge, and YAML import/export. |
|
|
71
|
+
| **One package** | `npx @darkrishabh/bench-ai`, `npm i -g @darkrishabh/bench-ai`, `bench-ai web`, and `import … from "@darkrishabh/bench-ai"`. |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Quick start
|
|
76
|
+
|
|
77
|
+
### CLI — zero install
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
ANTHROPIC_API_KEY=sk-... npx @darkrishabh/bench-ai "What is LoRA?"
|
|
81
|
+
|
|
82
|
+
npx @darkrishabh/bench-ai "Review this function" --file ./utils.py --models claude,ollama
|
|
83
|
+
|
|
84
|
+
# Average latency over 5 runs
|
|
85
|
+
npx @darkrishabh/bench-ai "Summarize this" --runs 5 --output json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The npm package is **scoped** as **`@darkrishabh/bench-ai`** because unscoped **`bench-ai`** is taken by another project and unscoped **`bench-ai`** is blocked as too similar. After **`npm i -g @darkrishabh/bench-ai`**, the CLI is **`bench-ai`** / **`bench-ai web`**.
|
|
89
|
+
|
|
90
|
+
### Web UI — hosted
|
|
91
|
+
|
|
92
|
+
Open [**https://bench-ai-web.vercel.app/**](https://bench-ai-web.vercel.app/). Add API keys under **Settings** in the browser; test suites live at `/suite`.
|
|
93
|
+
|
|
94
|
+
### Web UI — local dev
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git clone https://github.com/darkrishabh/bench-ai
|
|
98
|
+
cd bench-ai
|
|
99
|
+
npm install
|
|
100
|
+
npm run dev
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Then open [http://localhost:3000](http://localhost:3000) (or `3001` if 3000 is busy).
|
|
104
|
+
|
|
105
|
+
From a global or local install you can also run:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
bench-ai web
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> **Note:** Suite streaming and eval need a Node deployment (not `output: 'export'`). The suite API sets a long `maxDuration` for hosts like Vercel; very heavy runs may still need a higher limit or a long-lived server.
|
|
112
|
+
|
|
113
|
+
### Deploying on Vercel
|
|
114
|
+
|
|
115
|
+
1. **Root Directory** → `.` (repository root), or leave empty if the Vercel project is linked to this repo only.
|
|
116
|
+
2. **Build Command** → leave empty (uses root `vercel.json`: `npm run build`) or set explicitly to `npm run build`.
|
|
117
|
+
3. **Install** → default `npm install` at the repo root.
|
|
118
|
+
|
|
119
|
+
`next.config.ts` sets `outputFileTracingRoot` to the project root for correct serverless file tracing.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Providers
|
|
124
|
+
|
|
125
|
+
### Cloud APIs
|
|
126
|
+
|
|
127
|
+
| Provider | Env var | Notes |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| **Claude** | `ANTHROPIC_API_KEY` | Haiku, Sonnet, Opus |
|
|
130
|
+
| **OpenAI** | `OPENAI_API_KEY` | Full list in UI when key is set |
|
|
131
|
+
| **Groq** | `GROQ_API_KEY` | Very fast inference |
|
|
132
|
+
| **OpenRouter** | `OPENROUTER_API_KEY` | Many models, one key |
|
|
133
|
+
| **Together** | `TOGETHER_API_KEY` | Open-weight models |
|
|
134
|
+
| **NVIDIA NIM** | `NVIDIA_NIM_API_KEY` | NIM endpoints |
|
|
135
|
+
| **Perplexity** | `PERPLEXITY_API_KEY` | Search-grounded |
|
|
136
|
+
| **Minimax** | `MINIMAX_API_KEY` + `MINIMAX_GROUP_ID` | API + group ID |
|
|
137
|
+
| **Custom** | — | Any OpenAI-compatible base URL |
|
|
138
|
+
|
|
139
|
+
### Local & CLI
|
|
140
|
+
|
|
141
|
+
| Provider | Requirements |
|
|
142
|
+
|---|---|
|
|
143
|
+
| **Ollama** | [ollama.ai](https://ollama.ai) — local tags discovered via `/api/models` |
|
|
144
|
+
| **Claude CLI** | `@anthropic-ai/claude-code` on `PATH` |
|
|
145
|
+
| **Codex CLI** | `@openai/codex` on `PATH` |
|
|
146
|
+
| **LM Studio** | OpenAI-compatible server (e.g. `localhost:1234`) via **Custom** |
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Configuration
|
|
151
|
+
|
|
152
|
+
Copy `.env.example` to `.env.local` for the web app, or export vars in your shell for the CLI.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
156
|
+
OLLAMA_BASE_URL=http://localhost:11434 # optional
|
|
157
|
+
|
|
158
|
+
OPENAI_API_KEY=sk-...
|
|
159
|
+
GROQ_API_KEY=gsk_...
|
|
160
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
161
|
+
TOGETHER_API_KEY=...
|
|
162
|
+
NVIDIA_NIM_API_KEY=nvapi-...
|
|
163
|
+
PERPLEXITY_API_KEY=pplx-...
|
|
164
|
+
|
|
165
|
+
MINIMAX_API_KEY=...
|
|
166
|
+
MINIMAX_GROUP_ID=...
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Eval suites (YAML)
|
|
172
|
+
|
|
173
|
+
Define prompt templates, test rows (`vars`), and assertions: `contains`, `not-contains`, `latency`, `cost`, and `llm-rubric` (needs a judge — Claude when a key is available, or `--judge ollama` / `none`).
|
|
174
|
+
|
|
175
|
+
Full example: [`examples/bench-ai.yaml`](examples/bench-ai.yaml)
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npx @darkrishabh/bench-ai run --config examples/bench-ai.yaml --models claude,ollama,minimax
|
|
179
|
+
npx @darkrishabh/bench-ai run --config examples/bench-ai.yaml --output json --fail-on-error
|
|
180
|
+
npx @darkrishabh/bench-ai run --config examples/bench-ai.yaml --judge none
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
With a global install (`npm i -g @darkrishabh/bench-ai`), use **`bench-ai run --config …`** instead of **`npx @darkrishabh/bench-ai`**.
|
|
184
|
+
|
|
185
|
+
The web app runs the same engine at `POST /api/suite` with SSE live logs when `stream: true`.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Web UI
|
|
190
|
+
|
|
191
|
+
<div align="center">
|
|
192
|
+
<img src="https://raw.githubusercontent.com/darkrishabh/bench-ai/master/docs/screenshot.png" alt="Bench AI web UI screenshot" width="100%" />
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<br />
|
|
196
|
+
|
|
197
|
+
| Capability | Description |
|
|
198
|
+
|---|---|
|
|
199
|
+
| **Run workspace** | Prompt card, colored model chips, **+ add model**, **Run**, then **Responses / Compare & evaluate / History** |
|
|
200
|
+
| **Responses** | **Grid** (wrapping cards, 4+ models), **Side-by-side** (horizontal scroll), or **Diff** (line-level LCS between two outputs) |
|
|
201
|
+
| **Model cards** | Provider label, model ID, highlight pills (fastest / slowest / cheapest / best rated), 3-column metrics, markdown body, star rating + **Copy** |
|
|
202
|
+
| **Quick comparison** | Sticky footer mini-bars for latency, output tokens, and cost; **Full compare** jumps to the evaluate tab |
|
|
203
|
+
| **History** | Last runs stored in `localStorage`; click an entry to reload prompt + results |
|
|
204
|
+
| **Test suites** | `/suite` — YAML editor, run target banner, judge summary, live log, matrix results, recent runs (last 15, browser `localStorage`) |
|
|
205
|
+
| **Settings** | Models, secrets, judge, YAML import/export — stored in `localStorage` |
|
|
206
|
+
| **API routes** | `/api/diff`, `/api/suite`, `/api/models` (Ollama GET, OpenAI POST) |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## CLI usage
|
|
211
|
+
|
|
212
|
+
The binary name is **`bench-ai`**. Use **`npx @darkrishabh/bench-ai …`** for one-off runs, or **`npm i -g @darkrishabh/bench-ai`** and then **`bench-ai …`**.
|
|
213
|
+
|
|
214
|
+
Top-level: **`bench-ai --help`** — commands are **`diff`** (default), **`run`**, and **`web`**.
|
|
215
|
+
|
|
216
|
+
### `diff` — one prompt across providers
|
|
217
|
+
|
|
218
|
+
You can omit **`diff`**; it is the default command.
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
Usage: bench-ai diff [options] [prompt]
|
|
222
|
+
|
|
223
|
+
Arguments:
|
|
224
|
+
prompt Prompt to send to all providers
|
|
225
|
+
|
|
226
|
+
Options:
|
|
227
|
+
--file <path> Append file contents to the prompt
|
|
228
|
+
--models <list> Comma-separated providers (default: "claude,ollama")
|
|
229
|
+
--runs <n> Runs for latency averaging (default: 1)
|
|
230
|
+
--output <format> pretty | json (default: "pretty")
|
|
231
|
+
-h, --help Show help for this command
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Program options: **`-V` / `--version`**, **`-h` / `--help`** (when no subcommand).
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
bench-ai "Implement binary search in Python" --models claude,ollama
|
|
238
|
+
bench-ai diff "Hello" --models groq,claude --runs 10 --output json | jq '.results[].latencyMs'
|
|
239
|
+
bench-ai "Find bugs" --file ./server.ts
|
|
240
|
+
bench-ai "Explain recursion" --models claude-cli,codex
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### `run` — YAML eval suite
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
Usage: bench-ai run [options]
|
|
247
|
+
|
|
248
|
+
Options:
|
|
249
|
+
--config <path> Path to suite YAML (required)
|
|
250
|
+
--models <list> Comma-separated providers (default: "claude,ollama")
|
|
251
|
+
--output <format> pretty | json (default: "pretty")
|
|
252
|
+
--verbose Per-case assertion details and full prompts
|
|
253
|
+
--fail-on-error Exit 1 if any provider result fails
|
|
254
|
+
--judge <name> llm-rubric judge: auto | claude | ollama | none (default: "auto")
|
|
255
|
+
-h, --help Show help
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Use **`npx @darkrishabh/bench-ai run …`** when the CLI is not installed globally.
|
|
259
|
+
|
|
260
|
+
### `web` — local Next.js UI
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
Usage: bench-ai web [options]
|
|
264
|
+
|
|
265
|
+
Options:
|
|
266
|
+
-p, --port <port> Port to listen on (default: "3000")
|
|
267
|
+
-h, --help Show help
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Starts the Next.js dev server from the **`@darkrishabh/bench-ai`** package directory (works with **`npx @darkrishabh/bench-ai`** and global installs).
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Architecture
|
|
275
|
+
|
|
276
|
+
This repository is **one npm package at the root** (`@darkrishabh/bench-ai`): no workspaces or `packages/` split. Use **`npm install`** / **`npm run dev`** / **`npm run build`** from the clone root.
|
|
277
|
+
|
|
278
|
+
```mermaid
|
|
279
|
+
flowchart LR
|
|
280
|
+
subgraph clients [Clients]
|
|
281
|
+
CLI[CLI / Ink]
|
|
282
|
+
WEB[Next.js UI]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
subgraph pkg [npm @darkrishabh/bench-ai]
|
|
286
|
+
ENG["Engine\nrunDiff · runSuite · providers"]
|
|
287
|
+
API[API routes]
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
CLI --> ENG
|
|
291
|
+
WEB --> API
|
|
292
|
+
API --> ENG
|
|
293
|
+
ENG --> P1[Claude / Ollama / OpenAI-compat …]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Area | Role |
|
|
297
|
+
|---|---|
|
|
298
|
+
| **This repo** (npm **`@darkrishabh/bench-ai`**) | Engine (`src/engine`), CLI (`src/cli`, binary **`bench-ai`**), Next.js app (`src/app`, `src/components`, …) |
|
|
299
|
+
| **`bench-ai web`** | Runs `next dev` with cwd at the installed package root |
|
|
300
|
+
|
|
301
|
+
**Adding a provider** is on the order of tens of lines: implement `Provider` in the engine and wire it in the web API (and CLI config if needed). `OpenAICompatibleProvider` covers most REST APIs; subprocess adapters cover local CLIs.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Contributing
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
git clone https://github.com/darkrishabh/bench-ai.git
|
|
309
|
+
cd bench-ai
|
|
310
|
+
npm install
|
|
311
|
+
npm run dev # engine watch + Next dev
|
|
312
|
+
npm run build
|
|
313
|
+
npm run type-check
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
If your local `origin` still uses the old repository name:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
git remote set-url origin https://github.com/darkrishabh/bench-ai.git
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Ideas that move the needle: new providers (Gemini, Bedrock, Azure OpenAI), richer diff UX, terminal markdown, tighter CI eval stories.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## License
|
|
327
|
+
|
|
328
|
+
MIT — see [LICENSE](./LICENSE).
|
|
329
|
+
|
|
330
|
+
<div align="center">
|
|
331
|
+
<br />
|
|
332
|
+
<sub>Built by <a href="https://github.com/darkrishabh">@darkrishabh</a></sub>
|
|
333
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ProviderName, ProviderConfig } from "../engine/index.js";
|
|
2
|
+
interface AppProps {
|
|
3
|
+
prompt: string;
|
|
4
|
+
providers: ProviderName[];
|
|
5
|
+
config: ProviderConfig;
|
|
6
|
+
runs: number;
|
|
7
|
+
outputFormat: "pretty" | "json";
|
|
8
|
+
}
|
|
9
|
+
export declare function App({ prompt, providers, config, runs, outputFormat }: AppProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAc,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAInF,UAAU,QAAQ;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,QAAQ,GAAG,MAAM,CAAC;CACjC;AAED,wBAAgB,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,QAAQ,kDA2D9E"}
|
package/dist/cli/app.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Box, Text, useApp } from "ink";
|
|
4
|
+
import { runDiff, runDiffMany } from "../engine/index.js";
|
|
5
|
+
import { DiffView } from "./components/DiffView.js";
|
|
6
|
+
import { Spinner } from "./components/Spinner.js";
|
|
7
|
+
export function App({ prompt, providers, config, runs, outputFormat }) {
|
|
8
|
+
const { exit } = useApp();
|
|
9
|
+
const [loading, setLoading] = useState(true);
|
|
10
|
+
const [diffs, setDiffs] = useState([]);
|
|
11
|
+
const [error, setError] = useState(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const run = async () => {
|
|
14
|
+
try {
|
|
15
|
+
if (runs > 1) {
|
|
16
|
+
const results = await runDiffMany({ prompt, providers, config, runs });
|
|
17
|
+
setDiffs(results);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const result = await runDiff({ prompt, providers, config });
|
|
21
|
+
setDiffs([result]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
setLoading(false);
|
|
29
|
+
setTimeout(() => exit(), 50);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
run();
|
|
33
|
+
}, []);
|
|
34
|
+
if (outputFormat === "json") {
|
|
35
|
+
if (!loading) {
|
|
36
|
+
process.stdout.write(JSON.stringify(diffs, null, 2) + "\n");
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (loading) {
|
|
41
|
+
return (_jsx(Box, { children: _jsx(Spinner, { label: `Querying ${providers.join(", ")}...` }) }));
|
|
42
|
+
}
|
|
43
|
+
if (error) {
|
|
44
|
+
return _jsxs(Text, { color: "red", children: ["Error: ", error] });
|
|
45
|
+
}
|
|
46
|
+
return (_jsx(Box, { flexDirection: "column", children: diffs.map((diff, i) => (_jsxs(Box, { flexDirection: "column", children: [diffs.length > 1 && (_jsxs(Text, { bold: true, color: "yellow", children: ["\u2014 Run ", i + 1, " of ", diffs.length, " \u2014"] })), _jsx(DiffView, { diff: diff })] }, i))) }));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiffView.d.ts","sourceRoot":"","sources":["../../../src/cli/components/DiffView.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,uBAAuB,CAAC;AAoCxE,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,2CAetD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { formatCost } from "../../engine/index.js";
|
|
4
|
+
function ProviderCard({ result }) {
|
|
5
|
+
const color = result.error ? "red" : "green";
|
|
6
|
+
const latency = `${result.latencyMs}ms`;
|
|
7
|
+
const tokens = `${result.inputTokens}→${result.outputTokens} tok`;
|
|
8
|
+
const cost = formatCost(result.costUsd);
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: color, paddingX: 1, marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { bold: true, color: color, children: [result.provider.toUpperCase(), " (", result.model, ")"] }), _jsxs(Text, { dimColor: true, children: [latency, " ", tokens, " ", cost] })] }), _jsx(Box, { marginTop: 1, children: result.error ? (_jsxs(Text, { color: "red", children: ["Error: ", result.error] })) : (_jsx(Text, { wrap: "wrap", children: result.output })) })] }));
|
|
10
|
+
}
|
|
11
|
+
export function DiffView({ diff }) {
|
|
12
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Prompt: " }), _jsx(Text, { color: "cyan", wrap: "wrap", children: diff.prompt })] }), diff.results.map((r) => (_jsx(ProviderCard, { result: r }, r.provider))), _jsxs(Text, { dimColor: true, children: ["Ran at ", diff.ranAt] })] }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=DiffView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiffView.js","sourceRoot":"","sources":["../../../src/cli/components/DiffView.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,SAAS,YAAY,CAAC,EAAE,MAAM,EAA8B;IAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7C,MAAM,OAAO,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,CAAC;IACxC,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,YAAY,MAAM,CAAC;IAClE,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExC,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAC,OAAO,EACnB,WAAW,EAAE,KAAK,EAClB,QAAQ,EAAE,CAAC,EACX,YAAY,EAAE,CAAC,aAEf,MAAC,GAAG,IAAC,cAAc,EAAC,eAAe,aACjC,MAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,KAAK,aACpB,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,QAAI,MAAM,CAAC,KAAK,SACzC,EACP,MAAC,IAAI,IAAC,QAAQ,mBACX,OAAO,QAAI,MAAM,QAAI,IAAI,IACrB,IACH,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACd,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CACd,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,wBAAS,MAAM,CAAC,KAAK,IAAQ,CAC/C,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,IAAI,EAAC,MAAM,YAAE,MAAM,CAAC,MAAM,GAAQ,CACzC,GACG,IACF,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,EAAwB;IACrD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,GAAG,IAAC,YAAY,EAAE,CAAC,aAClB,KAAC,IAAI,IAAC,IAAI,+BAAgB,EAC1B,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,EAAC,MAAM,YAC3B,IAAI,CAAC,MAAM,GACP,IACH,EACL,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACvB,KAAC,YAAY,IAAkB,MAAM,EAAE,CAAC,IAArB,CAAC,CAAC,QAAQ,CAAe,CAC7C,CAAC,EACF,MAAC,IAAI,IAAC,QAAQ,8BAAS,IAAI,CAAC,KAAK,IAAQ,IACrC,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EvalView.d.ts","sourceRoot":"","sources":["../../../src/cli/components/EvalView.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAuD,MAAM,uBAAuB,CAAC;AAmO9G,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAe,EAAE,EAAE;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,2CA8B/F"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { formatCost } from "../../engine/index.js";
|
|
4
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
5
|
+
function pct(n) {
|
|
6
|
+
return `${Math.round(n * 100)}%`;
|
|
7
|
+
}
|
|
8
|
+
function bar(score, width = 12) {
|
|
9
|
+
const filled = Math.round(score * width);
|
|
10
|
+
return "█".repeat(filled) + "░".repeat(width - filled);
|
|
11
|
+
}
|
|
12
|
+
function scoreColor(score) {
|
|
13
|
+
if (score >= 0.8)
|
|
14
|
+
return "green";
|
|
15
|
+
if (score >= 0.5)
|
|
16
|
+
return "yellow";
|
|
17
|
+
return "red";
|
|
18
|
+
}
|
|
19
|
+
// ─── Summary table ────────────────────────────────────────────────────────────
|
|
20
|
+
function SummaryTable({ summary }) {
|
|
21
|
+
const colW = { provider: 20, model: 24, score: 18, pass: 10, latency: 12, cost: 10 };
|
|
22
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " Summary" }), _jsxs(Box, { children: [_jsx(Text, { bold: true, dimColor: true, children: "Provider".padEnd(colW.provider) }), _jsx(Text, { bold: true, dimColor: true, children: "Model".padEnd(colW.model) }), _jsx(Text, { bold: true, dimColor: true, children: "Score".padEnd(colW.score) }), _jsx(Text, { bold: true, dimColor: true, children: "Pass/Total".padEnd(colW.pass) }), _jsx(Text, { bold: true, dimColor: true, children: "Avg Latency".padEnd(colW.latency) }), _jsx(Text, { bold: true, dimColor: true, children: "Total Cost" })] }), _jsx(Text, { dimColor: true, children: "─".repeat(colW.provider + colW.model + colW.score + colW.pass + colW.latency + colW.cost) }), summary.map((s) => (_jsxs(Box, { children: [_jsx(Text, { children: s.provider.padEnd(colW.provider) }), _jsx(Text, { dimColor: true, children: s.model.slice(0, colW.model - 2).padEnd(colW.model) }), _jsx(Text, { color: scoreColor(s.score), children: `${bar(s.score)} ${pct(s.score)}`.padEnd(colW.score) }), _jsx(Text, { children: `${s.passed}/${s.total}`.padEnd(colW.pass) }), _jsx(Text, { dimColor: true, children: `${s.avgLatencyMs}ms`.padEnd(colW.latency) }), _jsx(Text, { dimColor: true, children: s.totalCostUsd === 0 ? "$0.00" : formatCost(s.totalCostUsd) })] }, `${s.provider}/${s.model}`)))] }));
|
|
23
|
+
}
|
|
24
|
+
// ─── Case × provider matrix (default view) ────────────────────────────────────
|
|
25
|
+
const COL_CASE = 42;
|
|
26
|
+
const COL_CELL = 11;
|
|
27
|
+
function userAssertions(pr) {
|
|
28
|
+
return pr.assertions.filter((a) => a.type !== "provider-error");
|
|
29
|
+
}
|
|
30
|
+
function MatrixCell({ pr }) {
|
|
31
|
+
const w = COL_CELL;
|
|
32
|
+
if (!pr) {
|
|
33
|
+
return (_jsx(Box, { width: w, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: "—".padStart(w - 1) }) }));
|
|
34
|
+
}
|
|
35
|
+
if (pr.error) {
|
|
36
|
+
return (_jsx(Box, { width: w, flexShrink: 0, children: _jsx(Text, { color: "red", bold: true, children: "ERR".padEnd(w - 1) }) }));
|
|
37
|
+
}
|
|
38
|
+
const ua = userAssertions(pr);
|
|
39
|
+
const suffix = ua.length > 0 ? ` ${ua.filter((a) => a.pass).length}/${ua.length}` : "";
|
|
40
|
+
const label = `${pr.pass ? "✓" : "✗"}${suffix}`.slice(0, w - 1).padEnd(w - 1);
|
|
41
|
+
return (_jsx(Box, { width: w, flexShrink: 0, children: _jsx(Text, { color: pr.pass ? "green" : "red", children: label }) }));
|
|
42
|
+
}
|
|
43
|
+
function CaseMatrix({ cases, providerOrder, }) {
|
|
44
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " Test matrix" }), _jsx(Text, { dimColor: true, children: " Rows = test cases \u00B7 Columns = providers (\u2713/\u2717, assertion pass/total)" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Box, { width: 4, flexShrink: 0, children: _jsx(Text, { bold: true, dimColor: true, children: "#".padEnd(3) }) }), _jsx(Box, { width: COL_CASE, flexShrink: 0, children: _jsx(Text, { bold: true, dimColor: true, children: "Case".padEnd(COL_CASE - 1) }) }), providerOrder.map((key) => {
|
|
45
|
+
const short = key.includes("/") ? key.split("/")[0] : key;
|
|
46
|
+
const head = short.slice(0, COL_CELL - 2).padEnd(COL_CELL - 1);
|
|
47
|
+
return (_jsx(Box, { width: COL_CELL, flexShrink: 0, children: _jsx(Text, { bold: true, dimColor: true, children: head }) }, key));
|
|
48
|
+
})] }), _jsx(Text, { dimColor: true, children: "─".repeat(4 + COL_CASE + providerOrder.length * COL_CELL) }), cases.map((c, i) => {
|
|
49
|
+
const prompt = c.prompt.length > COL_CASE - 2
|
|
50
|
+
? c.prompt.slice(0, COL_CASE - 4) + "… "
|
|
51
|
+
: c.prompt.padEnd(COL_CASE - 1);
|
|
52
|
+
return (_jsxs(Box, { children: [_jsx(Box, { width: 4, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: `${i + 1}`.padEnd(3) }) }), _jsx(Box, { width: COL_CASE, flexShrink: 0, children: _jsx(Text, { children: prompt }) }), providerOrder.map((key) => {
|
|
53
|
+
const pr = c.providerResults.find((r) => `${r.provider}/${r.model}` === key);
|
|
54
|
+
return _jsx(MatrixCell, { pr: pr }, key);
|
|
55
|
+
})] }, i));
|
|
56
|
+
})] }));
|
|
57
|
+
}
|
|
58
|
+
// ─── Per-case rows ────────────────────────────────────────────────────────────
|
|
59
|
+
function CaseRow({ c, idx, providerOrder }) {
|
|
60
|
+
const prompt = c.prompt.length > 60 ? c.prompt.slice(0, 57) + "…" : c.prompt;
|
|
61
|
+
const varStr = Object.entries(c.vars).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
62
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { bold: true, color: "cyan", children: ["#", idx + 1, " "] }), _jsx(Text, { wrap: "truncate-end", children: prompt }), varStr && _jsxs(Text, { dimColor: true, children: [" (", varStr, ")"] })] }), providerOrder.map((key) => {
|
|
63
|
+
const pr = c.providerResults.find((r) => `${r.provider}/${r.model}` === key);
|
|
64
|
+
if (!pr)
|
|
65
|
+
return null;
|
|
66
|
+
const icon = pr.error ? "✗" : pr.pass ? "✓" : "✗";
|
|
67
|
+
const color = pr.error ? "red" : pr.pass ? "green" : "red";
|
|
68
|
+
const label = `${pr.provider}/${pr.model}`;
|
|
69
|
+
return (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: color, children: icon }), _jsx(Text, { dimColor: true, children: label.slice(0, 36).padEnd(36) }), !pr.error && (_jsxs(Text, { dimColor: true, children: [pr.latencyMs, "ms"] }))] }), pr.assertions
|
|
70
|
+
.filter((a) => !(pr.error && a.type === "provider-error"))
|
|
71
|
+
.map((a, i) => a.type === "llm-rubric" ? (_jsxs(Box, { marginLeft: 4, flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsxs(Text, { bold: true, color: "magenta", children: ["[", a.type, "]"] }), _jsx(Text, { bold: true, color: a.pass ? "green" : "red", children: a.pass ? "Pass" : "Fail" })] }), a.rubricCriterion ? (_jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Rubric:" }), _jsx(Text, { wrap: "wrap", children: a.rubricCriterion })] })) : null, _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: [a.pass ? "Why it passed" : "Why it failed", ":"] }), _jsx(Text, { wrap: "wrap", children: a.reason ?? "—" })] })] }, i)) : (_jsxs(Box, { marginLeft: 4, children: [_jsxs(Text, { color: a.pass ? "green" : "red", children: [a.pass ? "✓" : "✗", " "] }), _jsxs(Text, { dimColor: true, children: ["[", a.type, "]"] }), a.reason && _jsxs(Text, { dimColor: true, children: [" \u2014 ", a.reason] })] }, i))), pr.error && (_jsx(Box, { marginLeft: 4, children: _jsxs(Text, { color: "red", children: ["Error: ", pr.error] }) }))] }, key));
|
|
72
|
+
})] }));
|
|
73
|
+
}
|
|
74
|
+
// ─── Main component ───────────────────────────────────────────────────────────
|
|
75
|
+
export function EvalView({ result, verbose = false }) {
|
|
76
|
+
const providerOrder = result.summary.map((s) => `${s.provider}/${s.model}`);
|
|
77
|
+
const allPassed = result.summary.every((s) => s.failed === 0);
|
|
78
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: allPassed ? "green" : "red", children: allPassed
|
|
79
|
+
? "✓ All test results passed"
|
|
80
|
+
: `✗ ${result.summary.reduce((acc, s) => acc + s.failed, 0)} failed (provider × case)` }), _jsxs(Text, { dimColor: true, children: [" (", result.cases.length, " test case", result.cases.length !== 1 ? "s" : "", ", ", result.summary.length, " provider", result.summary.length !== 1 ? "s" : "", ")"] })] }), _jsx(SummaryTable, { summary: result.summary }), _jsx(CaseMatrix, { cases: result.cases, providerOrder: providerOrder }), verbose && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "cyan", children: " Details" }), _jsx(Text, { dimColor: true, children: "─".repeat(80) }), result.cases.map((c, i) => (_jsx(CaseRow, { c: c, idx: i, providerOrder: providerOrder }, i)))] }))] }));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=EvalView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EvalView.js","sourceRoot":"","sources":["../../../src/cli/components/EvalView.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,iFAAiF;AAEjF,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;AACnC,CAAC;AAED,SAAS,GAAG,CAAC,KAAa,EAAE,KAAK,GAAG,EAAE;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;IACzC,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,IAAI,GAAG;QAAE,OAAO,OAAO,CAAC;IACjC,IAAI,KAAK,IAAI,GAAG;QAAE,OAAO,QAAQ,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iFAAiF;AAEjF,SAAS,YAAY,CAAC,EAAE,OAAO,EAAkC;IAC/D,MAAM,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAErF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACzC,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,yBAAgB,EACvC,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAQ,EAC7D,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAQ,EACvD,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAQ,EACvD,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAAE,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAQ,EAC3D,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAQ,EAC/D,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAAE,YAAY,GAAQ,IACrC,EACN,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAQ,EACjH,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,MAAC,GAAG,eACF,KAAC,IAAI,cAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAQ,EAC/C,KAAC,IAAI,IAAC,QAAQ,kBAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAQ,EAC3E,KAAC,IAAI,IAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,YAC7B,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAChD,EACP,KAAC,IAAI,cAAE,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAQ,EACzD,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAQ,EAClE,KAAC,IAAI,IAAC,QAAQ,kBAAE,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,GAAQ,KAR3E,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EAAE,CAS9B,CACP,CAAC,IACE,CACP,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,SAAS,cAAc,CAAC,EAAsB;IAC5C,OAAO,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,EAAE,EAA0C;IAChE,MAAM,CAAC,GAAG,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,CACL,KAAC,GAAG,IAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YAC1B,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,GAAQ,GACvC,CACP,CAAC;IACJ,CAAC;IACD,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,CACL,KAAC,GAAG,IAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YAC1B,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,EAAC,IAAI,kBACnB,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GACf,GACH,CACP,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,MAAM,GACV,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9E,OAAO,CACL,KAAC,GAAG,IAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YAC1B,KAAC,IAAI,IAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,YAAG,KAAK,GAAQ,GAClD,CACP,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,KAAK,EACL,aAAa,GAId;IACC,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACzC,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,6BAAoB,EAC3C,KAAC,IAAI,IAAC,QAAQ,0GAA4E,EAC1F,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,GAAG,IAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YAC1B,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAChB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GACT,GACH,EACN,KAAC,GAAG,IAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,YACjC,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAChB,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,GACvB,GACH,EACL,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;wBACzB,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,GAAG,CAAC;wBAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;wBAC/D,OAAO,CACL,KAAC,GAAG,IAAW,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,YAC3C,KAAC,IAAI,IAAC,IAAI,QAAC,QAAQ,kBAChB,IAAI,GACA,IAHC,GAAG,CAIP,CACP,CAAC;oBACJ,CAAC,CAAC,IACE,EACN,KAAC,IAAI,IAAC,QAAQ,kBACX,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,GAAG,aAAa,CAAC,MAAM,GAAG,QAAQ,CAAC,GACtD,EACN,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBAClB,MAAM,MAAM,GACV,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,GAAG,CAAC;oBAC5B,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI;oBACxC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;gBACpC,OAAO,CACL,MAAC,GAAG,eACF,KAAC,GAAG,IAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,YAC1B,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAQ,GACxC,EACN,KAAC,GAAG,IAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,YACjC,KAAC,IAAI,cAAE,MAAM,GAAQ,GACjB,EACL,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;4BACzB,MAAM,EAAE,GAAG,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;4BAC7E,OAAO,KAAC,UAAU,IAAW,EAAE,EAAE,EAAE,IAAX,GAAG,CAAY,CAAC;wBAC1C,CAAC,CAAC,KAVM,CAAC,CAWL,CACP,CAAC;YACJ,CAAC,CAAC,IACE,CACP,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,SAAS,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,EAA+D;IACrG,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7E,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE9E,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACzC,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,kBAAG,GAAG,GAAG,CAAC,SAAS,EAC1C,KAAC,IAAI,IAAC,IAAI,EAAC,cAAc,YAAE,MAAM,GAAQ,EACxC,MAAM,IAAI,MAAC,IAAI,IAAC,QAAQ,yBAAI,MAAM,SAAS,IACxC,EACL,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;gBACzB,MAAM,EAAE,GAAG,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;gBAC7E,IAAI,CAAC,EAAE;oBAAE,OAAO,IAAI,CAAC;gBACrB,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gBAClD,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;gBAC3D,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;gBAE3C,OAAO,CACL,MAAC,GAAG,IAAW,UAAU,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aAClD,MAAC,GAAG,IAAC,GAAG,EAAE,CAAC,aACT,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,IAAI,GAAQ,EACjC,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,EACpD,CAAC,EAAE,CAAC,KAAK,IAAI,CACZ,MAAC,IAAI,IAAC,QAAQ,mBAAE,EAAE,CAAC,SAAS,UAAU,CACvC,IACG,EACL,EAAE,CAAC,UAAU;6BACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;6BACzD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACZ,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,CACxB,MAAC,GAAG,IAAS,UAAU,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aAChE,MAAC,GAAG,IAAC,aAAa,EAAC,KAAK,EAAC,GAAG,EAAE,CAAC,aAC7B,MAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,kBACtB,CAAC,CAAC,IAAI,SACH,EACP,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,YACvC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GACpB,IACH,EACL,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CACnB,MAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACxC,KAAC,IAAI,IAAC,QAAQ,8BAAe,EAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,MAAM,YAAE,CAAC,CAAC,eAAe,GAAQ,IACxC,CACP,CAAC,CAAC,CAAC,IAAI,EACR,MAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACxC,MAAC,IAAI,IAAC,QAAQ,mBAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,SAAS,EACnE,KAAC,IAAI,IAAC,IAAI,EAAC,MAAM,YAAE,CAAC,CAAC,MAAM,IAAI,GAAG,GAAQ,IACtC,KAlBE,CAAC,CAmBL,CACP,CAAC,CAAC,CAAC,CACF,MAAC,GAAG,IAAS,UAAU,EAAE,CAAC,aACxB,MAAC,IAAI,IAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,aAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,EACnE,MAAC,IAAI,IAAC,QAAQ,wBAAG,CAAC,CAAC,IAAI,SAAS,EAC/B,CAAC,CAAC,MAAM,IAAI,MAAC,IAAI,IAAC,QAAQ,+BAAK,CAAC,CAAC,MAAM,IAAQ,KAHxC,CAAC,CAIL,CACP,CACJ,EACA,EAAE,CAAC,KAAK,IAAI,CACX,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,YAChB,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,wBAAS,EAAE,CAAC,KAAK,IAAQ,GACtC,CACP,KA5CO,GAAG,CA6CP,CACP,CAAC;YACJ,CAAC,CAAC,IACE,CACP,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,KAAK,EAA8C;IAC9F,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5E,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IAE9D,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,GAAG,IAAC,YAAY,EAAE,CAAC,aAClB,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,YAC1C,SAAS;4BACR,CAAC,CAAC,2BAA2B;4BAC7B,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,2BAA2B,GACnF,EACP,MAAC,IAAI,IAAC,QAAQ,0BAAK,MAAM,CAAC,KAAK,CAAC,MAAM,gBAAY,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAI,MAAM,CAAC,OAAO,CAAC,MAAM,eAAW,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,IACrK,EAEN,KAAC,YAAY,IAAC,OAAO,EAAE,MAAM,CAAC,OAAO,GAAI,EAEzC,KAAC,UAAU,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,aAAa,GAAI,EAEhE,OAAO,IAAI,CACV,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,yBAAgB,EACvC,KAAC,IAAI,IAAC,QAAQ,kBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,EACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAC1B,KAAC,OAAO,IAAS,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,aAAa,EAAE,aAAa,IAA7C,CAAC,CAAgD,CAChE,CAAC,IACE,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../../src/cli/components/Spinner.tsx"],"names":[],"mappings":"AAKA,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,2CAgBnD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Text } from "ink";
|
|
4
|
+
const FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
5
|
+
export function Spinner({ label }) {
|
|
6
|
+
const [frame, setFrame] = useState(0);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const id = setInterval(() => {
|
|
9
|
+
setFrame((f) => (f + 1) % FRAMES.length);
|
|
10
|
+
}, 80);
|
|
11
|
+
return () => clearInterval(id);
|
|
12
|
+
}, []);
|
|
13
|
+
return (_jsxs(Text, { children: [_jsxs(Text, { color: "cyan", children: [FRAMES[frame], " "] }), label] }));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=Spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../../src/cli/components/Spinner.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAElE,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAqB;IAClD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE;YAC1B,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,MAAC,IAAI,eACH,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,aAAE,MAAM,CAAC,KAAK,CAAC,SAAS,EACzC,KAAK,IACD,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|