@adhdev/ghostty-vt-node 1.0.46 → 1.0.78
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/package.json +1 -1
- package/prebuilt/darwin-arm64-node115/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node115/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node115/libghostty-vt.dylib +0 -0
- package/prebuilt/darwin-arm64-node127/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node127/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node127/libghostty-vt.dylib +0 -0
- package/prebuilt/darwin-arm64-node137/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node137/libghostty-vt.dylib +0 -0
- package/prebuilt/darwin-arm64-node141/ghostty_vt_node.node +0 -0
- package/prebuilt/darwin-arm64-node141/libghostty-vt.0.1.0.dylib +0 -0
- package/prebuilt/darwin-arm64-node141/libghostty-vt.dylib +0 -0
- package/prebuilt/linux-x64-node115/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node115/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node115/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node115/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/linux-x64-node127/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node127/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node127/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node127/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/linux-x64-node137/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node137/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node137/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/linux-x64-node141/ghostty_vt_node.node +0 -0
- package/prebuilt/linux-x64-node141/libghostty-vt.so +0 -0
- package/prebuilt/linux-x64-node141/libghostty-vt.so.0 +0 -0
- package/prebuilt/linux-x64-node141/libghostty-vt.so.0.1.0 +0 -0
- package/prebuilt/win32-x64-node127/ghostty-vt.dll +0 -0
- package/prebuilt/win32-x64-node127/ghostty_vt_node.node +0 -0
- package/scripts/build-or-use-prebuilt.mjs +95 -12
- package/scripts/ensure-prebuilt-sonames.mjs +52 -0
- package/prebuilt/win32-x64-node115/ghostty-vt.dll +0 -0
- package/prebuilt/win32-x64-node115/ghostty_vt_node.node +0 -0
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -27,24 +27,105 @@ function latestSourceMtime() {
|
|
|
27
27
|
return sourceInputs.reduce((latest, filePath) => Math.max(latest, safeMtime(filePath)), 0);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
const PREBUILT_ROOT = path.join(packageDir, 'prebuilt');
|
|
31
|
+
const ADDON_FILE = 'ghostty_vt_node.node';
|
|
32
|
+
// The addon plus its co-located runtime libs (.dylib/.so/.dll) — the addon
|
|
33
|
+
// resolves libghostty-vt next to itself, so it must travel with it.
|
|
34
|
+
const RUNTIME_FILE_PATTERN = /\.(node|dylib|so|so\.\d.*|dll)$/;
|
|
35
|
+
|
|
36
|
+
// The addon is a pure Node-API binding, so every same `platform-arch`
|
|
37
|
+
// prebuilt is loadable regardless of the `nodeNNN` ABI in its directory name
|
|
38
|
+
// (see index.js, which falls back the same way at runtime). Exact ABI first,
|
|
39
|
+
// then the other same-platform-arch directories, newest ABI first. Accepting
|
|
40
|
+
// only the exact triplet sent e.g. a Node 22 (ABI 127) fresh clone — where
|
|
41
|
+
// only `*-node137` is committed — into a cmake/zig source compile.
|
|
42
|
+
function samePlatformArchTriplets() {
|
|
43
|
+
const prefix = `${process.platform}-${process.arch}-node`;
|
|
44
|
+
let names = [];
|
|
45
|
+
try {
|
|
46
|
+
names = fs.readdirSync(PREBUILT_ROOT, { withFileTypes: true })
|
|
47
|
+
.filter((entry) => entry.isDirectory() && entry.name.startsWith(prefix) && entry.name !== triplet)
|
|
48
|
+
.map((entry) => entry.name);
|
|
49
|
+
} catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const abi = (name) => Number.parseInt(name.slice(prefix.length), 10) || 0;
|
|
53
|
+
return names.sort((a, b) => abi(b) - abi(a));
|
|
54
|
+
}
|
|
55
|
+
|
|
30
56
|
function candidatePrebuiltPaths() {
|
|
31
57
|
const candidates = [];
|
|
32
58
|
const explicitDir = process.env.ADHDEV_GHOSTTY_VT_PREBUILT_DIR?.trim();
|
|
33
59
|
if (explicitDir) {
|
|
34
|
-
candidates.push(path.join(explicitDir, triplet,
|
|
35
|
-
candidates.push(path.join(explicitDir,
|
|
60
|
+
candidates.push({ file: path.join(explicitDir, triplet, ADDON_FILE), explicit: true });
|
|
61
|
+
candidates.push({ file: path.join(explicitDir, ADDON_FILE), explicit: true });
|
|
62
|
+
}
|
|
63
|
+
for (const name of [triplet, ...samePlatformArchTriplets()]) {
|
|
64
|
+
candidates.push({ file: path.join(PREBUILT_ROOT, name, ADDON_FILE), explicit: false });
|
|
36
65
|
}
|
|
37
|
-
candidates.push(path.join(packageDir, 'prebuilt', triplet, 'ghostty_vt_node.node'));
|
|
38
66
|
return candidates;
|
|
39
67
|
}
|
|
40
68
|
|
|
41
|
-
function
|
|
69
|
+
function git(args) {
|
|
70
|
+
const result = spawnSync('git', ['-C', packageDir, ...args], { encoding: 'utf8', windowsHide: true });
|
|
71
|
+
if (result.error || result.status === null) return null;
|
|
72
|
+
return { status: result.status, stdout: result.stdout || '' };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Staleness of a candidate prebuilt relative to the sources it was built from.
|
|
76
|
+
//
|
|
77
|
+
// The mtime guard only means something for files this machine PRODUCED (a
|
|
78
|
+
// local compile, or a prebuilt emitted from one): their mtimes order
|
|
79
|
+
// genuinely. A git-tracked prebuilt's mtime is just checkout order — in a
|
|
80
|
+
// fresh clone a valid prebuilt often looks "older" than addon.cc and was
|
|
81
|
+
// skipped, and the build then died for lack of cmake. For a tracked prebuilt
|
|
82
|
+
// the question that matters is whether the SOURCES were edited locally since
|
|
83
|
+
// the committed state; only then is the committed binary out of date.
|
|
84
|
+
let sourcesLocallyModifiedMemo;
|
|
85
|
+
function sourcesLocallyModified() {
|
|
86
|
+
if (sourcesLocallyModifiedMemo !== undefined) return sourcesLocallyModifiedMemo;
|
|
87
|
+
const rels = sourceInputs.map((filePath) => path.relative(packageDir, filePath));
|
|
88
|
+
const status = git(['status', '--porcelain', '--', ...rels]);
|
|
89
|
+
sourcesLocallyModifiedMemo = !!status && status.status === 0 && status.stdout.trim().length > 0;
|
|
90
|
+
return sourcesLocallyModifiedMemo;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isGitTracked(filePath) {
|
|
94
|
+
const result = git(['ls-files', '--error-unmatch', '--', path.relative(packageDir, filePath)]);
|
|
95
|
+
return !!result && result.status === 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function isUsablePrebuilt(candidate, sourceMtime) {
|
|
99
|
+
// An explicit override dir is the operator's choice — trust it.
|
|
100
|
+
if (candidate.explicit) return true;
|
|
101
|
+
if (isGitTracked(candidate.file)) return !sourcesLocallyModified();
|
|
102
|
+
// Not tracked: either a locally emitted prebuilt (mtime is meaningful) or an
|
|
103
|
+
// npm-installed package with no git at all, where the shipped sources and
|
|
104
|
+
// prebuilts are pristine together. Without git metadata there is nothing
|
|
105
|
+
// local to be stale against, so only a working tree applies the guard.
|
|
106
|
+
const insideWorkTree = git(['rev-parse', '--is-inside-work-tree']);
|
|
107
|
+
if (!insideWorkTree || insideWorkTree.status !== 0) return true;
|
|
108
|
+
return safeMtime(candidate.file) >= sourceMtime;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function installPrebuilt(candidateFile) {
|
|
112
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
113
|
+
const sourceDir = path.dirname(candidateFile);
|
|
114
|
+
for (const entry of fs.readdirSync(sourceDir)) {
|
|
115
|
+
if (RUNTIME_FILE_PATTERN.test(entry)) fs.copyFileSync(path.join(sourceDir, entry), path.join(outputDir, entry));
|
|
116
|
+
}
|
|
117
|
+
if (!fs.existsSync(outputFile)) fs.copyFileSync(candidateFile, outputFile);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function installPrebuiltIfPresent(sourceMtime) {
|
|
42
121
|
for (const candidate of candidatePrebuiltPaths()) {
|
|
43
|
-
if (!fs.existsSync(candidate)) continue;
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
122
|
+
if (!fs.existsSync(candidate.file)) continue;
|
|
123
|
+
if (!isUsablePrebuilt(candidate, sourceMtime)) {
|
|
124
|
+
console.log(`[ghostty-vt-node] skipping prebuilt ${candidate.file}: sources were modified locally after it was built`);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
installPrebuilt(candidate.file);
|
|
128
|
+
console.log(`[ghostty-vt-node] using prebuilt native binding from ${candidate.file}`);
|
|
48
129
|
return true;
|
|
49
130
|
}
|
|
50
131
|
return false;
|
|
@@ -53,17 +134,19 @@ function installPrebuiltIfPresent(minMtime = 0) {
|
|
|
53
134
|
const sourceMtime = latestSourceMtime();
|
|
54
135
|
const outputMtime = safeMtime(outputFile);
|
|
55
136
|
|
|
137
|
+
// A local build output is something this machine compiled, so its mtime
|
|
138
|
+
// against the sources is meaningful: keep it while it is not older.
|
|
56
139
|
if (outputMtime >= sourceMtime && outputMtime > 0) {
|
|
57
140
|
console.log(`[ghostty-vt-node] keeping existing local build at ${outputFile}`);
|
|
58
141
|
process.exit(0);
|
|
59
142
|
}
|
|
60
143
|
|
|
61
|
-
if (
|
|
62
|
-
console.log(`[ghostty-vt-node] skipping native build for ${triplet} (ADHDEV_SKIP_GHOSTTY_VT_BUILD=1)`);
|
|
144
|
+
if (installPrebuiltIfPresent(sourceMtime)) {
|
|
63
145
|
process.exit(0);
|
|
64
146
|
}
|
|
65
147
|
|
|
66
|
-
if (
|
|
148
|
+
if (process.env.ADHDEV_SKIP_GHOSTTY_VT_BUILD === '1') {
|
|
149
|
+
console.log(`[ghostty-vt-node] skipping native build for ${triplet} (ADHDEV_SKIP_GHOSTTY_VT_BUILD=1)`);
|
|
67
150
|
process.exit(0);
|
|
68
151
|
}
|
|
69
152
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Make every Linux prebuilt directory carry the SONAME file its addon links
|
|
3
|
+
// against (libghostty-vt.so.0). CI artifacts and npm tarballs drop symlinks, so
|
|
4
|
+
// a directory restored from an artifact has only libghostty-vt.so and
|
|
5
|
+
// libghostty-vt.so.0.1.0 — and the addon then fails to load on every Linux
|
|
6
|
+
// machine (v1.0.77). Copies the versioned file to the SONAME name when missing.
|
|
7
|
+
//
|
|
8
|
+
// node scripts/ensure-prebuilt-sonames.mjs # fix in place
|
|
9
|
+
// node scripts/ensure-prebuilt-sonames.mjs --check # fail if any is missing
|
|
10
|
+
// ... --load also require() the package and fail unless the binding loads
|
|
11
|
+
// (only meaningful on a platform that has a prebuilt)
|
|
12
|
+
import { copyFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
|
|
17
|
+
const pkgDir = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
18
|
+
const prebuiltDir = join(pkgDir, 'prebuilt');
|
|
19
|
+
const check = process.argv.includes('--check');
|
|
20
|
+
const load = process.argv.includes('--load');
|
|
21
|
+
const SONAME = 'libghostty-vt.so.0';
|
|
22
|
+
const VERSIONED = /^libghostty-vt\.so\.0\.\d+\.\d+$/;
|
|
23
|
+
|
|
24
|
+
const problems = [];
|
|
25
|
+
for (const triplet of existsSync(prebuiltDir) ? readdirSync(prebuiltDir) : []) {
|
|
26
|
+
if (!triplet.startsWith('linux-')) continue;
|
|
27
|
+
const dir = join(prebuiltDir, triplet);
|
|
28
|
+
if (!statSync(dir).isDirectory()) continue;
|
|
29
|
+
if (existsSync(join(dir, SONAME))) continue;
|
|
30
|
+
const versioned = readdirSync(dir).find((name) => VERSIONED.test(name));
|
|
31
|
+
if (!versioned) { problems.push(`${triplet}: no ${SONAME} and no versioned library to copy`); continue; }
|
|
32
|
+
if (check) { problems.push(`${triplet}: missing ${SONAME}`); continue; }
|
|
33
|
+
copyFileSync(join(dir, versioned), join(dir, SONAME));
|
|
34
|
+
console.log(`[ghostty-vt] ${triplet}: ${versioned} -> ${SONAME}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (load) {
|
|
38
|
+
try {
|
|
39
|
+
const req = createRequire(join(pkgDir, 'index.js'));
|
|
40
|
+
const mod = req(join(pkgDir, 'index.js'));
|
|
41
|
+
if (!mod || (typeof mod !== 'object' && typeof mod !== 'function')) throw new Error('binding export is empty');
|
|
42
|
+
console.log(`[ghostty-vt] binding loads on ${process.platform}-${process.arch} (abi ${process.versions.modules})`);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
problems.push(`binding failed to load on ${process.platform}-${process.arch}: ${error?.message || error}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (problems.length) {
|
|
49
|
+
for (const p of problems) console.error(`✗ ${p}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
if (check) console.log('[ghostty-vt] prebuilt SONAME check passed');
|
|
Binary file
|
|
Binary file
|