@ornncompute/cli 0.1.0 → 0.1.2
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 +58 -28
- package/package.json +3 -4
- package/src/api-client.mjs +31 -7
- package/src/cli.mjs +1769 -364
package/README.md
CHANGED
|
@@ -1,44 +1,74 @@
|
|
|
1
|
-
# Ornn
|
|
1
|
+
# Ornn CLI
|
|
2
2
|
|
|
3
|
-
Command-line access for Ornn
|
|
4
|
-
|
|
3
|
+
Command-line access for Ornn bare-metal compute workflows: find
|
|
4
|
+
available capacity, buy or bid, manage reservations, activate SSH access,
|
|
5
|
+
resell capacity, and open billing.
|
|
6
|
+
|
|
7
|
+
For the end-user install, browser-login, command, and troubleshooting guide, see
|
|
8
|
+
the [`docs/cli.md`](../../docs/cli.md) guide.
|
|
5
9
|
|
|
6
10
|
## Install
|
|
7
11
|
|
|
8
12
|
```bash
|
|
9
|
-
curl -fsSL https://
|
|
13
|
+
curl -fsSL https://compute.ornn.com/cli/install | sh
|
|
10
14
|
```
|
|
11
15
|
|
|
12
16
|
The installer requires Node.js 20 or newer and npm. It installs `@ornncompute/cli`
|
|
13
|
-
globally, exposes
|
|
14
|
-
|
|
15
|
-
`ORNN_AUTH_BASE_URL` for the
|
|
17
|
+
globally, exposes the `ornn` binary, adds the npm global bin directory to the
|
|
18
|
+
user's shell profile when needed, and writes
|
|
19
|
+
`ORNN_AUTH_BASE_URL` for the Ornn host that served the installer. The
|
|
20
|
+
installer prints a short Ornn Compute welcome banner and login prompt; set
|
|
21
|
+
`ORNN_INSTALL_BANNER=0` to skip it or `ORNN_INSTALL_ANIMATION=0` to keep it
|
|
22
|
+
static.
|
|
16
23
|
|
|
17
24
|
## Commands
|
|
18
25
|
|
|
19
26
|
```bash
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
ornn help [command]
|
|
28
|
+
ornn login [--auth-base <url>] [--no-browser] [--timeout <seconds>]
|
|
29
|
+
ornn whoami [--json]
|
|
30
|
+
ornn status [--json]
|
|
31
|
+
ornn availability list [--gpu-type <type>] [--facility <name>] [--operator <name>] [--json]
|
|
32
|
+
ornn availability show <listing-id> [--open] [--json]
|
|
33
|
+
ornn buy <listing-id> [--no-open] [--json]
|
|
34
|
+
ornn bid create <listing-id> --gpu-count <n> --min-gpu-count <n> --start-date <yyyy-mm-dd> --end-date <yyyy-mm-dd> --price <usd> [--no-open] [--json]
|
|
35
|
+
ornn bid list [--json]
|
|
36
|
+
ornn bid show <bid-id> [--open] [--json]
|
|
37
|
+
ornn bid update <bid-id> --gpu-count <n> --min-gpu-count <n> --start-date <yyyy-mm-dd> --end-date <yyyy-mm-dd> --price <usd>
|
|
38
|
+
ornn bid withdraw <bid-id>
|
|
39
|
+
ornn reservations list [--status <status>] [--json]
|
|
40
|
+
ornn reservations show <reservation-id> [--open] [--json]
|
|
41
|
+
ornn reservations checkout <reservation-id> [--no-open] [--json]
|
|
42
|
+
ornn access show <reservation-id> [--json]
|
|
43
|
+
ornn access activate <reservation-id> --ssh-key-id <id> [--username <name>] [--no-open] [--json]
|
|
44
|
+
ornn access push-keys <reservation-id> --ssh-key-id <id> [--json]
|
|
45
|
+
ornn access keys list <reservation-id> [--json]
|
|
46
|
+
ornn access keys add <reservation-id> --public-key <key> [--label <label>] [--json]
|
|
47
|
+
ornn access keys add <reservation-id> --public-key-file <path> [--label <label>] [--json]
|
|
48
|
+
ornn access keys push <reservation-id> --ssh-key-id <id> [--json]
|
|
49
|
+
ornn access keys status <reservation-id> [--json]
|
|
50
|
+
ornn resale browse [--json]
|
|
51
|
+
ornn resale list <reservation-id> --ask-price <usd> [--no-open] [--json]
|
|
52
|
+
ornn resale update <reservation-id> --ask-price <usd> [--no-open] [--json]
|
|
53
|
+
ornn resale delist <reservation-id> [--no-open] [--json]
|
|
54
|
+
ornn ssh-keys list [--json]
|
|
55
|
+
ornn ssh-keys add --public-key <key> [--label <label>] [--json]
|
|
56
|
+
ornn ssh-keys add --public-key-file <path> [--label <label>] [--json]
|
|
57
|
+
ornn ssh-keys delete <key-id> [--json]
|
|
58
|
+
ornn billing open [--no-open] [--json]
|
|
59
|
+
ornn api <get|post|patch|put|delete> <compute-path> [--data <json>] [--raw]
|
|
60
|
+
ornn logout
|
|
36
61
|
```
|
|
37
62
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
63
|
+
Commands print concise human-readable output by default. Use `--json` on
|
|
64
|
+
read/show/list commands and transaction handoffs when you need structured
|
|
65
|
+
stdout for scripts. Errors and login/browser progress go to stderr.
|
|
66
|
+
|
|
67
|
+
`ornn login` opens a browser to the Ornn auth origin, lets the user sign in
|
|
68
|
+
with the normal web account flow, and then completes automatically in the
|
|
69
|
+
terminal once the browser session approves the CLI device request. If the CLI
|
|
70
|
+
cannot open a browser, copy the printed URL into any browser and sign in there;
|
|
71
|
+
the terminal keeps polling until the login is approved or expires.
|
|
42
72
|
|
|
43
|
-
Run `
|
|
73
|
+
Run `ornn --help` for the full command list and `ornn api` for the
|
|
44
74
|
allowlisted compute API escape hatch.
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ornncompute/cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Command-line interface for Ornn
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Command-line interface for Ornn bare-metal compute workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"fabric": "bin/ornn.js",
|
|
8
7
|
"ornn": "bin/ornn.js"
|
|
9
8
|
},
|
|
10
9
|
"files": [
|
|
@@ -12,7 +11,7 @@
|
|
|
12
11
|
"src",
|
|
13
12
|
"README.md"
|
|
14
13
|
],
|
|
15
|
-
"homepage": "https://
|
|
14
|
+
"homepage": "https://compute.ornn.com",
|
|
16
15
|
"bugs": {
|
|
17
16
|
"url": "https://github.com/Ornn-AI/fabric/issues"
|
|
18
17
|
},
|
package/src/api-client.mjs
CHANGED
|
@@ -23,7 +23,7 @@ export function resolveApiBaseUrl({ env = process.env, explicit, session } = {})
|
|
|
23
23
|
export async function loadRequiredSession({ env = process.env } = {}) {
|
|
24
24
|
const session = await loadAuthSession({ env });
|
|
25
25
|
if (!session?.accessToken) {
|
|
26
|
-
throw new CliApiError("Not logged in. Run `
|
|
26
|
+
throw new CliApiError("Not logged in. Run `ornn login` first.", { status: 401 });
|
|
27
27
|
}
|
|
28
28
|
return session;
|
|
29
29
|
}
|
|
@@ -64,7 +64,7 @@ export async function cliRequest({
|
|
|
64
64
|
});
|
|
65
65
|
} catch (error) {
|
|
66
66
|
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
-
throw new CliApiError(`Could not reach
|
|
67
|
+
throw new CliApiError(`Could not reach Ornn at ${baseUrl}: ${message}`);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (raw) {
|
|
@@ -76,10 +76,11 @@ export async function cliRequest({
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
const text = await response.text();
|
|
79
|
-
const data = text ? parseJson(text, url.toString()) : null;
|
|
79
|
+
const data = text ? parseJson(text, url.toString(), response) : null;
|
|
80
80
|
if (!response.ok) {
|
|
81
|
-
const detail = data?.detail
|
|
82
|
-
|
|
81
|
+
const detail = data?.detail ?? data?.error ?? response.statusText;
|
|
82
|
+
const message = detailMessage(detail) || response.statusText;
|
|
83
|
+
throw new CliApiError(`Ornn request failed: ${message}`, {
|
|
83
84
|
detail: data,
|
|
84
85
|
status: response.status,
|
|
85
86
|
});
|
|
@@ -103,10 +104,33 @@ export function normalizeComputePath(path) {
|
|
|
103
104
|
return trimmed;
|
|
104
105
|
}
|
|
105
106
|
|
|
106
|
-
function parseJson(text, url) {
|
|
107
|
+
function parseJson(text, url, response) {
|
|
107
108
|
try {
|
|
108
109
|
return JSON.parse(text);
|
|
109
110
|
} catch {
|
|
110
|
-
|
|
111
|
+
const contentType = response?.headers?.get?.("content-type") || "";
|
|
112
|
+
const isHtml = /html/i.test(contentType) || /^\s*</.test(text);
|
|
113
|
+
const hint = isHtml
|
|
114
|
+
? " The Ornn host may not have this CLI endpoint deployed yet."
|
|
115
|
+
: "";
|
|
116
|
+
throw new CliApiError(`Ornn returned a non-JSON response from ${url}.${hint}`, {
|
|
117
|
+
status: response?.status,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function detailMessage(detail) {
|
|
123
|
+
if (typeof detail === "string") {
|
|
124
|
+
return detail;
|
|
125
|
+
}
|
|
126
|
+
if (!detail || typeof detail !== "object") {
|
|
127
|
+
return "";
|
|
128
|
+
}
|
|
129
|
+
if (typeof detail.summary === "string") {
|
|
130
|
+
return detail.summary;
|
|
131
|
+
}
|
|
132
|
+
if (typeof detail.code === "string") {
|
|
133
|
+
return detail.code;
|
|
111
134
|
}
|
|
135
|
+
return "";
|
|
112
136
|
}
|