bmad-method 6.0.5-next.8 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/bmm/agents/analyst.agent.yaml +1 -1
- package/src/bmm/module-help.csv +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +31 -13
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +6 -2
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +4 -0
- package/src/bmm/workflows/4-implementation/code-review/workflow.md +4 -7
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md +0 -4
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +1 -1
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +1 -1
- package/src/core/module-help.csv +2 -2
- package/src/core/workflows/bmad-brainstorming/SKILL.md +6 -0
- package/src/core/workflows/bmad-brainstorming/bmad-skill-manifest.yaml +1 -0
- package/src/core/workflows/{brainstorming → bmad-brainstorming}/workflow.md +2 -5
- package/src/core/workflows/bmad-party-mode/SKILL.md +6 -0
- package/src/core/workflows/bmad-party-mode/bmad-skill-manifest.yaml +1 -0
- package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-03-graceful-exit.md +0 -1
- package/src/core/workflows/{party-mode → bmad-party-mode}/workflow.md +0 -4
- package/tools/cli/external-official-modules.yaml +18 -18
- package/tools/cli/installers/lib/core/installer.js +25 -8
- package/tools/cli/installers/lib/ide/_base-ide.js +0 -1
- package/tools/cli/installers/lib/ide/_config-driven.js +9 -4
- package/tools/cli/installers/lib/ide/manager.js +3 -3
- package/tools/cli/lib/agent/compiler.js +1 -1
- package/.augment/code_review_guidelines.yaml +0 -231
- package/.coderabbit.yaml +0 -85
- package/.github/CODE_OF_CONDUCT.md +0 -128
- package/.github/FUNDING.yaml +0 -15
- package/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -124
- package/.github/ISSUE_TEMPLATE/config.yaml +0 -8
- package/.github/ISSUE_TEMPLATE/documentation.yaml +0 -55
- package/.github/ISSUE_TEMPLATE/feature-request.md +0 -22
- package/.github/ISSUE_TEMPLATE/issue.md +0 -32
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -13
- package/.github/scripts/discord-helpers.sh +0 -34
- package/.github/workflows/coderabbit-review.yaml +0 -22
- package/.github/workflows/discord.yaml +0 -90
- package/.github/workflows/docs.yaml +0 -64
- package/.github/workflows/publish.yaml +0 -133
- package/.github/workflows/quality.yaml +0 -116
- package/.husky/pre-commit +0 -20
- package/.markdownlint-cli2.yaml +0 -41
- package/.nvmrc +0 -1
- package/.prettierignore +0 -12
- package/.vscode/settings.json +0 -96
- package/CHANGELOG.md +0 -1785
- package/CNAME +0 -1
- package/CONTRIBUTING.md +0 -176
- package/CONTRIBUTORS.md +0 -32
- package/SECURITY.md +0 -85
- package/TRADEMARK.md +0 -55
- package/Wordmark.png +0 -0
- package/banner-bmad-method.png +0 -0
- package/docs/404.md +0 -9
- package/docs/_STYLE_GUIDE.md +0 -370
- package/docs/explanation/advanced-elicitation.md +0 -49
- package/docs/explanation/adversarial-review.md +0 -59
- package/docs/explanation/brainstorming.md +0 -33
- package/docs/explanation/established-projects-faq.md +0 -50
- package/docs/explanation/party-mode.md +0 -59
- package/docs/explanation/preventing-agent-conflicts.md +0 -112
- package/docs/explanation/project-context.md +0 -157
- package/docs/explanation/quick-dev-new-preview.md +0 -73
- package/docs/explanation/quick-flow.md +0 -77
- package/docs/explanation/why-solutioning-matters.md +0 -77
- package/docs/how-to/customize-bmad.md +0 -172
- package/docs/how-to/established-projects.md +0 -117
- package/docs/how-to/get-answers-about-bmad.md +0 -138
- package/docs/how-to/install-bmad.md +0 -116
- package/docs/how-to/non-interactive-installation.md +0 -171
- package/docs/how-to/project-context.md +0 -136
- package/docs/how-to/quick-fixes.md +0 -123
- package/docs/how-to/shard-large-documents.md +0 -78
- package/docs/how-to/upgrade-to-v6.md +0 -100
- package/docs/index.md +0 -60
- package/docs/reference/agents.md +0 -28
- package/docs/reference/commands.md +0 -145
- package/docs/reference/modules.md +0 -76
- package/docs/reference/testing.md +0 -106
- package/docs/reference/workflow-map.md +0 -89
- package/docs/roadmap.mdx +0 -136
- package/docs/tutorials/getting-started.md +0 -275
- package/docs/zh-cn/404.md +0 -9
- package/docs/zh-cn/_STYLE_GUIDE.md +0 -370
- package/docs/zh-cn/explanation/advanced-elicitation.md +0 -62
- package/docs/zh-cn/explanation/adversarial-review.md +0 -71
- package/docs/zh-cn/explanation/brainstorming.md +0 -43
- package/docs/zh-cn/explanation/established-projects-faq.md +0 -60
- package/docs/zh-cn/explanation/party-mode.md +0 -79
- package/docs/zh-cn/explanation/preventing-agent-conflicts.md +0 -137
- package/docs/zh-cn/explanation/project-context.md +0 -176
- package/docs/zh-cn/explanation/quick-flow.md +0 -93
- package/docs/zh-cn/explanation/why-solutioning-matters.md +0 -90
- package/docs/zh-cn/how-to/customize-bmad.md +0 -182
- package/docs/zh-cn/how-to/established-projects.md +0 -134
- package/docs/zh-cn/how-to/get-answers-about-bmad.md +0 -144
- package/docs/zh-cn/how-to/install-bmad.md +0 -105
- package/docs/zh-cn/how-to/non-interactive-installation.md +0 -181
- package/docs/zh-cn/how-to/project-context.md +0 -152
- package/docs/zh-cn/how-to/quick-fixes.md +0 -140
- package/docs/zh-cn/how-to/shard-large-documents.md +0 -86
- package/docs/zh-cn/how-to/upgrade-to-v6.md +0 -120
- package/docs/zh-cn/index.md +0 -69
- package/docs/zh-cn/reference/agents.md +0 -41
- package/docs/zh-cn/reference/commands.md +0 -166
- package/docs/zh-cn/reference/modules.md +0 -94
- package/docs/zh-cn/reference/testing.md +0 -122
- package/docs/zh-cn/reference/workflow-map.md +0 -104
- package/docs/zh-cn/roadmap.mdx +0 -152
- package/docs/zh-cn/tutorials/getting-started.md +0 -300
- package/eslint.config.mjs +0 -141
- package/prettier.config.mjs +0 -32
- package/src/core/workflows/brainstorming/bmad-skill-manifest.yaml +0 -3
- package/src/core/workflows/party-mode/bmad-skill-manifest.yaml +0 -3
- package/test/README.md +0 -295
- package/test/adversarial-review-tests/README.md +0 -56
- package/test/adversarial-review-tests/sample-content.md +0 -46
- package/test/adversarial-review-tests/test-cases.yaml +0 -103
- package/test/fixtures/agent-schema/invalid/critical-actions/actions-as-string.agent.yaml +0 -27
- package/test/fixtures/agent-schema/invalid/critical-actions/empty-string-in-actions.agent.yaml +0 -30
- package/test/fixtures/agent-schema/invalid/menu/empty-menu.agent.yaml +0 -22
- package/test/fixtures/agent-schema/invalid/menu/missing-menu.agent.yaml +0 -20
- package/test/fixtures/agent-schema/invalid/menu-commands/empty-command-target.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-commands/no-command-target.agent.yaml +0 -24
- package/test/fixtures/agent-schema/invalid/menu-triggers/camel-case.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-triggers/compound-invalid-format.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-triggers/compound-mismatched-kebab.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-triggers/duplicate-triggers.agent.yaml +0 -31
- package/test/fixtures/agent-schema/invalid/menu-triggers/empty-trigger.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-triggers/leading-asterisk.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-triggers/snake-case.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/menu-triggers/trigger-with-spaces.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/metadata/empty-module-string.agent.yaml +0 -26
- package/test/fixtures/agent-schema/invalid/metadata/empty-name.agent.yaml +0 -24
- package/test/fixtures/agent-schema/invalid/metadata/extra-metadata-fields.agent.yaml +0 -27
- package/test/fixtures/agent-schema/invalid/metadata/missing-id.agent.yaml +0 -23
- package/test/fixtures/agent-schema/invalid/persona/empty-principles-array.agent.yaml +0 -24
- package/test/fixtures/agent-schema/invalid/persona/empty-string-in-principles.agent.yaml +0 -27
- package/test/fixtures/agent-schema/invalid/persona/extra-persona-fields.agent.yaml +0 -27
- package/test/fixtures/agent-schema/invalid/persona/missing-role.agent.yaml +0 -24
- package/test/fixtures/agent-schema/invalid/prompts/empty-content.agent.yaml +0 -29
- package/test/fixtures/agent-schema/invalid/prompts/extra-prompt-fields.agent.yaml +0 -31
- package/test/fixtures/agent-schema/invalid/prompts/missing-content.agent.yaml +0 -28
- package/test/fixtures/agent-schema/invalid/prompts/missing-id.agent.yaml +0 -28
- package/test/fixtures/agent-schema/invalid/top-level/empty-file.agent.yaml +0 -5
- package/test/fixtures/agent-schema/invalid/top-level/extra-top-level-keys.agent.yaml +0 -28
- package/test/fixtures/agent-schema/invalid/top-level/missing-agent-key.agent.yaml +0 -11
- package/test/fixtures/agent-schema/invalid/yaml-errors/invalid-indentation.agent.yaml +0 -19
- package/test/fixtures/agent-schema/invalid/yaml-errors/malformed-yaml.agent.yaml +0 -18
- package/test/fixtures/agent-schema/valid/critical-actions/empty-critical-actions.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/critical-actions/no-critical-actions.agent.yaml +0 -22
- package/test/fixtures/agent-schema/valid/critical-actions/valid-critical-actions.agent.yaml +0 -27
- package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +0 -31
- package/test/fixtures/agent-schema/valid/menu/single-menu-item.agent.yaml +0 -22
- package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +0 -38
- package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +0 -23
- package/test/fixtures/agent-schema/valid/menu-triggers/compound-triggers.agent.yaml +0 -31
- package/test/fixtures/agent-schema/valid/menu-triggers/kebab-case-triggers.agent.yaml +0 -34
- package/test/fixtures/agent-schema/valid/metadata/core-agent-with-module.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/metadata/empty-module-name-in-path.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/metadata/malformed-path-treated-as-core.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/metadata/module-agent-correct.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/metadata/module-agent-missing-module.agent.yaml +0 -23
- package/test/fixtures/agent-schema/valid/metadata/wrong-module-value.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/persona/complete-persona.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/prompts/empty-prompts.agent.yaml +0 -24
- package/test/fixtures/agent-schema/valid/prompts/no-prompts.agent.yaml +0 -22
- package/test/fixtures/agent-schema/valid/prompts/valid-prompts-minimal.agent.yaml +0 -28
- package/test/fixtures/agent-schema/valid/prompts/valid-prompts-with-description.agent.yaml +0 -30
- package/test/fixtures/agent-schema/valid/top-level/minimal-core-agent.agent.yaml +0 -24
- package/test/fixtures/file-refs-csv/invalid/all-empty-workflow.csv +0 -3
- package/test/fixtures/file-refs-csv/invalid/empty-data.csv +0 -1
- package/test/fixtures/file-refs-csv/invalid/no-workflow-column.csv +0 -3
- package/test/fixtures/file-refs-csv/invalid/unresolvable-vars.csv +0 -3
- package/test/fixtures/file-refs-csv/valid/bmm-style.csv +0 -3
- package/test/fixtures/file-refs-csv/valid/core-style.csv +0 -3
- package/test/fixtures/file-refs-csv/valid/minimal.csv +0 -2
- package/test/test-agent-schema.js +0 -387
- package/test/test-cli-integration.sh +0 -159
- package/test/test-file-refs-csv.js +0 -133
- package/test/test-install-to-bmad.js +0 -154
- package/test/test-installation-components.js +0 -1796
- package/test/test-rehype-plugins.mjs +0 -1050
- package/test/test-workflow-path-regex.js +0 -88
- package/test/unit-test-schema.js +0 -133
- package/tools/build-docs.mjs +0 -464
- package/tools/docs/_prompt-external-modules-page.md +0 -59
- package/tools/docs/fix-refs.md +0 -91
- package/tools/docs/native-skills-migration-checklist.md +0 -281
- package/tools/fix-doc-links.js +0 -285
- package/tools/validate-agent-schema.js +0 -110
- package/tools/validate-doc-links.js +0 -407
- package/tools/validate-file-refs.js +0 -556
- package/website/README.md +0 -75
- package/website/astro.config.mjs +0 -157
- package/website/public/diagrams/quick-dev-diagram.png +0 -0
- package/website/public/favicon.ico +0 -0
- package/website/public/img/bmad-dark.png +0 -0
- package/website/public/img/bmad-light.png +0 -0
- package/website/public/workflow-map-diagram.html +0 -361
- package/website/src/components/Banner.astro +0 -62
- package/website/src/components/Header.astro +0 -96
- package/website/src/components/MobileMenuFooter.astro +0 -33
- package/website/src/content/config.ts +0 -7
- package/website/src/content/i18n/zh-CN.json +0 -28
- package/website/src/lib/site-url.mjs +0 -25
- package/website/src/pages/404.astro +0 -11
- package/website/src/pages/robots.txt.ts +0 -48
- package/website/src/rehype-base-paths.js +0 -112
- package/website/src/rehype-markdown-links.js +0 -119
- package/website/src/styles/custom.css +0 -805
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/brain-methods.csv +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-01-session-setup.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-01b-continue.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02a-user-selected.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02b-ai-recommended.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02c-random-selection.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02d-progressive-flow.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-03-technique-execution.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-04-idea-organization.md +0 -0
- /package/src/core/workflows/{brainstorming → bmad-brainstorming}/template.md +0 -0
- /package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-01-agent-loading.md +0 -0
- /package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-02-discussion-orchestration.md +0 -0
package/tools/fix-doc-links.js
DELETED
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fix Documentation Links
|
|
3
|
-
*
|
|
4
|
-
* Converts relative markdown links to repo-relative paths with .md extension.
|
|
5
|
-
* This ensures links work both in GitHub and on the Astro/Starlight site
|
|
6
|
-
* (the rehype plugin transforms /docs/path/file.md → /path/file/ at build time).
|
|
7
|
-
*
|
|
8
|
-
* - ./file.md → /docs/current/path/file.md
|
|
9
|
-
* - ../other/file.md → /docs/resolved/path/file.md
|
|
10
|
-
* - /path/file/ → /docs/path/file.md (or /docs/path/file/index.md if it's a directory)
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* node tools/fix-doc-links.js # Dry run (shows what would change)
|
|
14
|
-
* node tools/fix-doc-links.js --write # Actually write changes
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const fs = require('node:fs');
|
|
18
|
-
const path = require('node:path');
|
|
19
|
-
|
|
20
|
-
const DOCS_ROOT = path.resolve(__dirname, '../docs');
|
|
21
|
-
const DRY_RUN = !process.argv.includes('--write');
|
|
22
|
-
|
|
23
|
-
// Match all markdown links; filtering (external, anchors, assets) happens in convertToRepoRelative.
|
|
24
|
-
// This intentionally matches broadly so the handler can make context-aware decisions.
|
|
25
|
-
const ALL_MARKDOWN_LINKS_REGEX = /\[([^\]]*)\]\(([^)]+)\)/g;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Get all markdown files in docs directory, excluding _* directories/files
|
|
29
|
-
*/
|
|
30
|
-
function getMarkdownFiles(dir) {
|
|
31
|
-
const files = [];
|
|
32
|
-
|
|
33
|
-
function walk(currentDir) {
|
|
34
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
35
|
-
|
|
36
|
-
for (const entry of entries) {
|
|
37
|
-
const fullPath = path.join(currentDir, entry.name);
|
|
38
|
-
|
|
39
|
-
// Skip underscore-prefixed entries
|
|
40
|
-
if (entry.name.startsWith('_')) {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (entry.isDirectory()) {
|
|
45
|
-
walk(fullPath);
|
|
46
|
-
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
47
|
-
files.push(fullPath);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
walk(dir);
|
|
53
|
-
return files;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Convert a markdown link href to repo-relative path with .md extension
|
|
58
|
-
*
|
|
59
|
-
* @param {string} href - The original href (e.g., "./file.md", "/path/to/page/", "/path/to/page/#anchor")
|
|
60
|
-
* @param {string} currentFilePath - Absolute path to the file containing this link
|
|
61
|
-
* @returns {string|null} - Repo-relative path (e.g., "/docs/path/to/file.md"), or null if shouldn't be converted
|
|
62
|
-
*/
|
|
63
|
-
function convertToRepoRelative(href, currentFilePath) {
|
|
64
|
-
// Skip external links (including protocol-relative URLs like //cdn.example.com)
|
|
65
|
-
if (href.includes('://') || href.startsWith('//') || href.startsWith('mailto:') || href.startsWith('tel:')) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Skip anchor-only links
|
|
70
|
-
if (href.startsWith('#')) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Extract anchor and query string if present
|
|
75
|
-
let anchor = '';
|
|
76
|
-
let query = '';
|
|
77
|
-
let pathPortion = href;
|
|
78
|
-
|
|
79
|
-
const hashIndex = href.indexOf('#');
|
|
80
|
-
const queryIndex = href.indexOf('?');
|
|
81
|
-
|
|
82
|
-
if (hashIndex !== -1 || queryIndex !== -1) {
|
|
83
|
-
const firstDelimiter = Math.min(hashIndex === -1 ? Infinity : hashIndex, queryIndex === -1 ? Infinity : queryIndex);
|
|
84
|
-
pathPortion = href.slice(0, Math.max(0, firstDelimiter));
|
|
85
|
-
|
|
86
|
-
const suffix = href.slice(Math.max(0, firstDelimiter));
|
|
87
|
-
const anchorInSuffix = suffix.indexOf('#');
|
|
88
|
-
|
|
89
|
-
if (suffix.startsWith('?')) {
|
|
90
|
-
if (anchorInSuffix === -1) {
|
|
91
|
-
query = suffix;
|
|
92
|
-
} else {
|
|
93
|
-
query = suffix.slice(0, Math.max(0, anchorInSuffix));
|
|
94
|
-
anchor = suffix.slice(Math.max(0, anchorInSuffix));
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
anchor = suffix;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Skip non-documentation links (images, external assets, etc.)
|
|
102
|
-
const ext = path.extname(pathPortion).toLowerCase();
|
|
103
|
-
if (
|
|
104
|
-
ext &&
|
|
105
|
-
ext !== '.md' &&
|
|
106
|
-
!['.md'].includes(ext) && // Has an extension that's not .md - skip unless it's a trailing slash path
|
|
107
|
-
!pathPortion.endsWith('/')
|
|
108
|
-
) {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Check if original path ends with / (directory reference) BEFORE path.join normalizes it
|
|
113
|
-
const isDirectoryPath = pathPortion.endsWith('/');
|
|
114
|
-
|
|
115
|
-
let absolutePath;
|
|
116
|
-
|
|
117
|
-
if (pathPortion.startsWith('/docs/')) {
|
|
118
|
-
// Already repo-relative with /docs/ prefix
|
|
119
|
-
absolutePath = path.join(path.dirname(DOCS_ROOT), pathPortion);
|
|
120
|
-
} else if (pathPortion.startsWith('/')) {
|
|
121
|
-
// Site-relative (e.g., /tutorials/getting-started/) - resolve from docs root
|
|
122
|
-
absolutePath = path.join(DOCS_ROOT, pathPortion);
|
|
123
|
-
} else {
|
|
124
|
-
// Relative path (./, ../, or bare filename) - resolve from current file's directory
|
|
125
|
-
const currentDir = path.dirname(currentFilePath);
|
|
126
|
-
absolutePath = path.resolve(currentDir, pathPortion);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Convert to repo-relative path (with /docs/ prefix)
|
|
130
|
-
let repoRelative = '/docs/' + path.relative(DOCS_ROOT, absolutePath);
|
|
131
|
-
|
|
132
|
-
// Normalize path separators for Windows
|
|
133
|
-
repoRelative = repoRelative.split(path.sep).join('/');
|
|
134
|
-
|
|
135
|
-
// If original path was a directory reference (ended with /), check for index.md or file.md
|
|
136
|
-
if (isDirectoryPath) {
|
|
137
|
-
const relativeDir = repoRelative.slice(6); // Remove '/docs/'
|
|
138
|
-
|
|
139
|
-
// Handle root path case (relativeDir is empty or just '.')
|
|
140
|
-
const normalizedDir = relativeDir === '' || relativeDir === '.' ? '' : relativeDir;
|
|
141
|
-
const indexPath = path.join(DOCS_ROOT, normalizedDir, 'index.md');
|
|
142
|
-
const filePath = normalizedDir ? path.join(DOCS_ROOT, normalizedDir + '.md') : null;
|
|
143
|
-
|
|
144
|
-
if (fs.existsSync(indexPath)) {
|
|
145
|
-
// Avoid double slash when repoRelative is '/docs/' (root case)
|
|
146
|
-
repoRelative = repoRelative.endsWith('/') ? repoRelative + 'index.md' : repoRelative + '/index.md';
|
|
147
|
-
} else if (filePath && fs.existsSync(filePath)) {
|
|
148
|
-
repoRelative = repoRelative + '.md';
|
|
149
|
-
} else {
|
|
150
|
-
// Neither exists - default to index.md and let validation catch it
|
|
151
|
-
repoRelative = repoRelative.endsWith('/') ? repoRelative + 'index.md' : repoRelative + '/index.md';
|
|
152
|
-
}
|
|
153
|
-
} else if (!repoRelative.endsWith('.md')) {
|
|
154
|
-
// Path doesn't end with .md - add .md
|
|
155
|
-
repoRelative = repoRelative + '.md';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return repoRelative + query + anchor;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Process a single markdown file, skipping links inside fenced code blocks
|
|
163
|
-
*
|
|
164
|
-
* @param {string} filePath - Absolute path to the file
|
|
165
|
-
* @returns {Object} - { changed: boolean, original: string, updated: string, changes: Array }
|
|
166
|
-
*/
|
|
167
|
-
function processFile(filePath) {
|
|
168
|
-
const original = fs.readFileSync(filePath, 'utf-8');
|
|
169
|
-
const changes = [];
|
|
170
|
-
|
|
171
|
-
// Extract fenced code blocks and replace with placeholders
|
|
172
|
-
const codeBlocks = [];
|
|
173
|
-
const CODE_PLACEHOLDER = '\u0000CODE_BLOCK_';
|
|
174
|
-
|
|
175
|
-
let contentWithPlaceholders = original.replaceAll(/```[\s\S]*?```/g, (match) => {
|
|
176
|
-
const index = codeBlocks.length;
|
|
177
|
-
codeBlocks.push(match);
|
|
178
|
-
return `${CODE_PLACEHOLDER}${index}\u0000`;
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// Process links only in non-code-block content
|
|
182
|
-
contentWithPlaceholders = contentWithPlaceholders.replaceAll(ALL_MARKDOWN_LINKS_REGEX, (match, linkText, href) => {
|
|
183
|
-
const newHref = convertToRepoRelative(href, filePath);
|
|
184
|
-
|
|
185
|
-
// Skip if conversion returned null (external link, anchor, etc.)
|
|
186
|
-
if (newHref === null) {
|
|
187
|
-
return match;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Only record as change if actually different
|
|
191
|
-
if (newHref !== href) {
|
|
192
|
-
changes.push({ from: href, to: newHref });
|
|
193
|
-
return `[${linkText}](${newHref})`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return match;
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Restore code blocks
|
|
200
|
-
const updated = contentWithPlaceholders.replaceAll(
|
|
201
|
-
new RegExp(`${CODE_PLACEHOLDER}(\\d+)\u0000`, 'g'),
|
|
202
|
-
(match, index) => codeBlocks[parseInt(index, 10)],
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
changed: changes.length > 0,
|
|
207
|
-
original,
|
|
208
|
-
updated,
|
|
209
|
-
changes,
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Validate that a repo-relative link points to an existing file
|
|
215
|
-
*/
|
|
216
|
-
function validateLink(repoRelativePath) {
|
|
217
|
-
// Strip anchor/query
|
|
218
|
-
const checkPath = repoRelativePath.split('#')[0].split('?')[0];
|
|
219
|
-
|
|
220
|
-
// Remove /docs/ prefix to get path relative to DOCS_ROOT
|
|
221
|
-
const relativePath = checkPath.startsWith('/docs/') ? checkPath.slice(6) : checkPath.slice(1);
|
|
222
|
-
|
|
223
|
-
return fs.existsSync(path.join(DOCS_ROOT, relativePath));
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Main execution
|
|
227
|
-
console.log(`\nScanning docs in: ${DOCS_ROOT}`);
|
|
228
|
-
console.log(`Mode: ${DRY_RUN ? 'DRY RUN (use --write to apply changes)' : 'WRITE MODE'}\n`);
|
|
229
|
-
|
|
230
|
-
const files = getMarkdownFiles(DOCS_ROOT);
|
|
231
|
-
console.log(`Found ${files.length} markdown files (excluding _* paths)\n`);
|
|
232
|
-
|
|
233
|
-
let totalChanges = 0;
|
|
234
|
-
let filesChanged = 0;
|
|
235
|
-
const brokenLinks = [];
|
|
236
|
-
|
|
237
|
-
for (const filePath of files) {
|
|
238
|
-
const relativePath = path.relative(DOCS_ROOT, filePath);
|
|
239
|
-
const result = processFile(filePath);
|
|
240
|
-
|
|
241
|
-
if (result.changed) {
|
|
242
|
-
filesChanged++;
|
|
243
|
-
totalChanges += result.changes.length;
|
|
244
|
-
|
|
245
|
-
console.log(`\n${relativePath}`);
|
|
246
|
-
for (const change of result.changes) {
|
|
247
|
-
const isValid = validateLink(change.to);
|
|
248
|
-
const status = isValid ? ' ' : '! ';
|
|
249
|
-
|
|
250
|
-
console.log(`${status} ${change.from}`);
|
|
251
|
-
console.log(` -> ${change.to}`);
|
|
252
|
-
|
|
253
|
-
if (!isValid) {
|
|
254
|
-
brokenLinks.push({
|
|
255
|
-
file: relativePath,
|
|
256
|
-
link: change.to,
|
|
257
|
-
original: change.from,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (!DRY_RUN) {
|
|
263
|
-
fs.writeFileSync(filePath, result.updated, 'utf-8');
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
console.log(`\n${'─'.repeat(60)}`);
|
|
269
|
-
console.log(`\nSummary:`);
|
|
270
|
-
console.log(` Files scanned: ${files.length}`);
|
|
271
|
-
console.log(` Files with changes: ${filesChanged}`);
|
|
272
|
-
console.log(` Total link updates: ${totalChanges}`);
|
|
273
|
-
|
|
274
|
-
if (brokenLinks.length > 0) {
|
|
275
|
-
console.log(`\n! Potential broken links (${brokenLinks.length}):`);
|
|
276
|
-
for (const bl of brokenLinks) {
|
|
277
|
-
console.log(` ${bl.file}: ${bl.link}`);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (DRY_RUN && totalChanges > 0) {
|
|
282
|
-
console.log(`\nRun with --write to apply these changes`);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
console.log('');
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent Schema Validator CLI
|
|
3
|
-
*
|
|
4
|
-
* Scans all *.agent.yaml files in src/{core,modules/*}/agents/
|
|
5
|
-
* and validates them against the Zod schema.
|
|
6
|
-
*
|
|
7
|
-
* Usage: node tools/validate-agent-schema.js [project_root]
|
|
8
|
-
* Exit codes: 0 = success, 1 = validation failures
|
|
9
|
-
*
|
|
10
|
-
* Optional argument:
|
|
11
|
-
* project_root - Directory to scan (defaults to BMAD repo root)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const { glob } = require('glob');
|
|
15
|
-
const yaml = require('yaml');
|
|
16
|
-
const fs = require('node:fs');
|
|
17
|
-
const path = require('node:path');
|
|
18
|
-
const { validateAgentFile } = require('./schema/agent.js');
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Main validation routine
|
|
22
|
-
* @param {string} [customProjectRoot] - Optional project root to scan (for testing)
|
|
23
|
-
*/
|
|
24
|
-
async function main(customProjectRoot) {
|
|
25
|
-
console.log('🔍 Scanning for agent files...\n');
|
|
26
|
-
|
|
27
|
-
// Determine project root: use custom path if provided, otherwise default to repo root
|
|
28
|
-
const project_root = customProjectRoot || path.join(__dirname, '..');
|
|
29
|
-
|
|
30
|
-
// Find all agent files
|
|
31
|
-
const agentFiles = await glob('src/{core,bmm}/agents/**/*.agent.yaml', {
|
|
32
|
-
cwd: project_root,
|
|
33
|
-
absolute: true,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
if (agentFiles.length === 0) {
|
|
37
|
-
console.log('❌ No agent files found. This likely indicates a configuration error.');
|
|
38
|
-
console.log(' Expected to find *.agent.yaml files in src/{core,modules/*}/agents/');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
console.log(`Found ${agentFiles.length} agent file(s)\n`);
|
|
43
|
-
|
|
44
|
-
const errors = [];
|
|
45
|
-
|
|
46
|
-
// Validate each file
|
|
47
|
-
for (const filePath of agentFiles) {
|
|
48
|
-
const relativePath = path.relative(process.cwd(), filePath);
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
52
|
-
const agentData = yaml.parse(fileContent);
|
|
53
|
-
|
|
54
|
-
// Convert absolute path to relative src/ path for module detection
|
|
55
|
-
const srcRelativePath = relativePath.startsWith('src/') ? relativePath : path.relative(project_root, filePath).replaceAll('\\', '/');
|
|
56
|
-
|
|
57
|
-
const result = validateAgentFile(srcRelativePath, agentData);
|
|
58
|
-
|
|
59
|
-
if (result.success) {
|
|
60
|
-
console.log(`✅ ${relativePath}`);
|
|
61
|
-
} else {
|
|
62
|
-
errors.push({
|
|
63
|
-
file: relativePath,
|
|
64
|
-
issues: result.error.issues,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
} catch (error) {
|
|
68
|
-
errors.push({
|
|
69
|
-
file: relativePath,
|
|
70
|
-
issues: [
|
|
71
|
-
{
|
|
72
|
-
code: 'parse_error',
|
|
73
|
-
message: `Failed to parse YAML: ${error.message}`,
|
|
74
|
-
path: [],
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Report errors
|
|
82
|
-
if (errors.length > 0) {
|
|
83
|
-
console.log('\n❌ Validation failed for the following files:\n');
|
|
84
|
-
|
|
85
|
-
for (const { file, issues } of errors) {
|
|
86
|
-
console.log(`\n📄 ${file}`);
|
|
87
|
-
for (const issue of issues) {
|
|
88
|
-
const pathString = issue.path.length > 0 ? issue.path.join('.') : '(root)';
|
|
89
|
-
console.log(` Path: ${pathString}`);
|
|
90
|
-
console.log(` Error: ${issue.message}`);
|
|
91
|
-
if (issue.code) {
|
|
92
|
-
console.log(` Code: ${issue.code}`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
console.log(`\n\n💥 ${errors.length} file(s) failed validation`);
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
console.log(`\n✨ All ${agentFiles.length} agent file(s) passed validation!\n`);
|
|
102
|
-
process.exit(0);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Run with optional command-line argument for project root
|
|
106
|
-
const customProjectRoot = process.argv[2];
|
|
107
|
-
main(customProjectRoot).catch((error) => {
|
|
108
|
-
console.error('Fatal error:', error);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
});
|