diff --git a/opc/scripts/setup/claude_integration.py b/opc/scripts/setup/claude_integration.py index 18deaf36..43e00fd0 100644 --- a/opc/scripts/setup/claude_integration.py +++ b/opc/scripts/setup/claude_integration.py @@ -812,10 +812,11 @@ def find_latest_backup(claude_dir: Path) -> Path | None: # Files to preserve during uninstall (user data accumulated since install) PRESERVE_FILES = [ - "history.jsonl", # Command history - "mcp_config.json", # MCP server configs - ".env", # API keys and settings - "projects.json", # Project configs + "history.jsonl", # Command history + "mcp_config.json", # MCP server configs + ".env", # API keys and settings + "projects.json", # Project configs + "settings.local.json", # User's custom permissions and overrides ] PRESERVE_DIRS = [ @@ -918,8 +919,8 @@ def uninstall_opc_integration( else: shutil.copy2(archived_src, dest) result["preserved"].append(name) - except Exception: - pass # Best effort + except Exception as e: + result.setdefault("preserve_warnings", []).append(f"{name}: {e}") # Build summary message msg_parts = ["Uninstalled successfully."] @@ -930,6 +931,9 @@ def uninstall_opc_integration( msg_parts.append(" No backup found (created empty .claude)") if result["preserved"]: msg_parts.append(f" Preserved user data: {', '.join(result['preserved'])}") + if result.get("preserve_warnings"): + for warning in result["preserve_warnings"]: + msg_parts.append(f" [WARN] Could not preserve {warning}") result["message"] = "\n".join(msg_parts) result["success"] = True diff --git a/opc/scripts/setup/wizard.py b/opc/scripts/setup/wizard.py index 142ddc78..1c12a6ae 100644 --- a/opc/scripts/setup/wizard.py +++ b/opc/scripts/setup/wizard.py @@ -1329,6 +1329,45 @@ async def run_uninstall_wizard() -> None: console.print(f"\n[green]SUCCESS[/green]\n{result['message']}") else: console.print(f"\n[red]FAILED[/red]\n{result['message']}") + return + + # Additional cleanup: shell config + console.print("\n[bold]Additional cleanup:[/bold]") + + # Remove CLAUDE_OPC_DIR from shell config + for shell_config in [Path.home() / ".zshrc", Path.home() / ".bashrc"]: + if shell_config.exists(): + content = shell_config.read_text() + if "CLAUDE_OPC_DIR" in content: + lines = content.splitlines() + cleaned = [ + line for line in lines + if "CLAUDE_OPC_DIR" not in line + and "Continuous-Claude OPC directory" not in line + ] + shell_config.write_text("\n".join(cleaned) + "\n") + console.print(f" [green]OK[/green] Removed CLAUDE_OPC_DIR from {shell_config.name}") + + # Offer to remove TLDR CLI + if shutil.which("tldr"): + if Confirm.ask("\n Remove TLDR CLI tool?", default=False): + import subprocess + + try: + remove_result = subprocess.run( + ["uv", "tool", "uninstall", "llm-tldr"], + capture_output=True, + text=True, + timeout=30, + ) + if remove_result.returncode == 0: + console.print(" [green]OK[/green] TLDR removed") + else: + console.print(" [yellow]WARN[/yellow] Could not remove TLDR") + console.print(" Remove manually: uv tool uninstall llm-tldr") + except (subprocess.TimeoutExpired, OSError) as e: + console.print(f" [yellow]WARN[/yellow] Could not remove TLDR: {e}") + console.print(" Remove manually: uv tool uninstall llm-tldr") async def main():