orgo 0.0.28__py3-none-any.whl → 0.0.30__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.
orgo/api/client.py CHANGED
@@ -3,6 +3,7 @@
3
3
  import requests
4
4
  from typing import Dict, Any, Optional, List
5
5
  import logging
6
+ import sys
6
7
 
7
8
  from orgo.utils.auth import get_api_key
8
9
 
@@ -39,7 +40,7 @@ class ApiClient:
39
40
  error_data = e.response.json()
40
41
  if 'error' in error_data:
41
42
  raise Exception(error_data['error']) from None
42
- except ValueError:
43
+ except (ValueError, KeyError):
43
44
  pass
44
45
  raise Exception(f"Request failed with status {e.response.status_code}") from None
45
46
 
orgo/computer.py CHANGED
@@ -1,336 +1,183 @@
1
- """Computer class for interacting with Orgo virtual environments"""
2
- import os as operating_system
3
- import base64
4
- import logging
5
- import uuid
6
- from typing import Dict, List, Any, Optional, Callable, Literal, Union
7
- from PIL import Image
1
+ """API client for Orgo service"""
2
+
8
3
  import requests
9
- from requests.exceptions import RequestException
4
+ from typing import Dict, Any, Optional, List
5
+ import logging
10
6
 
11
- from .api.client import ApiClient
12
- from .prompt import get_provider
7
+ from orgo.utils.auth import get_api_key
13
8
 
14
9
  logger = logging.getLogger(__name__)
15
10
 
16
- class Computer:
17
- def __init__(self,
18
- project: Optional[Union[str, 'Project']] = None,
19
- name: Optional[str] = None,
20
- computer_id: Optional[str] = None,
21
- api_key: Optional[str] = None,
22
- base_api_url: Optional[str] = None,
23
- ram: Optional[Literal[1, 2, 4, 8, 16, 32, 64]] = None,
24
- memory: Optional[Literal[1, 2, 4, 8, 16, 32, 64]] = None,
25
- cpu: Optional[Literal[1, 2, 4, 8, 16]] = None,
26
- os: Optional[Literal["linux", "windows"]] = None,
27
- gpu: Optional[Literal["none", "a10", "l40s", "a100-40gb", "a100-80gb"]] = None):
28
- """
29
- Initialize an Orgo virtual computer.
30
-
31
- Args:
32
- project: Project name (str) or Project instance. If not provided, creates a new project.
33
- name: Computer name within the project (optional, auto-generated if not provided)
34
- computer_id: Existing computer ID to connect to (optional)
35
- api_key: Orgo API key (defaults to ORGO_API_KEY env var)
36
- base_api_url: Custom API URL (optional)
37
- ram/memory: RAM in GB (1, 2, 4, 8, 16, 32, or 64) - only used when creating
38
- cpu: CPU cores (1, 2, 4, 8, or 16) - only used when creating
39
- os: Operating system ("linux" or "windows") - only used when creating
40
- gpu: GPU type - only used when creating
41
-
42
- Examples:
43
- # Create computer in new project
44
- computer = Computer(ram=4, cpu=2)
45
-
46
- # Create computer in existing project
47
- computer = Computer(project="manus", ram=4, cpu=2)
48
-
49
- # Connect to existing computer in project
50
- computer = Computer(project="manus")
51
- """
52
- self.api_key = api_key or operating_system.environ.get("ORGO_API_KEY")
53
- self.base_api_url = base_api_url
54
- self.api = ApiClient(self.api_key, self.base_api_url)
55
-
56
- # Handle memory parameter as an alias for ram
57
- if ram is None and memory is not None:
58
- ram = memory
59
-
60
- # Store configuration
61
- self.os = os or "linux"
62
- self.ram = ram or 2
63
- self.cpu = cpu or 2
64
- self.gpu = gpu or "none"
11
+ class ApiClient:
12
+ def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None):
13
+ self.api_key = get_api_key(api_key)
14
+ self.base_url = base_url or "https://www.orgo.ai/api"
15
+ self.session = requests.Session()
16
+ self.session.headers.update({
17
+ "Authorization": f"Bearer {self.api_key}",
18
+ "Content-Type": "application/json",
19
+ "Accept": "application/json"
20
+ })
21
+
22
+ def _request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
23
+ url = f"{self.base_url}/{endpoint}"
65
24
 
