code-puppy 0.0.170__py3-none-any.whl → 0.0.172__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 (66) hide show
  1. code_puppy/agent.py +10 -2
  2. code_puppy/agents/agent_creator_agent.py +0 -3
  3. code_puppy/agents/agent_qa_kitten.py +203 -0
  4. code_puppy/agents/base_agent.py +9 -0
  5. code_puppy/command_line/command_handler.py +68 -28
  6. code_puppy/command_line/mcp/add_command.py +1 -1
  7. code_puppy/command_line/mcp/base.py +1 -1
  8. code_puppy/command_line/mcp/install_command.py +1 -1
  9. code_puppy/command_line/mcp/list_command.py +1 -1
  10. code_puppy/command_line/mcp/search_command.py +1 -1
  11. code_puppy/command_line/mcp/start_all_command.py +1 -1
  12. code_puppy/command_line/mcp/status_command.py +2 -2
  13. code_puppy/command_line/mcp/stop_all_command.py +1 -1
  14. code_puppy/command_line/mcp/utils.py +1 -1
  15. code_puppy/command_line/mcp/wizard_utils.py +2 -2
  16. code_puppy/config.py +142 -12
  17. code_puppy/http_utils.py +50 -24
  18. code_puppy/{mcp → mcp_}/config_wizard.py +1 -1
  19. code_puppy/{mcp → mcp_}/examples/retry_example.py +1 -1
  20. code_puppy/{mcp → mcp_}/managed_server.py +1 -1
  21. code_puppy/{mcp → mcp_}/server_registry_catalog.py +1 -3
  22. code_puppy/message_history_processor.py +121 -125
  23. code_puppy/state_management.py +86 -127
  24. code_puppy/tools/__init__.py +103 -6
  25. code_puppy/tools/browser/__init__.py +0 -0
  26. code_puppy/tools/browser/browser_control.py +293 -0
  27. code_puppy/tools/browser/browser_interactions.py +552 -0
  28. code_puppy/tools/browser/browser_locators.py +642 -0
  29. code_puppy/tools/browser/browser_navigation.py +251 -0
  30. code_puppy/tools/browser/browser_screenshot.py +242 -0
  31. code_puppy/tools/browser/browser_scripts.py +478 -0
  32. code_puppy/tools/browser/browser_workflows.py +196 -0
  33. code_puppy/tools/browser/camoufox_manager.py +194 -0
  34. code_puppy/tools/browser/vqa_agent.py +66 -0
  35. code_puppy/tools/browser_control.py +293 -0
  36. code_puppy/tools/browser_interactions.py +552 -0
  37. code_puppy/tools/browser_locators.py +642 -0
  38. code_puppy/tools/browser_navigation.py +251 -0
  39. code_puppy/tools/browser_screenshot.py +278 -0
  40. code_puppy/tools/browser_scripts.py +478 -0
  41. code_puppy/tools/browser_workflows.py +215 -0
  42. code_puppy/tools/camoufox_manager.py +150 -0
  43. code_puppy/tools/command_runner.py +12 -7
  44. code_puppy/tools/file_operations.py +7 -7
  45. code_puppy/tui/app.py +4 -2
  46. code_puppy/tui/components/custom_widgets.py +1 -1
  47. code_puppy/tui/screens/mcp_install_wizard.py +8 -8
  48. {code_puppy-0.0.170.dist-info → code_puppy-0.0.172.dist-info}/METADATA +4 -2
  49. {code_puppy-0.0.170.dist-info → code_puppy-0.0.172.dist-info}/RECORD +66 -47
  50. /code_puppy/{mcp → mcp_}/__init__.py +0 -0
  51. /code_puppy/{mcp → mcp_}/async_lifecycle.py +0 -0
  52. /code_puppy/{mcp → mcp_}/blocking_startup.py +0 -0
  53. /code_puppy/{mcp → mcp_}/captured_stdio_server.py +0 -0
  54. /code_puppy/{mcp → mcp_}/circuit_breaker.py +0 -0
  55. /code_puppy/{mcp → mcp_}/dashboard.py +0 -0
  56. /code_puppy/{mcp → mcp_}/error_isolation.py +0 -0
  57. /code_puppy/{mcp → mcp_}/health_monitor.py +0 -0
  58. /code_puppy/{mcp → mcp_}/manager.py +0 -0
  59. /code_puppy/{mcp → mcp_}/registry.py +0 -0
  60. /code_puppy/{mcp → mcp_}/retry_manager.py +0 -0
  61. /code_puppy/{mcp → mcp_}/status_tracker.py +0 -0
  62. /code_puppy/{mcp → mcp_}/system_tools.py +0 -0
  63. {code_puppy-0.0.170.data → code_puppy-0.0.172.data}/data/code_puppy/models.json +0 -0
  64. {code_puppy-0.0.170.dist-info → code_puppy-0.0.172.dist-info}/WHEEL +0 -0
  65. {code_puppy-0.0.170.dist-info → code_puppy-0.0.172.dist-info}/entry_points.txt +0 -0
  66. {code_puppy-0.0.170.dist-info → code_puppy-0.0.172.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,150 @@
1
+ """Camoufox browser manager - privacy-focused Firefox automation."""
2
+
3
+ from typing import Optional
4
+
5
+ import camoufox
6
+ from playwright.async_api import Browser, BrowserContext, Page
7
+
8
+ from code_puppy.messaging import emit_info
9
+
10
+
11
+ class CamoufoxManager:
12
+ """Singleton browser manager for Camoufox (privacy-focused Firefox) automation."""
13
+
14
+ _instance: Optional["CamoufoxManager"] = None
15
+ _browser: Optional[Browser] = None
16
+ _context: Optional[BrowserContext] = None
17
+ _initialized: bool = False
18
+
19
+ def __new__(cls):
20
+ if cls._instance is None:
21
+ cls._instance = super().__new__(cls)
22
+ return cls._instance
23
+
24
+ def __init__(self):
25
+ # Only initialize once
26
+ if hasattr(self, "_init_done"):
27
+ return
28
+ self._init_done = True
29
+
30
+ self.headless = False
31
+ self.homepage = "https://www.google.com"
32
+ # Camoufox-specific settings
33
+ self.geoip = True # Enable GeoIP spoofing
34
+ self.block_webrtc = True # Block WebRTC for privacy
35
+ self.humanize = True # Add human-like behavior
36
+
37
+ @classmethod
38
+ def get_instance(cls) -> "CamoufoxManager":
39
+ """Get the singleton instance."""
40
+ if cls._instance is None:
41
+ cls._instance = cls()
42
+ return cls._instance
43
+
44
+ async def async_initialize(self) -> None:
45
+ """Initialize Camoufox browser."""
46
+ if self._initialized:
47
+ return
48
+
49
+ try:
50
+ emit_info("[yellow]Initializing Camoufox (privacy Firefox)...[/yellow]")
51
+
52
+ # Launch Camoufox with basic privacy settings
53
+ # Note: Many advanced features require additional packages or are handled internally
54
+ camoufox_instance = camoufox.AsyncCamoufox(
55
+ headless=self.headless,
56
+ # Only using well-supported basic options
57
+ block_webrtc=self.block_webrtc,
58
+ humanize=self.humanize,
59
+ # Let camoufox handle other privacy settings automatically
60
+ )
61
+ self._browser = await camoufox_instance.start()
62
+
63
+ # Create context (Camoufox handles most privacy settings automatically)
64
+ self._context = await self._browser.new_context(
65
+ viewport={"width": 1920, "height": 1080},
66
+ ignore_https_errors=True,
67
+ )
68
+
69
+ # Create initial page and navigate to homepage
70
+ page = await self._context.new_page()
71
+ await page.goto(self.homepage)
72
+
73
+ self._initialized = True
74
+ emit_info(
75
+ "[green]✅ Camoufox initialized successfully (privacy-focused Firefox)[/green]"
76
+ )
77
+
78
+ except Exception as e:
79
+ emit_info(f"[red]❌ Failed to initialize Camoufox: {e}[/red]")
80
+ await self._cleanup()
81
+ raise
82
+
83
+ async def get_current_page(self) -> Optional[Page]:
84
+ """Get the currently active page."""
85
+ if not self._initialized or not self._context:
86
+ await self.async_initialize()
87
+
88
+ if self._context:
89
+ pages = self._context.pages
90
+ return pages[0] if pages else None
91
+ return None
92
+
93
+ async def new_page(self, url: Optional[str] = None) -> Page:
94
+ """Create a new page and optionally navigate to URL."""
95
+ if not self._initialized:
96
+ await self.async_initialize()
97
+
98
+ page = await self._context.new_page()
99
+ if url:
100
+ await page.goto(url)
101
+ return page
102
+
103
+ async def close_page(self, page: Page) -> None:
104
+ """Close a specific page."""
105
+ await page.close()
106
+
107
+ async def get_all_pages(self) -> list[Page]:
108
+ """Get all open pages."""
109
+ if not self._context:
110
+ return []
111
+ return self._context.pages
112
+
113
+ async def _cleanup(self) -> None:
114
+ """Clean up browser resources."""
115
+ try:
116
+ if self._context:
117
+ await self._context.close()
118
+ self._context = None
119
+ if self._browser:
120
+ await self._browser.close()
121
+ self._browser = None
122
+ self._initialized = False
123
+ except Exception as e:
124
+ emit_info(f"[yellow]Warning during cleanup: {e}[/yellow]")
125
+
126
+ async def close(self) -> None:
127
+ """Close the browser and clean up resources."""
128
+ await self._cleanup()
129
+ emit_info("[yellow]Camoufox browser closed[/yellow]")
130
+
131
+ def __del__(self):
132
+ """Ensure cleanup on object destruction."""
133
+ # Note: Can't use async in __del__, so this is just a fallback
134
+ if self._initialized:
135
+ import asyncio
136
+
137
+ try:
138
+ loop = asyncio.get_event_loop()
139
+ if loop.is_running():
140
+ loop.create_task(self._cleanup())
141
+ else:
142
+ loop.run_until_complete(self._cleanup())
143
+ except:
144
+ pass # Best effort cleanup
145
+
146
+
147
+ # Convenience function for getting the singleton instance
148
+ def get_camoufox_manager() -> CamoufoxManager:
149
+ """Get the singleton CamoufoxManager instance."""
150
+ return CamoufoxManager.get_instance()
@@ -33,6 +33,7 @@ def _truncate_line(line: str) -> str:
33
33
  return line[:MAX_LINE_LENGTH] + "... [truncated]"
34
34
  return line
35
35
 
36
+
36
37
  _AWAITING_USER_INPUT = False
37
38
 
38
39
  _CONFIRMATION_LOCK = threading.Lock()
@@ -333,7 +334,7 @@ def run_shell_command_streaming(
333
334
  # Apply line length limits to stdout/stderr before returning
334
335
  truncated_stdout = [_truncate_line(line) for line in stdout_lines[-256:]]
335
336
  truncated_stderr = [_truncate_line(line) for line in stderr_lines[-256:]]
336
-
337
+
337
338
  return ShellCommandOutput(
338
339
  success=False,
339
340
  command=command,
@@ -349,7 +350,7 @@ def run_shell_command_streaming(
349
350
  # Apply line length limits to stdout/stderr before returning
350
351
  truncated_stdout = [_truncate_line(line) for line in stdout_lines[-256:]]
351
352
  truncated_stderr = [_truncate_line(line) for line in stderr_lines[-256:]]
352
-
353
+
353
354
  return ShellCommandOutput(
354
355
  success=exit_code == 0,
355
356
  command=command,
@@ -476,18 +477,22 @@ def run_shell_command(
476
477
  stdout = None
477
478
  if "stderr" not in locals():
478
479
  stderr = None
479
-
480
+
480
481
  # Apply line length limits to stdout/stderr if they exist
481
482
  truncated_stdout = None
482
483
  if stdout:
483
484
  stdout_lines = stdout.split("\n")
484
- truncated_stdout = "\n".join([_truncate_line(line) for line in stdout_lines[-256:]])
485
-
485
+ truncated_stdout = "\n".join(
486
+ [_truncate_line(line) for line in stdout_lines[-256:]]
487
+ )
488
+
486
489
  truncated_stderr = None
487
490
  if stderr:
488
491
  stderr_lines = stderr.split("\n")
489
- truncated_stderr = "\n".join([_truncate_line(line) for line in stderr_lines[-256:]])
490
-
492
+ truncated_stderr = "\n".join(
493
+ [_truncate_line(line) for line in stderr_lines[-256:]]
494
+ )
495
+
491
496
  return ShellCommandOutput(
492
497
  success=False,
493
498
  command=command,
@@ -110,8 +110,8 @@ def is_project_directory(directory):
110
110
  def _list_files(
111
111
  context: RunContext, directory: str = ".", recursive: bool = True
112
112
  ) -> ListFileOutput:
113
- import subprocess
114
113
  import shutil
114
+ import subprocess
115
115
  import sys
116
116
 
117
117
  results = []
@@ -218,7 +218,7 @@ def _list_files(
218
218
 
219
219
  # Extract relative path from the full path
220
220
  if full_path.startswith(directory):
221
- file_path = full_path[len(directory):].lstrip(os.sep)
221
+ file_path = full_path[len(directory) :].lstrip(os.sep)
222
222
  else:
223
223
  file_path = full_path
224
224
 
@@ -295,9 +295,11 @@ def _list_files(
295
295
  for entry in entries:
296
296
  full_entry_path = os.path.join(directory, entry)
297
297
  # Skip if it doesn't exist or if it's a file (since files are already listed by ripgrep)
298
- if not os.path.exists(full_entry_path) or os.path.isfile(full_entry_path):
298
+ if not os.path.exists(full_entry_path) or os.path.isfile(
299
+ full_entry_path
300
+ ):
299
301
  continue
300
-
302
+
301
303
  # For non-recursive mode, only include directories that are directly in the target directory
302
304
  if os.path.isdir(full_entry_path):
303
305
  # Create a ListedFile for the directory
@@ -373,8 +375,6 @@ def _list_files(
373
375
  dir_count = sum(1 for item in results if item.type == "directory")
374
376
  file_count = sum(1 for item in results if item.type == "file")
375
377
  total_size = sum(item.size for item in results if item.type == "file")
376
-
377
-
378
378
 
379
379
  # Build the directory header section
380
380
  dir_name = os.path.basename(directory) or directory
@@ -491,10 +491,10 @@ def _read_file(
491
491
 
492
492
 
493
493
  def _grep(context: RunContext, search_string: str, directory: str = ".") -> GrepOutput:
494
- import subprocess
495
494
  import json
496
495
  import os
497
496
  import shutil
497
+ import subprocess
498
498
  import sys
499
499
 
500
500
  directory = os.path.abspath(directory)
code_puppy/tui/app.py CHANGED
@@ -430,8 +430,10 @@ class CodePuppyTUI(App):
430
430
  else:
431
431
  # Only cancel the agent task if NO processes were killed
432
432
  self._current_worker.cancel()
433
- state_management._message_history = prune_interrupted_tool_calls(
434
- state_management.get_message_history()
433
+ state_management.set_message_history(
434
+ prune_interrupted_tool_calls(
435
+ state_management.get_message_history()
436
+ )
435
437
  )
436
438
  self.add_system_message("⚠️ Processing cancelled by user")
437
439
  # Stop spinner and clear state only when agent is actually cancelled
@@ -25,7 +25,7 @@ class CustomTextArea(TextArea):
25
25
  if event.key == "alt+enter":
26
26
  # Don't prevent default - let the binding system handle it
27
27
  return
28
-
28
+
29
29
  # Handle escape+enter manually
30
30
  if event.key == "escape+enter":
31
31
  self.action_insert_newline()
@@ -274,7 +274,7 @@ class MCPInstallWizardScreen(ModalScreen):
274
274
  counter = self.search_counter
275
275
 
276
276
  try:
277
- from code_puppy.mcp.server_registry_catalog import catalog
277
+ from code_puppy.mcp_.server_registry_catalog import catalog
278
278
 
279
279
  # Load ALL servers instead of just popular ones
280
280
  servers = catalog.servers
@@ -337,7 +337,7 @@ class MCPInstallWizardScreen(ModalScreen):
337
337
  counter = self.search_counter
338
338
 
339
339
  try:
340
- from code_puppy.mcp.server_registry_catalog import catalog
340
+ from code_puppy.mcp_.server_registry_catalog import catalog
341
341
 
342
342
  servers = catalog.search(query)
343
343
 
@@ -499,7 +499,7 @@ class MCPInstallWizardScreen(ModalScreen):
499
499
  parent.mount(Static("\n[bold cyan]System Tools:[/bold cyan]"))
500
500
 
501
501
  # Import here to avoid circular imports
502
- from code_puppy.mcp.system_tools import detector
502
+ from code_puppy.mcp_.system_tools import detector
503
503
 
504
504
  tool_status = detector.detect_tools(required_tools)
505
505
 
@@ -594,7 +594,7 @@ class MCPInstallWizardScreen(ModalScreen):
594
594
  parent.mount(Static("\n[bold magenta]Package Dependencies:[/bold magenta]"))
595
595
 
596
596
  # Import here to avoid circular imports
597
- from code_puppy.mcp.system_tools import detector
597
+ from code_puppy.mcp_.system_tools import detector
598
598
 
599
599
  package_status = detector.check_package_dependencies(packages)
600
600
 
@@ -654,8 +654,8 @@ class MCPInstallWizardScreen(ModalScreen):
654
654
  config_dict["env"][env_key] = env_vars[var_name]
655
655
 
656
656
  # Create and register the server
657
- from code_puppy.mcp import ServerConfig
658
- from code_puppy.mcp.manager import get_mcp_manager
657
+ from code_puppy.mcp_ import ServerConfig
658
+ from code_puppy.mcp_.manager import get_mcp_manager
659
659
 
660
660
  server_config = ServerConfig(
661
661
  id=server_name,
@@ -740,8 +740,8 @@ class MCPInstallWizardScreen(ModalScreen):
740
740
  server_type = config_dict.pop("type")
741
741
 
742
742
  # Create and register the server
743
- from code_puppy.mcp import ServerConfig
744
- from code_puppy.mcp.manager import get_mcp_manager
743
+ from code_puppy.mcp_ import ServerConfig
744
+ from code_puppy.mcp_.manager import get_mcp_manager
745
745
 
746
746
  server_config = ServerConfig(
747
747
  id=server_name,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.170
3
+ Version: 0.0.172
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Topic :: Software Development :: Code Generators
17
17
  Requires-Python: >=3.11
18
18
  Requires-Dist: bs4>=0.0.2
19
+ Requires-Dist: camoufox>=0.4.11
19
20
  Requires-Dist: fastapi>=0.110.0
20
21
  Requires-Dist: httpx-limiter>=0.3.0
21
22
  Requires-Dist: httpx>=0.24.1
@@ -23,8 +24,9 @@ Requires-Dist: json-repair>=0.46.2
23
24
  Requires-Dist: logfire>=0.7.1
24
25
  Requires-Dist: openai>=1.99.1
25
26
  Requires-Dist: pathspec>=0.11.0
27
+ Requires-Dist: playwright>=1.40.0
26
28
  Requires-Dist: prompt-toolkit>=3.0.38
27
- Requires-Dist: pydantic-ai>=1.0.0
29
+ Requires-Dist: pydantic-ai>=1.0.10
28
30
  Requires-Dist: pydantic>=2.4.0
29
31
  Requires-Dist: pyjwt>=2.8.0
30
32
  Requires-Dist: pytest-cov>=6.1.1
@@ -1,29 +1,30 @@
1
1
  code_puppy/__init__.py,sha256=ehbM1-wMjNmOXk_DBhhJECFyBv2dRHwwo7ucjHeM68E,107
2
2
  code_puppy/__main__.py,sha256=pDVssJOWP8A83iFkxMLY9YteHYat0EyWDQqMkKHpWp4,203
3
- code_puppy/agent.py,sha256=wCARhq7PcD38c4l83fuXm4Us_6c1TXVa0U7TnBnNPEY,8064
3
+ code_puppy/agent.py,sha256=G0eSd7RLFw0A1Jf6ZJFgtnzMD9PX9HA-QuKmbtHs4v8,8403
4
4
  code_puppy/callbacks.py,sha256=6wYB6K_fGSCkKKEFaYOYkJT45WaV5W_NhUIzcvVH_nU,5060
5
- code_puppy/config.py,sha256=J8XU0iOPtfzrkDD49b4TdrdHoQmW2kaP-25PPbGGdKU,16386
6
- code_puppy/http_utils.py,sha256=XJ1ItAW3I4zdJNzybV17Z8Y58NoFyAJEjUg7I69SXlw,8096
5
+ code_puppy/config.py,sha256=g0X-X_Wieo94k0hmwSXqpB5nPIif1H5p7Zw47A7aDmo,20651
6
+ code_puppy/http_utils.py,sha256=jnElpVNNIK-_gcqwsBYRImDGU-tYNfsLR7Gtme5CYzs,8423
7
7
  code_puppy/main.py,sha256=tYLfhUjPTJ-4S1r-pr-jSbn6kIU1iYvt2Z8lxI7zDFY,22220
8
- code_puppy/message_history_processor.py,sha256=zzeOSUC1Wpsry-z2MD6pQWk2wt1axGSOKaGR2v22_qQ,18825
8
+ code_puppy/message_history_processor.py,sha256=TsmH4L4srbk0JStaVIcLFoFqm6DVkj1yW3yyY2X_RqY,17823
9
9
  code_puppy/model_factory.py,sha256=z9vQbcGllgMwU0On8rPvzYxkygW2Uyd3NJmRzbKv-is,13759
10
10
  code_puppy/models.json,sha256=iXmLZGflnQcu2DRh4WUlgAhoXdvoxUc7KBhB8YxawXM,3088
11
11
  code_puppy/reopenable_async_client.py,sha256=4UJRaMp5np8cbef9F0zKQ7TPKOfyf5U-Kv-0zYUWDho,8274
12
12
  code_puppy/round_robin_model.py,sha256=SEN3VSwTgC5wHjx2sZsHQLPWOycf4jGwzB-EydgqkdY,5643
13
- code_puppy/state_management.py,sha256=o4mNBCPblRyVrNBH-992-1YqffgH6AKHU7iZRqgP1LI,5925
13
+ code_puppy/state_management.py,sha256=wAK8J63DHta0FQg89dn_FihW60aNU-wZI9cYv5XsfH0,4999
14
14
  code_puppy/status_display.py,sha256=F6eEAkGePDp4StM2BWj-uLLQTDGtJrf0IufzCeP1rRg,8336
15
15
  code_puppy/summarization_agent.py,sha256=kos4_YK-l_YjYRq4Fs4X5YoTUbmAcDhhPqefL-rdenI,3197
16
16
  code_puppy/version_checker.py,sha256=bjLDmgGPrl7XnYwX1u13O8uFlsfikV90PK6nbA9Z9QU,1150
17
17
  code_puppy/agents/__init__.py,sha256=SwtHGNG1GIgDBv7y3EGIXOXEWrG_Ou7fEknNgFbrHv8,594
18
18
  code_puppy/agents/agent_code_puppy.py,sha256=sbuQxLzlkMbPOyLbILbXOAHecRsxbFdQt13HJ_GEqQo,7972
19
- code_puppy/agents/agent_creator_agent.py,sha256=chxZlvvl_12ol1d9V2WF7cjE1Px9d-S6NEH3CaKg_lc,23270
19
+ code_puppy/agents/agent_creator_agent.py,sha256=eNOlJssQdyoQm1F7d-TZWcMXpkYmZ-w9WN-NDFXCgtw,23042
20
20
  code_puppy/agents/agent_manager.py,sha256=nXvro6fpX8KA-NedRoVJuhJW966trrePOrH4eAnqq40,17034
21
21
  code_puppy/agents/agent_orchestrator.json,sha256=Iqnc0p6ICoAlUTMkEsi1XXMXJi4pdxVnWZUMaih6s5o,1267
22
- code_puppy/agents/base_agent.py,sha256=XYSff6IQX9Z6C7hPVbN_YXC2xfjwd268e2jtG3ZGnVk,3450
22
+ code_puppy/agents/agent_qa_kitten.py,sha256=5PeFFSwCFlTUvP6h5bGntx0xv5NmRwBiw0HnMqY8nLI,9107
23
+ code_puppy/agents/base_agent.py,sha256=mll5s4Lsc6V-YcBJJT-oyXC50LZBGeR7xAJLBk62Zf8,3769
23
24
  code_puppy/agents/json_agent.py,sha256=y6AYE3Fx9LhmemcPzt46d7359MNnkGIjU83YBGNer2g,4533
24
25
  code_puppy/agents/runtime_manager.py,sha256=fUOBpmETo3wTyLc5wWBfGKSX1HFRQWSpuwxYAOyA-_8,10059
25
26
  code_puppy/command_line/__init__.py,sha256=y7WeRemfYppk8KVbCGeAIiTuiOszIURCDjOMZv_YRmU,45
26
- code_puppy/command_line/command_handler.py,sha256=Owf5ZFipN25XTy_wNrw7nOb22T0D0WVRxnGdB3A-4Cs,25960
27
+ code_puppy/command_line/command_handler.py,sha256=45jUScWIikVi2OgCL7LrcpWoDcrmfWv0do-y_mS4i8U,27248
27
28
  code_puppy/command_line/file_path_completion.py,sha256=gw8NpIxa6GOpczUJRyh7VNZwoXKKn-yvCqit7h2y6Gg,2931
28
29
  code_puppy/command_line/load_context_completion.py,sha256=6eZxV6Bs-EFwZjN93V8ZDZUC-6RaWxvtZk-04Wtikyw,2240
29
30
  code_puppy/command_line/meta_command_handler.py,sha256=80aK5JQOaqjt149qBmSsM02uy2Cikkee8zaQnu5u2KQ,5712
@@ -32,41 +33,41 @@ code_puppy/command_line/motd.py,sha256=PEdkp3ZnydVfvd7mNJylm8YyFNUKg9jmY6uwkA1em
32
33
  code_puppy/command_line/prompt_toolkit_completion.py,sha256=PLb1Yt_65iQI2mzPEPxPsSaRww5Ur951Qn-K-TLMCGQ,10006
33
34
  code_puppy/command_line/utils.py,sha256=7eyxDHjPjPB9wGDJQQcXV_zOsGdYsFgI0SGCetVmTqE,1251
34
35
  code_puppy/command_line/mcp/__init__.py,sha256=0-OQuwjq_pLiTVJ1_NrirVwdRerghyKs_MTZkwPC7YY,315
35
- code_puppy/command_line/mcp/add_command.py,sha256=RghGmOCjwwYJfrbLiV5UZojMA4-FNPlM04LKci0rpAw,6415
36
- code_puppy/command_line/mcp/base.py,sha256=nIDv0S5LmGuYtYjVAa9yw3NuSvldxDB17YEEvhbEL1s,889
36
+ code_puppy/command_line/mcp/add_command.py,sha256=f65ZVb_LF4y9KjAms66bPxGrxUW6EeEJCT4HrZXdkqY,6416
37
+ code_puppy/command_line/mcp/base.py,sha256=0uessGekNM37X3tLrKImkhZpgxjAoR7fqskbmkBjcf8,890
37
38
  code_puppy/command_line/mcp/handler.py,sha256=ZPWNfJEwGurNQh4KUCRRRsHXuB0kHlaGG4oLN1sFhBg,4412
38
39
  code_puppy/command_line/mcp/help_command.py,sha256=Z55-ObpUQFMdqMWAkSJkRi_v2uZhDFVxg6DcIdjVY6Q,5250
39
- code_puppy/command_line/mcp/install_command.py,sha256=AgrEp-MynkbLsrOZL54dod5jUsc0Zw_VbHcS3EFz8N4,8826
40
- code_puppy/command_line/mcp/list_command.py,sha256=9ggXgoqMyzCp9_XGMLbA0WOdIDTynRfJC0VRxnjG7uk,3178
40
+ code_puppy/command_line/mcp/install_command.py,sha256=Smp7nCDTwXplltQi2OPlUIwWdFvNEMcg-6h62EI5AhM,8827
41
+ code_puppy/command_line/mcp/list_command.py,sha256=tjxCMmK6yrmjM5L-lFY_qdL_dKTPdBZ_q0bEoAmBADg,3179
41
42
  code_puppy/command_line/mcp/logs_command.py,sha256=x_QsVGPpI5XY7RCZtiNFegc6R3csiwF_IEB_Rh2575w,4453
42
43
  code_puppy/command_line/mcp/remove_command.py,sha256=MrWmXQ9jZTq1wrohFDO3ls0a1faTHCqRZocN-ynTzh8,2753
43
44
  code_puppy/command_line/mcp/restart_command.py,sha256=-arZhayEVjTg3WErQKiBoFxbpbQcFlPXTzUI5o8AQLg,3254
44
- code_puppy/command_line/mcp/search_command.py,sha256=oBJaCMo07IQJyn4X17iP_Ek--WM61W_g_IoUjlO4qjs,4112
45
- code_puppy/command_line/mcp/start_all_command.py,sha256=Sfkx83X0KCid9lDGyVS7nfWoGvRCIgZ3JhU3aBsR6tk,4294
45
+ code_puppy/command_line/mcp/search_command.py,sha256=k4CGiNJ1MKJ1_dPHd3wlwXo899nzizSUr7PsR0V9y4Y,4113
46
+ code_puppy/command_line/mcp/start_all_command.py,sha256=9f8BPTijs7BVBQKKNXjtH3laQVuqhNyfPSgISvBUcfM,4295
46
47
  code_puppy/command_line/mcp/start_command.py,sha256=r00onOpfSSL-gtJLDOvmD-8G4RZhhmd-nv3TyIWGMUI,3350
47
- code_puppy/command_line/mcp/status_command.py,sha256=xInCR0WDUBfoIJzMYC8rzDmj_muIz7YAs-e5yoXFGEo,6638
48
- code_puppy/command_line/mcp/stop_all_command.py,sha256=-HbIE-WXzfWEMFVZhFtxf7pfeTh1F8LrzQiQyWL4R2I,3715
48
+ code_puppy/command_line/mcp/status_command.py,sha256=tQJrEDlN4DJ3n9jnKW-4kD0vL3TyUQbovb4V3nz-RsA,6640
49
+ code_puppy/command_line/mcp/stop_all_command.py,sha256=QioqCPFjIbbdT_P5tyVakB2idUD1rnlhwYXLpa-G4TI,3716
49
50
  code_puppy/command_line/mcp/stop_command.py,sha256=zuZO8pIP2Ix11LATf-cwwX3fPFIGAbRDaZ6qnfPTqLY,2594
50
51
  code_puppy/command_line/mcp/test_command.py,sha256=Pjod77DYRcA9WDZcxaCe6AUgpEXKJr42QRkxMhSjXhM,3689
51
- code_puppy/command_line/mcp/utils.py,sha256=FqaeJMPEp39suMq_R3_xb-e8zcNpw1Rcluwvdgum3Uo,3624
52
- code_puppy/command_line/mcp/wizard_utils.py,sha256=HabnT3y6EWLP6w1llRwVO_P25Wi15bYFddTM_2kxAq8,11073
53
- code_puppy/mcp/__init__.py,sha256=UZ6ZYEIN8At3Jq88ZTkrVQHswNMxHyIBz4hbOn71osk,1444
54
- code_puppy/mcp/async_lifecycle.py,sha256=pTQrwQCVgjad8EJeRTSHtIeSQRgT_8r5BeLv-1SgKog,7772
55
- code_puppy/mcp/blocking_startup.py,sha256=bgYln3j12kuHoBsoCUzCjVcTdcoSIAx8kSaOJVwUaRg,13484
56
- code_puppy/mcp/captured_stdio_server.py,sha256=ubINgtKdd5-oOLR7MRuavUqd40iQFJk2YCNtTFYeI5Q,8948
57
- code_puppy/mcp/circuit_breaker.py,sha256=a83YwXux9h4R6zBWBUrCIqtp2ffyl7JZEoK2tErG_0I,8601
58
- code_puppy/mcp/config_wizard.py,sha256=SIsm8uhDInfRYy_2W8wPIZcmoxk24680ikhMT93VuvQ,16481
59
- code_puppy/mcp/dashboard.py,sha256=y6t6trrBZU-mr8W1_29VN5DeZI8VYvOsKNz1EXxlvUg,9022
60
- code_puppy/mcp/error_isolation.py,sha256=mpPBiH17zTXPsOEAn9WmkbwQwnt4gmgiaWv87JBJbUo,12426
61
- code_puppy/mcp/health_monitor.py,sha256=n5R6EeYOYbUucUFe74qGWCU3g6Mep5UEQbLF0wbT0dU,19688
62
- code_puppy/mcp/managed_server.py,sha256=EZwWsQGxzgnjL6TGJTm58Pj6fw7kkYpLuolYQY-GbXY,14256
63
- code_puppy/mcp/manager.py,sha256=Yx9zxukdXgdPDgeJiiQPYlPae0zQPofHWB-axuoMNc8,26426
64
- code_puppy/mcp/registry.py,sha256=IvbIL-pETQ7HS7iRgsoT5j7eY8TOJXqYczSiigT2ofU,15752
65
- code_puppy/mcp/retry_manager.py,sha256=evVxbtrsHNyo8UoI7zpO-NVDegibn82RLlgN8VKewA8,10665
66
- code_puppy/mcp/server_registry_catalog.py,sha256=U0HJMgEeF8Ntq3ZWepA0Z9t8ZG82Toa9JCGBjiDAzh8,38760
67
- code_puppy/mcp/status_tracker.py,sha256=uekxrzkzIWrv3OfSVgblaPuoGFcAh_dBYwCcaHZ_CrM,12183
68
- code_puppy/mcp/system_tools.py,sha256=7_oR8k0c8YjtCcYF9g7A946oAGuKOf_i-92aJH7VmlQ,7331
69
- code_puppy/mcp/examples/retry_example.py,sha256=En3LiqECYmG00gWaa7K9L9vvGk1VJyYtKWcv3p3gzCc,7220
52
+ code_puppy/command_line/mcp/utils.py,sha256=0Wt4ttYgSlVvtusYmBLKXSkjAjcsDiUxcZQAoFLUNnE,3625
53
+ code_puppy/command_line/mcp/wizard_utils.py,sha256=mWuE5epVgCxgGoj-VGwPO_XWVkkXjegXoIJpC9LC2TM,11075
54
+ code_puppy/mcp_/__init__.py,sha256=UZ6ZYEIN8At3Jq88ZTkrVQHswNMxHyIBz4hbOn71osk,1444
55
+ code_puppy/mcp_/async_lifecycle.py,sha256=pTQrwQCVgjad8EJeRTSHtIeSQRgT_8r5BeLv-1SgKog,7772
56
+ code_puppy/mcp_/blocking_startup.py,sha256=bgYln3j12kuHoBsoCUzCjVcTdcoSIAx8kSaOJVwUaRg,13484
57
+ code_puppy/mcp_/captured_stdio_server.py,sha256=ubINgtKdd5-oOLR7MRuavUqd40iQFJk2YCNtTFYeI5Q,8948
58
+ code_puppy/mcp_/circuit_breaker.py,sha256=a83YwXux9h4R6zBWBUrCIqtp2ffyl7JZEoK2tErG_0I,8601
59
+ code_puppy/mcp_/config_wizard.py,sha256=3dQtx4D0mLYqcDP3mPznTo0l1nIchS-cOHCmnRb8qt8,16482
60
+ code_puppy/mcp_/dashboard.py,sha256=y6t6trrBZU-mr8W1_29VN5DeZI8VYvOsKNz1EXxlvUg,9022
61
+ code_puppy/mcp_/error_isolation.py,sha256=mpPBiH17zTXPsOEAn9WmkbwQwnt4gmgiaWv87JBJbUo,12426
62
+ code_puppy/mcp_/health_monitor.py,sha256=n5R6EeYOYbUucUFe74qGWCU3g6Mep5UEQbLF0wbT0dU,19688
63
+ code_puppy/mcp_/managed_server.py,sha256=7GYo7AVi-dy1E5XjJdEvmokbssywgjpIwkZzxwru-v0,14257
64
+ code_puppy/mcp_/manager.py,sha256=Yx9zxukdXgdPDgeJiiQPYlPae0zQPofHWB-axuoMNc8,26426
65
+ code_puppy/mcp_/registry.py,sha256=IvbIL-pETQ7HS7iRgsoT5j7eY8TOJXqYczSiigT2ofU,15752
66
+ code_puppy/mcp_/retry_manager.py,sha256=evVxbtrsHNyo8UoI7zpO-NVDegibn82RLlgN8VKewA8,10665
67
+ code_puppy/mcp_/server_registry_catalog.py,sha256=5H9S2IQIF9OE__tfsXmj_T8qOXceoTHH0AxLh4kAbpw,38729
68
+ code_puppy/mcp_/status_tracker.py,sha256=uekxrzkzIWrv3OfSVgblaPuoGFcAh_dBYwCcaHZ_CrM,12183
69
+ code_puppy/mcp_/system_tools.py,sha256=7_oR8k0c8YjtCcYF9g7A946oAGuKOf_i-92aJH7VmlQ,7331
70
+ code_puppy/mcp_/examples/retry_example.py,sha256=VVdSr7Jq7PPS7AVU1Ev5LnUZe2uBpdZYG7oJSo05TKM,7221
70
71
  code_puppy/messaging/__init__.py,sha256=h2eZ7nJblKF71_dNUIBj3vL5RDw7WGy8nh6T_EYVrcA,1176
71
72
  code_puppy/messaging/message_queue.py,sha256=CDVpstLee_RbCBeJWv2eON3c3qhlEISf2i9aSXJTLU4,12600
72
73
  code_puppy/messaging/queue_console.py,sha256=hf32bKfAOdAaxYuARnmDuWhq4ET77xMWDvu5_T2JggY,10912
@@ -76,21 +77,39 @@ code_puppy/messaging/spinner/console_spinner.py,sha256=DhEXjD37_FuJwcNNfIP2D0y1r
76
77
  code_puppy/messaging/spinner/spinner_base.py,sha256=474qMrTYpNfWcprFzmhaOJEOC-2rRHpTFCLsnl54bXA,1689
77
78
  code_puppy/messaging/spinner/textual_spinner.py,sha256=Omx9A-FSPkxYDMYgBXgYMBQnK-DMlyqLOgkFVG8cmo4,3465
78
79
  code_puppy/plugins/__init__.py,sha256=fksDqMUiXPJ5WNuMsYsVR8ulueQRCXPlvECEyicHPtQ,1312
79
- code_puppy/tools/__init__.py,sha256=YiiXRqxU1BEJ5t0Oe163lSqOneI9sKtwDW0swCPgBt4,2119
80
+ code_puppy/tools/__init__.py,sha256=BVTZ85jLHgDANwOnUSOz3UDlp8VQDq4DoGF23BRlyWw,6032
80
81
  code_puppy/tools/agent_tools.py,sha256=bHMrFIbYRhuubR41G_XdLsk3cUKWfIPl2O4bVzo2pE0,5591
81
- code_puppy/tools/command_runner.py,sha256=TeKbUY1BeHpUEYtBbmEXnYd4ESI-RGNXRlI-7I1UNHU,22427
82
+ code_puppy/tools/browser_control.py,sha256=6E_Kq63cErBk-iM9-03Cq8sTWWLh-Tk2kpdrB_rMmbg,8603
83
+ code_puppy/tools/browser_interactions.py,sha256=m-bVsAUbdrS-P1GbS0ChO2tMMg4tMIsDX34azn_Olzs,17070
84
+ code_puppy/tools/browser_locators.py,sha256=ZshjhYuV600vJqXUC23oNX89AZLMvY8rlvj-9oy7GMw,19574
85
+ code_puppy/tools/browser_navigation.py,sha256=Tj_fNcM3KGpkM2UTKcGQX8BpI373Sv7xZAJf-U7pO5M,7621
86
+ code_puppy/tools/browser_screenshot.py,sha256=QSwxS37G4LSo-Q9SBiuIofxWKnyInM90TY-_fiWQLrs,9222
87
+ code_puppy/tools/browser_scripts.py,sha256=BLSx1Q2F_mOOoGCoyXat3HvazTb1XaFYPXAF8CYVeX8,15071
88
+ code_puppy/tools/browser_workflows.py,sha256=4u4u59arpY65hdcDMvJGpT02vks0ufnXNJVujzKe_dg,6430
89
+ code_puppy/tools/camoufox_manager.py,sha256=bYnwyOETGDe_h8Q3kXH7w6kFr-OCpMi_Zuh4y11p__E,5097
90
+ code_puppy/tools/command_runner.py,sha256=sum09fxhHtQ0-8xBpVYyVGbQyLjscGQh0fHNYsoU09E,22424
82
91
  code_puppy/tools/common.py,sha256=pL-9xcRs3rxU7Fl9X9EUgbDp2-csh2LLJ5DHH_KAHKY,10596
83
92
  code_puppy/tools/file_modifications.py,sha256=EaDWcv6gi8wAvpgyeJdKSKPWg9fTpZoEkxQiLCE6rn4,23218
84
- code_puppy/tools/file_operations.py,sha256=dEnsGCbDF12ctegCm9Kiu-mgNCrvopf64ij_CQbikW4,32460
93
+ code_puppy/tools/file_operations.py,sha256=3RX-eqhIukle3KA-QTEaiTMIefOWy_JhmPQaijEAt6U,32481
85
94
  code_puppy/tools/tools_content.py,sha256=bsBqW-ppd1XNAS_g50B3UHDQBWEALC1UneH6-afz1zo,2365
95
+ code_puppy/tools/browser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
+ code_puppy/tools/browser/browser_control.py,sha256=6E_Kq63cErBk-iM9-03Cq8sTWWLh-Tk2kpdrB_rMmbg,8603
97
+ code_puppy/tools/browser/browser_interactions.py,sha256=m-bVsAUbdrS-P1GbS0ChO2tMMg4tMIsDX34azn_Olzs,17070
98
+ code_puppy/tools/browser/browser_locators.py,sha256=ZshjhYuV600vJqXUC23oNX89AZLMvY8rlvj-9oy7GMw,19574
99
+ code_puppy/tools/browser/browser_navigation.py,sha256=Tj_fNcM3KGpkM2UTKcGQX8BpI373Sv7xZAJf-U7pO5M,7621
100
+ code_puppy/tools/browser/browser_screenshot.py,sha256=zbOMmN9_9aVDWJkC54-3zv4OEGJMs7LpveTc6JTLcxg,8275
101
+ code_puppy/tools/browser/browser_scripts.py,sha256=BLSx1Q2F_mOOoGCoyXat3HvazTb1XaFYPXAF8CYVeX8,15071
102
+ code_puppy/tools/browser/browser_workflows.py,sha256=HZ0lPmEyAobPIWR-SK1E0ngW1OfULLqw8XILVT4N8Fg,5979
103
+ code_puppy/tools/browser/camoufox_manager.py,sha256=E1CJwQtzPFoDQiXSHHk28niWuJhk3soZ-ItxXCXWO0M,6938
104
+ code_puppy/tools/browser/vqa_agent.py,sha256=u3EhZQHNBiWUn-XLDK9MnVyd2ChshPnVZbB9iEkEqH4,2118
86
105
  code_puppy/tui/__init__.py,sha256=XesAxIn32zLPOmvpR2wIDxDAnnJr81a5pBJB4cZp1Xs,321
87
- code_puppy/tui/app.py,sha256=nPOzwlusjdWzBfu__EbC3Q0etkPrqRq-2g-mk4IcfG4,39378
106
+ code_puppy/tui/app.py,sha256=6yNOC7_93WjfwUxI6LBLmhTZl1FAXO03ErsSq5HxBVs,39434
88
107
  code_puppy/tui/messages.py,sha256=zQoToWI0eWdT36NEsY6RdCFzcDfAmfvoPlHv8jiCbgo,720
89
108
  code_puppy/tui/components/__init__.py,sha256=uj5pnk3s6SEN3SbFI0ZnzaA2KK1NNg8TfUj6U-Z732U,455
90
109
  code_puppy/tui/components/chat_view.py,sha256=NfyNXuN2idPht1rKJB4YhHVXb1AIRNO5q_nLdt8Ocug,19913
91
110
  code_puppy/tui/components/command_history_modal.py,sha256=pUPEQvoCWa2iUnuMgNwO22y8eUbyw0HpcPH3wAosHvU,7097
92
111
  code_puppy/tui/components/copy_button.py,sha256=E4-OJYk5YNzDf-E81NyiVGKsTRPrUX-RnQ8qFuVnabw,4375
93
- code_puppy/tui/components/custom_widgets.py,sha256=y-ZodibwL_GNaWntmFMn7eeC93wJNss590D43rGMO6A,2122
112
+ code_puppy/tui/components/custom_widgets.py,sha256=qsVsPLh_oUjMWBznewH8Ya1BdGSiIwNiad2qkdfvCJk,2114
94
113
  code_puppy/tui/components/human_input_modal.py,sha256=isj-zrSIcK5iy3L7HJNgDFWN1zhxY4f3zvp4krbs07E,5424
95
114
  code_puppy/tui/components/input_area.py,sha256=R4R32eXPZ2R8KFisIbldNGq60KMk7kCxWrdbeTgJUr8,4395
96
115
  code_puppy/tui/components/sidebar.py,sha256=nGtCiYzZalPmiFaJ4dwj2S4EJBu5wQZVzhoigYYY7U4,10369
@@ -101,12 +120,12 @@ code_puppy/tui/models/command_history.py,sha256=bPWr_xnyQvjG5tPg_5pwqlEzn2fR170H
101
120
  code_puppy/tui/models/enums.py,sha256=1ulsei95Gxy4r1sk-m-Sm5rdmejYCGRI-YtUwJmKFfM,501
102
121
  code_puppy/tui/screens/__init__.py,sha256=tJ00d0aYQ9kzOGHRChqy6cCQ6JUKKXBzLUTEbk_eA2Y,286
103
122
  code_puppy/tui/screens/help.py,sha256=eJuPaOOCp7ZSUlecearqsuX6caxWv7NQszUh0tZJjBM,3232
104
- code_puppy/tui/screens/mcp_install_wizard.py,sha256=xqwN5omltMkfxWZwXj3D2PbXbtrxUi1dT0XT77oxOKk,27685
123
+ code_puppy/tui/screens/mcp_install_wizard.py,sha256=vObpQwLbXjQsxmSg-WCasoev1usEi0pollKnL0SHu9U,27693
105
124
  code_puppy/tui/screens/settings.py,sha256=GMpv-qa08rorAE9mj3AjmqjZFPhmeJ_GWd-DBHG6iAA,10671
106
125
  code_puppy/tui/screens/tools.py,sha256=3pr2Xkpa9Js6Yhf1A3_wQVRzFOui-KDB82LwrsdBtyk,1715
107
- code_puppy-0.0.170.data/data/code_puppy/models.json,sha256=iXmLZGflnQcu2DRh4WUlgAhoXdvoxUc7KBhB8YxawXM,3088
108
- code_puppy-0.0.170.dist-info/METADATA,sha256=faIU-goxJPY_e6LEVisa1t8crQxk2weGEf_lLQWsBAE,20039
109
- code_puppy-0.0.170.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
110
- code_puppy-0.0.170.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
111
- code_puppy-0.0.170.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
112
- code_puppy-0.0.170.dist-info/RECORD,,
126
+ code_puppy-0.0.172.data/data/code_puppy/models.json,sha256=iXmLZGflnQcu2DRh4WUlgAhoXdvoxUc7KBhB8YxawXM,3088
127
+ code_puppy-0.0.172.dist-info/METADATA,sha256=VjpMGSIgA_Trvm70on6SEy3_9eFjgsOoakkVueRMWvA,20106
128
+ code_puppy-0.0.172.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
129
+ code_puppy-0.0.172.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
130
+ code_puppy-0.0.172.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
131
+ code_puppy-0.0.172.dist-info/RECORD,,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes