@runar-forge/cli 0.6.1 → 0.7.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 +27 -21
- package/bin/runar.js +33 -9
- package/package.json +10 -17
- package/scripts/install.js +0 -129
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# @runar-forge/cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
for your platform.
|
|
3
|
+
Cross-platform launcher for the `runar` Rust binary.
|
|
5
4
|
|
|
6
5
|
## Install
|
|
7
6
|
|
|
@@ -9,30 +8,37 @@ for your platform.
|
|
|
9
8
|
npm install -g @runar-forge/cli
|
|
10
9
|
```
|
|
11
10
|
|
|
12
|
-
|
|
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.
|
|
11
|
+
## No install scripts
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
This package has **no `postinstall` script** and performs **no network access
|
|
14
|
+
at install time**. The native binary ships as ordinary, npm-integrity-checked
|
|
15
|
+
package content via per-platform optional dependencies, so it installs cleanly
|
|
16
|
+
even with `ignore-scripts=true`:
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- `win32-x64` → `runar-x86_64-pc-windows-msvc`
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @runar-forge/cli --ignore-scripts # still works
|
|
20
|
+
```
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
npm installs only the optional dependency matching your `os` + `cpu`; the rest
|
|
23
|
+
are skipped by npm's platform check. The `runar` launcher (plain JS, run only
|
|
24
|
+
when you invoke it — never at install) resolves the binary from whichever
|
|
25
|
+
platform package was installed and execs it.
|
|
26
|
+
|
|
27
|
+
## Supported platforms
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
| Optional dependency | Host |
|
|
30
|
+
|-------------------------------|----------------|
|
|
31
|
+
| `@runar-forge/cli-linux-x64` | linux / x64 |
|
|
32
|
+
| `@runar-forge/cli-linux-arm64`| linux / arm64 |
|
|
33
|
+
| `@runar-forge/cli-darwin-x64` | macOS / Intel |
|
|
34
|
+
| `@runar-forge/cli-darwin-arm64`| macOS / Apple Silicon |
|
|
35
|
+
| `@runar-forge/cli-win32-x64` | Windows / x64 |
|
|
27
36
|
|
|
28
|
-
|
|
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) |
|
|
37
|
+
For other platforms, build from source — see the workspace root README.
|
|
34
38
|
|
|
35
39
|
## Direct binary download
|
|
36
40
|
|
|
37
|
-
If you prefer not to use npm, grab the binary from the
|
|
38
|
-
page and drop
|
|
41
|
+
If you prefer not to use npm, grab the binary from the
|
|
42
|
+
[GitHub Releases](https://github.com/crlome/runar-forge/releases) page and drop
|
|
43
|
+
it on your PATH, or use `runar update` once installed. The wrapper is pure
|
|
44
|
+
convenience.
|
package/bin/runar.js
CHANGED
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* @package @runar-forge/cli
|
|
4
|
-
* @description
|
|
5
|
-
*
|
|
4
|
+
* @description Launcher: execs the runar binary shipped in the matching
|
|
5
|
+
* per-platform optional dependency (@runar-forge/cli-<os>-<cpu>).
|
|
6
|
+
* No install scripts, no install-time network — the binary is
|
|
7
|
+
* ordinary, npm-integrity-checked package content, so this works
|
|
8
|
+
* with `ignore-scripts=true`.
|
|
6
9
|
*/
|
|
7
10
|
'use strict'
|
|
8
11
|
|
|
9
|
-
const { spawnSync } = require('node:child_process')
|
|
10
12
|
const path = require('node:path')
|
|
11
|
-
const
|
|
13
|
+
const { spawnSync } = require('node:child_process')
|
|
14
|
+
|
|
15
|
+
const PLATFORM_PACKAGES = {
|
|
16
|
+
'linux-x64': '@runar-forge/cli-linux-x64',
|
|
17
|
+
'linux-arm64': '@runar-forge/cli-linux-arm64',
|
|
18
|
+
'darwin-x64': '@runar-forge/cli-darwin-x64',
|
|
19
|
+
'darwin-arm64': '@runar-forge/cli-darwin-arm64',
|
|
20
|
+
'win32-x64': '@runar-forge/cli-win32-x64',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const key = `${process.platform}-${process.arch}`
|
|
24
|
+
const pkg = PLATFORM_PACKAGES[key]
|
|
25
|
+
if (!pkg) {
|
|
26
|
+
console.error(
|
|
27
|
+
`[runar] Unsupported platform: ${key}. `
|
|
28
|
+
+ 'Build from source: https://github.com/crlome/runar-forge',
|
|
29
|
+
)
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
12
32
|
|
|
13
33
|
const binName = process.platform === 'win32' ? 'runar.exe' : 'runar'
|
|
14
|
-
const binPath = path.join(__dirname, binName)
|
|
15
34
|
|
|
16
|
-
|
|
35
|
+
let binPath
|
|
36
|
+
try {
|
|
37
|
+
// Resolve the platform package via its package.json (robust against any
|
|
38
|
+
// `exports` map), then join the binary. Pure resolution — no network.
|
|
39
|
+
binPath = path.join(path.dirname(require.resolve(`${pkg}/package.json`)), binName)
|
|
40
|
+
} catch {
|
|
17
41
|
console.error(
|
|
18
|
-
`[runar]
|
|
19
|
-
+ `
|
|
42
|
+
`[runar] Missing optional dependency ${pkg}. `
|
|
43
|
+
+ `Reinstall without \`--omit=optional\` (and ensure ${key} is supported).`,
|
|
20
44
|
)
|
|
21
|
-
process.exit(
|
|
45
|
+
process.exit(1)
|
|
22
46
|
}
|
|
23
47
|
|
|
24
48
|
const result = spawnSync(binPath, process.argv.slice(2), {
|
package/package.json
CHANGED
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runar-forge/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Cross-platform launcher for the runar Rust binary (no install scripts)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"runar": "bin/runar.js"
|
|
7
7
|
},
|
|
8
|
-
"scripts": {
|
|
9
|
-
"postinstall": "node scripts/install.js"
|
|
10
|
-
},
|
|
11
8
|
"files": [
|
|
12
|
-
"bin"
|
|
13
|
-
"scripts",
|
|
14
|
-
"README.md"
|
|
9
|
+
"bin"
|
|
15
10
|
],
|
|
16
11
|
"engines": {
|
|
17
12
|
"node": ">=18"
|
|
18
13
|
},
|
|
19
|
-
"
|
|
20
|
-
"linux",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"arm64"
|
|
27
|
-
],
|
|
14
|
+
"optionalDependencies": {
|
|
15
|
+
"@runar-forge/cli-linux-x64": "0.7.0",
|
|
16
|
+
"@runar-forge/cli-linux-arm64": "0.7.0",
|
|
17
|
+
"@runar-forge/cli-darwin-x64": "0.7.0",
|
|
18
|
+
"@runar-forge/cli-darwin-arm64": "0.7.0",
|
|
19
|
+
"@runar-forge/cli-win32-x64": "0.7.0"
|
|
20
|
+
},
|
|
28
21
|
"repository": {
|
|
29
22
|
"type": "git",
|
|
30
23
|
"url": "git+https://github.com/crlome/runar-forge.git"
|
package/scripts/install.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
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
|
-
})
|