Compare commits

...

15 Commits

Author SHA1 Message Date
Jonah Schulte 6c6096e01b
Merge 5c0dfd85ad into f3f606a9ce 2026-03-17 18:26:47 -04:00
Alex Verkhovsky f3f606a9ce
Merge pull request #2042 from bmad-code-org/feat/coderabbit-docs-check
feat(coderabbit): add docs-staleness check for src/ changes
2026-03-17 15:37:25 -06:00
Alex Verkhovsky 9636e86b75 feat(coderabbit): add docs-staleness check for all src/ changes
Adds a path_instructions entry so CodeRabbit flags when documentation
under docs/ may need updating whenever source files are modified.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:30:32 -06:00
Alex Verkhovsky 88aa53506a
Merge pull request #2039 from bmad-code-org/feat/vscode-opening-ergonomics
feat(quick-dev): add VS Code opening ergonomics to step 5
2026-03-17 09:59:09 -06:00
Alex Verkhovsky 653c3ae152 fix(quick-dev): scope editor open and summary to plan-code-review only
One-shot mode displays the review order in conversation output and has
no spec file to open. Guard the code -r step and spec-specific summary
items behind plan-code-review.
2026-03-17 09:53:34 -06:00
Alex Verkhovsky 39359ddbcd fix(quick-dev): quote spec file path in code -r command
Ensure paths with spaces or special characters are handled correctly
by double-quoting the {spec_file} variable in the editor open command.
2026-03-17 09:52:48 -06:00
Alex Verkhovsky f036c21d13 feat(quick-dev): add VS Code opening ergonomics to step 5
Replace vscode://file/ absolute URI links with workspace-root-relative
markdown links using #L anchors — portable across machines and worktrees.
Add code -r open-in-editor step with graceful fallback, and Ctrl+click
navigation tip for reviewers.
2026-03-17 09:10:38 -06:00
Alex Verkhovsky cc300b3940
Merge pull request #2033 from bmad-code-org/feat/review-trail-generation
feat(quick-dev): add Review Trail generation to step 5
2026-03-17 07:52:45 -06:00
Alex Verkhovsky 6de6f45086 feat(quick-dev): add Review Trail generation to step 5
Step 5 now builds a concern-ordered trail of clickable vscode://file/
links with brief framing and appends it to the spec before committing.
Stops are sequenced by concern (not by file), lead with the entry point,
and use ≤15-word framing focused on design rationale. Single-concern
trails omit grouping labels. The trail is a standalone review artifact
useful without any skill.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 07:51:58 -06:00
Jonah Schulte 5c0dfd85ad
Merge branch 'main' into fix/non-interactive-install-defaults 2026-03-13 20:18:01 -04:00
Jonah Schulte 7422d3a0a3 fix(cli): address PR review feedback for non-interactive install defaults
- Validate cwd with validateDirectorySync in --yes path
- Fix JSDoc placement: move collectCoreConfig docs above its method
- Read user_name default from module.yaml, fall back to OS username
- Harden YAML defaults with type/empty-string normalization
- Log warning on module.yaml load failure instead of silent catch
- Fix backfill predicate to detect unresolved placeholders like {output_folder}
- Always merge defaults into existing config in --yes mode
2026-03-13 16:53:45 -04:00
Jonah Schulte d2e7158c72 Merge branch 'fix/non-interactive-install-defaults' of github.com:jschulte/BMAD-METHOD into fix/non-interactive-install-defaults 2026-03-13 16:49:15 -04:00
Jonah Schulte ac04378a1a Merge remote-tracking branch 'upstream/main' into fix/non-interactive-install-defaults 2026-03-13 16:48:46 -04:00
Jonah Schulte fe2cbe9a78
Merge branch 'main' into fix/non-interactive-install-defaults 2026-03-13 16:29:57 -04:00
Jonah Schulte 1cdc7f4a48 fix(cli): resolve non-interactive install defaults for directory and output_folder
When using --yes with partial CLI options (e.g. --user-name without
--output-folder), the installer had two bugs:

1. Still prompted for directory instead of defaulting to cwd
2. Left {output_folder} unresolved in module configs, creating a literal
   "{output_folder}" directory instead of "_bmad-output"

