@qverisai/cli 0.1.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 +323 -0
- package/bin/qveris.mjs +7 -0
- package/package.json +35 -0
- package/scripts/install.sh +129 -0
- package/src/client/api.mjs +96 -0
- package/src/client/auth.mjs +26 -0
- package/src/commands/call.mjs +100 -0
- package/src/commands/completions.mjs +58 -0
- package/src/commands/config.mjs +96 -0
- package/src/commands/credits.mjs +32 -0
- package/src/commands/discover.mjs +48 -0
- package/src/commands/doctor.mjs +47 -0
- package/src/commands/history.mjs +47 -0
- package/src/commands/inspect.mjs +47 -0
- package/src/commands/interactive.mjs +171 -0
- package/src/commands/login.mjs +163 -0
- package/src/compat/aliases.mjs +30 -0
- package/src/config/defaults.mjs +16 -0
- package/src/config/resolve.mjs +32 -0
- package/src/config/store.mjs +47 -0
- package/src/errors/codes.mjs +55 -0
- package/src/errors/handler.mjs +35 -0
- package/src/main.mjs +250 -0
- package/src/output/codegen.mjs +75 -0
- package/src/output/colors.mjs +16 -0
- package/src/output/formatter.mjs +280 -0
- package/src/output/json.mjs +11 -0
- package/src/output/spinner.mjs +17 -0
- package/src/session/session.mjs +53 -0
- package/src/utils/params.mjs +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# QVeris CLI
|
|
2
|
+
|
|
3
|
+
Discover, inspect, and call 10,000+ API capabilities from your terminal.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
$ qveris discover "weather forecast API"
|
|
7
|
+
Found 5 capabilities matching your query
|
|
8
|
+
|
|
9
|
+
1. gridpoint_forecast by Weather.gov
|
|
10
|
+
weather_gov.gridpoints.forecast.retrieve.v1
|
|
11
|
+
Returns a textual forecast for a 2.5km grid area
|
|
12
|
+
relevance: 95% · success: 99.8% · latency: ~180ms · cost: 3 cr
|
|
13
|
+
|
|
14
|
+
2. current_weather by OpenWeather
|
|
15
|
+
openweathermap.weather.current.v1
|
|
16
|
+
Get current weather data for any location
|
|
17
|
+
relevance: 87% · success: 99.5% · latency: ~200ms · cost: 2 cr
|
|
18
|
+
|
|
19
|
+
$ qveris inspect 1
|
|
20
|
+
gridpoint_forecast
|
|
21
|
+
Returns a textual forecast for a 2.5km grid area
|
|
22
|
+
|
|
23
|
+
Provider: Weather.gov
|
|
24
|
+
Latency: ~180ms
|
|
25
|
+
Success: 99.8%
|
|
26
|
+
Cost: 3 credits
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
wfo string required
|
|
30
|
+
Forecast office ID
|
|
31
|
+
values: "LWX", "OKX", "LAX", ...
|
|
32
|
+
x integer required
|
|
33
|
+
Forecast grid X coordinate
|
|
34
|
+
y integer required
|
|
35
|
+
Forecast grid Y coordinate
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
{"wfo": "LWX", "x": 90, "y": 90}
|
|
39
|
+
|
|
40
|
+
$ qveris call 1 --params '{"wfo":"LWX","x":90,"y":90}'
|
|
41
|
+
✓ success · 523ms · 10 credits · (1368087.93 remaining)
|
|
42
|
+
tool: weather_gov... · id: 7ebcaf9d-...
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
"type": "Feature",
|
|
46
|
+
"properties": {
|
|
47
|
+
"periods": [
|
|
48
|
+
{ "name": "Today", "temperature": 79, "shortForecast": "Partly Sunny" },
|
|
49
|
+
...
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
**One-liner (recommended):**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl -fsSL https://qveris.ai/install | bash
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Or via npm:**
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install -g @qverisai/cli
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Or run without installing:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx @qverisai/cli discover "stock price API"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Requires Node.js 18+.
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 1. Authenticate
|
|
81
|
+
qveris login
|
|
82
|
+
|
|
83
|
+
# 2. Discover capabilities
|
|
84
|
+
qveris discover "weather forecast"
|
|
85
|
+
|
|
86
|
+
# 3. Inspect a tool (by index from discover results)
|
|
87
|
+
qveris inspect 1
|
|
88
|
+
|
|
89
|
+
# 4. Call it
|
|
90
|
+
qveris call 1 --params '{"wfo": "LWX", "x": 90, "y": 90}'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Commands
|
|
94
|
+
|
|
95
|
+
### Core
|
|
96
|
+
|
|
97
|
+
| Command | Description |
|
|
98
|
+
|---------|-------------|
|
|
99
|
+
| `qveris discover <query>` | Find capabilities by natural language. Shows tool ID, provider, description, relevance, success rate, latency, and cost for each result. |
|
|
100
|
+
| `qveris inspect <id\|index>` | View full tool details: parameters (type, required, description, enum values), example, provider info, execution history. |
|
|
101
|
+
| `qveris call <id\|index>` | Execute a capability. Shows result data, execution time, cost, and remaining credits. |
|
|
102
|
+
|
|
103
|
+
### Account
|
|
104
|
+
|
|
105
|
+
| Command | Description |
|
|
106
|
+
|---------|-------------|
|
|
107
|
+
| `qveris login` | Authenticate with API key (opens browser or `--token` for direct input) |
|
|
108
|
+
| `qveris logout` | Remove stored key |
|
|
109
|
+
| `qveris whoami` | Show current auth status and key source |
|
|
110
|
+
| `qveris credits` | Check credit balance |
|
|
111
|
+
|
|
112
|
+
### Utilities
|
|
113
|
+
|
|
114
|
+
| Command | Description |
|
|
115
|
+
|---------|-------------|
|
|
116
|
+
| `qveris interactive` | Launch REPL mode (discover/inspect/call/codegen in one session) |
|
|
117
|
+
| `qveris doctor` | Self-check: Node.js version, API key, connectivity |
|
|
118
|
+
| `qveris config <subcommand>` | Manage CLI settings (set, get, list, reset, path) |
|
|
119
|
+
| `qveris completions <shell>` | Generate shell completions (bash/zsh/fish) |
|
|
120
|
+
|
|
121
|
+
## Usage
|
|
122
|
+
|
|
123
|
+
### Discover
|
|
124
|
+
|
|
125
|
+
Search for capabilities using natural language. Each result shows the tool name, provider, tool ID, description, and quality metrics to help you choose.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
qveris discover "stock price API"
|
|
129
|
+
qveris discover "translate text" --limit 10
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Inspect
|
|
133
|
+
|
|
134
|
+
View full details of a tool before calling it. Shows parameters with types, required/optional, descriptions, allowed values (enum), and example parameters.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# By index (from last discover)
|
|
138
|
+
qveris inspect 1
|
|
139
|
+
|
|
140
|
+
# By tool ID
|
|
141
|
+
qveris inspect alphavantage.quote.execute.v1
|
|
142
|
+
|
|
143
|
+
# Inspect multiple tools
|
|
144
|
+
qveris inspect 1 2 3
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Call
|
|
148
|
+
|
|
149
|
+
Execute a tool. Results are automatically truncated for terminal display (4KB). Large results get an OSS download link.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Inline params
|
|
153
|
+
qveris call 1 --params '{"symbol": "AAPL"}'
|
|
154
|
+
|
|
155
|
+
# From file
|
|
156
|
+
qveris call 1 --params @params.json
|
|
157
|
+
|
|
158
|
+
# From stdin
|
|
159
|
+
echo '{"symbol": "AAPL"}' | qveris call 1 --params -
|
|
160
|
+
|
|
161
|
+
# Dry run (validate without executing, no credits consumed)
|
|
162
|
+
qveris call 1 --params '{"symbol": "AAPL"}' --dry-run
|
|
163
|
+
|
|
164
|
+
# Full result (no truncation)
|
|
165
|
+
qveris call 1 --params '{"symbol": "AAPL"}' --max-size -1
|
|
166
|
+
|
|
167
|
+
# Generate code snippet after call
|
|
168
|
+
qveris call 1 --params '{"symbol": "AAPL"}' --codegen curl
|
|
169
|
+
qveris call 1 --params '{"symbol": "AAPL"}' --codegen python
|
|
170
|
+
qveris call 1 --params '{"symbol": "AAPL"}' --codegen js
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Response Truncation
|
|
174
|
+
|
|
175
|
+
For terminal use, results larger than 4KB are automatically truncated. The CLI shows:
|
|
176
|
+
- A preview of the truncated content
|
|
177
|
+
- A download link (valid 120 minutes) for the full result
|
|
178
|
+
- The response schema so you know the data structure
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
✓ success · 1200ms · 5 credits
|
|
182
|
+
|
|
183
|
+
Response truncated (32KB → 4KB preview)
|
|
184
|
+
|
|
185
|
+
Full content (valid 120 min):
|
|
186
|
+
https://qveris-tool-results-cache-bj.oss-cn-beijing...
|
|
187
|
+
Download: curl -o result.json '<url>'
|
|
188
|
+
|
|
189
|
+
Schema:
|
|
190
|
+
query: string
|
|
191
|
+
total_results: number
|
|
192
|
+
articles: array of
|
|
193
|
+
pmid: string
|
|
194
|
+
title: string
|
|
195
|
+
|
|
196
|
+
Preview:
|
|
197
|
+
{"query": "evolution", "total_results": 890994, ...
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
For agent/script use (`--json` or piped output), the default increases to 20KB (matching the MCP server). Use `--max-size -1` for unlimited.
|
|
201
|
+
|
|
202
|
+
### Interactive Mode
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
$ qveris interactive
|
|
206
|
+
|
|
207
|
+
qveris> discover "weather API"
|
|
208
|
+
Found 3 capabilities matching your query
|
|
209
|
+
1. openweathermap.weather.current.v1 by OpenWeather
|
|
210
|
+
...
|
|
211
|
+
|
|
212
|
+
qveris> inspect 1
|
|
213
|
+
openweathermap.weather.current.v1
|
|
214
|
+
Parameters:
|
|
215
|
+
city string required
|
|
216
|
+
...
|
|
217
|
+
|
|
218
|
+
qveris> call 1 '{"city": "London"}'
|
|
219
|
+
✓ success · 200ms · 2 credits
|
|
220
|
+
{ "temp": 18.5, ... }
|
|
221
|
+
|
|
222
|
+
qveris> codegen curl
|
|
223
|
+
curl -sS -X POST "https://qveris.ai/api/v1/tools/execute?tool_id=..." ...
|
|
224
|
+
|
|
225
|
+
qveris> exit
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Configuration
|
|
229
|
+
|
|
230
|
+
### API Key
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# Option 1: Login (saves to ~/.config/qveris/config.json)
|
|
234
|
+
qveris login
|
|
235
|
+
|
|
236
|
+
# Option 2: Environment variable
|
|
237
|
+
export QVERIS_API_KEY="sk-1_..."
|
|
238
|
+
|
|
239
|
+
# Option 3: Per-command flag
|
|
240
|
+
qveris discover "weather" --api-key "sk-1_..."
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Resolution order:** `--api-key` flag > `QVERIS_API_KEY` env > config file
|
|
244
|
+
|
|
245
|
+
### Config File
|
|
246
|
+
|
|
247
|
+
Located at `~/.config/qveris/config.json` (respects `XDG_CONFIG_HOME`).
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
qveris config list # View all settings with sources
|
|
251
|
+
qveris config set key value # Set a value
|
|
252
|
+
qveris config get key # Get a value
|
|
253
|
+
qveris config path # Print config file location
|
|
254
|
+
qveris config reset # Reset to defaults
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Shell Completions
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Bash
|
|
261
|
+
eval "$(qveris completions bash)"
|
|
262
|
+
|
|
263
|
+
# Zsh
|
|
264
|
+
eval "$(qveris completions zsh)"
|
|
265
|
+
|
|
266
|
+
# Fish
|
|
267
|
+
qveris completions fish | source
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Global Flags
|
|
271
|
+
|
|
272
|
+
| Flag | Short | Description |
|
|
273
|
+
|------|-------|-------------|
|
|
274
|
+
| `--json` | `-j` | Output raw JSON (for piping/agent use) |
|
|
275
|
+
| `--api-key <key>` | | Override API key |
|
|
276
|
+
| `--timeout <seconds>` | | Request timeout |
|
|
277
|
+
| `--max-size <bytes>` | | Response size limit (-1 = unlimited) |
|
|
278
|
+
| `--no-color` | | Disable colors |
|
|
279
|
+
| `--version` | `-V` | Print version |
|
|
280
|
+
| `--help` | `-h` | Show help |
|
|
281
|
+
|
|
282
|
+
## Agent / LLM Integration
|
|
283
|
+
|
|
284
|
+
When used by agents or in scripts, the CLI auto-detects non-TTY environments:
|
|
285
|
+
|
|
286
|
+
| Context | `max_response_size` | Rationale |
|
|
287
|
+
|---------|---------------------|-----------|
|
|
288
|
+
| Terminal (TTY) | 4KB | Human-friendly, auto-truncate |
|
|
289
|
+
| Piped / scripted | 20KB | Agent-friendly, matches MCP server |
|
|
290
|
+
| `--json` flag | 20KB | Explicit agent mode |
|
|
291
|
+
| `--max-size N` | N | User override |
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# Agent workflow: discover → select → call → parse
|
|
295
|
+
TOOL=$(qveris discover "weather" --json | jq -r '.results[0].tool_id')
|
|
296
|
+
qveris call "$TOOL" --params '{"city":"London"}' --json | jq '.result.data'
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Exit Codes
|
|
300
|
+
|
|
301
|
+
| Code | Meaning |
|
|
302
|
+
|------|---------|
|
|
303
|
+
| 0 | Success |
|
|
304
|
+
| 2 | Usage error (bad arguments) |
|
|
305
|
+
| 69 | Service unavailable |
|
|
306
|
+
| 75 | Temporary failure (timeout, rate limit) |
|
|
307
|
+
| 77 | Auth error (invalid key, insufficient credits) |
|
|
308
|
+
| 78 | Config error (missing key) |
|
|
309
|
+
|
|
310
|
+
## Zero Dependencies
|
|
311
|
+
|
|
312
|
+
QVeris CLI uses only Node.js built-in APIs. No `chalk`, no `commander`, no `yargs`. Installs instantly via `npx`.
|
|
313
|
+
|
|
314
|
+
## Links
|
|
315
|
+
|
|
316
|
+
- Website: https://qveris.ai
|
|
317
|
+
- API Docs: https://qveris.ai/docs
|
|
318
|
+
- Get API Key: https://qveris.ai/account?page=api-keys
|
|
319
|
+
- GitHub: https://github.com/QVerisAI/QVerisAI
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
MIT
|
package/bin/qveris.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qverisai/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "QVeris CLI -- discover, inspect, and call 10,000+ capabilities",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"qveris": "./bin/qveris.mjs"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"src/",
|
|
15
|
+
"scripts/"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"qveris",
|
|
19
|
+
"cli",
|
|
20
|
+
"api",
|
|
21
|
+
"agent",
|
|
22
|
+
"capabilities",
|
|
23
|
+
"tool-calling"
|
|
24
|
+
],
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/QVerisAI/QVerisAI",
|
|
28
|
+
"directory": "packages/cli"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://qveris.ai",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# QVeris CLI Installer
|
|
3
|
+
# Usage: curl -fsSL https://qveris.ai/install | bash
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
BOLD='\033[1m'
|
|
7
|
+
GREEN='\033[32m'
|
|
8
|
+
YELLOW='\033[33m'
|
|
9
|
+
CYAN='\033[36m'
|
|
10
|
+
RED='\033[31m'
|
|
11
|
+
DIM='\033[2m'
|
|
12
|
+
RESET='\033[0m'
|
|
13
|
+
|
|
14
|
+
info() { echo -e " ${CYAN}▸${RESET} $1"; }
|
|
15
|
+
ok() { echo -e " ${GREEN}✓${RESET} $1"; }
|
|
16
|
+
warn() { echo -e " ${YELLOW}!${RESET} $1"; }
|
|
17
|
+
fail() { echo -e " ${RED}✘${RESET} $1"; exit 1; }
|
|
18
|
+
|
|
19
|
+
echo ""
|
|
20
|
+
echo -e " ${BOLD}QVeris CLI Installer${RESET}"
|
|
21
|
+
echo ""
|
|
22
|
+
|
|
23
|
+
# ── 1. Check Node.js ──────────────────────────────────────────────────
|
|
24
|
+
if ! command -v node &>/dev/null; then
|
|
25
|
+
fail "Node.js not found. Install Node.js 18+ first: ${CYAN}https://nodejs.org${RESET}"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
NODE_VERSION=$(node -v | sed 's/v//')
|
|
29
|
+
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
|
|
30
|
+
|
|
31
|
+
if [ "$NODE_MAJOR" -lt 18 ]; then
|
|
32
|
+
fail "Node.js $NODE_VERSION detected. QVeris CLI requires Node.js 18+."
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
ok "Node.js v$NODE_VERSION"
|
|
36
|
+
|
|
37
|
+
# ── 2. Check npm ──────────────────────────────────────────────────────
|
|
38
|
+
if ! command -v npm &>/dev/null; then
|
|
39
|
+
fail "npm not found. Install npm first."
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
ok "npm $(npm -v)"
|
|
43
|
+
|
|
44
|
+
# ── 3. Install @qverisai/cli globally ────────────────────────────────
|
|
45
|
+
info "Installing @qverisai/cli..."
|
|
46
|
+
|
|
47
|
+
if ! npm install -g @qverisai/cli 2>&1 | while IFS= read -r line; do
|
|
48
|
+
# suppress verbose npm output, show only errors
|
|
49
|
+
case "$line" in
|
|
50
|
+
*ERR*|*error*|*Error*) echo " $line" ;;
|
|
51
|
+
esac
|
|
52
|
+
done; then
|
|
53
|
+
# If global install fails (permissions), try with --prefix
|
|
54
|
+
warn "Global install failed, trying user-local install..."
|
|
55
|
+
NPM_DIR="${HOME}/.npm-global"
|
|
56
|
+
mkdir -p "$NPM_DIR"
|
|
57
|
+
if ! npm_output=$(npm install -g @qverisai/cli --prefix "$NPM_DIR" 2>&1); then
|
|
58
|
+
echo "$npm_output" | grep -i err
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# ── 4. Verify installation ───────────────────────────────────────────
|
|
63
|
+
# Find where qveris was installed
|
|
64
|
+
QVERIS_BIN=""
|
|
65
|
+
if command -v qveris &>/dev/null; then
|
|
66
|
+
QVERIS_BIN=$(command -v qveris)
|
|
67
|
+
else
|
|
68
|
+
# Check common locations
|
|
69
|
+
for dir in \
|
|
70
|
+
"$(npm prefix -g 2>/dev/null)/bin" \
|
|
71
|
+
"${HOME}/.npm-global/bin" \
|
|
72
|
+
"/usr/local/bin" \
|
|
73
|
+
"/opt/homebrew/bin" \
|
|
74
|
+
"${HOME}/.local/bin"; do
|
|
75
|
+
if [ -f "$dir/qveris" ]; then
|
|
76
|
+
QVERIS_BIN="$dir/qveris"
|
|
77
|
+
break
|
|
78
|
+
fi
|
|
79
|
+
done
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [ -z "$QVERIS_BIN" ]; then
|
|
83
|
+
fail "Installation succeeded but 'qveris' not found in PATH."
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# ── 5. Check if qveris is in PATH ────────────────────────────────────
|
|
87
|
+
if command -v qveris &>/dev/null; then
|
|
88
|
+
ok "qveris installed at $QVERIS_BIN"
|
|
89
|
+
else
|
|
90
|
+
# Not in PATH — add it
|
|
91
|
+
BIN_DIR=$(dirname "$QVERIS_BIN")
|
|
92
|
+
SHELL_RC=""
|
|
93
|
+
case "${SHELL:-/bin/bash}" in
|
|
94
|
+
*/zsh) SHELL_RC="$HOME/.zshrc" ;;
|
|
95
|
+
*/bash) SHELL_RC="$HOME/.bashrc" ;;
|
|
96
|
+
*/fish) SHELL_RC="$HOME/.config/fish/config.fish" ;;
|
|
97
|
+
*) SHELL_RC="$HOME/.profile" ;;
|
|
98
|
+
esac
|
|
99
|
+
|
|
100
|
+
# Add to PATH in shell rc if not already there
|
|
101
|
+
if [ -n "$SHELL_RC" ] && ! grep -Fq "$BIN_DIR" "$SHELL_RC" 2>/dev/null; then
|
|
102
|
+
echo "" >> "$SHELL_RC"
|
|
103
|
+
echo "# QVeris CLI" >> "$SHELL_RC"
|
|
104
|
+
if [[ "$SHELL_RC" == *"fish"* ]]; then
|
|
105
|
+
echo "set -gx PATH $BIN_DIR \$PATH" >> "$SHELL_RC"
|
|
106
|
+
else
|
|
107
|
+
echo "export PATH=\"$BIN_DIR:\$PATH\"" >> "$SHELL_RC"
|
|
108
|
+
fi
|
|
109
|
+
ok "Added $BIN_DIR to PATH in $SHELL_RC"
|
|
110
|
+
warn "Run ${CYAN}source $SHELL_RC${RESET} or open a new terminal to use 'qveris'"
|
|
111
|
+
fi
|
|
112
|
+
export PATH="$BIN_DIR:$PATH"
|
|
113
|
+
ok "qveris installed at $QVERIS_BIN"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# ── 6. Print version and next steps ──────────────────────────────────
|
|
117
|
+
VERSION=$(qveris --version 2>/dev/null || echo "unknown")
|
|
118
|
+
|
|
119
|
+
echo ""
|
|
120
|
+
echo -e " ${GREEN}${BOLD}QVeris CLI installed successfully!${RESET} ${DIM}($VERSION)${RESET}"
|
|
121
|
+
echo ""
|
|
122
|
+
echo -e " ${BOLD}Get started:${RESET}"
|
|
123
|
+
echo -e " ${CYAN}qveris login${RESET} Authenticate"
|
|
124
|
+
echo -e " ${CYAN}qveris discover${RESET} \"weather API\" Find capabilities"
|
|
125
|
+
echo -e " ${CYAN}qveris inspect${RESET} 1 View tool details"
|
|
126
|
+
echo -e " ${CYAN}qveris call${RESET} 1 --params '{...}' Execute a tool"
|
|
127
|
+
echo ""
|
|
128
|
+
echo -e " ${DIM}Docs: https://qveris.ai/docs${RESET}"
|
|
129
|
+
echo ""
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { resolve } from "../config/resolve.mjs";
|
|
2
|
+
import { CliError } from "../errors/handler.mjs";
|
|
3
|
+
|
|
4
|
+
function getBaseUrl(flagValue) {
|
|
5
|
+
return resolve("base_url", flagValue).value;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async function requestJson(path, { method = "POST", query = {}, body, timeoutMs = 30000, apiKey, baseUrl }) {
|
|
9
|
+
const controller = new AbortController();
|
|
10
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const url = new URL(baseUrl.replace(/\/$/, "") + path);
|
|
14
|
+
for (const [key, value] of Object.entries(query)) {
|
|
15
|
+
if (value !== undefined && value !== null) {
|
|
16
|
+
url.searchParams.set(key, String(value));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const response = await fetch(url.toString(), {
|
|
21
|
+
method,
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: `Bearer ${apiKey}`,
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
},
|
|
26
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
const status = response.status;
|
|
32
|
+
const rawText = (await response.text()).slice(0, 8192);
|
|
33
|
+
let errorDetail, jsonBody;
|
|
34
|
+
try {
|
|
35
|
+
jsonBody = JSON.parse(rawText);
|
|
36
|
+
errorDetail = jsonBody.error_message || jsonBody.message || null;
|
|
37
|
+
} catch { /* not JSON */ }
|
|
38
|
+
// For known error codes, pass errorDetail only if it's a meaningful message
|
|
39
|
+
// (not raw JSON); otherwise let the CliError template message apply
|
|
40
|
+
if (status === 401 || status === 403) throw new CliError("AUTH_INVALID_KEY", errorDetail);
|
|
41
|
+
if (status === 402) throw new CliError("CREDITS_INSUFFICIENT", errorDetail);
|
|
42
|
+
if (status === 429) throw new CliError("RATE_LIMITED", errorDetail);
|
|
43
|
+
const err = new CliError("API_ERROR", `HTTP ${status}: ${errorDetail || rawText}`);
|
|
44
|
+
if (jsonBody) err.responseData = jsonBody;
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
return await response.json();
|
|
50
|
+
} catch {
|
|
51
|
+
throw new CliError("API_ERROR", "Invalid JSON response from API");
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
if (err instanceof CliError) throw err;
|
|
55
|
+
if (err.name === "AbortError") throw new CliError("NET_TIMEOUT");
|
|
56
|
+
throw err;
|
|
57
|
+
} finally {
|
|
58
|
+
clearTimeout(timeout);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function discoverTools({ apiKey, baseUrl: baseUrlFlag, query, limit = 5, timeoutMs = 30000 }) {
|
|
63
|
+
const baseUrl = getBaseUrl(baseUrlFlag);
|
|
64
|
+
return requestJson("/search", { apiKey, baseUrl, body: { query, limit }, timeoutMs });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function inspectToolsByIds({ apiKey, baseUrl: baseUrlFlag, toolIds, discoveryId, timeoutMs = 30000 }) {
|
|
68
|
+
const baseUrl = getBaseUrl(baseUrlFlag);
|
|
69
|
+
const body = { tool_ids: toolIds };
|
|
70
|
+
if (discoveryId) body.search_id = discoveryId;
|
|
71
|
+
return requestJson("/tools/by-ids", { apiKey, baseUrl, body, timeoutMs });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function callTool({
|
|
75
|
+
apiKey,
|
|
76
|
+
baseUrl: baseUrlFlag,
|
|
77
|
+
toolId,
|
|
78
|
+
discoveryId,
|
|
79
|
+
parameters,
|
|
80
|
+
maxResponseSize = 102400,
|
|
81
|
+
timeoutMs = 120000,
|
|
82
|
+
}) {
|
|
83
|
+
const baseUrl = getBaseUrl(baseUrlFlag);
|
|
84
|
+
return requestJson("/tools/execute", {
|
|
85
|
+
apiKey,
|
|
86
|
+
baseUrl,
|
|
87
|
+
query: { tool_id: toolId },
|
|
88
|
+
body: {
|
|
89
|
+
search_id: discoveryId,
|
|
90
|
+
parameters,
|
|
91
|
+
max_response_size: maxResponseSize,
|
|
92
|
+
},
|
|
93
|
+
timeoutMs,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { resolve } from "../config/resolve.mjs";
|
|
2
|
+
import { CliError } from "../errors/handler.mjs";
|
|
3
|
+
|
|
4
|
+
const PLACEHOLDER_PATTERNS = [
|
|
5
|
+
/^your[_-]?(qveris)?[_-]?api[_-]?key/i,
|
|
6
|
+
/^sk-1_xxx/,
|
|
7
|
+
/^sk-1_$/,
|
|
8
|
+
/^YOUR_/,
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export function resolveApiKey(flagValue) {
|
|
12
|
+
const { value } = resolve("api_key", flagValue);
|
|
13
|
+
|
|
14
|
+
if (!value || !value.trim()) {
|
|
15
|
+
throw new CliError("AUTH_MISSING_KEY");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const trimmed = value.trim();
|
|
19
|
+
for (const pattern of PLACEHOLDER_PATTERNS) {
|
|
20
|
+
if (pattern.test(trimmed)) {
|
|
21
|
+
throw new CliError("AUTH_MISSING_KEY", "API key appears to be a placeholder. Set a real key.");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return trimmed;
|
|
26
|
+
}
|