meshagent-computers 0.45.4__tar.gz → 0.45.5__tar.gz

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 (33) hide show
  1. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/CHANGELOG.md +3 -0
  2. {meshagent_computers-0.45.4/meshagent_computers.egg-info → meshagent_computers-0.45.5}/PKG-INFO +4 -4
  3. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/docker.py +2 -2
  4. meshagent_computers-0.45.5/meshagent/computers/docker_test.py +66 -0
  5. meshagent_computers-0.45.5/meshagent/computers/utils_test.py +99 -0
  6. meshagent_computers-0.45.5/meshagent/computers/version.py +1 -0
  7. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5/meshagent_computers.egg-info}/PKG-INFO +4 -4
  8. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent_computers.egg-info/requires.txt +3 -3
  9. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/pyproject.toml +3 -3
  10. meshagent_computers-0.45.4/meshagent/computers/docker_test.py +0 -22
  11. meshagent_computers-0.45.4/meshagent/computers/utils_test.py +0 -47
  12. meshagent_computers-0.45.4/meshagent/computers/version.py +0 -1
  13. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/LICENSE +0 -0
  14. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/MANIFEST.in +0 -0
  15. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/README.md +0 -0
  16. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/__init__.py +0 -0
  17. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/agent.py +0 -0
  18. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/agent_test.py +0 -0
  19. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/base_playwright.py +0 -0
  20. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/browserbase.py +0 -0
  21. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/computer.py +0 -0
  22. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/container_playwright.py +0 -0
  23. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/container_playwright_test.py +0 -0
  24. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/local_playwright.py +0 -0
  25. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/operator.py +0 -0
  26. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/operator_test.py +0 -0
  27. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/stagehand.py +0 -0
  28. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/stagehand_test.py +0 -0
  29. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent/computers/utils.py +0 -0
  30. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent_computers.egg-info/SOURCES.txt +0 -0
  31. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent_computers.egg-info/dependency_links.txt +0 -0
  32. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/meshagent_computers.egg-info/top_level.txt +0 -0
  33. {meshagent_computers-0.45.4 → meshagent_computers-0.45.5}/setup.cfg +0 -0
@@ -1,3 +1,6 @@
1
+ ## [0.45.5]
2
+ - Shell command analysis now handles mixed absolute and dynamic write targets more safely, keeping generated file previews and path grouping accurate.
3
+
1
4
  ## [0.45.4]
2
5
  - Stability
3
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-computers
3
- Version: 0.45.4
3
+ Version: 0.45.5
4
4
  Summary: Computer Building Blocks for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -12,9 +12,9 @@ License-File: LICENSE
12
12
  Requires-Dist: pytest~=8.4
13
13
  Requires-Dist: pytest-asyncio~=0.26
14
14
  Requires-Dist: openai~=2.25.0
15
- Requires-Dist: meshagent-api==0.45.4
16
- Requires-Dist: meshagent-agents==0.45.4
17
- Requires-Dist: meshagent-tools==0.45.4
15
+ Requires-Dist: meshagent-api==0.45.5
16
+ Requires-Dist: meshagent-agents==0.45.5
17
+ Requires-Dist: meshagent-tools==0.45.5
18
18
  Requires-Dist: playwright~=1.58.0
19
19
  Requires-Dist: stagehand~=3.6.0
20
20
  Requires-Dist: browserbase~=1.2
@@ -63,8 +63,8 @@ class DockerComputer:
63
63
  )
64
64
 
65
65
  # Fetch display geometry
