@fusion.dev/helix-cli 0.24.1 → 0.25.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.
Files changed (3) hide show
  1. package/README.md +6 -0
  2. package/bin.mjs +50 -4
  3. package/package.json +8 -1
package/README.md CHANGED
@@ -7,6 +7,12 @@ derives themes, scaffolds a project, and serves the derivation to an agent.
7
7
  npm install --save-dev @fusion.dev/helix-cli
8
8
  ```
9
9
 
10
+ The command is a native binary, and npm installs the build for your machine
11
+ beside this package: macOS and Linux on Arm and x86-64, and Windows on x86-64.
12
+ An install that skips optional dependencies skips it too, and `helix` then names
13
+ the package it's missing. To start a project rather than add Helix to one, use
14
+ `npm create @fusion.dev/helix-app`.
15
+
10
16
  ```sh
11
17
  helix component check # the CI shape: nothing printed on success
12
18
  helix component audit # every rule and what it found
package/bin.mjs CHANGED
@@ -15,9 +15,11 @@
15
15
  * **Resolution order, and each step is there for a reason.** `HELIX_BIN` first,
16
16
  * because a caller that knows better should not have to argue. Then the cargo
17
17
  * target directory, release before debug, honoring `CARGO_TARGET_DIR` because a
18
- * shared target is common and guessing `./target` would miss it. Then whatever
19
- * is on `PATH`, which is what an installed binary looks like. Only then a
20
- * build, and only when cargo is present.
18
+ * shared target is common and guessing `./target` would miss it. Then the
19
+ * binary npm installed beside this, which is what a consumer has: after the
20
+ * target, so a checkout runs what it built rather than a binary a release once
21
+ * placed. Then whatever is on `PATH`. Only then a build, and only in this
22
+ * repository, the one place there is a crate to build.
21
23
  *
22
24
  * **A build is a fallback and not the plan.** It happens once, prints that it
23
25
  * is happening, and a CI pipeline that has already run `cargo build` never
@@ -27,6 +29,7 @@
27
29
  */
28
30
  import { spawnSync } from 'node:child_process'
29
31
  import { existsSync, realpathSync, statSync } from 'node:fs'
32
+ import { createRequire } from 'node:module'
30
33
  import { delimiter, dirname, join, resolve } from 'node:path'
31
34
  import { fileURLToPath } from 'node:url'
32
35
 
@@ -57,6 +60,34 @@ const built = () =>
57
60
  .sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs)
58
61
  .at(0)
59
62
 
63
+ /**
64
+ * The platform package npm installed for this machine, named as they are
65
+ * published: `@fusion.dev/helix-cli-darwin-arm64` and the rest.
66
+ */
67
+ const PLATFORM = `@fusion.dev/helix-cli-${process.platform}-${process.arch}`
68
+
69
+ /**
70
+ * The binary in this machine's platform package, or undefined.
71
+ *
72
+ * **One of several optional dependencies, and npm installs only the one whose
73
+ * `os` and `cpu` match**, which is how Biome and esbuild ship a native binary
74
+ * without a download of their own. Resolved as a module, so it is found
75
+ * wherever the package manager put it, hoisted or not.
76
+ */
77
+ const packaged = () => {
78
+ let manifest
79
+ try {
80
+ manifest = createRequire(import.meta.url).resolve(`${PLATFORM}/package.json`)
81
+ } catch {
82
+ return undefined
83
+ }
84
+ const binary = join(dirname(manifest), NAME)
85
+ return existsSync(binary) ? binary : undefined
86
+ }
87
+
88
+ /** Whether this is the repository's own copy, where there is a crate to build. */
89
+ const checkout = existsSync(join(CRATE, 'Cargo.toml'))
90
+
60
91
  /** Whether cargo is on the path, asked once and cheaply. */
61
92
  const hasCargo = () => spawnSync('cargo', ['--version'], { stdio: 'ignore' }).status === 0
62
93
 
@@ -124,7 +155,7 @@ const run = (binary) => {
124
155
  process.exit(status ?? 70)
125
156
  }
126
157
 
127
- const found = process.env.HELIX_BIN ?? built()
158
+ const found = process.env.HELIX_BIN ?? built() ?? packaged()
128
159
  if (found && existsSync(found)) {
129
160
  run(found)
130
161
  }
@@ -136,6 +167,21 @@ if (installed) {
136
167
  run(installed)
137
168
  }
138
169
 
170
+ /* Installed from the registry, with no platform package for this machine. A
171
+ build would be `cargo build` in somebody else's project, for a crate that is
172
+ not in it. */
173
+ if (!checkout) {
174
+ console.error(
175
+ `helix: no binary for ${process.platform} ${process.arch}.\n\n` +
176
+ ` It comes in \`${PLATFORM}\`, an optional dependency of\n` +
177
+ ' `@fusion.dev/helix-cli`, and it is not installed. Either this machine is not\n' +
178
+ ' one there is a build for, or the install skipped optional dependencies\n' +
179
+ ' (`--omit=optional`, `--no-optional`), in which case install again without it.\n' +
180
+ ' `HELIX_BIN` names a binary to run instead.',
181
+ )
182
+ process.exit(69)
183
+ }
184
+
139
185
  if (!hasCargo()) {
140
186
  console.error(
141
187
  'helix: no binary and no cargo.\n\n' +
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix-cli",
3
3
  "description": "The Helix command line, for a workspace that reaches it through npm.",
4
- "version": "0.24.1",
4
+ "version": "0.25.0",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -28,6 +28,13 @@
28
28
  "scaffold",
29
29
  "theme"
30
30
  ],
31
+ "optionalDependencies": {
32
+ "@fusion.dev/helix-cli-darwin-arm64": "0.25.0",
33
+ "@fusion.dev/helix-cli-darwin-x64": "0.25.0",
34
+ "@fusion.dev/helix-cli-linux-arm64": "0.25.0",
35
+ "@fusion.dev/helix-cli-linux-x64": "0.25.0",
36
+ "@fusion.dev/helix-cli-win32-x64": "0.25.0"
37
+ },
31
38
  "publishConfig": {
32
39
  "access": "restricted"
33
40
  }