@@ -17,6 +17,8 @@ import {
17
17
mkdirSync ,
18
18
cpSync ,
19
19
rmSync ,
20
+ lstatSync ,
21
+ readlinkSync ,
20
22
} from "node:fs" ;
21
23
import { join , normalize } from "node:path" ;
22
24
// Use flora-colossus for finding all dependencies of EXTERNAL_DEPENDENCIES
@@ -29,7 +31,6 @@ let nativeModuleDependenciesToPackage: string[] = [];
29
31
30
32
export const EXTERNAL_DEPENDENCIES = [
31
33
"electron-squirrel-startup" ,
32
- "smart-whisper" ,
33
34
"@libsql/client" ,
34
35
"@libsql/darwin-arm64" ,
35
36
"@libsql/darwin-x64" ,
@@ -39,13 +40,13 @@ export const EXTERNAL_DEPENDENCIES = [
39
40
"libsql" ,
40
41
"onnxruntime-node" ,
41
42
"workerpool" ,
43
+ "@amical/smart-whisper" ,
42
44
// Add any other native modules you need here
43
45
] ;
44
46
45
47
const config : ForgeConfig = {
46
48
hooks : {
47
49
prePackage : async ( _forgeConfig , platform , arch ) => {
48
- console . error ( "prePackage" , { platform, arch } ) ;
49
50
const projectRoot = normalize ( __dirname ) ;
50
51
// In a monorepo, node_modules are typically at the root level
51
52
const monorepoRoot = join ( projectRoot , "../../" ) ; // Go up to monorepo root
@@ -148,15 +149,56 @@ const config: ForgeConfig = {
148
149
149
150
// Copy the package
150
151
console . log ( `Copying ${ dep } ...` ) ;
151
- cpSync ( rootDepPath , localDepPath , { recursive : true } ) ;
152
+ cpSync ( rootDepPath , localDepPath , { recursive : true , dereference : true , force : true } ) ;
152
153
console . log ( `✓ Successfully copied ${ dep } ` ) ;
153
154
} catch ( error ) {
154
155
console . error ( `Failed to copy ${ dep } :` , error ) ;
155
156
}
156
157
}
157
158
159
+ // Second pass: Replace any symlinks with dereferenced copies
160
+ console . log ( "Checking for symlinks in copied dependencies..." ) ;
161
+ for ( const dep of nativeModuleDependenciesToPackage ) {
162
+ const localDepPath = join ( localNodeModules , dep ) ;
163
+
164
+ try {
165
+ if ( existsSync ( localDepPath ) ) {
166
+ const stats = lstatSync ( localDepPath ) ;
167
+ if ( stats . isSymbolicLink ( ) ) {
168
+ console . log ( `Found symlink for ${ dep } , replacing with dereferenced copy...` ) ;
169
+
170
+ // Read where the symlink points to
171
+ const symlinkTarget = readlinkSync ( localDepPath ) ;
172
+ const absoluteTarget = join ( localDepPath , ".." , symlinkTarget ) ;
173
+ const sourcePath = normalize ( absoluteTarget ) ;
174
+
175
+ console . log ( ` Symlink points to: ${ sourcePath } ` ) ;
176
+
177
+ // Remove the symlink
178
+ rmSync ( localDepPath , { recursive : true , force : true } ) ;
179
+
180
+ // Copy with dereference to get actual content
181
+ cpSync ( sourcePath , localDepPath , {
182
+ recursive : true ,
183
+ force : true ,
184
+ dereference : true // Follow symlinks and copy actual content
185
+ } ) ;
186
+
187
+ console . log ( `✓ Successfully replaced symlink for ${ dep } with actual content` ) ;
188
+ }
189
+ }
190
+ } catch ( error ) {
191
+ console . error ( `Failed to check/replace symlink for ${ dep } :` , error ) ;
192
+ }
193
+ }
194
+
158
195
// Prune onnxruntime-node to keep only the required binary
159
- console . log ( "Pruning onnxruntime-node binaries..." ) ;
196
+ const targetPlatform = platform ;
197
+ const targetArch = arch ;
198
+
199
+ console . log (
200
+ `Pruning onnxruntime-node binaries for ${ targetPlatform } /${ targetArch } ...` ,
201
+ ) ;
160
202
const onnxBinRoot = join ( localNodeModules , "onnxruntime-node" , "bin" ) ;
161
203
if ( existsSync ( onnxBinRoot ) ) {
162
204
const napiVersionDirs = readdirSync ( onnxBinRoot ) ;
@@ -169,18 +211,18 @@ const config: ForgeConfig = {
169
211
const platformPath = join ( napiVersionPath , platformDir ) ;
170
212
if ( ! statSync ( platformPath ) . isDirectory ( ) ) continue ;
171
213
172
- // Delete other platform directories
173
- if ( platformDir !== process . platform ) {
214
+ // Delete unused platforms except Linux (keep for compatibility)
215
+ if ( platformDir !== targetPlatform && platformDir !== "linux" ) {
174
216
console . log ( `- Deleting unused platform: ${ platformPath } ` ) ;
175
217
rmSync ( platformPath , { recursive : true , force : true } ) ;
176
- } else {
218
+ } else if ( platformDir === targetPlatform ) {
177
219
// Now in the correct platform dir, prune architectures
178
220
const archDirs = readdirSync ( platformPath ) ;
179
221
for ( const archDir of archDirs ) {
180
222
const archPath = join ( platformPath , archDir ) ;
181
223
if ( ! statSync ( archPath ) . isDirectory ( ) ) continue ;
182
224
183
- if ( archDir !== process . arch ) {
225
+ if ( archDir !== targetArch ) {
184
226
console . log ( `- Deleting unused arch: ${ archPath } ` ) ;
185
227
rmSync ( archPath , { recursive : true , force : true } ) ;
186
228
}
@@ -196,6 +238,7 @@ const config: ForgeConfig = {
196
238
}
197
239
} ,
198
240
packageAfterPrune : async ( _forgeConfig , buildPath ) => {
241
+ console . error ( "PRE PACKAGE" ) ;
199
242
try {
200
243
function getItemsFromFolder (
201
244
path : string ,
@@ -264,14 +307,14 @@ const config: ForgeConfig = {
264
307
packagerConfig : {
265
308
asar : {
266
309
unpack :
267
- "{*.node,*.dylib,*.so,*.dll,*.metal,**/whisper.cpp/**,**/.vite/build/whisper-worker-fork.js,**/node_modules/smart-whisper /**,**/node_modules/jest-worker /**}" ,
310
+ "{*.node,*.dylib,*.so,*.dll,*.metal,**/node_modules/@amical/smart- whisper/**,**/whisper .cpp/**,**/.vite/build/whisper-worker-fork.js,**/node_modules/jest-worker /**,**/onnxruntime-node/bin /**}" ,
268
311
} ,
269
312
name : "Amical" ,
270
313
executableName : "Amical" ,
271
314
icon : "./assets/logo" , // Path to your icon file
272
315
appBundleId : "com.amical.desktop" , // Proper bundle ID
273
316
extraResource : [
274
- " ../../packages/native-helpers/swift-helper/bin",
317
+ ` ${ process . platform === "win32" ? " ../../packages/native-helpers/windows-helper/bin" : "../../packages/native-helpers/ swift-helper/bin"} ` ,
275
318
"./src/db/migrations" ,
276
319
// Only include the platform-specific node binary
277
320
`./node-binaries/${ process . platform } -${ process . arch } /node${
@@ -356,8 +399,18 @@ const config: ForgeConfig = {
356
399
}
357
400
358
401
// Handle scoped packages: if dep is @scope /package, also keep @scope/ directory
402
+ // But not for our workspace packages
359
403
if ( dep . includes ( "/" ) && dep . startsWith ( "@" ) ) {
360
404
const scopeDir = dep . split ( "/" ) [ 0 ] ; // @libsql /client -> @libsql
405
+ // for workspace packages only keep the actual package
406
+ if ( scopeDir === "@amical" ) {
407
+ if ( filePath . startsWith ( `/node_modules/${ dep } ` ) ||
408
+ filePath === `/node_modules/${ scopeDir } ` ) {
409
+ KEEP_FILE . keep = true ;
410
+ KEEP_FILE . log = true ;
411
+ }
412
+ continue ;
413
+ }
361
414
if (
362
415
filePath === `/node_modules/${ scopeDir } /` ||
363
416
filePath === `/node_modules/${ scopeDir } ` ||
0 commit comments