@@ -22,14 +22,28 @@ export class RegistryLockService {
2222 * Acquire an exclusive lock on the registry file
2323 * Returns a release function to unlock the file
2424 *
25- * If the file doesn't exist yet, creates a placeholder to lock against
25+ * Ensures the file exists before attempting to lock
2626 */
2727 async acquireLock ( ) : Promise < ( ) => Promise < void > > {
2828 try {
29- // For registry, we lock even if file doesn't exist yet
30- // (prevents race during initial creation)
3129 const lockPath = this . registryPath ;
3230
31+ // Ensure file exists before locking (proper-lockfile requires this)
32+ // Create empty file if it doesn't exist
33+ const { existsSync } = await import ( 'fs' ) ;
34+ const { writeFile, mkdir } = await import ( 'fs/promises' ) ;
35+ const { dirname } = await import ( 'path' ) ;
36+
37+ if ( ! existsSync ( lockPath ) ) {
38+ const dir = dirname ( lockPath ) ;
39+ if ( ! existsSync ( dir ) ) {
40+ await mkdir ( dir , { recursive : true } ) ;
41+ }
42+ // Create minimal valid registry file
43+ await writeFile ( lockPath , JSON . stringify ( { lastId : 0 , agents : { } } , null , 2 ) , 'utf-8' ) ;
44+ logger . debug ( `Created registry file for locking: ${ lockPath } ` ) ;
45+ }
46+
3347 // Acquire lock with proper-lockfile
3448 const release = await lockfile . lock ( lockPath , {
3549 stale : 30000 , // 30 second stale timeout to prevent deadlocks
@@ -38,7 +52,7 @@ export class RegistryLockService {
3852 minTimeout : 50 ,
3953 maxTimeout : 500 ,
4054 } ,
41- realpath : false , // Don't resolve symlinks (registry might not exist yet)
55+ realpath : false , // Don't resolve symlinks
4256 lockfilePath : `${ lockPath } .lock` , // Explicit lock file path
4357 } ) ;
4458
@@ -47,10 +61,10 @@ export class RegistryLockService {
4761
4862 return release ;
4963 } catch ( error ) {
50- logger . warn ( ` Failed to acquire lock for registry ${ this . registryPath } : ${ error } `) ;
51- // Return no-op release function for graceful degradation
52- // This allows the system to continue even if locking fails
53- return async ( ) => { } ;
64+ logger . error ( `CRITICAL: Failed to acquire lock for registry ${ this . registryPath } : ${ error } `) ;
65+ // DO NOT silently degrade - throw error for critical operations
66+ // This prevents data corruption from unprotected concurrent access
67+ throw new Error ( `Failed to acquire registry lock: ${ error } ` ) ;
5468 }
5569 }
5670
0 commit comments