portacode 0.3.24__py3-none-any.whl → 1.3.25__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.
portacode/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.3.24'
32
- __version_tuple__ = version_tuple = (0, 3, 24)
31
+ __version__ = version = '1.3.25'
32
+ __version_tuple__ = version_tuple = (1, 3, 25)
33
33
 
34
34
  __commit_id__ = commit_id = None
portacode/cli.py CHANGED
@@ -16,7 +16,7 @@ from .data import get_pid_file, is_process_running
16
16
  from .keypair import get_or_create_keypair, fingerprint_public_key
17
17
  from .connection.client import ConnectionManager, run_until_interrupt
18
18
 
19
- GATEWAY_URL = "wss://device.portacode.com/gateway"
19
+ GATEWAY_URL = "wss://portacode.com/gateway"
20
20
  GATEWAY_ENV = "PORTACODE_GATEWAY"
21
21
 
22
22
 
@@ -115,7 +115,7 @@ def connect(gateway: str | None, detach: bool, debug: bool, log_categories: str
115
115
  click.echo(click.style("🚀 Welcome to Portacode!", fg="bright_blue", bold=True))
116
116
  click.echo()
117
117
  click.echo(click.style("📱 Next steps:", fg="bright_cyan", bold=True))
118
- click.echo(click.style(" 1. Visit ", fg="white") + click.style("https://remote.portacode.com", fg="bright_blue", underline=True))
118
+ click.echo(click.style(" 1. Visit ", fg="white") + click.style("https://portacode.com", fg="bright_blue", underline=True))
119
119
  click.echo(click.style(" 2. Create your free account or sign in", fg="white"))
120
120
  click.echo(click.style(" 3. Add this device using the key below", fg="white"))
121
121
  click.echo()
@@ -25,7 +25,7 @@ class ConnectionManager:
25
25
  Parameters
26
26
  ----------
27
27
  gateway_url: str
28
- WebSocket URL, e.g. ``wss://device.portacode.com/gateway``
28
+ WebSocket URL, e.g. ``wss://portacode.com/gateway``
29
29
  keypair: KeyPair
30
30
  User's public/private keypair used for authentication.
31
31
  reconnect_delay: float
@@ -161,6 +161,10 @@ class TerminalSession:
161
161
  async def _send_terminal_data_now(self, data: str) -> None:
162
162
  """Send terminal data immediately and update last send time."""
163
163
  self._last_send_time = time.time()
164
+ data_size = len(data.encode('utf-8'))
165
+
166
+ logger.info("session: Attempting to send terminal_data for terminal %s (data_size=%d bytes)",
167
+ self.id, data_size)
164
168
 
165
169
  # Add to buffer for snapshots with size limiting
166
170
  self._add_to_buffer(data)
@@ -174,18 +178,25 @@ class TerminalSession:
174
178
  "data": data,
175
179
  "project_id": self.project_id
176
180
  }, project_id=self.project_id)
181
+ logger.info("session: Successfully queued terminal_data for terminal %s via terminal_manager", self.id)
177
182
  else:
178
183
  # Fallback to raw channel for backward compatibility
179
184
  await self.channel.send(data)
185
+ logger.info("session: Successfully sent terminal_data for terminal %s via raw channel", self.id)
180
186
  except Exception as exc:
181
- logger.warning("Failed to forward terminal output: %s", exc)
187
+ logger.warning("session: Failed to forward terminal output for terminal %s: %s", self.id, exc)
182
188
 
183
189
  async def _flush_pending_data(self) -> None:
184
190
  """Send accumulated pending data and reset pending buffer."""
185
191
  if self._pending_data:
192
+ pending_size = len(self._pending_data.encode('utf-8'))
193
+ logger.info("session: Flushing pending terminal_data for terminal %s (pending_size=%d bytes)",
194
+ self.id, pending_size)
186
195
  data_to_send = self._pending_data
187
196
  self._pending_data = ""
188
197
  await self._send_terminal_data_now(data_to_send)
198
+ else:
199
+ logger.debug("session: No pending data to flush for terminal %s", self.id)
189
200
 
190
201
  # Clear the debounce task
191
202
  self._debounce_task = None
@@ -194,6 +205,10 @@ class TerminalSession:
194
205
  """Handle new terminal data with rate limiting and debouncing."""
195
206
  current_time = time.time()
