Fix installer: skills path, pitch deck prompt, learn folder location

Three community-reported installer fixes:

1. Remove pitch deck question from installer — this is a workflow
   decision that changes per product, not a one-time config choice.
   Saga now asks at runtime instead.

2. Fix Claude Code skills path from .claude/skills/wds/{name}.md
   to .claude/skills/{name}/SKILL.md (correct format).

3. Move _wds-learn/ from project root into _bmad/wds/learn/ to
   reduce root-level noise in monorepos.

Also: fix LF line endings on npx wrapper, add ROADMAP.md.

Reported by: @Mr-z3r0 (BMad Discord)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mårten Angner 2026-03-12 12:40:34 +01:00
parent dd5fa936bb
commit cfcbdf3b3d
5 changed files with 44 additions and 25 deletions

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## 0.3.4 (unreleased)
### Fixes
- **Pitch deck question removed from installer** - The "start with pitch or Product Brief?" prompt was a config-time decision that should be runtime. Removed from installer; Saga now asks at activation when relevant. Supports monorepo workflows where multiple products have different starting points.
- **Skills file format** - Skills were installed to `.claude/skills/wds/saga.md` but Claude Code expects `.claude/skills/{name}/SKILL.md`. Fixed paths to `.claude/skills/saga/SKILL.md` and `.claude/skills/freya/SKILL.md`.
- **Learning material location** - `_wds-learn/` moved from project root into `_bmad/wds/learn/` to reduce root-level noise, especially in monorepos.
## 0.3.0 (2026-03-01) ## 0.3.0 (2026-03-01)
### Breaking Changes ### Breaking Changes

15
ROADMAP.md Normal file
View File

@ -0,0 +1,15 @@
# WDS Roadmap
## 0.3.4 — Installer Fixes
- [x] Remove pitch deck question from installer (runtime Saga prompt instead)
- [x] Fix skills path to `.claude/skills/{name}/SKILL.md`
- [x] Move `_wds-learn/` into `_bmad/wds/learn/`
## 0.4.0 — Agent Space
Active development on `feature/design-space-agent-messaging`.
- Agent Space (formerly Design Space) — shared semantic knowledge database with agent messaging
- Headless Excalidraw export — local Node script in `tools/` using `@excalidraw/utils` to render `.excalidraw` JSON to PNG. Agent uses it for wireframe previews during Design Loop iteration. Approval gate unchanged — user still exports manually to approve.
- Details TBD as feature branch stabilizes

View File

