feat: add slash command passthrough with autocomplete UI#68
Merged
Conversation
Implement transparent slash command invocation across all three engines (Claude Code, GitHub Copilot, OpenCode), allowing users to type engine- native commands directly in the chat input. - Types: Add EngineCommand, CommandListRequest, CommandInvokeRequest, CommandInvokeResult to unified type system; extend EngineCapabilities with slashCommands flag; add COMMAND_LIST/COMMAND_INVOKE request types and COMMANDS_CHANGED notification type - Engine adapters: Add listCommands() and invokeCommand() to base EngineAdapter with safe defaults; implement per-engine discovery and invocation (Claude via embedded text, Copilot via skills API, OpenCode via command REST API with sendMessage fallback) - Gateway: Route COMMAND_LIST and COMMAND_INVOKE through EngineManager; broadcast commands.changed events to all clients - Client API: Add listCommands() and invokeCommand() RPC methods to gateway-client and gateway-api layers - Frontend: Add autocomplete dropdown to PromptInput triggered on '/' with keyboard navigation (ArrowUp/Down/Tab/Enter/Escape); add command state management to Chat.tsx with availableCommands signal, engine- change fetch, and handleCommandInvoke handler with optimistic UI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…/slash-command-passthrough
Claude Code: - Fix init message field: use `slash_commands: string[]` (correct SDK type) instead of `msg.commands` which doesn't exist - Enrich command names with descriptions from well-known commands list since the init message only provides names without metadata - Extract getWellKnownCommands() for reuse between init and fallback GitHub Copilot: - Add command.execute event handler that acknowledges commands via session.rpc.commands.handlePendingCommand() — required by the SDK protocol to unblock the CLI after command dispatch - Add command.completed event handler (logging) - Add commands.changed event handler to dynamically refresh the cached command list when the CLI updates available commands - Document the command flow in invokeCommand() comments OpenCode: - Remove unnecessary `(client.session as any).command()` cast — the SDK v2 types already expose `session.command()` with full type safety - Remove `cmd: any` cast in fetchCommands() since SDK types flow through Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude Code fixes: - Handle local_command_output system messages so /help, /cost etc. actually display their output instead of silently dropping it - Extract user-installed skills from init message's skills[] array alongside built-in slash_commands[] - Improve listCommands() to check session state before falling back to the well-known commands list Copilot fixes: - Await fetchSkills() in createSession() instead of fire-and-forget, ensuring cachedCommands is populated before frontend requests - Retry fetchSkills in listCommands() when cache is empty - Add session.skills_loaded event handler for real-time skill updates - Format handlePendingCommand() call correctly Frontend (Chat.tsx): - Pass sessionId to gateway.listCommands() so adapters can look up the correct engine session for command discovery - Re-fetch commands when active session changes (not just engine type) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Claude /help and other slash commands producing no output:
- Handle string content in handleAssistantMessage (SDK wraps
slash command output as plain string, not content block array)
- Handle text content in handleUserMessage (synthetic user messages
from CLI with XML-stripped slash command output)
- Use result.result text as fallback in handleResultMessage when
buffer is empty (for local-jsx commands like /help)
- Keep local_command_output handler for future-proofing
2. Claude skills not showing: Added debug logging to init message
handler to trace slash_commands and skills arrays from SDK.
3. Copilot slash commands completely non-functional:
- Root cause: listCommands called before engine session is active
(lazy creation). activeSessions lookup returns undefined.
- Fix: activate session via ensureActiveSession in listCommands
when no active session found but directory is known.
- Enhanced fetchSkills with comprehensive debug logging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use SDK's supportedCommands() API via sdkQuery for Claude warmup, replacing init-message parsing (gets full name + description) - Trigger warmup in createSession() and await it in listCommands() so commands are available before user sends first message - Inject cached user skill names into system prompt via append - Pass directory from conversationStore to Copilot listCommands() so sessions can resume after app restart - Create engine session eagerly in engine-manager createSession() instead of lazily on first sendMessage - Track only engineType (not sessionId) in Chat.tsx createEffect to avoid re-fetching commands on every session switch Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds first-pass “slash command / skills” passthrough support end-to-end (types → gateway RPC → engine adapters → chat UI), plus some initial scaffolding for cron/scheduled tasks.
Changes:
- Extend unified types + gateway protocol with command list/invoke request/notifications (and new
slashCommandscapability flag). - Add UI support for slash-command autocomplete in
PromptInputand a command-invoke path inChat. - Implement adapter-level command discovery/invocation for Copilot/Claude/OpenCode and wire gateway routing/broadcast.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/unified.ts | Adds slashCommands capability, command/cron request+notification constants, and command/cron payload types. |
| src/pages/Chat.tsx | Fetches/updates available commands per engine; adds onCommandInvoke path with optimistic message. |
| src/components/PromptInput.tsx | Adds slash-command parsing, autocomplete dropdown, and routes /... sends to onCommandInvoke. |
| src/locales/en.ts | Adds prompt.noCommandsFound key to locale schema and English strings. |
| src/locales/ru.ts | Adds Russian string for noCommandsFound. |
| src/locales/zh.ts | Adds Chinese string for noCommandsFound. |
| src/lib/gateway-client.ts | Adds RPC helpers for command.* and cron.* request types; adds events for new notifications. |
| src/lib/gateway-api.ts | Exposes listCommands / invokeCommand and binds commands.changed notification handler. |
| electron/main/gateway/ws-server.ts | Routes command.list / command.invoke requests and broadcasts commands.changed. |
| electron/main/gateway/engine-manager.ts | Eagerly creates engine session on conversation creation; adds list/invoke command APIs. |
| electron/main/engines/engine-adapter.ts | Adds default listCommands / invokeCommand API surface + commands.changed event typing. |
| electron/main/engines/opencode/index.ts | Adds OpenCode command listing and invocation stub. |
| electron/main/engines/mock-adapter.ts | Sets slashCommands: false capability. |
| electron/main/engines/copilot/index.ts | Adds skill discovery/caching and command event handling + invoke passthrough. |
| electron/main/engines/claude/index.ts | Adds command warmup/listing + command passthrough; injects skill names into system prompt append. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ssthrough # Conflicts: # electron/main/gateway/ws-server.ts # src/lib/gateway-api.ts # src/lib/gateway-client.ts # src/pages/Chat.tsx # src/types/unified.ts
…/slash-command-passthrough
- Downgrade verbose debug logs from info to debug level (Claude SDK messages, system messages, Copilot session events, fetchSkills) - Remove JSON.stringify of full message payloads in logs to prevent leaking user data; log only type/subtype - Fix OpenCode invokeCommand to return handledAsCommand:false so gateway falls back to sendMessage correctly - Guard Cron RPC client methods with clear rejection until backend handlers are implemented - Add zero-length guard for modulo in command menu keyboard navigation to prevent NaN - Clean up orphaned conversation if engine session creation fails in EngineManager.createSession - Reduce local_command_output logging to debug level, remove content preview Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ee, file explorer, slash commands) - Add 'Developer Workflow Tools' section to all 5 README languages - Scheduled Tasks (interval/daily/weekly automation) - Git Worktree Parallel Sessions (isolated branches with merge/squash/rebase) - File Explorer & Git Monitoring (real-time change tracking, inline diff) - Slash Commands & Engine Skills (unified autocomplete for all engines) - Add Token usage tracking to 'And More' section - Website: add 4 new feature cards, remove 'Modern Tech Stack' card - Website: add i18n translations (en/zh) for new feature cards Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add end-to-end slash command support across all three engines (Claude Code, GitHub Copilot, OpenCode). Users can type
/in the prompt input to see an autocomplete menu of available commands and skills, then invoke them directly through the engine's native command API.Changes
Gateway Protocol
command.listandcommand.invokerequest types to the WebSocket gatewaycommands.changedpush notification for real-time command list updatesEngineCommand,CommandInvokeResult, and related types tounified.tsEngine Adapters
sdkQuery.supportedCommands()at session creation to discover built-in commands and user-installed skills; inject skill names into system prompt; handlelocal_command_outputand slash command text in stream processingrpc.skills.list()at session creation; handlecommand.execute,commands.changed, andsession.skills_loadedeventscommandAsync()REST API; fall back tosendMessagefor SSE-based response handlingFrontend
/commandinsertion on selectioncommands.changednotifications, addhandleCommandInvokefor optimistic UI with error rollbacklistCommands()andinvokeCommand()client methodsEngine Capabilities
slashCommands: booleantoEngineCapabilitiesso the frontend conditionally shows the autocomplete UIi18n
noCommandsFoundkey to en/zh/ru localesFuture: Cron types (stubs only)
CronCreateRequest,CronJobInfo, and related types tounified.tsTest Plan
bun run test:unit— 416 passed)npm run typecheck)