@@ -11,7 +11,7 @@ import React, {
1111import { CommandSuggestions , COMMAND_SUGGESTION_KEYS } from "../CommandSuggestions" ;
1212import type { Toast } from "../ChatInputToast" ;
1313import { ChatInputToast } from "../ChatInputToast" ;
14- import { createCommandToast , createErrorToast } from "../ChatInputToasts" ;
14+ import { createErrorToast } from "../ChatInputToasts" ;
1515import { parseCommand } from "@/browser/utils/slashCommands/parser" ;
1616import { usePersistedState , updatePersistedState } from "@/browser/hooks/usePersistedState" ;
1717import { useMode } from "@/browser/contexts/ModeContext" ;
@@ -26,11 +26,9 @@ import {
2626 getPendingScopeId ,
2727} from "@/common/constants/storage" ;
2828import {
29- handleNewCommand ,
30- handleCompactCommand ,
31- forkWorkspace ,
3229 prepareCompactionMessage ,
33- type CommandHandlerContext ,
30+ processSlashCommand ,
31+ type SlashCommandContext ,
3432} from "@/browser/utils/chatCommands" ;
3533import { CUSTOM_EVENTS } from "@/common/constants/events" ;
3634import {
@@ -59,7 +57,6 @@ import {
5957import type { ThinkingLevel } from "@/common/types/thinking" ;
6058import type { MuxFrontendMetadata } from "@/common/types/message" ;
6159import { useTelemetry } from "@/browser/hooks/useTelemetry" ;
62- import { setTelemetryEnabled } from "@/common/telemetry" ;
6360import { getTokenCountPromise } from "@/browser/utils/tokenizer/rendererClient" ;
6461import { CreationCenterContent } from "./CreationCenterContent" ;
6562import { cn } from "@/common/lib/utils" ;
@@ -467,8 +464,38 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
467464 }
468465
469466 const messageText = input . trim ( ) ;
467+ const parsed = parseCommand ( messageText ) ;
468+
469+ if ( parsed ) {
470+ const context : SlashCommandContext = {
471+ variant,
472+ workspaceId : variant === "workspace" ? props . workspaceId : undefined ,
473+ sendMessageOptions,
474+ setInput,
475+ setIsSending,
476+ setToast,
477+ setVimEnabled,
478+ setPreferredModel,
479+ onProviderConfig : props . onProviderConfig ,
480+ onModelChange : props . onModelChange ,
481+ onTruncateHistory : variant === "workspace" ? props . onTruncateHistory : undefined ,
482+ onCancelEdit : variant === "workspace" ? props . onCancelEdit : undefined ,
483+ editMessageId : editingMessage ?. id ,
484+ resetInputHeight : ( ) => {
485+ if ( inputRef . current ) {
486+ inputRef . current . style . height = "36px" ;
487+ }
488+ } ,
489+ } ;
490+
491+ const result = await processSlashCommand ( parsed , context ) ;
492+
493+ if ( ! result . clearInput ) {
494+ setInput ( messageText ) ; // Restore input on failure
495+ }
496+ return ;
497+ }
470498
471- // Route to creation handler for creation variant
472499 if ( variant === "creation" ) {
473500 // Creation variant: simple message send + workspace creation
474501 setIsSending ( true ) ;
@@ -483,193 +510,10 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
483510 return ;
484511 }
485512
486- // Workspace variant: full command handling + message send
513+ // Workspace variant: regular message send
487514 if ( variant !== "workspace" ) return ; // Type guard
488515
489516 try {
490- // Parse command
491- const parsed = parseCommand ( messageText ) ;
492-
493- if ( parsed ) {
494- // Handle /clear command
495- if ( parsed . type === "clear" ) {
496- setInput ( "" ) ;
497- if ( inputRef . current ) {
498- inputRef . current . style . height = "36px" ;
499- }
500- await props . onTruncateHistory ( 1.0 ) ;
501- setToast ( {
502- id : Date . now ( ) . toString ( ) ,
503- type : "success" ,
504- message : "Chat history cleared" ,
505- } ) ;
506- return ;
507- }
508-
509- // Handle /truncate command
510- if ( parsed . type === "truncate" ) {
511- setInput ( "" ) ;
512- if ( inputRef . current ) {
513- inputRef . current . style . height = "36px" ;
514- }
515- await props . onTruncateHistory ( parsed . percentage ) ;
516- setToast ( {
517- id : Date . now ( ) . toString ( ) ,
518- type : "success" ,
519- message : `Chat history truncated by ${ Math . round ( parsed . percentage * 100 ) } %` ,
520- } ) ;
521- return ;
522- }
523-
524- // Handle /providers set command
525- if ( parsed . type === "providers-set" && props . onProviderConfig ) {
526- setIsSending ( true ) ;
527- setInput ( "" ) ; // Clear input immediately
528-
529- try {
530- await props . onProviderConfig ( parsed . provider , parsed . keyPath , parsed . value ) ;
531- // Success - show toast
532- setToast ( {
533- id : Date . now ( ) . toString ( ) ,
534- type : "success" ,
535- message : `Provider ${ parsed . provider } updated` ,
536- } ) ;
537- } catch ( error ) {
538- console . error ( "Failed to update provider config:" , error ) ;
539- setToast ( {
540- id : Date . now ( ) . toString ( ) ,
541- type : "error" ,
542- message : error instanceof Error ? error . message : "Failed to update provider" ,
543- } ) ;
544- setInput ( messageText ) ; // Restore input on error
545- } finally {
546- setIsSending ( false ) ;
547- }
548- return ;
549- }
550-
551- // Handle /model command
552- if ( parsed . type === "model-set" ) {
553- setInput ( "" ) ; // Clear input immediately
554- setPreferredModel ( parsed . modelString ) ;
555- props . onModelChange ?.( parsed . modelString ) ;
556- setToast ( {
557- id : Date . now ( ) . toString ( ) ,
558- type : "success" ,
559- message : `Model changed to ${ parsed . modelString } ` ,
560- } ) ;
561- return ;
562- }
563-
564- // Handle /vim command
565- if ( parsed . type === "vim-toggle" ) {
566- setInput ( "" ) ; // Clear input immediately
567- setVimEnabled ( ( prev ) => ! prev ) ;
568- return ;
569- }
570-
571- // Handle /telemetry command
572- if ( parsed . type === "telemetry-set" ) {
573- setInput ( "" ) ; // Clear input immediately
574- setTelemetryEnabled ( parsed . enabled ) ;
575- setToast ( {
576- id : Date . now ( ) . toString ( ) ,
577- type : "success" ,
578- message : `Telemetry ${ parsed . enabled ? "enabled" : "disabled" } ` ,
579- } ) ;
580- return ;
581- }
582-
583- // Handle /compact command
584- if ( parsed . type === "compact" ) {
585- const context : CommandHandlerContext = {
586- workspaceId : props . workspaceId ,
587- sendMessageOptions,
588- editMessageId : editingMessage ?. id ,
589- setInput,
590- setIsSending,
591- setToast,
592- onCancelEdit : props . onCancelEdit ,
593- } ;
594-
595- const result = await handleCompactCommand ( parsed , context ) ;
596- if ( ! result . clearInput ) {
597- setInput ( messageText ) ; // Restore input on error
598- }
599- return ;
600- }
601-
602- // Handle /fork command
603- if ( parsed . type === "fork" ) {
604- setInput ( "" ) ; // Clear input immediately
605- setIsSending ( true ) ;
606-
607- try {
608- const forkResult = await forkWorkspace ( {
609- sourceWorkspaceId : props . workspaceId ,
610- newName : parsed . newName ,
611- startMessage : parsed . startMessage ,
612- sendMessageOptions,
613- } ) ;
614-
615- if ( ! forkResult . success ) {
616- const errorMsg = forkResult . error ?? "Failed to fork workspace" ;
617- console . error ( "Failed to fork workspace:" , errorMsg ) ;
618- setToast ( {
619- id : Date . now ( ) . toString ( ) ,
620- type : "error" ,
621- title : "Fork Failed" ,
622- message : errorMsg ,
623- } ) ;
624- setInput ( messageText ) ; // Restore input on error
625- } else {
626- setToast ( {
627- id : Date . now ( ) . toString ( ) ,
628- type : "success" ,
629- message : `Forked to workspace "${ parsed . newName } "` ,
630- } ) ;
631- }
632- } catch ( error ) {
633- const errorMsg = error instanceof Error ? error . message : "Failed to fork workspace" ;
634- console . error ( "Fork error:" , error ) ;
635- setToast ( {
636- id : Date . now ( ) . toString ( ) ,
637- type : "error" ,
638- title : "Fork Failed" ,
639- message : errorMsg ,
640- } ) ;
641- setInput ( messageText ) ; // Restore input on error
642- }
643-
644- setIsSending ( false ) ;
645- return ;
646- }
647-
648- // Handle /new command
649- if ( parsed . type === "new" ) {
650- const context : CommandHandlerContext = {
651- workspaceId : props . workspaceId ,
652- sendMessageOptions,
653- setInput,
654- setIsSending,
655- setToast,
656- } ;
657-
658- const result = await handleNewCommand ( parsed , context ) ;
659- if ( ! result . clearInput ) {
660- setInput ( messageText ) ; // Restore input on error
661- }
662- return ;
663- }
664-
665- // Handle all other commands - show display toast
666- const commandToast = createCommandToast ( parsed ) ;
667- if ( commandToast ) {
668- setToast ( commandToast ) ;
669- return ;
670- }
671- }
672-
673517 // Regular message - send directly via API
674518 setIsSending ( true ) ;
675519
0 commit comments