@oh-my-pi/pi-natives 18.8.5 → 18.8.7
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.
- package/native/embedded-addon.js +3 -12
- package/native/index.d.ts +50 -0
- package/native/index.js +2 -0
- package/native/loader-state.d.ts +8 -12
- package/native/loader-state.js +25 -108
- package/package.json +7 -7
package/native/embedded-addon.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
1
|
// Always null on disk. Standalone binary builds replace this module in memory
|
|
3
|
-
// with the target's manifest and addon
|
|
2
|
+
// with the target's manifest and one zstd frame per addon (scripts/embed-native.ts).
|
|
4
3
|
|
|
5
4
|
/** @typedef {"modern" | "baseline" | "default"} EmbeddedAddonVariant */
|
|
6
5
|
|
|
@@ -8,15 +7,8 @@
|
|
|
8
7
|
* @typedef {Object} EmbeddedAddonFile
|
|
9
8
|
* @property {EmbeddedAddonVariant} variant
|
|
10
9
|
* @property {string} filename
|
|
11
|
-
* @property {number} size
|
|
12
|
-
* @property {string
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {Object} EmbeddedAddonArchive
|
|
17
|
-
* @property {"tar.gz"} format
|
|
18
|
-
* @property {string} filename
|
|
19
|
-
* @property {string} filePath
|
|
10
|
+
* @property {number} size Decompressed `.node` size in bytes.
|
|
11
|
+
* @property {string} zstdPath Embedded zstd frame holding the addon bytes.
|
|
20
12
|
*/
|
|
21
13
|
|
|
22
14
|
/**
|
|
@@ -24,7 +16,6 @@
|
|
|
24
16
|
* @property {string} platformTag
|
|
25
17
|
* @property {string} version
|
|
26
18
|
* @property {EmbeddedAddonFile[]} files
|
|
27
|
-
* @property {EmbeddedAddonArchive=} archive
|
|
28
19
|
*/
|
|
29
20
|
|
|
30
21
|
/** @type {EmbeddedAddon|null} */
|
package/native/index.d.ts
CHANGED
|
@@ -730,6 +730,13 @@ export declare class VcsRepo {
|
|
|
730
730
|
*/
|
|
731
731
|
export declare function __ompInstallTokioRuntime(): void
|
|
732
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Points the addon at the directory holding downloaded wasm grammars
|
|
735
|
+
* (`<dir>/<file>`). The loader (`native/loader-state.js`) calls this once
|
|
736
|
+
* with `<natives dir>/grammars`; grammars then load lazily from it.
|
|
737
|
+
*/
|
|
738
|
+
export declare function __ompSetGrammarDir(dir: string): void
|
|
739
|
+
|
|
733
740
|
/**
|
|
734
741
|
* Release version stamped into this `.node` after linking.
|
|
735
742
|
*
|
|
@@ -863,6 +870,11 @@ export interface AstFindResult {
|
|
|
863
870
|
limitReached: boolean
|
|
864
871
|
/** Non-fatal parse or pattern errors collected during the run. */
|
|
865
872
|
parseErrors?: Array<string>
|
|
873
|
+
/**
|
|
874
|
+
* Languages whose on-demand grammar is not installed; their files were
|
|
875
|
+
* skipped (see `wasmGrammarFor`).
|
|
876
|
+
*/
|
|
877
|
+
missingGrammars?: Array<string>
|
|
866
878
|
}
|
|
867
879
|
|
|
868
880
|
/**
|
|
@@ -1035,6 +1047,11 @@ export interface AstReplaceResult {
|
|
|
1035
1047
|
limitReached: boolean
|
|
1036
1048
|
/** Parse or pattern errors when not failing the whole operation. */
|
|
1037
1049
|
parseErrors?: Array<string>
|
|
1050
|
+
/**
|
|
1051
|
+
* Languages whose on-demand grammar is not installed; their files were
|
|
1052
|
+
* skipped (see `wasmGrammarFor`).
|
|
1053
|
+
*/
|
|
1054
|
+
missingGrammars?: Array<string>
|
|
1038
1055
|
}
|
|
1039
1056
|
|
|
1040
1057
|
export interface AxNode {
|
|
@@ -3679,6 +3696,39 @@ export declare function warmBlockParse(options: BlockParseOptions): Promise<unde
|
|
|
3679
3696
|
*/
|
|
3680
3697
|
export declare function warmHighlighter(): Promise<undefined>
|
|
3681
3698
|
|
|
3699
|
+
/**
|
|
3700
|
+
* Wasm grammar backing `lang` (alias) or the language of `path`; `null` for
|
|
3701
|
+
* built-in or unknown languages.
|
|
3702
|
+
*/
|
|
3703
|
+
export declare function wasmGrammarFor(query: WasmGrammarQuery): WasmGrammarInfo | null
|
|
3704
|
+
|
|
3705
|
+
/** A grammar the host downloads on first use. */
|
|
3706
|
+
export interface WasmGrammarInfo {
|
|
3707
|
+
/** Canonical language name, e.g. `verilog`, `csharp`. */
|
|
3708
|
+
language: string
|
|
3709
|
+
/** stencil-hq/wasm-grammars release tag hosting the grammar, e.g. `v1`. */
|
|
3710
|
+
release: string
|
|
3711
|
+
/**
|
|
3712
|
+
* File name inside the grammar directory; the release asset is
|
|
3713
|
+
* `<file>.zst`.
|
|
3714
|
+
*/
|
|
3715
|
+
file: string
|
|
3716
|
+
/** Lowercase hex SHA-256 of the decompressed `.wasm`. */
|
|
3717
|
+
sha256: string
|
|
3718
|
+
/** Byte size of the decompressed `.wasm`. */
|
|
3719
|
+
size: number
|
|
3720
|
+
/** Whether the grammar is downloaded (or already loaded). */
|
|
3721
|
+
installed: boolean
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3724
|
+
/** Language to look up: an alias, or a path to infer it from. */
|
|
3725
|
+
export interface WasmGrammarQuery {
|
|
3726
|
+
/** Language alias (e.g. `kotlin`, `sv`); wins over `path`. */
|
|
3727
|
+
lang?: string
|
|
3728
|
+
/** File whose extension selects the language. */
|
|
3729
|
+
path?: string
|
|
3730
|
+
}
|
|
3731
|
+
|
|
3682
3732
|
/** Profiling results returned to JavaScript. */
|
|
3683
3733
|
export interface WorkProfile {
|
|
3684
3734
|
/** Folded stack format for flamegraph tools. */
|
package/native/index.js
CHANGED
|
@@ -46,6 +46,7 @@ export const VcsRepo = nativeBindings.VcsRepo;
|
|
|
46
46
|
|
|
47
47
|
// functions
|
|
48
48
|
export const __ompInstallTokioRuntime = nativeBindings.__ompInstallTokioRuntime ?? missingNativeExport("__ompInstallTokioRuntime");
|
|
49
|
+
export const __ompSetGrammarDir = nativeBindings.__ompSetGrammarDir ?? missingNativeExport("__ompSetGrammarDir");
|
|
49
50
|
export const __piNativesBuildVersion = nativeBindings.__piNativesBuildVersion;
|
|
50
51
|
export const appleFmAvailability = nativeBindings.appleFmAvailability ?? missingNativeExport("appleFmAvailability");
|
|
51
52
|
export const appleFmCancel = nativeBindings.appleFmCancel ?? missingNativeExport("appleFmCancel");
|
|
@@ -142,6 +143,7 @@ export const vectorIndexTopK = nativeBindings.vectorIndexTopK ?? missingNativeEx
|
|
|
142
143
|
export const visibleWidth = nativeBindings.visibleWidth ?? missingNativeExport("visibleWidth");
|
|
143
144
|
export const warmBlockParse = nativeBindings.warmBlockParse ?? missingNativeExport("warmBlockParse");
|
|
144
145
|
export const warmHighlighter = nativeBindings.warmHighlighter ?? missingNativeExport("warmHighlighter");
|
|
146
|
+
export const wasmGrammarFor = nativeBindings.wasmGrammarFor ?? missingNativeExport("wasmGrammarFor");
|
|
145
147
|
export const wrapTextWithAnsi = nativeBindings.wrapTextWithAnsi ?? missingNativeExport("wrapTextWithAnsi");
|
|
146
148
|
|
|
147
149
|
// string/numeric enums (napi-rs string_enum produces TS-only const enum)
|
package/native/loader-state.d.ts
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
export interface EmbeddedAddonFile {
|
|
2
2
|
variant: "modern" | "baseline" | "default";
|
|
3
|
+
/** Basename of the extracted `.node` file. */
|
|
3
4
|
filename: string;
|
|
4
|
-
size
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export interface EmbeddedAddonArchive {
|
|
9
|
-
format: "tar.gz";
|
|
10
|
-
filename: string;
|
|
11
|
-
filePath: string;
|
|
5
|
+
/** Decompressed addon size in bytes. */
|
|
6
|
+
size: number;
|
|
7
|
+
/** Embedded zstd frame holding the addon bytes. */
|
|
8
|
+
zstdPath: string;
|
|
12
9
|
}
|
|
13
10
|
|
|
14
11
|
export interface EmbeddedAddon {
|
|
15
12
|
platformTag: string;
|
|
16
13
|
version: string;
|
|
17
14
|
files: EmbeddedAddonFile[];
|
|
18
|
-
archive?: EmbeddedAddonArchive;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
export interface DetectCompiledBinaryInput {
|
|
@@ -90,13 +86,13 @@ export function cleanupStaleNativeVersions(input: CleanupStaleNativeVersionsInpu
|
|
|
90
86
|
|
|
91
87
|
export function prepareNativeVersionDir(versionedDir: string): void;
|
|
92
88
|
|
|
93
|
-
export interface
|
|
94
|
-
archivePath: string;
|
|
89
|
+
export interface ExtractEmbeddedAddonsInput {
|
|
95
90
|
files: EmbeddedAddonFile[];
|
|
96
91
|
targetDir: string;
|
|
97
92
|
}
|
|
98
93
|
|
|
99
|
-
|
|
94
|
+
/** Decompress every manifest addon missing or wrong-sized in `targetDir`; returns the paths written. */
|
|
95
|
+
export function extractEmbeddedAddons(input: ExtractEmbeddedAddonsInput): string[];
|
|
100
96
|
|
|
101
97
|
export interface SelectCpuVariantInput {
|
|
102
98
|
arch: string;
|
package/native/loader-state.js
CHANGED
|
@@ -3,7 +3,6 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
-
import * as zlib from "node:zlib";
|
|
7
6
|
import packageJson from "../package.json" with { type: "json" };
|
|
8
7
|
import { embeddedAddon } from "./embedded-addon.js";
|
|
9
8
|
import { bindingsHaveReleaseIdentity, bindingsReleaseVersion, containsVersionStamp } from "./version-sentinel.js";
|
|
@@ -450,36 +449,6 @@ function selectEmbeddedAddonFile(selectedVariant) {
|
|
|
450
449
|
return embeddedAddon.files.find(file => file.variant === "baseline") || null;
|
|
451
450
|
}
|
|
452
451
|
|
|
453
|
-
function readTarString(buffer, offset, length) {
|
|
454
|
-
const end = Math.min(offset + length, buffer.length);
|
|
455
|
-
let stringEnd = offset;
|
|
456
|
-
while (stringEnd < end && buffer[stringEnd] !== 0) stringEnd++;
|
|
457
|
-
return buffer.toString("utf8", offset, stringEnd);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function readTarOctal(buffer, offset, length) {
|
|
461
|
-
const value = readTarString(buffer, offset, length).trim();
|
|
462
|
-
if (!value) return 0;
|
|
463
|
-
const parsed = Number.parseInt(value, 8);
|
|
464
|
-
if (!Number.isFinite(parsed)) {
|
|
465
|
-
throw new Error(`Invalid tar octal value: ${value}`);
|
|
466
|
-
}
|
|
467
|
-
return parsed;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function isZeroTarBlock(buffer, offset) {
|
|
471
|
-
for (let index = 0; index < 512; index++) {
|
|
472
|
-
if (buffer[offset + index] !== 0) return false;
|
|
473
|
-
}
|
|
474
|
-
return true;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function getTarEntryName(header) {
|
|
478
|
-
const name = readTarString(header, 0, 100);
|
|
479
|
-
const prefix = readTarString(header, 345, 155);
|
|
480
|
-
return prefix ? `${prefix}/${name}` : name;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
452
|
function isSafeEmbeddedAddonFilename(filename) {
|
|
484
453
|
return filename.length > 0 && path.basename(filename) === filename && !filename.includes("/") && !filename.includes("\\");
|
|
485
454
|
}
|
|
@@ -488,7 +457,7 @@ function isEmbeddedAddonFileCurrent(targetPath, file) {
|
|
|
488
457
|
try {
|
|
489
458
|
const stat = fs.statSync(targetPath);
|
|
490
459
|
if (!stat.isFile()) return false;
|
|
491
|
-
return
|
|
460
|
+
return stat.size === file.size;
|
|
492
461
|
} catch (err) {
|
|
493
462
|
if (err && err.code === "ENOENT") return false;
|
|
494
463
|
throw err;
|
|
@@ -510,60 +479,23 @@ function writeEmbeddedAddonFile(targetPath, content) {
|
|
|
510
479
|
}
|
|
511
480
|
}
|
|
512
481
|
|
|
513
|
-
export function
|
|
514
|
-
const pending = new Map();
|
|
482
|
+
export function extractEmbeddedAddons({ files, targetDir }) {
|
|
515
483
|
for (const file of files) {
|
|
516
484
|
if (!isSafeEmbeddedAddonFilename(file.filename)) {
|
|
517
485
|
throw new Error(`Unsafe embedded addon filename: ${file.filename}`);
|
|
518
486
|
}
|
|
519
|
-
const targetPath = path.join(targetDir, file.filename);
|
|
520
|
-
if (!isEmbeddedAddonFileCurrent(targetPath, file)) {
|
|
521
|
-
pending.set(file.filename, file);
|
|
522
|
-
}
|
|
523
487
|
}
|
|
524
|
-
if (pending.size === 0) return [];
|
|
525
|
-
|
|
526
|
-
const archive = zlib.gunzipSync(fs.readFileSync(archivePath));
|
|
527
488
|
const writtenPaths = [];
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const size = readTarOctal(header, 124, 12);
|
|
535
|
-
const typeflag = header[156] === 0 ? "0" : String.fromCharCode(header[156]);
|
|
536
|
-
offset += 512;
|
|
537
|
-
|
|
538
|
-
if (offset + size > archive.length) {
|
|
539
|
-
throw new Error(`Truncated embedded addon archive entry: ${filename}`);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
if (!isSafeEmbeddedAddonFilename(filename)) {
|
|
543
|
-
throw new Error(`Unsafe embedded addon archive entry: ${filename}`);
|
|
544
|
-
}
|
|
545
|
-
if (typeflag !== "0") {
|
|
546
|
-
throw new Error(`Unsupported embedded addon archive entry type ${typeflag}: ${filename}`);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const file = pending.get(filename);
|
|
550
|
-
if (file) {
|
|
551
|
-
if (typeof file.size === "number" && file.size !== size) {
|
|
552
|
-
throw new Error(`Embedded addon size mismatch for ${filename}: expected ${file.size}, got ${size}`);
|
|
553
|
-
}
|
|
554
|
-
const targetPath = path.join(targetDir, filename);
|
|
555
|
-
writeEmbeddedAddonFile(targetPath, archive.subarray(offset, offset + size));
|
|
556
|
-
pending.delete(filename);
|
|
557
|
-
writtenPaths.push(targetPath);
|
|
489
|
+
for (const file of files) {
|
|
490
|
+
const targetPath = path.join(targetDir, file.filename);
|
|
491
|
+
if (isEmbeddedAddonFileCurrent(targetPath, file)) continue;
|
|
492
|
+
const content = Bun.zstdDecompressSync(fs.readFileSync(file.zstdPath));
|
|
493
|
+
if (content.length !== file.size) {
|
|
494
|
+
throw new Error(`Embedded addon size mismatch for ${file.filename}: expected ${file.size}, got ${content.length}`);
|
|
558
495
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
if (pending.size > 0) {
|
|
564
|
-
throw new Error(`Embedded addon archive missing: ${[...pending.keys()].join(", ")}`);
|
|
496
|
+
writeEmbeddedAddonFile(targetPath, content);
|
|
497
|
+
writtenPaths.push(targetPath);
|
|
565
498
|
}
|
|
566
|
-
|
|
567
499
|
return writtenPaths;
|
|
568
500
|
}
|
|
569
501
|
|
|
@@ -584,40 +516,12 @@ function maybeExtractEmbeddedAddon(ctx, errors) {
|
|
|
584
516
|
return null;
|
|
585
517
|
}
|
|
586
518
|
|
|
587
|
-
if (embeddedAddon.archive) {
|
|
588
|
-
try {
|
|
589
|
-
extractEmbeddedAddonArchive({
|
|
590
|
-
archivePath: embeddedAddon.archive.filePath,
|
|
591
|
-
files: embeddedAddon.files,
|
|
592
|
-
targetDir: ctx.versionedDir,
|
|
593
|
-
});
|
|
594
|
-
if (isEmbeddedAddonFileCurrent(targetPath, selectedEmbeddedFile)) {
|
|
595
|
-
return targetPath;
|
|
596
|
-
}
|
|
597
|
-
errors.push(`embedded addon archive (${embeddedAddon.archive.filename}): missing ${selectedEmbeddedFile.filename}`);
|
|
598
|
-
return null;
|
|
599
|
-
} catch (err) {
|
|
600
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
601
|
-
errors.push(`embedded addon archive (${embeddedAddon.archive.filename}): ${message}`);
|
|
602
|
-
return null;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
if (isEmbeddedAddonFileCurrent(targetPath, selectedEmbeddedFile)) {
|
|
607
|
-
return targetPath;
|
|
608
|
-
}
|
|
609
|
-
if (!selectedEmbeddedFile.filePath) {
|
|
610
|
-
errors.push(`embedded addon metadata missing file path for ${selectedEmbeddedFile.filename}`);
|
|
611
|
-
return null;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
519
|
try {
|
|
615
|
-
|
|
616
|
-
fs.writeFileSync(targetPath, buffer);
|
|
520
|
+
extractEmbeddedAddons({ files: embeddedAddon.files, targetDir: ctx.versionedDir });
|
|
617
521
|
return targetPath;
|
|
618
522
|
} catch (err) {
|
|
619
523
|
const message = err instanceof Error ? err.message : String(err);
|
|
620
|
-
errors.push(`embedded addon
|
|
524
|
+
errors.push(`embedded addon extraction (${selectedEmbeddedFile.filename}): ${message}`);
|
|
621
525
|
return null;
|
|
622
526
|
}
|
|
623
527
|
}
|
|
@@ -832,6 +736,18 @@ function installNativeTokioRuntime(bindings) {
|
|
|
832
736
|
}
|
|
833
737
|
}
|
|
834
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Point the addon at `<nativesDir>/grammars`, where the agent downloads the
|
|
741
|
+
* tree-sitter grammars that load as WebAssembly on demand (pi-utils
|
|
742
|
+
* `getNativeGrammarsDir()` resolves the same path). Version cleanup never
|
|
743
|
+
* touches it: only release-version directories are removed. Older addons
|
|
744
|
+
* predating the export link every grammar and need no directory.
|
|
745
|
+
*/
|
|
746
|
+
function configureGrammarDir(bindings, nativesDir) {
|
|
747
|
+
const setGrammarDir = bindings.__ompSetGrammarDir;
|
|
748
|
+
if (typeof setGrammarDir === "function") setGrammarDir(path.join(nativesDir, "grammars"));
|
|
749
|
+
}
|
|
750
|
+
|
|
835
751
|
|
|
836
752
|
function buildHelpMessage(ctx) {
|
|
837
753
|
if (ctx.isCompiledBinary) {
|
|
@@ -957,6 +873,7 @@ export function loadNative() {
|
|
|
957
873
|
const bindings = require_(candidate);
|
|
958
874
|
validateLoadedBindings(ctx, bindings, candidate);
|
|
959
875
|
installNativeTokioRuntime(bindings);
|
|
876
|
+
configureGrammarDir(bindings, ctx.nativesDir);
|
|
960
877
|
loadedAddon = describeLoadedAddon(bindings, candidate, ctx);
|
|
961
878
|
cleanupStaleNativeVersions({ nativesDir: ctx.nativesDir, currentVersion: ctx.packageVersion });
|
|
962
879
|
startupMarker("native:loadNative:done");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-natives",
|
|
3
|
-
"version": "18.8.
|
|
3
|
+
"version": "18.8.7",
|
|
4
4
|
"description": "Native Rust bindings for PDF conversion, audio, WebRTC, grep, clipboard, image processing, syntax highlighting, PTY, and shell operations via N-API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
@@ -112,11 +112,11 @@
|
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
114
|
"optionalDependencies": {
|
|
115
|
-
"@oh-my-pi/pi-natives-linux-x64": "18.8.
|
|
116
|
-
"@oh-my-pi/pi-natives-linux-arm64": "18.8.
|
|
117
|
-
"@oh-my-pi/pi-natives-darwin-x64": "18.8.
|
|
118
|
-
"@oh-my-pi/pi-natives-darwin-arm64": "18.8.
|
|
119
|
-
"@oh-my-pi/pi-natives-win32-x64": "18.8.
|
|
120
|
-
"@oh-my-pi/pi-natives-win32-arm64": "18.8.
|
|
115
|
+
"@oh-my-pi/pi-natives-linux-x64": "18.8.7",
|
|
116
|
+
"@oh-my-pi/pi-natives-linux-arm64": "18.8.7",
|
|
117
|
+
"@oh-my-pi/pi-natives-darwin-x64": "18.8.7",
|
|
118
|
+
"@oh-my-pi/pi-natives-darwin-arm64": "18.8.7",
|
|
119
|
+
"@oh-my-pi/pi-natives-win32-x64": "18.8.7",
|
|
120
|
+
"@oh-my-pi/pi-natives-win32-arm64": "18.8.7"
|
|
121
121
|
}
|
|
122
122
|
}
|