whitemagic-mcp 9.2.8 → 9.2.9

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 -3
  2. package/bin/lib.mjs +57 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -43,7 +43,7 @@ opencode) at:
43
43
  Or try it directly:
44
44
 
45
45
  ```bash
46
- npx whitemagic-mcp --version # wm 9.2.8
46
+ npx whitemagic-mcp --version # wm 9.2.9
47
47
  npx whitemagic-mcp doctor # environment health check
48
48
  ```
49
49
 
@@ -54,8 +54,11 @@ release tag (the `v9` tag line). Pin a different release with
54
54
 
55
55
  ## Platforms
56
56
 
57
- Linux x86-64 (static musl), macOS arm64/x64, Windows x64. No asset for
58
- your platform? Build from source:
57
+ Linux x86-64 (static musl), Linux arm64 (static musl), and macOS arm64 are
58
+ install-gated. macOS x64 and Windows x64 binaries are published, but their
59
+ install paths are not gated yet. Downloads prefer the compressed `.gz`
60
+ distributable when the release ships one (~58% smaller) and fall back to the
61
+ raw binary otherwise. No asset for your platform? Build from source:
59
62
  https://github.com/lbailey94/whitemagic#install
60
63
 
61
64
  ## Privacy
package/bin/lib.mjs CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  } from "node:fs";
21
21
  import { homedir, platform, arch, tmpdir } from "node:os";
22
22
  import { join } from "node:path";
23
+ import { gunzipSync } from "node:zlib";
23
24
 
24
25
  export const REPO = "lbailey94/whitemagic";
25
26
  const SHA256_RE = /^[0-9a-f]{64}$/i;
@@ -120,10 +121,32 @@ export async function fetchTo(url, dest, fetchImpl) {
120
121
  writeFileSync(dest, Buffer.from(await res.arrayBuffer()));
121
122
  }
122
123
 
124
+ /**
125
+ * Parse a release `.sha256` sidecar (first whitespace-delimited token) and
126
+ * refuse anything that is not a well-formed digest.
127
+ */
128
+ function parseDigestFile(path, label) {
129
+ const expected = (readFileSync(path, "utf8").trim().split(/\s+/)[0] ?? "").toLowerCase();
130
+ if (!SHA256_RE.test(expected)) {
131
+ throw new Error(`release checksum for ${label} is malformed — refusing to install it`);
132
+ }
133
+ return expected;
134
+ }
135
+
136
+ function checksumMismatch(label, expected, actual) {
137
+ return new Error(
138
+ `checksum mismatch for ${label} (expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…) — the download may be corrupted; retry`,
139
+ );
140
+ }
141
+
123
142
  /**
124
143
  * Ensure a verified `wm` binary for this platform exists in the cache and
125
144
  * return its path. Fresh downloads go temp -> checksum -> chmod -> rename;
126
145
  * a cache entry that fails re-verification is replaced (self-healing).
146
+ *
147
+ * The launcher prefers the gzipped distributable (~58% smaller; published
148
+ * for Linux/macOS) exactly like `scripts/install.sh` does. Windows `.exe`
149
+ * assets ship raw, and releases that predate the `.gz` fall back on a 404.
127
150
  */
128
151
  export async function ensureBinary({
129
152
  fetchImpl = fetch,
@@ -155,22 +178,45 @@ export async function ensureBinary({
155
178
  const tmp = mkdtempSync(join(binDir, ".download-"));
156
179
  try {
157
180
  const tmpBin = join(tmp, asset);
158
- const tmpSha = join(tmp, `${asset}.sha256`);
159
- await fetchTo(`${BASE_URL(resolvedTag)}/${asset}`, tmpBin, fetchImpl);
160
- await fetchTo(`${BASE_URL(resolvedTag)}/${asset}.sha256`, tmpSha, fetchImpl);
161
- const expected = (readFileSync(tmpSha, "utf8").trim().split(/\s+/)[0] ?? "").toLowerCase();
162
- if (!SHA256_RE.test(expected)) {
163
- throw new Error(`release checksum for ${asset} is malformed — refusing to install it`);
181
+ let compressed = false;
182
+ if (!asset.endsWith(".exe")) {
183
+ try {
184
+ await fetchTo(`${BASE_URL(resolvedTag)}/${asset}.gz`, join(tmp, `${asset}.gz`), fetchImpl);
185
+ await fetchTo(
186
+ `${BASE_URL(resolvedTag)}/${asset}.gz.sha256`,
187
+ join(tmp, `${asset}.gz.sha256`),
188
+ fetchImpl,
189
+ );
190
+ compressed = true;
191
+ } catch (err) {
192
+ if (!String(err?.message ?? "").includes("HTTP 404")) throw err;
193
+ }
164
194
  }
165
- const actual = digestFile(tmpBin);
166
- if (actual !== expected) {
167
- throw new Error(
168
- `checksum mismatch for ${asset} (expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…) — the download may be corrupted; retry`,
195
+ if (compressed) {
196
+ const gzPath = join(tmp, `${asset}.gz`);
197
+ const expectedGz = parseDigestFile(join(tmp, `${asset}.gz.sha256`), `${asset}.gz`);
198
+ const actualGz = digestFile(gzPath);
199
+ if (actualGz !== expectedGz) {
200
+ throw checksumMismatch(`${asset}.gz`, expectedGz, actualGz);
201
+ }
202
+ writeFileSync(tmpBin, gunzipSync(readFileSync(gzPath)));
203
+ log(`whitemagic-mcp: using the compressed distributable (${asset}.gz)`);
204
+ } else {
205
+ await fetchTo(`${BASE_URL(resolvedTag)}/${asset}`, tmpBin, fetchImpl);
206
+ await fetchTo(
207
+ `${BASE_URL(resolvedTag)}/${asset}.sha256`,
208
+ join(tmp, `${asset}.sha256`),
209
+ fetchImpl,
169
210
  );
211
+ const expected = parseDigestFile(join(tmp, `${asset}.sha256`), asset);
212
+ const actual = digestFile(tmpBin);
213
+ if (actual !== expected) {
214
+ throw checksumMismatch(asset, expected, actual);
215
+ }
170
216
  }
171
217
  chmodSync(tmpBin, 0o755);
172
218
  renameSync(tmpBin, cached);
173
- writeFileSync(sidecarFor(cached), `${expected}\n`);
219
+ writeFileSync(sidecarFor(cached), `${digestFile(cached)}\n`);
174
220
  return cached;
175
221
  } finally {
176
222
  rmSync(tmp, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whitemagic-mcp",
3
- "version": "9.2.8",
3
+ "version": "9.2.9",
4
4
  "description": "Local-first persistent memory and session continuity for AI coding agents (Claude Code, Cursor, Codex), over MCP - one static Rust binary, no telemetry by default, verifiable handoffs.",
5
5
  "license": "MIT",
6
6
  "bin": {