196
207
  time_since_last_send = (current_time - self._last_send_time) * 1000 # Convert to milliseconds
208
+ data_size = len(data.encode('utf-8'))
209
+
210
+ logger.info("session: Received terminal_data for terminal %s (data_size=%d bytes, time_since_last_send=%.1fms)",
211
+ self.id, data_size, time_since_last_send)
197
212
 
198
213
  # Add new data to pending buffer with simple size limiting
199
214
  # Always add the new data first
@@ -202,15 +217,19 @@ class TerminalSession:
202
217
  # Simple size limiting - only trim if we exceed the 30KB limit significantly
203
218
  pending_size = len(self._pending_data.encode('utf-8'))
204
219
  if pending_size > TERMINAL_BUFFER_SIZE_LIMIT_BYTES:
220
+ logger.info("session: Buffer size limit exceeded for terminal %s (pending_size=%d bytes, limit=%d bytes), trimming",
221
+ self.id, pending_size, TERMINAL_BUFFER_SIZE_LIMIT_BYTES)
205
222
  # Only do minimal ANSI-safe trimming from the beginning
206
223
  excess_bytes = pending_size - TERMINAL_BUFFER_SIZE_LIMIT_BYTES
207
224
  trim_pos = self._find_minimal_safe_trim_position(excess_bytes)
208
225
 
209
226
  if trim_pos > 0:
210
227
  self._pending_data = self._pending_data[trim_pos:]
228
+ logger.info("session: Trimmed %d bytes from pending buffer for terminal %s", trim_pos, self.id)
211
229
 
212
230
  # Cancel existing debounce task if any
213
231
  if self._debounce_task and not self._debounce_task.done():
232
+ logger.debug("session: Cancelling existing debounce task for terminal %s", self.id)
214
233
  self._debounce_task.cancel()
215
234
 
216
235
  # Always set up a debounce timer to catch rapid consecutive outputs
@@ -219,19 +238,27 @@ class TerminalSession:
219
238
  if time_since_last_send >= TERMINAL_DATA_RATE_LIMIT_MS:
220
239
  # Enough time has passed since last send, wait initial delay for more data
221
240
  wait_time = TERMINAL_DATA_INITIAL_WAIT_MS / 1000
241
+ logger.info("session: Rate limit satisfied for terminal %s, waiting %.1fms for more data",
242
+ self.id, wait_time * 1000)
222
243
  else:
223
244
  # Too soon since last send, wait for either the rate limit period or max wait time
224
245
  wait_time = min(
225
246
  (TERMINAL_DATA_RATE_LIMIT_MS - time_since_last_send) / 1000,
226
247
  TERMINAL_DATA_MAX_WAIT_MS / 1000
227
248
  )
249
+ logger.info("session: Rate limit active for terminal %s, waiting %.1fms before send (time_since_last=%.1fms, rate_limit=%dms)",
250
+ self.id, wait_time * 1000, time_since_last_send, TERMINAL_DATA_RATE_LIMIT_MS)
251
+
228
252
  await asyncio.sleep(wait_time)
253
+ logger.info("session: Debounce timer expired for terminal %s, flushing pending data", self.id)
229
254
  await self._flush_pending_data()
230
255
  except asyncio.CancelledError:
256
+ logger.debug("session: Debounce timer cancelled for terminal %s (new data arrived)", self.id)
231
257
  # Timer was cancelled, another data event came in
232
258
  pass
233
259
 
234
260
  self._debounce_task = asyncio.create_task(_debounce_timer())
261
+ logger.info("session: Started debounce timer for terminal %s", self.id)
235
262
 
236
263
  def _find_minimal_safe_trim_position(self, excess_bytes: int) -> int:
237
264
  """Find a minimal safe position to trim that only avoids breaking ANSI sequences."""
@@ -738,15 +738,17 @@ class TerminalManager:
738
738
  payload: The message payload to send
739
739
  project_id: Optional project filter for targeting specific sessions
740
740
  """
741
+ event_type = payload.get("event", "unknown")
742
+
741
743
  # Check if there are any interested clients
742
744
  if not self._client_session_manager.has_interested_clients():
743
- logger.debug("terminal_manager: No interested clients, skipping message send")
745
+ logger.info("terminal_manager: No interested clients for %s event, skipping send", event_type)
744
746
  return
745
747
 
746
748
  # Get target sessions
747
749
  target_sessions = self._client_session_manager.get_target_sessions(project_id)
748
750
  if not target_sessions:
749
- logger.debug("terminal_manager: No target sessions found, skipping message send")
751
+ logger.info("terminal_manager: No target sessions found for %s event (project_id=%s), skipping send", event_type, project_id)
750
752
  return
751
753
 
752
754
  # Add session targeting information
@@ -758,8 +760,15 @@ class TerminalManager:
758
760
  if reply_channel and "reply_channel" not in enhanced_payload:
759
761
  enhanced_payload["reply_channel"] = reply_channel
760
762
 
761
- logger.debug("terminal_manager: Sending to %d client sessions: %s",
762
- len(target_sessions), target_sessions)
763
+ # Log all event dispatches at INFO level, with data size for terminal_data
764
+ if event_type == "terminal_data":
765
+ data_size = len(payload.get("data", ""))
766
+ terminal_id = payload.get("channel", "unknown")
767
+ logger.info("terminal_manager: Dispatching %s event (terminal_id=%s, data_size=%d bytes) to %d client sessions",
768
+ event_type, terminal_id, data_size, len(target_sessions))
769
+ else:
770
+ logger.info("terminal_manager: Dispatching %s event to %d client sessions",
771
+ event_type, len(target_sessions))
763
772
 
764
773
  await self._control_channel.send(enhanced_payload)
765
774
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 0.3.24
3
+ Version: 1.3.25
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -71,7 +71,7 @@ portacode connect
71
71
  ```
72
72
 
73
73
  Follow the on-screen instructions to:
74
- - Visit [https://remote.portacode.com](https://remote.portacode.com)
74
+ - Visit [https://portacode.com](https://portacode.com)
75
75
  - Create your free account
76
76
  - Add your device using the generated key
77
77
  - Start coding and administrating!
@@ -158,7 +158,7 @@ sudo portacode service uninstall
158
158
 
159
159
  ## 🌐 Web Dashboard
160
160
 
161
- Access your connected devices at [https://remote.portacode.com](https://remote.portacode.com)
161
+ Access your connected devices at [https://portacode.com](https://portacode.com)
162
162
 
163
163
  **Current Features:**
164
164
  - Real-time terminal access
@@ -1,17 +1,17 @@
1
1
  portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
2
2
  portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
3
3
  portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
4
- portacode/_version.py,sha256=-sGbc_e4_IvCzq_UpGJECDvP_BbU_Ba1ROhJvn2pYYU,706
5
- portacode/cli.py,sha256=Fcz8aXhgKhoWR9UbtmkN843DVuoJZtCTqBF3K-neVSc,16347
4
+ portacode/_version.py,sha256=MS6U6SQUT3lPD_MWBRk6h6SwVr6EqudB5Gwbav4F8Us,706
5
+ portacode/cli.py,sha256=eDqcZMVFHKzqqWxedhhx8ylu5WMVCLqeJQkbPR7RcJE,16333
6
6
  portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
7
7
  portacode/keypair.py,sha256=PAcOYqlVLOoZTPYi6LvLjfsY6BkrWbLOhSZLb8r5sHs,3635
8
8
  portacode/logging_categories.py,sha256=9m-BYrjyHh1vjZYBQT4JhAh6b_oYUhIWayO-noH1cSE,5063
9
9
  portacode/service.py,sha256=p-HHMOAl20QsdcJydcZ74Iqes-wl8G8HItdSim30pUk,16537
10
10
  portacode/connection/README.md,sha256=f9rbuIEKa7cTm9C98rCiBbEtbiIXQU11esGSNhSMiJg,883
11
11
  portacode/connection/__init__.py,sha256=atqcVGkViIEd7pRa6cP2do07RJOM0UWpbnz5zXjGktU,250
12
- portacode/connection/client.py,sha256=tEM4rqzCRxIG5WXqYAT7s65NlEX2Z1sW42GosctBHIA,8013
12
+ portacode/connection/client.py,sha256=P5ubshMFbyV8PkGZxU2o_70gIYEy3Pv_R5blmF2ylWs,8006
13
13
  portacode/connection/multiplex.py,sha256=L-TxqJ_ZEbfNEfu1cwxgJ5vUdyRzZjsMy2Kx1diiZys,5237
14
- portacode/connection/terminal.py,sha256=OfjOjybC2RRrj_a3Eq17qVFF9mD1GlMn7l_O-mIcvIs,41716
14
+ portacode/connection/terminal.py,sha256=euST6O_3hm9qsBk52xTXORTKfKqsMYnTHuZjvlitYSE,42307
15
15
  portacode/connection/handlers/README.md,sha256=HsLZG1QK1JNm67HsgL6WoDg9nxzKXxwkc5fJPFJdX5g,12169
16
16
  portacode/connection/handlers/WEBSOCKET_PROTOCOL.md,sha256=0KBoJzqemXbvpu8Ps7LitLwRYhJNtzcTJ5WAHMGgAuc,62509
17
17
  portacode/connection/handlers/__init__.py,sha256=4nv3Z4TGYjWcauKPWsbL_FbrTXApI94V7j6oiU1Vv-o,2144
@@ -21,7 +21,7 @@ portacode/connection/handlers/file_handlers.py,sha256=CGMooOrfGbKx-bHA8vr8lmPG-v
21
21
  portacode/connection/handlers/project_aware_file_handlers.py,sha256=n0M2WmBNWPwzigdIkyZiAsePUQGXVqYSsDyOxm-Nsok,9253
22
22
  portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
23
23
  portacode/connection/handlers/registry.py,sha256=ebi0vhR1XXSYU7mJXlQJ4MjBYaMygGYqX7ReK7vsZ7o,5558
24
- portacode/connection/handlers/session.py,sha256=7fHC46YXe5Q3uGxYPGpwcBaU_0eBhH4Hg8fmNVZsVmQ,24528
24
+ portacode/connection/handlers/session.py,sha256=O7TMI5cRziOiXEBWCfBshkMpEthhjvKqGL0hhNOG1wU,26716
25
25
  portacode/connection/handlers/system_handlers.py,sha256=65V5ctT0dIBc-oWG91e62MbdvU0z6x6JCTQuIqCWmZ0,5242
26
26
  portacode/connection/handlers/tab_factory.py,sha256=VBZnwtxgeNJCsfBzUjkFWAAGBdijvai4MS2dXnhFY8U,18000
27
27
  portacode/connection/handlers/terminal_handlers.py,sha256=Yuo84zwKB5OiLuVtDLCQgMVrOS3T8ZOONxXpGnnougo,11019
@@ -33,7 +33,7 @@ portacode/connection/handlers/project_state/handlers.py,sha256=nkednSbCC-0n3Ztze
33
33
  portacode/connection/handlers/project_state/manager.py,sha256=03mN0H9TqVa_ohD5U5-5ZywDGj0s8-y1IxGdb07dZn8,57636
34
34
  portacode/connection/handlers/project_state/models.py,sha256=EZTKvxHKs8QlQUbzI0u2IqfzfRRXZixUIDBwTGCJATI,4313
35
35
  portacode/connection/handlers/project_state/utils.py,sha256=LsbQr9TH9Bz30FqikmtTxco4PlB_n0kUIuPKQ6Fb_mo,1665
36
- portacode-0.3.24.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
36
+ portacode-1.3.25.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
37
37
  test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
38
38
  test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
39
39
  test_modules/test_device_online.py,sha256=yiSyVaMwKAugqIX_ZIxmLXiOlmA_8IRXiUp12YmpB98,1653
@@ -58,8 +58,8 @@ testing_framework/core/playwright_manager.py,sha256=9kGXJtRpRNEhaSlV7XVXvx4UQSHS
58
58
  testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
59
59
  testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
60
60
  testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
61
- portacode-0.3.24.dist-info/METADATA,sha256=SS67gt2k2J9c4RMudmfgmce73fY93nhqzDHdX7IDZN8,7173
62
- portacode-0.3.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
- portacode-0.3.24.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
64
- portacode-0.3.24.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
65
- portacode-0.3.24.dist-info/RECORD,,
61
+ portacode-1.3.25.dist-info/METADATA,sha256=R11jncxQlC2FC6Q71MhT59AaAxSc-krUjpJX49ZWGeE,7145
62
+ portacode-1.3.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
+ portacode-1.3.25.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
64
+ portacode-1.3.25.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
65
+ portacode-1.3.25.dist-info/RECORD,,