@@ -19,6 +19,8 @@ import {
19
19
rmSync ,
20
20
lstatSync ,
21
21
readlinkSync ,
22
+ writeFileSync ,
23
+ appendFileSync ,
22
24
} from "node:fs" ;
23
25
import { join , normalize } from "node:path" ;
24
26
// Use flora-colossus for finding all dependencies of EXTERNAL_DEPENDENCIES
@@ -129,45 +131,144 @@ const config: ForgeConfig = {
129
131
`Found ${ nativeModuleDependenciesToPackage . length } dependencies to copy` ,
130
132
) ;
131
133
134
+ // Create debug log file for copy operations
135
+ const copyDebugLogPath = join ( projectRoot , "symlink-debug.log" ) ;
136
+ const copyTimestamp = new Date ( ) . toISOString ( ) ;
137
+ const copyDebugHeader = `========== Copy Dependencies Debug ==========\n` +
138
+ `Timestamp: ${ copyTimestamp } \n` +
139
+ `Platform: ${ platform } \n` +
140
+ `Arch: ${ arch } \n` +
141
+ `Total Dependencies: ${ nativeModuleDependenciesToPackage . length } \n` +
142
+ `===========================================\n\n` ;
143
+ writeFileSync ( copyDebugLogPath , copyDebugHeader ) ;
144
+
132
145
// Copy all required dependencies
133
146
for ( const dep of nativeModuleDependenciesToPackage ) {
134
147
const rootDepPath = join ( rootNodeModules , dep ) ;
135
148
const localDepPath = join ( localNodeModules , dep ) ;
136
149
150
+ const copyDebugInfo : any = {
151
+ dependency : dep ,
152
+ sourcePath : rootDepPath ,
153
+ targetPath : localDepPath ,
154
+ sourceExists : existsSync ( rootDepPath ) ,
155
+ targetExists : existsSync ( localDepPath ) ,
156
+ } ;
157
+
158
+ // Check source stats if it exists
159
+ if ( copyDebugInfo . sourceExists ) {
160
+ const sourceStats = lstatSync ( rootDepPath ) ;
161
+ copyDebugInfo . sourceIsSymlink = sourceStats . isSymbolicLink ( ) ;
162
+ copyDebugInfo . sourceIsDirectory = sourceStats . isDirectory ( ) ;
163
+
164
+ if ( sourceStats . isSymbolicLink ( ) ) {
165
+ try {
166
+ copyDebugInfo . sourceSymlinkTarget = readlinkSync ( rootDepPath ) ;
167
+ } catch ( e ) {
168
+ copyDebugInfo . sourceSymlinkTarget = `Error reading symlink: ${ e } ` ;
169
+ }
170
+ }
171
+ }
172
+
173
+ // Check target stats if it exists
174
+ if ( copyDebugInfo . targetExists ) {
175
+ const targetStats = lstatSync ( localDepPath ) ;
176
+ copyDebugInfo . targetIsSymlink = targetStats . isSymbolicLink ( ) ;
177
+ copyDebugInfo . targetIsDirectory = targetStats . isDirectory ( ) ;
178
+
179
+ if ( targetStats . isSymbolicLink ( ) ) {
180
+ try {
181
+ copyDebugInfo . targetSymlinkTarget = readlinkSync ( localDepPath ) ;
182
+ } catch ( e ) {
183
+ copyDebugInfo . targetSymlinkTarget = `Error reading symlink: ${ e } ` ;
184
+ }
185
+ }
186
+ }
187
+
188
+ appendFileSync ( copyDebugLogPath , `\nCopy operation for: ${ dep } \n` ) ;
189
+ appendFileSync ( copyDebugLogPath , JSON . stringify ( copyDebugInfo , null , 2 ) + "\n" ) ;
190
+
137
191
try {
138
192
// Skip if source doesn't exist
139
193
if ( ! existsSync ( rootDepPath ) ) {
140
194
console . log ( `Skipping ${ dep } : not found in root node_modules` ) ;
195
+ appendFileSync ( copyDebugLogPath , `>>> SKIPPED: Source not found\n` ) ;
141
196
continue ;
142
197
}
143
198
144
199
// Skip if target already exists (don't override)
145
200
if ( existsSync ( localDepPath ) ) {
146
201
console . log ( `Skipping ${ dep } : already exists locally` ) ;
202
+ appendFileSync ( copyDebugLogPath , `>>> SKIPPED: Target already exists\n` ) ;
147
203
continue ;
148
204
}
149
205
150
206
// Copy the package
151
207
console . log ( `Copying ${ dep } ...` ) ;
208
+ appendFileSync ( copyDebugLogPath , `>>> COPYING with options: { recursive: true, dereference: true, force: true }\n` ) ;
152
209
cpSync ( rootDepPath , localDepPath , { recursive : true , dereference : true , force : true } ) ;
153
210
console . log ( `✓ Successfully copied ${ dep } ` ) ;
211
+ appendFileSync ( copyDebugLogPath , `>>> SUCCESS: Copied successfully\n` ) ;
212
+
213
+ // Check what was actually copied
214
+ if ( existsSync ( localDepPath ) ) {
215
+ const afterCopyStats = lstatSync ( localDepPath ) ;
216
+ const afterCopyInfo = {
217
+ isSymlink : afterCopyStats . isSymbolicLink ( ) ,
218
+ isDirectory : afterCopyStats . isDirectory ( ) ,
219
+ } ;
220
+ appendFileSync ( copyDebugLogPath , `>>> After copy stats: ${ JSON . stringify ( afterCopyInfo ) } \n` ) ;
221
+ }
154
222
} catch ( error ) {
155
223
console . error ( `Failed to copy ${ dep } :` , error ) ;
224
+ appendFileSync ( copyDebugLogPath , `>>> ERROR: ${ error } \n` ) ;
156
225
}
157
226
}
227
+
228
+ appendFileSync ( copyDebugLogPath , `\n========== End of Copy Dependencies ==========\n` ) ;
158
229
159
230
// Second pass: Replace any symlinks with dereferenced copies
160
231
console . log ( "Checking for symlinks in copied dependencies..." ) ;
232
+
233
+ // Create debug log file
234
+ const debugLogPath = join ( projectRoot , "symlink-debug.log" ) ;
235
+ const timestamp = new Date ( ) . toISOString ( ) ;
236
+ const debugHeader = `\n========== Symlink Detection Debug ==========\n` +
237
+ `Timestamp: ${ timestamp } \n` +
238
+ `Platform: ${ platform } \n` +
239
+ `Arch: ${ arch } \n` +
240
+ `Process: ${ process . platform } -${ process . arch } \n` +
241
+ `===========================================\n\n` ;
242
+ appendFileSync ( debugLogPath , debugHeader ) ;
243
+
161
244
for ( const dep of nativeModuleDependenciesToPackage ) {
162
245
const localDepPath = join ( localNodeModules , dep ) ;
163
246
164
247
try {
165
248
if ( existsSync ( localDepPath ) ) {
166
249
const stats = lstatSync ( localDepPath ) ;
250
+
251
+ // Log detailed stat info for debugging
252
+ const debugInfo = {
253
+ dependency : dep ,
254
+ path : localDepPath ,
255
+ isSymbolicLink : stats . isSymbolicLink ( ) ,
256
+ isDirectory : stats . isDirectory ( ) ,
257
+ isFile : stats . isFile ( ) ,
258
+ mode : stats . mode ,
259
+ size : stats . size ,
260
+ forceProcessing : dep === "@amical/smart-whisper" ,
261
+ willProcess : stats . isSymbolicLink ( ) || dep === "@amical/smart-whisper" ,
262
+ } ;
263
+
264
+ appendFileSync ( debugLogPath , `Checking: ${ dep } \n` ) ;
265
+ appendFileSync ( debugLogPath , JSON . stringify ( debugInfo , null , 2 ) + "\n\n" ) ;
266
+
167
267
//! for w/e reason sym links are persisting in ci, while locally this is working
168
268
//! this is a temp bypass
169
269
if ( stats . isSymbolicLink ( ) || dep === "@amical/smart-whisper" ) {
170
270
console . log ( `Found symlink for ${ dep } , replacing with dereferenced copy...` ) ;
271
+ appendFileSync ( debugLogPath , `>>> PROCESSING ${ dep } (isSymlink: ${ stats . isSymbolicLink ( ) } , forced: ${ dep === "@amical/smart-whisper" } )\n` ) ;
171
272
172
273
// Read where the symlink points to
173
274
const symlinkTarget = readlinkSync ( localDepPath ) ;
@@ -187,12 +288,16 @@ const config: ForgeConfig = {
187
288
} ) ;
188
289
189
290
console . log ( `✓ Successfully replaced symlink for ${ dep } with actual content` ) ;
291
+ appendFileSync ( debugLogPath , `>>> SUCCESS: Replaced ${ dep } \n\n` ) ;
190
292
}
191
293
}
192
294
} catch ( error ) {
193
295
console . error ( `Failed to check/replace symlink for ${ dep } :` , error ) ;
296
+ appendFileSync ( debugLogPath , `>>> ERROR processing ${ dep } : ${ error } \n\n` ) ;
194
297
}
195
298
}
299
+
300
+ appendFileSync ( debugLogPath , `========== End of Symlink Detection ==========\n\n` ) ;
196
301
197
302
// Prune onnxruntime-node to keep only the required binary
198
303
const targetPlatform = platform ;
0 commit comments