coherence_beacon_utils.js
1 const fs = require('fs').promises; 2 const path = require('path'); 3 const Store = require('electron-store'); 4 const store = new Store(); 5 6 async function readDreamSongCanvas(repoName) { 7 const dreamVaultPath = store.get('dreamVaultPath'); 8 if (!dreamVaultPath) { 9 throw new Error('Dream Vault path is not set in the application settings'); 10 } 11 const canvasPath = path.join(dreamVaultPath, repoName, 'DreamSong.canvas'); 12 try { 13 const data = await fs.readFile(canvasPath, 'utf8'); 14 return JSON.parse(data); 15 } catch (error) { 16 console.error(`Error reading DreamSong.canvas for ${repoName}:`, error); 17 return null; 18 } 19 } 20 21 async function parseGitModules(repoName) { 22 const dreamVaultPath = store.get('dreamVaultPath'); 23 if (!dreamVaultPath) { 24 throw new Error('Dream Vault path is not set in the application settings'); 25 } 26 const gitmodulesPath = path.join(dreamVaultPath, repoName, '.gitmodules'); 27 try { 28 const data = await fs.readFile(gitmodulesPath, 'utf8'); 29 // Simple parsing of .gitmodules file 30 const submodules = data.match(/path = .+/g); 31 return submodules ? submodules.map(line => line.split(' = ')[1].trim()) : []; 32 } catch (error) { 33 if (error.code === 'ENOENT') { 34 // .gitmodules file doesn't exist, which is fine 35 return []; 36 } 37 throw error; 38 } 39 } 40 41 async function getDreamSongDependencies(repoName) { 42 const dreamVaultPath = store.get('dreamVaultPath'); 43 if (!dreamVaultPath) { 44 throw new Error('Dream Vault path is not set in the application settings'); 45 } 46 const canvasData = await readDreamSongCanvas(repoName); 47 if (!canvasData || !canvasData.nodes) { 48 return []; 49 } 50 51 const fileNodes = canvasData.nodes.filter(node => node.type === 'file' && node.file); 52 const externalDependencies = fileNodes 53 .map(node => node.file) 54 .filter(filePath => !filePath.startsWith(repoName + '/')) 55 .map(filePath => filePath.split('/')[0]); 56 57 return [...new Set(externalDependencies)]; // Remove duplicates 58 } 59 60 function computePositiveDelta(currentSubmodules, dreamSongDependencies) { 61 return dreamSongDependencies.filter(dep => !currentSubmodules.includes(dep)); 62 } 63 64 async function identifyFriendsToNotify(novelSubmodules) { 65 const dreamVaultPath = store.get('dreamVaultPath'); 66 if (!dreamVaultPath) { 67 throw new Error('Dream Vault path is not set in the application settings'); 68 } 69 70 const friendsToNotify = new Map(); 71 72 for (const submodule of novelSubmodules) { 73 const metadataPath = path.join(dreamVaultPath, submodule, '.pl'); 74 try { 75 const data = await fs.readFile(metadataPath, 'utf8'); 76 const metadata = JSON.parse(data); 77 78 if (metadata.relatedNodes && Array.isArray(metadata.relatedNodes)) { 79 for (const friend of metadata.relatedNodes) { 80 if (!friendsToNotify.has(friend)) { 81 const friendMetadataPath = path.join(dreamVaultPath, friend, '.pl'); 82 try { 83 const friendData = await fs.readFile(friendMetadataPath, 'utf8'); 84 const friendMetadata = JSON.parse(friendData); 85 friendsToNotify.set(friend, { 86 email: friendMetadata.email || '', 87 commonSubmodules: [submodule] 88 }); 89 } catch (error) { 90 console.error(`Error reading metadata for friend ${friend}:`, error); 91 friendsToNotify.set(friend, { email: '', commonSubmodules: [submodule] }); 92 } 93 } else { 94 friendsToNotify.get(friend).commonSubmodules.push(submodule); 95 } 96 } 97 } 98 } catch (error) { 99 console.error(`Error reading metadata for ${submodule}:`, error); 100 // Continue to the next submodule if there's an error 101 } 102 } 103 104 return Array.from(friendsToNotify.entries()).map(([name, data]) => ({ 105 name, 106 email: data.email, 107 commonSubmodules: data.commonSubmodules 108 })); 109 } 110 111 module.exports = { 112 parseGitModules, 113 getDreamSongDependencies, 114 computePositiveDelta, 115 identifyFriendsToNotify 116 };