hypha-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 +141 -0
- package/bin/postinstall.mjs +75 -0
- package/package.json +2 -1
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# hypha-cli
|
|
2
|
+
|
|
3
|
+
Command-line tool for managing [Hypha Cloud](https://hypha.aicell.io) resources — workspaces, server apps, and artifacts.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g hypha-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires **Node.js >= 22** (for native WebSocket support).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Login (opens browser for OAuth)
|
|
17
|
+
hypha login
|
|
18
|
+
|
|
19
|
+
# Check workspace info
|
|
20
|
+
hypha info
|
|
21
|
+
|
|
22
|
+
# List services
|
|
23
|
+
hypha services
|
|
24
|
+
|
|
25
|
+
# List artifacts
|
|
26
|
+
hypha artifacts ls
|
|
27
|
+
|
|
28
|
+
# Upload a file
|
|
29
|
+
hypha artifacts cp ./data.csv my-model:data/train.csv
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
Credentials are stored in `~/.hypha/.env`:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
HYPHA_SERVER_URL=https://hypha.aicell.io
|
|
38
|
+
HYPHA_TOKEN=<your-token>
|
|
39
|
+
HYPHA_WORKSPACE=<your-workspace>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
You can also set these as environment variables, or use global flags:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
hypha --server https://hypha.aicell.io --workspace my-ws artifacts ls
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Commands
|
|
49
|
+
|
|
50
|
+
### Workspace Management
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
hypha login [server-url] # OAuth login (opens browser)
|
|
54
|
+
hypha token [--expires-in N] [--permission P] [--workspace W] [--json]
|
|
55
|
+
hypha services [--type T] [--include-unlisted] [--json]
|
|
56
|
+
hypha info [--json]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Apps — Server App Lifecycle
|
|
60
|
+
|
|
61
|
+
Manage server app definitions (like Docker images) and running instances (like containers).
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
hypha apps list [--json] # List installed app definitions
|
|
65
|
+
hypha apps info <app-id> [--json] # Show app details
|
|
66
|
+
hypha apps install <source> [--id ID] [--manifest P] [--files D...] [--overwrite]
|
|
67
|
+
hypha apps uninstall <app-id> # Remove app definition
|
|
68
|
+
hypha apps start <app-id> [--timeout N] [--wait] # Start instance
|
|
69
|
+
hypha apps stop <id> [--all] # Stop instance(s)
|
|
70
|
+
hypha apps ps [--json] # List running instances
|
|
71
|
+
hypha apps logs <instance-id> [--tail N] [--type T]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Aliases**: `ls` = `list`, `rm` = `uninstall`
|
|
75
|
+
|
|
76
|
+
`stop` accepts either an instance ID or an app ID. With `--all`, stops all instances of that app.
|
|
77
|
+
|
|
78
|
+
### Artifacts — Data & File Management
|
|
79
|
+
|
|
80
|
+
Linux-style commands for managing artifacts (datasets, models, files). Artifact paths use `alias:path/to/file` notation.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
hypha artifacts ls [artifact[:path]] [--json] [--long]
|
|
84
|
+
hypha artifacts cat <artifact:path>
|
|
85
|
+
hypha artifacts cp <src> <dest> [-r] [--commit]
|
|
86
|
+
hypha artifacts rm <artifact[:path]> [-r] [--force]
|
|
87
|
+
hypha artifacts create <alias> [--type T] [--parent P]
|
|
88
|
+
hypha artifacts info <artifact> [--json]
|
|
89
|
+
hypha artifacts search <query> [--type T] [--limit N] [--json]
|
|
90
|
+
hypha artifacts commit <artifact> [--version V] [--message M]
|
|
91
|
+
hypha artifacts edit <artifact> [--name N] [--description D]
|
|
92
|
+
hypha artifacts discard <artifact>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Aliases**: `list` = `ls`, `mkdir` = `create`, `find` = `search`
|
|
96
|
+
|
|
97
|
+
**Shorthand**: `hypha art` = `hypha artifacts`
|
|
98
|
+
|
|
99
|
+
#### Copy Examples
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Upload a single file
|
|
103
|
+
hypha artifacts cp ./data.csv my-model:data/train.csv
|
|
104
|
+
|
|
105
|
+
# Download a file
|
|
106
|
+
hypha artifacts cp my-model:weights.bin ./local/
|
|
107
|
+
|
|
108
|
+
# Upload a directory (recursive)
|
|
109
|
+
hypha artifacts cp ./dataset/ my-model:data/ -r
|
|
110
|
+
|
|
111
|
+
# Upload and auto-commit
|
|
112
|
+
hypha artifacts cp ./results.json my-model:results.json --commit
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Programmatic API
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
import { connectToHypha, resolveServerUrl, resolveToken } from 'hypha-cli';
|
|
119
|
+
import { uploadFile, downloadFile } from 'hypha-cli';
|
|
120
|
+
import { parseArtifactPath, resolveArtifactId } from 'hypha-cli';
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Build
|
|
127
|
+
yarn workspace hypha-cli build
|
|
128
|
+
|
|
129
|
+
# Run unit tests (176 tests)
|
|
130
|
+
yarn workspace hypha-cli test
|
|
131
|
+
|
|
132
|
+
# Run integration tests (requires HYPHA_TOKEN)
|
|
133
|
+
yarn workspace hypha-cli test:integration
|
|
134
|
+
|
|
135
|
+
# Dev mode (run from source)
|
|
136
|
+
yarn workspace hypha-cli dev -- artifacts ls
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
See LICENSE in the repository root.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* postinstall script for hypha-cli
|
|
5
|
+
*
|
|
6
|
+
* Detects and removes conflicting Python 'hypha' command.
|
|
7
|
+
* The Python hypha package installs a 'hypha' console_script for starting
|
|
8
|
+
* the server, but `python -m hypha.server` is the preferred way to do that.
|
|
9
|
+
*
|
|
10
|
+
* npm runs postinstall in a stripped shell (no ~/.zshrc, no conda init, etc),
|
|
11
|
+
* so `which` can't see all PATH entries. We solve this by running `which -a`
|
|
12
|
+
* inside a login shell to get the user's full PATH.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { execSync } from 'child_process';
|
|
16
|
+
import { existsSync, readFileSync, unlinkSync } from 'fs';
|
|
17
|
+
|
|
18
|
+
function isPythonHyphaScript(filePath) {
|
|
19
|
+
try {
|
|
20
|
+
const head = readFileSync(filePath, 'utf-8').slice(0, 500);
|
|
21
|
+
return head.includes('python') && head.includes('from hypha');
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findConflictingBinaries() {
|
|
28
|
+
const found = new Set();
|
|
29
|
+
|
|
30
|
+
// Detect user's shell
|
|
31
|
+
const shell = process.env.SHELL || '/bin/sh';
|
|
32
|
+
|
|
33
|
+
// Run `which -a hypha` in a login shell to get full PATH (conda, pyenv, etc.)
|
|
34
|
+
for (const cmd of [
|
|
35
|
+
`${shell} -l -c 'which -a hypha' 2>/dev/null`, // login shell (loads ~/.zshrc, conda init, etc.)
|
|
36
|
+
'which -a hypha 2>/dev/null', // plain fallback
|
|
37
|
+
]) {
|
|
38
|
+
try {
|
|
39
|
+
const output = execSync(cmd, { encoding: 'utf-8', timeout: 10000 }).trim();
|
|
40
|
+
for (const line of output.split('\n')) {
|
|
41
|
+
const p = line.trim();
|
|
42
|
+
if (p && existsSync(p) && isPythonHyphaScript(p)) {
|
|
43
|
+
found.add(p);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// Shell or which not available
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return [...found];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function main() {
|
|
55
|
+
const conflicts = findConflictingBinaries();
|
|
56
|
+
if (conflicts.length === 0) return;
|
|
57
|
+
|
|
58
|
+
for (const binPath of conflicts) {
|
|
59
|
+
try {
|
|
60
|
+
unlinkSync(binPath);
|
|
61
|
+
console.log(`hypha-cli: removed conflicting Python 'hypha' at ${binPath}`);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
if (err.code === 'EACCES') {
|
|
64
|
+
console.log(`hypha-cli: conflicting Python 'hypha' at ${binPath}`);
|
|
65
|
+
console.log(` remove it manually: rm ${binPath}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (conflicts.length > 0) {
|
|
71
|
+
console.log(` (use 'python -m hypha.server' to start the Hypha server instead)`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypha-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Hypha Cloud CLI — manage workspaces, apps, and artifacts",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"./cli": "./dist/cli.mjs"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
+
"postinstall": "node bin/postinstall.mjs",
|
|
21
22
|
"build": "tsc --noEmit && pkgroll",
|
|
22
23
|
"typecheck": "tsc --noEmit",
|
|
23
24
|
"test": "npx tsx test/test-cli-routing.mjs && npx tsx test/test-artifact-path.mjs && npx tsx test/test-apps-commands.mjs && npx tsx test/test-artifacts-commands.mjs && npx tsx test/test-helpers.mjs",
|