fix: resolve Setup hook broken reference and warn on macOS-only binary (#1547) (#1696)

* fix: resolve Setup hook broken reference and warn on macOS-only binary (#1547)

On Linux ARM64, the plugin silently failed because:
1. The Setup hook called setup.sh which was removed; the hook exited 127
   (file not found), causing the plugin to appear uninstalled.
2. The committed plugin/scripts/claude-mem binary is macOS arm64 only;
   no warning was shown when it could not execute on other platforms.

Fix the Setup hook to call smart-install.js (the current setup mechanism)
and add checkBinaryPlatformCompatibility() to smart-install.js, which reads
the Mach-O magic bytes from the bundled binary and warns users on non-macOS
platforms that the JS fallback (bun-runner.js + worker-service.cjs) is active.

Generated by Claude Code
Vibe coded by ousamabenyounes

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: close fd in finally block, strengthen smart-install tests to use production function

- Wrap openSync/readSync in checkBinaryPlatformCompatibility with a finally block so the file descriptor is always closed even if readSync throws
- Export checkBinaryPlatformCompatibility with an optional binaryPath param for testability
- Refactor Mach-O detection tests to call the production function directly, mocking process.platform and passing controlled binary paths, eliminating duplicated inline logic
- Strengthen plugin-distribution test to assert at least one command hook exists before checking for smart-install.js, preventing vacuous pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Ben Younes
2026-04-15 09:58:29 +02:00
committed by GitHub
parent f97c50bfb9
commit 4538e686ad
4 changed files with 207 additions and 2 deletions
+54 -1
View File
@@ -9,7 +9,7 @@
* for both cache and marketplace installs), falling back to script location
* and legacy paths.
*/
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { existsSync, readFileSync, writeFileSync, openSync, readSync, closeSync } from 'fs';
import { execSync, spawnSync } from 'child_process';
import { join, dirname } from 'path';
import { homedir } from 'os';
@@ -490,6 +490,56 @@ function verifyCriticalModules() {
return true;
}
// Mach-O 64-bit magic values as seen when reading the first 4 file bytes with readUInt32LE.
// Native arm64/x86_64 Mach-O files start with bytes [CF FA ED FE]; readUInt32LE gives 0xFEEDFACF.
// Byte-swapped (big-endian) Mach-O files start with bytes [FE ED FA CF]; readUInt32LE gives 0xCFFAEDFE.
const MACHO_MAGIC_NATIVE = 0xFEEDFACF; // native 64-bit (arm64/x86_64) — file bytes CF FA ED FE
const MACHO_MAGIC_SWAPPED = 0xCFFAEDFE; // byte-swapped 64-bit — file bytes FE ED FA CF
/**
* Warn when the bundled claude-mem binary cannot run on the current platform.
*
* The committed binary (plugin/scripts/claude-mem) is compiled for macOS arm64.
* On Linux or Windows it produces "Exec format error" and silently fails.
* This check surfaces the incompatibility at install time so users know why
* the binary path doesn't work, and confirms the JS fallback (bun-runner.js →
* worker-service.cjs) is active and covers all functionality.
*
* Fixes #1547 — Plugin silently fails on Linux ARM64.
*/
export function checkBinaryPlatformCompatibility(binaryPath = join(ROOT, 'scripts', 'claude-mem')) {
if (!existsSync(binaryPath)) {
return; // Binary absent — nothing to check (e.g. after npm install which excludes it)
}
// The binary only matters on non-macOS platforms; on macOS it works correctly.
if (process.platform === 'darwin') {
return;
}
// Read the first 4 bytes to identify the binary format.
let fd;
try {
const buf = Buffer.alloc(4);
fd = openSync(binaryPath, 'r');
readSync(fd, buf, 0, 4, 0);
const magic = buf.readUInt32LE(0);
if (magic === MACHO_MAGIC_NATIVE || magic === MACHO_MAGIC_SWAPPED) {
console.error('⚠️ Platform notice: The bundled claude-mem binary is macOS-only.');
console.error(` Current platform: ${process.platform} ${process.arch}`);
console.error(' The binary will not execute on this platform.');
console.error(' Plugin functionality is provided by the JS fallback');
console.error(' (bun-runner.js → worker-service.cjs) which works on all platforms.');
}
} catch {
// Unreadable binary — not critical, skip silently
} finally {
if (fd !== undefined) closeSync(fd);
}
}
// Main execution
try {
// Step 1: Ensure Bun is installed and meets minimum version (REQUIRED)
@@ -582,6 +632,9 @@ try {
// Step 4: Install CLI to PATH
installCLI();
// Step 5: Warn if the bundled native binary is incompatible with this platform
checkBinaryPlatformCompatibility();
// Output valid JSON for Claude Code hook contract
console.log(JSON.stringify({ continue: true, suppressOutput: true }));
} catch (e) {