-
Notifications
You must be signed in to change notification settings - Fork 0
Dev: Summarizer #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sam43
wants to merge
7
commits into
master
Choose a base branch
from
dev
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Dev: Summarizer #21
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
df5b849
added /summerize for very project.
sam43 1e837a0
codeZ is able to summarize the project directory now in seconds
sam43 f864290
missing lib path added
sam43 eacc147
mode manager and user permission added
sam43 1d5f522
added ability to edit file and accept or reject changes while showing…
sam43 1da6e4f
`Enhanced code editing with LLM-driven changes and permission managem…
sam43 cfbb830
Merge pull request #20 from sam43/feature-code-summarizer-impl
sam43 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| """ | ||
| Mode management and permission system for automatic code editing (build mode). | ||
| Follows clean architecture and SOLID principles. | ||
| """ | ||
| from enum import Enum, auto | ||
| from typing import Dict, List, Optional, Tuple | ||
| from pathlib import Path | ||
| import difflib | ||
| import tempfile | ||
| import shutil | ||
|
|
||
| class OperationMode(Enum): | ||
| ASK = "ask" | ||
| BUILD = "build" | ||
|
|
||
| class PermissionLevel(Enum): | ||
| NONE = auto() | ||
| ONCE = auto() | ||
| ALL = auto() | ||
| GLOBAL = auto() | ||
|
|
||
| class FileChange: | ||
| def __init__(self, file_path: str, original_content: str, new_content: str, operation: str): | ||
| self.file_path = file_path | ||
| self.original_content = original_content | ||
| self.new_content = new_content | ||
| self.operation = operation # 'edit', 'create', 'delete' | ||
| self.applied = False | ||
| self.backup_path: Optional[str] = None | ||
|
|
||
| def get_diff(self) -> str: | ||
| """Return unified diff preview.""" | ||
| orig = self.original_content.splitlines(keepends=True) | ||
| new = self.new_content.splitlines(keepends=True) | ||
| diff = difflib.unified_diff( | ||
| orig, new, | ||
| fromfile=f"a/{self.file_path}", | ||
| tofile=f"b/{self.file_path}", | ||
| lineterm="" | ||
| ) | ||
| return ''.join(diff) | ||
|
|
||
| class ModeManager: | ||
| def __init__(self): | ||
| self.current_mode = OperationMode.ASK | ||
| self.permissions: Dict[str, PermissionLevel] = {} | ||
| self.pending_changes: List[FileChange] = [] | ||
| self.global_permission: Optional[PermissionLevel] = None | ||
| self.temp_dir: Optional[str] = None | ||
|
|
||
| def set_mode(self, mode: str) -> str: | ||
| try: | ||
| new_mode = OperationMode(mode.lower()) | ||
| except ValueError: | ||
| return "❌ Invalid mode. Use: /mode ask or /mode build" | ||
| if new_mode == self.current_mode: | ||
| return f"Already in {new_mode.value.upper()} mode." | ||
| self.current_mode = new_mode | ||
| if new_mode == OperationMode.BUILD: | ||
| self._init_build_mode() | ||
| return "✅ Switched to BUILD mode. I can now edit files automatically with your permission." | ||
| else: | ||
| self._cleanup_build_mode() | ||
| return "✅ Switched to ASK mode. I'll only suggest code, not edit files." | ||
|
|
||
| def _init_build_mode(self): | ||
| self.temp_dir = tempfile.mkdtemp(prefix="codez_build_") | ||
| self.pending_changes.clear() | ||
| self.permissions.clear() | ||
| self.global_permission = None | ||
|
|
||
| def _cleanup_build_mode(self): | ||
| if self.temp_dir and Path(self.temp_dir).exists(): | ||
| shutil.rmtree(self.temp_dir) | ||
| self.pending_changes.clear() | ||
| self.permissions.clear() | ||
| self.global_permission = None | ||
|
|
||
| def is_build_mode(self) -> bool: | ||
| return self.current_mode == OperationMode.BUILD | ||
|
|
||
| def can_edit_file(self, file_path: str) -> Tuple[bool, str]: | ||
| if not self.is_build_mode(): | ||
| return False, "Not in build mode." | ||
| if self.global_permission == PermissionLevel.GLOBAL: | ||
| return True, "Global permission granted." | ||
| perm = self.permissions.get(file_path, PermissionLevel.NONE) | ||
| if perm in (PermissionLevel.ALL, PermissionLevel.ONCE): | ||
| return True, f"File permission: {perm.name}" | ||
| return False, "Permission required." | ||
|
|
||
| def add_pending_change(self, change: FileChange): | ||
| self.pending_changes.append(change) | ||
|
|
||
| def request_permission_message(self, file_path: str, operation: str, diff_preview: str) -> str: | ||
| preview = diff_preview[:500] + ('...' if len(diff_preview) > 500 else '') | ||
| return ( | ||
| f"\n🔧 **BUILD MODE: Permission Required**\n\n" | ||
| f"**File**: `{file_path}`\n" | ||
| f"**Operation**: {operation}\n\n" | ||
| f"**Preview of changes**:\n" | ||
| f"```diff\n{preview}\n```\n" | ||
| "Choose your response:\n\n" | ||
| "accept once - Apply this change only\n" | ||
| "accept all - Apply this and all future changes to this file\n" | ||
| "accept global - Apply all changes to all files (until mode switch)\n" | ||
| "reject - Skip this change\n" | ||
| "show full - Show complete diff\n" | ||
| ) | ||
|
|
||
| def handle_permission_response(self, response: str, file_path: str) -> Tuple[bool, str]: | ||
| resp = response.strip().lower() | ||
| if resp == "accept once": | ||
| self.permissions[file_path] = PermissionLevel.ONCE | ||
| return True, "Accepted once." | ||
| elif resp == "accept all": | ||
| self.permissions[file_path] = PermissionLevel.ALL | ||
| return True, "Accepted all for this file." | ||
| elif resp == "accept global": | ||
| self.global_permission = PermissionLevel.GLOBAL | ||
| return True, "Accepted all for all files." | ||
| elif resp == "reject": | ||
| self.permissions[file_path] = PermissionLevel.NONE | ||
| return False, "Change rejected." | ||
| elif resp == "show full": | ||
| return False, "Show full diff." | ||
| else: | ||
| return False, "Unrecognized response." | ||
|
|
||
| def apply_change(self, change: FileChange) -> bool: | ||
| """Apply the file change if permitted.""" | ||
| if not self.can_edit_file(change.file_path)[0]: | ||
| return False | ||
| # Backup original file | ||
| file_path = Path(change.file_path) | ||
| if file_path.exists(): | ||
| backup = Path(self.temp_dir) / (file_path.name + ".bak") | ||
| shutil.copy2(file_path, backup) | ||
| change.backup_path = str(backup) | ||
| # Write new content | ||
| file_path.write_text(change.new_content, encoding="utf-8") | ||
| change.applied = True | ||
| return True | ||
|
|
||
| def revert_change(self, change: FileChange) -> bool: | ||
| """Revert a previously applied change.""" | ||
| if not change.applied or not change.backup_path: | ||
| return False | ||
| file_path = Path(change.file_path) | ||
| backup = Path(change.backup_path) | ||
| if backup.exists(): | ||
| shutil.copy2(backup, file_path) | ||
| change.applied = False | ||
| return True | ||
| return False | ||
|
|
||
| def clear_permissions(self): | ||
| self.permissions.clear() | ||
| self.global_permission = None | ||
|
|
||
| def list_pending_changes(self) -> List[FileChange]: | ||
| return self.pending_changes | ||
|
|
||
| def cleanup(self): | ||
| self._cleanup_build_mode() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for file operations.
The
apply_changemethod should handle potential exceptions when writing files, especially when the parent directory might not exist.def apply_change(self, change: FileChange) -> bool: """Apply the file change if permitted.""" if not self.can_edit_file(change.file_path)[0]: return False # Backup original file file_path = Path(change.file_path) if file_path.exists(): backup = Path(self.temp_dir) / (file_path.name + ".bak") shutil.copy2(file_path, backup) change.backup_path = str(backup) + + # Ensure parent directory exists + try: + file_path.parent.mkdir(parents=True, exist_ok=True) + except Exception: + return False + # Write new content - file_path.write_text(change.new_content, encoding="utf-8") - change.applied = True - return True + try: + file_path.write_text(change.new_content, encoding="utf-8") + change.applied = True + return True + except Exception: + # Restore from backup if write fails + if change.backup_path and Path(change.backup_path).exists(): + shutil.copy2(Path(change.backup_path), file_path) + return False📝 Committable suggestion
🤖 Prompt for AI Agents