66
- if computer_id:
67
- # Connect to existing computer by ID
68
- self._connect_by_id(computer_id)
69
- elif project:
70
- # Work with specified project
71
- if isinstance(project, str):
72
- # Project name provided
73
- self.project_name = project
74
- self._initialize_with_project_name(project, name)
75
- else:
76
- # Project instance provided
77
- from .project import Project as ProjectClass
78
- if isinstance(project, ProjectClass):
79
- self.project_name = project.name
80
- self.project_id = project.id
81
- self._initialize_with_project_instance(project, name)
82
- else:
83
- raise ValueError("project must be a string (project name) or Project instance")
84
- else:
85
- # No project specified, create a new one
86
- self._create_new_project_and_computer(name)
87
-
88
- def _connect_by_id(self, computer_id: str):
89
- """Connect to existing computer by ID"""
90
- self.computer_id = computer_id
91
- self._info = self.api.get_computer(computer_id)
92
- self.project_name = self._info.get("project_name")
93
- self.name = self._info.get("name")
94
-
95
- def _initialize_with_project_name(self, project_name: str, computer_name: Optional[str]):
96
- """Initialize with a project name (create project if needed)"""
97
25
  try:
98
- # Try to get existing project
99
- project = self.api.get_project_by_name(project_name)
100
- self.project_id = project.get("id")
26
+ if method.upper() == "GET":
27
+ response = self.session.get(url, params=data)
28
+ else:
29
+ response = self.session.request(method, url, json=data)
101
30
 
102
- # Check for existing computers
103
- computers = self.api.list_computers(project_name)
31
+ response.raise_for_status()
32
+ return response.json()
33
+ except requests.exceptions.RequestException as e:
34
+ # Log the full error for debugging
35
+ logger.debug(f"API request failed: {method} {url}", exc_info=True)
104
36
 
