cua-computer 0.2.9__py3-none-any.whl → 0.2.10__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.
computer/computer.py CHANGED
@@ -181,24 +181,25 @@ class Computer:
181
181
  self.logger.debug("Telemetry disabled - skipping initialization tracking")
182
182
 
183
183
  async def __aenter__(self):
184
- """Enter async context manager."""
184
+ """Start the computer."""
185
+ await self.run()
185
186
  return self
186
187
 
187
188
  async def __aexit__(self, exc_type, exc_val, exc_tb):
188
- """Exit async context manager."""
189
- pass
189
+ """Stop the computer."""
190
+ await self.disconnect()
190
191
 
191
192
  def __enter__(self):
192
- """Enter synchronous context manager."""
193
- # Run the event loop to call the async run method
193
+ """Start the computer."""
194
+ # Run the event loop to call the async enter method
194
195
  loop = asyncio.get_event_loop()
195
- loop.run_until_complete(self.run())
196
+ loop.run_until_complete(self.__aenter__())
196
197
  return self
197
198
 
198
199
  def __exit__(self, exc_type, exc_val, exc_tb):
199
- """Exit synchronous context manager."""
200
- # We could add cleanup here if needed in the future
201
- pass
200
+ """Stop the computer."""
201
+ loop = asyncio.get_event_loop()
202
+ loop.run_until_complete(self.__aexit__(exc_type, exc_val, exc_tb))
202
203
 
203
204
  async def run(self) -> Optional[str]:
204
205
  """Initialize the VM and computer interface."""
@@ -473,9 +474,14 @@ class Computer:
473
474
  duration_ms = (time.time() - start_time) * 1000
474
475
  self.logger.debug(f"Computer initialization took {duration_ms:.2f}ms")
475
476
  return
477
+
478
+ async def disconnect(self) -> None:
479
+ """Disconnect from the computer's WebSocket interface."""
480
+ if self._interface:
481
+ self._interface.close()
476
482
 
477
483
  async def stop(self) -> None:
478
- """Stop computer control."""
484
+ """Disconnect from the computer's WebSocket interface and stop the computer."""
479
485
  start_time = time.time()
480
486
 
481
487
  try:
@@ -496,6 +502,7 @@ class Computer:
496
502
  await self.config.vm_provider.__aexit__(None, None, None)
497
503
  self._provider_context = None
498
504
 
505
+ await self.disconnect()
499
506
  self.logger.info("Computer stopped")
500
507
  except Exception as e:
501
508
  self.logger.debug(f"Error during cleanup: {e}") # Log as debug since this might be expected
@@ -3,6 +3,7 @@
3
3
  from abc import ABC, abstractmethod
4
4
  from typing import Optional, Dict, Any, Tuple, List
5
5
  from ..logger import Logger, LogLevel
6
+ from .models import MouseButton
6
7
 
7
8
 
8
9
  class BaseComputerInterface(ABC):
@@ -51,6 +52,16 @@ class BaseComputerInterface(ABC):
51
52
  self.close()
52
53
 
53
54
  # Mouse Actions
55
+ @abstractmethod
56
+ async def mouse_down(self, x: Optional[int] = None, y: Optional[int] = None, button: "MouseButton" = "left") -> None:
57
+ """Press and hold a mouse button."""
58
+ pass
59
+
60
+ @abstractmethod
61
+ async def mouse_up(self, x: Optional[int] = None, y: Optional[int] = None, button: "MouseButton" = "left") -> None:
62
+ """Release a mouse button."""
63
+ pass
64
+
54
65
  @abstractmethod
55
66
  async def left_click(self, x: Optional[int] = None, y: Optional[int] = None) -> None:
56
67
  """Perform a left click."""
@@ -95,6 +106,16 @@ class BaseComputerInterface(ABC):
95
106
  pass
96
107
 
97
108
  # Keyboard Actions
