experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(electron): remove dead createExtensionWindow callers (Phase 2.5 #3)

+22 -98
+4 -2
app/index.js
··· 804 804 // Initialize core features (non-extension features only) 805 805 features().forEach(initFeature); 806 806 807 - // Extensions are now loaded by main process ExtensionManager 808 - // It receives the 'core:ready' signal and calls loadEnabledExtensions() 807 + // Extensions are now loaded by main process ExtensionManager. 808 + // The main-process startup (entry.ts -> loadExtensions()) runs the v2 809 + // feature pipeline (tile-compat / tile-loader); core background just 810 + // initializes in-process features and waits for `ext:all-loaded`. 809 811 log('core', 'Core features initialized. Extensions loaded by main process.'); 810 812 811 813 // Register extension commands after all extensions (including cmd) are loaded.
-2
backend/electron/index.ts
··· 145 145 initialize, 146 146 discoverBuiltinExtensions, 147 147 discoverBuiltinThemes, 148 - createExtensionWindow, 149 - loadEnabledExtensions, 150 148 loadExtensions, 151 149 getRunningExtensions, 152 150 destroyExtensionWindow,
+4 -32
backend/electron/ipc.ts
··· 94 94 } from './protocol.js'; 95 95 96 96 import { 97 - createExtensionWindow, 98 97 destroyExtensionWindow, 99 98 getExtensionWindow, 100 99 getExtensionHostWindow, ··· 1294 1293 } 1295 1294 }); 1296 1295 1297 - ipcMain.handle('extension-window-load', async (ev, data) => { 1298 - try { 1299 - const extId = data.id; 1300 - const win = await createExtensionWindow(extId); 1301 - if (!win) { 1302 - return { success: false, error: `Failed to load extension ${extId}` }; 1303 - } 1304 - return { success: true, data: { id: extId, windowId: win.id } }; 1305 - } catch (error) { 1306 - const message = error instanceof Error ? error.message : String(error); 1307 - return { success: false, error: message }; 1308 - } 1309 - }); 1310 - 1296 + // Note: `extension-window-load` and `extension-window-reload` were removed 1297 + // in Phase 2.5 #3 (dead handlers — no renderer invoked them). Extension 1298 + // reload now flows through `extension-reload` (ipc.ts below), which is the 1299 + // channel exposed via `api.extensions.reload()` from tile-preload.cts. 1311 1300 ipcMain.handle('extension-window-unload', async (ev, data) => { 1312 1301 try { 1313 1302 const extId = data.id; 1314 1303 const result = destroyExtensionWindow(extId); 1315 1304 return { success: result, data: { id: extId } }; 1316 - } catch (error) { 1317 - const message = error instanceof Error ? error.message : String(error); 1318 - return { success: false, error: message }; 1319 - } 1320 - }); 1321 - 1322 - ipcMain.handle('extension-window-reload', async (ev, data) => { 1323 - try { 1324 - const extId = data.id; 1325 - destroyExtensionWindow(extId); 1326 - // Small delay before reload 1327 - await new Promise(resolve => setTimeout(resolve, 100)); 1328 - const win = await createExtensionWindow(extId); 1329 - if (!win) { 1330 - return { success: false, error: `Failed to reload extension ${extId}` }; 1331 - } 1332 - return { success: true, data: { id: extId, windowId: win.id } }; 1333 1305 } catch (error) { 1334 1306 const message = error instanceof Error ? error.message : String(error); 1335 1307 return { success: false, error: message };
+14 -62
backend/electron/main.ts
··· 1107 1107 1108 1108 /** 1109 1109 * Create an extension window 1110 + * 1111 + * Legacy v1 path — creates a BrowserWindow for a registered extension with the 1112 + * v1 `preload.js`. Still used by `reloadExtension()` (features-manager UI reload 1113 + * button via `api.extensions.reload()`) and `loadDevExtension()` (CLI 1114 + * `--load-extension` flag). The two startup-path callers below 1115 + * (`externalBuiltinIds` + `enabledExternalExts` loops in `loadExtensions()`) 1116 + * are empty in practice — all features in `features/` are v2 and get loaded 1117 + * via `loadV2Tile()`; the `extensions` DB table is superseded by the v2 1118 + * feature registry. See Phase 2.5 #3 audit in AGENT_REPORT.md and 1119 + * `docs/v1-removal-plan.md`. 1120 + * 1121 + * Full removal requires a `relaunchTile(tileId)` helper in tile-launcher.ts — 1122 + * tracked as Phase 2.5 #3b. 1110 1123 */ 1111 - export async function createExtensionWindow(extId: string): Promise<BrowserWindow | null> { 1124 + async function createExtensionWindow(extId: string): Promise<BrowserWindow | null> { 1112 1125 if (extensionWindows.has(extId)) { 1113 1126 DEBUG && console.log(`[ext:win] Extension ${extId} already has a window`); 1114 1127 return extensionWindows.get(extId)!.win; ··· 1183 1196 win.destroy(); 1184 1197 return null; 1185 1198 } 1186 - } 1187 - 1188 - /** 1189 - * Load all enabled extensions with startup phases for optimization 1190 - * 1191 - * Startup phases allow extensions to defer work: 1192 - * - 'early': cmd loads first (it's the command registry) 1193 - * - 'commands': other extensions load, should register commands 1194 - * - 'ui': extensions can initialize UI elements 1195 - * - 'complete': all extensions loaded 1196 - */ 1197 - export async function loadEnabledExtensions(): Promise<number> { 1198 - const extStart = Date.now(); 1199 - const builtinExtIds = getRegisteredExtensionIds(); 1200 - 1201 - // Phase 1: Early 1202 - // Note: cmd (command registry) is no longer loaded here — it's core app code 1203 - // loaded via initCmd() from cmd-glue.ts in the main loadExtensions() path. 1204 - // This alternate loader (loadEnabledExtensions) creates a standalone window 1205 - // per extension, which is NOT how cmd runs — so no cmd handling here. 1206 - publish('system', scopes.GLOBAL, 'ext:startup:phase', { phase: 'early' }); 1207 - 1208 - // Phase 2: Commands - other extensions should register commands 1209 - publish('system', scopes.GLOBAL, 'ext:startup:phase', { phase: 'commands' }); 1210 - 1211 - // Register declarative commands/shortcuts from manifests (after cmd is ready) 1212 - registerDeclarativeCommands(); 1213 - 1214 - // Load built-in extensions in parallel (skip declarative-only) 1215 - const enabledBuiltinIds = builtinExtIds.filter(id => isBuiltinExtensionEnabled(id) && !isDeclarativeOnly(id)); 1216 - 1217 - const parallelStart = Date.now(); 1218 - await Promise.allSettled(enabledBuiltinIds.map(id => createExtensionWindow(id))); 1219 - DEBUG && console.log(`[ext:timing] parallel (${enabledBuiltinIds.join(',')}): ${Date.now() - parallelStart}ms`); 1220 - 1221 - // Load external extensions in parallel 1222 - const externalExts = getExternalExtensions(); 1223 - const enabledExternalExts = externalExts.filter(ext => { 1224 - if (extensionWindows.has(ext.id)) return false; 1225 - if (!ext.enabled || !ext.path) return false; 1226 - return true; 1227 - }); 1228 - 1229 - if (enabledExternalExts.length > 0) { 1230 - const extExtStart = Date.now(); 1231 - await Promise.allSettled(enabledExternalExts.map(ext => createExtensionWindow(ext.id))); 1232 - DEBUG && console.log(`[ext:timing] external: ${Date.now() - extExtStart}ms`); 1233 - } 1234 - 1235 - DEBUG && console.log(`[ext:timing] total: ${Date.now() - extStart}ms`); 1236 - 1237 - // Phase 3: UI - extensions can now initialize UI elements 1238 - publish('system', scopes.GLOBAL, 'ext:startup:phase', { phase: 'ui' }); 1239 - 1240 - // Phase 4: Complete - all extensions loaded 1241 - publish('system', scopes.GLOBAL, 'ext:startup:phase', { phase: 'complete' }); 1242 - publish('system', scopes.GLOBAL, 'ext:all-loaded', { 1243 - count: extensionWindows.size 1244 - }); 1245 - 1246 - return extensionWindows.size; 1247 1199 } 1248 1200 1249 1201 /**