@orth/cli 0.2.28 → 0.2.30
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/LICENSE +21 -0
- package/README.md +182 -117
- package/dist/api.js +15 -0
- package/dist/commands/run.js +97 -2
- package/dist/index.js +0 -0
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Orthogonal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,204 +1,269 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# Orthogonal CLI
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
**One command line for every API and agent skill on the [Orthogonal](https://orthogonal.com) platform.**
|
|
6
|
+
|
|
7
|
+
Discover APIs in natural language, call them with a single command, and pay per request from your Orthogonal credit balance — no per-provider signups, keys, or contracts.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/@orth/cli)
|
|
10
|
+
[](https://www.npmjs.com/package/@orth/cli)
|
|
11
|
+
[](https://nodejs.org)
|
|
12
|
+
[](./LICENSE)
|
|
4
13
|
|
|
5
14
|

|
|
6
15
|
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
## Table of Contents
|
|
19
|
+
|
|
20
|
+
- [Why Orthogonal](#why-orthogonal)
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Quick Start](#quick-start)
|
|
23
|
+
- [Authentication](#authentication)
|
|
24
|
+
- [Calling APIs](#calling-apis)
|
|
25
|
+
- [Agent Skills](#agent-skills)
|
|
26
|
+
- [Scheduled Tasks](#scheduled-tasks)
|
|
27
|
+
- [Account & Usage](#account--usage)
|
|
28
|
+
- [Command Reference](#command-reference)
|
|
29
|
+
- [Configuration](#configuration)
|
|
30
|
+
- [Programmatic Use](#programmatic-use)
|
|
31
|
+
- [Development](#development)
|
|
32
|
+
- [License](#license)
|
|
33
|
+
|
|
34
|
+
## Why Orthogonal
|
|
35
|
+
|
|
36
|
+
Orthogonal is a marketplace of production APIs and agent skills behind one account and one balance. The CLI lets you — and your AI agents — find and call any of them without leaving the terminal:
|
|
37
|
+
|
|
38
|
+
- **Discover** APIs and skills with natural-language search.
|
|
39
|
+
- **Call** any endpoint with one command — auth, billing, and routing are handled for you.
|
|
40
|
+
- **Pay per use** from a single credit balance instead of juggling dozens of provider subscriptions.
|
|
41
|
+
- **Script it** — clean JSON output (`--raw`) pipes straight into `jq` and shell pipelines.
|
|
42
|
+
|
|
7
43
|
## Installation
|
|
8
44
|
|
|
45
|
+
Requires **Node.js 18+**.
|
|
46
|
+
|
|
9
47
|
```bash
|
|
10
48
|
# Install globally
|
|
11
49
|
npm install -g @orth/cli
|
|
12
50
|
|
|
13
|
-
#
|
|
51
|
+
# …or run without installing
|
|
14
52
|
npx @orth/cli <command>
|
|
15
53
|
```
|
|
16
54
|
|
|
55
|
+
Verify the install:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
orth --version
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 1. Authenticate (get a key at https://orthogonal.com)
|
|
65
|
+
orth login --key orth_live_your_key
|
|
66
|
+
|
|
67
|
+
# 2. Find an API in plain English
|
|
68
|
+
orth api search "search the web"
|
|
69
|
+
|
|
70
|
+
# 3. Call an endpoint
|
|
71
|
+
orth run tavily /search -q query="latest AI news"
|
|
72
|
+
|
|
73
|
+
# 4. See what it cost
|
|
74
|
+
orth balance
|
|
75
|
+
```
|
|
76
|
+
|
|
17
77
|
## Authentication
|
|
18
78
|
|
|
19
79
|
```bash
|
|
20
|
-
#
|
|
80
|
+
# Log in with your API key (stored in your OS user-config directory)
|
|
21
81
|
orth login --key orth_live_your_key
|
|
22
82
|
|
|
23
|
-
#
|
|
83
|
+
# …or use an environment variable (takes precedence — great for CI)
|
|
24
84
|
export ORTHOGONAL_API_KEY=orth_live_your_key
|
|
25
85
|
|
|
26
|
-
#
|
|
86
|
+
# Show the current identity
|
|
27
87
|
orth whoami
|
|
28
88
|
|
|
29
|
-
#
|
|
89
|
+
# Remove the stored key
|
|
30
90
|
orth logout
|
|
31
91
|
```
|
|
32
92
|
|
|
33
|
-
|
|
93
|
+
Get an API key from your [Orthogonal dashboard](https://orthogonal.com/dashboard).
|
|
34
94
|
|
|
35
|
-
|
|
95
|
+
## Calling APIs
|
|
96
|
+
|
|
97
|
+
### Discover & inspect
|
|
36
98
|
|
|
37
99
|
```bash
|
|
38
|
-
#
|
|
39
|
-
orth api search "
|
|
40
|
-
orth api search "web scraping" --limit 20
|
|
100
|
+
# Natural-language search across the marketplace
|
|
101
|
+
orth api search "generate images"
|
|
41
102
|
|
|
42
|
-
# List
|
|
103
|
+
# List every available API
|
|
43
104
|
orth api list
|
|
44
105
|
|
|
45
|
-
# Show API endpoints
|
|
46
|
-
orth api show
|
|
106
|
+
# Show an API's endpoints
|
|
107
|
+
orth api show tavily
|
|
47
108
|
|
|
48
|
-
# Show endpoint
|
|
49
|
-
orth api show
|
|
109
|
+
# Show one endpoint's parameters, pricing, and schema
|
|
110
|
+
orth api show tavily /search
|
|
50
111
|
```
|
|
51
112
|
|
|
52
|
-
### Call
|
|
113
|
+
### Call an endpoint
|
|
53
114
|
|
|
54
115
|
```bash
|
|
55
|
-
# GET
|
|
56
|
-
orth run
|
|
57
|
-
|
|
58
|
-
# Multiple query params (two ways)
|
|
59
|
-
orth run searchapi /api/v1/search -q 'engine=amazon_search&q=wireless earbuds'
|
|
60
|
-
orth run searchapi /api/v1/search -q engine=amazon_search -q q=wireless earbuds
|
|
61
|
-
|
|
62
|
-
# POST request with body
|
|
63
|
-
orth run olostep /v1/scrapes -d '{"url": "https://stripe.com"}'
|
|
116
|
+
# GET with query params
|
|
117
|
+
orth run fantastic-jobs /v1/active-ats -q time_frame=1h -q limit=10
|
|
64
118
|
|
|
65
|
-
#
|
|
66
|
-
orth run
|
|
67
|
-
```
|
|
119
|
+
# Query params can also be passed as a single string
|
|
120
|
+
orth run fantastic-jobs /v1/active-ats -q "time_frame=1h&limit=10"
|
|
68
121
|
|
|
69
|
-
|
|
122
|
+
# POST with a JSON body
|
|
123
|
+
orth run some-api /v1/generate -X POST -b '{"prompt":"a red bicycle"}'
|
|
70
124
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
orth api code hunter /v2/domain-search
|
|
125
|
+
# Estimate the cost without spending credits
|
|
126
|
+
orth run some-api /v1/generate --dry-run
|
|
74
127
|
|
|
75
|
-
#
|
|
76
|
-
orth api
|
|
128
|
+
# Save a binary response (image, audio, PDF, …) to a file
|
|
129
|
+
orth run image-api /v1/render -q prompt="sunset" -o out.png
|
|
77
130
|
|
|
78
|
-
#
|
|
79
|
-
orth
|
|
131
|
+
# Machine-readable output for pipelines
|
|
132
|
+
orth run tavily /search -q query="orthogonal" --raw | jq '.results[0].url'
|
|
80
133
|
```
|
|
81
134
|
|
|
82
|
-
###
|
|
135
|
+
### Generate integration code
|
|
136
|
+
|
|
137
|
+
Scaffold a ready-to-run snippet for any endpoint:
|
|
83
138
|
|
|
84
139
|
```bash
|
|
85
|
-
|
|
86
|
-
orth api
|
|
140
|
+
orth api code tavily /search # TypeScript (default)
|
|
141
|
+
orth api code tavily /search --lang python # Python
|
|
142
|
+
orth api code tavily /search --lang curl # cURL
|
|
87
143
|
```
|
|
88
144
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
### Browse & Search
|
|
145
|
+
### Request a new API
|
|
92
146
|
|
|
93
147
|
```bash
|
|
94
|
-
|
|
95
|
-
orth skills list
|
|
96
|
-
|
|
97
|
-
# Search for skills
|
|
98
|
-
orth skills search "react best practices"
|
|
99
|
-
|
|
100
|
-
# Show skill details
|
|
101
|
-
orth skills show owner/skill-name
|
|
148
|
+
orth api request https://docs.example.com/api
|
|
102
149
|
```
|
|
103
150
|
|
|
104
|
-
|
|
151
|
+
## Agent Skills
|
|
105
152
|
|
|
106
|
-
|
|
107
|
-
# Install a skill to all supported agents
|
|
108
|
-
orth skills add owner/skill-name
|
|
153
|
+
Skills are packaged capabilities your AI agents can install and run. Browse the library, publish your own, and sync them to your local agent directories.
|
|
109
154
|
|
|
110
|
-
|
|
111
|
-
|
|
155
|
+
```bash
|
|
156
|
+
# Browse & search
|
|
157
|
+
orth skills list # verified, discoverable skills
|
|
158
|
+
orth skills search "web scraping"
|
|
159
|
+
orth skills show <slug> # details + files
|
|
160
|
+
|
|
161
|
+
# Install into your local agent skill directories
|
|
162
|
+
orth skills add <slug> # alias: orth skills install <slug>
|
|
163
|
+
|
|
164
|
+
# Author & publish
|
|
165
|
+
orth skills init [name] # scaffold a SKILL.md template
|
|
166
|
+
orth skills create <owner/repo> # create a skill from a GitHub repo
|
|
167
|
+
orth skills submit [path] # submit a local skill
|
|
168
|
+
orth skills push <slug> [path] # push local changes to the platform
|
|
169
|
+
orth skills update <slug> [path] # pull the latest version locally
|
|
170
|
+
orth skills mine # list your skills
|
|
171
|
+
orth skills request-verification <slug>
|
|
172
|
+
orth skills request <input> # request a skill by URL or description
|
|
112
173
|
```
|
|
113
174
|
|
|
114
|
-
|
|
175
|
+
**Verification workflow:** to make a skill discoverable to others, go `init`/`create` → `submit` → `request-verification`. Once approved, it becomes discoverable in the library.
|
|
115
176
|
|
|
116
|
-
|
|
117
|
-
|-------|-----------|
|
|
118
|
-
| Cursor | `~/.cursor/skills/` |
|
|
119
|
-
| Claude Code | `~/.claude/skills/` |
|
|
120
|
-
| GitHub Copilot | `~/.github/skills/` |
|
|
121
|
-
| Windsurf | `~/.codeium/windsurf/skills/` |
|
|
122
|
-
| Codex | `~/.agents/skills/` |
|
|
123
|
-
| Gemini | `~/.gemini/skills/` |
|
|
124
|
-
| OpenClaw | `~/.openclaw/skills/` |
|
|
177
|
+
## Scheduled Tasks
|
|
125
178
|
|
|
126
|
-
|
|
179
|
+
Run API calls and skills on a schedule.
|
|
127
180
|
|
|
128
181
|
```bash
|
|
129
|
-
|
|
130
|
-
orth
|
|
131
|
-
orth
|
|
182
|
+
orth tasks list # your scheduled tasks
|
|
183
|
+
orth tasks create # create a task
|
|
184
|
+
orth tasks show <id> # task details
|
|
185
|
+
orth tasks trigger <id> # run it now
|
|
186
|
+
orth tasks logs <id> # run history
|
|
187
|
+
orth tasks pause <id> # pause
|
|
188
|
+
orth tasks resume <id> # resume
|
|
189
|
+
orth tasks delete <id> # delete
|
|
190
|
+
```
|
|
132
191
|
|
|
133
|
-
|
|
134
|
-
orth skills create https://github.com/owner/repo
|
|
135
|
-
orth skills create owner/repo --path skills/my-skill --ref main
|
|
192
|
+
## Account & Usage
|
|
136
193
|
|
|
137
|
-
|
|
138
|
-
orth
|
|
139
|
-
orth
|
|
194
|
+
```bash
|
|
195
|
+
orth balance # current credit balance
|
|
196
|
+
orth usage # recent API usage
|
|
197
|
+
```
|
|
140
198
|
|
|
141
|
-
|
|
142
|
-
orth skills update owner/my-skill
|
|
143
|
-
orth skills update owner/my-skill ./local-dir --force
|
|
199
|
+
## Command Reference
|
|
144
200
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
orth
|
|
201
|
+
| Command | Description |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| `orth login` / `logout` / `whoami` | Manage authentication |
|
|
204
|
+
| `orth balance` / `usage` | Credit balance and recent usage |
|
|
205
|
+
| `orth api list` | List available APIs |
|
|
206
|
+
| `orth api search <query>` | Natural-language API search |
|
|
207
|
+
| `orth api show <slug> [path]` | Show endpoints / endpoint details (alias: `info`) |
|
|
208
|
+
| `orth api run <slug> <path>` | Call an endpoint |
|
|
209
|
+
| `orth api code <slug> <path>` | Generate integration code |
|
|
210
|
+
| `orth api request <docsUrl>` | Request an API to be added |
|
|
211
|
+
| `orth skills …` | Browse, install, author, and publish skills |
|
|
212
|
+
| `orth tasks …` | Create and manage scheduled tasks |
|
|
148
213
|
|
|
149
|
-
|
|
150
|
-
orth skills request-verification owner/my-skill
|
|
214
|
+
**Shorthand aliases** for the most common commands:
|
|
151
215
|
|
|
152
|
-
|
|
153
|
-
orth
|
|
154
|
-
orth
|
|
216
|
+
```bash
|
|
217
|
+
orth search <query> # → orth api search
|
|
218
|
+
orth run <slug> <path> # → orth api run
|
|
219
|
+
orth code <slug> <path> # → orth api code
|
|
155
220
|
```
|
|
156
221
|
|
|
157
|
-
|
|
222
|
+
Run `orth <command> --help` for the full options on any command.
|
|
158
223
|
|
|
159
|
-
|
|
160
|
-
2. **Request verification** → our team reviews it
|
|
161
|
-
3. **Once verified** → toggle discoverability on/off from your [dashboard](https://orthogonal.com/dashboard/skills)
|
|
224
|
+
### `run` options
|
|
162
225
|
|
|
163
|
-
|
|
226
|
+
| Flag | Description |
|
|
227
|
+
| --- | --- |
|
|
228
|
+
| `-X, --method <method>` | HTTP method (default `GET`) |
|
|
229
|
+
| `-q, --query <k=v...>` | Query params (repeatable, or one `a=1&b=2` string) |
|
|
230
|
+
| `-b, --body <json>` / `-d, --data <json>` | JSON request body |
|
|
231
|
+
| `-o, --output <file>` | Save the response to a file (auto-detects binary) |
|
|
232
|
+
| `--raw` | Print raw JSON (ideal for piping) |
|
|
233
|
+
| `--dry-run` | Estimate the cost without executing |
|
|
164
234
|
|
|
165
|
-
|
|
166
|
-
# Check balance
|
|
167
|
-
orth balance
|
|
235
|
+
## Configuration
|
|
168
236
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
237
|
+
| Environment variable | Purpose |
|
|
238
|
+
| --- | --- |
|
|
239
|
+
| `ORTHOGONAL_API_KEY` | API key; overrides the stored credential (use in CI) |
|
|
240
|
+
| `ORTH_API_URL` | Override the API base URL (advanced) |
|
|
172
241
|
|
|
173
|
-
|
|
242
|
+
Credentials from `orth login` are stored in your OS user-config directory (managed automatically); use `orth logout` to remove them.
|
|
174
243
|
|
|
175
|
-
|
|
244
|
+
## Programmatic Use
|
|
245
|
+
|
|
246
|
+
Building an application instead of scripting the terminal? Use the official TypeScript SDK, [`@orth/sdk`](https://www.npmjs.com/package/@orth/sdk):
|
|
176
247
|
|
|
177
248
|
```bash
|
|
178
|
-
|
|
179
|
-
orth run slug /path # → orth api run slug /path
|
|
180
|
-
orth code slug /path # → orth api code slug /path
|
|
249
|
+
npm install @orth/sdk
|
|
181
250
|
```
|
|
182
251
|
|
|
183
252
|
## Development
|
|
184
253
|
|
|
185
254
|
```bash
|
|
186
|
-
|
|
255
|
+
git clone https://github.com/orthogonal-sh/cli.git
|
|
256
|
+
cd cli
|
|
187
257
|
npm install
|
|
188
258
|
|
|
189
|
-
#
|
|
190
|
-
npm run
|
|
191
|
-
|
|
192
|
-
#
|
|
193
|
-
npm run dev
|
|
194
|
-
|
|
195
|
-
# Run tests
|
|
196
|
-
npm test
|
|
197
|
-
|
|
198
|
-
# Watch tests
|
|
199
|
-
npm run test:watch
|
|
259
|
+
npm run build # compile TypeScript to dist/
|
|
260
|
+
npm run dev # compile in watch mode
|
|
261
|
+
npm test # run the test suite (vitest)
|
|
262
|
+
npm start # run the built CLI
|
|
200
263
|
```
|
|
201
264
|
|
|
265
|
+
Contributions are welcome — please open an issue or a pull request.
|
|
266
|
+
|
|
202
267
|
## License
|
|
203
268
|
|
|
204
|
-
MIT
|
|
269
|
+
[MIT](./LICENSE) © Orthogonal
|
package/dist/api.js
CHANGED
|
@@ -25,8 +25,10 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
25
25
|
// or non-JSON body, which would otherwise throw here and lose the status.
|
|
26
26
|
const rawBody = await res.text();
|
|
27
27
|
let data;
|
|
28
|
+
let bodyParsed = false;
|
|
28
29
|
try {
|
|
29
30
|
data = (rawBody ? JSON.parse(rawBody) : {});
|
|
31
|
+
bodyParsed = rawBody.length > 0;
|
|
30
32
|
}
|
|
31
33
|
catch {
|
|
32
34
|
data = {};
|
|
@@ -64,6 +66,19 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
64
66
|
// string-matching the message (e.g. whoami treating 404 as "no /me").
|
|
65
67
|
const err = new Error(errorMsg);
|
|
66
68
|
err.status = res.status;
|
|
69
|
+
// Surface the self-correction hint the API attaches on contract violations
|
|
70
|
+
// (missing/out-of-range params, upstream 4xx). Without this the run command
|
|
71
|
+
// only sees `error.message` and the expected-schema diagnostics are lost.
|
|
72
|
+
if (data._orthogonal) {
|
|
73
|
+
err.orthogonal = data._orthogonal;
|
|
74
|
+
}
|
|
75
|
+
// Keep the full parsed error body too, so callers can render structured
|
|
76
|
+
// diagnostics (missing / out_of_range) and emit machine-readable JSON.
|
|
77
|
+
// Only when the body actually parsed as JSON — otherwise a non-JSON body
|
|
78
|
+
// would surface as `{}` and mask the real error message.
|
|
79
|
+
if (bodyParsed) {
|
|
80
|
+
err.responseBody = data;
|
|
81
|
+
}
|
|
67
82
|
throw err;
|
|
68
83
|
}
|
|
69
84
|
// Return the whole response, not just data field
|
package/dist/commands/run.js
CHANGED
|
@@ -58,6 +58,80 @@ function isBinaryEnvelope(data) {
|
|
|
58
58
|
typeof data.contentType === "string" &&
|
|
59
59
|
typeof data.size === "number");
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Render the API's self-correction diagnostics attached to a failed run.
|
|
63
|
+
* Pulls the `_orthogonal` hint (expected schema + field diagnostics) plus the
|
|
64
|
+
* top-level `missing` / `out_of_range` arrays from the error response body.
|
|
65
|
+
* The upstream-4xx path returns the schema ONLY inside `_orthogonal`, and the
|
|
66
|
+
* pre-validation path returns `out_of_range` at the top level — so without this
|
|
67
|
+
* the concrete violation is invisible in the human output.
|
|
68
|
+
*/
|
|
69
|
+
function printFailureHint(body) {
|
|
70
|
+
if (!body || typeof body !== "object")
|
|
71
|
+
return;
|
|
72
|
+
const hint = body._orthogonal;
|
|
73
|
+
const hasHint = hint && typeof hint === "object";
|
|
74
|
+
const outOfRange = Array.isArray(body.out_of_range) ? body.out_of_range : [];
|
|
75
|
+
const missing = Array.isArray(body.missing) ? body.missing : [];
|
|
76
|
+
if (!hasHint && outOfRange.length === 0 && missing.length === 0)
|
|
77
|
+
return;
|
|
78
|
+
console.error(chalk_1.default.yellow("\nHint:"));
|
|
79
|
+
if (hasHint && hint.message)
|
|
80
|
+
console.error(chalk_1.default.gray(` ${hint.message}`));
|
|
81
|
+
if (missing.length > 0) {
|
|
82
|
+
console.error(chalk_1.default.gray(" Missing required params: ") + chalk_1.default.white(missing.join(", ")));
|
|
83
|
+
}
|
|
84
|
+
if (outOfRange.length > 0) {
|
|
85
|
+
const parts = outOfRange.map((p) => {
|
|
86
|
+
const bounds = [
|
|
87
|
+
typeof p.min === "number" ? `>= ${p.min}` : null,
|
|
88
|
+
typeof p.max === "number" ? `<= ${p.max}` : null,
|
|
89
|
+
]
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.join(" and ");
|
|
92
|
+
return bounds ? `${p.name}=${p.value} (must be ${bounds})` : `${p.name}=${p.value}`;
|
|
93
|
+
});
|
|
94
|
+
console.error(chalk_1.default.gray(" Out of range: ") + chalk_1.default.white(parts.join(", ")));
|
|
95
|
+
}
|
|
96
|
+
if (!hasHint)
|
|
97
|
+
return;
|
|
98
|
+
const diagnostics = [
|
|
99
|
+
["Missing required query params", hint.missing_required_query],
|
|
100
|
+
["Unexpected query fields", hint.unexpected_query_fields],
|
|
101
|
+
["Missing required body params", hint.missing_required_body],
|
|
102
|
+
["Unexpected body fields", hint.unexpected_body_fields],
|
|
103
|
+
];
|
|
104
|
+
for (const [label, value] of diagnostics) {
|
|
105
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
106
|
+
console.error(chalk_1.default.gray(` ${label}: `) + chalk_1.default.white(value.join(", ")));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const summarize = (schema, kind) => {
|
|
110
|
+
if (!schema?.properties)
|
|
111
|
+
return;
|
|
112
|
+
const required = new Set(schema.required || []);
|
|
113
|
+
const names = Object.keys(schema.properties).map((name) => {
|
|
114
|
+
const prop = schema.properties[name] || {};
|
|
115
|
+
const bits = [name];
|
|
116
|
+
if (required.has(name))
|
|
117
|
+
bits.push("(required)");
|
|
118
|
+
const range = [
|
|
119
|
+
typeof prop.minimum === "number" ? `min ${prop.minimum}` : null,
|
|
120
|
+
typeof prop.maximum === "number" ? `max ${prop.maximum}` : null,
|
|
121
|
+
]
|
|
122
|
+
.filter(Boolean)
|
|
123
|
+
.join(", ");
|
|
124
|
+
if (range)
|
|
125
|
+
bits.push(`[${range}]`);
|
|
126
|
+
return bits.join(" ");
|
|
127
|
+
});
|
|
128
|
+
if (names.length > 0) {
|
|
129
|
+
console.error(chalk_1.default.gray(` Expected ${kind}: `) + chalk_1.default.white(names.join(", ")));
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
summarize(hint.expected_schema?.queryParams, "query params");
|
|
133
|
+
summarize(hint.expected_schema?.body, "body params");
|
|
134
|
+
}
|
|
61
135
|
function formatCost(result) {
|
|
62
136
|
if (result.price)
|
|
63
137
|
return result.price;
|
|
@@ -67,7 +141,11 @@ function formatCost(result) {
|
|
|
67
141
|
return null;
|
|
68
142
|
}
|
|
69
143
|
async function runCommand(api, path, options) {
|
|
70
|
-
|
|
144
|
+
// In --raw mode keep the streams clean for piping: don't animate the spinner
|
|
145
|
+
// on stderr, so a failed call's stderr is a single parseable JSON document.
|
|
146
|
+
const spinner = (0, ora_1.default)(`Calling ${api}${path}...`);
|
|
147
|
+
if (!options.raw)
|
|
148
|
+
spinner.start();
|
|
71
149
|
try {
|
|
72
150
|
// Parse query params
|
|
73
151
|
// Supports both `-q key=value -q key2=value2` and `-q 'key=value&key2=value2'`
|
|
@@ -190,7 +268,24 @@ async function runCommand(api, path, options) {
|
|
|
190
268
|
}
|
|
191
269
|
catch (error) {
|
|
192
270
|
spinner.stop();
|
|
193
|
-
|
|
271
|
+
const err = error;
|
|
272
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
273
|
+
if (options.raw) {
|
|
274
|
+
// In --raw mode, stderr must always be a single parseable JSON document
|
|
275
|
+
// so agents can JSON.parse it. Prefer the server's parsed body; otherwise
|
|
276
|
+
// (e.g. a non-JSON HTML 502) emit a synthesized error envelope.
|
|
277
|
+
const envelope = err?.responseBody ?? {
|
|
278
|
+
success: false,
|
|
279
|
+
error: message,
|
|
280
|
+
...(typeof err?.status === "number" ? { status: err.status } : {}),
|
|
281
|
+
};
|
|
282
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
console.error(chalk_1.default.red(`Error: ${message}`));
|
|
286
|
+
if (err?.responseBody)
|
|
287
|
+
printFailureHint(err.responseBody);
|
|
288
|
+
}
|
|
194
289
|
process.exit(1);
|
|
195
290
|
}
|
|
196
291
|
}
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orth/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.30",
|
|
4
4
|
"description": "CLI to access all APIs and skills on the Orthogonal platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
-
"README.md"
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsc",
|