Skip to content
Quickstart

Quickstart

Semantic command graph, projections and wire parsing

This creates a runtime, contributes one command to the palette and slash surfaces, reads the snapshot, and runs the command:

quickstart.ts
import { createWhistle } from "@fungi.computer/whistle";
const whistle = createWhistle();
const lease = whistle.contribute({
sourceId: "editor",
namespace: "editor",
commands: [
{
id: "save",
title: "Save file",
category: "File",
projections: {
palette: {},
slash: { aliases: ["save"] },
bindings: { values: ["mod+s"] },
},
handler: () => ({ saved: true }),
},
],
});
const snapshot = whistle.snapshot();
console.log(snapshot.palette.map((row) => row.command)); // [{ namespace: "editor", id: "save" }]
console.log(snapshot.slash.map((row) => row.alias)); // ["save"]
const outcome = await whistle.execute(
{ namespace: "editor", id: "save" },
{ origin: "palette" },
);
if (outcome.status === "handled") console.log(outcome.result); // { saved: true }
lease.dispose();
whistle.close();

A command is named by its typed key, { namespace, id }. Every projection row carries that key as command, so a palette click, a key press and a slash command all call the same execute with it. A row’s commandId is an opaque render key Whistle mints: use it for React keys or dedupe, never build or parse it. Namespaces may contain colons (an App surface such as installation:inkcap); command ids may not.

TERMINAL
npm install @opentui/keymap@0.5.10
TS
import { createWhistle } from "@fungi.computer/whistle";
import { bindHtmlKeymap } from "@fungi.computer/whistle/html";
const whistle = createWhistle();
whistle.contribute({
sourceId: "browser",
namespace: "browser",
commands: [
{
id: "save",
title: "Save",
category: "File",
projections: { bindings: { values: ["mod+s"] } },
handler: () => ({ saved: true }),
},
],
});
const keyboard = bindHtmlKeymap(document.body, whistle, "keyboard");
// Contributions and availability updates refresh the projected key layer.
keyboard.dispose();
whistle.close();

dispose removes the Whistle layer and subscription, and can be called twice. The underlying HTML keymap host follows the document’s lifetime; this helper does not remove its DOM listeners. Commands still execute through Whistle.