portacode 1.5.31.dev0__tar.gz → 1.5.31.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.5.31.dev0 → portacode-1.5.31.dev2}/PKG-INFO +1 -1
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/_version.py +2 -2
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/proxmox_infra.py +57 -4
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/test_proxmox_infra.py +87 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/terminal.py +27 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode.egg-info/PKG-INFO +1 -1
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/.claude/agents/communication-manager.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/.claude/settings.local.json +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/.gitignore +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/.gitmodules +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/AGENTS.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/LICENSE +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/MANIFEST.in +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/Makefile +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/build_android.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/connect.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/connect.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/docs/cloudflared-domain-connect-containers-audit.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/docs/creative-team-brief-portacode.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/docs/device-health-alerting-plan.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/docs/devops-messaging-ab-tests.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/docs/homepage-dashboard-positioning-fixes.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/docs/template-guide.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/simple_device/Dockerfile +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/simple_device/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/simple_device/docker-compose.yaml +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/Dockerfile +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/.local/share/portacode/run/gateway.pid +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/.gitignore +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/db.sqlite3 +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/settings.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/urls.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/wsgi.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/admin.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/apps.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/menu.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/models.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/urls.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/views.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-01/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-02/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-03/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-04/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-05/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-06/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-07/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-08/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-09/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode.pub +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/data/student-10/workspace/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/docker-compose.yaml +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/asgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/settings.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/galactic_bakeshop/wsgi.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/manage.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/templates/treats/home.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/admin.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/apps.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/menu.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/migrations/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/urls.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/initial_content/treats/views.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/examples/workshop_fleet/instructions/WELCOME.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/__main__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/cli.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/codex_loopback_proxy.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/codex_prepare.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/codex_usage_limit.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/client.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/codex_app_server.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/automation_v2_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/base.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/browser_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/chunked_content.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/cloudflare_forwarding.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/cloudflare_tunnel.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/codex_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/diff_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/file_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/file_transfer_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/git_manager.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/manager.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/models.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/test_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state/utils.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/project_state_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/registry.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/resumable_transfer_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/runtime_user.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/session.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/system_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/tab_factory.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/terminal_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/test_browser_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/test_cloudflare_forwarding.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/test_file_move_copy.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/test_runtime_user.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/update_handler.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/multiplex.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/test_webmin_proxy_config.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/webmin_proxy_config.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/data.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/exit_codes.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/github_credential.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/keypair.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/__pycache__/__init__.cpython-38.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-38.pyc +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/elinks +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/gio-open +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/gnome-open +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/gvfs-open +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/kde-open +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/kfmclient +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/link_capture_exec.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/link_capture_wrapper.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/links +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/links2 +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/lynx +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/mate-open +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/netsurf +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/sensible-browser +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/w3m +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/x-www-browser +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/link_capture/bin/xdg-open +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/logging_categories.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/pairing.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/provisioning_cache.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/restart.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/service.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/singleton.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/static/js/test-ntp-clock.html +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/static/js/utils/ntp-clock.js +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/test_runtime_paths.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/test_service.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/test_singleton.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/test_terminal_exposed_services.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_codex_app_server.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_codex_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_codex_loopback_proxy.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_codex_prepare.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_github_credential.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_image_read_handler.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_resumable_transfer_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tests/test_system_handlers.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/cloudflared_login.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/ensure_cloudflared.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/ensure_pyyaml.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/forwarding_state.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/get_domain.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/privileged.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/service_install.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/tunneling/state.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/updater.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/utils/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/utils/diff_apply.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/utils/diff_renderer.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/utils/ntp_clock.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/utils/runtime_paths.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode.egg-info/SOURCES.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode.egg-info/dependency_links.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode.egg-info/entry_points.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode.egg-info/requires.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode.egg-info/top_level.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/.gitignore +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/persistent_workspace/Dockerfile +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/persistent_workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/persistent_workspace/entrypoint.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/persistent_workspace/manage_classroom.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/temporary_workspace/Dockerfile +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/temporary_workspace/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/temporary_workspace/docker-compose.yaml +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/temporary_workspace/docs/device_transfere.png +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/temporary_workspace/docs/pairing_approval.png +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode_for_school/temporary_workspace/entrypoint.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/pyproject.toml +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/run_tests.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/scripts/diagnose_codex_gateway.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/setup.cfg +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/setup.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_device_online.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_file_operations.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_git_status_ui.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_login_flow.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_navigate_testing_folder.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_play_store_screenshots.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_terminal_buffer_performance.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_terminal_interaction.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_terminal_loading_race_condition.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_modules/test_terminal_start.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_request_id.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/test_session_terminal_shutdown.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/.env.example +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/README.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/cli.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/__init__.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/base_test.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/cli_manager.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/hierarchical_runner.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/playwright_manager.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/runner.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/shared_cli_manager.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/core/test_discovery.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/testing_framework/requirements.txt +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/UI_UX/server_occasionally_stops_communicating_with_all_devices.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/agent_context_management.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/django_server_time_sync.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/device_performance_degradation.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/indefinite_resource_loading.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/portacode_service_silently_down.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/premature_terminal_exit.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/project_cpu_hotspots.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/terminals_exit_upon_starting.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/websocket_client_silently_dead.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/issues/wrong_item_classification_on_client_side.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/todo/smartphone_terminal_input_frustrations.md +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/tools/generate_play_store_assets.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/tools/pairing_tester.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/tools/run_screenshot_suite.sh +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/tools/test_python_ntp_clock.py +0 -0
- {portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/validate.sh +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.5.31.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 5, 31, '
|
|
21
|
+
__version__ = version = '1.5.31.dev2'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 5, 31, 'dev2')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
{portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/proxmox_infra.py
RENAMED
|
@@ -53,6 +53,7 @@ CACHE_SOURCE_MARKER = "cache_source="
|
|
|
53
53
|
CACHE_PARENT_MARKER = "cache_parent="
|
|
54
54
|
_PROVISIONING_MAINTENANCE_LAST_RUN = 0.0
|
|
55
55
|
PROVISIONING_MAINTENANCE_INTERVAL_S = 300
|
|
56
|
+
PROXMOX_INVENTORY_RECONCILE_INTERVAL_S = 300
|
|
56
57
|
# Keep reusable roots small while leaving enough room for the OS, Portacode,
|
|
57
58
|
# Codex, and (on apt systems) Playwright Chromium to be installed. A request
|
|
58
59
|
# below this size still builds at its requested size; if the software cannot
|
|
@@ -154,6 +155,7 @@ _MANAGED_CONTAINERS_STATE: Dict[str, Any] = {
|
|
|
154
155
|
"initial_totals": {"ram_mib": 0, "disk_gib": 0, "cpu_share": 0.0},
|
|
155
156
|
"records": {},
|
|
156
157
|
"pending": {},
|
|
158
|
+
"revision": 0,
|
|
157
159
|
}
|
|
158
160
|
TEMPLATES_REFRESH_INTERVAL_S = 300
|
|
159
161
|
_TEMPLATE_CACHE_LOCK = threading.Lock()
|
|
@@ -1340,9 +1342,47 @@ def _initialize_managed_containers_state(force: bool = False) -> Dict[str, Any]:
|
|
|
1340
1342
|
_MANAGED_CONTAINERS_STATE["initial_totals"] = initial_totals
|
|
1341
1343
|
_MANAGED_CONTAINERS_STATE["records"] = record_map
|
|
1342
1344
|
_MANAGED_CONTAINERS_STATE["pending"] = {}
|
|
1345
|
+
_MANAGED_CONTAINERS_STATE["revision"] = int(
|
|
1346
|
+
_MANAGED_CONTAINERS_STATE.get("revision") or 0
|
|
1347
|
+
) + 1
|
|
1343
1348
|
return _copy_summary(base_summary)
|
|
1344
1349
|
|
|
1345
1350
|
|
|
1351
|
+
def reconcile_managed_containers_inventory() -> Dict[str, Any]:
|
|
1352
|
+
"""Refresh Proxmox inventory without blocking or racing provisioning.
|
|
1353
|
+
|
|
1354
|
+
The comparatively expensive Proxmox API scan runs outside the state lock.
|
|
1355
|
+
A revision check makes the final swap conditional: if a managed create,
|
|
1356
|
+
delete, or record update occurred during the scan, the stale result is
|
|
1357
|
+
discarded and the next periodic pass retries it. Pending reservations are
|
|
1358
|
+
never replaced by reconciliation.
|
|
1359
|
+
"""
|
|
1360
|
+
_initialize_managed_containers_state()
|
|
1361
|
+
with _MANAGED_CONTAINERS_STATE_LOCK:
|
|
1362
|
+
revision = int(_MANAGED_CONTAINERS_STATE.get("revision") or 0)
|
|
1363
|
+
records = [record.copy() for record in _MANAGED_CONTAINERS_STATE.get("records", {}).values()]
|
|
1364
|
+
|
|
1365
|
+
config = _load_config()
|
|
1366
|
+
if not config:
|
|
1367
|
+
return {"refreshed": False, "reason": "not_configured"}
|
|
1368
|
+
refreshed_summary = _build_full_container_summary(records, config)
|
|
1369
|
+
refreshed_totals = {
|
|
1370
|
+
"ram_mib": int(refreshed_summary.get("total_ram_mib") or 0),
|
|
1371
|
+
"disk_gib": int(refreshed_summary.get("total_disk_gib") or 0),
|
|
1372
|
+
"cpu_share": float(refreshed_summary.get("total_cpu_share") or 0.0),
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
with _MANAGED_CONTAINERS_STATE_LOCK:
|
|
1376
|
+
if int(_MANAGED_CONTAINERS_STATE.get("revision") or 0) != revision:
|
|
1377
|
+
return {"refreshed": False, "reason": "state_changed"}
|
|
1378
|
+
_MANAGED_CONTAINERS_STATE["base_summary"] = refreshed_summary
|
|
1379
|
+
_MANAGED_CONTAINERS_STATE["initial_totals"] = refreshed_totals
|
|
1380
|
+
return {
|
|
1381
|
+
"refreshed": True,
|
|
1382
|
+
"inventory_updated_at": refreshed_summary.get("inventory_updated_at"),
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
|
|
1346
1386
|
def _load_managed_container_records() -> List[Dict[str, Any]]:
|
|
1347
1387
|
_ensure_containers_dir()
|
|
1348
1388
|
records: List[Dict[str, Any]] = []
|
|
@@ -1668,10 +1708,17 @@ def _compose_managed_containers_summary(
|
|
|
1668
1708
|
for entry in base_summary.get("containers", [])
|
|
1669
1709
|
if entry.get("vmid") is not None
|
|
1670
1710
|
}
|
|
1711
|
+
missing_vmids = {
|
|
1712
|
+
str(entry.get("vmid"))
|
|
1713
|
+
for entry in base_summary.get("missing_containers", [])
|
|
1714
|
+
if entry.get("vmid") is not None
|
|
1715
|
+
}
|
|
1671
1716
|
default_storage = summary.get("default_storage")
|
|
1672
1717
|
merged_containers: List[Dict[str, Any]] = []
|
|
1673
1718
|
for entry in managed_summary["containers"]:
|
|
1674
1719
|
vmid = str(entry.get("vmid")) if entry.get("vmid") is not None else None
|
|
1720
|
+
if vmid in missing_vmids:
|
|
1721
|
+
continue
|
|
1675
1722
|
base_entry = base_by_vmid.get(vmid) if vmid is not None else None
|
|
1676
1723
|
if base_entry:
|
|
1677
1724
|
merged = base_entry.copy()
|
|
@@ -1748,9 +1795,9 @@ def _reserve_container_resources(payload: Dict[str, Any], *, device_id: str, req
|
|
|
1748
1795
|
available_disk = summary.get("available_disk_gib")
|
|
1749
1796
|
if available_disk is not None and disk_gib > available_disk:
|
|
1750
1797
|
raise RuntimeError("Not enough disk space to create this container.")
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1798
|
+
# CPU is oversubscribed by design. Keep the requested share in the
|
|
1799
|
+
# reservation/inventory for accounting, but RAM and disk are the only
|
|
1800
|
+
# consumable resources that can reject provisioning.
|
|
1754
1801
|
|
|
1755
1802
|
_MANAGED_CONTAINERS_STATE["pending"][reservation_id] = {
|
|
1756
1803
|
"reservation_id": reservation_id,
|
|
@@ -2832,12 +2879,18 @@ def _register_container_record(vmid: int, payload: Dict[str, Any], reservation_i
|
|
|
2832
2879
|
if reservation_id:
|
|
2833
2880
|
_MANAGED_CONTAINERS_STATE["pending"].pop(reservation_id, None)
|
|
2834
2881
|
_MANAGED_CONTAINERS_STATE["records"][str(vmid)] = payload.copy()
|
|
2882
|
+
_MANAGED_CONTAINERS_STATE["revision"] = int(
|
|
2883
|
+
_MANAGED_CONTAINERS_STATE.get("revision") or 0
|
|
2884
|
+
) + 1
|
|
2835
2885
|
|
|
2836
2886
|
|
|
2837
2887
|
def _unregister_container_record(vmid: int) -> None:
|
|
2838
2888
|
_initialize_managed_containers_state()
|
|
2839
2889
|
with _MANAGED_CONTAINERS_STATE_LOCK:
|
|
2840
2890
|
_MANAGED_CONTAINERS_STATE["records"].pop(str(vmid), None)
|
|
2891
|
+
_MANAGED_CONTAINERS_STATE["revision"] = int(
|
|
2892
|
+
_MANAGED_CONTAINERS_STATE.get("revision") or 0
|
|
2893
|
+
) + 1
|
|
2841
2894
|
|
|
2842
2895
|
|
|
2843
2896
|
def _write_container_record(vmid: int, payload: Dict[str, Any], reservation_id: Optional[str] = None) -> None:
|
|
@@ -4186,7 +4239,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
4186
4239
|
reservation_id = _run_lifecycle_step(
|
|
4187
4240
|
"reserve_resources",
|
|
4188
4241
|
"Reserving capacity",
|
|
4189
|
-
"Reserving
|
|
4242
|
+
"Reserving RAM and disk capacity…",
|
|
4190
4243
|
"Capacity reserved.",
|
|
4191
4244
|
lambda: _reserve_container_resources(
|
|
4192
4245
|
payload, device_id=device_id, request_id=request_id
|
{portacode-1.5.31.dev0 → portacode-1.5.31.dev2}/portacode/connection/handlers/test_proxmox_infra.py
RENAMED
|
@@ -6,6 +6,7 @@ from unittest.mock import MagicMock, patch
|
|
|
6
6
|
from portacode.connection.handlers.proxmox_infra import (
|
|
7
7
|
RemoveProxmoxContainerHandler,
|
|
8
8
|
_build_full_container_summary,
|
|
9
|
+
_compose_managed_containers_summary,
|
|
9
10
|
_build_bootstrap_steps,
|
|
10
11
|
_cacheable_bootstrap_steps,
|
|
11
12
|
_claim_ctid_for_reservation,
|
|
@@ -25,11 +26,97 @@ from portacode.connection.handlers.proxmox_infra import (
|
|
|
25
26
|
_pinned_portacode_install_command,
|
|
26
27
|
_running_portacode_version_is_prerelease,
|
|
27
28
|
_require_successful_proxmox_task,
|
|
29
|
+
_reserve_container_resources,
|
|
30
|
+
reconcile_managed_containers_inventory,
|
|
28
31
|
_sanitize_project_paths,
|
|
29
32
|
)
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
class ProxmoxInfraHandlerTests(TestCase):
|
|
36
|
+
def test_reconciled_external_deletion_is_not_reinserted_from_local_record(self):
|
|
37
|
+
summary = _compose_managed_containers_summary(
|
|
38
|
+
[{"vmid": 144, "device_id": "42", "ram_mib": 2048, "disk_gib": 14, "cpus": 1}],
|
|
39
|
+
[],
|
|
40
|
+
{
|
|
41
|
+
"containers": [],
|
|
42
|
+
"missing_containers": [{"vmid": "144", "device_id": "42"}],
|
|
43
|
+
"allocated_ram_mib": 0,
|
|
44
|
+
"allocated_disk_gib": 0,
|
|
45
|
+
"allocated_cpu_share": 0,
|
|
46
|
+
},
|
|
47
|
+
{"ram_mib": 2048, "disk_gib": 14, "cpu_share": 1},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
self.assertEqual(summary["containers"], [])
|
|
51
|
+
self.assertEqual(summary["missing_containers"][0]["vmid"], "144")
|
|
52
|
+
|
|
53
|
+
@patch("portacode.connection.handlers.proxmox_infra._build_full_container_summary")
|
|
54
|
+
@patch("portacode.connection.handlers.proxmox_infra._load_config", return_value={"node": "pve"})
|
|
55
|
+
def test_reconciliation_atomically_replaces_inventory_baseline(self, _config, build_summary):
|
|
56
|
+
refreshed = {"inventory_updated_at": "new", "total_ram_mib": 2, "total_disk_gib": 3, "total_cpu_share": 1}
|
|
57
|
+
build_summary.return_value = refreshed
|
|
58
|
+
state = {
|
|
59
|
+
"initialized": True, "base_summary": {"inventory_updated_at": "old"},
|
|
60
|
+
"initial_totals": {}, "records": {"144": {"vmid": 144}},
|
|
61
|
+
"pending": {"reservation": {"ram_mib": 1}}, "revision": 4,
|
|
62
|
+
}
|
|
63
|
+
with patch("portacode.connection.handlers.proxmox_infra._MANAGED_CONTAINERS_STATE", state):
|
|
64
|
+
result = reconcile_managed_containers_inventory()
|
|
65
|
+
|
|
66
|
+
self.assertTrue(result["refreshed"])
|
|
67
|
+
self.assertIs(state["base_summary"], refreshed)
|
|
68
|
+
self.assertIn("reservation", state["pending"])
|
|
69
|
+
self.assertEqual(state["revision"], 4)
|
|
70
|
+
|
|
71
|
+
@patch("portacode.connection.handlers.proxmox_infra._load_config", return_value={"node": "pve"})
|
|
72
|
+
def test_reconciliation_discards_scan_when_managed_state_changes(self, _config):
|
|
73
|
+
state = {
|
|
74
|
+
"initialized": True, "base_summary": {"inventory_updated_at": "old"},
|
|
75
|
+
"initial_totals": {}, "records": {"144": {"vmid": 144}},
|
|
76
|
+
"pending": {}, "revision": 7,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
def concurrent_scan(_records, _config):
|
|
80
|
+
state["records"]["145"] = {"vmid": 145}
|
|
81
|
+
state["revision"] += 1
|
|
82
|
+
return {"inventory_updated_at": "stale scan"}
|
|
83
|
+
|
|
84
|
+
with patch("portacode.connection.handlers.proxmox_infra._MANAGED_CONTAINERS_STATE", state), patch(
|
|
85
|
+
"portacode.connection.handlers.proxmox_infra._build_full_container_summary",
|
|
86
|
+
side_effect=concurrent_scan,
|
|
87
|
+
):
|
|
88
|
+
result = reconcile_managed_containers_inventory()
|
|
89
|
+
|
|
90
|
+
self.assertEqual(result, {"refreshed": False, "reason": "state_changed"})
|
|
91
|
+
self.assertEqual(state["base_summary"]["inventory_updated_at"], "old")
|
|
92
|
+
|
|
93
|
+
def test_cpu_can_be_oversubscribed_when_ram_and_disk_are_available(self):
|
|
94
|
+
state = {
|
|
95
|
+
"initialized": True,
|
|
96
|
+
"base_summary": {
|
|
97
|
+
"available_ram_mib": 4096,
|
|
98
|
+
"available_disk_gib": 20,
|
|
99
|
+
"available_cpu_share": 0,
|
|
100
|
+
"allocated_ram_mib": 0,
|
|
101
|
+
"allocated_disk_gib": 0,
|
|
102
|
+
"allocated_cpu_share": 4,
|
|
103
|
+
},
|
|
104
|
+
"initial_totals": {"ram_mib": 0, "disk_gib": 0, "cpu_share": 0},
|
|
105
|
+
"records": {},
|
|
106
|
+
"pending": {},
|
|
107
|
+
}
|
|
108
|
+
with patch(
|
|
109
|
+
"portacode.connection.handlers.proxmox_infra._MANAGED_CONTAINERS_STATE", state
|
|
110
|
+
):
|
|
111
|
+
reservation_id = _reserve_container_resources(
|
|
112
|
+
{"ram_mib": 1024, "disk_gib": 3, "cpus": 2},
|
|
113
|
+
device_id="123",
|
|
114
|
+
request_id="request",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
self.assertIn(reservation_id, state["pending"])
|
|
118
|
+
self.assertEqual(state["pending"][reservation_id]["cpu_share"], 2)
|
|
119
|
+
|
|
33
120
|
@patch("portacode.connection.handlers.proxmox_infra._load_provisioning_templates")
|
|
34
121
|
@patch("portacode.connection.handlers.proxmox_infra._get_node_from_config", return_value="pve")
|
|
35
122
|
@patch("portacode.connection.handlers.proxmox_infra._connect_proxmox")
|
|
@@ -513,6 +513,15 @@ class TerminalManager:
|
|
|
513
513
|
self._periodic_provisioning_template_maintenance()
|
|
514
514
|
)
|
|
515
515
|
|
|
516
|
+
if getattr(self, "_proxmox_inventory_reconciliation_task", None):
|
|
517
|
+
try:
|
|
518
|
+
self._proxmox_inventory_reconciliation_task.cancel()
|
|
519
|
+
except Exception:
|
|
520
|
+
pass
|
|
521
|
+
self._proxmox_inventory_reconciliation_task = asyncio.create_task(
|
|
522
|
+
self._periodic_proxmox_inventory_reconciliation()
|
|
523
|
+
)
|
|
524
|
+
|
|
516
525
|
# Start exposed-services file monitor for realtime updates.
|
|
517
526
|
if getattr(self, "_exposed_services_task", None):
|
|
518
527
|
try:
|
|
@@ -686,6 +695,24 @@ class TerminalManager:
|
|
|
686
695
|
logger.exception("Provisioning template maintenance failed: %s", exc)
|
|
687
696
|
await asyncio.sleep(PROVISIONING_MAINTENANCE_INTERVAL_S)
|
|
688
697
|
|
|
698
|
+
async def _periodic_proxmox_inventory_reconciliation(self) -> None:
|
|
699
|
+
"""Periodically detect changes made directly through Proxmox."""
|
|
700
|
+
from .handlers.proxmox_infra import (
|
|
701
|
+
PROXMOX_INVENTORY_RECONCILE_INTERVAL_S,
|
|
702
|
+
reconcile_managed_containers_inventory,
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
while True:
|
|
706
|
+
await asyncio.sleep(PROXMOX_INVENTORY_RECONCILE_INTERVAL_S)
|
|
707
|
+
try:
|
|
708
|
+
result = await asyncio.to_thread(reconcile_managed_containers_inventory)
|
|
709
|
+
if result.get("reason") == "state_changed":
|
|
710
|
+
logger.debug("Discarded Proxmox inventory scan after concurrent state change")
|
|
711
|
+
except asyncio.CancelledError:
|
|
712
|
+
raise
|
|
713
|
+
except Exception as exc:
|
|
714
|
+
logger.warning("Proxmox inventory reconciliation failed safely: %s", exc)
|
|
715
|
+
|
|
689
716
|
def _read_exposed_services_snapshot(self) -> Dict[str, Any]:
|
|
690
717
|
path = EXPOSED_SERVICES_MONITOR_PATH
|
|
691
718
|
if not os.path.exists(path):
|
|
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.5.31.dev0 → portacode-1.5.31.dev2}/docs/cloudflared-domain-connect-containers-audit.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{portacode-1.5.31.dev0 → portacode-1.5.31.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
|
|
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
|