portacode 0.3.24__py3-none-any.whl → 0.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 +2 -2
- portacode/connection/handlers/session.py +28 -1
- portacode/connection/terminal.py +13 -4
- {portacode-0.3.24.dist-info → portacode-0.3.25.dist-info}/METADATA +1 -1
- {portacode-0.3.24.dist-info → portacode-0.3.25.dist-info}/RECORD +9 -9
- {portacode-0.3.24.dist-info → portacode-0.3.25.dist-info}/WHEEL +0 -0
- {portacode-0.3.24.dist-info → portacode-0.3.25.dist-info}/entry_points.txt +0 -0
- {portacode-0.3.24.dist-info → portacode-0.3.25.dist-info}/licenses/LICENSE +0 -0
- {portacode-0.3.24.dist-info → portacode-0.3.25.dist-info}/top_level.txt +0 -0
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.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
31
|
+
__version__ = version = '0.3.25'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 25)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -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."""
|
portacode/connection/terminal.py
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
762
|
-
|
|
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,7 +1,7 @@
|
|
|
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
|
|
4
|
+
portacode/_version.py,sha256=hLpn_M2C5NIFPhfMSw9x0kkUzdCUeI3MFt6ODjxDxdA,706
|
|
5
5
|
portacode/cli.py,sha256=Fcz8aXhgKhoWR9UbtmkN843DVuoJZtCTqBF3K-neVSc,16347
|
|
6
6
|
portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
|
|
7
7
|
portacode/keypair.py,sha256=PAcOYqlVLOoZTPYi6LvLjfsY6BkrWbLOhSZLb8r5sHs,3635
|
|
@@ -11,7 +11,7 @@ portacode/connection/README.md,sha256=f9rbuIEKa7cTm9C98rCiBbEtbiIXQU11esGSNhSMiJ
|
|
|
11
11
|
portacode/connection/__init__.py,sha256=atqcVGkViIEd7pRa6cP2do07RJOM0UWpbnz5zXjGktU,250
|
|
12
12
|
portacode/connection/client.py,sha256=tEM4rqzCRxIG5WXqYAT7s65NlEX2Z1sW42GosctBHIA,8013
|
|
13
13
|
portacode/connection/multiplex.py,sha256=L-TxqJ_ZEbfNEfu1cwxgJ5vUdyRzZjsMy2Kx1diiZys,5237
|
|
14
|
-
portacode/connection/terminal.py,sha256=
|
|
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=
|
|
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.
|
|
36
|
+
portacode-0.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.
|
|
62
|
-
portacode-0.3.
|
|
63
|
-
portacode-0.3.
|
|
64
|
-
portacode-0.3.
|
|
65
|
-
portacode-0.3.
|
|
61
|
+
portacode-0.3.25.dist-info/METADATA,sha256=cUX77zERmm5WZHrmzV1z52TAEJi8HPP4D31wNdbEXuM,7173
|
|
62
|
+
portacode-0.3.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
63
|
+
portacode-0.3.25.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
64
|
+
portacode-0.3.25.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
65
|
+
portacode-0.3.25.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|