···1515import { initCmd } from './cmd-glue.js';
1616import { discoverExtensions, loadExtensionManifest, isBuiltinExtensionEnabled, getExternalExtensions, type ExtensionManifest, type ManifestCommand, type ManifestShortcut } from './extensions.js';
1717import { initializeFeatures, type FeatureStartupResult } from './feature-startup.js';
1818-import { getLoadedTileIds, getTileManifest } from './tile-launcher.js';
1818+import { getLoadedTileIds, getTileManifest, getAllTileWindows } from './tile-launcher.js';
1919import { initTray } from './tray.js';
2020import { registerLocalShortcut, unregisterLocalShortcut, handleLocalShortcut, registerGlobalShortcut, unregisterGlobalShortcut, unregisterShortcutsForAddress } from './shortcuts.js';
2121import { scopes, publish, subscribe, unsubscribe, hasSubscriber, setExtensionBroadcaster, getSystemAddress } from './pubsub.js';
···201201 } catch {
202202 // Window may have been destroyed between check and send (during shutdown)
203203 }
204204+ }
205205+ }
206206+207207+ // Broadcast to v2 tile BrowserWindows (launched by tile-launcher).
208208+ // Without this, v2 tiles that subscribe to global pubsub events (editor:open,
209209+ // item:created, etc.) never receive them, because they're not in
210210+ // extensionWindows or the consolidated extension host.
211211+ for (const tileWin of getAllTileWindows()) {
212212+ try {
213213+ const winOrigin = tileWin.webContents.getURL();
214214+ const winOriginPrefix = winOrigin.startsWith('peek://')
215215+ ? new URL(winOrigin).origin
216216+ : winOrigin;
217217+ // Don't echo back to sender
218218+ if (winOriginPrefix !== sourceOrigin) {
219219+ tileWin.webContents.send(`pubsub:${topic}`, {
220220+ ...(msg as object),
221221+ source
222222+ });
223223+ }
224224+ } catch {
225225+ // Window may have been destroyed between check and send
204226 }
205227 }
206228 });
+8
backend/electron/tile-launcher.ts
···279279}
280280281281/**
282282+ * Get all BrowserWindow instances for loaded tiles.
283283+ * Used by the pubsub broadcaster to forward messages to v2 tile windows.
284284+ */
285285+export function getAllTileWindows(): BrowserWindow[] {
286286+ return Array.from(tileWindows.values()).filter(win => !win.isDestroyed());
287287+}
288288+289289+/**
282290 * Unload a tile — close its window and revoke tokens
283291 */
284292export function unloadTile(tileId: string, entryId: string): void {