6.5 KiB
Natives Architecture
@oh-my-pi/pi-natives is now a two-layer package around a loader:
- CommonJS loader/package entrypoint resolves and loads the correct
.nodeaddon and patches generated enum objects onto the export object. - Rust N-API module layer implements the exported functions/classes and emits the generated TypeScript declarations.
This document is the foundation for deeper module-level docs.
Implementation files
packages/natives/native/index.jspackages/natives/native/index.d.tspackages/natives/native/loader-state.jspackages/natives/native/embedded-addon.jspackages/natives/scripts/build-native.tspackages/natives/scripts/embed-native.tspackages/natives/scripts/gen-enums.tspackages/natives/package.jsoncrates/pi-natives/src/lib.rs
Package entrypoint and public surface
packages/natives/package.json points directly at generated native bindings:
main:./native/index.jstypes:./native/index.d.tsexports["."].types:./native/index.d.tsexports["."].import:./native/index.js
There is no current packages/natives/src TypeScript wrapper layer. Consumers import functions/classes/enums directly from @oh-my-pi/pi-natives; the type contract is the generated native/index.d.ts plus enum exports appended by scripts/gen-enums.ts.
Current capability groups in the generated API include:
- Search/text/code primitives:
grep,search,hasMatch,fuzzyFind,glob,astGrep,astEdit, text width/slicing/wrapping/sanitization, syntax highlighting, token counting. - Execution/process/terminal primitives:
executeShell,Shell,PtySession, process-tree helpers, key parsing. - System/media/conversion primitives: clipboard, image resize/encode/SIXEL, HTML-to-Markdown, macOS appearance/power helpers, work profiling, Windows ProjFS overlay helpers.
Loader layer
packages/natives/native/index.js owns runtime addon selection and optional embedded extraction.
Candidate resolution model
- Platform tag is
${process.platform}-${process.arch}. - Supported tags are currently:
linux-x64linux-arm64darwin-x64darwin-arm64win32-x64
- x64 can use CPU variants:
modern(AVX2-capable)baseline(fallback)
- Non-x64 uses the default filename without a variant suffix.
Filename strategy:
- Default:
pi_natives.<platform>-<arch>.node - x64 variant:
pi_natives.<platform>-<arch>-modern.nodeor...-baseline.node - x64 runtime fallback includes the unsuffixed default filename after variant candidates.
Platform-specific variant detection
For x64, variant selection uses:
- Linux:
/proc/cpuinfo - macOS:
sysctl -n machdep.cpu.leaf7_features, thenmachdep.cpu.features - Windows: PowerShell check for
System.Runtime.Intrinsics.X86.Avx2
PI_NATIVE_VARIANT can force modern or baseline; invalid values are ignored.
Binary distribution and extraction model
packages/natives/package.json publishes native/, which contains the loader, generated declarations, generated enum patch, embedded-addon manifest stub, and prebuilt .node artifacts.
For compiled binaries, loader behavior is:
- Check versioned user cache path:
<getNativesDir()>/<packageVersion>/.... - Check legacy compiled-binary location:
- Windows:
%LOCALAPPDATA%/omp(fallback%USERPROFILE%/AppData/Local/omp) - non-Windows:
~/.local/bin
- Windows:
- Fall back to packaged
native/and executable directory candidates.
getNativesDir() uses $XDG_DATA_HOME/omp/natives when $XDG_DATA_HOME/omp exists; otherwise it uses ~/.omp/natives.
If a populated embedded addon manifest is present, it is also treated as a compiled-binary signal. The loader can extract the matching embedded .node into the versioned cache directory before candidate probing.
Failure modes
Loader failures are explicit:
- Unsupported platform tag: after failed probing, throws with supported platform list.
- No loadable candidate: throws with all attempted paths and remediation hints.
- Embedded extraction errors: directory/write failures are recorded and included in final load diagnostics if no candidate loads.
The current loader does not perform a separate post-require export validation pass.
Rust N-API module layer
crates/pi-natives/src/lib.rs declares exported module ownership:
appearanceastclipboardfdfs_cacheglobglob_utilgrephighlighthtmlimagekeyslanguagepowerprofprojfs_overlaypsptyshelltasktexttokensutils(crate-private helpers)
N-API exports are generated from Rust #[napi] functions/classes/objects/enums. Snake_case Rust names are exposed as camelCase JavaScript names unless explicitly configured by napi-rs.
Ownership boundaries
- Loader/package ownership (
packages/natives/native,packages/natives/scripts)- runtime binary selection
- CPU variant selection and override handling
- compiled-binary embedded extraction
- generated TypeScript declarations and enum export patching
- Rust ownership (
crates/pi-natives/src)- algorithmic and system-level implementation
- platform-native behavior and performance-sensitive logic
- N-API symbol implementation consumed directly by package callers
- Consumer ownership (
packages/coding-agent,packages/tui)- user-facing policy and fallbacks that are not built into the native API
- higher-level rendering, artifact, shell-session, and command behavior
Runtime flow (high level)
- Consumer imports from
@oh-my-pi/pi-natives. native/index.jscomputes platform/arch/variant and candidate paths.- Optional embedded binary extraction occurs for compiled distributions.
- The first
require(candidate)that succeeds becomes the exported addon object. - Generated enum objects are appended to
module.exports. - Caller invokes generated N-API functions/classes directly.
Glossary
- Native addon: A
.nodebinary loaded via Node-API (N-API). - Platform tag: Runtime tuple
platform-arch(for exampledarwin-arm64). - Variant: x64 CPU-specific build flavor (
modernAVX2,baselinefallback). - Generated binding declaration:
native/index.d.tsemitted by napi-rs duringbuild-native.ts. - Compiled binary mode: Runtime mode where the CLI is bundled and native addons are resolved from embedded/cache paths before package-local paths.
- Embedded addon: Build artifact metadata and file references generated into
native/embedded-addon.jsso compiled binaries can extract matching.nodepayloads.