diff --git a/packages/ui/src/components/chat/ChatInput.tsx b/packages/ui/src/components/chat/ChatInput.tsx index a7fa620a..cd5b950e 100644 --- a/packages/ui/src/components/chat/ChatInput.tsx +++ b/packages/ui/src/components/chat/ChatInput.tsx @@ -32,7 +32,7 @@ import { renderMagicPrompt } from '@/lib/magicPrompts'; import { AttachedFilesList } from './FileAttachment'; import { QueuedMessageChips } from './QueuedMessageChips'; import { FileMentionAutocomplete, type FileMentionHandle } from './FileMentionAutocomplete'; -import { CommandAutocomplete, type CommandAutocompleteHandle } from './CommandAutocomplete'; +import { CommandAutocomplete, type CommandAutocompleteHandle, type CommandInfo } from './CommandAutocomplete'; import { SkillAutocomplete, type SkillAutocompleteHandle } from './SkillAutocomplete'; import { cn, formatDirectoryName, isMacOS } from '@/lib/utils'; import { ModelControls } from './ModelControls'; @@ -2470,7 +2470,7 @@ const ChatInputComponent: React.FC = ({ onOpenSettings, scrollTo textareaRef.current?.focus(); }; - const handleCommandSelect = (command: { name: string; description?: string; agent?: string; model?: string }) => { + const handleCommandSelect = (command: CommandInfo) => { setMessage(`/${command.name} `); diff --git a/packages/ui/src/components/chat/CommandAutocomplete.tsx b/packages/ui/src/components/chat/CommandAutocomplete.tsx index ec13827b..07255f76 100644 --- a/packages/ui/src/components/chat/CommandAutocomplete.tsx +++ b/packages/ui/src/components/chat/CommandAutocomplete.tsx @@ -7,8 +7,12 @@ import { useCommandsStore } from '@/stores/useCommandsStore'; import { useSkillsStore } from '@/stores/useSkillsStore'; import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay'; -interface CommandInfo { +type CommandSource = 'openchamber' | 'opencode'; + +export interface CommandInfo { + id: string; name: string; + source: CommandSource; description?: string; agent?: string; model?: string; @@ -89,8 +93,10 @@ export const CommandAutocomplete = React.forwardRef skill.name)); - const customCommands: CommandInfo[] = commandsWithMetadata.map(cmd => ({ + const customCommands: CommandInfo[] = commandsWithMetadata.map((cmd, index) => ({ + id: `opencode:${cmd.scope ?? 'global'}:${cmd.name}:${cmd.agent ?? ''}:${cmd.model ?? ''}:${index}`, name: cmd.name, + source: 'opencode', description: cmd.description, agent: cmd.agent ?? undefined, model: cmd.model ?? undefined, @@ -101,30 +107,23 @@ export const CommandAutocomplete = React.forwardRef(); - - builtInCommands.forEach(cmd => commandMap.set(cmd.name, cmd)); - - customCommands.forEach(cmd => commandMap.set(cmd.name, cmd)); - - const allCommands = Array.from(commandMap.values()); + const allCommands = [...builtInCommands, ...customCommands]; const allowInitCommand = !hasMessagesInCurrentSession; const filtered = (searchQuery @@ -148,19 +147,19 @@ export const CommandAutocomplete = React.forwardRef { itemRefs.current[index] = el; }} className={cn( "flex items-start gap-2 px-3 py-2 cursor-pointer rounded-lg", @@ -425,5 +424,3 @@ export const CommandAutocomplete = React.forwardRef = ({ }); }, [prompt, updateAutocompleteState]); - const handleAutocompleteCommandSelect = React.useCallback((command: { name: string }) => { + const handleAutocompleteCommandSelect = React.useCallback((command: CommandInfo) => { const nextPrompt = `/${command.name} `; setPrompt(nextPrompt); setShowCommandAutocomplete(false); diff --git a/packages/ui/src/components/session/ScheduledTaskEditorDialog.tsx b/packages/ui/src/components/session/ScheduledTaskEditorDialog.tsx index 3c0d7508..641f7213 100644 --- a/packages/ui/src/components/session/ScheduledTaskEditorDialog.tsx +++ b/packages/ui/src/components/session/ScheduledTaskEditorDialog.tsx @@ -13,7 +13,7 @@ import { RiAddLine, RiCloseLine, RiCalendarLine, RiArrowLeftSLine, RiArrowRightS import { ModelSelector } from '@/components/sections/agents/ModelSelector'; import { AgentSelector } from '@/components/sections/commands/AgentSelector'; import { isPrimaryMode } from '@/components/chat/mobileControlsUtils'; -import { CommandAutocomplete, type CommandAutocompleteHandle } from '@/components/chat/CommandAutocomplete'; +import { CommandAutocomplete, type CommandAutocompleteHandle, type CommandInfo } from '@/components/chat/CommandAutocomplete'; import { FileMentionAutocomplete, type FileMentionHandle } from '@/components/chat/FileMentionAutocomplete'; import { useConfigStore } from '@/stores/useConfigStore'; import { useUIStore } from '@/stores/useUIStore'; @@ -907,7 +907,7 @@ export function ScheduledTaskEditorDialog(props: { }); }, [draft.execution.prompt, setPromptValue, updateAutocompleteState]); - const handleCommandSelect = React.useCallback((command: { name: string }) => { + const handleCommandSelect = React.useCallback((command: CommandInfo) => { const nextPrompt = `/${command.name} `; setPromptValue(nextPrompt); setShowCommandAutocomplete(false); diff --git a/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx b/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx index ae31a491..9a6fb7b2 100644 --- a/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx +++ b/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx @@ -20,7 +20,7 @@ import { useProjectsStore } from '@/stores/useProjectsStore'; import { ModelMultiSelect, generateInstanceId, type ModelSelectionWithId } from '@/components/multirun/ModelMultiSelect'; import { BranchSelector, useBranchOptions } from '@/components/multirun/BranchSelector'; import { AgentSelector } from '@/components/multirun/AgentSelector'; -import { CommandAutocomplete, type CommandAutocompleteHandle } from '@/components/chat/CommandAutocomplete'; +import { CommandAutocomplete, type CommandAutocompleteHandle, type CommandInfo } from '@/components/chat/CommandAutocomplete'; import { FileMentionAutocomplete, type FileMentionHandle } from '@/components/chat/FileMentionAutocomplete'; import { isIMECompositionEvent } from '@/lib/ime'; import { getWorktreeSetupCommands } from '@/lib/openchamberConfig'; @@ -294,7 +294,7 @@ export const AgentManagerEmptyState: React.FC = ({ }); }, [prompt, updateAutocompleteState]); - const handleAutocompleteCommandSelect = React.useCallback((command: { name: string }) => { + const handleAutocompleteCommandSelect = React.useCallback((command: CommandInfo) => { const nextPrompt = `/${command.name} `; setPrompt(nextPrompt); setShowCommandAutocomplete(false);