bmad-method 6.5.1-next.11 → 6.5.1-next.12
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-method",
|
|
4
|
-
"version": "6.5.1-next.
|
|
4
|
+
"version": "6.5.1-next.12",
|
|
5
5
|
"description": "Breakthrough Method of Agile AI-driven Development",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agile",
|
|
@@ -39,12 +39,13 @@
|
|
|
39
39
|
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
|
|
40
40
|
"lint:md": "markdownlint-cli2 \"**/*.md\"",
|
|
41
41
|
"prepare": "command -v husky >/dev/null 2>&1 && husky || exit 0",
|
|
42
|
-
"quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run test:install && npm run validate:refs && npm run validate:skills",
|
|
42
|
+
"quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run test:install && npm run test:urls && npm run validate:refs && npm run validate:skills",
|
|
43
43
|
"rebundle": "node tools/installer/bundlers/bundle-web.js rebundle",
|
|
44
|
-
"test": "npm run test:refs && npm run test:install && npm run test:channels && npm run lint && npm run lint:md && npm run format:check",
|
|
44
|
+
"test": "npm run test:refs && npm run test:install && npm run test:urls && npm run test:channels && npm run lint && npm run lint:md && npm run format:check",
|
|
45
45
|
"test:channels": "node test/test-installer-channels.js",
|
|
46
46
|
"test:install": "node test/test-installation-components.js",
|
|
47
47
|
"test:refs": "node test/test-file-refs-csv.js",
|
|
48
|
+
"test:urls": "node test/test-parse-source-urls.js",
|
|
48
49
|
"validate:refs": "node tools/validate-file-refs.js --strict",
|
|
49
50
|
"validate:skills": "node tools/validate-skills.js --strict"
|
|
50
51
|
},
|
|
@@ -128,58 +128,102 @@ class CustomModuleManager {
|
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
// HTTPS/HTTP URL:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
131
|
+
// HTTPS/HTTP URL: generic handling for any Git host.
|
|
132
|
+
// We avoid host-specific parsing — `git clone` will accept whatever URL the
|
|
133
|
+
// user provides. We only need to (a) separate an optional browser-style
|
|
134
|
+
// subdir suffix from the clone URL, (b) extract any embedded ref
|
|
135
|
+
// (branch/tag) from deep-path URLs, and (c) derive a cache key / display
|
|
136
|
+
// name from the path. The original protocol (http or https) is preserved.
|
|
137
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
138
|
+
let url;
|
|
139
|
+
try {
|
|
140
|
+
url = new URL(trimmed);
|
|
141
|
+
} catch {
|
|
142
|
+
url = null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (url && url.host) {
|
|
146
|
+
const host = url.host;
|
|
147
|
+
let repoPath = url.pathname.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
148
|
+
let subdir = null;
|
|
149
|
+
let urlRef = null; // branch/tag/commit extracted from deep-path URLs
|
|
150
|
+
|
|
151
|
+
// Detect browser-style deep-path patterns that embed a ref
|
|
152
|
+
// (branch/tag/commit) and optional subdirectory. These appear
|
|
153
|
+
// across many hosts:
|
|
154
|
+
// GitHub /<repo>/tree|blob/<ref>[/<subdir>]
|
|
155
|
+
// GitLab /<repo>/-/tree|blob/<ref>[/<subdir>]
|
|
156
|
+
// Gitea /<repo>/src/<ref>[/<subdir>]
|
|
157
|
+
// Gitea /<repo>/src/(branch|commit|tag)/<ref>[/<subdir>]
|
|
158
|
+
// Group 1 = repo path prefix, Group 2 = ref, Group 3 = subdir (optional).
|
|
141
159
|
const deepPathPatterns = [
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{ regex: /^\/src\/([^/]+)\/(.+)$/, refIdx: 1, pathIdx: 2 }, // Gitea/Forgejo
|
|
160
|
+
/^(.+?)\/(?:-\/)?(?:tree|blob)\/([^/]+)(?:\/(.+))?$/,
|
|
161
|
+
/^(.+?)\/src\/(?:branch\/|commit\/|tag\/)?([^/]+)(?:\/(.+))?$/,
|
|
145
162
|
];
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
for (const p of deepPathPatterns) {
|
|
150
|
-
const match = remainder.match(p.regex);
|
|
163
|
+
for (const pattern of deepPathPatterns) {
|
|
164
|
+
const match = repoPath.match(pattern);
|
|
151
165
|
if (match) {
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
repoPath = match[1];
|
|
167
|
+
if (match[2]) urlRef = match[2];
|
|
168
|
+
if (match[3]) {
|
|
169
|
+
const cleaned = match[3].replace(/\/+$/, '');
|
|
170
|
+
if (cleaned) subdir = cleaned;
|
|
171
|
+
}
|
|
154
172
|
break;
|
|
155
173
|
}
|
|
156
174
|
}
|
|
175
|
+
|
|
176
|
+
// Some hosts use ?path=/subdir on browse links to point at a file or
|
|
177
|
+
// directory. Honor it when no deep-path marker matched above.
|
|
157
178
|
if (!subdir) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
179
|
+
const pathParam = url.searchParams.get('path');
|
|
180
|
+
if (pathParam) {
|
|
181
|
+
const cleaned = pathParam.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
182
|
+
if (cleaned) subdir = cleaned;
|
|
164
183
|
}
|
|
165
184
|
}
|
|
166
|
-
}
|
|
167
185
|
|
|
168
|
-
|
|
169
|
-
|
|
186
|
+
// Strip a single trailing .git for a stable cacheKey/displayName.
|
|
187
|
+
const repoPathClean = repoPath.replace(/\.git$/i, '');
|
|
188
|
+
if (!repoPathClean) {
|
|
189
|
+
return {
|
|
190
|
+
type: null,
|
|
191
|
+
cloneUrl: null,
|
|
192
|
+
subdir: null,
|
|
193
|
+
localPath: null,
|
|
194
|
+
cacheKey: null,
|
|
195
|
+
displayName: null,
|
|
196
|
+
isValid: false,
|
|
197
|
+
error: 'Not a valid Git URL or local path',
|
|
198
|
+
};
|
|
199
|
+
}
|
|
170
200
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
displayName
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
201
|
+
const cloneUrl = `${url.protocol}//${host}/${repoPathClean}`;
|
|
202
|
+
const cacheKey = `${host}/${repoPathClean}`;
|
|
203
|
+
|
|
204
|
+
// Display name: prefer "<owner>/<repo>" using the last two meaningful
|
|
205
|
+
// path segments.
|
|
206
|
+
const segments = repoPathClean.split('/').filter(Boolean);
|
|
207
|
+
const repoSeg = segments.at(-1);
|
|
208
|
+
const ownerSeg = segments.at(-2);
|
|
209
|
+
const displayName = ownerSeg ? `${ownerSeg}/${repoSeg}` : repoSeg;
|
|
210
|
+
|
|
211
|
+
// Precedence: explicit @version suffix > URL /tree/<ref> path segment.
|
|
212
|
+
const version = versionSuffix || urlRef || null;
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
type: 'url',
|
|
216
|
+
cloneUrl,
|
|
217
|
+
subdir,
|
|
218
|
+
localPath: null,
|
|
219
|
+
version,
|
|
220
|
+
rawInput: trimmedRaw,
|
|
221
|
+
cacheKey,
|
|
222
|
+
displayName,
|
|
223
|
+
isValid: true,
|
|
224
|
+
error: null,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
183
227
|
}
|
|
184
228
|
|
|
185
229
|
return {
|