fat-notes-extension-cli
v0.1.4
Published
Scaffolding CLI for building FatNotes bespoke plugins via Module Federation.
Maintainers
Readme
fat-notes-extension-cli
fat-notes 高级定制插件脚手架 — Scaffolding CLI for FatNotes bespoke plugins.
FatNotes bespoke plugins are VSCode-style extensions loaded into the desktop host via Module Federation at runtime. A plugin can contribute elements to every UI block (activity bar, primary sidebar, panel, footer, routes, widget types) except the secondary sidebar — which is reserved for the chat block.
When FatNotes loads a plugin, the host injects a FatNotesPluginSDK carrying
the current user/auth info and helper APIs for reading data sources and
executing queries/mutations.
Install
npm install -g fat-notes-extension-cliOr use it through npx:
npx fat-notes-extension-cli create my-pluginCommands
fn-ext create <pluginId> [--name "Display Name"] [--dir <target>]
fn-ext build # inside a scaffolded project
fn-ext dev # watch mode<pluginId>must match^[a-z0-9][a-z0-9-]*$.--namesets the display name (defaults to<pluginId>).--dirsets an alternate output directory (defaults to./<pluginId>).
Scaffolded structure
my-plugin/
├── plugin.json # manifest read by the FatNotes installer
├── package.json
├── tsconfig.json
├── webpack.config.js # Module Federation build
├── public/
│ └── index.html # optional standalone preview shell
├── src/
│ ├── bootstrap.ts # async entry required by MF
│ ├── index.tsx # exports activate(sdk) / deactivate()
│ └── PluginView.tsx # example contribution component
└── types/
└── fat-notes-sdk.d.ts # SDK types (mirror of host)Module Federation contract
- Container name:
<plugin-id with dashes replaced by underscores>. - Exposed module:
./plugin→src/index.tsx. - Shared (singleton, non-eager) — versions must match the FatNotes host:
react18.2.0react-dom18.2.0react/jsx-runtime18.2.0react-redux9.1.2react-intl6.8.4antd6.3.1
Plugin entry
src/index.tsx must export:
export async function activate(sdk: FatNotesPluginSDK): Promise<void> { ... }
export function deactivate(): void { ... }SDK capabilities
| Namespace | Purpose |
| ---------------- | ------------------------------------------------------ |
| sdk.host | Host version + mode ("dev" \| "prod") |
| sdk.auth | Current user, token, auth-change subscription |
| sdk.dataSource | List / read data sources |
| sdk.query | Run saved queries or raw SQL |
| sdk.mutation | Run saved mutations or insert rows |
| sdk.ui | toast / modal / theme / i18n |
| sdk.commands | Register + execute commands |
| sdk.store | Read-only access to host Redux state |
| sdk.config | Read / write current plugin runtime config |
| sdk.contributions | Register UI contributions (see below) |
| sdk.events | Plugin/host event bus |
Contribution points
registerActivityBarItem— icon in the left activity barregisterSidebarView("primary", def)— primary sidebar view (secondary blocked)registerPanelTab— tab in the bottom panelregisterFooterItem— inline status in the footerregisterRoutePage— full-page routeregisterWidgetType— custom dashboard widget typeregisterMenu— contextual menu items
Every register* call returns a Disposable; your deactivate() must
dispose every one it collected.
Backend host helpers
When plugin.json enables backend, the scaffold includes backend/plugin_runtime.py
helpers that can call host common APIs:
host_get_login_info()— returns current{ token, user }host_get_plugin_config()— returns this plugin's runtime confighost_set_plugin_config(config, merge=True)— persists runtime config
Install a built plugin into FatNotes
npm run build— emitsdist/withremoteEntry.js.- Zip
plugin.json+ the contents ofdist/asinstall.zip. - In FatNotes → Extensions → Custom Bespoke Plugins → New Plugin,
or drop the zip via the standard apps-style installer. Files land under
extensions/bespokePlugins/(mirroring theappsinstallation layout).
Host-side wiring (for reference)
- Desktop app code:
fat-notes/src/views/pluginSdk/* - Python service:
fat-notes/src/services/extensionService/bespokePluginService/* - Server-side type enum:
fat-notes-server/backend/internal/models/extension.go(ExtensionTypeBespokePlugin)
