()
| 378 | * not found" state) |
| 379 | */ |
| 380 | export async function registerSeedMarketplaces(): Promise<boolean> { |
| 381 | const seedDirs = getPluginSeedDirs() |
| 382 | if (seedDirs.length === 0) return false |
| 383 | |
| 384 | const primary = await loadKnownMarketplacesConfig() |
| 385 | // First-seed-wins across this registration pass. Can't use the isEqual check |
| 386 | // alone — two seeds with the same name will have different installLocations. |
| 387 | const claimed = new Set<string>() |
| 388 | let changed = 0 |
| 389 | |
| 390 | for (const seedDir of seedDirs) { |
| 391 | const seedConfig = await readSeedKnownMarketplaces(seedDir) |
| 392 | if (!seedConfig) continue |
| 393 | |
| 394 | for (const [name, seedEntry] of Object.entries(seedConfig)) { |
| 395 | if (claimed.has(name)) continue |
| 396 | |
| 397 | // Compute installLocation relative to THIS seedDir, not the build-time |
| 398 | // path baked into the seed's JSON. Handles multi-stage Docker builds |
| 399 | // where the seed is mounted at a different path than where it was built. |
| 400 | const resolvedLocation = await findSeedMarketplaceLocation(seedDir, name) |
| 401 | if (!resolvedLocation) { |
| 402 | // Seed content missing (incomplete build) — leave primary alone, but |
| 403 | // don't claim the name either: a later seed may have working content. |
| 404 | logForDebugging( |
| 405 | `Seed marketplace '${name}' not found under ${seedDir}/marketplaces/, skipping`, |
| 406 | { level: 'warn' }, |
| 407 | ) |
| 408 | continue |
| 409 | } |
| 410 | claimed.add(name) |
| 411 | |
| 412 | const desired: KnownMarketplace = { |
| 413 | source: seedEntry.source, |
| 414 | installLocation: resolvedLocation, |
| 415 | lastUpdated: seedEntry.lastUpdated, |
| 416 | autoUpdate: false, |
| 417 | } |
| 418 | |
| 419 | // Skip if primary already matches — idempotent no-op, no write. |
| 420 | if (isEqual(primary[name], desired)) continue |
| 421 | |
| 422 | // Seed wins — admin-managed. Overwrite any existing primary entry. |
| 423 | primary[name] = desired |
| 424 | changed++ |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | if (changed > 0) { |
| 429 | await saveKnownMarketplacesConfig(primary) |
| 430 | logForDebugging(`Synced ${changed} marketplace(s) from seed dir(s)`) |
| 431 | return true |
| 432 | } |
| 433 | return false |
| 434 | } |
| 435 | |
| 436 | async function readSeedKnownMarketplaces( |
| 437 | seedDir: string, |
no test coverage detected