@@ -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" ;
@@ -458,8 +455,38 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
458455 }
459456
460457 const messageText = input . trim ( ) ;
458+ const parsed = parseCommand ( messageText ) ;
459+
460+ if ( parsed ) {
461+ const context : SlashCommandContext = {
462+ variant,
463+ workspaceId : variant === "workspace" ? props . workspaceId : undefined ,
464+ sendMessageOptions,
465+ setInput,
466+ setIsSending,
467+ setToast,
468+ setVimEnabled,
469+ setPreferredModel,
470+ onProviderConfig : props . onProviderConfig ,
471+ onModelChange : props . onModelChange ,
472+ onTruncateHistory : variant === "workspace" ? props . onTruncateHistory : undefined ,
473+ onCancelEdit : variant === "workspace" ? props . onCancelEdit : undefined ,
474+ editMessageId : editingMessage ?. id ,
475+ resetInputHeight : ( ) => {
476+ if ( inputRef . current ) {
477+ inputRef . current . style . height = "36px" ;
478+ }
479+ } ,
480+ } ;
481+
482+ const result = await processSlashCommand ( parsed , context ) ;
483+
484+ if ( ! result . clearInput ) {
485+ setInput ( messageText ) ; // Restore input on failure
486+ }
487+ return ;
488+ }
461489
462- // Route to creation handler for creation variant
463490 if ( variant === "creation" ) {
464491 // Creation variant: simple message send + workspace creation
465492 setIsSending ( true ) ;
@@ -474,193 +501,10 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
474501 return ;
475502 }
476503
477- // Workspace variant: full command handling + message send
504+ // Workspace variant: regular message send
478505 if ( variant !== "workspace" ) return ; // Type guard
479506
480507 try {
481- // Parse command
482- const parsed = parseCommand ( messageText ) ;
483-
484- if ( parsed ) {
485- // Handle /clear command
486- if ( parsed . type === "clear" ) {
487- setInput ( "" ) ;
488- if ( inputRef . current ) {
489- inputRef . current . style . height = "36px" ;
490- }
491- await props . onTruncateHistory ( 1.0 ) ;
492- setToast ( {
493- id : Date . now ( ) . toString ( ) ,
494- type : "success" ,
495- message : "Chat history cleared" ,
496- } ) ;
497- return ;
498- }
499-
500- // Handle /truncate command
501- if ( parsed . type === "truncate" ) {
502- setInput ( "" ) ;
503- if ( inputRef . current ) {
504- inputRef . current . style . height = "36px" ;
505- }
506- await props . onTruncateHistory ( parsed . percentage ) ;
507- setToast ( {
508- id : Date . now ( ) . toString ( ) ,
509- type : "success" ,
510- message : `Chat history truncated by ${ Math . round ( parsed . percentage * 100 ) } %` ,
511- } ) ;
512- return ;
513- }
514-
515- // Handle /providers set command
516- if ( parsed . type === "providers-set" && props . onProviderConfig ) {
517- setIsSending ( true ) ;
518- setInput ( "" ) ; // Clear input immediately
519-
520- try {
521- await props . onProviderConfig ( parsed . provider , parsed . keyPath , parsed . value ) ;
522- // Success - show toast
523- setToast ( {
524- id : Date . now ( ) . toString ( ) ,
525- type : "success" ,
526- message : `Provider ${ parsed . provider } updated` ,
527- } ) ;
528- } catch ( error ) {
529- console . error ( "Failed to update provider config:" , error ) ;
530- setToast ( {
531- id : Date . now ( ) . toString ( ) ,
532- type : "error" ,
533- message : error instanceof Error ? error . message : "Failed to update provider" ,
534- } ) ;
535- setInput ( messageText ) ; // Restore input on error
536- } finally {
537- setIsSending ( false ) ;
538- }
539- return ;
540- }
541-
542- // Handle /model command
543- if ( parsed . type === "model-set" ) {
544- setInput ( "" ) ; // Clear input immediately
545- setPreferredModel ( parsed . modelString ) ;
546- props . onModelChange ?.( parsed . modelString ) ;
547- setToast ( {
548- id : Date . now ( ) . toString ( ) ,
549- type : "success" ,
550- message : `Model changed to ${ parsed . modelString } ` ,
551- } ) ;
552- return ;
553- }
554-
555- // Handle /vim command
556- if ( parsed . type === "vim-toggle" ) {
557- setInput ( "" ) ; // Clear input immediately
558- setVimEnabled ( ( prev ) => ! prev ) ;
559- return ;
560- }
561-
562- // Handle /telemetry command
563- if ( parsed . type === "telemetry-set" ) {
564- setInput ( "" ) ; // Clear input immediately
565- setTelemetryEnabled ( parsed . enabled ) ;
566- setToast ( {
567- id : Date . now ( ) . toString ( ) ,
568- type : "success" ,
569- message : `Telemetry ${ parsed . enabled ? "enabled" : "disabled" } ` ,
570- } ) ;
571- return ;
572- }
573-
574- // Handle /compact command
575- if ( parsed . type === "compact" ) {
576- const context : CommandHandlerContext = {
577- workspaceId : props . workspaceId ,
578- sendMessageOptions,
579- editMessageId : editingMessage ?. id ,
580- setInput,
581- setIsSending,
582- setToast,
583- onCancelEdit : props . onCancelEdit ,
584- } ;
585-
586- const result = await handleCompactCommand ( parsed , context ) ;
587- if ( ! result . clearInput ) {
588- setInput ( messageText ) ; // Restore input on error
589- }
590- return ;
591- }
592-
593- // Handle /fork command
594- if ( parsed . type === "fork" ) {
595- setInput ( "" ) ; // Clear input immediately
596- setIsSending ( true ) ;
597-
598- try {
599- const forkResult = await forkWorkspace ( {
600- sourceWorkspaceId : props . workspaceId ,
601- newName : parsed . newName ,
602- startMessage : parsed . startMessage ,
603- sendMessageOptions,
604- } ) ;
605-
606- if ( ! forkResult . success ) {
607- const errorMsg = forkResult . error ?? "Failed to fork workspace" ;
608- console . error ( "Failed to fork workspace:" , errorMsg ) ;
609- setToast ( {
610- id : Date . now ( ) . toString ( ) ,
611- type : "error" ,
612- title : "Fork Failed" ,
613- message : errorMsg ,
614- } ) ;
615- setInput ( messageText ) ; // Restore input on error
616- } else {
617- setToast ( {
618- id : Date . now ( ) . toString ( ) ,
619- type : "success" ,
620- message : `Forked to workspace "${ parsed . newName } "` ,
621- } ) ;
622- }
623- } catch ( error ) {
624- const errorMsg = error instanceof Error ? error . message : "Failed to fork workspace" ;
625- console . error ( "Fork error:" , error ) ;
626- setToast ( {
627- id : Date . now ( ) . toString ( ) ,
628- type : "error" ,
629- title : "Fork Failed" ,
630- message : errorMsg ,
631- } ) ;
632- setInput ( messageText ) ; // Restore input on error
633- }
634-
635- setIsSending ( false ) ;
636- return ;
637- }
638-
639- // Handle /new command
640- if ( parsed . type === "new" ) {
641- const context : CommandHandlerContext = {
642- workspaceId : props . workspaceId ,
643- sendMessageOptions,
644- setInput,
645- setIsSending,
646- setToast,
647- } ;
648-
649- const result = await handleNewCommand ( parsed , context ) ;
650- if ( ! result . clearInput ) {
651- setInput ( messageText ) ; // Restore input on error
652- }
653- return ;
654- }
655-
656- // Handle all other commands - show display toast
657- const commandToast = createCommandToast ( parsed ) ;
658- if ( commandToast ) {
659- setToast ( commandToast ) ;
660- return ;
661- }
662- }
663-
664508 // Regular message - send directly via API
665509 setIsSending ( true ) ;
666510
0 commit comments