Commands
Commands are discrete, named actions that can appear in shortcuts, the command bar, the PathBar toolbar, the header bar, context menus, and the multi-select selection bar. Prefer CommandProvider for any new UI that would previously have used legacy context or selection providers.
Types: Command, PluginProvider union — in your local clone, open sdk/command-types.generated.d.ts.
Related: Plugin API · Getting started
Mental model
- One
Commanddescribes visibility (contextKeys,when), disabled state,action(ctx), optionaltoastData, keyboardshortcut, command-bar metadata (category,searchAliases), optionalchildren(nested commands), anddefaultPlacements(where the action appears by default; users can override some layouts in persisted settings). - Placement areas:
toolbar,headerBar,contextMenu,selectionBar. The command bar does not use a placement flag: registered commands can appear there unless hidden by session state. - Execution uses
CommandContext:pane,selectedFiles,targetFile(context menu: item under cursor),currentPath, vial flags,activeContextKeys, etc. — seesdk/command-types.generated.d.ts.
CommandProvider and Command
interface CommandProvider {
type: "command";
id: string;
name: string;
commands: Command[];
}Important Command fields:
| Concern | Fields |
|---|---|
| Fast visibility filter | contextKeys?: CommandContextKey[] — if present and not containing "always", all listed keys must be active. |
| Fine-grained visibility | when?: (ctx: CommandContext) => boolean |
| Grey-out vs hide | disabled?: (ctx: CommandContext) => boolean |
| Run | action: (ctx: CommandContext) => void \| Promise<void> |
| Feedback | toastData — static or derived from context |
| Shortcut | shortcut?.defaults, allowDefault, priority |
| Command bar | category, searchAliases |
| Surface placement | defaultPlacements — per-area configs |
Context menu placement
ContextMenuPlacementConfig adds selectionMode ("single" | "multi" | "both"), submenu, danger, order. Commands may supply renderSnippet(ctx) for custom context-menu rows.
Host registration
When your PhialsPlugin activates, the host registers each CommandProvider with the command subsystem and wires shortcuts for commands that declare shortcut.defaults. Shortcut ids follow the pattern command.${providerId}.${command.id}.
Superseding legacy context and selection
- Context menus: Prefer
defaultPlacements: [{ area: "contextMenu", … }]onCommand. LegacyContextProviderexists only for older plugins; new work should not add it. - Selection bar: Prefer
area: "selectionBar"placements. LegacySelectionProvideris deprecated — use commands so actions actually appear in the selection UI.
Example: context menu + selection bar
import { SystemIcons } from "$core/utils/icons";
const demoCommandsProvider: CommandProvider = {
type: "command",
id: "my.vendor.demo",
name: "Demo",
commands: [
{
id: "my.demo.archiveSelection",
label: "Archive…",
icon: SystemIcons.archive,
category: "File",
contextKeys: ["hasMultiSelection"],
when: (ctx) => ctx.selectedFiles.every((f) => !f.name.endsWith("..")),
disabled: (ctx) => ctx.selectedFiles.length < 2,
action: async (ctx) => {
void ctx.selectedFiles;
},
toastData: { variant: "success", title: "Archived" },
defaultPlacements: [
{ area: "contextMenu", selectionMode: "multi", order: 120 },
{ area: "selectionBar", icon: SystemIcons.archive, priority: 10 },
],
},
],
};Pitfalls
- Shortcuts vs
when: Shortcut eligibility may not mirrorcommand.when(ctx)in every build — guard insideactionwhen correctness matters. - Duplicate command ids collide in the registry; use a vendor prefix.
- Nested
children: Only the flatcommandslist on the provider receives standalone registration for shortcuts unless you add custom wiring.