@adhdev/ghostty-vt-node 1.0.82-rc.44 → 1.0.82-rc.46

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/ghostty-vt-node",
3
- "version": "1.0.82-rc.44",
3
+ "version": "1.0.82-rc.46",
4
4
  "description": "Native Node binding for libghostty-vt",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -6,29 +6,29 @@
6
6
  "sourceDigest": "e4ca3372235a1289373e172996a5e7804bc4d5f3eac630d91d9160dd932e0627",
7
7
  "ghosttyRevision": "d4a38c8661453026bd1b1bb022ba2c37b347adce",
8
8
  "napiVersion": 8,
9
- "builtWithNode": "v22.17.0",
9
+ "builtWithNode": "v24.22.1",
10
10
  "release": true,
11
11
  "provenance": {
12
12
  "problems": [],
13
13
  "ghosttySourceRevision": "d4a38c8661453026bd1b1bb022ba2c37b347adce",
14
14
  "ghosttySourceClean": true,
15
15
  "zigVersion": "0.15.2",
16
- "cCompiler": "AppleClang 17.0.0.17000316",
17
- "cxxCompiler": "AppleClang 17.0.0.17000316",
16
+ "cCompiler": "AppleClang 17.0.0.17000013",
17
+ "cxxCompiler": "AppleClang 17.0.0.17000013",
18
18
  "buildType": "Release"
19
19
  },
20
20
  "files": {
21
21
  "ghostty_vt_node.node": {
22
- "sha256": "fbdbf5e197b99d43b609b875d3621ce3e873ac8e0e04608cd057fba987a8555a",
22
+ "sha256": "dc33247d1de680b96e451a27e1103407e7ba9fb70a0a1fe3cba17c5aa34b458f",
23
23
  "size": 100536
24
24
  },
25
25
  "libghostty-vt.0.1.0.dylib": {
26
- "sha256": "d2f92f4bdbaa734b014fe8d38615ccaa5a97f9f07847e5476e87a4c7a64f3c00",
27
- "size": 1528392
26
+ "sha256": "8b270a58ffd6125741f3d87d5e6e47be66129f9067236330c996e7c7cc24b547",
27
+ "size": 1531560
28
28
  },
29
29
  "libghostty-vt.dylib": {
30
- "sha256": "d2f92f4bdbaa734b014fe8d38615ccaa5a97f9f07847e5476e87a4c7a64f3c00",
31
- "size": 1528392
30
+ "sha256": "8b270a58ffd6125741f3d87d5e6e47be66129f9067236330c996e7c7cc24b547",
31
+ "size": 1531560
32
32
  }
33
33
  }
34
34
  }
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
 
6
+ import { withMacosDeploymentTarget } from './macos-min-version.mjs';
6
7
  import { emitPrebuilt } from './prebuilt-manifest.mjs';
7
8
 
8
9
  const scriptDir = path.dirname(fileURLToPath(import.meta.url));
