Bump Vite 8, matrix-js-sdk, and related deps; fix immer/vanilla-extract imports for new majors. Replace blocking sync error dialog with background recovery on wake/offline, and disable Vite auto-open in dev. Add feature handoff documentation index.
3.9 KiB
3.9 KiB
Plugin system — handoff
Summary
Paarrot extends the Matrix client with JavaScript plugins loaded from disk or the marketplace. Plugins can register slash commands, inject UI buttons in 11 locations, hook Matrix events, register themes, and run background tasks. The runtime is @paarrot/plugin-manager; the app wires slots in settings, nav, composer, and room UI.
User-facing behavior
- Settings → Plugins: Installed, Marketplace, enable/disable, uninstall
- Plugins live in OS-specific dirs (
%APPDATA%\paarrot\plugins\,~/.config/Paarrot/plugins/, etc.) - Marketplace pulls from Plugin Directory JSON index
Architecture
Plugin folder (index.js + plugin-metadata.json)
→ PluginLoader (reads, validates, enables)
→ @paarrot/plugin-manager (lifecycle, API surface)
→ PluginAPI.ts (app-specific bindings: Matrix client, navigate, notifications)
→ UI slots: PluginNavSlot, PluginButtonSlot, PluginSidebarSlot, ...
Key files
| Path | Role |
|---|---|
cinny/src/app/features/settings/plugins/PluginLoader.tsx |
Load/enable/disable plugins |
cinny/src/app/features/settings/plugins/PluginAPI.ts |
Re-exports plugin-manager + app hooks |
cinny/src/app/features/settings/plugins/Plugins.tsx |
Settings UI (installed + marketplace) |
cinny/src/app/features/settings/plugins/PluginButtonSlot.tsx |
Icon button injection |
cinny/src/app/features/settings/plugins/PluginNavSlot.tsx |
Nav row injection |
cinny/src/app/features/settings/plugins/PluginSidebarSlot.tsx |
Sidebar icon injection |
cinny/src/app/features/settings/plugins/types.ts |
Local types |
cinny/src/app/features/settings/plugins/PLUGIN_DEVELOPMENT.md |
Author-facing dev guide |
example-plugin/ |
Reference plugin at repo root |
cinny/docs/PLUGIN_*.md |
API reference docs |
Data model
- Plugin metadata:
plugin-metadata.jsonper plugin (id, version, permissions,paarrot.utilsdeps) - Enabled state: persisted via plugin-manager (Electron userData)
- No Matrix events for plugins themselves
UI locations (UILocation)
channel-list, home-section, direct-messages, sidebar-actions, text-composer-toolbar, composer-actions, room-header, room-menu, message-actions, user-menu, search-notification-section
Dependencies
@paarrot/plugin-manager(npm)- Electron
fs/ IPC for plugin install paths - GitHub raw URLs for marketplace index (
PluginAPI.ts)
Integration points
- Matrix client: exposed to plugins for send/receive
- Local API: separate from plugins; plugins do not use HTTP API by default
- Settings: plugin tabs via
PluginTab - All major UI surfaces: search codebase for
PluginButtonSlot/PluginNavSlotusages
Testing
Manual
- Copy
example-plugin/to plugins directory. - Enable in Settings → Plugins.
- Verify slash command and injected button appear.
- Disable plugin; verify UI cleans up.
Automated
- None dedicated; validate via example-plugin manually
Known issues & gotchas
- Plugin API version must match
@paarrot/plugin-managerexpectations ctx.require("other-plugin-id")for inter-plugin deps- Marketplace cache-bust query param on index fetch
- Plugin dev guide lives inside
src/— consider linking from handoff only
Future work
- Sandboxing / permission prompts per capability
- Hot reload without app restart
- Signed plugin packages
Related docs
Add your extra things here
- Marketplace base:
https://raw.githubusercontent.com/Paarrot/Plugin-Directory/refs/heads/main/plugins/ - 11 UI injection points — see README plugin table in repo root