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 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.0",
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",