@@ -30,6 +30,9 @@ pub enum WorkspaceSubcommand {
3030 /// Set workspace settings
3131 Set ( WorkspaceSetArgs ) ,
3232
33+ /// Unset (remove) workspace settings
34+ Unset ( WorkspaceUnsetArgs ) ,
35+
3336 /// Open workspace configuration in editor
3437 Edit ( WorkspaceEditArgs ) ,
3538}
@@ -64,6 +67,13 @@ pub struct WorkspaceSetArgs {
6467 pub value : String ,
6568}
6669
70+ /// Arguments for workspace unset command.
71+ #[ derive( Debug , Parser ) ]
72+ pub struct WorkspaceUnsetArgs {
73+ /// Configuration key to remove
74+ pub key : String ,
75+ }
76+
6777/// Arguments for workspace edit command.
6878#[ derive( Debug , Parser ) ]
6979pub struct WorkspaceEditArgs {
@@ -104,6 +114,7 @@ impl WorkspaceCli {
104114 Some ( WorkspaceSubcommand :: Show ( args) ) => run_show ( args) . await ,
105115 Some ( WorkspaceSubcommand :: Init ( args) ) => run_init ( args) . await ,
106116 Some ( WorkspaceSubcommand :: Set ( args) ) => run_set ( args) . await ,
117+ Some ( WorkspaceSubcommand :: Unset ( args) ) => run_unset ( args) . await ,
107118 Some ( WorkspaceSubcommand :: Edit ( args) ) => run_edit ( args) . await ,
108119 }
109120 }
@@ -322,6 +333,19 @@ async fn run_init(args: WorkspaceInitArgs) -> Result<()> {
322333 Ok ( ( ) )
323334}
324335
336+ fn workspace_config_key ( key : & str ) -> ( & str , & str ) {
337+ match key {
338+ "model" | "default_model" => ( "model" , "default" ) ,
339+ "sandbox" | "sandbox_mode" => ( "sandbox" , "mode" ) ,
340+ "approval" | "approval_mode" => ( "approval" , "mode" ) ,
341+ k if k. contains ( '.' ) => {
342+ let parts: Vec < & str > = k. splitn ( 2 , '.' ) . collect ( ) ;
343+ ( parts[ 0 ] , parts[ 1 ] )
344+ }
345+ _ => ( "" , key) ,
346+ }
347+ }
348+
325349async fn run_set ( args : WorkspaceSetArgs ) -> Result < ( ) > {
326350 let root = find_workspace_root ( ) ;
327351 let cortex_dir = root. join ( ".cortex" ) ;
@@ -345,16 +369,7 @@ async fn run_set(args: WorkspaceSetArgs) -> Result<()> {
345369 . unwrap_or_else ( |_| toml_edit:: DocumentMut :: new ( ) ) ;
346370
347371 // Map common keys to their TOML sections
348- let ( section, actual_key) = match args. key . as_str ( ) {
349- "model" | "default_model" => ( "model" , "default" ) ,
350- "sandbox" | "sandbox_mode" => ( "sandbox" , "mode" ) ,
351- "approval" | "approval_mode" => ( "approval" , "mode" ) ,
352- k if k. contains ( '.' ) => {
353- let parts: Vec < & str > = k. splitn ( 2 , '.' ) . collect ( ) ;
354- ( parts[ 0 ] , parts[ 1 ] )
355- }
356- _ => ( "" , args. key . as_str ( ) ) ,
357- } ;
372+ let ( section, actual_key) = workspace_config_key ( & args. key ) ;
358373
359374 if section. is_empty ( ) {
360375 doc[ actual_key] = toml_edit:: value ( & args. value ) ;
@@ -373,6 +388,54 @@ async fn run_set(args: WorkspaceSetArgs) -> Result<()> {
373388 Ok ( ( ) )
374389}
375390
391+ async fn run_unset ( args : WorkspaceUnsetArgs ) -> Result < ( ) > {
392+ let root = find_workspace_root ( ) ;
393+ let cortex_dir = root. join ( ".cortex" ) ;
394+ let config_path = cortex_dir. join ( "config.toml" ) ;
395+
396+ if !config_path. exists ( ) {
397+ bail ! (
398+ "No workspace configuration file found at {}" ,
399+ config_path. display( )
400+ ) ;
401+ }
402+
403+ let content = std:: fs:: read_to_string ( & config_path) ?;
404+ let mut doc = content. parse :: < toml_edit:: DocumentMut > ( ) ?;
405+ let ( section, actual_key) = workspace_config_key ( & args. key ) ;
406+
407+ let removed = if section. is_empty ( ) {
408+ doc. as_table_mut ( ) . remove ( actual_key) . is_some ( )
409+ } else {
410+ let mut remove_empty_section = false ;
411+ let removed = if let Some ( table) = doc. get_mut ( section) . and_then ( |item| item. as_table_mut ( ) )
412+ {
413+ let removed = table. remove ( actual_key) . is_some ( ) ;
414+ remove_empty_section = removed && table. iter ( ) . next ( ) . is_none ( ) ;
415+ removed
416+ } else {
417+ false
418+ } ;
419+
420+ if remove_empty_section {
421+ doc. as_table_mut ( ) . remove ( section) ;
422+ }
423+
424+ removed
425+ } ;
426+
427+ if !removed {
428+ bail ! ( "Key '{}' not found in workspace configuration" , args. key) ;
429+ }
430+
431+ std:: fs:: write ( & config_path, doc. to_string ( ) ) ?;
432+
433+ println ! ( "Removed key: {}" , args. key) ;
434+ println ! ( "Config saved to: {}" , config_path. display( ) ) ;
435+
436+ Ok ( ( ) )
437+ }
438+
376439async fn run_edit ( args : WorkspaceEditArgs ) -> Result < ( ) > {
377440 let root = find_workspace_root ( ) ;
378441 let cortex_dir = root. join ( ".cortex" ) ;
@@ -691,6 +754,27 @@ mod tests {
691754 assert_eq ! ( args. value, "full-access" ) ;
692755 }
693756
757+ // ==========================================================================
758+ // WorkspaceUnsetArgs tests
759+ // ==========================================================================
760+
761+ #[ test]
762+ fn test_workspace_unset_args_simple_key ( ) {
763+ let args = WorkspaceUnsetArgs {
764+ key : "model" . to_string ( ) ,
765+ } ;
766+
767+ assert_eq ! ( args. key, "model" ) ;
768+ }
769+
770+ #[ test]
771+ fn test_workspace_config_key_maps_aliases ( ) {
772+ assert_eq ! ( workspace_config_key( "model" ) , ( "model" , "default" ) ) ;
773+ assert_eq ! ( workspace_config_key( "sandbox_mode" ) , ( "sandbox" , "mode" ) ) ;
774+ assert_eq ! ( workspace_config_key( "approval.mode" ) , ( "approval" , "mode" ) ) ;
775+ assert_eq ! ( workspace_config_key( "custom_key" ) , ( "" , "custom_key" ) ) ;
776+ }
777+
694778 // ==========================================================================
695779 // WorkspaceEditArgs tests
696780 // ==========================================================================
0 commit comments