105
- if computer_name:
106
- # Look for specific computer
107
- existing = next((c for c in computers if c.get("name") == computer_name), None)
108
- if existing:
109
- self._connect_to_existing_computer(existing)
110
- else:
111
- # Create new computer with specified name
112
- self._create_computer(project_name, computer_name)
113
- elif computers:
114
- # No name specified, use first available computer
115
- self._connect_to_existing_computer(computers[0])
116
- else:
117
- # No computers exist, create new one
118
- self._create_computer(project_name, computer_name)
119
-
120
- except Exception:
121
- # Project doesn't exist, create it
122
- logger.info(f"Project {project_name} not found, creating new project")
123
- project = self.api.create_project(project_name)
124
- self.project_id = project.get("id")
125
- self._create_computer(project_name, computer_name)
126
-
127
- def _initialize_with_project_instance(self, project: 'Project', computer_name: Optional[str]):
128
- """Initialize with a Project instance"""
129
- computers = project.list_computers()
130
-
131
- if computer_name:
132
- # Look for specific computer
133
- existing = next((c for c in computers if c.get("name") == computer_name), None)
134
- if existing:
135
- self._connect_to_existing_computer(existing)
136
- else:
137
- # Create new computer with specified name
138
- self._create_computer(project.name, computer_name)
139
- elif computers:
140
- # No name specified, use first available computer
141
- self._connect_to_existing_computer(computers[0])
142
- else:
143
- # No computers exist, create new one
144
- self._create_computer(project.name, computer_name)
145
-
146
- def _create_new_project_and_computer(self, computer_name: Optional[str]):
147
- """Create a new project and computer"""
148
- # Generate a unique project name
149
- project_name = f"project-{uuid.uuid4().hex[:8]}"
150
-
151
- # Create the project
152
- project = self.api.create_project(project_name)
153
- self.project_id = project.get("id")
154
- self.project_name = project_name
155
-
156
- # Create a computer in the new project
157
- self._create_computer(project_name, computer_name)
158
-
159
- def _connect_to_existing_computer(self, computer_info: Dict[str, Any]):
160
- """Connect to an existing computer"""
161
- self.computer_id = computer_info.get("id")
162
- self.name = computer_info.get("name")
163
- self._info = computer_info
164
- logger.info(f"Connected to existing computer {self.name} (ID: {self.computer_id})")
165
-
166
- def _create_computer(self, project_name: str, computer_name: Optional[str]):
167
- """Create a new computer in the project"""
168
- # Generate name if not provided
169
- if not computer_name:
170
- computer_name = f"desktop-{uuid.uuid4().hex[:8]}"
171
-
172
- self.name = computer_name
173
-
174
- # Validate parameters
175
- if self.ram not in [1, 2, 4, 8, 16, 32, 64]:
176
- raise ValueError("ram must be one of: 1, 2, 4, 8, 16, 32, 64 GB")
177
- if self.cpu not in [1, 2, 4, 8, 16]:
178
- raise ValueError("cpu must be one of: 1, 2, 4, 8, 16 cores")
179
- if self.os not in ["linux", "windows"]:
180
- raise ValueError("os must be either 'linux' or 'windows'")
181
- if self.gpu not in ["none", "a10", "l40s", "a100-40gb", "a100-80gb"]:
182
- raise ValueError("gpu must be one of: 'none', 'a10', 'l40s', 'a100-40gb', 'a100-80gb'")
183
-
184
- computer = self.api.create_computer(
185
- project_name=project_name,
186
- computer_name=computer_name,
187
- os=self.os,
188
- ram=self.ram,
189
- cpu=self.cpu,
190
- gpu=self.gpu
191
- )
192
- self.computer_id = computer.get("id")
193
- self._info = computer
194
- logger.info(f"Created new computer {self.name} (ID: {self.computer_id})")
195
-
196
- def status(self) -> Dict[str, Any]:
197
- """Get current computer status"""
198
- return self.api.get_computer(self.computer_id)
199
-
200
- def start(self) -> Dict[str, Any]:
201
- """Start the computer"""
202
- return self.api.start_computer(self.computer_id)
203
-
204
- def stop(self) -> Dict[str, Any]:
205
- """Stop the computer"""
206
- return self.api.stop_computer(self.computer_id)
207
-
208
- def restart(self) -> Dict[str, Any]:
209
- """Restart the computer"""
210
- return self.api.restart_computer(self.computer_id)
211
-
212
- def destroy(self) -> Dict[str, Any]:
213
- """Terminate and delete the computer instance"""
214
- return self.api.delete_computer(self.computer_id)
215
-
216
- # Navigation methods
217
- def left_click(self, x: int, y: int) -> Dict[str, Any]:
218
- """Perform left mouse click at specified coordinates"""
219
- return self.api.left_click(self.computer_id, x, y)
220
-
221
- def right_click(self, x: int, y: int) -> Dict[str, Any]:
222
- """Perform right mouse click at specified coordinates"""
223
- return self.api.right_click(self.computer_id, x, y)
224
-
225
- def double_click(self, x: int, y: int) -> Dict[str, Any]:
226
- """Perform double click at specified coordinates"""
227
- return self.api.double_click(self.computer_id, x, y)
228
-
229
- def drag(self, start_x: int, start_y: int, end_x: int, end_y: int,
230
- button: str = "left", duration: float = 0.5) -> Dict[str, Any]:
231
- """Perform a smooth drag operation from start to end coordinates"""
232
- return self.api.drag(self.computer_id, start_x, start_y, end_x, end_y, button, duration)
233
-
234
- def scroll(self, direction: str = "down", amount: int = 3) -> Dict[str, Any]:
235
- """Scroll in specified direction and amount"""
236
- return self.api.scroll(self.computer_id, direction, amount)
237
-
238
- # Input methods
239
- def type(self, text: str) -> Dict[str, Any]:
240
- """Type the specified text"""
241
- return self.api.type_text(self.computer_id, text)
242
-
243
- def key(self, key: str) -> Dict[str, Any]:
244
- """Press a key or key combination (e.g., "Enter", "ctrl+c")"""
245
- return self.api.key_press(self.computer_id, key)
246
-
247
- # View methods
248
- def screenshot(self) -> Image.Image:
249
- """Capture screenshot and return as PIL Image"""
250
- response = self.api.get_screenshot(self.computer_id)
251
- image_data = response.get("image", "")
252
-
253
- if image_data.startswith(('http://', 'https://')):
254
- img_response = requests.get(image_data)
255
- img_response.raise_for_status()
256
- return Image.open(io.BytesIO(img_response.content))
257
- else:
258
- img_data = base64.b64decode(image_data)
259
- return Image.open(io.BytesIO(img_data))
260
-
261
- def screenshot_base64(self) -> str:
262
- """Capture screenshot and return as base64 string"""
263
- response = self.api.get_screenshot(self.computer_id)
264
- image_data = response.get("image", "")
265
-
266
- if image_data.startswith(('http://', 'https://')):
267
- img_response = requests.get(image_data)
268
- img_response.raise_for_status()
269
- return base64.b64encode(img_response.content).decode('utf-8')
270
- else:
271
- return image_data
272
-
273
- # Execution methods
274
- def bash(self, command: str) -> str:
275
- """Execute a bash command and return output"""
276
- response = self.api.execute_bash(self.computer_id, command)
277
- return response.get("output", "")
278
-
279
- def exec(self, code: str, timeout: int = 10) -> Dict[str, Any]:
280
- """Execute Python code on the remote computer"""
281
- response = self.api.execute_python(self.computer_id, code, timeout)
282
- return response
283
-
284
- def wait(self, seconds: float) -> Dict[str, Any]:
285
- """Wait for specified number of seconds"""
286
- return self.api.wait(self.computer_id, seconds)
37
+ if hasattr(e, 'response') and e.response is not None:
38
+ try:
39
+ error_data = e.response.json()
40
+ if 'error' in error_data:
41
+ raise Exception(error_data['error']) from None
42
+ except (ValueError, KeyError):
43
+ pass
44
+ raise Exception(f"Request failed with status {e.response.status_code}") from None
45
+
46
+ # Generic error message without exposing internal details
47
+ raise Exception("Failed to connect to Orgo service. Please check your connection and try again.") from None
48
+
49
+ # Project methods
50
+ def create_project(self, name: str) -> Dict[str, Any]:
51
+ """Create a new named project"""
52
+ return self._request("POST", "projects", {"name": name})
53
+
54
+ def get_project_by_name(self, name: str) -> Dict[str, Any]:
55
+ """Get project details by name"""
56
+ projects = self.list_projects()
57
+ for project in projects:
58
+ if project.get("name") == name:
59
+ return project
60
+ raise Exception(f"Project '{name}' not found") from None
61
+
62
+ def get_project(self, project_id: str) -> Dict[str, Any]:
63
+ """Get project details by ID"""
64
+ return self._request("GET", f"projects/{project_id}")
65
+
66
+ def list_projects(self) -> List[Dict[str, Any]]:
67
+ """List all projects"""
68
+ response = self._request("GET", "projects")
69
+ return response.get("projects", [])
70
+
71
+ def delete_project(self, project_id: str) -> Dict[str, Any]:
72
+ """Delete a project and all its computers"""
73
+ return self._request("DELETE", f"projects/{project_id}")
74
+
75
+ # Computer methods
76
+ def create_computer(self, project_id: str, computer_name: str,
77
+ os: str = "linux", ram: int = 2, cpu: int = 2,
78
+ gpu: str = "none") -> Dict[str, Any]:
79
+ """Create a new computer within a project"""
80
+ return self._request("POST", "computers", {
81
+ "project_id": project_id,
82
+ "name": computer_name,
83
+ "os": os,
84
+ "ram": ram,
85
+ "cpu": cpu,
86
+ "gpu": gpu
87
+ })
88
+
89
+ def list_computers(self, project_id: str) -> List[Dict[str, Any]]:
90
+ """List all computers in a project"""
91
+ project = self.get_project(project_id)
92
+ return project.get("desktops", [])
93
+
94
+ def get_computer(self, computer_id: str) -> Dict[str, Any]:
95
+ """Get computer details"""
96
+ return self._request("GET", f"computers/{computer_id}")
97
+
98
+ def delete_computer(self, computer_id: str) -> Dict[str, Any]:
99
+ """Delete a computer"""
100
+ return self._request("DELETE", f"computers/{computer_id}")
101
+
102
+ def restart_computer(self, computer_id: str) -> Dict[str, Any]:
103
+ """Restart a computer"""
104
+ return self._request("POST", f"computers/{computer_id}/restart")
105
+
106
+ # Computer control methods
107
+ def left_click(self, computer_id: str, x: int, y: int) -> Dict[str, Any]:
108
+ return self._request("POST", f"computers/{computer_id}/click", {
109
+ "button": "left", "x": x, "y": y
110
+ })
111
+
112
+ def right_click(self, computer_id: str, x: int, y: int) -> Dict[str, Any]:
113
+ return self._request("POST", f"computers/{computer_id}/click", {
114
+ "button": "right", "x": x, "y": y
115
+ })
116
+
117
+ def double_click(self, computer_id: str, x: int, y: int) -> Dict[str, Any]:
118
+ return self._request("POST", f"computers/{computer_id}/click", {
119
+ "button": "left", "x": x, "y": y, "double": True
120
+ })
121
+
122
+ def drag(self, computer_id: str, start_x: int, start_y: int,
123
+ end_x: int, end_y: int, button: str = "left",
124
+ duration: float = 0.5) -> Dict[str, Any]:
125
+ """Perform a drag operation from start to end coordinates"""
126
+ return self._request("POST", f"computers/{computer_id}/drag", {
127
+ "start_x": start_x,
128
+ "start_y": start_y,
129
+ "end_x": end_x,
130
+ "end_y": end_y,
131
+ "button": button,
132
+ "duration": duration
133
+ })
134
+
135
+ def scroll(self, computer_id: str, direction: str, amount: int = 3) -> Dict[str, Any]:
136
+ return self._request("POST", f"computers/{computer_id}/scroll", {
137
+ "direction": direction, "amount": amount
138
+ })
139
+
140
+ def type_text(self, computer_id: str, text: str) -> Dict[str, Any]:
141
+ return self._request("POST", f"computers/{computer_id}/type", {
142
+ "text": text
143
+ })
144
+
145
+ def key_press(self, computer_id: str, key: str) -> Dict[str, Any]:
146
+ return self._request("POST", f"computers/{computer_id}/key", {
147
+ "key": key
148
+ })
149
+
150
+ def get_screenshot(self, computer_id: str) -> Dict[str, Any]:
151
+ return self._request("GET", f"computers/{computer_id}/screenshot")
152
+
153
+ def execute_bash(self, computer_id: str, command: str) -> Dict[str, Any]:
154
+ return self._request("POST", f"computers/{computer_id}/bash", {
155
+ "command": command
156
+ })
157
+
158
+ def execute_python(self, computer_id: str, code: str, timeout: int = 10) -> Dict[str, Any]:
159
+ """Execute Python code on the computer"""
160
+ return self._request("POST", f"computers/{computer_id}/exec", {
161
+ "code": code,
162
+ "timeout": timeout
163
+ })
164
+
165
+ def wait(self, computer_id: str, duration: float) -> Dict[str, Any]:
166
+ return self._request("POST", f"computers/{computer_id}/wait", {
167
+ "duration": duration
168
+ })
287
169
 
288
170
  # Streaming methods
289
- def start_stream(self, connection: str) -> Dict[str, Any]:
290
- """Start streaming the computer screen to an RTMP server"""
291
- return self.api.start_stream(self.computer_id, connection)
171
+ def start_stream(self, computer_id: str, connection_name: str) -> Dict[str, Any]:
172
+ """Start streaming to a configured RTMP connection"""
173
+ return self._request("POST", f"computers/{computer_id}/stream/start", {
174
+ "connection_name": connection_name
175
+ })
292
176
 
293
- def stop_stream(self) -> Dict[str, Any]:
177
+ def stop_stream(self, computer_id: str) -> Dict[str, Any]:
294
178
  """Stop the active stream"""
295
- return self.api.stop_stream(self.computer_id)
296
-
297
- def stream_status(self) -> Dict[str, Any]:
298
- """Get the current streaming status"""
299
- return self.api.get_stream_status(self.computer_id)
300
-
301
- # AI control method
302
- def prompt(self,
303
- instruction: str,
304
- provider: str = "anthropic",
305
- model: str = "claude-3-7-sonnet-20250219",
306
- display_width: int = 1024,
307
- display_height: int = 768,
308
- callback: Optional[Callable[[str, Any], None]] = None,
309
- thinking_enabled: bool = False,
310
- thinking_budget: int = 1024,
311
- max_tokens: int = 4096,
312
- max_iterations: int = 20,
313
- max_saved_screenshots: int = 5,
314
- api_key: Optional[str] = None) -> List[Dict[str, Any]]:
315
- """Control the computer with natural language instructions using an AI assistant"""
316
- provider_instance = get_provider(provider)
317
-
318
- return provider_instance.execute(
319
- computer_id=self.computer_id,
320
- instruction=instruction,
321
- callback=callback,
322
- api_key=api_key,
323
- model=model,
324
- display_width=display_width,
325
- display_height=display_height,
326
- thinking_enabled=thinking_enabled,
327
- thinking_budget=thinking_budget,
328
- max_tokens=max_tokens,
329
- max_iterations=max_iterations,
330
- max_saved_screenshots=max_saved_screenshots,
331
- orgo_api_key=self.api_key,
332
- orgo_base_url=self.base_api_url
333
- )
179
+ return self._request("POST", f"computers/{computer_id}/stream/stop")
334
180
 
