quilltap 4.6.0-dev.41 → 4.6.0-dev.83
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/bin/quilltap.js +1 -79
- package/lib/native-modules.js +105 -0
- package/package.json +6 -3
package/bin/quilltap.js
CHANGED
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
loadDbKey,
|
|
14
14
|
} = require('../lib/db-helpers');
|
|
15
15
|
const { resolveInstance } = require('../lib/instances');
|
|
16
|
+
const { resolveModuleDir, ensureNativeModules } = require('../lib/native-modules');
|
|
16
17
|
|
|
17
18
|
const PACKAGE_DIR = path.resolve(__dirname, '..');
|
|
18
19
|
|
|
@@ -137,85 +138,6 @@ function openBrowser(url) {
|
|
|
137
138
|
});
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
// Resolve a native module's directory, handling npm hoisting.
|
|
141
|
-
// Returns the directory containing package.json, or null if not found.
|
|
142
|
-
function resolveModuleDir(moduleName) {
|
|
143
|
-
try {
|
|
144
|
-
const pkgJson = require.resolve(moduleName + '/package.json');
|
|
145
|
-
return path.dirname(pkgJson);
|
|
146
|
-
} catch {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Check if native modules are compiled for the current Node.js version.
|
|
152
|
-
// This handles the case where npx caches the package but the user upgrades
|
|
153
|
-
// Node.js — the cached native modules will have a stale NODE_MODULE_VERSION.
|
|
154
|
-
function ensureNativeModules() {
|
|
155
|
-
const needsRebuild = [];
|
|
156
|
-
|
|
157
|
-
// Check better-sqlite3-multiple-ciphers (provides SQLCipher encryption support).
|
|
158
|
-
// The main app depends on this via an npm alias as 'better-sqlite3', so we must
|
|
159
|
-
// ensure the SQLCipher-capable version is available and link it as 'better-sqlite3'.
|
|
160
|
-
// We must load the native binding directly to detect NODE_MODULE_VERSION mismatches.
|
|
161
|
-
try {
|
|
162
|
-
const modDir = resolveModuleDir('better-sqlite3-multiple-ciphers')
|
|
163
|
-
|| resolveModuleDir('better-sqlite3');
|
|
164
|
-
if (!modDir) throw Object.assign(new Error('not found'), { code: 'MODULE_NOT_FOUND' });
|
|
165
|
-
const bindingsPath = path.join(modDir, 'build', 'Release', 'better_sqlite3.node');
|
|
166
|
-
require(bindingsPath);
|
|
167
|
-
} catch (err) {
|
|
168
|
-
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
169
|
-
needsRebuild.push('better-sqlite3-multiple-ciphers');
|
|
170
|
-
} else if (err.code === 'MODULE_NOT_FOUND') {
|
|
171
|
-
needsRebuild.push('better-sqlite3-multiple-ciphers');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Check sharp: loads its native binding eagerly on require, but we use
|
|
176
|
-
// the same explicit-path approach for consistency and reliability.
|
|
177
|
-
try {
|
|
178
|
-
require('sharp');
|
|
179
|
-
} catch (err) {
|
|
180
|
-
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
181
|
-
needsRebuild.push('sharp');
|
|
182
|
-
} else if (err.code === 'MODULE_NOT_FOUND') {
|
|
183
|
-
needsRebuild.push('sharp');
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Check node-pty: backs the Ariel terminal feature. Loaded dynamically by
|
|
188
|
-
// pty-manager in the standalone server, so resolution must succeed and the
|
|
189
|
-
// native binding's NODE_MODULE_VERSION must match the runtime.
|
|
190
|
-
try {
|
|
191
|
-
require('node-pty');
|
|
192
|
-
} catch (err) {
|
|
193
|
-
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
194
|
-
needsRebuild.push('node-pty');
|
|
195
|
-
} else if (err.code === 'MODULE_NOT_FOUND') {
|
|
196
|
-
needsRebuild.push('node-pty');
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (needsRebuild.length === 0) return;
|
|
201
|
-
|
|
202
|
-
console.log(` Rebuilding native modules for Node.js ${process.version}...`);
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
execSync(`npm rebuild ${needsRebuild.join(' ')}`, {
|
|
206
|
-
cwd: PACKAGE_DIR,
|
|
207
|
-
stdio: 'inherit',
|
|
208
|
-
});
|
|
209
|
-
console.log(' Done.');
|
|
210
|
-
console.log('');
|
|
211
|
-
} catch (err) {
|
|
212
|
-
console.error('');
|
|
213
|
-
console.error(` Warning: Failed to rebuild native modules: ${err.message}`);
|
|
214
|
-
console.error(' Try running: npm rebuild --prefix ' + PACKAGE_DIR);
|
|
215
|
-
console.error('');
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
141
|
// Symlink native modules into the standalone directory's node_modules
|
|
220
142
|
// so that standard Node.js resolution finds them without relying on NODE_PATH.
|
|
221
143
|
function linkNativeModules(standaloneDir) {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Shared helpers for keeping native modules compiled against the current Node
|
|
4
|
+
// ABI. Used by both the runtime CLI entry (bin/quilltap.js) and the package's
|
|
5
|
+
// `postinstall` hook, so a fresh install picks up the correct binaries up front
|
|
6
|
+
// and a later Node upgrade still self-heals on first run.
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { execSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const PACKAGE_DIR = path.resolve(__dirname, '..');
|
|
12
|
+
|
|
13
|
+
// Resolve a native module's directory, handling npm hoisting.
|
|
14
|
+
// Returns the directory containing package.json, or null if not found.
|
|
15
|
+
function resolveModuleDir(moduleName) {
|
|
16
|
+
try {
|
|
17
|
+
const pkgJson = require.resolve(moduleName + '/package.json', { paths: [PACKAGE_DIR] });
|
|
18
|
+
return path.dirname(pkgJson);
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Check if native modules are compiled for the current Node.js version.
|
|
25
|
+
// This handles the case where npx caches the package but the user upgrades
|
|
26
|
+
// Node.js — the cached native modules will have a stale NODE_MODULE_VERSION.
|
|
27
|
+
// Returns true if everything was healthy or successfully rebuilt; false on
|
|
28
|
+
// rebuild failure. Never throws.
|
|
29
|
+
function ensureNativeModules() {
|
|
30
|
+
const needsRebuild = [];
|
|
31
|
+
|
|
32
|
+
// Check better-sqlite3-multiple-ciphers (provides SQLCipher encryption support).
|
|
33
|
+
// The main app depends on this via an npm alias as 'better-sqlite3', so we must
|
|
34
|
+
// ensure the SQLCipher-capable version is available and link it as 'better-sqlite3'.
|
|
35
|
+
// We must load the native binding directly to detect NODE_MODULE_VERSION mismatches.
|
|
36
|
+
try {
|
|
37
|
+
const modDir = resolveModuleDir('better-sqlite3-multiple-ciphers')
|
|
38
|
+
|| resolveModuleDir('better-sqlite3');
|
|
39
|
+
if (!modDir) throw Object.assign(new Error('not found'), { code: 'MODULE_NOT_FOUND' });
|
|
40
|
+
const bindingsPath = path.join(modDir, 'build', 'Release', 'better_sqlite3.node');
|
|
41
|
+
require(bindingsPath);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
44
|
+
needsRebuild.push('better-sqlite3-multiple-ciphers');
|
|
45
|
+
} else if (err.code === 'MODULE_NOT_FOUND') {
|
|
46
|
+
needsRebuild.push('better-sqlite3-multiple-ciphers');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check sharp: loads its native binding eagerly on require.
|
|
51
|
+
try {
|
|
52
|
+
require.resolve('sharp', { paths: [PACKAGE_DIR] });
|
|
53
|
+
require('sharp');
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
56
|
+
needsRebuild.push('sharp');
|
|
57
|
+
} else if (err.code === 'MODULE_NOT_FOUND') {
|
|
58
|
+
needsRebuild.push('sharp');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check node-pty: backs the Ariel terminal feature. Loaded dynamically by
|
|
63
|
+
// pty-manager in the standalone server, so resolution must succeed and the
|
|
64
|
+
// native binding's NODE_MODULE_VERSION must match the runtime.
|
|
65
|
+
try {
|
|
66
|
+
require.resolve('node-pty', { paths: [PACKAGE_DIR] });
|
|
67
|
+
require('node-pty');
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
70
|
+
needsRebuild.push('node-pty');
|
|
71
|
+
} else if (err.code === 'MODULE_NOT_FOUND') {
|
|
72
|
+
needsRebuild.push('node-pty');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (needsRebuild.length === 0) return true;
|
|
77
|
+
|
|
78
|
+
console.log(` Rebuilding native modules for Node.js ${process.version}...`);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
execSync(`npm rebuild ${needsRebuild.join(' ')}`, {
|
|
82
|
+
cwd: PACKAGE_DIR,
|
|
83
|
+
stdio: 'inherit',
|
|
84
|
+
});
|
|
85
|
+
console.log(' Done.');
|
|
86
|
+
console.log('');
|
|
87
|
+
return true;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error('');
|
|
90
|
+
console.error(` Warning: Failed to rebuild native modules: ${err.message}`);
|
|
91
|
+
console.error(' Try running: npm rebuild --prefix ' + PACKAGE_DIR);
|
|
92
|
+
console.error('');
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = { resolveModuleDir, ensureNativeModules, PACKAGE_DIR };
|
|
98
|
+
|
|
99
|
+
// Allow this file to be invoked directly as a postinstall script:
|
|
100
|
+
// node lib/native-modules.js
|
|
101
|
+
// Exits 0 on success or graceful warning; never blocks npm install on failure.
|
|
102
|
+
if (require.main === module) {
|
|
103
|
+
ensureNativeModules();
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quilltap",
|
|
3
|
-
"version": "4.6.0-dev.
|
|
3
|
+
"version": "4.6.0-dev.83",
|
|
4
4
|
"description": "Self-hosted AI workspace for writers, worldbuilders, and roleplayers. Run with npx quilltap.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Charles Sebold",
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"bin": {
|
|
28
28
|
"quilltap": "bin/quilltap.js"
|
|
29
29
|
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"postinstall": "node lib/native-modules.js"
|
|
32
|
+
},
|
|
30
33
|
"files": [
|
|
31
34
|
"bin/",
|
|
32
35
|
"lib/",
|
|
@@ -34,11 +37,11 @@
|
|
|
34
37
|
],
|
|
35
38
|
"dependencies": {
|
|
36
39
|
"@napi-rs/canvas": "^0.1.100",
|
|
37
|
-
"better-sqlite3-multiple-ciphers": "^12.
|
|
40
|
+
"better-sqlite3-multiple-ciphers": "^12.10.0",
|
|
38
41
|
"node-pty": "^1.1.0",
|
|
39
42
|
"sharp": "^0.34.5",
|
|
40
43
|
"tar": "^7.5.15",
|
|
41
|
-
"yauzl": "^3.3.
|
|
44
|
+
"yauzl": "^3.3.1"
|
|
42
45
|
},
|
|
43
46
|
"engines": {
|
|
44
47
|
"node": ">=24.0.0"
|