probbit 0.8.0 → 0.8.2

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
@@ -11,7 +11,7 @@ probbit stats --pretty
11
11
  ```
12
12
 
13
13
  The install step fetches the release archive for your platform from GitHub Releases (macOS arm64 and x86_64, Linux
14
- x86_64 with glibc, Windows x86_64), checks it against the `.sha256` file published beside it and keeps the binary inside
14
+ x86_64 with glibc or musl, Linux ARM64 static musl, Windows x86_64), checks it against the `.sha256` file published beside it and keeps the binary inside
15
15
  this package. No dependencies; Node >= 18. If the install step could not run (`--ignore-scripts`, offline), the first
16
16
  `probbit` call fetches the binary. A checksum mismatch fails the install and installs nothing.
17
17
 
package/bin/probbit.js CHANGED
@@ -16,15 +16,16 @@ async function main() {
16
16
  }
17
17
  const child = spawn(bin, process.argv.slice(2), { stdio: 'inherit' });
18
18
  const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'].filter((s) => process.platform !== 'win32' || s !== 'SIGHUP');
19
- const forward = (s) => { try { child.kill(s); } catch (e) { /* already gone */ } };
20
- for (const s of signals) process.on(s, forward);
19
+ // Node's signal events carry no argument. Bind each signal explicitly instead of accidentally forwarding SIGTERM.
20
+ const handlers = new Map(signals.map(s => [s, () => { try { child.kill(s); } catch (e) { /* already gone */ } }]));
21
+ for (const [s, handler] of handlers) process.on(s, handler);
21
22
  child.on('error', (e) => {
22
23
  process.stderr.write(`probbit: cannot run ${bin}: ${e.message}\n`);
23
24
  process.exit(127);
24
25
  });
25
26
  child.on('exit', (code, signal) => {
26
27
  if (signal) {
27
- for (const s of signals) process.removeListener(s, forward);
28
+ for (const [s, handler] of handlers) process.removeListener(s, handler);
28
29
  process.exitCode = 128 + (os.constants.signals[signal] || 0); // if the signal is ignored here (SIGPIPE)
29
30
  process.kill(process.pid, signal); // die the same way, so the shell sees 128 + n
30
31
  return;
package/install.js CHANGED
@@ -22,6 +22,7 @@ const TARGETS = {
22
22
  'darwin-arm64': 'aarch64-apple-darwin',
23
23
  'darwin-x64': 'x86_64-apple-darwin',
24
24
  'linux-x64': 'x86_64-unknown-linux-gnu',
25
+ 'linux-arm64': 'aarch64-unknown-linux-musl',
25
26
  'win32-x64': 'x86_64-pc-windows-msvc',
26
27
  'win32-arm64': 'x86_64-pc-windows-msvc', // x64 emulation on Windows on Arm
27
28
  };
@@ -34,7 +35,7 @@ function binaryPath() {
34
35
  class ChecksumError extends Error {}
35
36
 
36
37
  async function get(url) {
37
- const res = await fetch(url, { redirect: 'follow' });
38
+ const res = await fetch(url, { redirect: 'follow', signal: AbortSignal.timeout(30000) });
38
39
  if (!res.ok) throw new Error(`GET ${url}: HTTP ${res.status}`);
39
40
  return Buffer.from(await res.arrayBuffer());
40
41
  }
@@ -49,7 +50,8 @@ function place(src, dest) {
49
50
  fs.renameSync(tmp, dest);
50
51
  } catch (e) {
51
52
  fs.rmSync(tmp, { force: true });
52
- if (!fs.existsSync(dest)) throw e; // another process put it there first
53
+ // Only forgive an actual identical concurrent install, not an old binary left behind by a permission/rename error.
54
+ if (!fs.existsSync(dest) || !fs.readFileSync(src).equals(fs.readFileSync(dest))) throw e;
53
55
  }
54
56
  }
55
57
 
@@ -62,13 +64,18 @@ async function install(log = (m) => process.stderr.write(`${m}\n`)) {
62
64
  log(`probbit: using ${src} (PROBBIT_BINARY)`);
63
65
  return dest;
64
66
  }
65
- const target = env.PROBBIT_TARGET || TARGETS[`${process.platform}-${process.arch}`];
67
+ const glibc = process.platform === 'linux' && process.report && process.report.getReport().header.glibcVersionRuntime;
68
+ const detected = process.platform === 'linux' && process.arch === 'x64' && !glibc
69
+ ? 'x86_64-unknown-linux-musl' : TARGETS[`${process.platform}-${process.arch}`];
70
+ const target = env.PROBBIT_TARGET || detected;
66
71
  if (!target) {
67
72
  throw new Error(`no prebuilt probbit for ${process.platform}-${process.arch}; build one (cargo build --release -p probbit-cli) `
68
73
  + 'and reinstall with PROBBIT_BINARY=/path/to/probbit');
69
74
  }
70
75
  let tag = env.PROBBIT_VERSION || `v${pkg.version}`;
71
76
  if (!tag.startsWith('v')) tag = `v${tag}`;
77
+ if (!/^v[A-Za-z0-9][A-Za-z0-9._+-]*$/.test(tag)) throw new Error(`invalid release version: ${tag}`);
78
+ if (!/^[A-Za-z0-9_-]+$/.test(target)) throw new Error(`invalid target: ${target}`);
72
79
  const base = (env.PROBBIT_DOWNLOAD_BASE || `https://github.com/${REPO}/releases/download`).replace(/\/+$/, '');
73
80
  const zip = target.includes('windows');
74
81
  const name = `probbit-${tag}-${target}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "probbit",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "probbit, a virtual p-bit processor for joint decisions under hard rules: installs the prebuilt probbit CLI (JSON in, JSON out).",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {