bmad-method 6.3.1-next.19 → 6.3.1-next.20

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.3.1-next.19",
4
+ "version": "6.3.1-next.20",
5
5
  "description": "Breakthrough Method of Agile AI-driven Development",
6
6
  "keywords": [
7
7
  "agile",
@@ -11,6 +11,7 @@ const prompts = require('../prompts');
11
11
  const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
12
12
  const { InstallPaths } = require('./install-paths');
13
13
  const { ExternalModuleManager } = require('../modules/external-manager');
14
+ const { resolveModuleVersion } = require('../modules/version-resolver');
14
15
 
15
16
  const { ExistingInstall } = require('./existing-install');
16
17
 
@@ -24,44 +25,6 @@ class Installer {
24
25
  this.bmadFolderName = BMAD_FOLDER_NAME;
25
26
  }
26
27
 
27
- /**
28
- * Read the module version from .claude-plugin/marketplace.json
29
- * Walks up from sourcePath looking for .claude-plugin/marketplace.json
30
- * @param {string} sourcePath - Module source directory
31
- * @returns {string} Version string or empty string
32
- */
33
- async _getMarketplaceVersion(sourcePath) {
34
- let dir = sourcePath;
35
- for (let i = 0; i < 5; i++) {
36
- const marketplacePath = path.join(dir, '.claude-plugin', 'marketplace.json');
37
- if (await fs.pathExists(marketplacePath)) {
38
- try {
39
- const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8'));
40
- return this._extractMarketplaceVersion(data);
41
- } catch {
42
- return '';
43
- }
44
- }
45
- const parent = path.dirname(dir);
46
- if (parent === dir) break;
47
- dir = parent;
48
- }
49
- return '';
50
- }
51
-
52
- /**
53
- * Extract the highest version from marketplace.json plugins array
54
- */
55
- _extractMarketplaceVersion(data) {
56
- const plugins = data?.plugins;
57
- if (!Array.isArray(plugins) || plugins.length === 0) return '';
58
- let best = '';
59
- for (const p of plugins) {
60
- if (p.version && (!best || p.version > best)) best = p.version;
61
- }
62
- return best;
63
- }
64
-
65
28
  /**
66
29
  * Main installation method
67
30
  * @param {Object} config - Installation configuration
@@ -641,15 +604,18 @@ class Installer {
641
604
  },
642
605
  );
643
606
 
644
- // Get display name from source module.yaml; version from resolution cache or marketplace.json
607
+ // Get display name from source module.yaml and resolve the freshest version metadata we can find locally.
645
608
  const sourcePath = await officialModules.findModuleSource(moduleName, { silent: true });
646
609
  const moduleInfo = sourcePath ? await officialModules.getModuleInfo(sourcePath, moduleName, '') : null;
647
610
  const displayName = moduleInfo?.name || moduleName;
648
611
 
649
- // Prefer version from resolution cache (accurate for custom/local modules),
650
- // fall back to marketplace.json walk-up for official modules
651
612
  const cachedResolution = CustomModuleManager._resolutionCache.get(moduleName);
652
- const version = cachedResolution?.version || (sourcePath ? await this._getMarketplaceVersion(sourcePath) : '');
613
+ const versionInfo = await resolveModuleVersion(moduleName, {
614
+ moduleSourcePath: sourcePath,
615
+ fallbackVersion: cachedResolution?.version,
616
+ marketplacePluginNames: cachedResolution?.pluginName ? [cachedResolution.pluginName] : [],
617
+ });
618
+ const version = versionInfo.version || '';
653
619
  addResult(displayName, 'ok', '', { moduleCode: moduleName, newVersion: version });
654
620
  }
655
621
  }
@@ -1,7 +1,7 @@
1
1
  const path = require('node:path');
2
2
  const fs = require('../fs-native');
3
3
  const crypto = require('node:crypto');
4
- const { getProjectRoot } = require('../project-root');
4
+ const { resolveModuleVersion } = require('../modules/version-resolver');
5
5
  const prompts = require('../prompts');
6
6
 
7
7
  class Manifest {
@@ -258,13 +258,11 @@ class Manifest {
258
258
  * @returns {Object} Version info object with version, source, npmPackage, repoUrl
259
259
  */
260
260
  async getModuleVersionInfo(moduleName, bmadDir, moduleSourcePath = null) {
261
- const yaml = require('yaml');
262
-
263
261
  // Resolve source type first, then read version with the correct path context
264
262
  if (['core', 'bmm'].includes(moduleName)) {
265
- const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath);
263
+ const versionInfo = await resolveModuleVersion(moduleName, { moduleSourcePath });
266
264
  return {
267
- version,
265
+ version: versionInfo.version,
268
266
  source: 'built-in',
269
267
  npmPackage: null,
270
268
  repoUrl: null,
@@ -277,10 +275,9 @@ class Manifest {
277
275
  const moduleInfo = await extMgr.getModuleByCode(moduleName);
278
276
 
279
277
  if (moduleInfo) {
280
- // External module: use moduleSourcePath if provided, otherwise fall back to cache
281
- const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath);
278
+ const versionInfo = await resolveModuleVersion(moduleName, { moduleSourcePath });
282
279
  return {
283
- version,
280
+ version: versionInfo.version,
284
281
  source: 'external',
285
282
  npmPackage: moduleInfo.npmPackage || null,
286
283
  repoUrl: moduleInfo.url || null,
@@ -292,9 +289,12 @@ class Manifest {
292
289
  const communityMgr = new CommunityModuleManager();
293
290
  const communityInfo = await communityMgr.getModuleByCode(moduleName);
294
291
  if (communityInfo) {
295
- const communityVersion = await this._readMarketplaceVersion(moduleName, moduleSourcePath);
292
+ const versionInfo = await resolveModuleVersion(moduleName, {
293
+ moduleSourcePath,
294
+ fallbackVersion: communityInfo.version,
295
+ });
296
296
  return {
297
- version: communityVersion || communityInfo.version,
297
+ version: versionInfo.version || communityInfo.version,
298
298
  source: 'community',
299
299
  npmPackage: communityInfo.npmPackage || null,
300
300
  repoUrl: communityInfo.url || null,
@@ -307,9 +307,13 @@ class Manifest {
307
307
  const resolved = customMgr.getResolution(moduleName);
308
308
  const customSource = await customMgr.findModuleSourceByCode(moduleName, { bmadDir });
309
309
  if (customSource || resolved) {
310
- const customVersion = resolved?.version || (await this._readMarketplaceVersion(moduleName, moduleSourcePath));
310
+ const versionInfo = await resolveModuleVersion(moduleName, {
311
+ moduleSourcePath: moduleSourcePath || customSource,
312
+ fallbackVersion: resolved?.version,
313
+ marketplacePluginNames: resolved?.pluginName ? [resolved.pluginName] : [],
314
+ });
311
315
  return {
312
- version: customVersion,
316
+ version: versionInfo.version,
313
317
  source: 'custom',
314
318
  npmPackage: null,
315
319
  repoUrl: resolved?.repoUrl || null,
@@ -318,64 +322,15 @@ class Manifest {
318
322
  }
319
323
 
320
324
  // Unknown module
321
- const version = await this._readMarketplaceVersion(moduleName, moduleSourcePath);
325
+ const versionInfo = await resolveModuleVersion(moduleName, { moduleSourcePath });
322
326
  return {
323
- version,
327
+ version: versionInfo.version,
324
328
  source: 'unknown',
325
329
  npmPackage: null,
326
330
  repoUrl: null,
327
331
  };
328
332
  }
329
333
 
330
- /**
331
- * Read version from .claude-plugin/marketplace.json for a module
332
- * @param {string} moduleName - Module code
333
- * @returns {string|null} Version or null
334
- */
335
- async _readMarketplaceVersion(moduleName, moduleSourcePath = null) {
336
- const os = require('node:os');
337
- let marketplacePath;
338
-
339
- if (['core', 'bmm'].includes(moduleName)) {
340
- marketplacePath = path.join(getProjectRoot(), '.claude-plugin', 'marketplace.json');
341
- } else if (moduleSourcePath) {
342
- // Walk up from source path to find marketplace.json
343
- let dir = moduleSourcePath;
344
- for (let i = 0; i < 5; i++) {
345
- const candidate = path.join(dir, '.claude-plugin', 'marketplace.json');
346
- if (await fs.pathExists(candidate)) {
347
- marketplacePath = candidate;
348
- break;
349
- }
350
- const parent = path.dirname(dir);
351
- if (parent === dir) break;
352
- dir = parent;
353
- }
354
- }
355
-
356
- // Fallback to external module cache
357
- if (!marketplacePath) {
358
- const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules', moduleName);
359
- marketplacePath = path.join(cacheDir, '.claude-plugin', 'marketplace.json');
360
- }
361
-
362
- try {
363
- if (await fs.pathExists(marketplacePath)) {
364
- const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8'));
365
- const plugins = data?.plugins;
366
- if (!Array.isArray(plugins) || plugins.length === 0) return null;
367
- let best = null;
368
- for (const p of plugins) {
369
- if (p.version && (!best || p.version > best)) best = p.version;
370
- }
371
- return best;
372
- }
373
- } catch {
374
- // ignore
375
- }
376
- return null;
377
- }
378
-
379
334
  /**
380
335
  * Fetch latest version from npm for a package
381
336
  * @param {string} packageName - npm package name
@@ -424,6 +379,7 @@ class Manifest {
424
379
  * @returns {Array} Array of update info objects
425
380
  */
426
381
  async checkForUpdates(bmadDir) {
382
+ const semver = require('semver');
427
383
  const modules = await this.getAllModuleVersions(bmadDir);
428
384
  const updates = [];
429
385
 
@@ -437,7 +393,10 @@ class Manifest {
437
393
  continue;
438
394
  }
439
395
 
440
- if (module.version !== latestVersion) {
396
+ const installedVersion = semver.valid(module.version) || semver.valid(semver.coerce(module.version || ''));
397
+ const availableVersion = semver.valid(latestVersion) || semver.valid(semver.coerce(latestVersion));
398
+
399
+ if (installedVersion && availableVersion && semver.gt(availableVersion, installedVersion)) {
441
400
  updates.push({
442
401
  name: module.name,
443
402
  installedVersion: module.version,
@@ -0,0 +1,336 @@
1
+ const path = require('node:path');
2
+ const semver = require('semver');
3
+ const yaml = require('yaml');
4
+ const fs = require('../fs-native');
5
+ const { getExternalModuleCachePath, getModulePath, resolveInstalledModuleYaml } = require('../project-root');
6
+
7
+ const DEFAULT_PARENT_DEPTH = 8;
8
+
9
+ /**
10
+ * Resolve a module version from authoritative on-disk metadata.
11
+ * Preference order:
12
+ * 1. package.json nearest the module source/cache root
13
+ * 2. module.yaml in the module source directory
14
+ * 3. .claude-plugin/marketplace.json
15
+ * 4. caller-provided fallback version
16
+ *
17
+ * @param {string} moduleName - Module code/name
18
+ * @param {Object} [options]
19
+ * @param {string} [options.moduleSourcePath] - Directory containing module.yaml
20
+ * @param {string} [options.fallbackVersion] - Final fallback when no metadata is found
21
+ * @param {string[]} [options.marketplacePluginNames] - Preferred marketplace plugin names
22
+ * @returns {Promise<{version: string|null, source: string|null, path: string|null}>}
23
+ */
24
+ async function resolveModuleVersion(moduleName, options = {}) {
25
+ const moduleSourcePath = await normalizeDirectoryPath(options.moduleSourcePath);
26
+ const packageJsonPath = await findPackageJsonPath(moduleName, moduleSourcePath);
27
+
28
+ if (packageJsonPath) {
29
+ const packageVersion = await readPackageJsonVersion(packageJsonPath);
30
+ if (packageVersion) {
31
+ return {
32
+ version: packageVersion,
33
+ source: 'package.json',
34
+ path: packageJsonPath,
35
+ };
36
+ }
37
+ }
38
+
39
+ const moduleYamlPath = await findModuleYamlPath(moduleName, moduleSourcePath);
40
+ if (moduleYamlPath) {
41
+ const moduleVersion = await readModuleYamlVersion(moduleYamlPath);
42
+ if (moduleVersion) {
43
+ return {
44
+ version: moduleVersion,
45
+ source: 'module.yaml',
46
+ path: moduleYamlPath,
47
+ };
48
+ }
49
+ }
50
+
51
+ const marketplaceVersion = await findMarketplaceVersion(moduleName, moduleSourcePath, options.marketplacePluginNames || []);
52
+ if (marketplaceVersion) {
53
+ return marketplaceVersion;
54
+ }
55
+
56
+ const fallbackVersion = normalizeVersion(options.fallbackVersion);
57
+ if (fallbackVersion) {
58
+ return {
59
+ version: fallbackVersion,
60
+ source: 'fallback',
61
+ path: null,
62
+ };
63
+ }
64
+
65
+ return {
66
+ version: null,
67
+ source: null,
68
+ path: null,
69
+ };
70
+ }
71
+
72
+ async function findPackageJsonPath(moduleName, moduleSourcePath) {
73
+ const roots = await buildSearchRoots(moduleName, moduleSourcePath);
74
+
75
+ for (const root of roots) {
76
+ const packageJsonPath = await findNearestUpwardFile(root.searchDir, 'package.json', { boundaryDir: root.boundaryDir });
77
+ if (packageJsonPath) {
78
+ return packageJsonPath;
79
+ }
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ async function findModuleYamlPath(moduleName, moduleSourcePath) {
86
+ if (moduleSourcePath) {
87
+ const directModuleYamlPath = path.join(moduleSourcePath, 'module.yaml');
88
+ if (await fs.pathExists(directModuleYamlPath)) {
89
+ return directModuleYamlPath;
90
+ }
91
+ }
92
+
93
+ return resolveInstalledModuleYaml(moduleName);
94
+ }
95
+
96
+ async function findMarketplaceVersion(moduleName, moduleSourcePath, marketplacePluginNames) {
97
+ const roots = await buildSearchRoots(moduleName, moduleSourcePath);
98
+
99
+ for (const root of roots) {
100
+ const marketplacePath = await findNearestUpwardFile(root.searchDir, path.join('.claude-plugin', 'marketplace.json'), {
101
+ boundaryDir: root.boundaryDir,
102
+ });
103
+ if (!marketplacePath) {
104
+ continue;
105
+ }
106
+
107
+ const data = await readJsonFile(marketplacePath);
108
+ if (!data) {
109
+ continue;
110
+ }
111
+
112
+ const version = extractMarketplaceVersion(data, moduleName, marketplacePluginNames);
113
+ if (version) {
114
+ return {
115
+ version,
116
+ source: 'marketplace.json',
117
+ path: marketplacePath,
118
+ };
119
+ }
120
+ }
121
+
122
+ return null;
123
+ }
124
+
125
+ async function buildSearchRoots(moduleName, moduleSourcePath) {
126
+ const roots = [];
127
+ const seen = new Set();
128
+
129
+ const addRoot = async (candidate) => {
130
+ const normalized = await normalizeExistingDirectory(candidate);
131
+ if (!normalized || seen.has(normalized)) {
132
+ return;
133
+ }
134
+
135
+ seen.add(normalized);
136
+ roots.push({
137
+ searchDir: normalized,
138
+ boundaryDir: await findSearchBoundary(normalized),
139
+ });
140
+ };
141
+
142
+ await addRoot(moduleSourcePath);
143
+
144
+ if (moduleName === 'core' || moduleName === 'bmm') {
145
+ await addRoot(getModulePath(moduleName));
146
+ } else {
147
+ await addRoot(getExternalModuleCachePath(moduleName));
148
+ }
149
+
150
+ return roots;
151
+ }
152
+
153
+ async function findNearestUpwardFile(startDir, relativeFilePath, options = {}) {
154
+ const normalizedStartDir = await normalizeExistingDirectory(startDir);
155
+ if (!normalizedStartDir) {
156
+ return null;
157
+ }
158
+
159
+ const maxDepth = options.maxDepth ?? DEFAULT_PARENT_DEPTH;
160
+ const normalizedBoundaryDir = await normalizeDirectoryPath(options.boundaryDir);
161
+ let currentDir = normalizedStartDir;
162
+ for (let depth = 0; depth <= maxDepth; depth++) {
163
+ const candidate = path.join(currentDir, relativeFilePath);
164
+ if (await fs.pathExists(candidate)) {
165
+ return candidate;
166
+ }
167
+
168
+ if (normalizedBoundaryDir && currentDir === normalizedBoundaryDir) {
169
+ break;
170
+ }
171
+
172
+ const parentDir = path.dirname(currentDir);
173
+ if (parentDir === currentDir) {
174
+ break;
175
+ }
176
+ currentDir = parentDir;
177
+ }
178
+
179
+ return null;
180
+ }
181
+
182
+ async function findSearchBoundary(startDir) {
183
+ const normalizedStartDir = await normalizeExistingDirectory(startDir);
184
+ if (!normalizedStartDir) {
185
+ return null;
186
+ }
187
+
188
+ let currentDir = normalizedStartDir;
189
+ for (let depth = 0; depth <= DEFAULT_PARENT_DEPTH; depth++) {
190
+ if (
191
+ (await fs.pathExists(path.join(currentDir, 'package.json'))) ||
192
+ (await fs.pathExists(path.join(currentDir, '.claude-plugin', 'marketplace.json'))) ||
193
+ (await fs.pathExists(path.join(currentDir, '.git')))
194
+ ) {
195
+ return currentDir;
196
+ }
197
+
198
+ const parentDir = path.dirname(currentDir);
199
+ if (parentDir === currentDir) {
200
+ break;
201
+ }
202
+ currentDir = parentDir;
203
+ }
204
+
205
+ return normalizedStartDir;
206
+ }
207
+
208
+ async function normalizeDirectoryPath(candidate) {
209
+ if (!candidate) {
210
+ return null;
211
+ }
212
+
213
+ const resolvedPath = path.resolve(candidate);
214
+ try {
215
+ const stats = await fs.stat(resolvedPath);
216
+ return stats.isDirectory() ? resolvedPath : path.dirname(resolvedPath);
217
+ } catch {
218
+ return resolvedPath;
219
+ }
220
+ }
221
+
222
+ async function normalizeExistingDirectory(candidate) {
223
+ const normalized = await normalizeDirectoryPath(candidate);
224
+ if (!normalized) {
225
+ return null;
226
+ }
227
+
228
+ if (!(await fs.pathExists(normalized))) {
229
+ return null;
230
+ }
231
+
232
+ return normalized;
233
+ }
234
+
235
+ async function readPackageJsonVersion(packageJsonPath) {
236
+ const data = await readJsonFile(packageJsonPath);
237
+ return normalizeVersion(data?.version);
238
+ }
239
+
240
+ async function readModuleYamlVersion(moduleYamlPath) {
241
+ try {
242
+ const content = await fs.readFile(moduleYamlPath, 'utf8');
243
+ const data = yaml.parse(content);
244
+ return normalizeVersion(data?.version || data?.module_version || data?.moduleVersion);
245
+ } catch {
246
+ return null;
247
+ }
248
+ }
249
+
250
+ async function readJsonFile(filePath) {
251
+ try {
252
+ const content = await fs.readFile(filePath, 'utf8');
253
+ return JSON.parse(content);
254
+ } catch {
255
+ return null;
256
+ }
257
+ }
258
+
259
+ function extractMarketplaceVersion(data, moduleName, marketplacePluginNames = []) {
260
+ const plugins = Array.isArray(data?.plugins) ? data.plugins : [];
261
+ if (plugins.length === 0) {
262
+ return null;
263
+ }
264
+
265
+ const preferredNames = new Set(
266
+ [moduleName, ...marketplacePluginNames]
267
+ .filter((value) => typeof value === 'string')
268
+ .map((value) => value.trim())
269
+ .filter(Boolean),
270
+ );
271
+
272
+ const exactMatches = [];
273
+ const fallbackVersions = [];
274
+
275
+ for (const plugin of plugins) {
276
+ const version = normalizeVersion(plugin?.version);
277
+ if (!version) {
278
+ continue;
279
+ }
280
+
281
+ fallbackVersions.push(version);
282
+
283
+ const pluginNames = [plugin?.name, plugin?.code].filter((value) => typeof value === 'string').map((value) => value.trim());
284
+ if (pluginNames.some((name) => preferredNames.has(name))) {
285
+ exactMatches.push(version);
286
+ }
287
+ }
288
+
289
+ return pickBestVersion(exactMatches.length > 0 ? exactMatches : fallbackVersions);
290
+ }
291
+
292
+ function pickBestVersion(versions) {
293
+ const candidates = versions.map(normalizeVersion).filter(Boolean);
294
+ if (candidates.length === 0) {
295
+ return null;
296
+ }
297
+
298
+ candidates.sort(compareVersionsDescending);
299
+ return candidates[0];
300
+ }
301
+
302
+ function compareVersionsDescending(left, right) {
303
+ const leftSemver = normalizeSemver(left);
304
+ const rightSemver = normalizeSemver(right);
305
+
306
+ if (leftSemver && rightSemver) {
307
+ return semver.rcompare(leftSemver, rightSemver);
308
+ }
309
+
310
+ if (leftSemver) {
311
+ return -1;
312
+ }
313
+
314
+ if (rightSemver) {
315
+ return 1;
316
+ }
317
+
318
+ return right.localeCompare(left, undefined, { numeric: true, sensitivity: 'base' });
319
+ }
320
+
321
+ function normalizeSemver(version) {
322
+ return semver.valid(version) || semver.valid(semver.coerce(version));
323
+ }
324
+
325
+ function normalizeVersion(version) {
326
+ if (typeof version !== 'string') {
327
+ return null;
328
+ }
329
+
330
+ const trimmed = version.trim();
331
+ return trimmed || null;
332
+ }
333
+
334
+ module.exports = {
335
+ resolveModuleVersion,
336
+ };
@@ -3,48 +3,17 @@ const os = require('node:os');
3
3
  const fs = require('./fs-native');
4
4
  const { CLIUtils } = require('./cli-utils');
5
5
  const { ExternalModuleManager } = require('./modules/external-manager');
6
- const { getProjectRoot } = require('./project-root');
6
+ const { resolveModuleVersion } = require('./modules/version-resolver');
7
7
  const prompts = require('./prompts');
8
8
 
9
9
  /**
10
- * Read module version from .claude-plugin/marketplace.json
10
+ * Read a module version from the freshest local metadata available.
11
11
  * @param {string} moduleCode - Module code (e.g., 'core', 'bmm', 'cis')
12
12
  * @returns {string} Version string or empty string
13
13
  */
14
- async function getMarketplaceVersion(moduleCode) {
15
- let marketplacePath;
16
- if (moduleCode === 'core' || moduleCode === 'bmm') {
17
- marketplacePath = path.join(getProjectRoot(), '.claude-plugin', 'marketplace.json');
18
- } else {
19
- const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules', moduleCode);
20
- marketplacePath = path.join(cacheDir, '.claude-plugin', 'marketplace.json');
21
- }
22
- try {
23
- if (await fs.pathExists(marketplacePath)) {
24
- const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8'));
25
- return _extractMarketplaceVersion(data);
26
- }
27
- } catch {
28
- // ignore
29
- }
30
- return '';
31
- }
32
-
33
- /**
34
- * Extract the highest version from marketplace.json plugins array.
35
- * Handles multiple plugins per file safely.
36
- * @param {Object} data - Parsed marketplace.json
37
- * @returns {string} Version string or empty string
38
- */
39
- function _extractMarketplaceVersion(data) {
40
- const plugins = data?.plugins;
41
- if (!Array.isArray(plugins) || plugins.length === 0) return '';
42
- // Use the highest version across all plugins in the file
43
- let best = '';
44
- for (const p of plugins) {
45
- if (p.version && (!best || p.version > best)) best = p.version;
46
- }
47
- return best;
14
+ async function getModuleVersion(moduleCode) {
15
+ const versionInfo = await resolveModuleVersion(moduleCode);
16
+ return versionInfo.version || '';
48
17
  }
49
18
 
50
19
  /**
@@ -644,7 +613,7 @@ class UI {
644
613
 
645
614
  const buildModuleEntry = async (code, name, description, isDefault) => {
646
615
  const isInstalled = installedModuleIds.has(code);
647
- const version = await getMarketplaceVersion(code);
616
+ const version = await getModuleVersion(code);
648
617
  const label = version ? `${name} (v${version})` : name;
649
618
  return {
650
619
  label,