Skip to content

feat: allow disabling built-in plugins + fix MCP server FTS5 crash#237

Merged
github-actions[bot] merged 2 commits into
developfrom
fix/allow-disable-builtin-plugins
Apr 24, 2026
Merged

feat: allow disabling built-in plugins + fix MCP server FTS5 crash#237
github-actions[bot] merged 2 commits into
developfrom
fix/allow-disable-builtin-plugins

Conversation

@tomymaritano

@tomymaritano tomymaritano commented Apr 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Allow disabling built-in plugins — users can now toggle built-in plugins on/off from settings
  • Fix MCP server FTS5 crash — replaced sql.js (WASM, no FTS5) with better-sqlite3 (native, FTS5 included). Write operations (create/update/trash notes) were failing with no such module: fts5 because the FTS5 triggers in the database fired against a runtime that didn't support FTS5
  • FTS5 runtime check — MCP server now verifies FTS5 availability at startup and fails with a clear error message instead of a cryptic trigger failure
  • WAL mode — enables safe concurrent DB access between the Electron app and MCP server (the old sql.js approach loaded the entire DB into memory, risking data loss on concurrent writes)
  • Fix: gate built-in plugins until enabled state loads (P1) — builtInEnabledMap started as {} so !== false passed for every plugin, briefly activating disabled plugins on launch. Now starts as null and built-in plugins are excluded from PluginHost until listState() resolves
  • Fix: IPC listener cleanup (P2) — ipc.on() cleanup used removeAllListeners(channel) which nuked other listeners on the same channel (e.g. pluginRuntimeStore). Changed to removeListener with the specific handler reference

Test plan

  • pnpm test — all 17 suites pass
  • pnpm typecheck — clean across all packages
  • pnpm build — builds successfully
  • FTS5 regression tests: INSERT/UPDATE/DELETE triggers execute without error
  • Manual: run MCP server and verify readied_create_note / readied_update_note work
  • Manual: disable a built-in plugin in settings, restart app, confirm it does not activate

🤖 Generated with Claude Code

Previously built-in plugins were hardcoded as always enabled with the
toggle disabled. Now:

- Toggle enabled for built-in plugins (removed disabled={isBuiltIn})
- Built-in enabled state loaded from plugin_registry DB table
- onToggle handler wired for built-in plugins (same as community)
- App.tsx filters built-in plugins by enabled state before passing
  to PluginHost — disabled plugins won't load at runtime
- State re-checked on plugins:reload event

The DB infrastructure (plugin_registry table) and IPC handlers
(plugins:setEnabled/isEnabled) already existed but were unused.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
readide Error Error Apr 24, 2026 4:32pm

Request Review

@coderabbitai

coderabbitai Bot commented Apr 24, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR enables built-in plugin enablement/disablement in the desktop app by tracking state through builtInEnabledMap, and migrates the MCP server's database layer from sql.js (WASM) to better-sqlite3 (native SQLite), including FTS5 support testing.

Changes

Cohort / File(s) Summary
Desktop app plugin state management
apps/desktop/src/renderer/App.tsx, apps/desktop/src/renderer/pages/settings/sections/plugins/PluginCard.tsx, apps/desktop/src/renderer/pages/settings/sections/plugins/index.tsx
Adds builtInEnabledMap state to track enabled/disabled status of built-in plugins, removes the disabled prop on built-in plugin toggles to make them interactive, and extends the plugin toggle handler to update both community and built-in plugin state maps.
MCP server database migration
packages/mcp-server/src/db.ts, packages/mcp-server/src/index.ts, packages/mcp-server/sql.js.d.ts
Migrates from sql.js (WASM) to better-sqlite3 (native), replacing async openDb/saveDb with synchronous file-backed database operations, updating all SQL query/execute calls to use the new API, and removing WASM-specific type definitions.
MCP server test infrastructure
packages/mcp-server/src/__tests__/fts5-triggers.test.ts, packages/mcp-server/package.json, packages/mcp-server/tsconfig.json
Adds vitest test framework with new test file verifying FTS5 virtual table triggers and soft-delete behavior, updates package.json with better-sqlite3 dependency and test script, and configures TypeScript to exclude test files from compilation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as PluginCard UI
    participant App as App Component
    participant IPC as IPC Handler
    participant Store as Plugin System
    participant Toast as Toast Notification

    User->>UI: Click toggle for built-in plugin
    UI->>App: handleToggle(pluginId)
    App->>Store: window.readied.plugins.setEnabled(pluginId, enabled)
    Store->>IPC: Persist enablement to storage
    IPC-->>Store: Persistence successful
    App->>App: Update builtInEnabled map
    App->>App: Trigger main window reload
    App->>Toast: Show success toast
    Toast-->>User: Confirmation displayed
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

size/M

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly summarizes the two main changes in the changeset: enabling disabling of built-in plugins and fixing an MCP server FTS5 issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/allow-disable-builtin-plugins

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2e08f4ced

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


