Two related defects were breaking the 'open file' flow:
1. The BrowserWindow webPreferences had no preload path AND
contextIsolation: false, so contextBridge.exposeInMainWorld
threw on load and window.electronAPI was never set. Result:
every renderer-side ipc.* call returned CHANNEL_MISSING and
silently no-op'd. Toolbar Open/Save, the file menu, every
dialog — all broken.
2. The 'file.opened' IPC bridge in register-menu-commands.ts
dispatched to a 'file.opened' command that was never registered
as a handler. Even if the preload had worked, the main menu's
File -> Open would have been a no-op once it reached the
command store.
Fixes:
- window/index.js: add preload path; set contextIsolation: true
(required for contextBridge) and nodeIntegration: false
(renderer no longer needs direct Node access; everything goes
through the whitelisted preload bridge).
- file-store.ts: add openFileFromMain(path, content) that opens
a tab + editor buffer from content the main process already read
(skips the renderer's ipc.file.read since main has the bytes).
Preserves existing buffer content if the file is already open.
- register-menu-commands.ts: register 'file.opened' to call
openFileFromMain. Drop the dead 'command.palette' bridge
(no consumer, no UI, no handler).
- tests: two new cases for openFileFromMain — verifies it does
not call ipc.file.read and does not clobber user edits on
re-open.
Verified end-to-end via the run-desktop driver: triggering
file-opened from the main process with a test .md now shows the
content in BOTH the CodeMirror editor and the rendered preview
pane (plus the Outline panel picks up the H1). 497 tests pass.