V2 Plugin SDK
The V2 plugin system uses @hone/sdk to build native Hone plugins compiled by Perry and distributed via the marketplace.
Installation
npm install @hone/sdk
Plugin Lifecycle
- init – Host calls
hone_plugin_init(host_api). The plugin stores the host API pointer for later use. - activate – Host calls
hone_plugin_activate(). The plugin initializes its state, registers commands, and sets up event handlers. - hooks – Host calls hook methods as events occur (e.g.,
hone_plugin_on_document_format(event_ptr),hone_plugin_on_command(cmd_ptr)). - deactivate – Host calls
hone_plugin_deactivate(). The plugin cleans up resources. - unload – Host calls
dlclose(). The plugin binary is unloaded from memory.
Basic Plugin Structure
import { HonePlugin } from '@hone/sdk';
import type { HoneHost } from '@hone/sdk';
export class MyPlugin extends HonePlugin {
activate(host: HoneHost): void {
host.log('info', 'My plugin activated');
host.commands.register('my-plugin.greet', 'Greet User', () => {
host.ui.notify({ message: 'Hello from my plugin!' });
});
}
deactivate(): void {
// Clean up resources
}
}
Host APIs
The HoneHost interface provides access to IDE functionality. Available APIs depend on declared capabilities – undeclared capabilities have null function pointers and will not be linked.
Editor
Requires editor.read and/or editor.write capabilities.
// Read buffer content
const text = host.editor.getBufferText(bufferId);
const lines = host.editor.getLines(bufferId, startLine, endLine);
const selection = host.editor.getSelection(bufferId);
const lineCount = host.editor.getLineCount(bufferId);
// Write edits (requires editor.write)
host.editor.submitEdits(bufferId, [
{ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 5 } }, text: 'replacement' }
]);
Filesystem
Requires filesystem.read and/or filesystem.write capabilities.
// Read (patterns must match declared globs)
const content = host.fs.readText('/path/to/file.txt');
const exists = host.fs.exists('/path/to/file.txt');
const entries = host.fs.listDirectory('/path/to/dir');
// Write (requires filesystem.write)
host.fs.writeText('/path/to/file.txt', 'content');
host.fs.delete('/path/to/file.txt');
host.fs.createDirectory('/path/to/dir', { recursive: true });
UI
Requires various ui.* capabilities.
// Status bar (ui.statusbar)
const item = host.ui.createStatusBarItem({ text: 'My Plugin', alignment: 'left' });
host.ui.updateStatusBarItem(item, { text: 'Updated' });
// Panels (ui.panel)
const panel = host.ui.createPanel({
title: 'My Panel',
icon: 'list',
content: [
{ type: 'Heading', text: 'Results', level: 2 },
{ type: 'List', items: ['Item 1', 'Item 2'] }
]
});
// Notifications (ui.notifications)
host.ui.notify({ message: 'Operation complete', type: 'info' });
// Command palette (ui.commandPalette)
host.commands.register('my-plugin.action', 'My Action', callback);
Process
Requires process.spawn capability with allowlisted binaries.
const result = host.process.spawn('git', ['status', '--porcelain'], {
cwd: host.getWorkspacePath()
});
Network
Requires network capability (forces Tier 3 execution).
const response = host.network.httpRequest({
method: 'GET',
url: 'https://api.example.com/data',
headers: { 'Authorization': 'Bearer token' }
});
Custom UI Panels
Plugins can create panels with structured content using PanelElement types:
| Element | Description |
|---|---|
Text | Plain or styled text |
Heading | Section heading (levels 1-4) |
List | Ordered or unordered list |
Tree | Collapsible tree structure |
Table | Tabular data |
Input | Text input field |
Button | Clickable button |
Separator | Visual divider |
Progress | Progress bar or spinner |
CodeBlock | Syntax-highlighted code |
Group | Container for other elements |
Testing
Use MockHost and createTestBuffer from the SDK to test plugin logic without the full IDE:
import { MockHost, createTestBuffer } from '@hone/sdk';
const host = new MockHost();
const buffer = createTestBuffer('hello world');
const plugin = new MyPlugin();
plugin.activate(host);
// Assert plugin behavior against mock host
Compiling
Plugins are compiled to native shared libraries using Perry:
perry compile src/index.ts --output my-plugin
The output is a platform-specific shared library (.dylib on macOS, .dll on Windows, .so on Linux) that the Hone plugin host loads via dlopen/dlclose.
Perry AOT Constraints
Plugin code is compiled by Perry and must follow its constraints. Avoid:
- Optional chaining (
?.) – use explicit null checks - Nullish coalescing (
??) – useif (x !== undefined) - Dynamic key access (
obj[variable]) – useif/else ifper key for...ofon arrays – use index-basedforloops- ES6 shorthand properties (
{ key }) – use{ key: key } - Closures capturing
this– use module-level functions and variables
See the Perry constraints reference for the full list.