fix(installer): simplify install summary
This commit is contained in:
parent
32693f1a6b
commit
83b0387a5b
|
|
@ -81,6 +81,60 @@ async function createTestBmadFixture() {
|
|||
return fixtureDir;
|
||||
}
|
||||
|
||||
async function createSkillCollisionFixture() {
|
||||
const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-skill-collision-'));
|
||||
const fixtureDir = path.join(fixtureRoot, '_bmad');
|
||||
const configDir = path.join(fixtureDir, '_config');
|
||||
await fs.ensureDir(configDir);
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(configDir, 'agent-manifest.csv'),
|
||||
[
|
||||
'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path,canonicalId',
|
||||
'"bmad-master","BMAD Master","","","","","","","","core","_bmad/core/agents/bmad-master.md","bmad-master"',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(configDir, 'workflow-manifest.csv'),
|
||||
[
|
||||
'name,description,module,path,canonicalId',
|
||||
'"help","Workflow help","core","_bmad/core/workflows/help/workflow.md","bmad-help"',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
await fs.writeFile(path.join(configDir, 'task-manifest.csv'), 'name,displayName,description,module,path,standalone,canonicalId\n');
|
||||
await fs.writeFile(path.join(configDir, 'tool-manifest.csv'), 'name,displayName,description,module,path,standalone,canonicalId\n');
|
||||
await fs.writeFile(
|
||||
path.join(configDir, 'skill-manifest.csv'),
|
||||
[
|
||||
'canonicalId,name,description,module,path,install_to_bmad',
|
||||
'"bmad-help","bmad-help","Native help skill","core","_bmad/core/tasks/bmad-help/SKILL.md","true"',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
const skillDir = path.join(fixtureDir, 'core', 'tasks', 'bmad-help');
|
||||
await fs.ensureDir(skillDir);
|
||||
await fs.writeFile(
|
||||
path.join(skillDir, 'SKILL.md'),
|
||||
['---', 'name: bmad-help', 'description: Native help skill', '---', '', 'Use this skill directly.'].join('\n'),
|
||||
);
|
||||
|
||||
const agentDir = path.join(fixtureDir, 'core', 'agents');
|
||||
await fs.ensureDir(agentDir);
|
||||
await fs.writeFile(
|
||||
path.join(agentDir, 'bmad-master.md'),
|
||||
['---', 'name: BMAD Master', 'description: Master agent', '---', '', '<agent name="BMAD Master" title="Master">', '</agent>'].join(
|
||||
'\n',
|
||||
),
|
||||
);
|
||||
|
||||
return fixtureDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Suite
|
||||
*/
|
||||
|
|
@ -1770,6 +1824,46 @@ async function runTests() {
|
|||
|
||||
console.log('');
|
||||
|
||||
// ============================================================
|
||||
// Test 31: Skill-format installs report unique skill directories
|
||||
// ============================================================
|
||||
console.log(`${colors.yellow}Test Suite 31: Skill Count Reporting${colors.reset}\n`);
|
||||
|
||||
let collisionFixture = null;
|
||||
let collisionProjectDir = null;
|
||||
|
||||
try {
|
||||
clearCache();
|
||||
collisionFixture = await createSkillCollisionFixture();
|
||||
collisionProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-antigravity-test-'));
|
||||
|
||||
const ideManager = new IdeManager();
|
||||
await ideManager.ensureInitialized();
|
||||
const result = await ideManager.setup('antigravity', collisionProjectDir, collisionFixture, {
|
||||
silent: true,
|
||||
selectedModules: ['core'],
|
||||
});
|
||||
|
||||
assert(result.success === true, 'Antigravity setup succeeds with overlapping skill names');
|
||||
assert(result.detail === '2 skills', 'Installer detail reports unique installed skill directories');
|
||||
assert(result.handlerResult.results.skillDirectories === 2, 'Result exposes unique skill directory count');
|
||||
assert(result.handlerResult.results.agents === 2, 'Result retains generated agent write count');
|
||||
assert(result.handlerResult.results.workflows === 1, 'Result retains generated workflow count');
|
||||
assert(result.handlerResult.results.skills === 1, 'Result retains verbatim skill count');
|
||||
assert(
|
||||
await fs.pathExists(path.join(collisionProjectDir, '.agent', 'skills', 'bmad-agent-bmad-master', 'SKILL.md')),
|
||||
'Agent skill directory is created',
|
||||
);
|
||||
assert(await fs.pathExists(path.join(collisionProjectDir, '.agent', 'skills', 'bmad-help', 'SKILL.md')), 'Overlapping skill directory is created once');
|
||||
} catch (error) {
|
||||
assert(false, 'Skill-format unique count test succeeds', error.message);
|
||||
} finally {
|
||||
if (collisionProjectDir) await fs.remove(collisionProjectDir).catch(() => {});
|
||||
if (collisionFixture) await fs.remove(collisionFixture).catch(() => {});
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
// ============================================================
|
||||
// Summary
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -1153,12 +1153,6 @@ class Installer {
|
|||
preservedModules: modulesForCsvPreserve,
|
||||
});
|
||||
|
||||
addResult(
|
||||
'Manifests',
|
||||
'ok',
|
||||
`${manifestStats.workflows} workflows, ${manifestStats.agents} agents, ${manifestStats.tasks} tasks, ${manifestStats.tools} tools`,
|
||||
);
|
||||
|
||||
// Merge help catalogs
|
||||
message('Generating help catalog...');
|
||||
await this.mergeModuleHelpCatalogs(bmadDir);
|
||||
|
|
@ -1379,10 +1373,27 @@ class Installer {
|
|||
*/
|
||||
async renderInstallSummary(results, context = {}) {
|
||||
const color = await prompts.getColor();
|
||||
const selectedIdes = new Set((context.ides || []).map((ide) => String(ide).toLowerCase()));
|
||||
|
||||
// Build step lines with status indicators
|
||||
const lines = [];
|
||||
for (const r of results) {
|
||||
let stepLabel = null;
|
||||
|
||||
if (r.status !== 'ok') {
|
||||
stepLabel = r.step;
|
||||
} else if (r.step === 'Core') {
|
||||
stepLabel = 'BMAD';
|
||||
} else if (r.step.startsWith('Module: ')) {
|
||||
stepLabel = r.step;
|
||||
} else if (selectedIdes.has(String(r.step).toLowerCase())) {
|
||||
stepLabel = r.step;
|
||||
}
|
||||
|
||||
if (!stepLabel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let icon;
|
||||
if (r.status === 'ok') {
|
||||
icon = color.green('\u2713');
|
||||
|
|
@ -1392,7 +1403,11 @@ class Installer {
|
|||
icon = color.red('\u2717');
|
||||
}
|
||||
const detail = r.detail ? color.dim(` (${r.detail})`) : '';
|
||||
lines.push(` ${icon} ${r.step}${detail}`);
|
||||
lines.push(` ${icon} ${stepLabel}${detail}`);
|
||||
}
|
||||
|
||||
if ((context.ides || []).length === 0) {
|
||||
lines.push(` ${color.green('\u2713')} No IDE selected ${color.dim('(installed in _bmad only)')}`);
|
||||
}
|
||||
|
||||
// Context and warnings
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
|
|||
|
||||
const selectedModules = options.selectedModules || [];
|
||||
const results = { agents: 0, workflows: 0, tasks: 0, tools: 0, skills: 0 };
|
||||
this.skillWriteTracker = config.skill_format ? new Set() : null;
|
||||
|
||||
// Install standard artifacts (agents, workflows, tasks, tools)
|
||||
if (!skipStandardArtifacts) {
|
||||
|
|
@ -159,9 +160,11 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
|
|||
// Install verbatim skills (type: skill)
|
||||
if (config.skill_format) {
|
||||
results.skills = await this.installVerbatimSkills(projectDir, bmadDir, targetPath, config);
|
||||
results.skillDirectories = this.skillWriteTracker ? this.skillWriteTracker.size : 0;
|
||||
}
|
||||
|
||||
await this.printSummary(results, target_dir, options);
|
||||
this.skillWriteTracker = null;
|
||||
return { success: true, results };
|
||||
}
|
||||
|
||||
|
|
@ -495,6 +498,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
|
|||
// Create skill directory
|
||||
const skillDir = path.join(targetPath, skillName);
|
||||
await this.ensureDir(skillDir);
|
||||
this.skillWriteTracker?.add(skillName);
|
||||
|
||||
// Transform content: rewrite frontmatter for skills format
|
||||
const skillContent = this.transformToSkillFormat(content, skillName);
|
||||
|
|
@ -667,6 +671,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
|
|||
const skillDir = path.join(targetPath, canonicalId);
|
||||
await fs.remove(skillDir);
|
||||
await fs.ensureDir(skillDir);
|
||||
this.skillWriteTracker?.add(canonicalId);
|
||||
|
||||
// Copy all skill files, filtering OS/editor artifacts recursively
|
||||
const skipPatterns = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']);
|
||||
|
|
@ -707,11 +712,15 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
|
|||
async printSummary(results, targetDir, options = {}) {
|
||||
if (options.silent) return;
|
||||
const parts = [];
|
||||
if (results.agents > 0) parts.push(`${results.agents} agents`);
|
||||
if (results.workflows > 0) parts.push(`${results.workflows} workflows`);
|
||||
if (results.tasks > 0) parts.push(`${results.tasks} tasks`);
|
||||
if (results.tools > 0) parts.push(`${results.tools} tools`);
|
||||
if (results.skills > 0) parts.push(`${results.skills} skills`);
|
||||
if (results.skillDirectories > 0) {
|
||||
parts.push(`${results.skillDirectories} skills`);
|
||||
} else {
|
||||
if (results.agents > 0) parts.push(`${results.agents} agents`);
|
||||
if (results.workflows > 0) parts.push(`${results.workflows} workflows`);
|
||||
if (results.tasks > 0) parts.push(`${results.tasks} tasks`);
|
||||
if (results.tools > 0) parts.push(`${results.tools} tools`);
|
||||
if (results.skills > 0) parts.push(`${results.skills} skills`);
|
||||
}
|
||||
await prompts.log.success(`${this.name} configured: ${parts.join(', ')} → ${targetDir}`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,10 +162,15 @@ class IdeManager {
|
|||
// Config-driven handlers return { success, results: { agents, workflows, tasks, tools } }
|
||||
const r = handlerResult.results;
|
||||
const parts = [];
|
||||
if (r.agents > 0) parts.push(`${r.agents} agents`);
|
||||
if (r.workflows > 0) parts.push(`${r.workflows} workflows`);
|
||||
if (r.tasks > 0) parts.push(`${r.tasks} tasks`);
|
||||
if (r.tools > 0) parts.push(`${r.tools} tools`);
|
||||
if (r.skillDirectories > 0) {
|
||||
parts.push(`${r.skillDirectories} skills`);
|
||||
} else {
|
||||
if (r.agents > 0) parts.push(`${r.agents} agents`);
|
||||
if (r.workflows > 0) parts.push(`${r.workflows} workflows`);
|
||||
if (r.tasks > 0) parts.push(`${r.tasks} tasks`);
|
||||
if (r.tools > 0) parts.push(`${r.tools} tools`);
|
||||
if (r.skills > 0) parts.push(`${r.skills} skills`);
|
||||
}
|
||||
detail = parts.join(', ');
|
||||
}
|
||||
// Propagate handler's success status (default true for backward compat)
|
||||
|
|
|
|||
Loading…
Reference in New Issue