From a6dffb4706e2523226875cb58e1a7c411acb8826 Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Sat, 6 Dec 2025 10:36:17 -0800 Subject: [PATCH] fix(installer): remove hardcoded 'bmad' prefix from files-manifest.csv paths (#1043) The manifest writer hardcoded 'bmad' as the path prefix regardless of the actual folder name (.bmad, bmad, etc). The reader had a matching hardcoded strip, so it worked by accident. Now paths are stored relative to bmadDir without any prefix. Legacy fallback strips 'bmad/' on read - safe because no real path inside bmadDir would start with 'bmad/'. Co-authored-by: Brian --- tools/cli/installers/lib/core/installer.js | 5 +++-- tools/cli/installers/lib/core/manifest-generator.js | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index db8333bb..f113c141 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -2210,8 +2210,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: const installedFilesMap = new Map(); for (const fileEntry of existingFilesManifest) { if (fileEntry.path) { - // Files in manifest are stored as relative paths starting with 'bmad/' - // Convert to absolute path + // Paths are relative to bmadDir. Legacy manifests incorrectly prefixed 'bmad/' - + // strip it if present. This is safe because no real path inside bmadDir would + // start with 'bmad/' (you'd never have .bmad/bmad/... as an actual structure). const relativePath = fileEntry.path.startsWith('bmad/') ? fileEntry.path.slice(5) : fileEntry.path; const absolutePath = path.join(bmadDir, relativePath); installedFilesMap.set(path.normalize(absolutePath), { diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index 644fd494..f10d0deb 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -650,13 +650,14 @@ class ManifestGenerator { if (this.allInstalledFiles && this.allInstalledFiles.length > 0) { // Process all installed files for (const filePath of this.allInstalledFiles) { - const relativePath = 'bmad' + filePath.replace(this.bmadDir, '').replaceAll('\\', '/'); + // Store paths relative to bmadDir (no folder prefix) + const relativePath = filePath.replace(this.bmadDir, '').replaceAll('\\', '/').replace(/^\//, ''); const ext = path.extname(filePath).toLowerCase(); const fileName = path.basename(filePath, ext); - // Determine module from path + // Determine module from path (first directory component) const pathParts = relativePath.split('/'); - const module = pathParts.length > 1 ? pathParts[1] : 'unknown'; + const module = pathParts.length > 0 ? pathParts[0] : 'unknown'; // Calculate hash const hash = await this.calculateFileHash(filePath); @@ -672,10 +673,13 @@ class ManifestGenerator { } else { // Fallback: use the collected workflows/agents/tasks for (const file of this.files) { - const filePath = path.join(this.bmadDir, file.path.replace(this.bmadFolderName + '/', '')); + // Strip the folder prefix if present (for consistency) + const relPath = file.path.replace(this.bmadFolderName + '/', ''); + const filePath = path.join(this.bmadDir, relPath); const hash = await this.calculateFileHash(filePath); allFiles.push({ ...file, + path: relPath, hash: hash, }); }