@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 CHANGED
@@ -1,7 +1,6 @@
1
1
  # @runar-forge/cli
2
2
 
3
- Thin npm wrapper that downloads the `runar` Rust binary appropriate
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
- 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.
11
+ ## No install scripts
16
12
 
17
- ## Supported platforms
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
- - `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`
18
+ ```bash
19
+ npm install -g @runar-forge/cli --ignore-scripts # still works
20
+ ```
23
21
 
24
- For other platforms, build from source: see the workspace root README.
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
- ## Configuration
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
- | 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) |
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 GitHub Releases
38
- page and drop it on your PATH. The wrapper is pure convenience.
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 Shim: execs the platform-native runar binary dropped
5
- * into this directory by scripts/install.js.
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 fs = require('node:fs')
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
- if (!fs.existsSync(binPath)) {
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] Binary not found at ${binPath}. `
19
- + `Re-run \`npm install -g @runar-forge/cli\` or check postinstall output.`,
42
+ `[runar] Missing optional dependency ${pkg}. `
43
+ + `Reinstall without \`--omit=optional\` (and ensure ${key} is supported).`,
20
44
  )
21
- process.exit(127)
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.6.1",
4
- "description": "npm wrapper that downloads the runar Rust binary for your platform",
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
- "os": [
20
- "linux",
21
- "darwin",
22
- "win32"
23
- ],
24
- "cpu": [
25
- "x64",
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"
@@ -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
- })