/** * Native addon loader and bindings. * * Types are auto-generated by napi-rs in `native/index.d.ts`. */ const fs = require("node:fs"); const { createRequire } = require("node:module"); const os = require("node:os"); const path = require("node:path"); function getNativesDir() { const xdgDataHome = process.env.XDG_DATA_HOME; if (xdgDataHome && fs.existsSync(path.join(xdgDataHome, "omp"))) { return path.join(xdgDataHome, "omp", "natives"); } return path.join(os.homedir(), ".omp", "natives"); } const packageJson = require("../package.json"); const { embeddedAddon } = require("./embedded-addon"); const require_ = createRequire(__filename); const platformTag = `${process.platform}-${process.arch}`; const packageVersion = packageJson.version; const nativeDir = path.join(__dirname, "..", "native"); const execDir = path.dirname(process.execPath); const versionedDir = path.join(getNativesDir(), packageVersion); const userDataDir = process.platform === "win32" ? path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"), "omp") : path.join(os.homedir(), ".local", "bin"); const isCompiledBinary = process.env.PI_COMPILED || __filename.includes("$bunfs") || __filename.includes("~BUN") || __filename.includes("%7EBUN"); const SUPPORTED_PLATFORMS = ["linux-x64", "linux-arm64", "darwin-x64", "darwin-arm64", "win32-x64"]; function getVariantOverride() { const value = process.env.PI_NATIVE_VARIANT; if (!value) return null; if (value === "modern" || value === "baseline") return value; return null; } function detectAvx2Support() { if (process.arch !== "x64") { return false; } if (process.platform === "linux") { try { const cpuInfo = fs.readFileSync("/proc/cpuinfo", "utf8"); return /\bavx2\b/i.test(cpuInfo); } catch { return false; } } if (process.platform === "darwin") { const leaf7 = runCommand("sysctl", ["-n", "machdep.cpu.leaf7_features"]); if (leaf7 && /\bAVX2\b/i.test(leaf7)) { return true; } const features = runCommand("sysctl", ["-n", "machdep.cpu.features"]); return Boolean(features && /\bAVX2\b/i.test(features)); } if (process.platform === "win32") { const output = runCommand("powershell.exe", [ "-NoProfile", "-NonInteractive", "-Command", "[System.Runtime.Intrinsics.X86.Avx2]::IsSupported", ]); return output && output.toLowerCase() === "true"; } return false; } function resolveCpuVariant(override) { if (process.arch !== "x64") return null; if (override) return override; return detectAvx2Support() ? "modern" : "baseline"; } function getAddonFilenames(tag, variant) { const defaultFilename = `pi_natives.${tag}.node`; if (process.arch !== "x64" || !variant) return [defaultFilename]; const baselineFilename = `pi_natives.${tag}-baseline.node`; const modernFilename = `pi_natives.${tag}-modern.node`; if (variant === "modern") { return [modernFilename, baselineFilename, defaultFilename]; } return [baselineFilename, defaultFilename]; } const variantOverride = getVariantOverride(); const selectedVariant = resolveCpuVariant(variantOverride); const addonFilenames = getAddonFilenames(platformTag, selectedVariant); const addonLabel = selectedVariant ? `${platformTag} (${selectedVariant})` : platformTag; const baseReleaseCandidates = addonFilenames.flatMap(filename => [ path.join(nativeDir, filename), path.join(execDir, filename), ]); const compiledCandidates = addonFilenames.flatMap(filename => [ path.join(versionedDir, filename), path.join(userDataDir, filename), ]); const releaseCandidates = isCompiledBinary ? [...compiledCandidates, ...baseReleaseCandidates] : baseReleaseCandidates; const dedupedCandidates = [...new Set(releaseCandidates)]; function runCommand(command, args) { // removed logger.time try { const { spawnSync } = require("child_process"); const result = spawnSync(command, args, { encoding: "utf-8" }); if (result.error) return null; if (result.status !== 0) return null; return (result.stdout || "").trim(); } catch { return null; } } function selectEmbeddedAddonFile() { if (!embeddedAddon) return null; const defaultFile = embeddedAddon.files.find(file => file.variant === "default") || null; if (process.arch !== "x64") return defaultFile || embeddedAddon.files[0] || null; if (selectedVariant === "modern") { return ( embeddedAddon.files.find(file => file.variant === "modern") || embeddedAddon.files.find(file => file.variant === "baseline") || null ); } return embeddedAddon.files.find(file => file.variant === "baseline") || null; } function maybeExtractEmbeddedAddon(errors) { if (!isCompiledBinary || !embeddedAddon) return null; if (embeddedAddon.platformTag !== platformTag || embeddedAddon.version !== packageVersion) return null; const selectedEmbeddedFile = selectEmbeddedAddonFile(); if (!selectedEmbeddedFile) return null; const targetPath = path.join(versionedDir, selectedEmbeddedFile.filename); try { fs.mkdirSync(versionedDir, { recursive: true }); } catch (err) { const message = err instanceof Error ? err.message : String(err); errors.push(`embedded addon dir: ${message}`); return null; } if (fs.existsSync(targetPath)) { return targetPath; } try { const buffer = fs.readFileSync(selectedEmbeddedFile.filePath); fs.writeFileSync(targetPath, buffer); return targetPath; } catch (err) { const message = err instanceof Error ? err.message : String(err); errors.push(`embedded addon write (${selectedEmbeddedFile.filename}): ${message}`); return null; } } function loadNative() { const errors = []; const embeddedCandidate = maybeExtractEmbeddedAddon(errors); const runtimeCandidates = embeddedCandidate ? [embeddedCandidate, ...dedupedCandidates] : dedupedCandidates; for (const candidate of runtimeCandidates) { try { const bindings = require_(candidate); if (process.env.PI_DEV) { console.log(`Loaded native addon from ${candidate}`); } return bindings; } catch (err) { if (process.env.PI_DEV) { console.error(`Error loading native addon from ${candidate}:`, err); } const message = err instanceof Error ? err.message : String(err); errors.push(`${candidate}: ${message}`); } } // Check if this is an unsupported platform if (!SUPPORTED_PLATFORMS.includes(platformTag)) { throw new Error( `Unsupported platform: ${platformTag}\n` + `Supported platforms: ${SUPPORTED_PLATFORMS.join(", ")}\n` + "If you need support for this platform, please open an issue.", ); } const details = errors.map(error => `- ${error}`).join("\n"); let helpMessage; if (isCompiledBinary) { const expectedPaths = addonFilenames.map(filename => ` ${path.join(versionedDir, filename)}`).join("\n"); const downloadHints = addonFilenames .map(filename => { const downloadUrl = `https://github.com/can1357/oh-my-pi/releases/latest/download/${filename}`; const targetPath = path.join(versionedDir, filename); return ` curl -fsSL "${downloadUrl}" -o "${targetPath}"`; }) .join("\n"); helpMessage = `The compiled binary should extract one of:\n${expectedPaths}\n\n` + `If missing, delete ${versionedDir} and re-run, or download manually:\n${downloadHints}`; } else { helpMessage = "If installed via npm/bun, try reinstalling: bun install @oh-my-pi/pi-natives\n" + "If developing locally, build with: bun --cwd=packages/natives run build\n" + "Optional x64 variants: TARGET_VARIANT=baseline|modern bun --cwd=packages/natives run build"; } throw new Error(`Failed to load pi_natives native addon for ${addonLabel}.\n\nTried:\n${details}\n\n${helpMessage}`); } module.exports = loadNative(); // --- generated const enum exports (do not edit) --- exports.AstMatchStrictness = { Cst: 'cst', Smart: 'smart', Ast: 'ast', Relaxed: 'relaxed', Signature: 'signature', Template: 'template', }; exports.ChunkAnchorStyle = { Full: 'full', Kind: 'kind', Bare: 'bare', FullOmit: 'full-omit', KindOmit: 'kind-omit', None: 'none', }; exports.ChunkEditOp = { Replace: 'replace', Delete: 'delete', Before: 'before', After: 'after', Prepend: 'prepend', Append: 'append', }; exports.ChunkFocusMode = { Expanded: 'expanded', Collapsed: 'collapsed', Container: 'container', }; exports.ChunkReadStatus = { Ok: 'ok', NotFound: 'not_found', UnsupportedRegion: 'unsupported_region', }; exports.ChunkRegion = { Head: 'head', Body: 'body', Tail: 'tail', }; exports.Ellipsis = { Unicode: 0, Ascii: 1, Omit: 2, }; exports.FileType = { File: 1, Dir: 2, Symlink: 3, }; exports.GrepOutputMode = { Content: 'content', Count: 'count', FilesWithMatches: 'filesWithMatches', }; exports.ImageFormat = { PNG: 0, JPEG: 1, WEBP: 2, GIF: 3, }; exports.KeyEventType = { Press: 1, Repeat: 2, Release: 3, }; exports.MacOSAppearance = { Dark: 'dark', Light: 'light', }; exports.SamplingFilter = { Nearest: 1, Triangle: 2, CatmullRom: 3, Gaussian: 4, Lanczos3: 5, }; // --- end generated const enum exports ---