@hanzo/cli 1.9.53
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 +19 -0
- package/bin/hanzo.js +22 -0
- package/install.js +85 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @hanzo/cli
|
|
2
|
+
|
|
3
|
+
The Hanzo CLI — manage Hanzo AI cloud resources from your terminal.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm i -g @hanzo/cli
|
|
7
|
+
hanzo --help
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`postinstall` downloads the binary for your platform from the GitHub release
|
|
11
|
+
matching this package's version, and **verifies it against the `.sha256`
|
|
12
|
+
published beside it**. If you install with `--ignore-scripts`, run
|
|
13
|
+
`node node_modules/@hanzo/cli/install.js` yourself — the wrapper will tell you so
|
|
14
|
+
rather than failing with a confusing error.
|
|
15
|
+
|
|
16
|
+
Prebuilt for macOS (arm64, x64), Linux (arm64, x64) and Windows (x64). On any
|
|
17
|
+
other platform the install is skipped with a warning rather than failing.
|
|
18
|
+
|
|
19
|
+
The binary is Rust and lives at https://github.com/hanzoai/cli.
|
package/bin/hanzo.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Hand the real binary the argv it was given and get out of the way.
|
|
3
|
+
//
|
|
4
|
+
// exec-and-replace, not spawn-and-wait: a wrapper that survives its child owns
|
|
5
|
+
// that child's signals, and `hanzo` is interactive — Ctrl-C has to reach the
|
|
6
|
+
// program, not a Node process sitting in front of it. The exit code is the
|
|
7
|
+
// binary's for the same reason.
|
|
8
|
+
const { spawnSync } = require("node:child_process");
|
|
9
|
+
const { existsSync } = require("node:fs");
|
|
10
|
+
const { join } = require("node:path");
|
|
11
|
+
|
|
12
|
+
const bin = join(__dirname, process.platform === "win32" ? "hanzo.exe" : "hanzo");
|
|
13
|
+
if (!existsSync(bin)) {
|
|
14
|
+
console.error(
|
|
15
|
+
"hanzo: the binary is missing. `npm install` runs install.js to fetch it;\n" +
|
|
16
|
+
"if that was skipped (--ignore-scripts) run `node " + join(__dirname, "..", "install.js") + "`."
|
|
17
|
+
);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const r = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
21
|
+
if (r.error) { console.error("hanzo:", r.error.message); process.exit(1); }
|
|
22
|
+
process.exit(r.status ?? 0);
|
package/install.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Fetch the binary for THIS platform from the GitHub release for THIS version.
|
|
3
|
+
//
|
|
4
|
+
// Why a downloader rather than five optionalDependencies (which is what
|
|
5
|
+
// @hanzo/dev does): the release matrix already publishes
|
|
6
|
+
// `hanzo-<platform>.tar.gz` assets, and pointing at those means one artifact,
|
|
7
|
+
// built once, verified once. Five npm packages would be a second copy of the
|
|
8
|
+
// same bytes under a second set of version numbers, and they drift — that is
|
|
9
|
+
// how a `latest` ends up serving last week's binary for one platform only.
|
|
10
|
+
//
|
|
11
|
+
// The download is VERIFIED against the .sha256 the release publishes beside
|
|
12
|
+
// each asset. This script runs on every `npm install` and then that binary is
|
|
13
|
+
// executed, so it is a supply chain: an unverified download here is arbitrary
|
|
14
|
+
// code execution on every machine that installs us.
|
|
15
|
+
const { createWriteStream, mkdirSync, chmodSync, existsSync } = require("node:fs");
|
|
16
|
+
const { createHash } = require("node:crypto");
|
|
17
|
+
const { readFile, rm } = require("node:fs/promises");
|
|
18
|
+
const { join } = require("node:path");
|
|
19
|
+
const { execFileSync } = require("node:child_process");
|
|
20
|
+
const { pipeline } = require("node:stream/promises");
|
|
21
|
+
|
|
22
|
+
const VERSION = require("./package.json").version;
|
|
23
|
+
const REPO = "hanzoai/cli";
|
|
24
|
+
|
|
25
|
+
// The asset ids the release matrix actually emits (release-matrix.yml).
|
|
26
|
+
// windows-arm64 and linux-*-musl are deliberately absent: a name here that the
|
|
27
|
+
// matrix does not build is an install that fails at the 404 instead of at a
|
|
28
|
+
// sentence a human can read.
|
|
29
|
+
const TARGETS = {
|
|
30
|
+
"darwin-arm64": "darwin-arm64",
|
|
31
|
+
"darwin-x64": "darwin-amd64",
|
|
32
|
+
"linux-arm64": "linux-arm64",
|
|
33
|
+
"linux-x64": "linux-amd64",
|
|
34
|
+
"win32-x64": "windows-amd64",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
async function get(url) {
|
|
38
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
39
|
+
if (!res.ok) throw new Error(`${res.status} ${res.statusText} for ${url}`);
|
|
40
|
+
return res;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function main() {
|
|
44
|
+
const key = `${process.platform}-${process.arch}`;
|
|
45
|
+
const target = TARGETS[key];
|
|
46
|
+
if (!target) {
|
|
47
|
+
// Not an error. A platform we do not build for should not fail an install
|
|
48
|
+
// that may not even use this package; `hanzo` will say so if it is run.
|
|
49
|
+
console.warn(`@hanzo/cli: no prebuilt binary for ${key}; skipping download.`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const base = `https://github.com/${REPO}/releases/download/v${VERSION}`;
|
|
54
|
+
const asset = `hanzo-${target}.tar.gz`;
|
|
55
|
+
const tmp = join(__dirname, asset);
|
|
56
|
+
const dest = join(__dirname, "bin");
|
|
57
|
+
|
|
58
|
+
const want = (await (await get(`${base}/${asset}.sha256`)).text()).trim().split(/\s+/)[0];
|
|
59
|
+
|
|
60
|
+
const res = await get(`${base}/${asset}`);
|
|
61
|
+
const hash = createHash("sha256");
|
|
62
|
+
const file = createWriteStream(tmp);
|
|
63
|
+
await pipeline(res.body, async function* (src) {
|
|
64
|
+
for await (const chunk of src) { hash.update(chunk); yield chunk; }
|
|
65
|
+
}, file);
|
|
66
|
+
|
|
67
|
+
const got = hash.digest("hex");
|
|
68
|
+
if (got !== want) {
|
|
69
|
+
await rm(tmp, { force: true });
|
|
70
|
+
throw new Error(`checksum mismatch for ${asset}\n expected ${want}\n got ${got}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
mkdirSync(dest, { recursive: true });
|
|
74
|
+
execFileSync("tar", ["-xzf", tmp, "-C", dest]);
|
|
75
|
+
await rm(tmp, { force: true });
|
|
76
|
+
|
|
77
|
+
const bin = join(dest, process.platform === "win32" ? "hanzo.exe" : "hanzo");
|
|
78
|
+
if (existsSync(bin) && process.platform !== "win32") chmodSync(bin, 0o755);
|
|
79
|
+
console.log(`@hanzo/cli: installed hanzo ${VERSION} (${target})`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main().catch((err) => {
|
|
83
|
+
console.error(`@hanzo/cli: ${err.message}`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hanzo/cli",
|
|
3
|
+
"version": "1.9.53",
|
|
4
|
+
"description": "Hanzo CLI — manage Hanzo AI cloud resources",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/hanzoai/cli.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://hanzo.ai",
|
|
11
|
+
"bin": {
|
|
12
|
+
"hanzo": "bin/hanzo.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"install.js",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"postinstall": "node install.js"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
}
|
|
25
|
+
}
|