portacode 1.3.35__tar.gz → 1.3.36__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.
Potentially problematic release.
This version of portacode might be problematic. Click here for more details.
- {portacode-1.3.35 → portacode-1.3.36}/PKG-INFO +1 -1
- {portacode-1.3.35 → portacode-1.3.36}/portacode/_version.py +2 -2
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/git_manager.py +63 -1
- {portacode-1.3.35 → portacode-1.3.36}/portacode.egg-info/PKG-INFO +1 -1
- {portacode-1.3.35 → portacode-1.3.36}/portacode.egg-info/SOURCES.txt +3 -0
- portacode-1.3.36/todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md +1 -0
- portacode-1.3.36/todo/issues/portacode_service_silently_down.md +69 -0
- portacode-1.3.36/todo/issues/project_cpu_hotspots.md +33 -0
- {portacode-1.3.35 → portacode-1.3.36}/.claude/agents/communication-manager.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/.claude/settings.local.json +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/.gitignore +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/.gitmodules +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/LICENSE +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/MANIFEST.in +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/Makefile +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/backup.sh +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/connect.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/connect.sh +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/docker-compose.yaml +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/__main__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/cli.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/client.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/base.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/chunked_content.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/file_handlers.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/handlers.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/manager.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/models.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/utils.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state_handlers.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/registry.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/session.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/system_handlers.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/tab_factory.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/terminal_handlers.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/multiplex.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/connection/terminal.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/data.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/keypair.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/logging_categories.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/service.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/static/js/test-ntp-clock.html +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/static/js/utils/ntp-clock.js +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/utils/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode/utils/ntp_clock.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode.egg-info/dependency_links.txt +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode.egg-info/entry_points.txt +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode.egg-info/requires.txt +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/portacode.egg-info/top_level.txt +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/pyproject.toml +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/restore.sh +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/run_tests.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/setup.cfg +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/setup.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test.sh +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_device_online.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_file_operations.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_git_status_ui.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_login_flow.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_navigate_testing_folder.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_terminal_buffer_performance.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_terminal_interaction.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_terminal_loading_race_condition.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_modules/test_terminal_start.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/test_request_id.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/.env.example +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/README.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/cli.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/__init__.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/base_test.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/cli_manager.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/hierarchical_runner.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/playwright_manager.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/runner.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/shared_cli_manager.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/core/test_discovery.py +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/testing_framework/requirements.txt +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/todo/agent_context_management.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/todo/issues/device_performance_degradation.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/todo/issues/indefinite_resource_loading.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/todo/issues/premature_terminal_exit.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/todo/issues/terminals_exit_upon_starting.md +0 -0
- {portacode-1.3.35 → portacode-1.3.36}/tools/test_python_ntp_clock.py +0 -0
|
@@ -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 = '1.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 3,
|
|
31
|
+
__version__ = version = '1.3.36'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 3, 36)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
{portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/git_manager.py
RENAMED
|
@@ -61,6 +61,9 @@ class GitManager:
|
|
|
61
61
|
self.is_git_repo = False
|
|
62
62
|
self._change_callback = change_callback
|
|
63
63
|
|
|
64
|
+
# Track git processes spawned by this specific GitManager instance
|
|
65
|
+
self._tracked_git_processes = set()
|
|
66
|
+
|
|
64
67
|
# Periodic monitoring attributes
|
|
65
68
|
self._monitoring_task: Optional[asyncio.Task] = None
|
|
66
69
|
self._cached_status_summary: Optional[Dict[str, int]] = None
|
|
@@ -84,9 +87,29 @@ class GitManager:
|
|
|
84
87
|
self.repo = Repo(self.project_path)
|
|
85
88
|
self.is_git_repo = True
|
|
86
89
|
logger.info("Initialized Git repo for project: %s", self.project_path)
|
|
90
|
+
|
|
91
|
+
# Track initial git processes after repo creation
|
|
92
|
+
self._track_current_git_processes()
|
|
93
|
+
|
|
87
94
|
except (InvalidGitRepositoryError, Exception) as e:
|
|
88
95
|
logger.debug("Not a Git repository or Git error: %s", e)
|
|
89
96
|
|
|
97
|
+
def _track_current_git_processes(self):
|
|
98
|
+
"""Track currently running git cat-file processes for this repo."""
|
|
99
|
+
try:
|
|
100
|
+
import psutil
|
|
101
|
+
for proc in psutil.process_iter(['pid', 'cmdline', 'cwd']):
|
|
102
|
+
try:
|
|
103
|
+
cmdline = proc.info['cmdline']
|
|
104
|
+
if (cmdline and len(cmdline) >= 2 and
|
|
105
|
+
'git' in cmdline[0] and 'cat-file' in cmdline[1] and
|
|
106
|
+
proc.info['cwd'] == self.project_path):
|
|
107
|
+
self._tracked_git_processes.add(proc.pid)
|
|
108
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
109
|
+
continue
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.debug("Error tracking git processes: %s", e)
|
|
112
|
+
|
|
90
113
|
def reinitialize(self):
|
|
91
114
|
"""Reinitialize git repo detection (useful when .git directory is created after initialization)."""
|
|
92
115
|
logger.info("Reinitializing git repo detection for: %s", self.project_path)
|
|
@@ -1933,4 +1956,43 @@ class GitManager:
|
|
|
1933
1956
|
def cleanup(self):
|
|
1934
1957
|
"""Cleanup resources when GitManager is being destroyed."""
|
|
1935
1958
|
logger.info("Cleaning up GitManager for %s", self.project_path)
|
|
1936
|
-
self.stop_periodic_monitoring()
|
|
1959
|
+
self.stop_periodic_monitoring()
|
|
1960
|
+
|
|
1961
|
+
# CRITICAL: Close GitPython repo to cleanup git cat-file processes
|
|
1962
|
+
if self.repo:
|
|
1963
|
+
try:
|
|
1964
|
+
# Force cleanup of git command processes
|
|
1965
|
+
if hasattr(self.repo.git, 'clear_cache'):
|
|
1966
|
+
self.repo.git.clear_cache()
|
|
1967
|
+
self.repo.close()
|
|
1968
|
+
logger.info("Successfully closed GitPython repo for %s", self.project_path)
|
|
1969
|
+
except Exception as e:
|
|
1970
|
+
logger.warning("Error during git repo cleanup for %s: %s", self.project_path, e)
|
|
1971
|
+
finally:
|
|
1972
|
+
self.repo = None
|
|
1973
|
+
|
|
1974
|
+
# Clean up only the git processes tracked by this specific GitManager instance
|
|
1975
|
+
try:
|
|
1976
|
+
import psutil
|
|
1977
|
+
killed_count = 0
|
|
1978
|
+
|
|
1979
|
+
for pid in list(self._tracked_git_processes):
|
|
1980
|
+
try:
|
|
1981
|
+
proc = psutil.Process(pid)
|
|
1982
|
+
if proc.is_running():
|
|
1983
|
+
proc.terminate()
|
|
1984
|
+
killed_count += 1
|
|
1985
|
+
logger.info("Terminated tracked git process %d", pid)
|
|
1986
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
1987
|
+
pass
|
|
1988
|
+
finally:
|
|
1989
|
+
self._tracked_git_processes.discard(pid)
|
|
1990
|
+
|
|
1991
|
+
if killed_count > 0:
|
|
1992
|
+
logger.info("Cleaned up %d tracked git processes for session", killed_count)
|
|
1993
|
+
|
|
1994
|
+
except Exception as e:
|
|
1995
|
+
logger.warning("Error cleaning up tracked git processes: %s", e)
|
|
1996
|
+
|
|
1997
|
+
# Clear the tracking set
|
|
1998
|
+
self._tracked_git_processes.clear()
|
|
@@ -87,9 +87,12 @@ testing_framework/core/runner.py
|
|
|
87
87
|
testing_framework/core/shared_cli_manager.py
|
|
88
88
|
testing_framework/core/test_discovery.py
|
|
89
89
|
todo/agent_context_management.md
|
|
90
|
+
todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md
|
|
90
91
|
todo/issues/device_performance_degradation.md
|
|
91
92
|
todo/issues/git_data_not_captured_in_proxmox.md
|
|
92
93
|
todo/issues/indefinite_resource_loading.md
|
|
94
|
+
todo/issues/portacode_service_silently_down.md
|
|
93
95
|
todo/issues/premature_terminal_exit.md
|
|
96
|
+
todo/issues/project_cpu_hotspots.md
|
|
94
97
|
todo/issues/terminals_exit_upon_starting.md
|
|
95
98
|
tools/test_python_ntp_clock.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
In desktop or big screens, the project workspace allows the user to squeeze the code editor unill it's fully collapsed and not visible. When it's in that state and then the user attempts to open a file, visually, it looks like nothing happended even though the file tab was already opened but in the collapsed editor. This can be confusing for users and in such scenario, opening any new tabs in the code editor should automatically expand the code editor and make it visible.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
Frequency of reoccurence: Rare
|
|
4
|
+
Importance: Critical
|
|
5
|
+
|
|
6
|
+
The issue has been happening with recent versions of portacode, probably after adding handlers for search_project_files and read_project_file where the service will be running and the command "portacode service status" shows "Service status: active" and in verbose mode, here's the output:
|
|
7
|
+
|
|
8
|
+
menas@portacode-streamer:~/portacode$ portacode service status -v
|
|
9
|
+
Service status: active
|
|
10
|
+
|
|
11
|
+
--- system output ---
|
|
12
|
+
● portacode.service - Portacode persistent connection (system-wide)
|
|
13
|
+
Loaded: loaded (/etc/systemd/system/portacode.service; enabled; vendor preset: enabled)
|
|
14
|
+
Active: active (running) since Tue 2025-10-28 17:20:26 UTC; 16h ago
|
|
15
|
+
Main PID: 1123848 (python3)
|
|
16
|
+
Tasks: 53 (limit: 19020)
|
|
17
|
+
Memory: 30.7M
|
|
18
|
+
CPU: 1h 19min 54.804s
|
|
19
|
+
CGroup: /system.slice/portacode.service
|
|
20
|
+
├─1123848 /usr/bin/python3 -m portacode connect --non-interactive
|
|
21
|
+
├─1124026 git cat-file --batch-check
|
|
22
|
+
├─1124106 git cat-file --batch-check
|
|
23
|
+
├─1157407 git cat-file --batch-check
|
|
24
|
+
├─1159306 git cat-file --batch-check
|
|
25
|
+
├─1160451 git cat-file --batch-check
|
|
26
|
+
├─1162408 git cat-file --batch-check
|
|
27
|
+
├─1164471 git cat-file --batch-check
|
|
28
|
+
├─1181608 git cat-file --batch-check
|
|
29
|
+
├─1192855 git cat-file --batch-check
|
|
30
|
+
└─1211883 git cat-file --batch-check
|
|
31
|
+
|
|
32
|
+
Oct 29 09:20:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
33
|
+
Oct 29 09:20:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=4.18ms, latency=7.25ms, server=time.cloudflare.com
|
|
34
|
+
Oct 29 09:25:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
35
|
+
Oct 29 09:25:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=3.51ms, latency=6.30ms, server=time.cloudflare.com
|
|
36
|
+
Oct 29 09:30:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
37
|
+
Oct 29 09:30:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=2.85ms, latency=7.06ms, server=time.cloudflare.com
|
|
38
|
+
Oct 29 09:36:40 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
39
|
+
Oct 29 09:37:59 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=10.93ms, latency=15.25ms, server=time.cloudflare.com
|
|
40
|
+
Oct 29 09:42:58 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
41
|
+
Oct 29 09:42:58 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=7.10ms, latency=5.28ms, server=time.cloudflare.com
|
|
42
|
+
|
|
43
|
+
--- recent logs ---
|
|
44
|
+
-- Logs begin at Thu 2025-10-02 13:56:04 UTC, end at Wed 2025-10-29 09:43:24 UTC. --
|
|
45
|
+
Oct 29 08:55:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
46
|
+
Oct 29 08:55:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=7.12ms, latency=9.52ms, server=time.cloudflare.com
|
|
47
|
+
Oct 29 09:00:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
48
|
+
Oct 29 09:00:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=4.70ms, latency=5.65ms, server=time.cloudflare.com
|
|
49
|
+
Oct 29 09:05:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
50
|
+
Oct 29 09:05:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=4.28ms, latency=6.05ms, server=time.cloudflare.com
|
|
51
|
+
Oct 29 09:10:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
52
|
+
Oct 29 09:10:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=1.89ms, latency=6.13ms, server=time.cloudflare.com
|
|
53
|
+
Oct 29 09:15:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
54
|
+
Oct 29 09:15:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=0.81ms, latency=6.46ms, server=time.cloudflare.com
|
|
55
|
+
Oct 29 09:20:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
56
|
+
Oct 29 09:20:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=4.18ms, latency=7.25ms, server=time.cloudflare.com
|
|
57
|
+
Oct 29 09:25:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
58
|
+
Oct 29 09:25:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=3.51ms, latency=6.30ms, server=time.cloudflare.com
|
|
59
|
+
Oct 29 09:30:43 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
60
|
+
Oct 29 09:30:43 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=2.85ms, latency=7.06ms, server=time.cloudflare.com
|
|
61
|
+
Oct 29 09:36:40 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
62
|
+
Oct 29 09:37:59 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=10.93ms, latency=15.25ms, server=time.cloudflare.com
|
|
63
|
+
Oct 29 09:42:58 portacode-streamer python3[1123848]: [INFO] 🔄 Starting periodic NTP sync...
|
|
64
|
+
Oct 29 09:42:58 portacode-streamer python3[1123848]: [INFO] ✅ NTP sync successful: offset=7.10ms, latency=5.28ms, server=time.cloudflare.com
|
|
65
|
+
|
|
66
|
+
menas@portacode-streamer:~/portacode$
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
not showing any errors, however, it got disconnected from the server and is still showing as offline on the server
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Portacode Project Connection CPU Hotspots
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
Devices spike to 100% CPU as soon as a client session connects to specific projects. The analysis below highlights the most expensive paths invoked during project onboarding and state sync, pinpointing the five most likely culprits.
|
|
5
|
+
|
|
6
|
+
## Top 5 Likely Causes
|
|
7
|
+
1. **Full project rescan on every refresh**
|
|
8
|
+
- `portacode/connection/handlers/project_state/manager.py:361` rebuilds the entire project item list on each refresh, walking every monitored directory and re-sorting the full item set.
|
|
9
|
+
- During the same pass, `git_status_map` is populated via a threadpool call into `GitManager.get_file_status_batch` (`portacode/connection/handlers/project_state/manager.py:396` → `portacode/connection/handlers/project_state/git_manager.py:295`), which shells out to several `git` commands (`status`, `diff`, `ls-files`). For large trees this keeps CPU saturated.
|
|
10
|
+
|
|
11
|
+
2. **Recursive `.git` watcher flood**
|
|
12
|
+
- Every project session starts a recursive watchdog on the `.git` directory (`portacode/connection/handlers/project_state/file_system_watcher.py:170`).
|
|
13
|
+
- The handler forwards virtually any qualifying Git event into `_handle_file_change` (`portacode/connection/handlers/project_state/manager.py:816`), which in turn calls `_refresh_project_state` (`portacode/connection/handlers/project_state/manager.py:881`).
|
|
14
|
+
- Busy repositories generate continuous `.git/objects` churn, so the device keeps re-running the heavy refresh path above even when workspace files stay untouched.
|
|
15
|
+
|
|
16
|
+
3. **Unbounded project-state initialisers**
|
|
17
|
+
- Each `client_sessions_update` spawns `_manage_project_states_for_session_changes` via `loop.create_task` without guard rails (`portacode/connection/terminal.py:96-104`).
|
|
18
|
+
- Rapid consecutive updates therefore overlap the expensive `ProjectStateManager.initialize_project_state` calls inside that coroutine (`portacode/connection/terminal.py:192` / `portacode/connection/handlers/project_state/manager.py:131`). Multiple full scans and git probes run simultaneously, pegging CPU.
|
|
19
|
+
|
|
20
|
+
4. **Per-session git monitoring loops**
|
|
21
|
+
- A fresh `GitManager` is created for every client session, even when they point at the same project folder (`portacode/connection/handlers/project_state/manager.py:146-155`).
|
|
22
|
+
- Each instance schedules its own `_monitor_git_changes` loop (`portacode/connection/handlers/project_state/git_manager.py:1803` → `portacode/connection/handlers/project_state/git_manager.py:1843`) that executes `git status`, `git diff` and related commands every five seconds. With multiple viewers attached to a large repo, these redundant polls easily saturate CPU.
|
|
23
|
+
|
|
24
|
+
5. **Hashing every changed file on each update**
|
|
25
|
+
- `_refresh_project_state` refreshes `git_detailed_status` for every run (`portacode/connection/handlers/project_state/manager.py:905-912`).
|
|
26
|
+
- `GitManager.get_detailed_status` (`portacode/connection/handlers/project_state/git_manager.py:1187-1292`) computes SHA hashes for each staged, unstaged and untracked file by reading their full contents. When sizeable files change—or when the refresh path is invoked frequently via the `.git` watcher above—this repeated hashing drives sustained CPU usage.
|
|
27
|
+
|
|
28
|
+
## Recommended Next Steps
|
|
29
|
+
- Introduce incremental diffing (e.g., track dirty directories) so `_build_flattened_items_structure` only touches changed paths.
|
|
30
|
+
- Throttle or narrow `.git` monitoring (consider ignoring `objects/` and batching events).
|
|
31
|
+
- Debounce `client_sessions_update` orchestration so only one state-initialisation task can run per session/project at a time.
|
|
32
|
+
- Promote `GitManager` to be shared per project/root and pause the periodic monitor when no deltas are detected.
|
|
33
|
+
- Cache git detailed status / file hashes and invalidate selectively instead of recomputing every refresh.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_aware_file_handlers.py
RENAMED
|
File without changes
|
|
File without changes
|
{portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/handlers.py
RENAMED
|
File without changes
|
{portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state/manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{portacode-1.3.35 → portacode-1.3.36}/portacode/connection/handlers/project_state_handlers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|