fix: ensure POSIX-compliant newlines in generated files (#856)

- Add final newline check to YAML config generation
- Add final newline check to YAML manifest generation
- Add final newline check to agent .md file generation
- Ensures all text files end with \n per POSIX standard
- Fixes 'No newline at end of file' git warnings
This commit is contained in:
Serhii 2025-11-05 04:18:12 +02:00 committed by GitHub
parent ba5f76c37d
commit c283344a54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 15 deletions

View File

@ -68,7 +68,9 @@ class IdeConfigManager {
sortKeys: false,
});
await fs.writeFile(configPath, yamlContent, 'utf8');
// Ensure POSIX-compliant final newline
const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n';
await fs.writeFile(manifestPath, content, 'utf8');
}
/**

View File

@ -906,8 +906,9 @@ class Installer {
}
}
// Write the clean config file
await fs.writeFile(configPath, header + yamlContent, 'utf8');
// Write the clean config file with POSIX-compliant final newline
const content = header + yamlContent;
await fs.writeFile(configPath, content.endsWith('\n') ? content : content + '\n', 'utf8');
// Track the config file in installedFiles
this.installedFiles.push(configPath);
@ -1195,8 +1196,9 @@ class Installer {
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
// Write the built .md file to bmad/{module}/agents/
await fs.writeFile(mdPath, xmlContent, 'utf8');
// Write the built .md file to bmad/{module}/agents/ with POSIX-compliant final newline
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
await fs.writeFile(mdPath, content, 'utf8');
this.installedFiles.push(mdPath);
// Remove the source YAML file - we can regenerate from installer source if needed
@ -1213,7 +1215,9 @@ class Installer {
if (content.includes('<agent') && !content.includes('<activation')) {
// Inject the activation block using XML handler
content = this.xmlHandler.injectActivationSimple(content);
await fs.writeFile(agentPath, content, 'utf8');
// Ensure POSIX-compliant final newline
const finalContent = content.endsWith('\n') ? content : content + '\n';
await fs.writeFile(agentPath, finalContent, 'utf8');
}
}
}
@ -1294,8 +1298,9 @@ class Installer {
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
// Write the built .md file
await fs.writeFile(targetMdPath, xmlContent, 'utf8');
// Write the built .md file with POSIX-compliant final newline
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
await fs.writeFile(targetMdPath, content, 'utf8');
// Display result
if (customizedFields.length > 0) {
@ -1387,8 +1392,9 @@ class Installer {
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
// Write the rebuilt .md file
await fs.writeFile(targetMdPath, xmlContent, 'utf8');
// Write the rebuilt .md file with POSIX-compliant final newline
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
await fs.writeFile(targetMdPath, content, 'utf8');
// Display result with customizations if any
if (customizedFields.length > 0) {
@ -2005,6 +2011,11 @@ class Installer {
configContent += processedTemplate;
// Ensure POSIX-compliant final newline
if (!configContent.endsWith('\n')) {
configContent += '\n';
}
await fs.writeFile(configPath, configContent, 'utf8');
this.installedFiles.push(configPath); // Track agent config files
createdCount++;

View File

@ -469,7 +469,9 @@ class ManifestGenerator {
sortKeys: false,
});
await fs.writeFile(manifestPath, yamlStr);
// Ensure POSIX-compliant final newline
const content = yamlStr.endsWith('\n') ? yamlStr : yamlStr + '\n';
await fs.writeFile(manifestPath, content);
return manifestPath;
}

View File

@ -35,7 +35,9 @@ class Manifest {
sortKeys: false,
});
await fs.writeFile(manifestPath, yamlContent, 'utf8');
// Ensure POSIX-compliant final newline
const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n';
await fs.writeFile(manifestPath, content, 'utf8');
return { success: true, path: manifestPath, filesTracked: 0 };
}
@ -104,7 +106,9 @@ class Manifest {
sortKeys: false,
});
await fs.writeFile(manifestPath, yamlContent, 'utf8');
// Ensure POSIX-compliant final newline
const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n';
await fs.writeFile(manifestPath, content, 'utf8');
return manifest;
}

View File

@ -33,7 +33,9 @@ class Config {
});
await fs.ensureDir(path.dirname(configPath));
await fs.writeFile(configPath, yamlContent, 'utf8');
// Ensure POSIX-compliant final newline
const content = yamlContent.endsWith('\n') ? yamlContent : yamlContent + '\n';
await fs.writeFile(configPath, content, 'utf8');
}
/**

View File

@ -64,7 +64,8 @@ async function formatYamlContent(content, filename) {
noRefs: true,
sortKeys: false, // Preserve key order
});
return formatted;
// Ensure POSIX-compliant final newline
return formatted.endsWith('\n') ? formatted : formatted + '\n';
} catch (error) {
console.error(chalk.red(`❌ YAML syntax error in ${filename}:`), error.message);
console.error(chalk.yellow(`💡 Try manually fixing the YAML structure first`));