109
+ @abstractmethod
110
+ async def key_down(self, key: str) -> None:
111
+ """Press and hold a key."""
112
+ pass
113
+
114
+ @abstractmethod
115
+ async def key_up(self, key: str) -> None:
116
+ """Release a key."""
117
+ pass
118
+
98
119
  @abstractmethod
99
120
  async def type_text(self, text: str) -> None:
100
121
  """Type the specified text."""
@@ -111,6 +132,11 @@ class BaseComputerInterface(ABC):
111
132
  pass
112
133
 
113
134
  # Scrolling Actions
135
+ @abstractmethod
136
+ async def scroll(self, x: int, y: int) -> None:
137
+ """Scroll the mouse wheel."""
138
+ pass
139
+
114
140
  @abstractmethod
115
141
  async def scroll_down(self, clicks: int = 1) -> None:
116
142
  """Scroll down."""
@@ -166,7 +192,47 @@ class BaseComputerInterface(ABC):
166
192
  async def directory_exists(self, path: str) -> bool:
167
193
  """Check if directory exists."""
168
194
  pass
169
-
195
+
196
+ @abstractmethod
197
+ async def list_dir(self, path: str) -> List[str]:
198
+ """List directory contents."""
199
+ pass
200
+
201
+ @abstractmethod
202
+ async def read_text(self, path: str) -> str:
203
+ """Read file text contents."""
204
+ pass
205
+
206
+ @abstractmethod
207
+ async def write_text(self, path: str, content: str) -> None:
208
+ """Write file text contents."""
209
+ pass
210
+
211
+ @abstractmethod
212
+ async def read_bytes(self, path: str) -> bytes:
213
+ """Read file binary contents."""
214
+ pass
215
+
216
+ @abstractmethod
217
+ async def write_bytes(self, path: str, content: bytes) -> None:
218
+ """Write file binary contents."""
219
+ pass
220
+
221
+ @abstractmethod
222
+ async def delete_file(self, path: str) -> None:
223
+ """Delete file."""
224
+ pass
225
+
226
+ @abstractmethod
227
+ async def create_dir(self, path: str) -> None:
228
+ """Create directory."""
229
+ pass
230
+
231
+ @abstractmethod
232
+ async def delete_dir(self, path: str) -> None:
233
+ """Delete directory."""
234
+ pass
235
+
170
236
  @abstractmethod
171
237
  async def run_command(self, command: str) -> Tuple[str, str]:
172
238
  """Run shell command."""
@@ -8,8 +8,8 @@ import websockets
8
8
 
9
9
  from ..logger import Logger, LogLevel
10
10
  from .base import BaseComputerInterface
11
- from ..utils import decode_base64_image, bytes_to_image, draw_box, resize_image
12
- from .models import Key, KeyType
11
+ from ..utils import decode_base64_image, encode_base64_image, bytes_to_image, draw_box, resize_image
12
+ from .models import Key, KeyType, MouseButton
13
13
 
14
14
 
15
15
  class LinuxComputerInterface(BaseComputerInterface):
@@ -22,7 +22,7 @@ class LinuxComputerInterface(BaseComputerInterface):
22
22
  self._closed = False
23
23
  self._last_ping = 0
24
24
  self._ping_interval = 5 # Send ping every 5 seconds
25
- self._ping_timeout = 10 # Wait 10 seconds for pong response
25
+ self._ping_timeout = 120 # Wait 120 seconds for pong response
26
26
  self._reconnect_delay = 1 # Start with 1 second delay
27
27
  self._max_reconnect_delay = 30 # Maximum delay between reconnection attempts
28
28
  self._log_connection_attempts = True # Flag to control connection attempt logging
@@ -87,7 +87,7 @@ class LinuxComputerInterface(BaseComputerInterface):
87
87
  close_timeout=5,
88
88
  compression=None, # Disable compression to reduce overhead
89
89
  ),
90
- timeout=30,
90
+ timeout=120,
91
91
  )
92
92
  self.logger.info("WebSocket connection established")
93
93
 
@@ -349,6 +349,12 @@ class LinuxComputerInterface(BaseComputerInterface):
349
349
  self._ws = None
350
350
 
351
351
  # Mouse Actions
352
+ async def mouse_down(self, x: Optional[int] = None, y: Optional[int] = None, button: str = "left") -> None:
353
+ await self._send_command("mouse_down", {"x": x, "y": y, "button": button})
354
+
355
+ async def mouse_up(self, x: Optional[int] = None, y: Optional[int] = None, button: str = "left") -> None:
356
+ await self._send_command("mouse_up", {"x": x, "y": y, "button": button})
357
+
352
358
  async def left_click(self, x: Optional[int] = None, y: Optional[int] = None) -> None:
353
359
  await self._send_command("left_click", {"x": x, "y": y})
354
360
 
@@ -361,17 +367,23 @@ class LinuxComputerInterface(BaseComputerInterface):
361
367
  async def move_cursor(self, x: int, y: int) -> None:
362
368
  await self._send_command("move_cursor", {"x": x, "y": y})
363
369
 
364
- async def drag_to(self, x: int, y: int, button: str = "left", duration: float = 0.5) -> None:
370
+ async def drag_to(self, x: int, y: int, button: "MouseButton" = "left", duration: float = 0.5) -> None:
365
371
  await self._send_command(
366
372
  "drag_to", {"x": x, "y": y, "button": button, "duration": duration}
367
373
  )
368
374
 
369
- async def drag(self, path: List[Tuple[int, int]], button: str = "left", duration: float = 0.5) -> None:
375
+ async def drag(self, path: List[Tuple[int, int]], button: "MouseButton" = "left", duration: float = 0.5) -> None:
370
376
  await self._send_command(
371
377
  "drag", {"path": path, "button": button, "duration": duration}
372
378
  )
373
379
 
374
380
  # Keyboard Actions
381
+ async def key_down(self, key: "KeyType") -> None:
382
+ await self._send_command("key_down", {"key": key})
383
+
384
+ async def key_up(self, key: "KeyType") -> None:
385
+ await self._send_command("key_up", {"key": key})
386
+
375
387
  async def type_text(self, text: str) -> None:
376
388
  # Temporary fix for https://github.com/trycua/cua/issues/165
377
389
  # Check if text contains Unicode characters
@@ -464,6 +476,9 @@ class LinuxComputerInterface(BaseComputerInterface):
464
476
  await self._send_command("hotkey", {"keys": actual_keys})
465
477
 
466
478
  # Scrolling Actions
479
+ async def scroll(self, x: int, y: int) -> None:
480
+ await self._send_command("scroll", {"x": x, "y": y})
481
+
467
482
  async def scroll_down(self, clicks: int = 1) -> None:
468
483
  await self._send_command("scroll_down", {"clicks": clicks})
469
484
 
@@ -557,6 +572,50 @@ class LinuxComputerInterface(BaseComputerInterface):
557
572
  result = await self._send_command("directory_exists", {"path": path})
558
573
  return result.get("exists", False)
559
574
 
575
+ async def list_dir(self, path: str) -> list[str]:
576
+ result = await self._send_command("list_dir", {"path": path})
577
+ if not result.get("success", False):
578
+ raise RuntimeError(result.get("error", "Failed to list directory"))
579
+ return result.get("files", [])
580
+
581
+ async def read_text(self, path: str) -> str:
582
+ result = await self._send_command("read_text", {"path": path})
583
+ if not result.get("success", False):
584
+ raise RuntimeError(result.get("error", "Failed to read file"))
585
+ return result.get("content", "")
586
+
587
+ async def write_text(self, path: str, content: str) -> None:
588
+ result = await self._send_command("write_text", {"path": path, "content": content})
589
+ if not result.get("success", False):
590
+ raise RuntimeError(result.get("error", "Failed to write file"))
591
+
592
+ async def read_bytes(self, path: str) -> bytes:
593
+ result = await self._send_command("read_bytes", {"path": path})
594
+ if not result.get("success", False):
595
+ raise RuntimeError(result.get("error", "Failed to read file"))
596
+ content_b64 = result.get("content_b64", "")
597
+ return decode_base64_image(content_b64)
598
+
599
+ async def write_bytes(self, path: str, content: bytes) -> None:
600
+ result = await self._send_command("write_bytes", {"path": path, "content_b64": encode_base64_image(content)})
601
+ if not result.get("success", False):
602
+ raise RuntimeError(result.get("error", "Failed to write file"))
603
+
604
+ async def delete_file(self, path: str) -> None:
605
+ result = await self._send_command("delete_file", {"path": path})
606
+ if not result.get("success", False):
607
+ raise RuntimeError(result.get("error", "Failed to delete file"))
608
+
609
+ async def create_dir(self, path: str) -> None:
610
+ result = await self._send_command("create_dir", {"path": path})
611
+ if not result.get("success", False):
612
+ raise RuntimeError(result.get("error", "Failed to create directory"))
613
+
614
+ async def delete_dir(self, path: str) -> None:
615
+ result = await self._send_command("delete_dir", {"path": path})
616
+ if not result.get("success", False):
617
+ raise RuntimeError(result.get("error", "Failed to delete directory"))
618
+
560
619
  async def run_command(self, command: str) -> Tuple[str, str]:
561
620
  result = await self._send_command("run_command", {"command": command})
562
621
  if not result.get("success", False):
@@ -8,8 +8,8 @@ import websockets
8
8
 
9
9
  from ..logger import Logger, LogLevel
10
10
  from .base import BaseComputerInterface
11
- from ..utils import decode_base64_image, bytes_to_image, draw_box, resize_image
12
- from .models import Key, KeyType
11
+ from ..utils import decode_base64_image, encode_base64_image, bytes_to_image, draw_box, resize_image
12
+ from .models import Key, KeyType, MouseButton
13
13
 
14
14
 
15
15
  class MacOSComputerInterface(BaseComputerInterface):
@@ -22,7 +22,7 @@ class MacOSComputerInterface(BaseComputerInterface):
22
22
  self._closed = False
23
23
  self._last_ping = 0
24
24
  self._ping_interval = 5 # Send ping every 5 seconds
25
- self._ping_timeout = 10 # Wait 10 seconds for pong response
25
+ self._ping_timeout = 120 # Wait 120 seconds for pong response
26
26
  self._reconnect_delay = 1 # Start with 1 second delay
27
27
  self._max_reconnect_delay = 30 # Maximum delay between reconnection attempts
28
28
  self._log_connection_attempts = True # Flag to control connection attempt logging
@@ -86,7 +86,7 @@ class MacOSComputerInterface(BaseComputerInterface):
86
86
  close_timeout=5,
87
87
  compression=None, # Disable compression to reduce overhead
88
88
  ),
89
- timeout=30,
89
+ timeout=120,
90
90
  )
91
91
  self.logger.info("WebSocket connection established")
92
92
 
@@ -231,7 +231,7 @@ class MacOSComputerInterface(BaseComputerInterface):
231
231
 
232
232
  message = {"command": command, "params": params or {}}
233
233
  await self._ws.send(json.dumps(message))
234
- response = await asyncio.wait_for(self._ws.recv(), timeout=30)
234
+ response = await asyncio.wait_for(self._ws.recv(), timeout=120)
235
235
  self.logger.debug(f"Completed command: {command}")
236
236
  return json.loads(response)
237
237
  except Exception as e:
@@ -356,6 +356,12 @@ class MacOSComputerInterface(BaseComputerInterface):
356
356
  return await self._send_command("diorama_cmd", {"action": action, "arguments": arguments or {}})
357
357
 
358
358
  # Mouse Actions
359
+ async def mouse_down(self, x: Optional[int] = None, y: Optional[int] = None, button: "MouseButton" = "left") -> None:
360
+ await self._send_command("mouse_down", {"x": x, "y": y, "button": button})
361
+
362
+ async def mouse_up(self, x: Optional[int] = None, y: Optional[int] = None, button: "MouseButton" = "left") -> None:
363
+ await self._send_command("mouse_up", {"x": x, "y": y, "button": button})
364
+
359
365
  async def left_click(self, x: Optional[int] = None, y: Optional[int] = None) -> None:
360
366
  await self._send_command("left_click", {"x": x, "y": y})
361
367
 
@@ -379,6 +385,12 @@ class MacOSComputerInterface(BaseComputerInterface):
379
385
  )
380
386
 
381
387
  # Keyboard Actions
388
+ async def key_down(self, key: "KeyType") -> None:
389
+ await self._send_command("key_down", {"key": key})
390
+
391
+ async def key_up(self, key: "KeyType") -> None:
392
+ await self._send_command("key_up", {"key": key})
393
+
382
394
  async def type_text(self, text: str) -> None:
383
395
  # Temporary fix for https://github.com/trycua/cua/issues/165
384
396
  # Check if text contains Unicode characters
@@ -471,6 +483,9 @@ class MacOSComputerInterface(BaseComputerInterface):
471
483
  await self._send_command("hotkey", {"keys": actual_keys})
472
484
 
473
485
  # Scrolling Actions
486
+ async def scroll(self, x: int, y: int) -> None:
487
+ await self._send_command("scroll", {"x": x, "y": y})
488
+
474
489
  async def scroll_down(self, clicks: int = 1) -> None:
475
490
  await self._send_command("scroll_down", {"clicks": clicks})
476
491
 
@@ -564,6 +579,50 @@ class MacOSComputerInterface(BaseComputerInterface):
564
579
  result = await self._send_command("directory_exists", {"path": path})
565
580
  return result.get("exists", False)
566
581
 
582
+ async def list_dir(self, path: str) -> list[str]:
583
+ result = await self._send_command("list_dir", {"path": path})
584
+ if not result.get("success", False):
585
+ raise RuntimeError(result.get("error", "Failed to list directory"))
586
+ return result.get("files", [])
587
+
588
+ async def read_text(self, path: str) -> str:
589
+ result = await self._send_command("read_text", {"path": path})
590
+ if not result.get("success", False):
591
+ raise RuntimeError(result.get("error", "Failed to read file"))
592
+ return result.get("content", "")
593
+
594
+ async def write_text(self, path: str, content: str) -> None:
595
+ result = await self._send_command("write_text", {"path": path, "content": content})
596
+ if not result.get("success", False):
597
+ raise RuntimeError(result.get("error", "Failed to write file"))
598
+
599
+ async def read_bytes(self, path: str) -> bytes:
600
+ result = await self._send_command("read_bytes", {"path": path})
601
+ if not result.get("success", False):
602
+ raise RuntimeError(result.get("error", "Failed to read file"))
603
+ content_b64 = result.get("content_b64", "")
604
+ return decode_base64_image(content_b64)
605
+
606
+ async def write_bytes(self, path: str, content: bytes) -> None:
607
+ result = await self._send_command("write_bytes", {"path": path, "content_b64": encode_base64_image(content)})
608
+ if not result.get("success", False):
609
+ raise RuntimeError(result.get("error", "Failed to write file"))
610
+
611
+ async def delete_file(self, path: str) -> None:
612
+ result = await self._send_command("delete_file", {"path": path})
613
+ if not result.get("success", False):
614
+ raise RuntimeError(result.get("error", "Failed to delete file"))
615
+
616
+ async def create_dir(self, path: str) -> None:
617
+ result = await self._send_command("create_dir", {"path": path})
618
+ if not result.get("success", False):
619
+ raise RuntimeError(result.get("error", "Failed to create directory"))
620
+
621
+ async def delete_dir(self, path: str) -> None:
622
+ result = await self._send_command("delete_dir", {"path": path})
623
+ if not result.get("success", False):
624
+ raise RuntimeError(result.get("error", "Failed to delete directory"))
625
+
567
626
  async def run_command(self, command: str) -> Tuple[str, str]:
