bmad-method 6.6.1-next.8 → 6.7.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.
Files changed (27) hide show
  1. package/README.md +3 -3
  2. package/{tools/installer/modules/registry-fallback.yaml → bmad-modules.yaml} +29 -15
  3. package/package.json +4 -4
  4. package/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +18 -11
  5. package/src/bmm-skills/1-analysis/bmad-product-brief/customize.toml +13 -8
  6. package/src/bmm-skills/2-plan-workflows/bmad-prd/SKILL.md +54 -57
  7. package/src/bmm-skills/2-plan-workflows/bmad-prd/assets/headless-schemas.md +2 -2
  8. package/src/bmm-skills/2-plan-workflows/bmad-prd/assets/prd-template.md +40 -30
  9. package/src/bmm-skills/2-plan-workflows/bmad-prd/assets/prd-validation-checklist.md +126 -21
  10. package/src/bmm-skills/2-plan-workflows/bmad-prd/assets/validation-report-template.html +193 -58
  11. package/src/bmm-skills/2-plan-workflows/bmad-prd/customize.toml +47 -13
  12. package/src/bmm-skills/2-plan-workflows/bmad-prd/references/headless.md +27 -12
  13. package/src/bmm-skills/2-plan-workflows/bmad-prd/references/validate.md +97 -0
  14. package/src/bmm-skills/module.yaml +2 -2
  15. package/src/core-skills/module.yaml +1 -1
  16. package/tools/installer/core/installer.js +1 -22
  17. package/tools/installer/core/manifest.js +0 -22
  18. package/tools/installer/modules/channel-plan.js +1 -1
  19. package/tools/installer/modules/external-manager.js +9 -27
  20. package/tools/installer/modules/official-modules.js +9 -48
  21. package/tools/installer/prompts.js +149 -0
  22. package/tools/installer/ui.js +13 -197
  23. package/src/bmm-skills/2-plan-workflows/bmad-prd/references/facilitation-guide.md +0 -79
  24. package/src/bmm-skills/2-plan-workflows/bmad-prd/references/validation-render.md +0 -58
  25. package/src/bmm-skills/2-plan-workflows/bmad-prd/scripts/render-validation-html.py +0 -290
  26. package/tools/installer/modules/community-manager.js +0 -704
  27. package/tools/installer/modules/registry-client.js +0 -187
