portacode 2.2.20.dev6__tar.gz → 2.2.20.dev7__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.
Files changed (452) hide show
  1. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/PKG-INFO +1 -1
  2. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/_version.py +2 -2
  3. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/README.md +12 -0
  4. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +126 -15
  5. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/browser_handlers.py +18 -0
  6. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/test_browser_handlers.py +22 -4
  7. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode.egg-info/PKG-INFO +1 -1
  8. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/.gitignore +0 -0
  9. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/LICENSE +0 -0
  10. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/MANIFEST.in +0 -0
  11. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/Makefile +0 -0
  12. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/README.md +0 -0
  13. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/build_android.sh +0 -0
  14. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/connect.py +0 -0
  15. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/connect.sh +0 -0
  16. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/cloudflared-domain-connect-containers-audit.md +0 -0
  17. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/creative-team-brief-portacode.md +0 -0
  18. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/device-health-alerting-plan.md +0 -0
  19. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/devops-messaging-ab-tests.md +0 -0
  20. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/guest-host-requests-plan.md +0 -0
  21. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/homepage-dashboard-positioning-fixes.md +0 -0
  22. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/template-engineering-roadmap.md +0 -0
  23. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/docs/template-guide.html +0 -0
  24. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/README.md +0 -0
  25. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/simple_device/Dockerfile +0 -0
  26. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/simple_device/README.md +0 -0
  27. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode +0 -0
  28. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode.pub +0 -0
  29. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/simple_device/docker-compose.yaml +0 -0
  30. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/Dockerfile +0 -0
  31. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/README.md +0 -0
  32. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode +0 -0
  33. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode.pub +0 -0
  34. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/.local/share/portacode/run/gateway.pid +0 -0
  35. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/.gitignore +0 -0
  36. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/README.md +0 -0
  37. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/db.sqlite3 +0 -0
  38. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__init__.py +0 -0
  39. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/__init__.cpython-311.pyc +0 -0
  40. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/settings.cpython-311.pyc +0 -0
  41. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/urls.cpython-311.pyc +0 -0
  42. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/wsgi.cpython-311.pyc +0 -0
  43. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/asgi.py +0 -0
  44. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/settings.py +0 -0
  45. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/urls.py +0 -0
  46. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/wsgi.py +0 -0
  47. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/manage.py +0 -0
  48. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/requirements.txt +0 -0
  49. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/templates/treats/home.html +0 -0
  50. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__init__.py +0 -0
  51. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/__init__.cpython-311.pyc +0 -0
  52. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/admin.cpython-311.pyc +0 -0
  53. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/apps.cpython-311.pyc +0 -0
  54. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/menu.cpython-311.pyc +0 -0
  55. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/models.cpython-311.pyc +0 -0
  56. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/urls.cpython-311.pyc +0 -0
  57. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/views.cpython-311.pyc +0 -0
  58. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/admin.py +0 -0
  59. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/apps.py +0 -0
  60. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/menu.py +0 -0
  61. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__init__.py +0 -0
  62. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
  63. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/models.py +0 -0
  64. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/tests.py +0 -0
  65. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/urls.py +0 -0
  66. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-01/workspace/treats/views.py +0 -0
  67. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode +0 -0
  68. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode.pub +0 -0
  69. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/README.md +0 -0
  70. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/__init__.py +0 -0
  71. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/asgi.py +0 -0
  72. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/settings.py +0 -0
  73. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/urls.py +0 -0
  74. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/wsgi.py +0 -0
  75. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/manage.py +0 -0
  76. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/requirements.txt +0 -0
  77. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/templates/treats/home.html +0 -0
  78. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/__init__.py +0 -0
  79. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/admin.py +0 -0
  80. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/apps.py +0 -0
  81. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/menu.py +0 -0
  82. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/migrations/__init__.py +0 -0
  83. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/models.py +0 -0
  84. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/tests.py +0 -0
  85. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/urls.py +0 -0
  86. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-02/workspace/treats/views.py +0 -0
  87. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode +0 -0
  88. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode.pub +0 -0
  89. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/README.md +0 -0
  90. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/__init__.py +0 -0
  91. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/asgi.py +0 -0
  92. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/settings.py +0 -0
  93. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/urls.py +0 -0
  94. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/wsgi.py +0 -0
  95. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/manage.py +0 -0
  96. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/requirements.txt +0 -0
  97. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/templates/treats/home.html +0 -0
  98. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/__init__.py +0 -0
  99. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/admin.py +0 -0
  100. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/apps.py +0 -0
  101. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/menu.py +0 -0
  102. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/migrations/__init__.py +0 -0
  103. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/models.py +0 -0
  104. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/tests.py +0 -0
  105. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/urls.py +0 -0
  106. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-03/workspace/treats/views.py +0 -0
  107. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode +0 -0
  108. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode.pub +0 -0
  109. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/README.md +0 -0
  110. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/__init__.py +0 -0
  111. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/asgi.py +0 -0
  112. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/settings.py +0 -0
  113. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/urls.py +0 -0
  114. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/wsgi.py +0 -0
  115. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/manage.py +0 -0
  116. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/requirements.txt +0 -0
  117. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/templates/treats/home.html +0 -0
  118. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/__init__.py +0 -0
  119. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/admin.py +0 -0
  120. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/apps.py +0 -0
  121. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/menu.py +0 -0
  122. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/migrations/__init__.py +0 -0
  123. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/models.py +0 -0
  124. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/tests.py +0 -0
  125. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/urls.py +0 -0
  126. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-04/workspace/treats/views.py +0 -0
  127. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode +0 -0
  128. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode.pub +0 -0
  129. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/README.md +0 -0
  130. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/__init__.py +0 -0
  131. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/asgi.py +0 -0
  132. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/settings.py +0 -0
  133. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/urls.py +0 -0
  134. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/wsgi.py +0 -0
  135. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/manage.py +0 -0
  136. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/requirements.txt +0 -0
  137. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/templates/treats/home.html +0 -0
  138. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/__init__.py +0 -0
  139. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/admin.py +0 -0
  140. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/apps.py +0 -0
  141. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/menu.py +0 -0
  142. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/migrations/__init__.py +0 -0
  143. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/models.py +0 -0
  144. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/tests.py +0 -0
  145. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/urls.py +0 -0
  146. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-05/workspace/treats/views.py +0 -0
  147. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode +0 -0
  148. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode.pub +0 -0
  149. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/README.md +0 -0
  150. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/__init__.py +0 -0
  151. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/asgi.py +0 -0
  152. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/settings.py +0 -0
  153. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/urls.py +0 -0
  154. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/wsgi.py +0 -0
  155. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/manage.py +0 -0
  156. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/requirements.txt +0 -0
  157. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/templates/treats/home.html +0 -0
  158. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/__init__.py +0 -0
  159. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/admin.py +0 -0
  160. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/apps.py +0 -0
  161. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/menu.py +0 -0
  162. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/migrations/__init__.py +0 -0
  163. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/models.py +0 -0
  164. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/tests.py +0 -0
  165. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/urls.py +0 -0
  166. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-06/workspace/treats/views.py +0 -0
  167. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode +0 -0
  168. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode.pub +0 -0
  169. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/README.md +0 -0
  170. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/__init__.py +0 -0
  171. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/asgi.py +0 -0
  172. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/settings.py +0 -0
  173. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/urls.py +0 -0
  174. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/wsgi.py +0 -0
  175. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/manage.py +0 -0
  176. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/requirements.txt +0 -0
  177. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/templates/treats/home.html +0 -0
  178. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/__init__.py +0 -0
  179. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/admin.py +0 -0
  180. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/apps.py +0 -0
  181. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/menu.py +0 -0
  182. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/migrations/__init__.py +0 -0
  183. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/models.py +0 -0
  184. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/tests.py +0 -0
  185. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/urls.py +0 -0
  186. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-07/workspace/treats/views.py +0 -0
  187. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode +0 -0
  188. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode.pub +0 -0
  189. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/README.md +0 -0
  190. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/__init__.py +0 -0
  191. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/asgi.py +0 -0
  192. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/settings.py +0 -0
  193. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/urls.py +0 -0
  194. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/wsgi.py +0 -0
  195. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/manage.py +0 -0
  196. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/requirements.txt +0 -0
  197. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/templates/treats/home.html +0 -0
  198. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/__init__.py +0 -0
  199. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/admin.py +0 -0
  200. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/apps.py +0 -0
  201. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/menu.py +0 -0
  202. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/migrations/__init__.py +0 -0
  203. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/models.py +0 -0
  204. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/tests.py +0 -0
  205. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/urls.py +0 -0
  206. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-08/workspace/treats/views.py +0 -0
  207. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode +0 -0
  208. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode.pub +0 -0
  209. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/README.md +0 -0
  210. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/__init__.py +0 -0
  211. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/asgi.py +0 -0
  212. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/settings.py +0 -0
  213. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/urls.py +0 -0
  214. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/wsgi.py +0 -0
  215. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/manage.py +0 -0
  216. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/requirements.txt +0 -0
  217. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/templates/treats/home.html +0 -0
  218. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/__init__.py +0 -0
  219. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/admin.py +0 -0
  220. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/apps.py +0 -0
  221. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/menu.py +0 -0
  222. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/migrations/__init__.py +0 -0
  223. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/models.py +0 -0
  224. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/tests.py +0 -0
  225. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/urls.py +0 -0
  226. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-09/workspace/treats/views.py +0 -0
  227. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode +0 -0
  228. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode.pub +0 -0
  229. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/README.md +0 -0
  230. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/__init__.py +0 -0
  231. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/asgi.py +0 -0
  232. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/settings.py +0 -0
  233. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/urls.py +0 -0
  234. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/wsgi.py +0 -0
  235. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/manage.py +0 -0
  236. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/requirements.txt +0 -0
  237. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/templates/treats/home.html +0 -0
  238. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/__init__.py +0 -0
  239. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/admin.py +0 -0
  240. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/apps.py +0 -0
  241. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/menu.py +0 -0
  242. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/migrations/__init__.py +0 -0
  243. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/models.py +0 -0
  244. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/tests.py +0 -0
  245. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/urls.py +0 -0
  246. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/data/student-10/workspace/treats/views.py +0 -0
  247. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/docker-compose.yaml +0 -0
  248. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/README.md +0 -0
  249. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/galactic_bakeshop/__init__.py +0 -0
  250. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/galactic_bakeshop/asgi.py +0 -0
  251. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/galactic_bakeshop/settings.py +0 -0
  252. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/galactic_bakeshop/urls.py +0 -0
  253. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/galactic_bakeshop/wsgi.py +0 -0
  254. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/manage.py +0 -0
  255. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/requirements.txt +0 -0
  256. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/templates/treats/home.html +0 -0
  257. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/__init__.py +0 -0
  258. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/admin.py +0 -0
  259. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/apps.py +0 -0
  260. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/menu.py +0 -0
  261. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/migrations/__init__.py +0 -0
  262. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/models.py +0 -0
  263. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/tests.py +0 -0
  264. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/urls.py +0 -0
  265. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/initial_content/treats/views.py +0 -0
  266. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/examples/workshop_fleet/instructions/WELCOME.md +0 -0
  267. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/README.md +0 -0
  268. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/__init__.py +0 -0
  269. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/__main__.py +0 -0
  270. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/assets/skills/portacode-github/SKILL.md +0 -0
  271. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/assets/skills/portacode-github/agents/openai.yaml +0 -0
  272. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/assets/skills/portacode-github/scripts/create_repository.py +0 -0
  273. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/assets/skills/portacode-image/SKILL.md +0 -0
  274. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/assets/skills/portacode-image/agents/openai.yaml +0 -0
  275. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/browser_cli.py +0 -0
  276. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/cli.py +0 -0
  277. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/codex_loopback_proxy.py +0 -0
  278. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/codex_prepare.py +0 -0
  279. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/codex_usage_limit.py +0 -0
  280. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/README.md +0 -0
  281. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/__init__.py +0 -0
  282. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/client.py +0 -0
  283. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/codex_app_server.py +0 -0
  284. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/guest_host_protocol.py +0 -0
  285. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/__init__.py +0 -0
  286. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/automation_v2_handlers.py +0 -0
  287. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/base.py +0 -0
  288. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/chunked_content.py +0 -0
  289. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/cloudflare_forwarding.py +0 -0
  290. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/cloudflare_tunnel.py +0 -0
  291. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/codex_handlers.py +0 -0
  292. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/diff_handlers.py +0 -0
  293. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/file_handlers.py +0 -0
  294. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/file_transfer_handlers.py +0 -0
  295. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/git_handlers.py +0 -0
  296. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
  297. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/README.md +0 -0
  298. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/__init__.py +0 -0
  299. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
  300. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/git_manager.py +0 -0
  301. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/handlers.py +0 -0
  302. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/manager.py +0 -0
  303. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/models.py +0 -0
  304. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/test_handlers.py +0 -0
  305. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state/utils.py +0 -0
  306. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/project_state_handlers.py +0 -0
  307. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/proxmox_infra.py +0 -0
  308. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/registry.py +0 -0
  309. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/resumable_transfer_handlers.py +0 -0
  310. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/runtime_user.py +0 -0
  311. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/session.py +0 -0
  312. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/system_handlers.py +0 -0
  313. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/tab_factory.py +0 -0
  314. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/terminal_handlers.py +0 -0
  315. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/test_cloudflare_forwarding.py +0 -0
  316. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/test_file_move_copy.py +0 -0
  317. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/test_git_handlers.py +0 -0
  318. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/test_proxmox_infra.py +0 -0
  319. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/test_runtime_user.py +0 -0
  320. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/handlers/update_handler.py +0 -0
  321. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/multiplex.py +0 -0
  322. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/terminal.py +0 -0
  323. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/test_guest_host_protocol.py +0 -0
  324. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/test_guest_host_terminal.py +0 -0
  325. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/test_webmin_proxy_config.py +0 -0
  326. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/connection/webmin_proxy_config.py +0 -0
  327. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/data.py +0 -0
  328. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/exit_codes.py +0 -0
  329. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/github_credential.py +0 -0
  330. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/image_cli.py +0 -0
  331. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/keypair.py +0 -0
  332. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/__init__.py +0 -0
  333. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
  334. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/__pycache__/__init__.cpython-38.pyc +0 -0
  335. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
  336. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-38.pyc +0 -0
  337. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/elinks +0 -0
  338. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/gio-open +0 -0
  339. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/gnome-open +0 -0
  340. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/gvfs-open +0 -0
  341. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/kde-open +0 -0
  342. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/kfmclient +0 -0
  343. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/link_capture_exec.sh +0 -0
  344. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/link_capture_wrapper.py +0 -0
  345. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/links +0 -0
  346. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/links2 +0 -0
  347. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/lynx +0 -0
  348. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/mate-open +0 -0
  349. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/netsurf +0 -0
  350. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/sensible-browser +0 -0
  351. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/w3m +0 -0
  352. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/x-www-browser +0 -0
  353. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/link_capture/bin/xdg-open +0 -0
  354. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/logging_categories.py +0 -0
  355. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/pairing.py +0 -0
  356. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/provisioning_cache.py +0 -0
  357. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/restart.py +0 -0
  358. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/service.py +0 -0
  359. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/singleton.py +0 -0
  360. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/static/js/test-ntp-clock.html +0 -0
  361. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/static/js/utils/ntp-clock.js +0 -0
  362. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/test_runtime_paths.py +0 -0
  363. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/test_service.py +0 -0
  364. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/test_singleton.py +0 -0
  365. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/test_terminal_exposed_services.py +0 -0
  366. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_automation_v2_inputs.py +0 -0
  367. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_browser_cli.py +0 -0
  368. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_cli_service_logs.py +0 -0
  369. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_codex_app_server.py +0 -0
  370. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_codex_handlers.py +0 -0
  371. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_codex_loopback_proxy.py +0 -0
  372. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_codex_prepare.py +0 -0
  373. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_github_credential.py +0 -0
  374. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_image_cli.py +0 -0
  375. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_image_read_handler.py +0 -0
  376. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_resumable_transfer_handlers.py +0 -0
  377. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_system_handlers.py +0 -0
  378. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_terminal_periodic_system_info.py +0 -0
  379. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tests/test_terminal_session_shell.py +0 -0
  380. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/__init__.py +0 -0
  381. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/cloudflared_login.py +0 -0
  382. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/ensure_cloudflared.py +0 -0
  383. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/ensure_pyyaml.py +0 -0
  384. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/forwarding_state.py +0 -0
  385. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/get_domain.py +0 -0
  386. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/privileged.py +0 -0
  387. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/service_install.py +0 -0
  388. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/tunneling/state.py +0 -0
  389. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/updater.py +0 -0
  390. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
  391. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/utils/__init__.py +0 -0
  392. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/utils/diff_apply.py +0 -0
  393. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/utils/diff_renderer.py +0 -0
  394. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/utils/ntp_clock.py +0 -0
  395. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode/utils/runtime_paths.py +0 -0
  396. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode.egg-info/SOURCES.txt +0 -0
  397. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode.egg-info/dependency_links.txt +0 -0
  398. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode.egg-info/entry_points.txt +0 -0
  399. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode.egg-info/requires.txt +0 -0
  400. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/portacode.egg-info/top_level.txt +0 -0
  401. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/pyproject.toml +0 -0
  402. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/run_tests.py +0 -0
  403. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/scripts/diagnose_codex_gateway.py +0 -0
  404. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/setup.cfg +0 -0
  405. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/setup.py +0 -0
  406. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test.sh +0 -0
  407. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/README.md +0 -0
  408. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/__init__.py +0 -0
  409. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_device_online.py +0 -0
  410. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_file_operations.py +0 -0
  411. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_git_status_ui.py +0 -0
  412. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_login_flow.py +0 -0
  413. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_navigate_testing_folder.py +0 -0
  414. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_play_store_screenshots.py +0 -0
  415. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_terminal_buffer_performance.py +0 -0
  416. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_terminal_interaction.py +0 -0
  417. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_terminal_loading_race_condition.py +0 -0
  418. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_modules/test_terminal_start.py +0 -0
  419. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_request_id.py +0 -0
  420. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/test_session_terminal_shutdown.py +0 -0
  421. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/.env.example +0 -0
  422. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/README.md +0 -0
  423. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/__init__.py +0 -0
  424. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/cli.py +0 -0
  425. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/__init__.py +0 -0
  426. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/base_test.py +0 -0
  427. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/cli_manager.py +0 -0
  428. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/hierarchical_runner.py +0 -0
  429. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/playwright_manager.py +0 -0
  430. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/runner.py +0 -0
  431. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/shared_cli_manager.py +0 -0
  432. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/core/test_discovery.py +0 -0
  433. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/testing_framework/requirements.txt +0 -0
  434. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md +0 -0
  435. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/UI_UX/server_occasionally_stops_communicating_with_all_devices.md +0 -0
  436. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/agent_context_management.md +0 -0
  437. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/django_server_time_sync.md +0 -0
  438. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/device_performance_degradation.md +0 -0
  439. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
  440. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/indefinite_resource_loading.md +0 -0
  441. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/portacode_service_silently_down.md +0 -0
  442. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/premature_terminal_exit.md +0 -0
  443. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/project_cpu_hotspots.md +0 -0
  444. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/terminals_exit_upon_starting.md +0 -0
  445. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/websocket_client_silently_dead.md +0 -0
  446. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/issues/wrong_item_classification_on_client_side.md +0 -0
  447. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/todo/smartphone_terminal_input_frustrations.md +0 -0
  448. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/tools/generate_play_store_assets.py +0 -0
  449. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/tools/pairing_tester.py +0 -0
  450. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/tools/run_screenshot_suite.sh +0 -0
  451. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/tools/test_python_ntp_clock.py +0 -0
  452. {portacode-2.2.20.dev6 → portacode-2.2.20.dev7}/validate.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 2.2.20.dev6