568
627
  result = await self._send_command("run_command", {"command": command})
569
628
  if not result.get("success", False):
@@ -106,6 +106,9 @@ class Key(Enum):
106
106
  # Combined key type
107
107
  KeyType = Union[Key, NavigationKey, SpecialKey, ModifierKey, FunctionKey, str]
108
108
 
109
+ # Key type for mouse actions
110
+ MouseButton = Literal['left', 'right', 'middle']
111
+
109
112
  class AccessibilityWindow(TypedDict):
110
113
  """Information about a window in the accessibility tree."""
111
114
  app_name: str
@@ -52,11 +52,11 @@ class CloudProvider(BaseVMProvider):
52
52
  return []
53
53
 
54
54
  async def run_vm(self, image: str, name: str, run_opts: Dict[str, Any], storage: Optional[str] = None) -> Dict[str, Any]:
55
- logger.warning("CloudProvider.run_vm is not implemented")
56
- return {"name": name, "status": "unavailable", "message": "CloudProvider is not implemented"}
55
+ # logger.warning("CloudProvider.run_vm is not implemented")
56
+ return {"name": name, "status": "unavailable", "message": "CloudProvider.run_vm is not implemented"}
57
57
 
58
58
  async def stop_vm(self, name: str, storage: Optional[str] = None) -> Dict[str, Any]:
59
- logger.warning("CloudProvider.stop_vm is not implemented")
59
+ logger.warning("CloudProvider.stop_vm is not implemented. To clean up resources, please use Computer.disconnect()")
60
60
  return {"name": name, "status": "stopped", "message": "CloudProvider is not implemented"}
61
61
 
62
62
  async def update_vm(self, name: str, update_opts: Dict[str, Any], storage: Optional[str] = None) -> Dict[str, Any]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cua-computer
3
- Version: 0.2.9
3
+ Version: 0.2.10
4
4
  Summary: Computer-Use Interface (CUI) framework powering Cua
5
5
  Author-Email: TryCua <gh@trycua.com>
6
6
  Requires-Python: >=3.11
@@ -1,19 +1,19 @@
1
1
  computer/__init__.py,sha256=QOxNrrJAuLRnsUC2zIFgRfzVSuDSXiYHlEF-9vkhV0o,1241
2
- computer/computer.py,sha256=zmx_jsQdWy8nsbeb1u9rptJRv5ChR0l0JeyQJcrhiSc,40246
2
+ computer/computer.py,sha256=vFJEyMkvTlT49SEO1QgLe8yMX6DbvdI9eDWjSd3CwCQ,40555
3
3
  computer/diorama_computer.py,sha256=jOP7_eXxxU6SMIoE25ni0YXPK0E7p5sZeLKmkYLh6G8,3871
4
4
  computer/helpers.py,sha256=0ob9d9ynVGi0JRxhHCgXTuHPHFpa8AVKldn6k0hvxOo,1766
5
5
  computer/interface/__init__.py,sha256=xQvYjq5PMn9ZJOmRR5mWtONTl_0HVd8ACvW6AQnzDdw,262
6
- computer/interface/base.py,sha256=wmLBiX7rB8cG2Q4fmchdKpjralktzicuYhAh6fDIeqw,6025
6
+ computer/interface/base.py,sha256=Uc3pp-8_9YJpawAwt1ixaVN3N0_MtY6nAOSvuKy0Mpc,7863
7
7
  computer/interface/factory.py,sha256=RjAZAB_jFuS8JierYjLbapRX6RqFE0qE3BiIyP5UDOE,1441
