@orbit-tools/cli 0.3.0

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,40 @@
1
+ # @orbit-tools/cli
2
+
3
+ npm proxy for the [Orbit](https://github.com/danieljhkim/orbit) CLI.
4
+
5
+ On install, downloads the matching prebuilt `orbit` binary from
6
+ [GitHub Releases](https://github.com/danieljhkim/orbit/releases), verifies its
7
+ SHA-256 against the published `orbit-checksums.txt`, and exposes it as the
8
+ `orbit` command.
9
+
10
+ ## Usage
11
+
12
+ ```bash
13
+ # Install globally
14
+ npm install -g @orbit-tools/cli
15
+ orbit --version
16
+
17
+ # One-shot via npx (used by the orbit Claude plugin)
18
+ npx -y @orbit-tools/cli mcp serve
19
+ ```
20
+
21
+ All arguments are forwarded to the native `orbit` binary.
22
+
23
+ ## Supported platforms
24
+
25
+ - macOS arm64 / x64
26
+ - Linux arm64 / x64
27
+
28
+ Windows is not currently published. Use WSL or build from source.
29
+
30
+ ## Environment variables
31
+
32
+ | Variable | Effect |
33
+ |---|---|
34
+ | `ORBIT_BINARY` | Path to a local `orbit` binary; bypasses download. |
35
+ | `ORBIT_BINARY_VERSION` | Override the release tag to install (e.g. `v0.3.0`). |
36
+ | `ORBIT_SKIP_DOWNLOAD=1` | Skip postinstall download (lazy install on first run still works). |
37
+
38
+ ## License
39
+
40
+ MIT.
package/bin/orbit.js ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { spawn, spawnSync } = require('node:child_process');
7
+
8
+ const PKG_ROOT = path.resolve(__dirname, '..');
9
+ const DEFAULT_BIN = path.join(
10
+ PKG_ROOT,
11
+ 'binaries',
12
+ process.platform === 'win32' ? 'orbit.exe' : 'orbit'
13
+ );
14
+
15
+ function resolveBinary() {
16
+ if (process.env.ORBIT_BINARY) return process.env.ORBIT_BINARY;
17
+ if (fs.existsSync(DEFAULT_BIN)) return DEFAULT_BIN;
18
+ // Lazy install path: handles `npm install --ignore-scripts`.
19
+ process.stderr.write('@orbit-tools/cli: binary not found, attempting download...\n');
20
+ const installer = path.join(PKG_ROOT, 'scripts', 'install-binary.js');
21
+ const result = spawnSync(process.execPath, [installer], { stdio: 'inherit' });
22
+ if (result.status !== 0 || !fs.existsSync(DEFAULT_BIN)) {
23
+ process.stderr.write('@orbit-tools/cli: binary install failed. Set ORBIT_BINARY to point at a local orbit binary, or reinstall the package.\n');
24
+ process.exit(result.status || 1);
25
+ }
26
+ return DEFAULT_BIN;
27
+ }
28
+
29
+ const binary = resolveBinary();
30
+ const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
31
+
32
+ child.on('exit', (code, signal) => {
33
+ if (signal) {
34
+ process.kill(process.pid, signal);
35
+ } else {
36
+ process.exit(code === null ? 1 : code);
37
+ }
38
+ });
39
+
40
+ child.on('error', (err) => {
41
+ process.stderr.write(`@orbit-tools/cli: failed to launch ${binary}: ${err.message}\n`);
42
+ process.exit(1);
43
+ });
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@orbit-tools/cli",
3
+ "version": "0.3.0",
4
+ "description": "npm proxy for the Orbit CLI. Downloads the matching native binary from GitHub Releases on install and forwards all invocations.",
5
+ "bin": {
6
+ "orbit": "bin/orbit.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/install-binary.js",
10
+ "test": "node bin/orbit.js --version"
11
+ },
12
+ "files": [
13
+ "bin/",
14
+ "scripts/",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "os": [
22
+ "darwin",
23
+ "linux"
24
+ ],
25
+ "cpu": [
26
+ "x64",
27
+ "arm64"
28
+ ],
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/danieljhkim/orbit.git",
32
+ "directory": "plugin/npm"
33
+ },
34
+ "homepage": "https://github.com/danieljhkim/orbit",
35
+ "bugs": "https://github.com/danieljhkim/orbit/issues",
36
+ "license": "MIT",
37
+ "keywords": [
38
+ "orbit",
39
+ "mcp",
40
+ "code-intelligence",
41
+ "knowledge-graph"
42
+ ],
43
+ "config": {
44
+ "orbit": {
45
+ "binaryRepo": "danieljhkim/orbit"
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const https = require('node:https');
7
+ const crypto = require('node:crypto');
8
+ const { spawnSync } = require('node:child_process');
9
+ const os = require('node:os');
10
+
11
+ const PKG = require('../package.json');
12
+ const BINARY_REPO = PKG.config.orbit.binaryRepo;
13
+ // Convention: npm package version is kept in lockstep with the orbit release tag.
14
+ // `0.3.1` → fetches `v0.3.1` from GitHub Releases. Override with $ORBIT_BINARY_VERSION.
15
+ const BINARY_VERSION = process.env.ORBIT_BINARY_VERSION || `v${PKG.version}`;
16
+ const PKG_ROOT = path.resolve(__dirname, '..');
17
+ const BIN_DIR = path.join(PKG_ROOT, 'binaries');
18
+ const BIN_PATH = path.join(BIN_DIR, process.platform === 'win32' ? 'orbit.exe' : 'orbit');
19
+
20
+ function log(msg) {
21
+ process.stderr.write(`@orbit-tools/cli: ${msg}\n`);
22
+ }
23
+
24
+ function fail(msg) {
25
+ process.stderr.write(`@orbit-tools/cli: ${msg}\n`);
26
+ process.exit(1);
27
+ }
28
+
29
+ function resolveTarget() {
30
+ const platform = process.platform;
31
+ const arch = process.arch;
32
+ const key = `${platform}-${arch}`;
33
+ const map = {
34
+ 'darwin-arm64': 'aarch64-apple-darwin',
35
+ 'darwin-x64': 'x86_64-apple-darwin',
36
+ 'linux-x64': 'x86_64-unknown-linux-gnu',
37
+ 'linux-arm64': 'aarch64-unknown-linux-gnu',
38
+ };
39
+ const target = map[key];
40
+ if (!target) {
41
+ fail(`unsupported platform/arch: ${key}. Supported: ${Object.keys(map).join(', ')}`);
42
+ }
43
+ return target;
44
+ }
45
+
46
+ function fetchBuffer(url, redirectsLeft = 5) {
47
+ return new Promise((resolve, reject) => {
48
+ https
49
+ .get(url, { headers: { 'user-agent': '@orbit-tools/cli installer' } }, (res) => {
50
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
51
+ if (redirectsLeft <= 0) return reject(new Error(`too many redirects fetching ${url}`));
52
+ res.resume();
53
+ return resolve(fetchBuffer(res.headers.location, redirectsLeft - 1));
54
+ }
55
+ if (res.statusCode !== 200) {
56
+ res.resume();
57
+ return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`));
58
+ }
59
+ const chunks = [];
60
+ res.on('data', (c) => chunks.push(c));
61
+ res.on('end', () => resolve(Buffer.concat(chunks)));
62
+ res.on('error', reject);
63
+ })
64
+ .on('error', reject);
65
+ });
66
+ }
67
+
68
+ function sha256(buf) {
69
+ return crypto.createHash('sha256').update(buf).digest('hex');
70
+ }
71
+
72
+ function parseChecksums(text) {
73
+ const out = {};
74
+ for (const line of text.split('\n')) {
75
+ const m = line.trim().match(/^([a-f0-9]{64})\s+(\S+)$/i);
76
+ if (m) out[m[2]] = m[1].toLowerCase();
77
+ }
78
+ return out;
79
+ }
80
+
81
+ function extractTarGz(archivePath, destDir) {
82
+ const result = spawnSync('tar', ['-xzf', archivePath, '-C', destDir], { stdio: 'inherit' });
83
+ if (result.status !== 0) {
84
+ fail(`tar extraction failed (status ${result.status}). Is 'tar' installed?`);
85
+ }
86
+ }
87
+
88
+ async function main() {
89
+ if (process.env.ORBIT_SKIP_DOWNLOAD === '1') {
90
+ log('ORBIT_SKIP_DOWNLOAD=1 set; skipping binary download.');
91
+ return;
92
+ }
93
+ if (process.env.ORBIT_BINARY) {
94
+ log(`ORBIT_BINARY=${process.env.ORBIT_BINARY} set; skipping download (bin shim will use it directly).`);
95
+ return;
96
+ }
97
+
98
+ const target = resolveTarget();
99
+ const asset = `orbit-${target}.tar.gz`;
100
+ const baseUrl = `https://github.com/${BINARY_REPO}/releases/download/${BINARY_VERSION}`;
101
+ const archiveUrl = `${baseUrl}/${asset}`;
102
+ const checksumUrl = `${baseUrl}/orbit-checksums.txt`;
103
+
104
+ log(`installing orbit ${BINARY_VERSION} for ${target}...`);
105
+
106
+ fs.mkdirSync(BIN_DIR, { recursive: true });
107
+
108
+ let archiveBuf;
109
+ try {
110
+ archiveBuf = await fetchBuffer(archiveUrl);
111
+ } catch (err) {
112
+ fail(`failed to download ${archiveUrl}: ${err.message}`);
113
+ }
114
+
115
+ try {
116
+ const checksumText = (await fetchBuffer(checksumUrl)).toString('utf8');
117
+ const checksums = parseChecksums(checksumText);
118
+ const expected = checksums[asset];
119
+ if (!expected) {
120
+ fail(`checksum entry for ${asset} was not found in orbit-checksums.txt`);
121
+ } else {
122
+ const actual = sha256(archiveBuf);
123
+ if (actual !== expected) {
124
+ fail(`checksum mismatch for ${asset}: expected ${expected}, got ${actual}`);
125
+ }
126
+ }
127
+ } catch (err) {
128
+ fail(`could not verify checksum for ${asset}: ${err.message}`);
129
+ }
130
+
131
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'orbit-cli-'));
132
+ const archivePath = path.join(tmpDir, asset);
133
+ fs.writeFileSync(archivePath, archiveBuf);
134
+ extractTarGz(archivePath, tmpDir);
135
+
136
+ const extractedBinary = path.join(tmpDir, 'orbit');
137
+ if (!fs.existsSync(extractedBinary)) {
138
+ fail(`extracted archive did not contain 'orbit' binary at ${extractedBinary}`);
139
+ }
140
+ fs.copyFileSync(extractedBinary, BIN_PATH);
141
+ fs.chmodSync(BIN_PATH, 0o755);
142
+ fs.rmSync(tmpDir, { recursive: true, force: true });
143
+
144
+ log(`installed orbit binary at ${BIN_PATH}`);
145
+ }
146
+
147
+ main().catch((err) => fail(err && err.message ? err.message : String(err)));