@ -8,7 +8,7 @@ const chalk = require('chalk');
class ClaudeCodeSetup extends BaseIdeSetup { class ClaudeCodeSetup extends BaseIdeSetup {
constructor() { constructor() {
super('claude-code', 'Claude Code', true); // preferred IDE super('claude-code', 'Claude Code', true); // preferred IDE
this.configDir = '.claude/skills/wds'; this.configDir = '.claude/skills';
} }
/** /**
@ -18,10 +18,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
* @param {Object} options - Setup options * @param {Object} options - Setup options
*/ */
async setup(projectDir, wdsDir, options = {}) { async setup(projectDir, wdsDir, options = {}) {
// Create .claude/skills/wds directory
const targetDir = path.join(projectDir, this.configDir);
await this.ensureDir(targetDir);
// Get all WDS agents // Get all WDS agents
const agents = await this.getAgents(wdsDir); const agents = await this.getAgents(wdsDir);
@ -29,7 +25,8 @@ class ClaudeCodeSetup extends BaseIdeSetup {
throw new Error('No agents found in WDS installation'); throw new Error('No agents found in WDS installation');
} }
// Create launcher file for each agent // Create launcher file for each agent in .claude/skills/{slug}/SKILL.md
const skillsDir = path.join(projectDir, this.configDir);
let agentCount = 0; let agentCount = 0;
for (const agent of agents) { for (const agent of agents) {
// Create launcher content that references the compiled agent // Create launcher content that references the compiled agent
@ -38,8 +35,10 @@ class ClaudeCodeSetup extends BaseIdeSetup {
// Add Claude Code-specific YAML frontmatter // Add Claude Code-specific YAML frontmatter
const content = this.processContent(launcher, agent.metadata); const content = this.processContent(launcher, agent.metadata);
// Write launcher file // Write launcher file as .claude/skills/{slug}/SKILL.md
const filePath = path.join(targetDir, `${agent.slug}.md`); const agentDir = path.join(skillsDir, agent.slug);
await this.ensureDir(agentDir);
const filePath = path.join(agentDir, 'SKILL.md');
await this.writeFile(filePath, content); await this.writeFile(filePath, content);
agentCount++; agentCount++;
} }
@ -84,11 +83,20 @@ description: ${description}
* @param {string} projectDir - Project directory * @param {string} projectDir - Project directory
*/ */
async cleanup(projectDir) { async cleanup(projectDir) {
const wdsPath = path.join(projectDir, this.configDir); // Remove per-agent skill directories
const agents = ['saga', 'freya'];
for (const slug of agents) {
const skillPath = path.join(projectDir, this.configDir, slug);
if (await this.exists(skillPath)) {
await this.remove(skillPath);
}
}
if (await this.exists(wdsPath)) { // Also clean up legacy .claude/skills/wds/ if present
await this.remove(wdsPath); const legacyPath = path.join(projectDir, '.claude/skills/wds');
console.log(chalk.dim(`Removed Claude Code WDS configuration`)); if (await this.exists(legacyPath)) {
await this.remove(legacyPath);
console.log(chalk.dim(`Removed legacy Claude Code WDS configuration`));
} }
} }

View File

@ -166,7 +166,7 @@ class Installer {
const learnSpinner = ora('Copying learning & reference material...').start(); const learnSpinner = ora('Copying learning & reference material...').start();
try { try {
await this.copyLearningMaterial(projectDir); await this.copyLearningMaterial(projectDir);
learnSpinner.succeed('Learning material added to _wds-learn/ (safe to remove when no longer needed)'); learnSpinner.succeed('Learning material added to _bmad/wds/learn/ (safe to remove when no longer needed)');
} catch (error) { } catch (error) {
learnSpinner.fail('Failed to copy learning material'); learnSpinner.fail('Failed to copy learning material');
throw error; throw error;
@ -225,7 +225,6 @@ class Installer {
const configData = { const configData = {
user_name: getUserName(), user_name: getUserName(),
project_name: config.project_name || 'Untitled Project', project_name: config.project_name || 'Untitled Project',
starting_point: config.starting_point || 'brief',
communication_language: 'en', communication_language: 'en',
document_output_language: 'en', document_output_language: 'en',
output_folder: config.root_folder || 'design-process', output_folder: config.root_folder || 'design-process',
@ -260,7 +259,7 @@ class Installer {
* Users can safely delete this folder without affecting agents or workflows. * Users can safely delete this folder without affecting agents or workflows.
*/ */
async copyLearningMaterial(projectDir) { async copyLearningMaterial(projectDir) {
const learnDir = path.join(projectDir, '_wds-learn'); const learnDir = path.join(projectDir, '_bmad/wds/learn');
const learningDirs = ['getting-started', 'learn', 'method', 'models', 'tools']; const learningDirs = ['getting-started', 'learn', 'method', 'models', 'tools'];
const excludeDirs = new Set(['course-explainers', 'Webinars']); const excludeDirs = new Set(['course-explainers', 'Webinars']);

View File

@ -140,16 +140,6 @@ class UI {
message: 'Output folder name:', message: 'Output folder name:',
default: 'design-process', default: 'design-process',
}, },
{
type: 'list',
name: 'starting_point',
message: 'Do you need to create a pitch deck & project contract before starting the project?',
choices: [
{ name: 'No, start directly with the Product Brief', value: 'brief' },
{ name: 'Yes, start with a project pitch', value: 'pitch' },
],
default: 'brief',
},
{ {
type: 'checkbox', type: 'checkbox',
name: 'ides', name: 'ides',