const allPlugins = useMemo(() => [...builtInPlugins, ...discoveredPlugins], [discoveredPlugins]);
const allPlugins = useMemo(() => {
const enabledBuiltIn = builtInPlugins.filter(p => builtInEnabledMap[p.id] !== false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate built-in plugins until enabled state is loaded

This filter defaults every built-in plugin to enabled while builtInEnabledMap is still empty, so PluginHost mounts disabled built-ins during initial render and only unloads them after the async listState() call finishes in the mount effect. In the startup path where a user has previously disabled a built-in plugin, its activate() logic still runs once per launch, which can cause unwanted side effects and contradicts the expected disabled behavior.

Useful? React with 👍 / 👎.

setBuiltInEnabledMap(map);
})();
};
return window.readied.ipc.on('plugins:reload', handler);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid clearing shared reload listeners on App cleanup

This subscription returns a cleanup from readied.ipc.on, and that API currently removes all listeners for the channel (removeAllListeners) rather than just this handler. During an App unmount/remount cycle (notably React StrictMode in development), cleanup here removes pluginRuntimeStore's own plugins:reload listener as well; because that store marks its listener as already attached, it does not re-register, so later reload events stop reloading runtime plugins.

Useful? React with 👍 / 👎.

sql.js (WASM) lacks FTS5, causing "no such module: fts5" when MCP
write operations fire the notes_fts triggers. Since the MCP server
runs as a standalone Node.js process (not inside Electron), native
modules work without conflict.

- Switch from sql.js to better-sqlite3 for full DB feature parity
- Add FTS5 runtime check on startup (assertFts5Available)
- Enable WAL mode for safe concurrent access with the desktop app
- Remove saveDb() pattern (better-sqlite3 writes directly)
- Add regression tests for FTS5 trigger execution (INSERT/UPDATE/DELETE)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file size/XL and removed size/S labels Apr 24, 2026
@tomymaritano tomymaritano changed the title feat: allow disabling built-in plugins feat: allow disabling built-in plugins + fix MCP server FTS5 crash Apr 24, 2026
@github-actions github-actions Bot merged commit 272c85f into develop Apr 24, 2026
12 of 15 checks passed
tomymaritano added a commit that referenced this pull request Apr 24, 2026
…er cleanup (#239)

## Summary

This commit was pushed to #237 after the squash-merge, so it didn't make
it into develop. Cherry-picked here.

- **P1: gate built-in plugins until enabled state loads** —
`builtInEnabledMap` started as `{}` so `!== false` passed for every
plugin, briefly activating disabled plugins on launch. Now starts as
`null` and built-in plugins are excluded from `PluginHost` until
`listState()` resolves
- **P2: fix IPC listener cleanup** — `ipc.on()` cleanup used
`removeAllListeners(channel)` which nuked other listeners on the same
channel (e.g. `pluginRuntimeStore`). Changed to `removeListener` with
the specific handler reference

## Test plan

- [x] `pnpm typecheck` — clean
- [x] `pnpm test` — all pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Apr 24, 2026
## Release PR

Merges `develop` into `main` to trigger a new release via
semantic-release.

### Highlights since last release

- **feat: allow disabling built-in plugins** + MCP server FTS5 fix
(#237)
- **fix: move @readied/* to devDependencies** — ASAR startup crash
(#235)
- **fix: exclude @readied/* from ASAR** (#233)
- **feat: local HTTP API, quick capture, mermaid/math plugins** (#231)
- **fix: replace removed lucide brand icons** (#229)
- Multiple CI, type compat, and dependency fixes

### MCP server: sql.js → better-sqlite3
- FTS5 triggers now work (was crashing with `no such module: fts5`)
- WAL mode for safe concurrent access with the desktop app
- Runtime FTS5 check at startup with descriptive error

### Plugin system fixes (from code review)
- Built-in plugins no longer briefly activate before enabled state loads
- IPC listener cleanup no longer nukes unrelated listeners

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Built-in plugins can now be toggled on/off in settings;
enabled/disabled states persist across sessions
* Improved markdown editor URL auto-linking for more reliable link
creation

* **Bug Fixes**
* Fixed URL auto-linking to correctly identify URLs when document
content changes

* **Tests**
  * Added comprehensive test suite for database trigger functionality

* **Chores**
  * Migrated database backend for improved performance and stability

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
tomymaritano added a commit that referenced this pull request Apr 24, 2026
## Summary

- **fix(mcp-server):** non-destructive FTS5 check + switch search to
FTS5 MATCH (#241)
- **fix:** unwrap getToken IPC result + use exact range for auto-link
paste (#240)
- **fix:** gate built-in plugins until enabled state loads + fix IPC
listener cleanup (#239)
- **feat:** allow disabling built-in plugins + fix MCP server FTS5 crash
(#237)
- **chore(deps):** sync postcss bump from main

## Test plan
- [ ] CI passes (typecheck, lint, tests, build)
- [ ] After merge, run Release workflow via `workflow_dispatch`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:desktop dependencies Pull requests that update a dependency file size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant