portacode 1.3.32__py3-none-any.whl → 1.4.15.dev3__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 (57) hide show
  1. portacode/_version.py +2 -2
  2. portacode/cli.py +158 -14
  3. portacode/connection/client.py +127 -8
  4. portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +600 -4
  5. portacode/connection/handlers/__init__.py +30 -1
  6. portacode/connection/handlers/diff_handlers.py +603 -0
  7. portacode/connection/handlers/file_handlers.py +674 -17
  8. portacode/connection/handlers/project_aware_file_handlers.py +11 -0
  9. portacode/connection/handlers/project_state/file_system_watcher.py +31 -61
  10. portacode/connection/handlers/project_state/git_manager.py +139 -572
  11. portacode/connection/handlers/project_state/handlers.py +28 -14
  12. portacode/connection/handlers/project_state/manager.py +226 -101
  13. portacode/connection/handlers/proxmox_infra.py +2082 -0
  14. portacode/connection/handlers/session.py +465 -84
  15. portacode/connection/handlers/system_handlers.py +311 -9
  16. portacode/connection/handlers/tab_factory.py +1 -47
  17. portacode/connection/handlers/test_proxmox_infra.py +13 -0
  18. portacode/connection/handlers/update_handler.py +61 -0
  19. portacode/connection/terminal.py +64 -10
  20. portacode/keypair.py +63 -1
  21. portacode/link_capture/__init__.py +38 -0
  22. portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
  23. portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
  24. portacode/link_capture/bin/elinks +3 -0
  25. portacode/link_capture/bin/gio-open +3 -0
  26. portacode/link_capture/bin/gnome-open +3 -0
  27. portacode/link_capture/bin/gvfs-open +3 -0
  28. portacode/link_capture/bin/kde-open +3 -0
  29. portacode/link_capture/bin/kfmclient +3 -0
  30. portacode/link_capture/bin/link_capture_exec.sh +11 -0
  31. portacode/link_capture/bin/link_capture_wrapper.py +75 -0
  32. portacode/link_capture/bin/links +3 -0
  33. portacode/link_capture/bin/links2 +3 -0
  34. portacode/link_capture/bin/lynx +3 -0
  35. portacode/link_capture/bin/mate-open +3 -0
  36. portacode/link_capture/bin/netsurf +3 -0
  37. portacode/link_capture/bin/sensible-browser +3 -0
  38. portacode/link_capture/bin/w3m +3 -0
  39. portacode/link_capture/bin/x-www-browser +3 -0
  40. portacode/link_capture/bin/xdg-open +3 -0
  41. portacode/pairing.py +103 -0
  42. portacode/static/js/utils/ntp-clock.js +170 -79
  43. portacode/utils/diff_apply.py +456 -0
  44. portacode/utils/diff_renderer.py +371 -0
  45. portacode/utils/ntp_clock.py +45 -131
  46. {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/METADATA +71 -3
  47. portacode-1.4.15.dev3.dist-info/RECORD +98 -0
  48. {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/WHEEL +1 -1
  49. test_modules/test_device_online.py +1 -1
  50. test_modules/test_login_flow.py +8 -4
  51. test_modules/test_play_store_screenshots.py +294 -0
  52. testing_framework/.env.example +4 -1
  53. testing_framework/core/playwright_manager.py +63 -9
  54. portacode-1.3.32.dist-info/RECORD +0 -70
  55. {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/entry_points.txt +0 -0
  56. {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/licenses/LICENSE +0 -0
  57. {portacode-1.3.32.dist-info → portacode-1.4.15.dev3.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ import logging
8
8
  import json
9
9
  import time
10
10
  from datetime import datetime
11
+ from urllib.parse import urlparse
11
12
 
12
13
  try:
13
14
  from playwright.async_api import async_playwright, Browser, BrowserContext, Page
@@ -71,6 +72,13 @@ class PlaywrightManager:
71
72
  env_headless = os.getenv('TEST_HEADLESS', 'false').lower() in ('true', '1', 'yes')
72
73
  env_video_width = int(os.getenv('TEST_VIDEO_WIDTH', '1920'))
73
74
  env_video_height = int(os.getenv('TEST_VIDEO_HEIGHT', '1080'))
75
+ env_viewport_width = os.getenv('TEST_VIEWPORT_WIDTH')
76
+ env_viewport_height = os.getenv('TEST_VIEWPORT_HEIGHT')
77
+ env_device_scale = os.getenv('TEST_DEVICE_SCALE_FACTOR')
78
+ env_is_mobile = os.getenv('TEST_IS_MOBILE')
79
+ env_has_touch = os.getenv('TEST_HAS_TOUCH')
80
+ env_user_agent = os.getenv('TEST_USER_AGENT')
81
+ automation_token = os.getenv('TEST_RUNNER_BYPASS_TOKEN')
74
82
 
75
83
  # Use provided values or fall back to environment
76
84
  self.base_url = url or env_url
@@ -124,15 +132,61 @@ class PlaywrightManager:
124
132
  raise Exception(f"Failed to launch {browser_type} browser: {e}")
125
133
 
126
134
  # Create context with recording enabled and proper viewport
135
+ viewport_size = {
136
+ "width": int(env_viewport_width) if env_viewport_width else env_video_width,
137
+ "height": int(env_viewport_height) if env_viewport_height else env_video_height
138
+ }
127
139
  video_size = {"width": env_video_width, "height": env_video_height}
128
- self.context = await self.browser.new_context(
129
- record_video_dir=str(self.test_recordings_dir),
130
- record_video_size=video_size,
131
- record_har_path=str(self.har_path),
132
- record_har_omit_content=False,
133
- viewport=video_size
140
+ context_kwargs = {
141
+ "record_video_dir": str(self.test_recordings_dir),
142
+ "record_video_size": video_size,
143
+ "record_har_path": str(self.har_path),
144
+ "record_har_omit_content": False,
145
+ "viewport": viewport_size
146
+ }
147
+
148
+ if env_device_scale:
149
+ try:
150
+ context_kwargs["device_scale_factor"] = float(env_device_scale)
151
+ except ValueError:
152
+ self.logger.warning(f"Invalid TEST_DEVICE_SCALE_FACTOR '{env_device_scale}' - ignoring")
153
+
154
+ if env_is_mobile:
155
+ context_kwargs["is_mobile"] = env_is_mobile.lower() in ('true', '1', 'yes')
156
+
157
+ if env_has_touch:
158
+ context_kwargs["has_touch"] = env_has_touch.lower() in ('true', '1', 'yes')
159
+
160
+ if env_user_agent:
161
+ context_kwargs["user_agent"] = env_user_agent
162
+
163
+ self.context = await self.browser.new_context(**context_kwargs)
164
+ self.logger.info(
165
+ "Viewport configured: %sx%s (device scale: %s, mobile: %s, touch: %s)",
166
+ viewport_size["width"],
167
+ viewport_size["height"],
168
+ context_kwargs.get("device_scale_factor", 1.0),
169
+ context_kwargs.get("is_mobile", False),
170
+ context_kwargs.get("has_touch", False),
134
171
  )
135
-
172
+ if automation_token:
173
+ parsed_base = urlparse(self.base_url)
174
+ target_host = parsed_base.hostname
175
+ target_scheme = parsed_base.scheme or "http"
176
+ header_name = "X-Portacode-Automation"
177
+
178
+ async def automation_header_route(route, request):
179
+ headers = dict(request.headers)
180
+ parsed_request = urlparse(request.url)
181
+ if parsed_request.hostname == target_host and parsed_request.scheme == target_scheme:
182
+ headers[header_name] = automation_token
183
+ else:
184
+ headers.pop(header_name, None)
185
+ await route.continue_(headers=headers)
186
+
187
+ await self.context.route("**/*", automation_header_route)
188
+ self.logger.info("Automation bypass header restricted to same-origin requests")
189
+
136
190
  self.logger.info(f"Video recording configured: {env_video_width}x{env_video_height}")
137
191
 
138
192
  # Start tracing
@@ -178,7 +232,7 @@ class PlaywrightManager:
178
232
  """Perform login using provided credentials."""
179
233
  try:
180
234
  # Navigate to login page first
181
- login_url = f"{self.base_url}/accounts/login/"
235
+ login_url = f"{self.base_url}accounts/login/"
182
236
  await self.page.goto(login_url)
183
237
  await self.log_action("navigate_to_login", {"url": login_url})
184
238
  await self.take_screenshot("login_page")
@@ -463,4 +517,4 @@ class PlaywrightManager:
463
517
  "actions_count": len(self.actions_log),
464
518
  "console_logs_count": len(getattr(self, 'console_logs', [])),
465
519
  "websocket_logs_count": len(self.websocket_logs)
466
- }
520
+ }
@@ -1,70 +0,0 @@
1
- portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
2
- portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
3
- portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
4
- portacode/_version.py,sha256=d_JbLCEf2f0Y5ScYYYOP97vUKSwyr-VyTj2aQkfr7KU,706
5
- portacode/cli.py,sha256=eDqcZMVFHKzqqWxedhhx8ylu5WMVCLqeJQkbPR7RcJE,16333
6
- portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
7
- portacode/keypair.py,sha256=PAcOYqlVLOoZTPYi6LvLjfsY6BkrWbLOhSZLb8r5sHs,3635
8
- portacode/logging_categories.py,sha256=9m-BYrjyHh1vjZYBQT4JhAh6b_oYUhIWayO-noH1cSE,5063
9
- portacode/service.py,sha256=p-HHMOAl20QsdcJydcZ74Iqes-wl8G8HItdSim30pUk,16537
10
- portacode/connection/README.md,sha256=f9rbuIEKa7cTm9C98rCiBbEtbiIXQU11esGSNhSMiJg,883
11
- portacode/connection/__init__.py,sha256=atqcVGkViIEd7pRa6cP2do07RJOM0UWpbnz5zXjGktU,250
12
- portacode/connection/client.py,sha256=Uqsy5xzN0j5AY0xkYs2_qd67N7SUopcnpkCbkmOnMgg,9102
13
- portacode/connection/multiplex.py,sha256=L-TxqJ_ZEbfNEfu1cwxgJ5vUdyRzZjsMy2Kx1diiZys,5237
14
- portacode/connection/terminal.py,sha256=iz4bi9pppxsiAiOtXEkffcHoyaWkvRG9BkojUyfZ784,42421
15
- portacode/connection/handlers/README.md,sha256=HsLZG1QK1JNm67HsgL6WoDg9nxzKXxwkc5fJPFJdX5g,12169
16
- portacode/connection/handlers/WEBSOCKET_PROTOCOL.md,sha256=U-d58S-X2r5T6QAu-6NOzCIJg71FIj_vmOdUGCWFIhw,68211
17
- portacode/connection/handlers/__init__.py,sha256=4nv3Z4TGYjWcauKPWsbL_FbrTXApI94V7j6oiU1Vv-o,2144
18
- portacode/connection/handlers/base.py,sha256=oENFb-Fcfzwk99Qx8gJQriEMiwSxwygwjOiuCH36hM4,10231
19
- portacode/connection/handlers/chunked_content.py,sha256=h6hXRmxSeOgnIxoU8CkmvEf2Odv-ajPrpHIe_W3GKcA,9251
20
- portacode/connection/handlers/file_handlers.py,sha256=kBj-o3HkqZTKsju2ZxRgBB3Ke42dn4sDQQKGO7APYf8,15451
21
- portacode/connection/handlers/project_aware_file_handlers.py,sha256=n0M2WmBNWPwzigdIkyZiAsePUQGXVqYSsDyOxm-Nsok,9253
22
- portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
23
- portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
24
- portacode/connection/handlers/session.py,sha256=O7TMI5cRziOiXEBWCfBshkMpEthhjvKqGL0hhNOG1wU,26716
25
- portacode/connection/handlers/system_handlers.py,sha256=65V5ctT0dIBc-oWG91e62MbdvU0z6x6JCTQuIqCWmZ0,5242
26
- portacode/connection/handlers/tab_factory.py,sha256=VBZnwtxgeNJCsfBzUjkFWAAGBdijvai4MS2dXnhFY8U,18000
27
- portacode/connection/handlers/terminal_handlers.py,sha256=HRwHW1GiqG1NtHVEqXHKaYkFfQEzCDDH6YIlHcb4XD8,11866
28
- portacode/connection/handlers/project_state/README.md,sha256=trdd4ig6ungmwH5SpbSLfyxbL-QgPlGNU-_XrMEiXtw,10114
29
- portacode/connection/handlers/project_state/__init__.py,sha256=5ucIqk6Iclqg6bKkL8r_wVs5Tlt6B9J7yQH6yQUt7gc,2541
30
- portacode/connection/handlers/project_state/file_system_watcher.py,sha256=2zingW9BoNKRijghHC2eHHdRoyDRdLmIl1yH1y-iuF8,10831
31
- portacode/connection/handlers/project_state/git_manager.py,sha256=tVcuiGYKk1GJ0f7dgjoSGNL13IXCHUOtoi_VBc8ZTqQ,88682
32
- portacode/connection/handlers/project_state/handlers.py,sha256=nhs-3yiENdewAzVZnSdn2Ir-e6TQ9Nz_Bxk3iiFPd9c,37985
33
- portacode/connection/handlers/project_state/manager.py,sha256=XX3wMgGdPbRgBBs_R1dXtQ4D9j-itETrJR_6IfBeDU0,61296
34
- portacode/connection/handlers/project_state/models.py,sha256=EZTKvxHKs8QlQUbzI0u2IqfzfRRXZixUIDBwTGCJATI,4313
35
- portacode/connection/handlers/project_state/utils.py,sha256=LsbQr9TH9Bz30FqikmtTxco4PlB_n0kUIuPKQ6Fb_mo,1665
36
- portacode/static/js/test-ntp-clock.html,sha256=bUow9sifIuLNPqKvuPbpQozmEE6RhdCI4Plib3CqUmw,2130
37
- portacode/static/js/utils/ntp-clock.js,sha256=KMeHGT-IlUSlxVRZZ899z25dQCJh6EJbgXjlh8dD8vA,4495
38
- portacode/utils/NTP_ARCHITECTURE.md,sha256=WkESTbz5SNAgdmDKk3DrHMhtYOPji_Kt3_a9arWdRig,3894
39
- portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,33
40
- portacode/utils/ntp_clock.py,sha256=6QJOVZr9VQuxIyJt9KNG4dR-nZ3bKNyipMxjqDWP89Y,5152
41
- portacode-1.3.32.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
42
- test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
43
- test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
44
- test_modules/test_device_online.py,sha256=yiSyVaMwKAugqIX_ZIxmLXiOlmA_8IRXiUp12YmpB98,1653
45
- test_modules/test_file_operations.py,sha256=KXbh9t8Fah1jZp1pEPlU4_F06iJIJr2fR-yYc4RL6m8,38372
46
- test_modules/test_git_status_ui.py,sha256=A_qkt-0lFLwxdr7t6YQaM0HqUElDwlZi84mlngg11RA,18734
47
- test_modules/test_login_flow.py,sha256=eGjoZQj345qYxNm1arvYVNzjJ-TutT81lSdI6_8A5GU,1685
48
- test_modules/test_navigate_testing_folder.py,sha256=-1EXceUEwof_sYp5paMWUNT3mAv5aIpYJ65_vqFbZew,18233
49
- test_modules/test_terminal_buffer_performance.py,sha256=YQeDDZVnsQD3ug6udKUZH3NR7PHGP75uZsLZJYya7jg,12183
50
- test_modules/test_terminal_interaction.py,sha256=AxLb63oKhNLjKrny4hBj4hhFhrmHZ5UGStYDA0KzA0w,3163
51
- test_modules/test_terminal_loading_race_condition.py,sha256=PsGF8QzWeNNv6G7Fda6kETcBUcXyg_vRYeD-hDHAhCo,4158
52
- test_modules/test_terminal_start.py,sha256=y3IqG54UfMk-pAQ_fn5LuoM3kki6xRm11oB5AzfC-iE,1978
53
- testing_framework/.env.example,sha256=lReCwHAx7vxPxRT7TebEKiZ5HpEOQnpgraXJl2k-0xU,541
54
- testing_framework/README.md,sha256=7o04mS2siNDuHA1UBh3Uu6XCbGomKjgb8gfl8YbClhE,9662
55
- testing_framework/__init__.py,sha256=safHXo_xBMwAwfiF_5rx0xGcPGfpBSOgkMZx04uj4No,575
56
- testing_framework/cli.py,sha256=ZHO37QO2IqZpC9VovrAYur2Vfc2AYeDqzi9Nb4lIA-w,13434
57
- testing_framework/requirements.txt,sha256=VeKSPyqS4MWwLhr0Upu7fImlXZQQjtL8uYeyHOjkYaE,249
58
- testing_framework/core/__init__.py,sha256=8AJQgqSCa9WgwkQNH_wTsA3JmJ4d4FRCweI-ioDgcNI,40
59
- testing_framework/core/base_test.py,sha256=0kKQDNCdAJyTQfJiMBzx9_2MMRrmaVfQF0cawhvian4,13149
60
- testing_framework/core/cli_manager.py,sha256=LDH_tWn-CmO08U_rmBIPpN_O6HLaQKRjdnfKGrtqs8Y,6991
61
- testing_framework/core/hierarchical_runner.py,sha256=tCeksh2cXbRspurSiE-mQM1M1BOPeY8mKFbjvaBTVHw,26401
62
- testing_framework/core/playwright_manager.py,sha256=8xl-19b8NQjKNdiRyDjyeXlYyKPZouSSmmlXjDpuI50,19559
63
- testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
64
- testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
65
- testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
66
- portacode-1.3.32.dist-info/METADATA,sha256=rTf7KoQ6JhbUqq_aOd-8ASc7UfR53vtrxdaLQ-ANsZ8,6989
67
- portacode-1.3.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
68
- portacode-1.3.32.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
69
- portacode-1.3.32.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
70
- portacode-1.3.32.dist-info/RECORD,,