66
- geometry = await self._exec(
67
- f"DISPLAY={self.display} xdotool getdisplaygeometry"
66
+ geometry = (
67
+ await self._exec(f"DISPLAY={self.display} xdotool getdisplaygeometry")
68
68
  ).strip()
69
69
  if geometry:
70
70
  w, h = geometry.split()
@@ -0,0 +1,66 @@
1
+ import subprocess
2
+
3
+ import pytest
4
+
5
+ from meshagent.computers import docker as docker_module
6
+ from meshagent.computers.docker import DockerComputer, _async_check_output
7
+
8
+
9
+ @pytest.mark.asyncio
10
+ async def test_async_check_output_shell_executes_and_preserves_failure_fields():
11
+ assert await _async_check_output("printf stdout", shell=True) == b"stdout"
12
+
13
+ with pytest.raises(subprocess.CalledProcessError) as exc_info:
14
+ await _async_check_output(
15
+ "printf stdout; printf stderr >&2; exit 7",
16
+ shell=True,
17
+ )
18
+
19
+ exc = exc_info.value
20
+ assert exc.returncode == 7
21
+ assert exc.cmd == ("printf stdout; printf stderr >&2; exit 7",)
22
+ assert exc.output == b"stdout"
23
+ assert exc.stderr == b"stderr"
24
+
25
+
26
+ @pytest.mark.asyncio
27
+ async def test_docker_computer_aenter_awaits_exec_before_stripping_geometry(
28
+ monkeypatch,
29
+ ):
30
+ class Result:
31
+ stdout = "container-id\n"
32
+
33
+ run_calls = []
34
+
35
+ def fake_run(*args, **kwargs):
36
+ run_calls.append((args, kwargs))
37
+ return Result()
38
+
39
+ async def fake_exec(self, cmd):
40
+ exec_calls.append(cmd)
41
+ return "1600 900\n"
42
+
43
+ exec_calls = []
44
+ monkeypatch.setattr(docker_module.subprocess, "run", fake_run)
45
+ monkeypatch.setattr(DockerComputer, "_exec", fake_exec)
46
+
47
+ computer = DockerComputer()
48
+ result = await computer.__aenter__(context=object())
49
+
50
+ assert result is computer
51
+ assert computer.dimensions == (1600, 900)
52
+ assert run_calls == [
53
+ (
54
+ (
55
+ [
56
+ "docker",
57
+ "ps",
58
+ "-q",
59
+ "-f",
60
+ "name=cua-sample-app",
61
+ ],
62
+ ),
63
+ {"capture_output": True, "text": True},
64
+ )
65
+ ]
66
+ assert exec_calls == ["DISPLAY=:99 xdotool getdisplaygeometry"]
@@ -0,0 +1,99 @@
1
+ import base64
2
+
3
+ import pytest
4
+
5
+ from meshagent.computers import utils as utils_module
6
+
7
+
8
+ @pytest.mark.parametrize(
9
+ "url",
10
+ [
11
+ "https://maliciousbook.com",
12
+ "https://login.maliciousbook.com/path",
13
+ "https://evilvideos.com/watch?v=1",
14
+ "https://user:pass@evilvideos.com:443/path",
15
+ "//evilvideos.com/path",
16
+ ],
17
+ )
18
+ def test_check_blocklisted_url_rejects_blocklisted_domains(url: str) -> None:
19
+ with pytest.raises(ValueError, match="Blocked URL"):
20
+ utils_module.check_blocklisted_url(url)
21
+
22
+
23
+ def test_check_blocklisted_url_allows_other_domains() -> None:
24
+ utils_module.check_blocklisted_url("https://example.com/path")
25
+
26
+
27
+ @pytest.mark.parametrize(
28
+ "url",
29
+ [
30
+ "EVILVIDEOS.COM/path",
31
+ "evilvideos.com/path",
32
+ "http://evilvideos.com\\@example.com/path",
33
+ "http://sub.ilanbigio.com.",
34
+ "http:// evilvideos.com /path",
35
+ ],
36
+ )
37
+ def test_check_blocklisted_url_preserves_urlparse_hostname_edges(url: str) -> None:
38
+ utils_module.check_blocklisted_url(url)
39
+
40
+
41
+ def test_check_blocklisted_url_raises_urlparse_errors() -> None:
42
+ with pytest.raises(ValueError, match="Invalid IPv6 URL"):
43
+ utils_module.check_blocklisted_url("http://[::1")
44
+
45
+
46
+ @pytest.mark.parametrize("value", [None, [], "x", 3])
47
+ def test_sanitize_message_non_dict_inputs_raise_python_get_error(value) -> None:
48
+ with pytest.raises(AttributeError, match="object has no attribute 'get'"):
49
+ utils_module.sanitize_message(value)
50
+
51
+
52
+ def test_calculate_image_dimensions_supports_xbm_like_pillow() -> None:
53
+ xbm = (
54
+ b"#define sample_width 17\n"
55
+ b"#define sample_height 9\n"
56
+ b"static unsigned char sample_bits[] = { 0x00 };\n"
57
+ )
58
+ assert utils_module.calculate_image_dimensions(base64.b64encode(xbm).decode()) == (
59
+ 17,
60
+ 9,
61
+ )
62
+
63
+
64
+ def test_calculate_image_dimensions_supports_xpm_like_pillow() -> None:
65
+ xpm = (
66
+ b"/* XPM */\n"
67
+ b"static char * sample[] = {\n"
68
+ b'"13 7 1 1",\n'
69
+ b'"a c #000000",\n'
70
+ b'"aaaaaaaaaaaaa",\n'
71
+ b'"aaaaaaaaaaaaa",\n'
72
+ b'"aaaaaaaaaaaaa",\n'
73
+ b'"aaaaaaaaaaaaa",\n'
74
+ b'"aaaaaaaaaaaaa",\n'
75
+ b'"aaaaaaaaaaaaa",\n'
76
+ b'"aaaaaaaaaaaaa"};\n'
77
+ )
78
+ assert utils_module.calculate_image_dimensions(base64.b64encode(xpm).decode()) == (
79
+ 13,
80
+ 7,
81
+ )
82
+
83
+
84
+ @pytest.mark.parametrize(
85
+ "payload",
86
+ [
87
+ bytes([0, 0, 1, 0, 1, 0, 16, 10, 0, 0, 1, 0, 32, 0, 4, 0, 0, 0, 22, 0, 0, 0])
88
+ + b"abcd",
89
+ bytes([0, 0, 2, 0, 1, 0, 16, 10, 0, 0, 1, 0, 32, 0, 4, 0, 0, 0, 22, 0, 0, 0])
90
+ + b"abcd",
91
+ bytes([0, 0, 1, 0, 1, 0, 16, 10, 0, 0, 1, 0, 32, 0, 4, 0, 0, 0, 100, 0, 0, 0])
92
+ + b"abcd",
93
+ ],
94
+ )
95
+ def test_calculate_image_dimensions_rejects_invalid_ico_payloads_like_pillow(
96
+ payload: bytes,
97
+ ) -> None:
98
+ with pytest.raises(Exception):
99
+ utils_module.calculate_image_dimensions(base64.b64encode(payload).decode())
@@ -0,0 +1 @@
1
+ __version__ = "0.45.5"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-computers
3
- Version: 0.45.4
3
+ Version: 0.45.5
4
4
  Summary: Computer Building Blocks for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -12,9 +12,9 @@ License-File: LICENSE
12
12
  Requires-Dist: pytest~=8.4
13
13
  Requires-Dist: pytest-asyncio~=0.26
14
14
  Requires-Dist: openai~=2.25.0
15
- Requires-Dist: meshagent-api==0.45.4
16
- Requires-Dist: meshagent-agents==0.45.4
17
- Requires-Dist: meshagent-tools==0.45.4
15
+ Requires-Dist: meshagent-api==0.45.5
16
+ Requires-Dist: meshagent-agents==0.45.5
17
+ Requires-Dist: meshagent-tools==0.45.5
18
18
  Requires-Dist: playwright~=1.58.0
19
19
  Requires-Dist: stagehand~=3.6.0
20
20
  Requires-Dist: browserbase~=1.2
@@ -1,9 +1,9 @@
1
1
  pytest~=8.4
2
2
  pytest-asyncio~=0.26
3
3
  openai~=2.25.0
4
- meshagent-api==0.45.4
5
- meshagent-agents==0.45.4
6
- meshagent-tools==0.45.4
4
+ meshagent-api==0.45.5
5
+ meshagent-agents==0.45.5
6
+ meshagent-tools==0.45.5
7
7
  playwright~=1.58.0
8
8
  stagehand~=3.6.0
9
9
  browserbase~=1.2
@@ -15,9 +15,9 @@ dependencies = [
15
15
  "pytest~=8.4",
16
16
  "pytest-asyncio~=0.26",
17
17
  "openai~=2.25.0",
18
- "meshagent-api==0.45.4",
19
- "meshagent-agents==0.45.4",
20
- "meshagent-tools==0.45.4",
18
+ "meshagent-api==0.45.5",
19
+ "meshagent-agents==0.45.5",
20
+ "meshagent-tools==0.45.5",
21
21
  "playwright~=1.58.0",
22
22
  "stagehand~=3.6.0",
23
23
  "browserbase~=1.2",
@@ -1,22 +0,0 @@
1
- import subprocess
2
-
3
- import pytest
4
-
5
- from meshagent.computers.docker import _async_check_output
6
-
7
-
8
- @pytest.mark.asyncio
9
- async def test_async_check_output_shell_executes_and_preserves_failure_fields():
10
- assert await _async_check_output("printf stdout", shell=True) == b"stdout"
11
-
12
- with pytest.raises(subprocess.CalledProcessError) as exc_info:
13
- await _async_check_output(
14
- "printf stdout; printf stderr >&2; exit 7",
15
- shell=True,
16
- )
17
-
18
- exc = exc_info.value
19
- assert exc.returncode == 7
20
- assert exc.cmd == ("printf stdout; printf stderr >&2; exit 7",)
21
- assert exc.output == b"stdout"
22
- assert exc.stderr == b"stderr"
@@ -1,47 +0,0 @@
1
- import pytest
2
-
3
- from meshagent.computers import utils as utils_module
4
-
5
-
6
- @pytest.mark.parametrize(
7
- "url",
8
- [
9
- "https://maliciousbook.com",
10
- "https://login.maliciousbook.com/path",
11
- "https://evilvideos.com/watch?v=1",
12
- "https://user:pass@evilvideos.com:443/path",
13
- "//evilvideos.com/path",
14
- ],
15
- )
16
- def test_check_blocklisted_url_rejects_blocklisted_domains(url: str) -> None:
17
- with pytest.raises(ValueError, match="Blocked URL"):
18
- utils_module.check_blocklisted_url(url)
19
-
20
-
21
- def test_check_blocklisted_url_allows_other_domains() -> None:
22
- utils_module.check_blocklisted_url("https://example.com/path")
23
-
24
-
25
- @pytest.mark.parametrize(
26
- "url",
27
- [
28
- "EVILVIDEOS.COM/path",
29
- "evilvideos.com/path",
30
- "http://evilvideos.com\\@example.com/path",
31
- "http://sub.ilanbigio.com.",
32
- "http:// evilvideos.com /path",
33
- ],
34
- )
35
- def test_check_blocklisted_url_preserves_urlparse_hostname_edges(url: str) -> None:
36
- utils_module.check_blocklisted_url(url)
37
-
38
-
39
- def test_check_blocklisted_url_raises_urlparse_errors() -> None:
40
- with pytest.raises(ValueError, match="Invalid IPv6 URL"):
41
- utils_module.check_blocklisted_url("http://[::1")
42
-
43
-
44
- @pytest.mark.parametrize("value", [None, [], "x", 3])
45
- def test_sanitize_message_non_dict_inputs_raise_python_get_error(value) -> None:
46
- with pytest.raises(AttributeError, match="object has no attribute 'get'"):
47
- utils_module.sanitize_message(value)
@@ -1 +0,0 @@
1
- __version__ = "0.45.4"