3
+ Version: 2.2.20.dev7
4
4
  Summary: Device agent for the AI platform that builds, tests, deploys, and operates real software
5
5
  Home-page: https://portacode.com/
6
6
  Author: Meena Erian
@@ -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 = '2.2.20.dev6'
22
- __version_tuple__ = version_tuple = (2, 2, 20, 'dev6')
21
+ __version__ = version = '2.2.20.dev7'
22
+ __version_tuple__ = version_tuple = (2, 2, 20, 'dev7')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -43,6 +43,18 @@ The handler system consists of:
43
43
  - Provides system resource information
44
44
  - Returns CPU, memory, and disk usage data
45
45
 
46
+ ### Browser Handlers (`browser_handlers.py`)
47
+
48
+ 1. **`BrowserConfigHandler`** - `browser_config`
49
+ - Reads or atomically persists runtime-user browser viewport and recording dimensions
50
+ - Returns `browser_config_response`; the same effective values appear in `system_info.info.browser_config`
51
+
52
+ 2. **`BrowserRunHandler`** - `browser_run`
53
+ - Runs up to 30 Playwright navigation, interaction, assertion, read, bounded DOM, and screenshot steps in a named persistent profile
54
+ - Applies saved dimensions unless the request supplies per-run overrides and returns `browser_run_response`
55
+ - Returns screenshots inline, a device-side `video_path` for recordings, and uses the standard chunk framing for large responses
56
+ - Adds polished cursor, pacing, focus, ripple, typing, and desktop zoom effects only while recording video; non-recorded automation stays fast
57
+
46
58
  ## Adding New Handlers
47
59
 
48
60
  ### 1. Asynchronous Handlers
@@ -119,6 +119,8 @@ This document describes the complete protocol for communicating with devices thr
119
119
  - [`terminal_exec`](#terminal_exec)
120
120
  - [System Actions](#system-actions)
121
121
  - [`system_info`](#system_info)
122
+ - [`browser_config`](#browser_config)
123
+ - [`browser_run`](#browser_run)
122
124
  - [`update_portacode_cli`](#update_portacode_cli)
123
125
  - [`clock_sync_request`](#clock_sync_request)
124
126
  - [File Actions](#file-actions)
@@ -171,6 +173,8 @@ This document describes the complete protocol for communicating with devices thr
171
173
  - [`terminal_list`](#terminal_list-event)
172
174
  - [System Events](#system-events)
173
175
  - [`system_info`](#system_info-event)
176
+ - [`browser_config_response`](#browser_config_response)
177
+ - [`browser_run_response`](#browser_run_response)
174
178
  - [`update_portacode_response`](#update_portacode_response)
175
179
  - [`clock_sync_response`](#clock_sync_response)
176
180
  - [File Events](#file-events)
@@ -429,6 +433,96 @@ This action does not require any payload fields.
429
433
 
430
434
  * On success, the device will respond with a [`system_info`](#system_info-event) event.
431
435
 
436
+ ### `browser_config`
437
+
438
+ Reads or atomically updates the runtime user's persistent browser dimensions.
439
+ Handled by [`BrowserConfigHandler`](./browser_handlers.py). Omitting `config`
440
+ performs a read without changing the saved values.
441
+
442
+ **Payload Fields:**
443
+
444
+ * `config` (object, optional): Sections to merge into the saved configuration.
445
+ * `viewport` (object, optional): `width` and/or `height` for browser pages.
446
+ * `video` (object, optional): `width` and/or `height` for recordings.
447
+ * Every supplied dimension must be an integer from 240 through 1920. Unknown
448
+ sections and fields are rejected.
449
+
450
+ **Responses:**
451
+
452
+ * On success, the device responds with
453
+ [`browser_config_response`](#browser_config_response).
454
+ * The resulting configuration is also reported at
455
+ `system_info.info.browser_config` and becomes the default for later runs.
456
+
457
+ Example read:
458
+
459
+ ```json
460
+ {"cmd":"browser_config"}
461
+ ```
462
+
463
+ Example update:
464
+
465
+ ```json
466
+ {
467
+ "cmd": "browser_config",
468
+ "config": {
469
+ "viewport": {"width": 390, "height": 844},
470
+ "video": {"width": 390, "height": 844}
471
+ }
472
+ }
473
+ ```
474
+
475
+ ### `browser_run`
476
+
477
+ Runs a bounded Playwright batch in a persistent, runtime-user-scoped Chromium
478
+ profile. Handled by [`BrowserRunHandler`](./browser_handlers.py). A safe logical
479
+ `session_id` preserves cookies and local storage between calls.
480
+
481
+ **Payload Fields:**
482
+
483
+ * `session_id` (string, optional): Profile name containing only letters,
484
+ numbers, dot, dash, or underscore; defaults to `default`.
485
+ * `start_url` (string, optional): Initial page to load.
486
+ * `steps` (array, optional): At most 30 ordered operations: `goto`, `click`,
487
+ `fill`, `press`, `select`, `check`, `uncheck`, `wait`, `assert`, `read`,
488
+ `dom`, or `screenshot`. Locators support CSS (`css` or `selector`) and the
489
+ semantic `role`/`name`, `label`, `text`, and `testid` forms, with optional
490
+ `nth`. A `dom` step returns bounded `outerHTML` for `selector` (or `body`),
491
+ with `max_chars` clamped to 200–20000.
492
+ * `timeout_ms` (integer, optional): Per-operation timeout, clamped to
493
+ 250–30000 milliseconds.
494
+ * `viewport` (object, optional): Per-run `width`/`height` override. Missing
495
+ fields retain the saved viewport values; dimensions must be 240–1920.
496
+ * `video` (object, optional): Per-run recording-size override with the same
497
+ merge and dimension rules. It does not enable recording by itself.
498
+ * `record_video` (boolean, optional): Record the run and return its device-side
499
+ path. Recorded runs have a 180-second action deadline.
500
+ * `final_screenshot` (boolean, optional): Capture the final viewport; defaults
501
+ to true.
502
+ * `screenshot_on_failure` (boolean, optional): Capture the viewport at a failed
503
+ step; defaults to true.
504
+ * `image_quality` (integer, optional): JPEG quality, clamped to 30–85.
505
+
506
+ Saved `browser_config` values are applied first and per-run `viewport`/`video`
507
+ fields override them. Screenshots use the active viewport; a `full_page`
508
+ screenshot may be taller than it. Recordings always keep the configured video
509
+ frame size and aspect ratio.
510
+
511
+ When video recording is enabled, the device automatically adds presentation
512
+ pacing: a virtual cursor, smooth movement and scrolling, target highlighting,
513
+ click ripples, human-paced non-password typing, pauses, and desktop zoom. This
514
+ layer is intentionally disabled for non-recorded automation, so screenshots,
515
+ DOM inspection, reads, assertions, and ordinary browser use remain fast.
516
+
517
+ **Responses:**
518
+
519
+ * The device responds with
520
+ [`browser_run_response`](#browser_run_response), including failures that
521
+ have a useful failure screenshot.
522
+ * Large responses use the standard chunk envelope with `browser_chunked=true`;
523
+ concatenate `chunk_content` in chunk order and parse the resulting JSON as
524
+ the ordinary response.
525
+
432
526
  ### `setup_proxmox_infra`
433
527
 
434
528
  Configures a Proxmox node for Portacode infrastructure usage (API token validation, automatic storage/template detection, bridge/NAT setup, and connectivity verification). Handled by [`ConfigureProxmoxInfraHandler`](./proxmox_infra.py).
@@ -1419,6 +1513,9 @@ Provides system information in response to a `system_info` action. Handled by [`
1419
1513
  * `available` (boolean): True when Playwright knows an executable path.
1420
1514
  * `executable_path` (string|null): Absolute path to the browser binary when known.
1421
1515
  * `error` (string|null): Any warning message captured while probing Playwright.
1516
+ * `browser_config` (object): Persistent defaults used by browser automation:
1517
+ * `viewport` (object): Browser page `width` and `height` in pixels.
1518
+ * `video` (object): Recorded video `width` and `height` in pixels.
1422
1519
  * `proxmox` (object): Detection hints for Proxmox VE nodes:
1423
1520
  * `is_proxmox_node` (boolean): True when Proxmox artifacts (e.g., `/etc/proxmox-release`) exist.
1424
1521
  * `version` (string|null): Raw contents of `/etc/proxmox-release` when readable.
@@ -2141,23 +2238,37 @@ Confirms the result of a git commit operation.
2141
2238
  * `error` (string, optional): Error message if the operation failed.
2142
2239
  * `commit_hash` (string, optional): The SHA hash of the new commit if successful.
2143
2240
 
2144
- ### Client Session Events
2241
+ ### <a name="browser_config_response"></a>`browser_config_response`
2145
2242
 
2146
- ### `browser_run`
2243
+ Returns the complete effective configuration after a `browser_config` read or
2244
+ update.
2245
+
2246
+ * `config` (object): `viewport` and `video` objects, each containing integer
2247
+ `width` and `height` values.
2248
+
2249
+ ### <a name="browser_run_response"></a>`browser_run_response`
2147
2250
 
2148
- Runs a bounded Playwright action batch in a persistent, runtime-user-scoped
2149
- Chromium profile. `session_id` is a safe logical name, never a filesystem path.
2150
- The handler accepts at most 30 `steps`; supported operations are `goto`,
2151
- `click`, `fill`, `press`, `select`, `check`, `uncheck`, `wait`, `assert`, and
2152
- `screenshot`. Selectors may use CSS or the semantic `role`/`name`, `label`,
2153
- `text`, and `testid` forms. Optional recording is stored below the runtime
2154
- user's Portacode browser data directory and returned as `video_path`; recording
2155
- bytes are not placed on the control channel.
2156
-
2157
- The `browser_run_response` contains compact per-step outcomes, final URL/title,
2158
- bounded JPEG screenshots encoded as base64, and an optional absolute recording
2159
- path. `success` describes protocol execution while `ok` describes whether all
2160
- browser steps passed, allowing a failure screenshot to reach the caller.
2251
+ Returns the browser batch result.
2252
+
2253
+ * `success` (boolean): True only when every browser step passed.
2254
+ * `ok` (boolean): Playwright batch result; currently equivalent to `success`.
2255
+ * `session_id` (string): Profile used for the run.
2256
+ * `steps` (array): Compact outcomes with step index `i`, `op`, `ok`, and an
2257
+ optional returned `value` or bounded `error`.
2258
+ * `url` and `title` (string, success only): Final page identity.
2259
+ * `screenshots` (array): JPEG captures with `step`, base64 `data`,
2260
+ `mime_type`, and optional `failure=true`.
2261
+ * `video_path` (string, recorded runs): Absolute path on the device. Video
2262
+ bytes are not sent over the control channel.
2263
+ * `error` (string, failed runs): Bounded failure detail. A failed run remains
2264
+ a normal `browser_run_response` with `success=false`, preserving completed
2265
+ step results and any failure screenshot.
2266
+
2267
+ For chunked responses, each envelope also contains `browser_chunked=true`, a
2268
+ shared `transfer_id`, chunk metadata, and `chunk_content` holding a slice of the
2269
+ serialized complete response.
2270
+
2271
+ ### Client Session Events
2161
2272
 
2162
2273
  ### <a name="request_client_sessions"></a>`request_client_sessions`
2163
2274
 
@@ -490,6 +490,24 @@ class BrowserRunHandler(AsyncHandler):
490
490
  if playwright_js := _playwright_js_package():
491
491
  env["PORTACODE_PLAYWRIGHT_JS"] = playwright_js
492
492
  argv = wrap_argv_for_user([_node_executable(), "-e", _RUNNER], user, login=False)
493
+ existing_worker = _WORKERS.get((user, session_id))
494
+ session_is_live = bool(
495
+ existing_worker
496
+ and (existing_worker.process is None or existing_worker.process.returncode is None)
497
+ )
498
+ if not message.get("start_url") and not session_is_live:
499
+ return {
500
+ "event": "browser_run_response",
501
+ "success": False,
502
+ "ok": False,
503
+ "session_id": session_id,
504
+ "error": (
505
+ f"Browser session {session_id!r} is not active. "
506
+ "Provide start_url to create or restore it."
507
+ ),
508
+ "screenshots": [],
509
+ "steps": [],
510
+ }
493
511
  worker = await _worker_for(
494
512
  user=user, session_id=session_id, argv=argv, env=env,
495
513
  )
@@ -95,7 +95,7 @@ class BrowserRunHandlerTests(unittest.IsolatedAsyncioTestCase):
95
95
  async def test_reuses_worker_for_same_runtime_user_and_session(self):
96
96
  worker = AsyncMock()
97
97
  worker.run.return_value = {"ok": True, "steps": [], "screenshots": []}
98
- message = {"session_id": "safe", "steps": [], "final_screenshot": False}
98
+ message = {"session_id": "safe", "start_url": "about:blank", "steps": [], "final_screenshot": False}
99
99
  with (
100
100
  patch.object(browser_handlers, "get_default_runtime_user", return_value="tester"),
101
101
  patch.object(browser_handlers, "get_runtime_user_home", return_value="/tmp"),
@@ -138,11 +138,27 @@ class BrowserRunHandlerTests(unittest.IsolatedAsyncioTestCase):
138
138
  patch.object(browser_handlers, "_worker_for", AsyncMock(return_value=worker)),
139
139
  ):
140
140
  result = await self.handler.execute(
141
- {"session_id": "failure", "steps": [], "final_screenshot": False}
141
+ {"session_id": "failure", "start_url": "about:blank", "steps": [], "final_screenshot": False}
142
142
  )
143
143
  self.assertFalse(result["success"])
144
144
  self.assertEqual(result["error"], "expected text")
145
145
 
146
+ async def test_missing_session_requires_start_url(self):
147
+ browser_handlers._WORKERS.clear()
148
+ with (
149
+ patch.object(browser_handlers, "get_default_runtime_user", return_value="tester"),
150
+ patch.object(browser_handlers, "get_runtime_user_home", return_value="/tmp"),
151
+ patch.object(browser_handlers, "mkdir_with_owner"),
152
+ patch.object(browser_handlers, "wrap_argv_for_user", return_value=["node"]),
153
+ patch.object(browser_handlers, "_node_path", AsyncMock(return_value="/modules")),
154
+ patch.object(browser_handlers, "_node_executable", return_value="/bundled/node"),
155
+ patch.object(browser_handlers, "_playwright_js_package", return_value=None),
156
+ ):
157
+ result = await self.handler.execute({"session_id": "lost", "steps": []})
158
+ self.assertFalse(result["success"])
159
+ self.assertIn("Provide start_url", result["error"])
160
+ self.assertEqual(result["screenshots"], [])
161
+
146
162
  async def test_worker_registry_separates_users_and_sessions(self):
147
163
  browser_handlers._WORKERS.clear()
148
164
  first = await browser_handlers._worker_for(
@@ -240,8 +256,8 @@ class BrowserRunHandlerTests(unittest.IsolatedAsyncioTestCase):
240
256
  patch.object(browser_handlers, "_playwright_js_package", return_value=None),
241
257
  patch.object(browser_handlers, "_worker_for", AsyncMock(return_value=worker)),
242
258
  ):
243
- await self.handler.execute({"session_id":"fast","steps":[],"record_video":False})
244
- await self.handler.execute({"session_id":"demo","steps":[],"record_video":True})
259
+ await self.handler.execute({"session_id":"fast","start_url":"about:blank","steps":[],"record_video":False})
260
+ await self.handler.execute({"session_id":"demo","start_url":"about:blank","steps":[],"record_video":True})
245
261
  self.assertFalse(worker.run.await_args_list[0].args[0]["demo"])
246
262
  self.assertTrue(worker.run.await_args_list[1].args[0]["demo"])
247
263
 
@@ -267,6 +283,7 @@ class BrowserRunHandlerTests(unittest.IsolatedAsyncioTestCase):
267
283
  })
268
284
  await self.handler.execute({
269
285
  "session_id": "mobile", "steps": [], "record_video": True,
286
+ "start_url": "about:blank",
270
287
  "final_screenshot": False,
271
288
  })
272
289
  saved = json.loads(
@@ -294,6 +311,7 @@ class BrowserRunHandlerTests(unittest.IsolatedAsyncioTestCase):
294
311
  ):
295
312
  await self.handler.execute({
296
313
  "session_id": "override", "steps": [], "record_video": True,
314
+ "start_url": "about:blank",
297
315
  "viewport": {"width": 430}, "video": {"height": 932},
298
316
  })
299
317
  run_config = worker.run.await_args.args[0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 2.2.20.dev6
3
+ Version: 2.2.20.dev7
4
4
  Summary: Device agent for the AI platform that builds, tests, deploys, and operates real software
5
5
  Home-page: https://portacode.com/
6
6
  Author: Meena Erian
File without changes