@runar-forge/cli 0.6.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 ADDED
@@ -0,0 +1,38 @@
1
+ # @runar-forge/cli
2
+
3
+ Thin npm wrapper that downloads the `runar` Rust binary appropriate
4
+ for your platform.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ npm install -g @runar-forge/cli
10
+ ```
11
+
12
+ On install, `scripts/install.js` downloads the matching release asset
13
+ from GitHub Releases, extracts it, and places `runar` (or `runar.exe`
14
+ on Windows) under `bin/`. The `bin` entry in `package.json` then links
15
+ `runar` into your global PATH.
16
+
17
+ ## Supported platforms
18
+
19
+ - `linux-x64` → `runar-x86_64-unknown-linux-gnu`
20
+ - `linux-arm64` → `runar-aarch64-unknown-linux-gnu`
21
+ - `darwin-arm64` → `runar-aarch64-apple-darwin`
22
+ - `win32-x64` → `runar-x86_64-pc-windows-msvc`
23
+
24
+ For other platforms, build from source: see the workspace root README.
25
+
26
+ ## Configuration
27
+
28
+ | Env var | Default | Purpose |
29
+ |---|---|---|
30
+ | `RUNAR_RELEASE_REPO` | `crlome/runar-forge` | GitHub `owner/repo` to fetch from |
31
+ | `RUNAR_RELEASE_TAG` | `v<pkg.version>` | Release tag to fetch |
32
+ | `RUNAR_RELEASE_BASE_URL` | computed from repo+tag | Full base URL override (mirrors / forks) |
33
+ | `RUNAR_SKIP_DOWNLOAD` | unset | Set to `1` to skip postinstall (CI / sandboxes) |
34
+
35
+ ## Direct binary download
36
+
37
+ If you prefer not to use npm, grab the binary from the GitHub Releases
38
+ page and drop it on your PATH. The wrapper is pure convenience.
package/bin/runar.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @package @runar-forge/cli
4
+ * @description Shim: execs the platform-native runar binary dropped
5
+ * into this directory by scripts/install.js.
6
+ */
7
+ 'use strict'
8
+
9
+ const { spawnSync } = require('node:child_process')
10
+ const path = require('node:path')
11
+ const fs = require('node:fs')
12
+
13
+ const binName = process.platform === 'win32' ? 'runar.exe' : 'runar'
14
+ const binPath = path.join(__dirname, binName)
15
+
16
+ if (!fs.existsSync(binPath)) {
17
+ console.error(
18
+ `[runar] Binary not found at ${binPath}. `
19
+ + `Re-run \`npm install -g @runar-forge/cli\` or check postinstall output.`,
20
+ )
21
+ process.exit(127)
22
+ }
23
+
24
+ const result = spawnSync(binPath, process.argv.slice(2), {
25
+ stdio: 'inherit',
26
+ windowsHide: true,
27
+ })
28
+ if (result.error) {
29
+ console.error(`[runar] ${result.error.message}`)
30
+ process.exit(1)
31
+ }
32
+ process.exit(result.status ?? 0)
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@runar-forge/cli",
3
+ "version": "0.6.1",
4
+ "description": "npm wrapper that downloads the runar Rust binary for your platform",
5
+ "bin": {
6
+ "runar": "bin/runar.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/install.js"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "scripts",
14
+ "README.md"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "os": [
20
+ "linux",
21
+ "darwin",
22
+ "win32"
23
+ ],
24
+ "cpu": [
25
+ "x64",
26
+ "arm64"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/crlome/runar-forge.git"
31
+ },
32
+ "license": "MIT"
33
+ }
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @package @runar-forge/cli
4
+ * @description Postinstall: downloads the platform-appropriate `runar`
5
+ * Rust binary from GitHub Releases and places it at
6
+ * bin/runar (or runar.exe).
7
+ */
8
+ 'use strict'
9
+
10
+ const fs = require('node:fs')
11
+ const path = require('node:path')
12
+ const https = require('node:https')
13
+ const zlib = require('node:zlib')
14
+ const { pipeline } = require('node:stream/promises')
15
+ const { spawnSync } = require('node:child_process')
16
+
17
+ const pkg = require('../package.json')
18
+
19
+ const DEFAULT_REPO = 'crlome/runar-forge'
20
+ const REPO = process.env.RUNAR_RELEASE_REPO || DEFAULT_REPO
21
+ const TAG = process.env.RUNAR_RELEASE_TAG || `v${pkg.version}`
22
+ const BASE = process.env.RUNAR_RELEASE_BASE_URL
23
+ || `https://github.com/${REPO}/releases/download/${TAG}`
24
+
25
+ const TARGETS = {
26
+ 'linux-x64': { asset: 'runar-x86_64-unknown-linux-gnu.tar.gz', archive: 'tar.gz' },
27
+ 'linux-arm64': { asset: 'runar-aarch64-unknown-linux-gnu.tar.gz', archive: 'tar.gz' },
28
+ 'darwin-arm64': { asset: 'runar-aarch64-apple-darwin.tar.gz', archive: 'tar.gz' },
29
+ 'darwin-x64': { asset: 'runar-x86_64-apple-darwin.tar.gz', archive: 'tar.gz' },
30
+ 'win32-x64': { asset: 'runar-x86_64-pc-windows-msvc.zip', archive: 'zip' },
31
+ }
32
+
33
+ function resolveTarget() {
34
+ const key = `${process.platform}-${process.arch}`
35
+ const target = TARGETS[key]
36
+ if (!target) {
37
+ throw new Error(
38
+ `Unsupported platform: ${key}. `
39
+ + `Supported: ${Object.keys(TARGETS).join(', ')}. `
40
+ + `Build from source: https://github.com/${REPO}`,
41
+ )
42
+ }
43
+ return target
44
+ }
45
+
46
+ function download(url, dest, redirects = 5) {
47
+ return new Promise((resolve, reject) => {
48
+ https
49
+ .get(url, (res) => {
50
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
51
+ if (redirects <= 0) return reject(new Error('Too many redirects'))
52
+ res.resume()
53
+ return resolve(download(res.headers.location, dest, redirects - 1))
54
+ }
55
+ if (res.statusCode !== 200) {
56
+ res.resume()
57
+ return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`))
58
+ }
59
+ pipeline(res, fs.createWriteStream(dest)).then(resolve, reject)
60
+ })
61
+ .on('error', reject)
62
+ })
63
+ }
64
+
65
+ function extractTarGz(archivePath, destDir) {
66
+ const r = spawnSync('tar', ['-xzf', archivePath, '-C', destDir], { stdio: 'inherit' })
67
+ if (r.status !== 0) throw new Error(`tar exited with ${r.status}`)
68
+ }
69
+
70
+ function extractZip(archivePath, destDir) {
71
+ if (process.platform === 'win32') {
72
+ const r = spawnSync('powershell', [
73
+ '-NoProfile', '-Command',
74
+ `Expand-Archive -LiteralPath '${archivePath}' -DestinationPath '${destDir}' -Force`,
75
+ ], { stdio: 'inherit' })
76
+ if (r.status !== 0) throw new Error(`Expand-Archive exited with ${r.status}`)
77
+ } else {
78
+ const r = spawnSync('unzip', ['-o', archivePath, '-d', destDir], { stdio: 'inherit' })
79
+ if (r.status !== 0) throw new Error(`unzip exited with ${r.status}`)
80
+ }
81
+ }
82
+
83
+ async function main() {
84
+ if (process.env.RUNAR_SKIP_DOWNLOAD === '1') {
85
+ console.log('[runar] RUNAR_SKIP_DOWNLOAD=1, skipping binary download.')
86
+ return
87
+ }
88
+ const { asset, archive } = resolveTarget()
89
+ const url = `${BASE}/${asset}`
90
+ const binDir = path.join(__dirname, '..', 'bin')
91
+ fs.mkdirSync(binDir, { recursive: true })
92
+ const archivePath = path.join(binDir, asset)
93
+
94
+ console.log(`[runar] Downloading ${asset} from ${url}`)
95
+ try {
96
+ await download(url, archivePath)
97
+ } catch (err) {
98
+ console.error(`[runar] Download failed: ${err.message}`)
99
+ console.error(
100
+ '[runar] Override RUNAR_RELEASE_REPO, RUNAR_RELEASE_TAG, or '
101
+ + 'RUNAR_RELEASE_BASE_URL to fetch from a different location.',
102
+ )
103
+ process.exit(1)
104
+ }
105
+
106
+ try {
107
+ if (archive === 'tar.gz') extractTarGz(archivePath, binDir)
108
+ else extractZip(archivePath, binDir)
109
+ } catch (err) {
110
+ console.error(`[runar] Extract failed: ${err.message}`)
111
+ process.exit(1)
112
+ } finally {
113
+ try { fs.unlinkSync(archivePath) } catch (_) {}
114
+ }
115
+
116
+ const isWin = process.platform === 'win32'
117
+ const finalName = isWin ? 'runar.exe' : 'runar'
118
+ const finalPath = path.join(binDir, finalName)
119
+ if (!fs.existsSync(finalPath)) {
120
+ throw new Error(`Expected binary not found at ${finalPath} after extraction`)
121
+ }
122
+ if (!isWin) fs.chmodSync(finalPath, 0o755)
123
+ console.log(`[runar] Installed ${finalName} at ${finalPath}`)
124
+ }
125
+
126
+ main().catch((err) => {
127
+ console.error(`[runar] ${err.message}`)
128
+ process.exit(1)
129
+ })