@iaforged/context-code 2.3.3 → 2.3.5

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 (70) hide show
  1. package/context-bootstrap.js +7 -5
  2. package/dist/src/commands/login/login.js +1 -1
  3. package/dist/src/components/BaseTextInput.js +1 -1
  4. package/dist/src/components/LogoV2/AnimatedClawd.js +1 -1
  5. package/dist/src/components/LogoV2/Clawd.js +1 -1
  6. package/dist/src/components/LogoV2/LogoV2.js +1 -1
  7. package/dist/src/components/LogoV2/WelcomeV2.js +1 -1
  8. package/dist/src/components/PromptInput/PromptInputFooterLeftSide.js +1 -1
  9. package/dist/src/components/SessionTokenFooter.js +1 -1
  10. package/dist/src/components/Spinner.js +1 -1
  11. package/dist/src/components/Stats.js +1 -1
  12. package/dist/src/components/TeleportProgress.js +1 -1
  13. package/dist/src/components/TextInput.js +1 -1
  14. package/dist/src/components/design-system/ThemeProvider.js +1 -1
  15. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.js +1 -1
  16. package/dist/src/main.js +1 -1
  17. package/dist/src/query/stopHooks.js +1 -1
  18. package/dist/src/screens/REPL.js +1 -1
  19. package/dist/src/services/PromptSuggestion/promptSuggestion.js +1 -1
  20. package/dist/src/services/analytics/config.js +1 -1
  21. package/dist/src/services/analytics/datadog.js +1 -1
  22. package/dist/src/services/mcp/config.js +1 -1
  23. package/dist/src/services/tips/tipRegistry.js +1 -1
  24. package/dist/src/services/toolUseSummary/toolUseSummaryGenerator.js +1 -1
  25. package/dist/src/tools/BriefTool/UI.js +1 -1
  26. package/dist/src/utils/computerControlMcp/mcpServer.js +1 -1
  27. package/dist/src/utils/computerControlMcp/server/.gitattributes +18 -0
  28. package/dist/src/utils/computerControlMcp/server/Dockerfile +25 -0
  29. package/dist/src/utils/computerControlMcp/server/LICENSE +21 -0
  30. package/dist/src/utils/computerControlMcp/server/MANIFEST.in +10 -0
  31. package/dist/src/utils/computerControlMcp/server/README.md +193 -0
  32. package/dist/src/utils/computerControlMcp/server/demonstration.gif +0 -0
  33. package/dist/src/utils/computerControlMcp/server/icon.png +0 -0
  34. package/dist/src/utils/computerControlMcp/server/pyproject.toml +52 -0
  35. package/dist/src/utils/computerControlMcp/server/smithery.yaml +13 -0
  36. package/dist/src/utils/computerControlMcp/server/src/README.md +12 -0
  37. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/FZYTK.TTF +0 -0
  38. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/__init__.py +11 -0
  39. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/__main__.py +21 -0
  40. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/cli.py +128 -0
  41. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/core.py +1008 -0
  42. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/gui.py +126 -0
  43. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/server.py +15 -0
  44. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/test.py +346 -0
  45. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/test_image.png +0 -0
  46. package/dist/src/utils/computerControlMcp/server/tests/README.md +22 -0
  47. package/dist/src/utils/computerControlMcp/server/tests/conftest.py +10 -0
  48. package/dist/src/utils/computerControlMcp/server/tests/rapidocr_test.py +21 -0
  49. package/dist/src/utils/computerControlMcp/server/tests/run_cli.py +9 -0
  50. package/dist/src/utils/computerControlMcp/server/tests/run_server.py +15 -0
  51. package/dist/src/utils/computerControlMcp/server/tests/setup.py +16 -0
  52. package/dist/src/utils/computerControlMcp/server/tests/test_computer_control.py +161 -0
  53. package/dist/src/utils/computerControlMcp/server/tests/test_screenshot.py +14 -0
  54. package/dist/src/utils/computerControlMcp/server/tests/test_wgc_env_var.py +42 -0
  55. package/dist/src/utils/computerControlMcp/server/tests/test_wgc_screenshot.py +67 -0
  56. package/dist/src/utils/computerControlMcp/server/uv.lock +4986 -0
  57. package/dist/src/utils/computerControlMcp/setup.js +1 -1
  58. package/dist/src/utils/logoV2Utils.js +1 -1
  59. package/dist/src/utils/model/configs.js +1 -1
  60. package/dist/src/utils/model/model.js +1 -1
  61. package/dist/src/utils/model/modelOptions.js +1 -1
  62. package/dist/src/utils/model/providerModels.js +1 -1
  63. package/dist/src/utils/sembleMcp/setup.js +1 -1
  64. package/dist/src/utils/theme.js +1 -1
  65. package/dist/src/utils/themes/bootstrap.js +1 -1
  66. package/dist/src/utils/themes/opencodeMapper.js +1 -1
  67. package/dist/webapp/chunk-VAB2VXFI.js +1 -1
  68. package/dist/webapp/ngsw.json +1 -1
  69. package/dist/webapp/polyfills-7R4CRVNH.js +1 -1
  70. package/package.json +1 -1
