forked from anomalyco/opencode
-
Notifications
You must be signed in to change notification settings - Fork 3
Closed
Labels
Description
Summary
Integrate the plugin commands feature from upstream PR sst/opencode#4411 which allows plugins to register custom slash commands that execute code.
Context
The upstream PR adds a powerful new plugin.command hook that enables plugins to register their own /commands in the TUI. This unlocks use cases like:
/prune- prune tool outputs from session- Toggling plugin features on/off
- Creating composable workflows
- Custom session manipulation commands
Acceptance Criteria
- Plugin commands appear in autocomplete when typing
/ - Plugin commands with
sessionOnly: trueonly show when a session exists - Command aliases work (e.g.,
/hiresolves to/hello) - Plugin command execution works with error handling
- SDK types are updated with
sessionOnlyandaliasesfields - SDK rebuild works (
cd packages/sdk/js && bun run script/build.ts)
Implementation Details
Files to Update
| File | Changes |
|---|---|
packages/plugin/src/index.ts:145-192 |
Add plugin.command hook interface to Hooks |
packages/opencode/src/plugin/index.ts:53-76 |
Exclude plugin.command from trigger, add client() export |
packages/opencode/src/command/index.ts:23-79 |
Add sessionOnly/aliases to schema, load plugin commands, support alias lookup |
packages/opencode/src/session/prompt.ts:1413-1498 |
Execute plugin commands with error handling |
packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx:207-222 |
Filter sessionOnly commands, add aliases to options |
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:506-518 |
Resolve command aliases |
packages/sdk/js/src/gen/types.gen.ts |
Add sessionOnly to Command type |
packages/sdk/js/src/v2/gen/types.gen.ts |
Add sessionOnly and aliases to Command type |
Key Changes
1. New Plugin Hook Interface (packages/plugin/src/index.ts)
"plugin.command"?: {
[key: string]: {
description: string
aliases?: string[]
sessionOnly?: boolean
execute(input: { sessionID?: string; client: ReturnType<typeof createOpencodeClient> }): Promise<void>
}
}2. Command Schema Updates (packages/opencode/src/command/index.ts)
// Add to Command.Info schema
sessionOnly: z.boolean().optional(),
aliases: z.array(z.string()).optional(),3. Plugin Command Loading (packages/opencode/src/command/index.ts)
const plugins = await Plugin.list()
for (const plugin of plugins) {
const commands = plugin["plugin.command"]
if (!commands) continue
for (const [name, cmd] of Object.entries(commands)) {
if (result[name]) continue
result[name] = {
name,
description: cmd.description,
template: "",
sessionOnly: cmd.sessionOnly,
aliases: cmd.aliases,
}
}
}4. Plugin Command Execution (packages/opencode/src/session/prompt.ts)
- Check for plugin commands before built-in commands
- Execute with
{ sessionID, client }context - Handle errors gracefully with user feedback
Example Plugin Command
import type { Plugin } from "@opencode-ai/plugin"
export const CommandsPlugin: Plugin = async (ctx) => {
return {
"plugin.command": {
hello: {
description: "Say hello",
aliases: ["hi"],
sessionOnly: true,
async execute({ sessionID, client }) {
await client.session.sendMessage({
path: { id: sessionID! },
body: { content: "Hello from plugin command!" },
})
},
},
},
}
}Tasks
- Cherry-pick or manually apply changes from upstream PR
- Verify no conflicts with fork-specific changes
- Rebuild SDK:
cd packages/sdk/js && bun run script/build.ts - Test plugin command registration
- Test autocomplete with
sessionOnlyfiltering - Test alias resolution
- Test error handling for failed plugin commands
- Run full test suite
References
- Upstream PR: feat(plugin commands): allows for code execution on plugin registered slash commands anomalyco/opencode#4411
- PR Diff:
gh pr diff 4411 --repo sst/opencode