* 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:
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { spawnSync } from 'child_process';
|
||||
import { checkBinaryPlatformCompatibility } from '../plugin/scripts/smart-install.js';
|
||||
|
||||
/**
|
||||
* Smart Install Script Tests
|
||||
@@ -237,3 +238,119 @@ describe('smart-install stdout JSON output (#1253)', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests for checkBinaryPlatformCompatibility() (#1547).
|
||||
*
|
||||
* The bundled plugin/scripts/claude-mem binary is macOS arm64 only.
|
||||
* On Linux/Windows it cannot execute and hooks fail silently.
|
||||
* These tests call the production function directly, mocking process.platform
|
||||
* and passing controlled binary paths to verify Mach-O detection behaviour.
|
||||
*/
|
||||
describe('smart-install binary platform compatibility (#1547)', () => {
|
||||
let testDir: string;
|
||||
let originalPlatform: PropertyDescriptor | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
testDir = join(tmpdir(), `claude-mem-binary-compat-test-${process.pid}`);
|
||||
mkdirSync(testDir, { recursive: true });
|
||||
originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(testDir, { recursive: true, force: true });
|
||||
// Restore process.platform
|
||||
if (originalPlatform) {
|
||||
Object.defineProperty(process, 'platform', originalPlatform);
|
||||
}
|
||||
});
|
||||
|
||||
function setPlatform(value: string) {
|
||||
Object.defineProperty(process, 'platform', { value, configurable: true });
|
||||
}
|
||||
|
||||
it('should detect native arm64/x86_64 Mach-O binary and warn on Linux', () => {
|
||||
// Real macOS arm64 binary header: bytes CF FA ED FE (MH_MAGIC_64)
|
||||
const binaryPath = join(testDir, 'claude-mem');
|
||||
writeFileSync(binaryPath, Buffer.from([0xCF, 0xFA, 0xED, 0xFE, 0x0C, 0x00, 0x00, 0x01]));
|
||||
|
||||
const stderrLines: string[] = [];
|
||||
const originalError = console.error;
|
||||
console.error = (...args: any[]) => stderrLines.push(args.join(' '));
|
||||
|
||||
setPlatform('linux');
|
||||
try {
|
||||
checkBinaryPlatformCompatibility(binaryPath);
|
||||
} finally {
|
||||
console.error = originalError;
|
||||
}
|
||||
|
||||
expect(stderrLines.some(l => l.includes('macOS-only'))).toBe(true);
|
||||
expect(stderrLines.some(l => l.includes('linux'))).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect byte-swapped Mach-O binary and warn on Linux', () => {
|
||||
// Byte-swapped 64-bit Mach-O: bytes FE ED FA CF (MH_CIGAM_64)
|
||||
const binaryPath = join(testDir, 'claude-mem-swapped');
|
||||
writeFileSync(binaryPath, Buffer.from([0xFE, 0xED, 0xFA, 0xCF, 0x01, 0x00, 0x00, 0x0C]));
|
||||
|
||||
const stderrLines: string[] = [];
|
||||
const originalError = console.error;
|
||||
console.error = (...args: any[]) => stderrLines.push(args.join(' '));
|
||||
|
||||
setPlatform('linux');
|
||||
try {
|
||||
checkBinaryPlatformCompatibility(binaryPath);
|
||||
} finally {
|
||||
console.error = originalError;
|
||||
}
|
||||
|
||||
expect(stderrLines.some(l => l.includes('macOS-only'))).toBe(true);
|
||||
});
|
||||
|
||||
it('should NOT warn for an ELF binary (Linux native) on Linux', () => {
|
||||
// ELF magic: 0x7F 'E' 'L' 'F'
|
||||
const binaryPath = join(testDir, 'claude-mem-elf');
|
||||
writeFileSync(binaryPath, Buffer.from([0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00]));
|
||||
|
||||
const stderrLines: string[] = [];
|
||||
const originalError = console.error;
|
||||
console.error = (...args: any[]) => stderrLines.push(args.join(' '));
|
||||
|
||||
setPlatform('linux');
|
||||
try {
|
||||
checkBinaryPlatformCompatibility(binaryPath);
|
||||
} finally {
|
||||
console.error = originalError;
|
||||
}
|
||||
|
||||
expect(stderrLines.some(l => l.includes('macOS-only'))).toBe(false);
|
||||
});
|
||||
|
||||
it('should not throw when binary path does not exist', () => {
|
||||
const binaryPath = join(testDir, 'nonexistent-claude-mem');
|
||||
expect(existsSync(binaryPath)).toBe(false);
|
||||
|
||||
setPlatform('linux');
|
||||
expect(() => checkBinaryPlatformCompatibility(binaryPath)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should skip the check entirely when platform is darwin', () => {
|
||||
// Write a Mach-O binary — on macOS the check returns early, so no warning
|
||||
const binaryPath = join(testDir, 'claude-mem');
|
||||
writeFileSync(binaryPath, Buffer.from([0xCF, 0xFA, 0xED, 0xFE, 0x0C, 0x00, 0x00, 0x01]));
|
||||
|
||||
const stderrLines: string[] = [];
|
||||
const originalError = console.error;
|
||||
console.error = (...args: any[]) => stderrLines.push(args.join(' '));
|
||||
|
||||
setPlatform('darwin');
|
||||
try {
|
||||
checkBinaryPlatformCompatibility(binaryPath);
|
||||
} finally {
|
||||
console.error = originalError;
|
||||
}
|
||||
|
||||
expect(stderrLines.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user