diff --git a/tools/installer/core/manifest-generator.js b/tools/installer/core/manifest-generator.js index f7b5d0084..50aaf870a 100644 --- a/tools/installer/core/manifest-generator.js +++ b/tools/installer/core/manifest-generator.js @@ -544,6 +544,28 @@ class ManifestGenerator { userLines.push(''); } + const updatedModuleSet = new Set(this.updatedModules); + const preservedModuleBlocks = { team: [], user: [] }; + if (updatedModuleSet.size > 0) { + const collectPreservedModuleBlocks = async (filePath, target) => { + if (!(await fs.pathExists(filePath))) return; + try { + const prev = await fs.readFile(filePath, 'utf8'); + for (const block of extractModuleBlocks(prev)) { + if (!updatedModuleSet.has(block.code)) continue; + if (moduleConfigs[block.code] && Object.keys(moduleConfigs[block.code]).length > 0) continue; + target.push(block.body); + } + } catch (error) { + console.warn( + `[warn] writeCentralConfig: could not read prior ${path.basename(filePath)} to preserve module config: ${error.message}`, + ); + } + }; + await collectPreservedModuleBlocks(teamPath, preservedModuleBlocks.team); + await collectPreservedModuleBlocks(userPath, preservedModuleBlocks.user); + } + // [modules.] — split per module for (const moduleName of this.updatedModules) { if (moduleName === 'core') continue; @@ -574,6 +596,13 @@ class ManifestGenerator { } } + for (const body of preservedModuleBlocks.team) { + teamLines.push(body, ''); + } + for (const body of preservedModuleBlocks.user) { + userLines.push(body, ''); + } + // [agents.] — always team (agent roster is organizational). // Freshly collected agents come from module.yaml this run. If a module // was preserved (e.g. during quickUpdate when its source isn't available), @@ -856,4 +885,26 @@ function extractAgentBlocks(tomlContent) { return blocks; } +function extractModuleBlocks(tomlContent) { + const lines = tomlContent.split(/\r?\n/); + const blocks = []; + for (let i = 0; i < lines.length; i++) { + const startMatch = lines[i].match(/^\[modules\.([^\]]+)\]\s*$/); + if (!startMatch) continue; + const code = startMatch[1]; + const bodyLines = [lines[i]]; + i++; + while (i < lines.length && !/^\[[^\]]+\]\s*$/.test(lines[i])) { + bodyLines.push(lines[i]); + i++; + } + i--; + while (bodyLines.length > 0 && bodyLines.at(-1).trim() === '') { + bodyLines.pop(); + } + blocks.push({ code, body: bodyLines.join('\n') }); + } + return blocks; +} + module.exports = { ManifestGenerator };