@uniac/cli 0.0.1 → 0.2.1

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 CHANGED
@@ -8,30 +8,39 @@ Control-plane CLI for [Uniac](https://uniac.ai).
8
8
  npm i -g @uniac/cli
9
9
  ```
10
10
 
11
- Verify:
11
+ Or run without installing:
12
12
 
13
13
  ```bash
14
- uniac --version
14
+ npx -y @uniac/cli version
15
15
  ```
16
16
 
17
- ## Other channels
18
-
19
- - GitHub Releases (raw tar.gz): <https://github.com/uniac-ai/Uniac/releases>
20
-
21
17
  ## How it works
22
18
 
23
- This package ships a JS shim plus a postinstall script. After `npm install`,
24
- the postinstall downloads the matching Go binary from this repo's
25
- [GitHub Releases](https://github.com/uniac-ai/Uniac/releases) and drops it
26
- next to the shim. The shim then `execFileSync`s the binary with your argv.
27
-
28
- Supported platforms: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`.
29
-
30
- Requirements: Node 18+ (for built-in `fetch`) and `tar` on `$PATH`
31
- (present by default on macOS, Linux, and Windows 10 1803+).
32
-
33
- Set `UNIAC_SKIP_POSTINSTALL=1` to skip the binary download — useful for
34
- sandboxes that vendor the binary by other means.
19
+ `@uniac/cli` is a tiny JS shim plus one `optionalDependencies` entry
20
+ per supported platform (`@uniac/cli-darwin-arm64`, …), each carrying
21
+ the prebuilt Go binary. npm installs only the package whose `os`/`cpu`
22
+ fields match the machine and verifies its registry checksum; the shim
23
+ resolves that package's `bin/uniac` and runs it with your argv.
24
+
25
+ No package in the set has install scripts or fetches anything outside
26
+ the npm registry, so installs work in restricted environments CI,
27
+ containers, AI-agent sandboxes including under `--ignore-scripts`
28
+ and behind proxies or registry mirrors.
29
+
30
+ Supported platforms: `darwin-arm64`, `darwin-x64`, `linux-arm64`,
31
+ `linux-x64` — the authoritative table is [`targets.js`](./targets.js).
32
+ On any other platform, grab a tar.gz from
33
+ [GitHub Releases](https://github.com/uniac-ai/Uniac/releases) and put
34
+ `uniac` on `$PATH`.
35
+
36
+ ## Releasing
37
+
38
+ `.github/workflows/release.yml` publishes on `cli-v*` tags: it runs
39
+ [`scripts/package-platform-npm.js`](./scripts/package-platform-npm.js)
40
+ to turn GoReleaser's `dist/` into the platform packages and pin them
41
+ as exact-version `optionalDependencies` here, then publishes the
42
+ platform packages followed by this meta package. See
43
+ [`../go/README.md`](../go/README.md) for the full release runbook.
35
44
 
36
45
  ## License
37
46
 
package/bin/uniac.js CHANGED
@@ -1,17 +1,47 @@
1
1
  #!/usr/bin/env node
2
- // Thin shim. The postinstall script downloads the matching `uniac` Go
3
- // binary into this same directory; we just exec it with our argv.
4
- import { execFileSync } from "node:child_process";
5
- import path from "node:path";
6
- import { fileURLToPath } from "node:url";
2
+ // Shim that resolves the platform-matched `uniac` Go binary — shipped
3
+ // as the optionalDependency @uniac/cli-<platform>-<arch> and runs
4
+ // it with this process's argv, stdio, and exit status.
5
+ import { spawnSync } from "node:child_process";
6
+ import { createRequire } from "node:module";
7
+ import { TARGETS, packageName } from "../targets.js";
7
8
 
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
- const exe = process.platform === "win32" ? "uniac.exe" : "uniac";
9
+ const key = `${process.platform}-${process.arch}`;
10
10
 
11
+ function fail(lines) {
12
+ console.error(lines.map((l) => `[uniac] ${l}`).join("\n"));
13
+ process.exit(1);
14
+ }
15
+
16
+ if (!(key in TARGETS)) {
17
+ fail([
18
+ `no prebuilt binary for ${key}.`,
19
+ `Supported: ${Object.keys(TARGETS).join(", ")}.`,
20
+ "Grab a tar.gz from https://github.com/uniac-ai/Uniac/releases",
21
+ "and put `uniac` on $PATH instead.",
22
+ ]);
23
+ }
24
+
25
+ let binary;
11
26
  try {
12
- execFileSync(path.join(__dirname, exe), process.argv.slice(2), {
13
- stdio: "inherit",
14
- });
15
- } catch (err) {
16
- process.exit(typeof err.status === "number" ? err.status : 1);
27
+ binary = createRequire(import.meta.url).resolve(
28
+ `${packageName(key)}/bin/uniac`
29
+ );
30
+ } catch {
31
+ fail([
32
+ `${packageName(key)} is missing.`,
33
+ "It carries the uniac binary and installs as an optionalDependency",
34
+ "of @uniac/cli — reinstall without --omit=optional/--no-optional:",
35
+ " npm install -g @uniac/cli",
36
+ ]);
37
+ }
38
+
39
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
40
+ if (result.error) {
41
+ fail([`failed to run ${binary}: ${result.error.message}`]);
42
+ }
43
+ if (result.signal) {
44
+ // Re-raise so the caller observes the same termination signal.
45
+ process.kill(process.pid, result.signal);
17
46
  }
47
+ process.exit(result.status ?? 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniac/cli",
3
- "version": "0.0.1",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Control-plane CLI for Uniac services",
6
6
  "bin": {
@@ -24,5 +24,11 @@
24
24
  "url": "https://github.com/uniac-ai/Uniac.git",
25
25
  "directory": "uniac_cli/npm"
26
26
  },
27
- "homepage": "https://uniac.ai"
27
+ "homepage": "https://uniac.ai",
28
+ "optionalDependencies": {
29
+ "@uniac/cli-darwin-arm64": "0.2.1",
30
+ "@uniac/cli-darwin-x64": "0.2.1",
31
+ "@uniac/cli-linux-arm64": "0.2.1",
32
+ "@uniac/cli-linux-x64": "0.2.1"
33
+ }
28
34
  }
@@ -1,25 +0,0 @@
1
- // Postinstall configuration. Pure data, no runtime logic — keep it
2
- // trivial so platform/URL changes don't touch postinstall.js.
3
- //
4
- // The URL template must match the archive name_template in
5
- // uniac_ctl/.goreleaser.yml — they're two sides of the same contract.
6
- // GoReleaser produces archives named:
7
- // uniac_<version>_<title-case OS>_<arch>.tar.gz
8
- // where arch is x86_64 for amd64 and bare arch otherwise. The GitHub
9
- // Release tag GoReleaser creates strips the `cli-` prefix from the
10
- // user-pushed tag, so the URL path uses v<version>.
11
-
12
- export const PLATFORMS = {
13
- // process.platform-process.arch -> { os, arch } parts of the archive name
14
- "darwin-arm64": { os: "Darwin", arch: "arm64" },
15
- "darwin-x64": { os: "Darwin", arch: "x86_64" },
16
- "linux-arm64": { os: "Linux", arch: "arm64" },
17
- "linux-x64": { os: "Linux", arch: "x86_64" },
18
- };
19
-
20
- export const URL_TEMPLATE =
21
- "https://github.com/uniac-ai/Uniac/releases/download/v{{version}}/uniac_{{version}}_{{os}}_{{arch}}.tar.gz";
22
-
23
- // Name of the binary inside the tar.gz (top-level entry — GoReleaser
24
- // doesn't nest under a directory).
25
- export const BINARY_NAME = "uniac";
@@ -1,77 +0,0 @@
1
- // Runs after `npm install @uniac/cli`. Downloads the matching Go binary
2
- // from this repo's GitHub Release and drops it next to bin/uniac.js so
3
- // the shim can exec it. Zero npm deps — uses Node 18+ built-in fetch +
4
- // the system `tar` binary (Win10 1803+ ships one).
5
- //
6
- // Skip with UNIAC_SKIP_POSTINSTALL=1. Useful for sandbox / CI builds
7
- // that vendor the binary by other means.
8
-
9
- import fs from "node:fs";
10
- import path from "node:path";
11
- import { execFileSync } from "node:child_process";
12
- import { fileURLToPath } from "node:url";
13
- import { PLATFORMS, URL_TEMPLATE, BINARY_NAME } from "./config.js";
14
-
15
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
- const pkgRoot = path.resolve(__dirname, "..");
17
- const binDir = path.join(pkgRoot, "bin");
18
-
19
- async function main() {
20
- if (process.env.UNIAC_SKIP_POSTINSTALL === "1") {
21
- console.log("[uniac] UNIAC_SKIP_POSTINSTALL=1 — skipping binary download.");
22
- return;
23
- }
24
-
25
- const key = `${process.platform}-${process.arch}`;
26
- const target = PLATFORMS[key];
27
- if (!target) {
28
- console.error(
29
- `[uniac] no prebuilt binary for ${key}.\n` +
30
- `Supported: ${Object.keys(PLATFORMS).join(", ")}.\n` +
31
- `Grab the matching tar.gz from\n` +
32
- `https://github.com/uniac-ai/Uniac/releases and put \`${BINARY_NAME}\` on $PATH.`
33
- );
34
- process.exit(1);
35
- }
36
-
37
- const pkg = JSON.parse(
38
- fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8")
39
- );
40
- const version = pkg.version;
41
- const url = URL_TEMPLATE
42
- .replaceAll("{{version}}", version)
43
- .replaceAll("{{os}}", target.os)
44
- .replaceAll("{{arch}}", target.arch);
45
-
46
- fs.mkdirSync(binDir, { recursive: true });
47
- const tarPath = path.join(binDir, "uniac.tar.gz");
48
-
49
- console.log(`[uniac] downloading ${url}`);
50
- await downloadTo(url, tarPath);
51
-
52
- // Extract just the binary — GoReleaser archives also include LICENSE
53
- // and README*, which would clutter bin/. Positional arg restricts the
54
- // extraction to a single entry.
55
- execFileSync("tar", ["-xzf", tarPath, "-C", binDir, BINARY_NAME], {
56
- stdio: "inherit",
57
- });
58
- fs.unlinkSync(tarPath);
59
- fs.chmodSync(path.join(binDir, BINARY_NAME), 0o755);
60
- console.log(`[uniac] installed ${BINARY_NAME} ${version} for ${key}`);
61
- }
62
-
63
- async function downloadTo(url, destPath) {
64
- // Built-in fetch follows redirects automatically. GitHub Releases
65
- // 302s to a CDN — Node 18+ handles that without extra code.
66
- const res = await fetch(url);
67
- if (!res.ok) {
68
- throw new Error(`HTTP ${res.status} ${res.statusText} fetching ${url}`);
69
- }
70
- const buf = Buffer.from(await res.arrayBuffer());
71
- fs.writeFileSync(destPath, buf);
72
- }
73
-
74
- main().catch((err) => {
75
- console.error("[uniac] postinstall failed:", err.message);
76
- process.exit(1);
77
- });