Extract getDefaultCoreConfig() that reads defaults from
src/core/module.yaml (single source of truth) and use it to backfill
missing fields when --yes skips interactive prompts.
2026-03-13 16:27:26 -04:00
3 changed files with 128 additions and 18 deletions

View File

@ -60,6 +60,13 @@ reviews:
- "!**/validation-report-*.md"
- "!CHANGELOG.md"
path_instructions:
- path: "src/**"
instructions: |
Source file changed. Check whether documentation under docs/ needs
a corresponding update — new features, changed behavior, renamed
concepts, altered CLI flags, or modified configuration options should
all be reflected in the relevant doc pages. Flag missing or outdated
docs as a review comment.
- path: "src/**/skills/**"
instructions: |
Skill file. Apply the full rule catalog defined in tools/skill-validator.md.

View File

@ -10,8 +10,57 @@
## INSTRUCTIONS
1. Change `{spec_file}` status to `done` in the frontmatter.
2. If version control is available and the tree is dirty, create a local commit with a conventional message derived from the spec title.
3. Display summary of your work to the user, including the commit hash if one was created. Advise on how to review the changes. Offer to push and/or create a pull request.
### Generate Suggested Review Order
Determine what changed:
- **Plan-code-review:** Read `{baseline_commit}` from `{spec_file}` frontmatter and construct the diff of all changes since that commit.
- **One-shot:** No baseline exists. Use the files you created or modified during implementation.
**Plan-code-review:** Append the review order as a `## Suggested Review Order` section to `{spec_file}` **after the last existing section**. Do not modify the Code Map.
**One-shot:** Display the review order directly in conversation output.
Build the trail as an ordered sequence of **stops** — clickable `path:line` references with brief framing — optimized for a human reviewer reading top-down to understand the change:
1. **Order by concern, not by file.** Group stops by the conceptual concern they address (e.g., "validation logic", "schema change", "UI binding"). A single file may appear under multiple concerns.
2. **Lead with the entry point** — the single highest-leverage file:line a reviewer should look at first to grasp the design intent.
3. **Inside each concern**, order stops from most important / architecturally interesting to supporting. Lightly bias toward higher-risk or boundary-crossing stops.
4. **End with peripherals** — tests, config, types, and other supporting changes come last.
5. **Every code reference is a clickable workspace-relative link.** Format each stop as a markdown link: `[short-name:line](/project-root-relative/path/to/file.ts#L42)`. The link target uses a leading `/` (workspace root) with a `#L` line anchor. Use the file's basename (or shortest unambiguous suffix) plus line number as the link text.
6. **Each stop gets one ultra-concise line of framing** (≤15 words) — why this approach was chosen here and what it achieves in the context of the change. No paragraphs.
Format each stop as framing first, link on the next indented line:
```markdown
## Suggested Review Order
**{Concern name}**
- {one-line framing}
[`file.ts:42`](/src/path/to/file.ts#L42)
- {one-line framing}
[`other.ts:17`](/src/path/to/other.ts#L17)
**{Next concern}**
- {one-line framing}
[`file.ts:88`](/src/path/to/file.ts#L88)
```
When there is only one concern, omit the bold label — just list the stops directly.
### Commit and Present
1. **Plan-code-review:** Change `{spec_file}` status to `done` in the frontmatter.
2. If version control is available and the tree is dirty, create a local commit with a conventional message derived from the spec title (plan-code-review) or the intent (one-shot).
3. **Plan-code-review only:** Open the spec in the user's editor so they can click through the Suggested Review Order:
- Run `code -r "{spec_file}"` to open the spec in the current VS Code window (reuses the window where the project or worktree is open). Always double-quote the path to handle spaces and special characters.
- If `code` is not available (command fails), skip gracefully and tell the user the spec file path instead.
4. Display summary of your work to the user, including the commit hash if one was created. Include:
- **Plan-code-review:** A note that the spec is open in their editor (or the file path if it couldn't be opened). Mention that `{spec_file}` now contains a Suggested Review Order.
- **Navigation tip:** "Ctrl+click (Cmd+click on macOS) the links in the Suggested Review Order to jump to each stop."
- Offer to push and/or create a pull request.
Workflow complete.

View File

@ -47,6 +47,15 @@ class UI {
}
confirmedDirectory = expandedDir;
await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);
} else if (options.yes) {
// Default to current directory when --yes flag is set
const cwd = process.cwd();
const validation = this.validateDirectorySync(cwd);
if (validation) {
throw new Error(`Invalid current directory: ${validation}`);
}
confirmedDirectory = cwd;
await prompts.log.info(`Using current directory (--yes flag): ${confirmedDirectory}`);
} else {
confirmedDirectory = await this.getConfirmedDirectory();
}
@ -842,6 +851,45 @@ class UI {
return { existingInstall, installedModuleIds, bmadDir };
}
/**
* Get default core config values by reading from src/core/module.yaml
* @returns {Object} Default core config with user_name, communication_language, document_output_language, output_folder
*/
getDefaultCoreConfig() {
const { getModulePath } = require('./project-root');
const yaml = require('yaml');
let safeUsername;
try {
safeUsername = os.userInfo().username;
} catch {
safeUsername = process.env.USER || process.env.USERNAME || 'User';
}
const osUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1);
const norm = (value, fallback) => (typeof value === 'string' && value.trim() !== '' ? value.trim() : fallback);
// Read defaults from core module.yaml (single source of truth)
try {
const moduleYamlPath = path.join(getModulePath('core'), 'module.yaml');
const moduleConfig = yaml.parse(fs.readFileSync(moduleYamlPath, 'utf8'));
return {
user_name: norm(moduleConfig.user_name?.default, osUsername),
communication_language: norm(moduleConfig.communication_language?.default, 'English'),
document_output_language: norm(moduleConfig.document_output_language?.default, 'English'),
output_folder: norm(moduleConfig.output_folder?.default, '_bmad-output'),
};
} catch (error) {
console.warn(`Failed to load module.yaml, falling back to defaults: ${error.message}`);
return {
user_name: osUsername,
communication_language: 'English',
document_output_language: 'English',
output_folder: '_bmad-output',
};
}
}
/**
* Collect core configuration
* @param {string} directory - Installation directory
@ -885,27 +933,33 @@ class UI {
(!options.userName || !options.communicationLanguage || !options.documentOutputLanguage || !options.outputFolder)
) {
await configCollector.collectModuleConfig('core', directory, false, true);
} else if (options.yes) {
// Fill in defaults for any fields not provided via command-line or existing config
const isMissingOrUnresolved = (v) => v == null || (typeof v === 'string' && (v.trim() === '' || /^\{[^}]+\}$/.test(v.trim())));
const defaults = this.getDefaultCoreConfig();
for (const [key, value] of Object.entries(defaults)) {
if (isMissingOrUnresolved(configCollector.collectedConfig.core[key])) {
configCollector.collectedConfig.core[key] = value;
}
}
}
} else if (options.yes) {
// Use all defaults when --yes flag is set
// Use all defaults when --yes flag is set, merging with any existing config
await configCollector.loadExistingConfig(directory);
const existingConfig = configCollector.collectedConfig.core || {};
const defaults = this.getDefaultCoreConfig();
configCollector.collectedConfig.core = { ...defaults, ...existingConfig };
// If no existing config, use defaults
if (Object.keys(existingConfig).length === 0) {
let safeUsername;
try {
safeUsername = os.userInfo().username;
} catch {
safeUsername = process.env.USER || process.env.USERNAME || 'User';
// Clean up any unresolved placeholder tokens from existing config
const isMissingOrUnresolved = (v) => v == null || (typeof v === 'string' && (v.trim() === '' || /^\{[^}]+\}$/.test(v.trim())));
for (const [key, value] of Object.entries(configCollector.collectedConfig.core)) {
if (isMissingOrUnresolved(value)) {
configCollector.collectedConfig.core[key] = defaults[key];
}
const defaultUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1);
configCollector.collectedConfig.core = {
user_name: defaultUsername,
communication_language: 'English',
document_output_language: 'English',
output_folder: '_bmad-output',
};
}
if (Object.keys(existingConfig).length === 0) {
await prompts.log.info('Using default configuration (--yes flag)');
}
} else {