Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
6.0 kB · 184 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185/** * Background plugin and marketplace installation manager * * This module handles automatic installation of plugins and marketplaces * from trusted sources (repository and user settings) without blocking startup. */
import type { AppState } from '../../state/AppState.js'import { logForDebugging } from '../../utils/debug.js'import { logForDiagnosticsNoPII } from '../../utils/diagLogs.js'import { logError } from '../../utils/log.js'import { clearMarketplacesCache, getDeclaredMarketplaces, loadKnownMarketplacesConfig,} from '../../utils/plugins/marketplaceManager.js'import { clearPluginCache } from '../../utils/plugins/pluginLoader.js'import { diffMarketplaces, reconcileMarketplaces,} from '../../utils/plugins/reconciler.js'import { refreshActivePlugins } from '../../utils/plugins/refresh.js'import { logEvent } from '../analytics/index.js'
type SetAppState = (f: (prevState: AppState) => AppState) => void
/** * Update marketplace installation status in app state */function updateMarketplaceStatus( setAppState: SetAppState, name: string, status: 'pending' | 'installing' | 'installed' | 'failed', error?: string,): void { setAppState(prevState => ({ ...prevState, plugins: { ...prevState.plugins, installationStatus: { ...prevState.plugins.installationStatus, marketplaces: prevState.plugins.installationStatus.marketplaces.map( m => (m.name === name ? { ...m, status, error } : m), ), }, }, }))}
/** * Perform background plugin startup checks and installations. * * This is a thin wrapper around reconcileMarketplaces() that maps onProgress * events to AppState updates for the REPL UI. After marketplaces are * reconciled: * - New installs → auto-refresh plugins (fixes "plugin-not-found" errors * from the initial cache-only load on fresh homespace/cleared cache) * - Updates only → set needsRefresh, show notification for /reload-plugins */export async function performBackgroundPluginInstallations( setAppState: SetAppState,): Promise<void> { logForDebugging('performBackgroundPluginInstallations called')
try { // Compute diff upfront for initial UI status (pending spinners) const declared = getDeclaredMarketplaces() const materialized = await loadKnownMarketplacesConfig().catch(() => ({})) const diff = diffMarketplaces(declared, materialized)
const pendingNames = [ ...diff.missing, ...diff.sourceChanged.map(c => c.name), ]
// Initialize AppState with pending status. No per-plugin pending status — // plugin load is fast (cache hit or local copy); marketplace clone is the // slow part worth showing progress for. setAppState(prev => ({ ...prev, plugins: { ...prev.plugins, installationStatus: { marketplaces: pendingNames.map(name => ({ name, status: 'pending' as const, })), plugins: [], }, }, }))
if (pendingNames.length === 0) { return }
logForDebugging( `Installing ${pendingNames.length} marketplace(s) in background`, )
const result = await reconcileMarketplaces({ onProgress: event => { switch (event.type) { case 'installing': updateMarketplaceStatus(setAppState, event.name, 'installing') break case 'installed': updateMarketplaceStatus(setAppState, event.name, 'installed') break case 'failed': updateMarketplaceStatus( setAppState, event.name, 'failed', event.error, ) break } }, })
const metrics = { installed_count: result.installed.length, updated_count: result.updated.length, failed_count: result.failed.length, up_to_date_count: result.upToDate.length, } logEvent('tengu_marketplace_background_install', metrics) logForDiagnosticsNoPII( 'info', 'tengu_marketplace_background_install', metrics, )
if (result.installed.length > 0) { // New marketplaces were installed — auto-refresh plugins. This fixes // "Plugin not found in marketplace" errors from the initial cache-only // load (e.g., fresh homespace where marketplace cache was empty). // refreshActivePlugins clears all caches, reloads plugins, and bumps // pluginReconnectKey so MCP connections are re-established. clearMarketplacesCache() logForDebugging( `Auto-refreshing plugins after ${result.installed.length} new marketplace(s) installed`, ) try { await refreshActivePlugins(setAppState) } catch (refreshError) { // If auto-refresh fails, fall back to needsRefresh notification so // the user can manually run /reload-plugins to recover. logError(refreshError) logForDebugging( `Auto-refresh failed, falling back to needsRefresh: ${refreshError}`, { level: 'warn' }, ) clearPluginCache( 'performBackgroundPluginInstallations: auto-refresh failed', ) setAppState(prev => { if (prev.plugins.needsRefresh) return prev return { ...prev, plugins: { ...prev.plugins, needsRefresh: true }, } }) } } else if (result.updated.length > 0) { // Existing marketplaces updated — notify user to run /reload-plugins. // Updates are less urgent and the user should choose when to apply them. clearMarketplacesCache() clearPluginCache( 'performBackgroundPluginInstallations: marketplaces reconciled', ) setAppState(prev => { if (prev.plugins.needsRefresh) return prev return { ...prev, plugins: { ...prev.plugins, needsRefresh: true }, } }) } } catch (error) { logError(error) }}