@@ -0,0 +1,161 @@
1
+ """
2
+ Tests for the Computer Control MCP package.
3
+ """
4
+
5
+ import pytest
6
+ from unittest.mock import Mock, patch
7
+ import json
8
+ import sys
9
+ import tkinter as tk
10
+ from tkinter import ttk
11
+ import asyncio
12
+ import os
13
+ import ast
14
+ from computer_control_mcp.core import mcp
15
+
16
+ # Helper function to print request/response JSON, skipping non-serializable properties
17
+ def print_json_data(name, request_data=None, response_data=None):
18
+ def serialize(obj):
19
+ try:
20
+ json.dumps(obj)
21
+ return obj
22
+ except (TypeError, OverflowError):
23
+ return str(obj)
24
+
25
+ print(f"\n===== TEST: {name} =====", file=sys.stderr)
26
+ if isinstance(request_data, dict):
27
+ serializable_request = {k: serialize(v) for k, v in request_data.items()}
28
+ print(f"REQUEST: {json.dumps(serializable_request, indent=2)}", file=sys.stderr)
29
+ elif request_data is not None:
30
+ print(f"REQUEST: {serialize(request_data)}", file=sys.stderr)
31
+ if response_data is not None:
32
+ if isinstance(response_data, dict):
33
+ serializable_response = {k: serialize(v) for k, v in response_data.items()}
34
+ print(
35
+ f"RESPONSE: {json.dumps(serializable_response, indent=2)}",
36
+ file=sys.stderr,
37
+ )
38
+ else:
39
+ print(f"RESPONSE: {serialize(response_data)}", file=sys.stderr)
40
+ print("======================\n", file=sys.stderr)
41
+
42
+
43
+ # Test drag_mouse tool
44
+ @pytest.mark.asyncio
45
+ async def test_drag_mouse():
46
+ # Test data
47
+ test_window = tk.Tk()
48
+ test_window.title("Test Drag Mouse")
49
+ test_window.geometry("400x400")
50
+
51
+ # Update the window to ensure coordinates are calculated
52
+ test_window.update_idletasks()
53
+ test_window.update()
54
+
55
+ # Window title coordinates
56
+ window_x = test_window.winfo_x()
57
+ window_y = test_window.winfo_y()
58
+
59
+ screen_width = test_window.winfo_screenwidth()
60
+ screen_height = test_window.winfo_screenheight()
61
+ center_x = screen_width // 2
62
+ center_y = screen_height // 2
63
+ request_data = {
64
+ "from_x": window_x + 55,
65
+ "from_y": window_y + 15,
66
+ "to_x": center_x,
67
+ "to_y": center_y,
68
+ "duration": 1.0,
69
+ }
70
+
71
+ print(f"starting coordinates: x={window_x}, y={window_y}", file=sys.stderr)
72
+
73
+ # Create an event to track completion
74
+ drag_complete = asyncio.Event()
75
+
76
+ async def perform_drag():
77
+ try:
78
+ result = await mcp.call_tool("drag_mouse", request_data)
79
+ print(f"Result: {result}", file=sys.stderr)
80
+ finally:
81
+ drag_complete.set()
82
+
83
+ # Start the drag operation
84
+ drag_task = asyncio.create_task(perform_drag())
85
+
86
+ # Keep updating the window while waiting for drag to complete
87
+ while not drag_complete.is_set():
88
+ test_window.update()
89
+ await asyncio.sleep(0.01) # Small delay to prevent high CPU usage
90
+
91
+ # Wait for drag operation to complete
92
+ await drag_task
93
+
94
+ window_x_end = test_window.winfo_x()
95
+ window_y_end = test_window.winfo_y()
96
+ print(f'ending coordinates: x={window_x_end}, y={window_y_end}', file=sys.stderr)
97
+
98
+ assert window_y_end != window_y and window_x_end != window_x
99
+
100
+ test_window.destroy()
101
+
102
+
103
+ # Test list_windows tool
104
+ @pytest.mark.asyncio
105
+ async def test_list_windows():
106
+ # open tkinter
107
+ test_window = tk.Tk()
108
+ test_window.title("Test Window")
109
+ test_window.geometry("400x400")
110
+
111
+ # Update the window to ensure coordinates are calculated
112
+ test_window.update_idletasks()
113
+ test_window.update()
114
+
115
+ # list all windows
116
+ result = await mcp.call_tool("list_windows", {})
117
+
118
+ # check if "Test Window" is in the list
119
+ # Parse the TextContent objects to extract the JSON data
120
+ window_data = []
121
+ for item in result:
122
+ if hasattr(item, 'text'):
123
+ try:
124
+ window_info = json.loads(item.text)
125
+ window_data.append(window_info)
126
+ except json.JSONDecodeError:
127
+ print(f"Failed to parse JSON: {item.text}", file=sys.stderr)
128
+
129
+ print(f"Result: {window_data}")
130
+
131
+ assert any(window.get("title") == "Test Window" for window in window_data)
132
+
133
+ test_window.destroy()
134
+
135
+ # Test screenshot with downloads
136
+ @pytest.mark.asyncio
137
+ async def test_take_screenshot():
138
+ # Take a screenshot of the whole screen and save to downloads
139
+ results = await mcp.call_tool("take_screenshot", {'save_to_downloads': True, 'mode': 'whole_screen'})
140
+
141
+ for result in results:
142
+ # Check if file_path is in the result
143
+ if hasattr(result, 'text'):
144
+ try:
145
+ result_dict = json.loads(result.text)
146
+ print(f"Screenshot result: {result_dict['title']}", file=sys.stderr)
147
+ assert 'file_path' in result_dict, "file_path should be in the result"
148
+ file_path = result_dict['file_path']
149
+
150
+ # Check if the file exists
151
+ assert os.path.exists(file_path), f"File {file_path} should exist"
152
+ print(f"Screenshot saved to: {file_path}", file=sys.stderr)
153
+
154
+ # Clean up - remove the file
155
+ os.remove(file_path)
156
+ print(f"Removed test file: {file_path}", file=sys.stderr)
157
+ except (ValueError, SyntaxError, AttributeError) as e:
158
+ print(f"Error processing result: {e}", file=sys.stderr)
159
+ assert False, f"Error processing result: {e}"
160
+
161
+ assert True, "Successfully tested screenshot with downloads"
@@ -0,0 +1,14 @@
1
+ import sys
2
+ sys.path.append('src')
3
+ from computer_control_mcp.core import take_screenshot
4
+
5
+ # Test with save_to_downloads=False
6
+ result = take_screenshot(mode='whole_screen', save_to_downloads=False)
7
+ print('Base64 image included:', 'base64_image' in result)
8
+ print('MCP Image included:', 'image' in result)
9
+
10
+ # Test with save_to_downloads=True
11
+ result = take_screenshot(mode='whole_screen', save_to_downloads=True)
12
+ print('Base64 image included:', 'base64_image' in result)
13
+ print('MCP Image included:', 'image' in result)
14
+ print('File path included:', 'file_path' in result)
@@ -0,0 +1,42 @@
1
+ import sys
2
+ import os
3
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
4
+
5
+ from computer_control_mcp.core import _should_use_wgc_by_default
6
+ import os
7
+
8
+ def test_wgc_env_var():
9
+ """Test the WGC environment variable pattern matching"""
10
+ print("Testing WGC environment variable pattern matching...")
11
+
12
+ # Test with no environment variable set
13
+ if 'COMPUTER_CONTROL_MCP_WGC_PATTERNS' in os.environ:
14
+ del os.environ['COMPUTER_CONTROL_MCP_WGC_PATTERNS']
15
+
16
+ result = _should_use_wgc_by_default("OBS Studio")
17
+ print(f"Without env var - 'OBS Studio': {result} (expected: False)")
18
+
19
+ # Test with environment variable set
20
+ os.environ['COMPUTER_CONTROL_MCP_WGC_PATTERNS'] = "obs, discord, game"
21
+
22
+ test_cases = [
23
+ ("OBS Studio", True),
24
+ ("Discord", True),
25
+ ("My Game", True),
26
+ ("Notepad", False),
27
+ ("Google Chrome", False),
28
+ ("obs studio", True), # Test case insensitivity
29
+ ("DISCORD APP", True), # Test case insensitivity
30
+ ]
31
+
32
+ for window_title, expected in test_cases:
33
+ result = _should_use_wgc_by_default(window_title)
34
+ status = "✓" if result == expected else "✗"
35
+ print(f"{status} '{window_title}': {result} (expected: {expected})")
36
+
37
+ # Clean up
38
+ if 'COMPUTER_CONTROL_MCP_WGC_PATTERNS' in os.environ:
39
+ del os.environ['COMPUTER_CONTROL_MCP_WGC_PATTERNS']
40
+
41
+ if __name__ == "__main__":
42
+ test_wgc_env_var()
@@ -0,0 +1,67 @@
1
+ import sys
2
+ import os
3
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
4
+
5
+ from computer_control_mcp.core import take_screenshot, _wgc_screenshot
6
+ import tempfile
7
+ import os
8
+
9
+ def test_wgc_screenshot():
10
+ """Test WGC screenshot functionality"""
11
+ print("Testing WGC screenshot functionality...")
12
+
13
+ # Test if WGC is available
14
+ try:
15
+ from windows_capture import WindowsCapture
16
+ wgc_available = True
17
+ print("Windows Graphics Capture API is available")
18
+ except ImportError:
19
+ wgc_available = False
20
+ print("Windows Graphics Capture API is not available")
21
+
22
+ if wgc_available:
23
+ # Try to capture the desktop window (usually available)
24
+ try:
25
+ # Get the first available window title
26
+ import pywinctl as gw
27
+ windows = gw.getAllWindows()
28
+ if windows:
29
+ window_title = windows[0].title
30
+ print(f"Attempting to capture window: {window_title}")
31
+
32
+ # Test the internal WGC function
33
+ result = _wgc_screenshot(window_title)
34
+ if result:
35
+ image_bytes, width, height = result
36
+ print(f"Successfully captured window: {width}x{height}")
37
+
38
+ # Save to a temporary file to verify
39
+ with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
40
+ tmp.write(image_bytes)
41
+ print(f"Saved test screenshot to: {tmp.name}")
42
+ # Clean up
43
+ os.unlink(tmp.name)
44
+ else:
45
+ print("Failed to capture window with WGC")
46
+ else:
47
+ print("No windows found to capture")
48
+ except Exception as e:
49
+ print(f"Error during WGC test: {e}")
50
+ else:
51
+ print("Skipping WGC tests as the API is not available")
52
+
53
+ def test_take_screenshot_with_wgc():
54
+ """Test take_screenshot function with WGC enabled"""
55
+ print("\nTesting take_screenshot with WGC...")
56
+
57
+ try:
58
+ # Test with WGC enabled (will fall back if not available)
59
+ result = take_screenshot(use_wgc=True)
60
+ print("take_screenshot with WGC completed")
61
+ print(f"Result type: {type(result)}")
62
+ except Exception as e:
63
+ print(f"Error in take_screenshot with WGC: {e}")
64
+
65
+ if __name__ == "__main__":
66
+ test_wgc_screenshot()
67
+ test_take_screenshot_with_wgc()