diff --git a/CHANGELOG.md b/CHANGELOG.md index d5697488..d1efd4b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,12 @@ ### Features -* v0.14.0 — local HTTP API, quick capture, plugins, Vercel fix ([#232](https://github.com/tomymaritano/readide/issues/232)) ([19301a8](https://github.com/tomymaritano/readide/commit/19301a895f15fa9464d67b7e879502e751b08ab8)) +- v0.14.0 — local HTTP API, quick capture, plugins, Vercel fix ([#232](https://github.com/tomymaritano/readide/issues/232)) ([19301a8](https://github.com/tomymaritano/readide/commit/19301a895f15fa9464d67b7e879502e751b08ab8)) ### Bug Fixes -* v0.14.1 — ASAR startup crash fix ([#234](https://github.com/tomymaritano/readide/issues/234)) ([b051785](https://github.com/tomymaritano/readide/commit/b0517852c52241a633344907974e962a376f8dc1)) -* v0.14.2 — ASAR startup crash fix (devDependencies) ([#236](https://github.com/tomymaritano/readide/issues/236)) ([17b951a](https://github.com/tomymaritano/readide/commit/17b951a634ea55992ce29afad1d969dd821f1f29)) +- v0.14.1 — ASAR startup crash fix ([#234](https://github.com/tomymaritano/readide/issues/234)) ([b051785](https://github.com/tomymaritano/readide/commit/b0517852c52241a633344907974e962a376f8dc1)) +- v0.14.2 — ASAR startup crash fix (devDependencies) ([#236](https://github.com/tomymaritano/readide/issues/236)) ([17b951a](https://github.com/tomymaritano/readide/commit/17b951a634ea55992ce29afad1d969dd821f1f29)) ## [0.14.1](https://github.com/tomymaritano/readide/compare/v0.14.0...v0.14.1) (2026-04-24) diff --git a/apps/desktop/src/preload/api/localServer.ts b/apps/desktop/src/preload/api/localServer.ts index a072faaa..215ad95e 100644 --- a/apps/desktop/src/preload/api/localServer.ts +++ b/apps/desktop/src/preload/api/localServer.ts @@ -18,6 +18,10 @@ export function createLocalServerApi(): LocalServerAPI { start: (port?: number) => ipcRenderer.invoke('localServer:start', port), stop: () => ipcRenderer.invoke('localServer:stop'), status: () => ipcRenderer.invoke('localServer:status'), - getToken: () => ipcRenderer.invoke('localServer:getToken'), + getToken: async () => { + const result = await ipcRenderer.invoke('localServer:getToken'); + if (!result.ok) throw new Error(result.error ?? 'Failed to get token'); + return result.value as string; + }, }; } diff --git a/apps/desktop/src/preload/api/settings.ts b/apps/desktop/src/preload/api/settings.ts index de01e0e5..09edd589 100644 --- a/apps/desktop/src/preload/api/settings.ts +++ b/apps/desktop/src/preload/api/settings.ts @@ -36,9 +36,10 @@ export function createSettingsApi(): SettingsAPI { export function createIpcApi(): IpcAPI { return { on: (channel: string, listener: (...args: unknown[]) => void) => { - ipcRenderer.on(channel, (_event, ...args) => listener(...args)); + const handler = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => listener(...args); + ipcRenderer.on(channel, handler); return () => { - ipcRenderer.removeAllListeners(channel); + ipcRenderer.removeListener(channel, handler); }; }, }; diff --git a/apps/desktop/src/renderer/App.tsx b/apps/desktop/src/renderer/App.tsx index 78c096c4..678411f5 100644 --- a/apps/desktop/src/renderer/App.tsx +++ b/apps/desktop/src/renderer/App.tsx @@ -438,12 +438,44 @@ function NotesApp() { // Plugin runtime: init once, React observes const discoveredPlugins = useStore(pluginRuntimeStore, s => s.plugins); const pluginErrors = useStore(pluginRuntimeStore, s => s.errors); + const [builtInEnabledMap, setBuiltInEnabledMap] = useState | null>(null); useEffect(() => { void pluginRuntimeStore.getState().init(); + // Load built-in plugin enabled states + void (async () => { + const stateList = await window.readied.plugins.listState(); + const map: Record = {}; + for (const s of stateList) { + map[s.pluginId] = s.enabled; + } + setBuiltInEnabledMap(map); + })(); + }, []); + + // Re-check built-in enabled state when plugins reload + useEffect(() => { + const handler = () => { + void (async () => { + const stateList = await window.readied.plugins.listState(); + const map: Record = {}; + for (const s of stateList) { + map[s.pluginId] = s.enabled; + } + setBuiltInEnabledMap(map); + })(); + }; + return window.readied.ipc.on('plugins:reload', handler); }, []); - const allPlugins = useMemo(() => [...builtInPlugins, ...discoveredPlugins], [discoveredPlugins]); + const allPlugins = useMemo(() => { + // Don't mount built-in plugins until the enabled state is loaded + // to avoid activating disabled plugins on the initial render + const enabledBuiltIn = builtInEnabledMap + ? builtInPlugins.filter(p => builtInEnabledMap[p.id] !== false) + : []; + return [...enabledBuiltIn, ...discoveredPlugins]; + }, [discoveredPlugins, builtInEnabledMap]); const configBridge = useMemo( () => ({ diff --git a/apps/desktop/src/renderer/components/MarkdownEditor.tsx b/apps/desktop/src/renderer/components/MarkdownEditor.tsx index 05dd283f..2e1a6822 100644 --- a/apps/desktop/src/renderer/components/MarkdownEditor.tsx +++ b/apps/desktop/src/renderer/components/MarkdownEditor.tsx @@ -575,22 +575,26 @@ export const MarkdownEditor = forwardRef { if (!title) return; - // Find the URL in the document — it may have moved due to edits + // Verify the URL still sits at the expected position const currentDoc = view.state.doc.toString(); - const urlIndex = currentDoc.indexOf(plainText, from > 20 ? from - 20 : 0); - if (urlIndex === -1) return; + const textAtRange = currentDoc.slice(insertedFrom, insertedTo); + if (textAtRange !== plainText) return; // Verify it's still a bare URL (not already wrapped in markdown link) - const charBefore = urlIndex > 0 ? currentDoc[urlIndex - 1] : ''; + const charBefore = insertedFrom > 0 ? currentDoc[insertedFrom - 1] : ''; if (charBefore === '(' || charBefore === '<') return; const mdLink = `[${title}](${plainText})`; view.dispatch({ - changes: { from: urlIndex, to: urlIndex + plainText.length, insert: mdLink }, - selection: EditorSelection.cursor(urlIndex + mdLink.length), + changes: { from: insertedFrom, to: insertedTo, insert: mdLink }, + selection: EditorSelection.cursor(insertedFrom + mdLink.length), userEvent: 'input.paste', }); }) diff --git a/apps/desktop/src/renderer/pages/settings/sections/plugins/PluginCard.tsx b/apps/desktop/src/renderer/pages/settings/sections/plugins/PluginCard.tsx index 9bffbb85..51357077 100644 --- a/apps/desktop/src/renderer/pages/settings/sections/plugins/PluginCard.tsx +++ b/apps/desktop/src/renderer/pages/settings/sections/plugins/PluginCard.tsx @@ -59,7 +59,6 @@ export function PluginCard({ id={`plugin-${name.toLowerCase().replace(/\s+/g, '-')}`} checked={enabled} onChange={checked => onToggle?.(checked)} - disabled={isBuiltIn} /> {!isBuiltIn && onUninstall && (