@@ -1,187 +0,0 @@
1
- const https = require('node:https');
2
- const yaml = require('yaml');
3
-
4
- /**
5
- * Build a rich Error from a non-2xx response. Includes the URL, the GitHub
6
- * JSON error message (or a truncated body snippet), rate-limit reset time,
7
- * and Retry-After — anything present that would help a user recover.
8
- */
9
- function buildHttpError(url, res, body) {
10
- const parts = [`HTTP ${res.statusCode} ${url}`];
11
-
12
- if (body) {
13
- try {
14
- const parsed = JSON.parse(body);
15
- if (parsed.message) parts.push(parsed.message);
16
- if (parsed.documentation_url) parts.push(`(see ${parsed.documentation_url})`);
17
- } catch {
18
- const snippet = body.slice(0, 200).trim();
19
- if (snippet) parts.push(snippet);
20
- }
21
- }
22
-
23
- const remaining = res.headers['x-ratelimit-remaining'];
24
- const reset = res.headers['x-ratelimit-reset'];
25
- if (remaining === '0' && reset) {
26
- parts.push(`rate limit exhausted; resets at ${new Date(Number(reset) * 1000).toISOString()}`);
27
- }
28
-
29
- const retryAfter = res.headers['retry-after'];
30
- if (retryAfter) parts.push(`retry after ${retryAfter}`);
31
-
32
- return new Error(parts.join(' — '));
33
- }
34
-
35
- /**
36
- * Shared HTTP client for fetching registry data from GitHub.
37
- * Used by ExternalModuleManager, CommunityModuleManager, and CustomModuleManager.
38
- */
39
- class RegistryClient {
40
- constructor(options = {}) {
41
- this.timeout = options.timeout || 10_000;
42
- }
43
-
44
- /**
45
- * Fetch a URL and return the response body as a string.
46
- * Follows up to 3 redirects (GitHub sometimes 301s).
47
- * @param {string} url - URL to fetch
48
- * @param {number} [timeout] - Timeout in ms (overrides default)
49
- * @param {number} [maxRedirects=3] - Maximum redirects to follow
50
- * @returns {Promise<string>} Response body
51
- */
52
- fetch(url, timeout, maxRedirects = 3) {
53
- const timeoutMs = timeout || this.timeout;
54
- return new Promise((resolve, reject) => {
55
- const req = https
56
- .get(url, { timeout: timeoutMs }, (res) => {
57
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
58
- if (maxRedirects <= 0) {
59
- return reject(new Error('Too many redirects'));
60
- }
61
- return this.fetch(res.headers.location, timeoutMs, maxRedirects - 1).then(resolve, reject);
62
- }
63
- let data = '';
64
- res.on('data', (chunk) => (data += chunk));
65
- res.on('end', () => {
66
- if (res.statusCode !== 200) {
67
- return reject(buildHttpError(url, res, data));
68
- }
69
- resolve(data);
70
- });
71
- })
72
- .on('error', reject)
73
- .on('timeout', () => {
74
- req.destroy();
75
- reject(new Error('Request timed out'));
76
- });
77
- });
78
- }
79
-
80
- /**
81
- * Fetch a URL and parse the response as YAML.
82
- * @param {string} url - URL to fetch
83
- * @param {number} [timeout] - Timeout in ms
84
- * @returns {Promise<Object>} Parsed YAML content
85
- */
86
- async fetchYaml(url, timeout) {
87
- const content = await this.fetch(url, timeout);
88
- return yaml.parse(content);
89
- }
90
-
91
- /**
92
- * Fetch a file from a GitHub repo using the Contents API first,
93
- * falling back to raw.githubusercontent.com if the API fails.
94
- *
95
- * The API endpoint (`api.github.com`) is tried first because corporate
96
- * proxies commonly block `raw.githubusercontent.com` while allowing
97
- * `api.github.com` under the "Software Development" category.
98
- *
99
- * @param {string} owner - Repository owner (e.g., 'bmad-code-org')
100
- * @param {string} repo - Repository name (e.g., 'bmad-plugins-marketplace')
101
- * @param {string} filePath - Path within the repo (e.g., 'registry/official.yaml')
102
- * @param {string} ref - Git ref (branch, tag, or SHA; e.g., 'main')
103
- * @param {number} [timeout] - Timeout in ms (overrides default)
104
- * @returns {Promise<string>} Raw file content
105
- */
106
- async fetchGitHubFile(owner, repo, filePath, ref, timeout) {
107
- const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${filePath}?ref=${ref}`;
108
- const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${filePath}`;
109
-
110
- // Try GitHub Contents API first (with raw content accept header)
111
- try {
112
- return await this._fetchWithHeaders(apiUrl, { Accept: 'application/vnd.github.raw+json' }, timeout);
113
- } catch (apiError) {
114
- // API failed — fall back to raw CDN
115
- try {
116
- return await this.fetch(rawUrl, timeout);
117
- } catch (cdnError) {
118
- throw new AggregateError([apiError, cdnError], `Both GitHub API and raw CDN failed for ${filePath}`);
119
- }
120
- }
121
- }
122
-
123
- /**
124
- * Fetch a file from GitHub and parse as YAML.
125
- * @param {string} owner - Repository owner
126
- * @param {string} repo - Repository name
127
- * @param {string} filePath - Path within the repo
128
- * @param {string} ref - Git ref
129
- * @param {number} [timeout] - Timeout in ms
130
- * @returns {Promise<Object>} Parsed YAML content
131
- */
132
- async fetchGitHubYaml(owner, repo, filePath, ref, timeout) {
133
- const content = await this.fetchGitHubFile(owner, repo, filePath, ref, timeout);
134
- return yaml.parse(content);
135
- }
136
-
137
- /**
138
- * Fetch a URL with custom headers. Used for GitHub API requests.
139
- * Follows up to 3 redirects.
140
- * @param {string} url - URL to fetch
141
- * @param {Object} headers - Request headers
142
- * @param {number} [timeout] - Timeout in ms
143
- * @param {number} [maxRedirects=3] - Maximum redirects to follow
144
- * @returns {Promise<string>} Response body
145
- * @private
146
- */
147
- _fetchWithHeaders(url, headers, timeout, maxRedirects = 3) {
148
- const timeoutMs = timeout || this.timeout;
149
- const parsed = new URL(url);
150
- const options = {
151
- hostname: parsed.hostname,
152
- path: parsed.pathname + parsed.search,
153
- timeout: timeoutMs,
154
- headers: {
155
- 'User-Agent': 'bmad-installer',
156
- ...headers,
157
- },
158
- };
159
-
160
- return new Promise((resolve, reject) => {
161
- const req = https
162
- .get(options, (res) => {
163
- if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
164
- if (maxRedirects <= 0) {
165
- return reject(new Error('Too many redirects'));
166
- }
167
- return this._fetchWithHeaders(res.headers.location, headers, timeoutMs, maxRedirects - 1).then(resolve, reject);
168
- }
169
- let data = '';
170
- res.on('data', (chunk) => (data += chunk));
171
- res.on('end', () => {
172
- if (res.statusCode !== 200) {
173
- return reject(buildHttpError(url, res, data));
174
- }
175
- resolve(data);
176
- });
177
- })
178
- .on('error', reject)
179
- .on('timeout', () => {
180
- req.destroy();
181
- reject(new Error('Request timed out'));
182
- });
183
- });
184
- }
185
- }
186
-
187
- module.exports = { RegistryClient };