code-puppy 0.0.287__py3-none-any.whl → 0.0.323__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. code_puppy/__init__.py +3 -1
  2. code_puppy/agents/agent_code_puppy.py +5 -4
  3. code_puppy/agents/agent_creator_agent.py +22 -18
  4. code_puppy/agents/agent_manager.py +2 -2
  5. code_puppy/agents/base_agent.py +496 -102
  6. code_puppy/callbacks.py +8 -0
  7. code_puppy/chatgpt_codex_client.py +283 -0
  8. code_puppy/cli_runner.py +795 -0
  9. code_puppy/command_line/add_model_menu.py +19 -16
  10. code_puppy/command_line/attachments.py +10 -5
  11. code_puppy/command_line/autosave_menu.py +269 -41
  12. code_puppy/command_line/colors_menu.py +515 -0
  13. code_puppy/command_line/command_handler.py +10 -24
  14. code_puppy/command_line/config_commands.py +106 -25
  15. code_puppy/command_line/core_commands.py +32 -20
  16. code_puppy/command_line/mcp/add_command.py +3 -16
  17. code_puppy/command_line/mcp/base.py +0 -3
  18. code_puppy/command_line/mcp/catalog_server_installer.py +15 -15
  19. code_puppy/command_line/mcp/custom_server_form.py +66 -5
  20. code_puppy/command_line/mcp/custom_server_installer.py +17 -17
  21. code_puppy/command_line/mcp/edit_command.py +15 -22
  22. code_puppy/command_line/mcp/handler.py +7 -2
  23. code_puppy/command_line/mcp/help_command.py +2 -2
  24. code_puppy/command_line/mcp/install_command.py +10 -14
  25. code_puppy/command_line/mcp/install_menu.py +2 -6
  26. code_puppy/command_line/mcp/list_command.py +2 -2
  27. code_puppy/command_line/mcp/logs_command.py +174 -65
  28. code_puppy/command_line/mcp/remove_command.py +2 -2
  29. code_puppy/command_line/mcp/restart_command.py +7 -2
  30. code_puppy/command_line/mcp/search_command.py +16 -10
  31. code_puppy/command_line/mcp/start_all_command.py +16 -6
  32. code_puppy/command_line/mcp/start_command.py +12 -10
  33. code_puppy/command_line/mcp/status_command.py +4 -5
  34. code_puppy/command_line/mcp/stop_all_command.py +5 -1
  35. code_puppy/command_line/mcp/stop_command.py +6 -4
  36. code_puppy/command_line/mcp/test_command.py +2 -2
  37. code_puppy/command_line/mcp/wizard_utils.py +20 -16
  38. code_puppy/command_line/model_settings_menu.py +53 -7
  39. code_puppy/command_line/motd.py +1 -1
  40. code_puppy/command_line/pin_command_completion.py +82 -7
  41. code_puppy/command_line/prompt_toolkit_completion.py +32 -9
  42. code_puppy/command_line/session_commands.py +11 -4
  43. code_puppy/config.py +217 -53
  44. code_puppy/error_logging.py +118 -0
  45. code_puppy/gemini_code_assist.py +385 -0
  46. code_puppy/keymap.py +126 -0
  47. code_puppy/main.py +5 -745
  48. code_puppy/mcp_/__init__.py +17 -0
  49. code_puppy/mcp_/blocking_startup.py +63 -36
  50. code_puppy/mcp_/captured_stdio_server.py +1 -1
  51. code_puppy/mcp_/config_wizard.py +4 -4
  52. code_puppy/mcp_/dashboard.py +15 -6
  53. code_puppy/mcp_/managed_server.py +25 -5
  54. code_puppy/mcp_/manager.py +65 -0
  55. code_puppy/mcp_/mcp_logs.py +224 -0
  56. code_puppy/mcp_/registry.py +6 -6
  57. code_puppy/messaging/__init__.py +184 -2
  58. code_puppy/messaging/bus.py +610 -0
  59. code_puppy/messaging/commands.py +167 -0
  60. code_puppy/messaging/markdown_patches.py +57 -0
  61. code_puppy/messaging/message_queue.py +3 -3
  62. code_puppy/messaging/messages.py +470 -0
  63. code_puppy/messaging/renderers.py +43 -141
  64. code_puppy/messaging/rich_renderer.py +900 -0
  65. code_puppy/messaging/spinner/console_spinner.py +39 -2
  66. code_puppy/model_factory.py +292 -53
  67. code_puppy/model_utils.py +57 -48
  68. code_puppy/models.json +19 -5
  69. code_puppy/plugins/__init__.py +152 -10
  70. code_puppy/plugins/chatgpt_oauth/config.py +20 -12
  71. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +5 -6
  72. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +3 -3
  73. code_puppy/plugins/chatgpt_oauth/test_plugin.py +30 -13
  74. code_puppy/plugins/chatgpt_oauth/utils.py +180 -65
  75. code_puppy/plugins/claude_code_oauth/config.py +15 -11
  76. code_puppy/plugins/claude_code_oauth/register_callbacks.py +28 -0
  77. code_puppy/plugins/claude_code_oauth/utils.py +6 -1
  78. code_puppy/plugins/example_custom_command/register_callbacks.py +2 -2
  79. code_puppy/plugins/oauth_puppy_html.py +3 -0
  80. code_puppy/plugins/shell_safety/agent_shell_safety.py +1 -134
  81. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  82. code_puppy/plugins/shell_safety/register_callbacks.py +77 -3
  83. code_puppy/prompts/codex_system_prompt.md +310 -0
  84. code_puppy/pydantic_patches.py +131 -0
  85. code_puppy/session_storage.py +2 -1
  86. code_puppy/status_display.py +7 -5
  87. code_puppy/terminal_utils.py +126 -0
  88. code_puppy/tools/agent_tools.py +131 -70
  89. code_puppy/tools/browser/browser_control.py +10 -14
  90. code_puppy/tools/browser/browser_interactions.py +20 -28
  91. code_puppy/tools/browser/browser_locators.py +27 -29
  92. code_puppy/tools/browser/browser_navigation.py +9 -9
  93. code_puppy/tools/browser/browser_screenshot.py +12 -14
  94. code_puppy/tools/browser/browser_scripts.py +17 -29
  95. code_puppy/tools/browser/browser_workflows.py +24 -25
  96. code_puppy/tools/browser/camoufox_manager.py +22 -26
  97. code_puppy/tools/command_runner.py +410 -88
  98. code_puppy/tools/common.py +51 -38
  99. code_puppy/tools/file_modifications.py +98 -24
  100. code_puppy/tools/file_operations.py +113 -202
  101. code_puppy/version_checker.py +28 -13
  102. {code_puppy-0.0.287.data → code_puppy-0.0.323.data}/data/code_puppy/models.json +19 -5
  103. {code_puppy-0.0.287.dist-info → code_puppy-0.0.323.dist-info}/METADATA +3 -8
  104. code_puppy-0.0.323.dist-info/RECORD +168 -0
  105. code_puppy/tui_state.py +0 -55
  106. code_puppy-0.0.287.dist-info/RECORD +0 -153
  107. {code_puppy-0.0.287.data → code_puppy-0.0.323.data}/data/code_puppy/models_dev_api.json +0 -0
  108. {code_puppy-0.0.287.dist-info → code_puppy-0.0.323.dist-info}/WHEEL +0 -0
  109. {code_puppy-0.0.287.dist-info → code_puppy-0.0.323.dist-info}/entry_points.txt +0 -0
  110. {code_puppy-0.0.287.dist-info → code_puppy-0.0.323.dist-info}/licenses/LICENSE +0 -0
