bmad-method 6.5.1-next.2 → 6.5.1-next.3
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,5 +1,6 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
2
|
const os = require('node:os');
|
|
3
|
+
const yaml = require('yaml');
|
|
3
4
|
const fs = require('./fs-native');
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -86,8 +87,11 @@ function getExternalModuleCachePath(moduleName, ...segments) {
|
|
|
86
87
|
* Built-in modules (core, bmm) live under <src>. External official modules are
|
|
87
88
|
* cloned into ~/.bmad/cache/external-modules/<name>/ with varying internal
|
|
88
89
|
* layouts (some at src/module.yaml, some at skills/module.yaml, some nested).
|
|
89
|
-
*
|
|
90
|
-
*
|
|
90
|
+
* Url-source custom modules are cloned into ~/.bmad/cache/custom-modules/<host>/<owner>/<repo>/
|
|
91
|
+
* and are resolved by walking the cache and matching `code` or `name` from the
|
|
92
|
+
* discovered module.yaml. Local custom-source modules are not cached; their
|
|
93
|
+
* path is read from the CustomModuleManager resolution cache set during the
|
|
94
|
+
* same install run.
|
|
91
95
|
* This mirrors the candidate-path search in
|
|
92
96
|
* ExternalModuleManager.findExternalModuleSource but performs no git/network
|
|
93
97
|
* work, which keeps it safe to call during manifest writing.
|
|
@@ -99,11 +103,14 @@ async function resolveInstalledModuleYaml(moduleName) {
|
|
|
99
103
|
const builtIn = path.join(getModulePath(moduleName), 'module.yaml');
|
|
100
104
|
if (await fs.pathExists(builtIn)) return builtIn;
|
|
101
105
|
|
|
102
|
-
//
|
|
103
|
-
|
|
106
|
+
// Collect every module.yaml under a root using the standard candidate paths.
|
|
107
|
+
// Url-source repos can host multiple plugins (discovery mode), so we need all
|
|
108
|
+
// matches, not just the first. Returned in priority order.
|
|
109
|
+
async function searchRootAll(root) {
|
|
110
|
+
const results = [];
|
|
104
111
|
for (const dir of ['skills', 'src']) {
|
|
105
112
|
const direct = path.join(root, dir, 'module.yaml');
|
|
106
|
-
if (await fs.pathExists(direct))
|
|
113
|
+
if (await fs.pathExists(direct)) results.push(direct);
|
|
107
114
|
|
|
108
115
|
const dirPath = path.join(root, dir);
|
|
109
116
|
if (await fs.pathExists(dirPath)) {
|
|
@@ -111,7 +118,7 @@ async function resolveInstalledModuleYaml(moduleName) {
|
|
|
111
118
|
for (const entry of entries) {
|
|
112
119
|
if (!entry.isDirectory()) continue;
|
|
113
120
|
const nested = path.join(dirPath, entry.name, 'module.yaml');
|
|
114
|
-
if (await fs.pathExists(nested))
|
|
121
|
+
if (await fs.pathExists(nested)) results.push(nested);
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
124
|
}
|
|
@@ -121,12 +128,19 @@ async function resolveInstalledModuleYaml(moduleName) {
|
|
|
121
128
|
for (const entry of rootEntries) {
|
|
122
129
|
if (!entry.isDirectory() || !entry.name.endsWith('-setup')) continue;
|
|
123
130
|
const setupAssets = path.join(root, entry.name, 'assets', 'module.yaml');
|
|
124
|
-
if (await fs.pathExists(setupAssets))
|
|
131
|
+
if (await fs.pathExists(setupAssets)) results.push(setupAssets);
|
|
125
132
|
}
|
|
126
133
|
|
|
127
134
|
const atRoot = path.join(root, 'module.yaml');
|
|
128
|
-
if (await fs.pathExists(atRoot))
|
|
129
|
-
return
|
|
135
|
+
if (await fs.pathExists(atRoot)) results.push(atRoot);
|
|
136
|
+
return results;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Backwards-compatible single-result variant for the existing external-cache
|
|
140
|
+
// and resolution-cache fallbacks (one module per root by construction).
|
|
141
|
+
async function searchRoot(root) {
|
|
142
|
+
const all = await searchRootAll(root);
|
|
143
|
+
return all.length > 0 ? all[0] : null;
|
|
130
144
|
}
|
|
131
145
|
|
|
132
146
|
const cacheRoot = getExternalModuleCachePath(moduleName);
|
|
@@ -150,6 +164,37 @@ async function resolveInstalledModuleYaml(moduleName) {
|
|
|
150
164
|
// Resolution cache unavailable — continue
|
|
151
165
|
}
|
|
152
166
|
|
|
167
|
+
// Fallback: url-source custom modules cloned to ~/.bmad/cache/custom-modules/.
|
|
168
|
+
// Walk every cached repo, enumerate ALL module.yaml files via searchRootAll
|
|
169
|
+
// (a single repo can host multiple plugins in discovery mode), and match by
|
|
170
|
+
// the yaml's `code` or `name` field. This works on re-install runs where
|
|
171
|
+
// _resolutionCache is empty and covers both discovery-mode (with marketplace.json)
|
|
172
|
+
// and direct-mode modules, since we identify repo roots by .bmad-source.json
|
|
173
|
+
// (written by cloneRepo) or .claude-plugin/ rather than by marketplace.json.
|
|
174
|
+
try {
|
|
175
|
+
const customCacheDir = path.join(os.homedir(), '.bmad', 'cache', 'custom-modules');
|
|
176
|
+
if (await fs.pathExists(customCacheDir)) {
|
|
177
|
+
const { CustomModuleManager } = require('./modules/custom-module-manager');
|
|
178
|
+
const customMgr = new CustomModuleManager();
|
|
179
|
+
const repoRoots = await customMgr._findCacheRepoRoots(customCacheDir);
|
|
180
|
+
for (const { repoPath } of repoRoots) {
|
|
181
|
+
const candidates = await searchRootAll(repoPath);
|
|
182
|
+
for (const candidate of candidates) {
|
|
183
|
+
try {
|
|
184
|
+
const parsed = yaml.parse(await fs.readFile(candidate, 'utf8'));
|
|
185
|
+
if (parsed && (parsed.code === moduleName || parsed.name === moduleName)) {
|
|
186
|
+
return candidate;
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
// Malformed yaml — skip
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} catch {
|
|
195
|
+
// Custom-modules cache walk failed — continue
|
|
196
|
+
}
|
|
197
|
+
|
|
153
198
|
return null;
|
|
154
199
|
}
|
|
155
200
|
|