8
- computer/interface/linux.py,sha256=WA-jpjNHId3blaT__ftd_X7qhKi_50vwy97-jq2yd6g,27412
9
- computer/interface/macos.py,sha256=B-siwSKNOwNNBVvUQh9TO0nWIaMRvvCUbIQ3oziIF5A,27791
10
- computer/interface/models.py,sha256=RZKVUdwKrKUoFqwlx2Dk8Egkmq_AInlIu_d0xg7SZzw,3238
8
+ computer/interface/linux.py,sha256=40SXd-xqYWFUaTnx3Tf7lIDEtluNwYoDkCZaESkIvRE,30468
9
+ computer/interface/macos.py,sha256=uFU9bmPJqPPxlUBw9u1TG3ksqXqB4azJ0pYYx9cRM6w,30848
10
+ computer/interface/models.py,sha256=CYbX3PLlWqjFuDiLWMiBzPmmXB8_g9VNLfBFBC6RtvI,3317
11
11
  computer/logger.py,sha256=UVvnmZGOWVF9TCsixEbeQnDZ3wBPAJ2anW3Zp-MoJ8Y,2896
12
12
  computer/models.py,sha256=iFNM1QfZArD8uf66XJXb2EDIREsfrxqqA5_liLBMfrE,1188
13
13
  computer/providers/__init__.py,sha256=hS9lLxmmHa1u82XJJ_xuqSKipClsYUEPx-8OK9ogtVg,194
14
14
  computer/providers/base.py,sha256=J_9r6pJsvGAFDRl56jog_atN7e8uzrvlCQEdRRqye_U,3624
15
15
  computer/providers/cloud/__init__.py,sha256=SDAcfhI2BlmVBrBZOHxQd3i1bJZjMIfl7QgmqjXa4z8,144
16
- computer/providers/cloud/provider.py,sha256=gpBl_ZVbwk-0FhYycne-69KslnrAoDSZcyzetpLfiKE,2864
16
+ computer/providers/cloud/provider.py,sha256=XEdCrnZzRwvvkPHIwfhfJl3xB6W7tZKdBI0duKEXLw4,2930
17
17
  computer/providers/factory.py,sha256=9qVdt-fIovSNOokGMZ_2B1VPCLSZeDky4edcXyelZy4,4616
18
18
  computer/providers/lume/__init__.py,sha256=E6hTbVQF5lLZD8JyG4rTwUnCBO4q9K8UkYNQ31R0h7c,193
19
19
  computer/providers/lume/provider.py,sha256=grLZeXd4Y8iYsNq2gfNGcQq1bnTcNYNepEv-mxmROG4,20562
@@ -25,7 +25,7 @@ computer/ui/__init__.py,sha256=pmo05ek9qiB_x7DPeE6Vf_8RsIOqTD0w1dBLMHfoOnY,45
25
25
  computer/ui/gradio/__init__.py,sha256=5_KimixM48-X74FCsLw7LbSt39MQfUMEL8-M9amK3Cw,117
26
26
  computer/ui/gradio/app.py,sha256=pLMoMpxyKsGhg9wlsiqyKiRujd-lzubs0nGWAtkleL0,67316
27
27
  computer/utils.py,sha256=zY50NXB7r51GNLQ6l7lhG_qv0_ufpQ8n0-SDhCei8m4,2838
28
- cua_computer-0.2.9.dist-info/METADATA,sha256=wbPfNftTjYS0NSsy77kUlDdle8a3c8TBQ07ncdq65zM,5844
29
- cua_computer-0.2.9.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
30
- cua_computer-0.2.9.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
31
- cua_computer-0.2.9.dist-info/RECORD,,
28
+ cua_computer-0.2.10.dist-info/METADATA,sha256=dC5av4YtGJH20X77m7FPpn8J1bUFmU1p1J7qJX32HGs,5845
29
+ cua_computer-0.2.10.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
30
+ cua_computer-0.2.10.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
31
+ cua_computer-0.2.10.dist-info/RECORD,,