Skip to main content

Extensions

A capability is rarely one plugin. A notebook is an editor, a toolbar, a set of commands — and nobody wants to install four things to get one, or to read a plugin list where those four sit at the same level as everything else.

export const NotebookExtension = defineExtension({
name: '@app/notebooks',
displayName: 'Notebooks',
description: 'The editor, its toolbar, and the commands that drive them.',
emoji: '📓',
plugins: [NotebookEditorPlugin, NotebookToolbarPlugin, NotebookCommandsPlugin],
});

const reactor = buildReactorFromPlugins([NotebookExtension, ShellPlugin]);

Deliberately thin​

It hasIt does not have
a name and versiona lifecycle, phases, or config
presentation (displayName, description, octicon, emoji)contributions of its own
the plugins it deliversan enabled/disabled state

Registering one registers its plugins and records the grouping on each manifest. From that moment the platform deals only in plugins:

reactor.listPlugins(); // ['@app/notebook-editor', …]
reactor.hasPlugin('@app/notebooks'); // false — it is not a plugin
reactor.getManifest('@app/notebook-editor'); // { extension: '@app/notebooks', … }
reactor.listExtensions(); // ['@app/notebooks']
reactor.getExtensionManifest('@app/notebooks');
// { displayName: 'Notebooks', plugins: ['@app/notebook-editor', …] }

Each member is still switched off on its own — grouping is about delivery, not governance. A plugin that merely arrived as a dependency of a member is not grouped: a package should not claim to deliver what it only relies on.

In React, and on the graph​

useGroupedPluginManifests() returns the same list arranged by extension, with ungrouped plugins in one bucket at the end.

The graph plugin draws extensions in a column of their own, joined to each plugin they delivered by a groups edge — so "what would I uninstall to lose this view?" is answerable by following arrows.