@@ -193,7 +194,8 @@ if (forceCompile) {
193
194
  console.log(`[ghostty-vt-node] compiling ${triplet} (${decision.reason}) via ${command} ${args.join(' ')}`);
194
195
  const result = spawnSync(command, args, {
195
196
  cwd: packageDir,
196
- env: process.env,
197
+ // darwin: pin the deployment target so the addon loads on older macOS (see macos-min-version.mjs).
198
+ env: withMacosDeploymentTarget(process.env),
197
199
  stdio: 'inherit',
198
200
  });
199
201
 
@@ -0,0 +1,84 @@
1
+ // Minimum macOS version every darwin Mach-O we ship must load on.
2
+ //
3
+ // Why: a prebuilt linked without a deployment target inherits the BUILD
4
+ // machine's OS as `minos` (a macOS 26 builder produced minos 26.0), and dyld
5
+ // then refuses to load it on anything older. The loader falls back to a
6
+ // cmake-js + zig source compile, which end users cannot run, so terminal
7
+ // rendering breaks. libghostty-vt already targets 13.0 through zig's default;
8
+ // the node addon (clang via cmake-js) needs MACOSX_DEPLOYMENT_TARGET.
9
+ //
10
+ // This is deliberately NOT in CMakeLists.txt: that file is a binding digest
11
+ // input, so editing it would invalidate the linux/win32 prebuilts too.
12
+ //
13
+ // Floor 13.0: the lowest target zig 0.15.2 / this ghostty pin build for
14
+ // (ghostty itself supports macOS 13+); nothing here needs newer APIs.
15
+ import { readFileSync } from 'node:fs';
16
+
17
+ export const MACOS_MIN_VERSION = '13.0';
18
+
19
+ // Env for darwin builds; an explicit caller value is kept only if not newer than the floor.
20
+ export function withMacosDeploymentTarget(env = process.env, platform = process.platform) {
21
+ if (platform !== 'darwin') return env;
22
+ const current = env.MACOSX_DEPLOYMENT_TARGET;
23
+ if (current && compareVersions(current, MACOS_MIN_VERSION) <= 0) return env;
24
+ return { ...env, MACOSX_DEPLOYMENT_TARGET: MACOS_MIN_VERSION };
25
+ }
26
+
27
+ export function compareVersions(a, b) {
28
+ const pa = String(a).split('.').map(Number);
29
+ const pb = String(b).split('.').map(Number);
30
+ for (let i = 0; i < 3; i++) {
31
+ const d = (pa[i] || 0) - (pb[i] || 0);
32
+ if (d) return d;
33
+ }
34
+ return 0;
35
+ }
36
+
37
+ const decode = (v) => `${v >>> 16}.${(v >>> 8) & 0xff}${(v & 0xff) ? `.${v & 0xff}` : ''}`;
38
+
39
+ // Returns [{ offset, minos, sdk }] for each macOS slice of a Mach-O (thin or
40
+ // fat), or null if the buffer is not a Mach-O. Parsed in JS so the guard runs
41
+ // on every host, not only where `otool` exists.
42
+ export function readMachOMinos(buf) {
43
+ if (buf.length < 8) return null;
44
+ const magicBE = buf.readUInt32BE(0);
45
+ if (magicBE === 0xcafebabe) {
46
+ const n = buf.readUInt32BE(4);
47
+ const out = [];
48
+ for (let i = 0; i < n; i++) {
49
+ const off = buf.readUInt32BE(8 + i * 20 + 8);
50
+ const slice = readMachOMinos(buf.subarray(off));
51
+ if (slice) out.push(...slice);
52
+ }
53
+ return out;
54
+ }
55
+ if (buf.readUInt32LE(0) !== 0xfeedfacf) return null;
56
+ const ncmds = buf.readUInt32LE(16);
57
+ let p = 32;
58
+ const out = [];
59
+ for (let i = 0; i < ncmds && p + 8 <= buf.length; i++) {
60
+ const cmd = buf.readUInt32LE(p);
61
+ const size = buf.readUInt32LE(p + 4);
62
+ if (cmd === 0x32 && buf.readUInt32LE(p + 8) === 1) { // LC_BUILD_VERSION, PLATFORM_MACOS
63
+ out.push({ minos: decode(buf.readUInt32LE(p + 12)), sdk: decode(buf.readUInt32LE(p + 16)) });
64
+ } else if (cmd === 0x24) { // LC_VERSION_MIN_MACOSX
65
+ out.push({ minos: decode(buf.readUInt32LE(p + 8)), sdk: decode(buf.readUInt32LE(p + 12)) });
66
+ }
67
+ p += size;
68
+ }
69
+ return out;
70
+ }
71
+
72
+ // Problems for one file ([] when fine or when it is not a Mach-O).
73
+ export function macosMinVersionProblems(name, buf, floor = MACOS_MIN_VERSION) {
74
+ const slices = readMachOMinos(buf);
75
+ if (!slices) return [];
76
+ if (slices.length === 0) return [`${name}: Mach-O carries no macOS minimum-version load command`];
77
+ return slices
78
+ .filter(({ minos }) => compareVersions(minos, floor) > 0)
79
+ .map(({ minos }) => `${name}: minos ${minos} is above the macOS ${floor} floor (dyld will refuse it on older macOS; rebuild with MACOSX_DEPLOYMENT_TARGET=${floor})`);
80
+ }
81
+
82
+ export function macosMinVersionProblemsForFile(path, floor = MACOS_MIN_VERSION) {
83
+ return macosMinVersionProblems(path.split(/[\\/]/).pop(), readFileSync(path), floor);
84
+ }
@@ -15,6 +15,7 @@ import { fileURLToPath } from 'node:url';
15
15
 
16
16
  import { computeBindingDigest, pinnedGhosttyRevision, pinnedZigVersion } from './binding-digest.mjs';
17
17
  import { scanHostPaths } from './host-path-scan.mjs';
18
+ import { macosMinVersionProblems, MACOS_MIN_VERSION } from './macos-min-version.mjs';
18
19
  import { checkNativeFile } from './native-format.mjs';
19
20
  import { ADDON_FILE, RUNTIME_FILE_PATTERN, expectedApiLevel } from './prebuilt-manifest.mjs';
20
21
 
@@ -43,6 +44,10 @@ export function verifyPrebuilt(dir, { hostPathScan = true } = {}) {
43
44
  const problems = checkNativeFile(name, readFileSync(resolve(dir, name)), process.platform, process.arch);
44
45
  checks.push({ name: `native format of ${name}`, ok: problems.length === 0, detail: problems.length ? problems.join('; ') : `${process.platform}-${process.arch} shared library` });
45
46
  }
47
+ for (const name of readdirSync(dir).filter((entry) => RUNTIME_FILE_PATTERN.test(entry)).sort()) {
48
+ const problems = macosMinVersionProblems(name, readFileSync(resolve(dir, name)));
49
+ if (problems.length) checks.push({ name: `macOS ${MACOS_MIN_VERSION} floor of ${name}`, ok: false, detail: problems.join('; ') });
50
+ }
46
51
  const file = resolve(dir, ADDON_FILE);
47
52
  let addon;
48
53
  try {