portacode 0.3.19.dev4__py3-none-any.whl → 1.4.11.dev1__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.

Potentially problematic release.


This version of portacode might be problematic. Click here for more details.

Files changed (92) hide show
  1. portacode/_version.py +16 -3
  2. portacode/cli.py +143 -17
  3. portacode/connection/client.py +149 -10
  4. portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +824 -21
  5. portacode/connection/handlers/__init__.py +28 -1
  6. portacode/connection/handlers/base.py +78 -16
  7. portacode/connection/handlers/chunked_content.py +244 -0
  8. portacode/connection/handlers/diff_handlers.py +603 -0
  9. portacode/connection/handlers/file_handlers.py +902 -17
  10. portacode/connection/handlers/project_aware_file_handlers.py +226 -0
  11. portacode/connection/handlers/project_state/README.md +312 -0
  12. portacode/connection/handlers/project_state/__init__.py +92 -0
  13. portacode/connection/handlers/project_state/file_system_watcher.py +179 -0
  14. portacode/connection/handlers/project_state/git_manager.py +1502 -0
  15. portacode/connection/handlers/project_state/handlers.py +875 -0
  16. portacode/connection/handlers/project_state/manager.py +1331 -0
  17. portacode/connection/handlers/project_state/models.py +108 -0
  18. portacode/connection/handlers/project_state/utils.py +50 -0
  19. portacode/connection/handlers/project_state_handlers.py +45 -2185
  20. portacode/connection/handlers/proxmox_infra.py +361 -0
  21. portacode/connection/handlers/registry.py +15 -4
  22. portacode/connection/handlers/session.py +483 -32
  23. portacode/connection/handlers/system_handlers.py +147 -8
  24. portacode/connection/handlers/tab_factory.py +53 -46
  25. portacode/connection/handlers/terminal_handlers.py +21 -8
  26. portacode/connection/handlers/update_handler.py +61 -0
  27. portacode/connection/multiplex.py +60 -2
  28. portacode/connection/terminal.py +214 -24
  29. portacode/keypair.py +63 -1
  30. portacode/link_capture/__init__.py +38 -0
  31. portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
  32. portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
  33. portacode/link_capture/bin/elinks +3 -0
  34. portacode/link_capture/bin/gio-open +3 -0
  35. portacode/link_capture/bin/gnome-open +3 -0
  36. portacode/link_capture/bin/gvfs-open +3 -0
  37. portacode/link_capture/bin/kde-open +3 -0
  38. portacode/link_capture/bin/kfmclient +3 -0
  39. portacode/link_capture/bin/link_capture_exec.sh +11 -0
  40. portacode/link_capture/bin/link_capture_wrapper.py +75 -0
  41. portacode/link_capture/bin/links +3 -0
  42. portacode/link_capture/bin/links2 +3 -0
  43. portacode/link_capture/bin/lynx +3 -0
  44. portacode/link_capture/bin/mate-open +3 -0
  45. portacode/link_capture/bin/netsurf +3 -0
  46. portacode/link_capture/bin/sensible-browser +3 -0
  47. portacode/link_capture/bin/w3m +3 -0
  48. portacode/link_capture/bin/x-www-browser +3 -0
  49. portacode/link_capture/bin/xdg-open +3 -0
  50. portacode/logging_categories.py +140 -0
  51. portacode/pairing.py +103 -0
  52. portacode/static/js/test-ntp-clock.html +63 -0
  53. portacode/static/js/utils/ntp-clock.js +232 -0
  54. portacode/utils/NTP_ARCHITECTURE.md +136 -0
  55. portacode/utils/__init__.py +1 -0
  56. portacode/utils/diff_apply.py +456 -0
  57. portacode/utils/diff_renderer.py +371 -0
  58. portacode/utils/ntp_clock.py +65 -0
  59. portacode-1.4.11.dev1.dist-info/METADATA +298 -0
  60. portacode-1.4.11.dev1.dist-info/RECORD +97 -0
  61. {portacode-0.3.19.dev4.dist-info → portacode-1.4.11.dev1.dist-info}/WHEEL +1 -1
  62. portacode-1.4.11.dev1.dist-info/top_level.txt +3 -0
  63. test_modules/README.md +296 -0
  64. test_modules/__init__.py +1 -0
  65. test_modules/test_device_online.py +44 -0
  66. test_modules/test_file_operations.py +743 -0
  67. test_modules/test_git_status_ui.py +370 -0
  68. test_modules/test_login_flow.py +50 -0
  69. test_modules/test_navigate_testing_folder.py +361 -0
  70. test_modules/test_play_store_screenshots.py +294 -0
  71. test_modules/test_terminal_buffer_performance.py +261 -0
  72. test_modules/test_terminal_interaction.py +80 -0
  73. test_modules/test_terminal_loading_race_condition.py +95 -0
  74. test_modules/test_terminal_start.py +56 -0
  75. testing_framework/.env.example +21 -0
  76. testing_framework/README.md +334 -0
  77. testing_framework/__init__.py +17 -0
  78. testing_framework/cli.py +326 -0
  79. testing_framework/core/__init__.py +1 -0
  80. testing_framework/core/base_test.py +336 -0
  81. testing_framework/core/cli_manager.py +177 -0
  82. testing_framework/core/hierarchical_runner.py +577 -0
  83. testing_framework/core/playwright_manager.py +520 -0
  84. testing_framework/core/runner.py +447 -0
  85. testing_framework/core/shared_cli_manager.py +234 -0
  86. testing_framework/core/test_discovery.py +112 -0
  87. testing_framework/requirements.txt +12 -0
  88. portacode-0.3.19.dev4.dist-info/METADATA +0 -241
  89. portacode-0.3.19.dev4.dist-info/RECORD +0 -30
  90. portacode-0.3.19.dev4.dist-info/top_level.txt +0 -1
  91. {portacode-0.3.19.dev4.dist-info → portacode-1.4.11.dev1.dist-info}/entry_points.txt +0 -0
  92. {portacode-0.3.19.dev4.dist-info → portacode-1.4.11.dev1.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,112 @@
1
+ """Test discovery and categorization system."""
2
+
3
+ import os
4
+ import importlib.util
5
+ import inspect
6
+ from pathlib import Path
7
+ from typing import List, Dict, Any, Optional, Set
8
+ import logging
9
+
10
+ from .base_test import BaseTest, TestCategory
11
+
12
+
13
+ class TestDiscovery:
14
+ """Discovers and categorizes tests from the filesystem."""
15
+
16
+ def __init__(self, test_directories: Optional[List[str]] = None):
17
+ self.test_directories = test_directories or ["tests", "test_modules"]
18
+ self.logger = logging.getLogger("test_discovery")
19
+ self.logger.setLevel(logging.ERROR) # Show errors during discovery
20
+ self.discovered_tests: Dict[str, BaseTest] = {}
21
+
22
+ def discover_tests(self, base_path: str = ".") -> Dict[str, BaseTest]:
23
+ """Discover all test classes in the specified directories."""
24
+ base_path = Path(base_path)
25
+ self.discovered_tests = {}
26
+
27
+ for test_dir in self.test_directories:
28
+ test_path = base_path / test_dir
29
+ if test_path.exists() and test_path.is_dir():
30
+ self.logger.info(f"Discovering tests in: {test_path}")
31
+ self._discover_in_directory(test_path)
32
+
33
+ self.logger.info(f"Discovered {len(self.discovered_tests)} tests")
34
+ return self.discovered_tests
35
+
36
+ def _discover_in_directory(self, directory: Path):
37
+ """Recursively discover tests in a directory."""
38
+ for item in directory.rglob("*.py"):
39
+ if item.name.startswith("test_") or item.name.endswith("_test.py"):
40
+ self._discover_in_file(item)
41
+
42
+ def _discover_in_file(self, file_path: Path):
43
+ """Discover test classes in a Python file."""
44
+ try:
45
+ # Load the module
46
+ spec = importlib.util.spec_from_file_location("test_module", file_path)
47
+ if spec and spec.loader:
48
+ module = importlib.util.module_from_spec(spec)
49
+ spec.loader.exec_module(module)
50
+
51
+ # Find test classes
52
+ for name, obj in inspect.getmembers(module):
53
+ if (inspect.isclass(obj) and
54
+ issubclass(obj, BaseTest) and
55
+ obj is not BaseTest):
56
+
57
+ # Instantiate the test class
58
+ try:
59
+ test_instance = obj()
60
+ self.discovered_tests[test_instance.name] = test_instance
61
+ self.logger.debug(f"Discovered test: {test_instance.name}")
62
+ except Exception as e:
63
+ error_msg = f"Failed to instantiate test {name} in {file_path}: {e}"
64
+ self.logger.error(error_msg)
65
+ print(f"❌ {error_msg}") # Also print to console for immediate visibility
66
+
67
+ except Exception as e:
68
+ error_msg = f"Failed to load test file {file_path}: {e}"
69
+ self.logger.error(error_msg)
70
+ print(f"❌ {error_msg}") # Also print to console for immediate visibility
71
+
72
+ def get_tests_by_category(self, category: TestCategory) -> List[BaseTest]:
73
+ """Get all tests belonging to a specific category."""
74
+ return [test for test in self.discovered_tests.values()
75
+ if test.category == category]
76
+
77
+ def get_tests_by_tags(self, tags: Set[str]) -> List[BaseTest]:
78
+ """Get all tests that have any of the specified tags."""
79
+ return [test for test in self.discovered_tests.values()
80
+ if any(tag in test.tags for tag in tags)]
81
+
82
+ def get_tests_by_name_pattern(self, pattern: str) -> List[BaseTest]:
83
+ """Get all tests whose names match the pattern."""
84
+ import re
85
+ regex = re.compile(pattern, re.IGNORECASE)
86
+ return [test for test in self.discovered_tests.values()
87
+ if regex.search(test.name)]
88
+
89
+ def list_all_categories(self) -> Set[TestCategory]:
90
+ """Get all categories found in discovered tests."""
91
+ return {test.category for test in self.discovered_tests.values()}
92
+
93
+ def list_all_tags(self) -> Set[str]:
94
+ """Get all tags found in discovered tests."""
95
+ all_tags = set()
96
+ for test in self.discovered_tests.values():
97
+ all_tags.update(test.tags)
98
+ return all_tags
99
+
100
+ def get_test_info(self) -> Dict[str, Dict[str, Any]]:
101
+ """Get detailed information about all discovered tests."""
102
+ info = {}
103
+ for name, test in self.discovered_tests.items():
104
+ info[name] = {
105
+ "name": test.name,
106
+ "category": test.category.value,
107
+ "description": test.description,
108
+ "tags": test.tags,
109
+ "class_name": test.__class__.__name__,
110
+ "module": test.__class__.__module__
111
+ }
112
+ return info
@@ -0,0 +1,12 @@
1
+ # Testing Framework Dependencies
2
+
3
+ # Core testing framework dependencies
4
+ playwright>=1.40.0
5
+ click>=8.1.0
6
+
7
+ # Optional: For environment variable management
8
+ python-dotenv>=1.0.0
9
+
10
+ # Development dependencies (optional)
11
+ pytest>=7.0.0
12
+ pytest-asyncio>=0.21.0
@@ -1,241 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: portacode
3
- Version: 0.3.19.dev4
4
- Summary: Portacode CLI client and SDK
5
- Home-page: https://github.com/portacode/portacode
6
- Author: Meena Erian
7
- Author-email: hi@menas.pro
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.8
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
- Requires-Dist: click>=8.0
15
- Requires-Dist: platformdirs>=3.0
16
- Requires-Dist: cryptography>=41.0
17
- Requires-Dist: websockets>=12.0
18
- Requires-Dist: pyperclip>=1.8
19
- Requires-Dist: psutil>=5.9
20
- Requires-Dist: pyte>=0.8
21
- Requires-Dist: GitPython>=3.1.45
22
- Requires-Dist: watchdog>=3.0
23
- Requires-Dist: diff-match-patch>=20230430
24
- Requires-Dist: Pygments>=2.14.0
25
- Requires-Dist: pywinpty>=2.0; platform_system == "Windows"
26
- Provides-Extra: dev
27
- Requires-Dist: black; extra == "dev"
28
- Requires-Dist: flake8; extra == "dev"
29
- Requires-Dist: pytest; extra == "dev"
30
-
31
- # Portacode
32
-
33
- **An AI-first, mobile-first IDE and admin tool, made with love and passion by software engineers, for software engineers.**
34
-
35
- Portacode transforms any computer into a remotely accessible development environment. Access your home lab from your phone, code on your desktop from anywhere, or help a colleague debug their server - all through a beautiful web interface designed for the modern developer.
36
-
37
- ## ✨ Why Portacode?
38
-
39
- - **🤖 AI-First**: Built from the ground up with AI integration in mind
40
- - **📱 Mobile-First**: Code and administrate from your phone or tablet
41
- - **🌍 Global Access**: Connect to your devices from anywhere with internet
42
- - **🔐 Secure**: HTTPS encrypted with RSA key authentication
43
- - **⚡ Fast Setup**: Get connected in under 60 seconds
44
- - **🔄 Always Connected**: Automatic reconnection and persistent service options
45
- - **🆓 Free Account**: Create your account and start connecting immediately
46
- - **🖥️ Cross-Platform**: Works on Windows, macOS, and Linux
47
-
48
- ## 🚀 Quick Start
49
-
50
- ### 1. Install Portacode
51
-
52
- ```bash
53
- pip install portacode
54
- ```
55
-
56
- ### 2. Connect Your Device
57
-
58
- ```bash
59
- portacode connect
60
- ```
61
-
62
- Follow the on-screen instructions to:
63
- - Visit [https://remote.portacode.com](https://remote.portacode.com)
64
- - Create your free account
65
- - Add your device using the generated key
66
- - Start coding and administrating!
67
-
68
- ### 3. Access Your Development Environment
69
-
70
- Once connected, you can:
71
- - Open terminal sessions from the web dashboard
72
- - Execute commands remotely
73
- - Monitor system status
74
- - Access your development environment from any device
75
-
76
- ## 💡 Use Cases
77
-
78
- ### Remote Development
79
- ```bash
80
- # Connect your development machine
81
- portacode connect
82
-
83
- # Now code, build, and debug from anywhere - even your phone
84
- ```
85
-
86
- ### Server Administration
87
- ```bash
88
- # For a persistent connection, install system-wide first
89
- sudo pip install portacode --system
90
-
91
- # Then install as a service
92
- sudo portacode service install
93
-
94
- # Your server is now accessible 24/7 from the web dashboard
95
- ```
96
-
97
- ### Mobile Development
98
- ```bash
99
- # Connect your desktop/laptop
100
- portacode connect
101
-
102
- # Code on-the-go from your mobile device with a full IDE experience
103
- ```
104
-
105
- ### Team Collaboration
106
- ```bash
107
- # Connect shared development environments
108
- portacode connect
109
-
110
- # Enable team members to access shared resources securely
111
- ```
112
-
113
- ## 🔧 Essential Commands
114
-
115
- ### Basic Usage
116
- ```bash
117
- # Start a connection (runs until closed)
118
- portacode connect
119
-
120
- # Run connection in background
121
- portacode connect --detach
122
-
123
- # Check version
124
- portacode --version
125
-
126
- # Get help
127
- portacode --help
128
- ```
129
-
130
- ### Service Management
131
- ```bash
132
- # For system services, install package system-wide first
133
- sudo pip install portacode --system
134
-
135
- # Install persistent service (auto-start on boot)
136
- sudo portacode service install
137
-
138
- # Check service status
139
- sudo portacode service status
140
-
141
- # Stop the service
142
- sudo portacode service stop
143
-
144
- # Remove the service
145
- sudo portacode service uninstall
146
- ```
147
-
148
- ## 🌐 Web Dashboard
149
-
150
- Access your connected devices at [https://remote.portacode.com](https://remote.portacode.com)
151
-
152
- **Current Features:**
153
- - Real-time terminal access
154
- - System monitoring
155
- - Device management
156
- - Multi-device switching
157
- - Secure authentication
158
-
159
- **Coming Soon:**
160
- - AI-powered code assistance
161
- - Mobile-optimized IDE interface
162
- - File management and editing
163
- - Collaborative development tools
164
-
165
- ## 🔐 Security
166
-
167
- - **RSA Key Authentication**: Each device gets a unique RSA key pair
168
- - **HTTPS Encrypted**: All communication is encrypted in transit
169
- - **No Passwords**: Key-based authentication eliminates password risks
170
- - **Revocable Access**: Remove devices instantly from the web dashboard
171
- - **Local Key Storage**: Private keys never leave your device
172
-
173
- ## 🆘 Troubleshooting
174
-
175
- ### Connection Issues
176
- ```bash
177
- # Check if another connection is running
178
- portacode connect
179
-
180
- # View service logs
181
- sudo portacode service status --verbose
182
- ```
183
-
184
- ### Service Installation Issues
185
- ```bash
186
- # If service commands fail, ensure system-wide installation
187
- sudo pip install portacode --system
188
-
189
- # Then try service installation again
190
- sudo portacode service install
191
- ```
192
-
193
- ### Clipboard Issues (Linux)
194
- ```bash
195
- # Install clipboard support
196
- sudo apt-get install xclip
197
- ```
198
-
199
- ### Key Management
200
- Key files are stored in:
201
- - **Linux**: `~/.local/share/portacode/keys/`
202
- - **macOS**: `~/Library/Application Support/portacode/keys/`
203
- - **Windows**: `%APPDATA%\portacode\keys\`
204
-
205
- ## 🌱 Early Stage Project
206
-
207
- **Portacode is a young project with big dreams.** We're building the future of remote development and mobile-first coding experiences. As a new project, we're actively seeking:
208
-
209
- - **👥 Community Feedback**: Does this solve a real problem for you?
210
- - **🤝 Contributors**: Help us build the IDE of the future
211
- - **📢 Early Adopters**: Try it out and let us know what you think
212
- - **💡 Feature Ideas**: What would make your remote development workflow better?
213
-
214
- **Your support matters!** Whether you contribute code, report bugs, share ideas, or simply let us know that you find value in what we're building - every bit of feedback helps us decide whether to continue investing in this vision or focus on other projects.
215
-
216
- ## 📞 Get In Touch
217
-
218
- - **Email**: hi@menas.pro
219
- - **Support**: support@portacode.com
220
- - **GitHub**: [https://github.com/portacode/portacode](https://github.com/portacode/portacode)
221
-
222
- ## 🤝 Contributing
223
-
224
- We welcome all forms of contribution:
225
- - 🐛 **Bug Reports**: Found something broken? Let us know!
226
- - ✨ **Feature Requests**: What would make Portacode better for you?
227
- - 📖 **Documentation**: Help others get started
228
- - 💻 **Code Contributions**: Help us build the future of remote development
229
- - 💬 **Feedback**: Tell us if you find this useful!
230
-
231
- Check out our [GitHub repository](https://github.com/portacode/portacode) to get started.
232
-
233
- ## 📄 License
234
-
235
- MIT License - see [LICENSE](LICENSE) file for details.
236
-
237
- ---
238
-
239
- **Get started today**: `pip install portacode && portacode connect`
240
-
241
- *Built with ❤️ and ☕ by passionate software engineers*
@@ -1,30 +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=WBFgD85Z3qa-RLtzswkobBLkYm8VpzVhGWzklECzwl0,526
5
- portacode/cli.py,sha256=Zb2XjPsfomFsgIudYiuL2AYXqSDqmj8vJDQzsAMiyYY,15218
6
- portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
7
- portacode/keypair.py,sha256=PAcOYqlVLOoZTPYi6LvLjfsY6BkrWbLOhSZLb8r5sHs,3635
8
- portacode/service.py,sha256=p-HHMOAl20QsdcJydcZ74Iqes-wl8G8HItdSim30pUk,16537
9
- portacode/connection/README.md,sha256=f9rbuIEKa7cTm9C98rCiBbEtbiIXQU11esGSNhSMiJg,883
10
- portacode/connection/__init__.py,sha256=atqcVGkViIEd7pRa6cP2do07RJOM0UWpbnz5zXjGktU,250
11
- portacode/connection/client.py,sha256=pjAcsgPIwtvUs0AL2XiqoFeaQxQjHTvWP8cZZj8ooN4,7821
12
- portacode/connection/multiplex.py,sha256=P3jMo-Wm-RWpQ_aV1d73z8wWzjUvRfCZTmceWdkScYc,2087
13
- portacode/connection/terminal.py,sha256=ao1t5kMdERgLpHyKzPL2DCVaVGQ0mpXppXhXNB0vO1E,33573
14
- portacode/connection/handlers/README.md,sha256=HsLZG1QK1JNm67HsgL6WoDg9nxzKXxwkc5fJPFJdX5g,12169
15
- portacode/connection/handlers/WEBSOCKET_PROTOCOL.md,sha256=P07JUAhO26fIaSB8QodKaytMR8dnGoATZD19jjbEAns,40839
16
- portacode/connection/handlers/__init__.py,sha256=5d0RiFKTVhJNdBhricvLHmU9VanhMp8XrlD6XkHE2BI,1586
17
- portacode/connection/handlers/base.py,sha256=VCu8UO7sf_G3a-YyeE4ZTH8u83ZEcgNZY7Y7-y3Gv1M,6405
18
- portacode/connection/handlers/file_handlers.py,sha256=LQVavJTAFy9xaINRYUN5qSCiavfZf0sVhUz5ZHILju0,7095
19
- portacode/connection/handlers/project_state_handlers.py,sha256=MS0YZ_SAiPcs6Iwla4vHWaVGxvciDZMfwGRSpPz2MCk,97606
20
- portacode/connection/handlers/registry.py,sha256=ebi0vhR1XXSYU7mJXlQJ4MjBYaMygGYqX7ReK7vsZ7o,5558
21
- portacode/connection/handlers/session.py,sha256=_DQWAXdzhpLxl8k7LFGc9RsGNGHTJMyI73rGOzqXMjc,22574
22
- portacode/connection/handlers/system_handlers.py,sha256=65V5ctT0dIBc-oWG91e62MbdvU0z6x6JCTQuIqCWmZ0,5242
23
- portacode/connection/handlers/tab_factory.py,sha256=nKZ-Y3OHwzOU6aG_zLarLKwhJOHeSszPLCLDVuAgQ94,15494
24
- portacode/connection/handlers/terminal_handlers.py,sha256=Yuo84zwKB5OiLuVtDLCQgMVrOS3T8ZOONxXpGnnougo,11019
25
- portacode-0.3.19.dev4.dist-info/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
26
- portacode-0.3.19.dev4.dist-info/METADATA,sha256=oT5w5ZBFtqsFKhE22_F851xyWLbop4w3KcU0Wu5EYGw,6935
27
- portacode-0.3.19.dev4.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
28
- portacode-0.3.19.dev4.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
29
- portacode-0.3.19.dev4.dist-info/top_level.txt,sha256=U_n6hYjK7CBYFzYluuG-AP8UouIIQLCObIj6-WtG3Go,10
30
- portacode-0.3.19.dev4.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- portacode