335
- def __repr__(self):
336
- return f"Computer(name='{self.name}', project='{self.project_name}', id='{self.computer_id}')"
181
+ def get_stream_status(self, computer_id: str) -> Dict[str, Any]:
182
+ """Get current stream status"""
183
+ return self._request("GET", f"computers/{computer_id}/stream/status")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orgo
3
- Version: 0.0.28
3
+ Version: 0.0.30
4
4
  Summary: Computers for AI agents
5
5
  Author: Orgo Team
6
6
  License: MIT
@@ -1,12 +1,12 @@
1
1
  orgo/__init__.py,sha256=aw3BM7-Wy8jk-mvIWRG2gC4-nsc74s6ZFm1U21NyGeM,171
2
- orgo/computer.py,sha256=B3B0NQwpSHzadjbssxHzoXe3-A3A3cuUD1fXW18k_bU,14487
2
+ orgo/computer.py,sha256=apny7V3IYJTyDwn5utukzyECLWT65oo-1EmFRwHL--E,7544
3
3
  orgo/project.py,sha256=uVDFa8iyn5OaHzTzjGQhxnF_nVzwkqkqUShiV3M0AWU,3150
4
4
  orgo/prompt.py,sha256=ynblwXPTDp_aF1MbGBsY0PIEr9naklDaKFcfSE_EZ6E,19781
