portacode 1.4.37.dev0__tar.gz → 1.4.37.dev2__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.
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/PKG-INFO +1 -1
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/_version.py +2 -2
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/file_system_watcher.py +49 -2
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/manager.py +52 -1
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/terminal.py +0 -198
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode.egg-info/PKG-INFO +1 -1
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/.claude/agents/communication-manager.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/.claude/settings.local.json +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/.gitignore +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/.gitmodules +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/LICENSE +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/MANIFEST.in +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/Makefile +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/backup.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/build_android.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/connect.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/connect.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docker-compose.yaml +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/cloudflared-domain-connect-containers-audit.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/creative-team-brief-portacode.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/devops-messaging-ab-tests.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/homepage-dashboard-positioning-fixes.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/images/device-transfer-button.png +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/images/device-transfer-modal.png +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/images/pair-device-button.png +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/images/pairing-request.png +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/images/student-workspace.png +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/template-guide.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/simple_device/Dockerfile +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/simple_device/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/simple_device/docker-compose.yaml +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/Dockerfile +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/.local/share/portacode/run/gateway.pid +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/.gitignore +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/db.sqlite3 +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/settings.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/urls.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/wsgi.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/admin.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/apps.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/menu.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/models.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/urls.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/views.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/docker-compose.yaml +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/settings.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/manage.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/templates/treats/home.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/admin.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/apps.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/menu.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/migrations/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/urls.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/initial_content/treats/views.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/examples/workshop_fleet/instructions/WELCOME.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/__main__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/cli.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/client.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/automation_v2_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/base.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/chunked_content.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/cloudflare_forwarding.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/cloudflare_tunnel.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/diff_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/file_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/git_manager.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/models.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state/utils.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/project_state_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/proxmox_infra.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/registry.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/session.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/system_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/tab_factory.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/terminal_handlers.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/test_proxmox_infra.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/handlers/update_handler.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/connection/multiplex.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/data.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/exit_codes.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/keypair.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/elinks +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/gio-open +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/gnome-open +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/gvfs-open +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/kde-open +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/kfmclient +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/link_capture_exec.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/link_capture_wrapper.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/links +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/links2 +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/lynx +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/mate-open +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/netsurf +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/sensible-browser +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/w3m +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/x-www-browser +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/link_capture/bin/xdg-open +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/logging_categories.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/pairing.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/restart.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/service.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/static/js/test-ntp-clock.html +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/static/js/utils/ntp-clock.js +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/cloudflared_login.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/ensure_cloudflared.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/ensure_pyyaml.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/forwarding_state.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/get_domain.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/privileged.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/service_install.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/tunneling/state.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/updater.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/utils/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/utils/diff_apply.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/utils/diff_renderer.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode/utils/ntp_clock.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode.egg-info/SOURCES.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode.egg-info/dependency_links.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode.egg-info/entry_points.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode.egg-info/requires.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/portacode.egg-info/top_level.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/pyproject.toml +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/restore.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/run_tests.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/setup.cfg +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/setup.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_device_online.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_file_operations.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_git_status_ui.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_login_flow.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_navigate_testing_folder.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_play_store_screenshots.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_terminal_buffer_performance.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_terminal_interaction.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_terminal_loading_race_condition.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_modules/test_terminal_start.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/test_request_id.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/.env.example +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/README.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/cli.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/__init__.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/base_test.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/cli_manager.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/hierarchical_runner.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/playwright_manager.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/runner.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/shared_cli_manager.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/core/test_discovery.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/testing_framework/requirements.txt +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/UI_UX/server_occasionally_stops_communicating_with_all_devices.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/agent_context_management.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/django_server_time_sync.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/device_performance_degradation.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/indefinite_resource_loading.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/portacode_service_silently_down.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/premature_terminal_exit.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/project_cpu_hotspots.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/terminals_exit_upon_starting.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/websocket_client_silently_dead.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/issues/wrong_item_classification_on_client_side.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/todo/smartphone_terminal_input_frustrations.md +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/tools/generate_play_store_assets.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/tools/pairing_tester.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/tools/run_screenshot_suite.sh +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/tools/test_python_ntp_clock.py +0 -0
- {portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/validate.sh +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.4.37.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 4, 37, '
|
|
31
|
+
__version__ = version = '1.4.37.dev2'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 37, 'dev2')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -6,8 +6,11 @@ files or directories are modified.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import asyncio
|
|
9
|
+
import faulthandler
|
|
9
10
|
import logging
|
|
10
11
|
import os
|
|
12
|
+
import sys
|
|
13
|
+
import time
|
|
11
14
|
from pathlib import Path
|
|
12
15
|
from typing import Optional, Set
|
|
13
16
|
|
|
@@ -125,6 +128,12 @@ class FileSystemWatcher:
|
|
|
125
128
|
if normalized_name == '.git':
|
|
126
129
|
logger.debug("Skipping watch for .git path: %s", path)
|
|
127
130
|
return
|
|
131
|
+
if not os.path.isdir(path):
|
|
132
|
+
logger.debug("Skipping watch for non-directory path: %s", path)
|
|
133
|
+
return
|
|
134
|
+
if not os.access(path, os.R_OK | os.X_OK):
|
|
135
|
+
logger.debug("Skipping watch due to insufficient access: %s", path)
|
|
136
|
+
return
|
|
128
137
|
|
|
129
138
|
if path not in self.watched_paths:
|
|
130
139
|
try:
|
|
@@ -151,16 +160,54 @@ class FileSystemWatcher:
|
|
|
151
160
|
# Actually unschedule the watch using stored handle
|
|
152
161
|
watch_handle = self.watch_handles.get(path)
|
|
153
162
|
if watch_handle:
|
|
163
|
+
start = time.monotonic()
|
|
164
|
+
logger.info(
|
|
165
|
+
"About to unschedule watch: path=%s handle=%s observer_alive=%s watched_paths=%d watch_handles=%d",
|
|
166
|
+
path,
|
|
167
|
+
id(watch_handle),
|
|
168
|
+
bool(self.observer and self.observer.is_alive()),
|
|
169
|
+
len(self.watched_paths),
|
|
170
|
+
len(self.watch_handles),
|
|
171
|
+
)
|
|
154
172
|
try:
|
|
173
|
+
# If unschedule blocks silently, force a thread traceback dump for diagnosis.
|
|
174
|
+
faulthandler.dump_traceback_later(8.0, file=sys.stderr, repeat=False)
|
|
155
175
|
self.observer.unschedule(watch_handle)
|
|
156
|
-
logger.info(
|
|
176
|
+
logger.info(
|
|
177
|
+
"Successfully unscheduled watch for: %s (elapsed=%.3fs)",
|
|
178
|
+
path,
|
|
179
|
+
max(time.monotonic() - start, 0.0),
|
|
180
|
+
)
|
|
157
181
|
except Exception as e:
|
|
158
|
-
logger.
|
|
182
|
+
logger.exception(
|
|
183
|
+
"Error unscheduling watch for %s after %.3fs: %s",
|
|
184
|
+
path,
|
|
185
|
+
max(time.monotonic() - start, 0.0),
|
|
186
|
+
e,
|
|
187
|
+
)
|
|
159
188
|
finally:
|
|
189
|
+
try:
|
|
190
|
+
faulthandler.cancel_dump_traceback_later()
|
|
191
|
+
except Exception:
|
|
192
|
+
pass
|
|
160
193
|
self.watch_handles.pop(path, None)
|
|
194
|
+
else:
|
|
195
|
+
logger.warning(
|
|
196
|
+
"Path %s marked as watched but has no watch handle; watched_paths=%d watch_handles=%d",
|
|
197
|
+
path,
|
|
198
|
+
len(self.watched_paths),
|
|
199
|
+
len(self.watch_handles),
|
|
200
|
+
)
|
|
161
201
|
|
|
162
202
|
self.watched_paths.discard(path)
|
|
163
203
|
logger.debug("Stopped watching path: %s", path)
|
|
204
|
+
else:
|
|
205
|
+
logger.debug(
|
|
206
|
+
"stop_watching called for non-watched path: %s (watched_paths=%d watch_handles=%d)",
|
|
207
|
+
path,
|
|
208
|
+
len(self.watched_paths),
|
|
209
|
+
len(self.watch_handles),
|
|
210
|
+
)
|
|
164
211
|
|
|
165
212
|
def stop_all(self):
|
|
166
213
|
"""Stop all file watching."""
|
|
@@ -281,6 +281,12 @@ class ProjectStateManager:
|
|
|
281
281
|
with os.scandir(project_state.project_folder_path) as entries:
|
|
282
282
|
for entry in entries:
|
|
283
283
|
if entry.is_dir() and entry.name != '.git': # Only exclude .git, allow other dot folders
|
|
284
|
+
if not os.access(entry.path, os.R_OK | os.X_OK):
|
|
285
|
+
logger.debug(
|
|
286
|
+
"Skipping monitored folder due to insufficient access: %s",
|
|
287
|
+
entry.path,
|
|
288
|
+
)
|
|
289
|
+
continue
|
|
284
290
|
project_state.monitored_folders.append(
|
|
285
291
|
MonitoredFolder(folder_path=entry.path, is_expanded=False)
|
|
286
292
|
)
|
|
@@ -350,6 +356,12 @@ class ProjectStateManager:
|
|
|
350
356
|
with os.scandir(parent_folder_path) as entries:
|
|
351
357
|
for entry in entries:
|
|
352
358
|
if entry.is_dir() and entry.name != '.git': # Only exclude .git, allow other dot folders
|
|
359
|
+
if not os.access(entry.path, os.R_OK | os.X_OK):
|
|
360
|
+
logger.debug(
|
|
361
|
+
"Skipping monitored folder due to insufficient access: %s",
|
|
362
|
+
entry.path,
|
|
363
|
+
)
|
|
364
|
+
continue
|
|
353
365
|
# logger.info("Found subdirectory: %s", entry.path)
|
|
354
366
|
if entry.path not in existing_paths:
|
|
355
367
|
logger.info("Adding new monitored folder: %s", entry.path)
|
|
@@ -1210,13 +1222,52 @@ class ProjectStateManager:
|
|
|
1210
1222
|
logger.debug("Removed %d pending change paths for session %s during cleanup", len(removed), client_session_id)
|
|
1211
1223
|
|
|
1212
1224
|
# Stop watching all monitored folders for this project
|
|
1213
|
-
|
|
1225
|
+
total_monitored = len(project_state.monitored_folders)
|
|
1226
|
+
logger.info(
|
|
1227
|
+
"Cleanup starting watcher unschedule loop: session=%s project_path=%s monitored_folders=%d watched_paths=%d watch_handles=%d",
|
|
1228
|
+
client_session_id,
|
|
1229
|
+
project_state.project_folder_path,
|
|
1230
|
+
total_monitored,
|
|
1231
|
+
len(self.file_watcher.watched_paths) if self.file_watcher else -1,
|
|
1232
|
+
len(self.file_watcher.watch_handles) if self.file_watcher else -1,
|
|
1233
|
+
)
|
|
1234
|
+
cleanup_loop_start = time.monotonic()
|
|
1235
|
+
for idx, monitored_folder in enumerate(project_state.monitored_folders, start=1):
|
|
1236
|
+
per_folder_start = time.monotonic()
|
|
1237
|
+
logger.info(
|
|
1238
|
+
"Cleanup unschedule start: session=%s idx=%d/%d path=%s",
|
|
1239
|
+
client_session_id,
|
|
1240
|
+
idx,
|
|
1241
|
+
total_monitored,
|
|
1242
|
+
monitored_folder.folder_path,
|
|
1243
|
+
)
|
|
1214
1244
|
self.file_watcher.stop_watching(monitored_folder.folder_path)
|
|
1245
|
+
logger.info(
|
|
1246
|
+
"Cleanup unschedule done: session=%s idx=%d/%d path=%s elapsed=%.3fs",
|
|
1247
|
+
client_session_id,
|
|
1248
|
+
idx,
|
|
1249
|
+
total_monitored,
|
|
1250
|
+
monitored_folder.folder_path,
|
|
1251
|
+
max(time.monotonic() - per_folder_start, 0.0),
|
|
1252
|
+
)
|
|
1253
|
+
logger.info(
|
|
1254
|
+
"Cleanup watcher unschedule loop completed: session=%s total_elapsed=%.3fs",
|
|
1255
|
+
client_session_id,
|
|
1256
|
+
max(time.monotonic() - cleanup_loop_start, 0.0),
|
|
1257
|
+
)
|
|
1215
1258
|
|
|
1216
1259
|
# Stop watching .git directory if it was being monitored
|
|
1217
1260
|
if project_state.is_git_repo:
|
|
1218
1261
|
git_dir_path = os.path.join(project_state.project_folder_path, '.git')
|
|
1262
|
+
git_unschedule_start = time.monotonic()
|
|
1263
|
+
logger.info("Cleanup unschedule start (git dir): session=%s path=%s", client_session_id, git_dir_path)
|
|
1219
1264
|
self.file_watcher.stop_watching(git_dir_path)
|
|
1265
|
+
logger.info(
|
|
1266
|
+
"Cleanup unschedule done (git dir): session=%s path=%s elapsed=%.3fs",
|
|
1267
|
+
client_session_id,
|
|
1268
|
+
git_dir_path,
|
|
1269
|
+
max(time.monotonic() - git_unschedule_start, 0.0),
|
|
1270
|
+
)
|
|
1220
1271
|
|
|
1221
1272
|
self.projects.pop(client_session_id, None)
|
|
1222
1273
|
logger.info("Cleaned up project state: %s", client_session_id)
|
|
@@ -14,12 +14,9 @@ in the handlers directory.
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import asyncio
|
|
17
|
-
import faulthandler
|
|
18
17
|
import json
|
|
19
18
|
import logging
|
|
20
19
|
import os
|
|
21
|
-
import sys
|
|
22
|
-
import threading
|
|
23
20
|
import time
|
|
24
21
|
from datetime import datetime, timezone
|
|
25
22
|
from dataclasses import asdict
|
|
@@ -392,185 +389,11 @@ class TerminalManager:
|
|
|
392
389
|
self.mux = mux
|
|
393
390
|
self.debug = debug
|
|
394
391
|
self._last_exposed_services_signature = "__unset__"
|
|
395
|
-
self._diag_lock = threading.Lock()
|
|
396
|
-
now_mono = time.monotonic()
|
|
397
|
-
self._diag_state: Dict[str, Any] = {
|
|
398
|
-
"heartbeat_monotonic": now_mono,
|
|
399
|
-
"heartbeat_epoch_s": time.time(),
|
|
400
|
-
"loop_phase": "init",
|
|
401
|
-
"active_cmd": None,
|
|
402
|
-
"active_cmd_started_monotonic": None,
|
|
403
|
-
"active_cmd_reply_channel": None,
|
|
404
|
-
"last_completed_cmd": None,
|
|
405
|
-
"last_completed_cmd_duration_s": None,
|
|
406
|
-
"queue_stats": {},
|
|
407
|
-
}
|
|
408
|
-
self._diag_monitor_enabled = os.getenv("PORTACODE_EVENT_LOOP_BLOCK_MONITOR", "1").lower() not in ("0", "false", "no")
|
|
409
|
-
self._diag_threshold_s = float(os.getenv("PORTACODE_EVENT_LOOP_BLOCK_THRESHOLD_S", "5"))
|
|
410
|
-
self._diag_monitor_interval_s = float(os.getenv("PORTACODE_EVENT_LOOP_BLOCK_MONITOR_INTERVAL_S", "0.5"))
|
|
411
|
-
self._diag_report_interval_s = float(os.getenv("PORTACODE_EVENT_LOOP_BLOCK_REPORT_INTERVAL_S", "30"))
|
|
412
|
-
self._diag_heartbeat_interval_s = float(os.getenv("PORTACODE_EVENT_LOOP_BLOCK_HEARTBEAT_INTERVAL_S", "0.5"))
|
|
413
|
-
self._diag_dump_threads = os.getenv("PORTACODE_EVENT_LOOP_BLOCK_DUMP_THREADS", "1").lower() not in ("0", "false", "no")
|
|
414
|
-
self._diag_monitor_stop = threading.Event()
|
|
415
|
-
self._diag_monitor_thread: Optional[threading.Thread] = None
|
|
416
|
-
self._diag_last_report_monotonic = 0.0
|
|
417
|
-
self._diag_last_report_key: Optional[str] = None
|
|
418
392
|
self._session_manager = None # Initialize as None first
|
|
419
393
|
self._client_session_manager = ClientSessionManager() # Initialize client session manager
|
|
420
394
|
self._client_session_manager.set_terminal_manager(self) # Set reference for cleanup
|
|
421
|
-
self._start_block_monitor_thread_if_enabled()
|
|
422
395
|
self._set_mux(mux, is_initial=True)
|
|
423
396
|
|
|
424
|
-
def _start_block_monitor_thread_if_enabled(self) -> None:
|
|
425
|
-
if not self._diag_monitor_enabled or self._diag_monitor_thread:
|
|
426
|
-
return
|
|
427
|
-
self._diag_monitor_thread = threading.Thread(
|
|
428
|
-
target=self._event_loop_block_monitor_thread,
|
|
429
|
-
name="portacode-event-loop-block-monitor",
|
|
430
|
-
daemon=True,
|
|
431
|
-
)
|
|
432
|
-
self._diag_monitor_thread.start()
|
|
433
|
-
|
|
434
|
-
def _set_diag_phase(self, phase: str) -> None:
|
|
435
|
-
now_mono = time.monotonic()
|
|
436
|
-
now_epoch = time.time()
|
|
437
|
-
with self._diag_lock:
|
|
438
|
-
self._diag_state["loop_phase"] = phase
|
|
439
|
-
self._diag_state["heartbeat_monotonic"] = now_mono
|
|
440
|
-
self._diag_state["heartbeat_epoch_s"] = now_epoch
|
|
441
|
-
|
|
442
|
-
def _set_diag_active_cmd(self, cmd: str, reply_channel: Optional[str]) -> None:
|
|
443
|
-
now_mono = time.monotonic()
|
|
444
|
-
now_epoch = time.time()
|
|
445
|
-
with self._diag_lock:
|
|
446
|
-
self._diag_state["active_cmd"] = cmd
|
|
447
|
-
self._diag_state["active_cmd_reply_channel"] = reply_channel
|
|
448
|
-
self._diag_state["active_cmd_started_monotonic"] = now_mono
|
|
449
|
-
self._diag_state["heartbeat_monotonic"] = now_mono
|
|
450
|
-
self._diag_state["heartbeat_epoch_s"] = now_epoch
|
|
451
|
-
|
|
452
|
-
def _clear_diag_active_cmd(self, completed_cmd: str, duration_s: float) -> None:
|
|
453
|
-
now_mono = time.monotonic()
|
|
454
|
-
now_epoch = time.time()
|
|
455
|
-
with self._diag_lock:
|
|
456
|
-
self._diag_state["active_cmd"] = None
|
|
457
|
-
self._diag_state["active_cmd_reply_channel"] = None
|
|
458
|
-
self._diag_state["active_cmd_started_monotonic"] = None
|
|
459
|
-
self._diag_state["last_completed_cmd"] = completed_cmd
|
|
460
|
-
self._diag_state["last_completed_cmd_duration_s"] = round(duration_s, 4)
|
|
461
|
-
self._diag_state["heartbeat_monotonic"] = now_mono
|
|
462
|
-
self._diag_state["heartbeat_epoch_s"] = now_epoch
|
|
463
|
-
|
|
464
|
-
def _snapshot_diag_state_for_monitor(self) -> Dict[str, Any]:
|
|
465
|
-
with self._diag_lock:
|
|
466
|
-
return dict(self._diag_state)
|
|
467
|
-
|
|
468
|
-
def _event_loop_block_monitor_thread(self) -> None:
|
|
469
|
-
while not self._diag_monitor_stop.wait(self._diag_monitor_interval_s):
|
|
470
|
-
snapshot = self._snapshot_diag_state_for_monitor()
|
|
471
|
-
now = time.monotonic()
|
|
472
|
-
last_hb = float(snapshot.get("heartbeat_monotonic") or now)
|
|
473
|
-
blocked_for_s = max(now - last_hb, 0.0)
|
|
474
|
-
|
|
475
|
-
if blocked_for_s < self._diag_threshold_s:
|
|
476
|
-
continue
|
|
477
|
-
|
|
478
|
-
active_cmd = snapshot.get("active_cmd")
|
|
479
|
-
queue_stats = snapshot.get("queue_stats") if isinstance(snapshot.get("queue_stats"), dict) else {}
|
|
480
|
-
control_q = queue_stats.get("control_channel_queue_size")
|
|
481
|
-
total_mux_q = queue_stats.get("mux_total_queued_frames")
|
|
482
|
-
has_backlog = (
|
|
483
|
-
(isinstance(control_q, int) and control_q > 0)
|
|
484
|
-
or (isinstance(total_mux_q, int) and total_mux_q > 0)
|
|
485
|
-
)
|
|
486
|
-
if not active_cmd and not has_backlog:
|
|
487
|
-
continue
|
|
488
|
-
|
|
489
|
-
active_cmd_started = snapshot.get("active_cmd_started_monotonic")
|
|
490
|
-
active_cmd_age_s = None
|
|
491
|
-
if active_cmd and isinstance(active_cmd_started, (int, float)):
|
|
492
|
-
active_cmd_age_s = max(now - float(active_cmd_started), 0.0)
|
|
493
|
-
|
|
494
|
-
report_key = f"{snapshot.get('loop_phase')}:{active_cmd}:{snapshot.get('heartbeat_epoch_s')}"
|
|
495
|
-
if report_key == self._diag_last_report_key and (now - self._diag_last_report_monotonic) < self._diag_report_interval_s:
|
|
496
|
-
continue
|
|
497
|
-
|
|
498
|
-
self._diag_last_report_key = report_key
|
|
499
|
-
self._diag_last_report_monotonic = now
|
|
500
|
-
|
|
501
|
-
payload = {
|
|
502
|
-
"event": "event_loop_blocking_detected",
|
|
503
|
-
"blocked_for_s": round(blocked_for_s, 3),
|
|
504
|
-
"threshold_s": self._diag_threshold_s,
|
|
505
|
-
"cause_hint": {
|
|
506
|
-
"loop_phase": snapshot.get("loop_phase"),
|
|
507
|
-
"active_cmd": active_cmd,
|
|
508
|
-
"active_cmd_reply_channel": snapshot.get("active_cmd_reply_channel"),
|
|
509
|
-
"active_cmd_age_s": round(active_cmd_age_s, 3) if active_cmd_age_s is not None else None,
|
|
510
|
-
"last_completed_cmd": snapshot.get("last_completed_cmd"),
|
|
511
|
-
"last_completed_cmd_duration_s": snapshot.get("last_completed_cmd_duration_s"),
|
|
512
|
-
},
|
|
513
|
-
"queue_stats": queue_stats,
|
|
514
|
-
"last_heartbeat_epoch_s": snapshot.get("heartbeat_epoch_s"),
|
|
515
|
-
"monitor_thread_epoch_s": time.time(),
|
|
516
|
-
"pid": os.getpid(),
|
|
517
|
-
}
|
|
518
|
-
logger.error("Event loop stall monitor: %s", json.dumps(payload, sort_keys=True))
|
|
519
|
-
|
|
520
|
-
if self._diag_dump_threads:
|
|
521
|
-
try:
|
|
522
|
-
faulthandler.dump_traceback(file=sys.stderr, all_threads=True)
|
|
523
|
-
except Exception as exc:
|
|
524
|
-
logger.error("Event loop stall monitor failed to dump thread traceback: %s", exc)
|
|
525
|
-
|
|
526
|
-
def _collect_loop_queue_stats(self) -> Dict[str, Any]:
|
|
527
|
-
control_q_size = None
|
|
528
|
-
try:
|
|
529
|
-
control_q = getattr(self._control_channel, "_incoming", None)
|
|
530
|
-
if control_q is not None:
|
|
531
|
-
control_q_size = control_q.qsize()
|
|
532
|
-
except Exception:
|
|
533
|
-
control_q_size = None
|
|
534
|
-
|
|
535
|
-
mux_channels = getattr(self.mux, "_channels", {}) if self.mux else {}
|
|
536
|
-
total_queued = 0
|
|
537
|
-
top_channels = []
|
|
538
|
-
for channel_id, channel in mux_channels.items():
|
|
539
|
-
try:
|
|
540
|
-
incoming_q = getattr(channel, "_incoming", None)
|
|
541
|
-
size = incoming_q.qsize() if incoming_q is not None else None
|
|
542
|
-
except Exception:
|
|
543
|
-
size = None
|
|
544
|
-
if isinstance(size, int):
|
|
545
|
-
total_queued += size
|
|
546
|
-
top_channels.append((str(channel_id), size))
|
|
547
|
-
|
|
548
|
-
top_channels.sort(key=lambda item: item[1], reverse=True)
|
|
549
|
-
return {
|
|
550
|
-
"control_channel_queue_size": control_q_size,
|
|
551
|
-
"mux_channel_count": len(mux_channels),
|
|
552
|
-
"mux_total_queued_frames": total_queued,
|
|
553
|
-
"mux_top_queues": [{"channel_id": cid, "size": size} for cid, size in top_channels[:5]],
|
|
554
|
-
"client_sessions_count": len(self._client_session_manager.get_sessions()),
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
async def _diag_heartbeat_loop(self) -> None:
|
|
558
|
-
while True:
|
|
559
|
-
try:
|
|
560
|
-
await asyncio.sleep(self._diag_heartbeat_interval_s)
|
|
561
|
-
queue_stats = self._collect_loop_queue_stats()
|
|
562
|
-
now_mono = time.monotonic()
|
|
563
|
-
now_epoch = time.time()
|
|
564
|
-
with self._diag_lock:
|
|
565
|
-
self._diag_state["heartbeat_monotonic"] = now_mono
|
|
566
|
-
self._diag_state["heartbeat_epoch_s"] = now_epoch
|
|
567
|
-
self._diag_state["queue_stats"] = queue_stats
|
|
568
|
-
except asyncio.CancelledError:
|
|
569
|
-
return
|
|
570
|
-
except Exception as exc:
|
|
571
|
-
logger.debug("Event loop heartbeat diagnostics error: %s", exc)
|
|
572
|
-
await asyncio.sleep(self._diag_heartbeat_interval_s)
|
|
573
|
-
|
|
574
397
|
# ------------------------------------------------------------------
|
|
575
398
|
# Mux attach/detach helpers (for reconnection resilience)
|
|
576
399
|
# ------------------------------------------------------------------
|
|
@@ -646,14 +469,6 @@ class TerminalManager:
|
|
|
646
469
|
except Exception:
|
|
647
470
|
pass
|
|
648
471
|
self._exposed_services_task = asyncio.create_task(self._watch_exposed_services())
|
|
649
|
-
|
|
650
|
-
# Start passive event-loop diagnostics heartbeat (asyncio thread only).
|
|
651
|
-
if getattr(self, "_diag_heartbeat_task", None):
|
|
652
|
-
try:
|
|
653
|
-
self._diag_heartbeat_task.cancel()
|
|
654
|
-
except Exception:
|
|
655
|
-
pass
|
|
656
|
-
self._diag_heartbeat_task = asyncio.create_task(self._diag_heartbeat_loop())
|
|
657
472
|
|
|
658
473
|
# For initial connections, request client sessions after control loop starts
|
|
659
474
|
if is_initial:
|
|
@@ -716,9 +531,7 @@ class TerminalManager:
|
|
|
716
531
|
logger.info("terminal_manager: Starting control loop")
|
|
717
532
|
while True:
|
|
718
533
|
try:
|
|
719
|
-
self._set_diag_phase("control_loop_waiting_for_message")
|
|
720
534
|
message = await self._control_channel.recv()
|
|
721
|
-
self._set_diag_phase("control_loop_received_message")
|
|
722
535
|
logger.debug("terminal_manager: Received message: %s", message)
|
|
723
536
|
|
|
724
537
|
# Older parts of the system may send *raw* str. Ensure dict.
|
|
@@ -741,8 +554,6 @@ class TerminalManager:
|
|
|
741
554
|
logger.warning("terminal_manager: Missing 'cmd' in control frame: %s", message)
|
|
742
555
|
continue
|
|
743
556
|
reply_chan = message.get("reply_channel")
|
|
744
|
-
cmd_start = time.monotonic()
|
|
745
|
-
self._set_diag_active_cmd(cmd, reply_chan)
|
|
746
557
|
|
|
747
558
|
logger.info("terminal_manager: Processing command '%s' with reply_channel=%s", cmd, reply_chan)
|
|
748
559
|
logger.debug("terminal_manager: Full message: %s", message)
|
|
@@ -762,8 +573,6 @@ class TerminalManager:
|
|
|
762
573
|
asyncio.create_task(self._send_initial_data_to_clients(newly_added_sessions))
|
|
763
574
|
else:
|
|
764
575
|
logger.info("terminal_manager: ℹ️ No new sessions to send data to")
|
|
765
|
-
self._clear_diag_active_cmd(cmd, time.monotonic() - cmd_start)
|
|
766
|
-
self._set_diag_phase("control_loop_completed_client_sessions_update")
|
|
767
576
|
continue
|
|
768
577
|
|
|
769
578
|
# Dispatch command through registry
|
|
@@ -771,16 +580,9 @@ class TerminalManager:
|
|
|
771
580
|
if not handled:
|
|
772
581
|
logger.warning("terminal_manager: Command '%s' was not handled by any handler", cmd)
|
|
773
582
|
await self._send_error(f"Unknown cmd: {cmd}", reply_chan)
|
|
774
|
-
self._clear_diag_active_cmd(cmd, time.monotonic() - cmd_start)
|
|
775
|
-
self._set_diag_phase(f"control_loop_completed_{cmd}")
|
|
776
583
|
|
|
777
584
|
except Exception as exc:
|
|
778
585
|
logger.exception("terminal_manager: Error in control loop: %s", exc)
|
|
779
|
-
with self._diag_lock:
|
|
780
|
-
self._diag_state["active_cmd"] = None
|
|
781
|
-
self._diag_state["active_cmd_started_monotonic"] = None
|
|
782
|
-
self._diag_state["active_cmd_reply_channel"] = None
|
|
783
|
-
self._set_diag_phase("control_loop_exception")
|
|
784
586
|
# Continue processing other messages
|
|
785
587
|
continue
|
|
786
588
|
|
|
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.4.37.dev0 → portacode-1.4.37.dev2}/docs/cloudflared-domain-connect-containers-audit.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{portacode-1.4.37.dev0 → portacode-1.4.37.dev2}/docs/homepage-dashboard-positioning-fixes.md
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
|