@@ -616,42 +616,130 @@ def persist_mode_manager():
616616 persist_mode_manager ()
617617 console .print (msg )
618618 continue
619- elif cmd [0 ] == "/edit" :
619+ elif cmd [0 ] in ( "/fix" , "/add" , "/remove" ) :
620620 if not mode_manager .is_build_mode ():
621621 console .print ("[yellow]Not in build mode. Use /mode build first.[/yellow]" )
622622 continue
623- if len (cmd ) < 2 :
624- console .print ("Usage: /edit <file>" )
623+ if len (cmd ) < 3 :
624+ console .print (f "Usage: { cmd [ 0 ] } <file> <your request >" )
625625 continue
626626 file_path = cmd [1 ]
627+ user_request = " " .join (cmd [2 :])
627628 try :
628629 orig = open (file_path , encoding = "utf-8" ).read ()
629630 except Exception :
630631 orig = ""
631- console .print ("Enter new content for the file. End input with a single line containing only 'END'." )
632- lines = []
633- while True :
634- l = console .input ()
635- if l .strip () == "END" :
636- break
637- lines .append (l )
638- new_content = "\n " .join (lines )
639- change = FileChange (file_path , orig , new_content , "edit" )
632+ # --- Real LLM-driven code change ---
633+ # LLM prompt: ask for only the changed code, not markdown or code blocks
634+ llm_prompt = (
635+ f"You are an expert code editor. User request: { user_request } \n "
636+ f"Current file content:\n { orig } \n "
637+ "Respond with the new file content only, as plain text. Do NOT use markdown or code block formatting."
638+ )
639+ try :
640+ from core import model as model_mod
641+ selected_model = load_model_choice () or "deepseek-r1:latest"
642+ new_content = model_mod .query_ollama (llm_prompt , selected_model )
643+ # Remove accidental code block markers if present
644+ if new_content .strip ().startswith ("```" ):
645+ new_content = new_content .strip ().lstrip ("`python" ).strip ("`" ).strip ()
646+ except Exception as e :
647+ console .print (f"[red]LLM error: { e } . Using fallback stub.[/red]" )
648+ if cmd [0 ] == "/fix" :
649+ new_content = orig + f"\n # FIX REQUEST: { user_request } \n "
650+ elif cmd [0 ] == "/add" :
651+ new_content = orig + f"\n # ADD REQUEST: { user_request } \n "
652+ elif cmd [0 ] == "/remove" :
653+ new_content = orig + f"\n # REMOVE REQUEST: { user_request } \n "
654+ change = FileChange (file_path , orig , new_content , cmd [0 ][1 :])
640655 mode_manager .add_pending_change (change )
656+ # Enhanced diff preview with rich
657+ from rich .syntax import Syntax
658+ from rich .panel import Panel
641659 diff = change .get_diff ()
642- console .print (mode_manager .request_permission_message (file_path , "edit" , diff ))
643- resp = console .input ("Your response: " )
644- allowed , msg = mode_manager .handle_permission_response (resp , file_path )
660+ syntax = Syntax (diff , "diff" , theme = "monokai" , line_numbers = False , word_wrap = True )
661+ console .print (Panel (syntax , title = "Diff Preview" , border_style = "cyan" ))
662+ # --- Inline terminal permission menu ---
663+ options = [
664+ ("accept once" , "Accept once" ),
665+ ("accept all" , "Accept all for this file" ),
666+ ("accept global" , "Accept all for all files" ),
667+ ("reject" , "Reject this change" ),
668+ ("show full" , "Show full diff" )
669+ ]
670+ selected = 0
671+ while True :
672+ console .print ("\n [bold cyan]BUILD MODE: Permission Required[/bold cyan]" )
673+ console .print (f"File: [bold]{ file_path } [/bold] Operation: [bold]{ cmd [0 ][1 :]} [/bold]" )
674+ for idx , (val , label ) in enumerate (options ):
675+ style = "bold cyan" if idx == selected else ""
676+ prefix = "→ " if idx == selected else " "
677+ console .print (f"{ prefix } [{ val } ] " , style = style , end = "" )
678+ console .print (label , style = style )
679+ console .print ("\n Use [bold]up/down[/bold] arrows then [bold]Enter[/bold] to select." )
680+ key = console .input ("Select option (u/d/Enter): " ).strip ().lower ()
681+ if key in ("u" , "up" ) and selected > 0 :
682+ selected -= 1
683+ elif key in ("d" , "down" ) and selected < len (options ) - 1 :
684+ selected += 1
685+ elif key == "" or key == "enter" :
686+ break
687+ # Hide permission block by clearing screen section
688+ console .clear () # Optionally, use console.clear() or print blank lines
689+ result = options [selected ][0 ]
690+ allowed , msg = mode_manager .handle_permission_response (result , file_path )
691+ # --- Logging/audit trail ---
692+ import datetime
693+ with open (os .path .join (SESSION_DIR , "edit_audit.log" ), "a" ) as logf :
694+ logf .write (f"[{ datetime .datetime .now ()} ] { cmd [0 ][1 :].upper ()} { file_path } | { user_request } | { result } | { msg } \n " )
645695 console .print (msg )
696+ # Autonomous file/folder creation for test tasks
697+ import re
698+ def is_test_task (request ):
699+ return bool (re .search (r"unit test|test case|write test|add test" , request , re .I ))
700+ def get_test_file_path (src_path ):
701+ p = Path (src_path )
702+ if p .name .startswith ("test_" ):
703+ return str (p )
704+ return str (p .parent / ("test_" + p .name ))
646705 if allowed :
647- if mode_manager .apply_change (change ):
706+ # If the user request is for a test, create a test file/folder as needed
707+ if is_test_task (user_request ):
708+ test_file = get_test_file_path (file_path )
709+ test_dir = os .path .dirname (test_file )
710+ if not os .path .exists (test_dir ):
711+ os .makedirs (test_dir , exist_ok = True )
712+ with open (test_file , "w" , encoding = "utf-8" ) as f :
713+ f .write (new_content )
714+ undo_stack .append (change )
715+ persist_mode_manager ()
716+ console .print (f"[green]New test file created: { test_file } .[/green]" )
717+ with open (os .path .join (SESSION_DIR , "edit_audit.log" ), "a" ) as logf :
718+ logf .write (f"[{ datetime .datetime .now ()} ] CREATED { test_file } \n " )
719+ elif not os .path .exists (file_path ):
720+ with open (file_path , "w" , encoding = "utf-8" ) as f :
721+ f .write (new_content )
722+ undo_stack .append (change )
723+ persist_mode_manager ()
724+ console .print (f"[green]New file created: { file_path } .[/green]" )
725+ with open (os .path .join (SESSION_DIR , "edit_audit.log" ), "a" ) as logf :
726+ logf .write (f"[{ datetime .datetime .now ()} ] CREATED { file_path } \n " )
727+ elif mode_manager .apply_change (change ):
648728 undo_stack .append (change )
649729 persist_mode_manager ()
650730 console .print (f"[green]Change applied to { file_path } .[/green]" )
731+ with open (os .path .join (SESSION_DIR , "edit_audit.log" ), "a" ) as logf :
732+ logf .write (f"[{ datetime .datetime .now ()} ] APPLIED { file_path } \n " )
651733 else :
652734 console .print ("[red]Permission denied or error applying change.[/red]" )
653735 else :
654736 console .print ("[yellow]Change not applied.[/yellow]" )
737+ # LLM clarification: if the LLM output contains a special marker, prompt user for more info
738+ if "[NEED_USER_INPUT]" in new_content :
739+ clarification = console .input ("[bold yellow]LLM needs more info: Please clarify your request: [/bold yellow]" )
740+ # Re-run the command with the clarification
741+ cmd .append (clarification )
742+ continue
655743 continue
656744 elif cmd [0 ] == "/review_changes" :
657745 # List all pending changes
0 commit comments