@@ -4,7 +4,7 @@ from typing import Any, Dict, Optional
4
4
 
5
5
  from pydantic_ai import RunContext
6
6
 
7
- from code_puppy.messaging import emit_info
7
+ from code_puppy.messaging import emit_error, emit_info, emit_success
8
8
  from code_puppy.tools.common import generate_group_id
9
9
 
10
10
  from .camoufox_manager import get_camoufox_manager
@@ -17,7 +17,7 @@ async def execute_javascript(
17
17
  """Execute JavaScript code in the browser context."""
18
18
  group_id = generate_group_id("browser_execute_js", script[:100])
19
19
  emit_info(
20
- f"[bold white on blue] BROWSER EXECUTE JS [/bold white on blue] 📜 script='{script[:100]}{'...' if len(script) > 100 else ''}'",
20
+ f"BROWSER EXECUTE JS 📜 script='{script[:100]}{'...' if len(script) > 100 else ''}'",
21
21
  message_group=group_id,
22
22
  )
23
23
  try:
@@ -30,16 +30,12 @@ async def execute_javascript(
30
30
  # Execute JavaScript
31
31
  result = await page.evaluate(script, timeout=timeout)
32
32
 
33
- emit_info(
34
- "[green]JavaScript executed successfully[/green]", message_group=group_id
35
- )
33
+ emit_success("JavaScript executed successfully", message_group=group_id)
36
34
 
37
35
  return {"success": True, "script": script, "result": result}
38
36
 
39
37
  except Exception as e:
40
- emit_info(
41
- f"[red]JavaScript execution failed: {str(e)}[/red]", message_group=group_id
42
- )
38
+ emit_error(f"JavaScript execution failed: {str(e)}", message_group=group_id)
43
39
  return {"success": False, "error": str(e), "script": script}
44
40
 
45
41
 
@@ -52,7 +48,7 @@ async def scroll_page(
52
48
  target = element_selector or "page"
53
49
  group_id = generate_group_id("browser_scroll", f"{direction}_{amount}_{target}")
54
50
  emit_info(
55
- f"[bold white on blue] BROWSER SCROLL [/bold white on blue] 📋 direction={direction} amount={amount} target='{target}'",
51
+ f"BROWSER SCROLL 📋 direction={direction} amount={amount} target='{target}'",
56
52
  message_group=group_id,
57
53
  )
58
54
  try:
@@ -120,9 +116,7 @@ async def scroll_page(
120
116
  })
121
117
  """)
122
118
 
123
- emit_info(
124
- f"[green]Scrolled {target} {direction}[/green]", message_group=group_id
125
- )
119
+ emit_success(f"Scrolled {target} {direction}", message_group=group_id)
126
120
 
127
121
  return {
128
122
  "success": True,
@@ -148,7 +142,7 @@ async def scroll_to_element(
148
142
  """Scroll to bring an element into view."""
149
143
  group_id = generate_group_id("browser_scroll_to_element", selector[:100])
150
144
  emit_info(
151
- f"[bold white on blue] BROWSER SCROLL TO ELEMENT [/bold white on blue] 🎯 selector='{selector}'",
145
+ f"BROWSER SCROLL TO ELEMENT 🎯 selector='{selector}'",
152
146
  message_group=group_id,
153
147
  )
154
148
  try:
@@ -165,9 +159,7 @@ async def scroll_to_element(
165
159
  # Check if element is now visible
166
160
  is_visible = await element.is_visible()
167
161
 
168
- emit_info(
169
- f"[green]Scrolled to element: {selector}[/green]", message_group=group_id
170
- )
162
+ emit_success(f"Scrolled to element: {selector}", message_group=group_id)
171
163
 
172
164
  return {"success": True, "selector": selector, "visible": is_visible}
173
165
 
@@ -182,7 +174,7 @@ async def set_viewport_size(
182
174
  """Set the viewport size."""
183
175
  group_id = generate_group_id("browser_set_viewport", f"{width}x{height}")
184
176
  emit_info(
185
- f"[bold white on blue] BROWSER SET VIEWPORT [/bold white on blue] 🖥️ size={width}x{height}",
177
+ f"BROWSER SET VIEWPORT 🖥️ size={width}x{height}",
186
178
  message_group=group_id,
187
179
  )
188
180
  try:
@@ -194,8 +186,8 @@ async def set_viewport_size(
194
186
 
195
187
  await page.set_viewport_size({"width": width, "height": height})
196
188
 
197
- emit_info(
198
- f"[green]Set viewport size to {width}x{height}[/green]",
189
+ emit_success(
190
+ f"Set viewport size to {width}x{height}",
199
191
  message_group=group_id,
200
192
  )
201
193
 
@@ -213,7 +205,7 @@ async def wait_for_element(
213
205
  """Wait for an element to reach a specific state."""
214
206
  group_id = generate_group_id("browser_wait_for_element", f"{selector[:50]}_{state}")
215
207
  emit_info(
216
- f"[bold white on blue] BROWSER WAIT FOR ELEMENT [/bold white on blue] ⏱️ selector='{selector}' state={state} timeout={timeout}ms",
208
+ f"BROWSER WAIT FOR ELEMENT ⏱️ selector='{selector}' state={state} timeout={timeout}ms",
217
209
  message_group=group_id,
218
210
  )
219
211
  try:
@@ -226,9 +218,7 @@ async def wait_for_element(
226
218
  element = page.locator(selector)
227
219
  await element.wait_for(state=state, timeout=timeout)
228
220
 
229
- emit_info(
230
- f"[green]Element {selector} is now {state}[/green]", message_group=group_id
231
- )
221
+ emit_success(f"Element {selector} is now {state}", message_group=group_id)
232
222
 
233
223
  return {"success": True, "selector": selector, "state": state}
234
224
 
@@ -246,7 +236,7 @@ async def highlight_element(
246
236
  "browser_highlight_element", f"{selector[:50]}_{color}"
247
237
  )
248
238
  emit_info(
249
- f"[bold white on blue] BROWSER HIGHLIGHT ELEMENT [/bold white on blue] 🔦 selector='{selector}' color={color}",
239
+ f"BROWSER HIGHLIGHT ELEMENT 🔦 selector='{selector}' color={color}",
250
240
  message_group=group_id,
251
241
  )
252
242
  try:
@@ -271,9 +261,7 @@ async def highlight_element(
271
261
 
272
262
  await element.evaluate(highlight_script)
273
263
 
274
- emit_info(
275
- f"[green]Highlighted element: {selector}[/green]", message_group=group_id
276
- )
264
+ emit_success(f"Highlighted element: {selector}", message_group=group_id)
277
265
 
278
266
  return {"success": True, "selector": selector, "color": color}
279
267
 
@@ -285,7 +273,7 @@ async def clear_highlights() -> Dict[str, Any]:
285
273
  """Clear all element highlights."""
286
274
  group_id = generate_group_id("browser_clear_highlights")
287
275
  emit_info(
288
- "[bold white on blue] BROWSER CLEAR HIGHLIGHTS [/bold white on blue] 🧹",
276
+ "BROWSER CLEAR HIGHLIGHTS 🧹",
289
277
  message_group=group_id,
290
278
  )
291
279
  try:
@@ -311,7 +299,7 @@ async def clear_highlights() -> Dict[str, Any]:
311
299
 
312
300
  count = await page.evaluate(clear_script)
313
301
 
314
- emit_info(f"[green]Cleared {count} highlights[/green]", message_group=group_id)
302
+ emit_success(f"Cleared {count} highlights", message_group=group_id)
315
303
 
316
304
  return {"success": True, "cleared_count": count}
317
305
 
@@ -5,15 +5,16 @@ from typing import Any, Dict
5
5
 
6
6
  from pydantic_ai import RunContext
7
7
 
8
- from code_puppy.messaging import emit_info
8
+ from code_puppy import config
9
+ from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
9
10
  from code_puppy.tools.common import generate_group_id
10
11
 
11
12
 
12
13
  def get_workflows_directory() -> Path:
13
- """Get the browser workflows directory, creating it if it doesn't exist."""
14
- home_dir = Path.home()
15
- workflows_dir = home_dir / ".code_puppy" / "browser_workflows"
16
- workflows_dir.mkdir(parents=True, exist_ok=True)
14
+ """Get the browser workflows directory, creating it if it doesn't exist (uses XDG_DATA_HOME)."""
15
+ data_dir = Path(config.DATA_DIR)
16
+ workflows_dir = data_dir / "browser_workflows"
17
+ workflows_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
17
18
  return workflows_dir
18
19
 
19
20
 
@@ -21,7 +22,7 @@ async def save_workflow(name: str, content: str) -> Dict[str, Any]:
21
22
  """Save a browser workflow as a markdown file."""
22
23
  group_id = generate_group_id("save_workflow", name)
23
24
  emit_info(
24
- f"[bold white on blue] SAVE WORKFLOW [/bold white on blue] 💾 name='{name}'",
25
+ f"SAVE WORKFLOW 💾 name='{name}'",
25
26
  message_group=group_id,
26
27
  )
27
28
 
@@ -61,8 +62,8 @@ async def save_workflow(name: str, content: str) -> Dict[str, Any]:
61
62
  with open(workflow_path, "w", encoding="utf-8") as f:
62
63
  f.write(content)
63
64
 
64
- emit_info(
65
- f"[green]✅ Workflow saved successfully: {workflow_path}[/green]",
65
+ emit_success(
66
+ f"Workflow saved successfully: {workflow_path}",
66
67
  message_group=group_id,
67
68
  )
68
69
 
@@ -74,8 +75,8 @@ async def save_workflow(name: str, content: str) -> Dict[str, Any]:
74
75
  }
75
76
 
76
77
  except Exception as e:
77
- emit_info(
78
- f"[red]❌ Failed to save workflow: {e}[/red]",
78
+ emit_error(
79
+ f"Failed to save workflow: {e}",
79
80
  message_group=group_id,
80
81
  )
81
82
  return {"success": False, "error": str(e), "name": name}
@@ -85,7 +86,7 @@ async def list_workflows() -> Dict[str, Any]:
85
86
  """List all available browser workflows."""
86
87
  group_id = generate_group_id("list_workflows")
87
88
  emit_info(
88
- "[bold white on blue] LIST WORKFLOWS [/bold white on blue] 📋",
89
+ "LIST WORKFLOWS 📋",
89
90
  message_group=group_id,
90
91
  )
91
92
 
@@ -108,15 +109,13 @@ async def list_workflows() -> Dict[str, Any]:
108
109
  }
109
110
  )
110
111
  except Exception as e:
111
- emit_info(
112
- f"[yellow]Warning: Could not read {workflow_file}: {e}[/yellow]"
113
- )
112
+ emit_warning(f"Could not read {workflow_file}: {e}")
114
113
 
115
114
  # Sort by modification time (newest first)
116
115
  workflows.sort(key=lambda x: x["modified"], reverse=True)
117
116
 
118
- emit_info(
119
- f"[green]✅ Found {len(workflows)} workflow(s)[/green]",
117
+ emit_success(
118
+ f"Found {len(workflows)} workflow(s)",
120
119
  message_group=group_id,
121
120
  )
122
121
 
@@ -128,8 +127,8 @@ async def list_workflows() -> Dict[str, Any]:
128
127
  }
129
128
 
130
129
  except Exception as e:
131
- emit_info(
132
- f"[red]❌ Failed to list workflows: {e}[/red]",
130
+ emit_error(
131
+ f"Failed to list workflows: {e}",
133
132
  message_group=group_id,
134
133
  )
135
134
  return {"success": False, "error": str(e)}
@@ -139,7 +138,7 @@ async def read_workflow(name: str) -> Dict[str, Any]:
139
138
  """Read a saved browser workflow."""
140
139
  group_id = generate_group_id("read_workflow", name)
141
140
  emit_info(
142
- f"[bold white on blue] READ WORKFLOW [/bold white on blue] 📖 name='{name}'",
141
+ f"READ WORKFLOW 📖 name='{name}'",
143
142
  message_group=group_id,
144
143
  )
145
144
 
@@ -153,8 +152,8 @@ async def read_workflow(name: str) -> Dict[str, Any]:
153
152
  workflow_path = workflows_dir / name
154
153
 
155
154
  if not workflow_path.exists():
156
- emit_info(
157
- f"[red]❌ Workflow not found: {name}[/red]",
155
+ emit_error(
156
+ f"Workflow not found: {name}",
158
157
  message_group=group_id,
159
158
  )
160
159
  return {
@@ -167,8 +166,8 @@ async def read_workflow(name: str) -> Dict[str, Any]:
167
166
  with open(workflow_path, "r", encoding="utf-8") as f:
168
167
  content = f.read()
169
168
 
170
- emit_info(
171
- f"[green]✅ Workflow read successfully: {len(content)} characters[/green]",
169
+ emit_success(
170
+ f"Workflow read successfully: {len(content)} characters",
172
171
  message_group=group_id,
173
172
  )
174
173
 
@@ -181,8 +180,8 @@ async def read_workflow(name: str) -> Dict[str, Any]:
181
180
  }
182
181
 
183
182
  except Exception as e:
184
- emit_info(
185
- f"[red]❌ Failed to read workflow: {e}[/red]",
183
+ emit_error(
184
+ f"Failed to read workflow: {e}",
186
185
  message_group=group_id,
187
186
  )
188
187
  return {"success": False, "error": str(e), "name": name}
@@ -6,7 +6,8 @@ from typing import Optional
6
6
 
7
7
  from playwright.async_api import Browser, BrowserContext, Page
8
8
 
9
- from code_puppy.messaging import emit_info
9
+ from code_puppy import config
10
+ from code_puppy.messaging import emit_info, emit_success, emit_warning
10
11
 
11
12
 
12
13
  class CamoufoxManager:
@@ -48,13 +49,14 @@ class CamoufoxManager:
48
49
  return cls._instance
49
50
 
50
51
  def _get_profile_directory(self) -> Path:
51
- """Get or create the persistent profile directory.
52
+ """Get or create the persistent profile directory (uses XDG_CACHE_HOME).
52
53
 
53
- Returns a Path object pointing to ~/.code_puppy/camoufox_profile
54
+ Returns a Path object pointing to XDG_CACHE_HOME/code_puppy/camoufox_profile
54
55
  where browser data (cookies, history, bookmarks, etc.) will be stored.
55
56
  """
56
- profile_path = Path.home() / ".code_puppy" / "camoufox_profile"
57
- profile_path.mkdir(parents=True, exist_ok=True)
57
+ cache_dir = Path(config.CACHE_DIR)
58
+ profile_path = cache_dir / "camoufox_profile"
59
+ profile_path.mkdir(parents=True, exist_ok=True, mode=0o700)
58
60
  return profile_path
59
61
 
60
62
  async def async_initialize(self) -> None:
@@ -63,7 +65,7 @@ class CamoufoxManager:
63
65
  return
64
66
 
65
67
  try:
66
- emit_info("[yellow]Initializing Camoufox (privacy Firefox)...[/yellow]")
68
+ emit_info("Initializing Camoufox (privacy Firefox)...")
67
69
 
68
70
  # Ensure Camoufox binary and dependencies are fetched before launching
69
71
  await self._prefetch_camoufox()
@@ -80,7 +82,7 @@ class CamoufoxManager:
80
82
 
81
83
  async def _initialize_camoufox(self) -> None:
82
84
  """Try to start Camoufox with the configured privacy settings."""
83
- emit_info(f"[cyan]📁 Using persistent profile: {self.profile_dir}[/cyan]")
85
+ emit_info(f"Using persistent profile: {self.profile_dir}")
84
86
  # Lazy import camoufox to avoid triggering heavy optional deps at import time
85
87
  try:
86
88
  import camoufox
@@ -103,8 +105,8 @@ class CamoufoxManager:
103
105
  except Exception:
104
106
  from playwright.async_api import async_playwright
105
107
 
106
- emit_info(
107
- "[yellow]Camoufox no disponible. Usando Playwright (Chromium) como alternativa.[/yellow]"
108
+ emit_warning(
109
+ "Camoufox no disponible. Usando Playwright (Chromium) como alternativa."
108
110
  )
109
111
  pw = await async_playwright().start()
110
112
  # Use persistent context directory for Chromium to emulate previous behavior
@@ -142,9 +144,7 @@ class CamoufoxManager:
142
144
 
143
145
  async def _prefetch_camoufox(self) -> None:
144
146
  """Prefetch Camoufox binary and dependencies."""
145
- emit_info(
146
- "[cyan]🔍 Ensuring Camoufox binary and dependencies are up-to-date...[/cyan]"
147
- )
147
+ emit_info("Ensuring Camoufox binary and dependencies are up-to-date...")
148
148
 
149
149
  # Lazy import camoufox utilities to avoid side effects during module import
150
150
  try:
@@ -152,20 +152,20 @@ class CamoufoxManager:
152
152
  from camoufox.locale import ALLOW_GEOIP, download_mmdb
153
153
  from camoufox.pkgman import CamoufoxFetcher, camoufox_path
154
154
  except Exception:
155
- emit_info(
156
- "[yellow]Camoufox no disponible. Omitiendo prefetch y preparándose para usar Playwright.[/yellow]"
155
+ emit_warning(
156
+ "Camoufox no disponible. Omitiendo prefetch y preparándose para usar Playwright."
157
157
  )
158
158
  return
159
159
 
160
160
  needs_install = False
161
161
  try:
162
162
  camoufox_path(download_if_missing=False)
163
- emit_info("[cyan]🗃️ Using cached Camoufox installation[/cyan]")
163
+ emit_info("Using cached Camoufox installation")
164
164
  except (CamoufoxNotInstalled, FileNotFoundError):
165
- emit_info("[cyan]📥 Camoufox not found, installing fresh copy[/cyan]")
165
+ emit_info("Camoufox not found, installing fresh copy")
166
166
  needs_install = True
167
167
  except UnsupportedVersion:
168
- emit_info("[cyan]♻️ Camoufox update required, reinstalling[/cyan]")
168
+ emit_info("Camoufox update required, reinstalling")
169
169
  needs_install = True
170
170
 
171
171
  if needs_install:
@@ -175,7 +175,7 @@ class CamoufoxManager:
175
175
  if ALLOW_GEOIP:
176
176
  download_mmdb()
177
177
 
178
- emit_info("[cyan]📦 Camoufox dependencies ready[/cyan]")
178
+ emit_info("Camoufox dependencies ready")
179
179
 
180
180
  async def close_page(self, page: Page) -> None:
181
181
  """Close a specific page."""
@@ -195,13 +195,9 @@ class CamoufoxManager:
195
195
  try:
196
196
  storage_state_path = self.profile_dir / "storage_state.json"
197
197
  await self._context.storage_state(path=str(storage_state_path))
198
- emit_info(
199
- f"[green]💾 Browser state saved to {storage_state_path}[/green]"
200
- )
198
+ emit_success(f"Browser state saved to {storage_state_path}")
201
199
  except Exception as e:
202
- emit_info(
203
- f"[yellow]Warning: Could not save storage state: {e}[/yellow]"
204
- )
200
+ emit_warning(f"Could not save storage state: {e}")
205
201
 
206
202
  await self._context.close()
207
203
  self._context = None
@@ -210,12 +206,12 @@ class CamoufoxManager:
210
206
  self._browser = None
211
207
  self._initialized = False
212
208
  except Exception as e:
213
- emit_info(f"[yellow]Warning during cleanup: {e}[/yellow]")
209
+ emit_warning(f"Warning during cleanup: {e}")
214
210
 
215
211
  async def close(self) -> None:
216
212
  """Close the browser and clean up resources."""
217
213
  await self._cleanup()
218
- emit_info("[yellow]Camoufox browser closed[/yellow]")
214
+ emit_info("Camoufox browser closed")
219
215
 
220
216
  def __del__(self):
221
217
  """Ensure cleanup on object destruction."""