@@ -2365,6 +2365,7 @@ export const webviewMessageHandler = async (
23652365 const commandList = commands . map ( ( command ) => ( {
23662366 name : command . name ,
23672367 source : command . source ,
2368+ filePath : command . filePath ,
23682369 } ) )
23692370
23702371 await provider . postMessageToWebview ( {
@@ -2381,5 +2382,170 @@ export const webviewMessageHandler = async (
23812382 }
23822383 break
23832384 }
2385+ case "openCommandFile" : {
2386+ try {
2387+ if ( message . text ) {
2388+ const { getCommand } = await import ( "../../services/command/commands" )
2389+ const command = await getCommand ( provider . cwd || "" , message . text )
2390+
2391+ if ( command && command . filePath ) {
2392+ openFile ( command . filePath )
2393+ } else {
2394+ vscode . window . showErrorMessage ( t ( "common:errors.command_not_found" , { name : message . text } ) )
2395+ }
2396+ }
2397+ } catch ( error ) {
2398+ provider . log (
2399+ `Error opening command file: ${ JSON . stringify ( error , Object . getOwnPropertyNames ( error ) , 2 ) } ` ,
2400+ )
2401+ vscode . window . showErrorMessage ( t ( "common:errors.open_command_file" ) )
2402+ }
2403+ break
2404+ }
2405+ case "deleteCommand" : {
2406+ try {
2407+ if ( message . text && message . values ?. source ) {
2408+ const { getCommand } = await import ( "../../services/command/commands" )
2409+ const command = await getCommand ( provider . cwd || "" , message . text )
2410+
2411+ if ( command && command . filePath ) {
2412+ // Delete the command file
2413+ await fs . unlink ( command . filePath )
2414+ provider . log ( `Deleted command file: ${ command . filePath } ` )
2415+ } else {
2416+ vscode . window . showErrorMessage ( t ( "common:errors.command_not_found" , { name : message . text } ) )
2417+ }
2418+ }
2419+ } catch ( error ) {
2420+ provider . log ( `Error deleting command: ${ JSON . stringify ( error , Object . getOwnPropertyNames ( error ) , 2 ) } ` )
2421+ vscode . window . showErrorMessage ( t ( "common:errors.delete_command" ) )
2422+ }
2423+ break
2424+ }
2425+ case "createCommand" : {
2426+ try {
2427+ const source = message . values ?. source as "global" | "project"
2428+ const fileName = message . text // Custom filename from user input
2429+
2430+ if ( ! source ) {
2431+ provider . log ( "Missing source for createCommand" )
2432+ break
2433+ }
2434+
2435+ // Determine the commands directory based on source
2436+ let commandsDir : string
2437+ if ( source === "global" ) {
2438+ const globalConfigDir = path . join ( os . homedir ( ) , ".roo" )
2439+ commandsDir = path . join ( globalConfigDir , "commands" )
2440+ } else {
2441+ // Project commands
2442+ const workspaceRoot = vscode . workspace . workspaceFolders ?. [ 0 ] ?. uri . fsPath
2443+ if ( ! workspaceRoot ) {
2444+ vscode . window . showErrorMessage ( "No workspace folder found for project command" )
2445+ break
2446+ }
2447+ commandsDir = path . join ( workspaceRoot , ".roo" , "commands" )
2448+ }
2449+
2450+ // Ensure the commands directory exists
2451+ await fs . mkdir ( commandsDir , { recursive : true } )
2452+
2453+ // Use provided filename or generate a unique one
2454+ let commandName : string
2455+ if ( fileName && fileName . trim ( ) ) {
2456+ let cleanFileName = fileName . trim ( )
2457+
2458+ // Strip leading slash if present
2459+ if ( cleanFileName . startsWith ( "/" ) ) {
2460+ cleanFileName = cleanFileName . substring ( 1 )
2461+ }
2462+
2463+ // Remove .md extension if present BEFORE slugification
2464+ if ( cleanFileName . toLowerCase ( ) . endsWith ( ".md" ) ) {
2465+ cleanFileName = cleanFileName . slice ( 0 , - 3 )
2466+ }
2467+
2468+ // Slugify the command name: lowercase, replace spaces with dashes, remove special characters
2469+ commandName = cleanFileName
2470+ . toLowerCase ( )
2471+ . replace ( / \s + / g, "-" ) // Replace spaces with dashes
2472+ . replace ( / [ ^ a - z 0 - 9 - ] / g, "" ) // Remove special characters except dashes
2473+ . replace ( / - + / g, "-" ) // Replace multiple dashes with single dash
2474+ . replace ( / ^ - | - $ / g, "" ) // Remove leading/trailing dashes
2475+
2476+ // Ensure we have a valid command name
2477+ if ( ! commandName || commandName . length === 0 ) {
2478+ commandName = "new-command"
2479+ }
2480+ } else {
2481+ // Generate a unique command name
2482+ commandName = "new-command"
2483+ let counter = 1
2484+ let filePath = path . join ( commandsDir , `${ commandName } .md` )
2485+
2486+ while (
2487+ await fs
2488+ . access ( filePath )
2489+ . then ( ( ) => true )
2490+ . catch ( ( ) => false )
2491+ ) {
2492+ commandName = `new-command-${ counter } `
2493+ filePath = path . join ( commandsDir , `${ commandName } .md` )
2494+ counter ++
2495+ }
2496+ }
2497+
2498+ const filePath = path . join ( commandsDir , `${ commandName } .md` )
2499+
2500+ // Check if file already exists
2501+ if (
2502+ await fs
2503+ . access ( filePath )
2504+ . then ( ( ) => true )
2505+ . catch ( ( ) => false )
2506+ ) {
2507+ vscode . window . showErrorMessage ( `Command "${ commandName } " already exists` )
2508+ break
2509+ }
2510+
2511+ // Create the command file with template content
2512+ const templateContent = "This is a new slash command. Edit this file to customize the command behavior."
2513+
2514+ await fs . writeFile ( filePath , templateContent , "utf8" )
2515+ provider . log ( `Created new command file: ${ filePath } ` )
2516+
2517+ // Open the new file in the editor
2518+ openFile ( filePath )
2519+
2520+ // Refresh commands list
2521+ const { getCommands } = await import ( "../../services/command/commands" )
2522+ const commands = await getCommands ( provider . cwd || "" )
2523+ const commandList = commands . map ( ( command ) => ( {
2524+ name : command . name ,
2525+ source : command . source ,
2526+ filePath : command . filePath ,
2527+ } ) )
2528+ await provider . postMessageToWebview ( {
2529+ type : "commands" ,
2530+ commands : commandList ,
2531+ } )
2532+ } catch ( error ) {
2533+ provider . log ( `Error creating command: ${ JSON . stringify ( error , Object . getOwnPropertyNames ( error ) , 2 ) } ` )
2534+ vscode . window . showErrorMessage ( "Failed to create command" )
2535+ }
2536+ break
2537+ }
2538+
2539+ case "insertTextIntoTextarea" : {
2540+ const text = message . text
2541+ if ( text ) {
2542+ // Send message to insert text into the chat textarea
2543+ await provider . postMessageToWebview ( {
2544+ type : "insertTextIntoTextarea" ,
2545+ text : text ,
2546+ } )
2547+ }
2548+ break
2549+ }
23842550 }
23852551}
0 commit comments