5
5
  orgo/api/__init__.py,sha256=9Tzb_OPJ5DH7Cg7OrHzpZZUT4ip05alpa9RLDYmnId8,113
6
- orgo/api/client.py,sha256=BgRJQaQxng4EUD72bcQGF6Iwkw79fvvx1tTR1koLGx0,7383
6
+ orgo/api/client.py,sha256=sBvX1e1BSY_BB7N4Cnb7mhBt1JBn-EpIYc5KO5sf6m4,7406
7
7
  orgo/utils/__init__.py,sha256=W4G_nwGBf_7jy0w_mfcrkllurYHSRU4B5cMTVYH_uCc,123
8
8
  orgo/utils/auth.py,sha256=tPLBJY-6gdBQWLUjUbwIwxHphC3KoRT_XgP3Iykw3Mw,509
9
- orgo-0.0.28.dist-info/METADATA,sha256=ixsfJKWG9dL3AxbYN0aAsS_4J8D-5zcIpfhIfJZb9C4,822
10
- orgo-0.0.28.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- orgo-0.0.28.dist-info/top_level.txt,sha256=q0rYtFji8GbYuhFW8A5Ab9e0j27761IKPhnL0E9xow4,5
12
- orgo-0.0.28.dist-info/RECORD,,
9
+ orgo-0.0.30.dist-info/METADATA,sha256=piWp5WsPjKfXfJPjDKxtq9YBE2Io4FAH_JLASnoeJVg,822
10
+ orgo-0.0.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ orgo-0.0.30.dist-info/top_level.txt,sha256=q0rYtFji8GbYuhFW8A5Ab9e0j27761IKPhnL0E9xow4,5
12
+ orgo-0.0.30.dist-info/RECORD,,
File without changes