portacode 2.2.22.dev0__tar.gz → 2.2.22.dev1__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 (456) hide show
  1. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/PKG-INFO +1 -1
  2. portacode-2.2.22.dev1/docs/template-engineering-roadmap.md +414 -0
  3. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/_version.py +2 -2
  4. portacode-2.2.22.dev1/portacode/browser_prepare.py +117 -0
  5. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/codex_prepare.py +21 -6
  6. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/proxmox_infra.py +57 -105
  7. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/test_browser_handlers.py +4 -4
  8. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/test_proxmox_infra.py +12 -27
  9. portacode-2.2.22.dev1/portacode/tests/test_browser_prepare.py +123 -0
  10. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_codex_prepare.py +38 -0
  11. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode.egg-info/PKG-INFO +1 -1
  12. portacode-2.2.22.dev1/portacode.egg-info/SOURCES.txt +232 -0
  13. portacode-2.2.22.dev0/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode +0 -15
  14. portacode-2.2.22.dev0/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode.pub +0 -6
  15. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode +0 -15
  16. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode.pub +0 -6
  17. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/.local/share/portacode/run/gateway.pid +0 -1
  18. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/.gitignore +0 -2
  19. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/db.sqlite3 +0 -0
  20. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/__init__.cpython-311.pyc +0 -0
  21. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/settings.cpython-311.pyc +0 -0
  22. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/urls.cpython-311.pyc +0 -0
  23. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/wsgi.cpython-311.pyc +0 -0
  24. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/templates/treats/home.html +0 -137
  25. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/__init__.cpython-311.pyc +0 -0
  26. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/admin.cpython-311.pyc +0 -0
  27. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/apps.cpython-311.pyc +0 -0
  28. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/menu.cpython-311.pyc +0 -0
  29. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/models.cpython-311.pyc +0 -0
  30. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/urls.cpython-311.pyc +0 -0
  31. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/views.cpython-311.pyc +0 -0
  32. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/menu.py +0 -69
  33. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
  34. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace/treats/views.py +0 -28
  35. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode +0 -15
  36. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode.pub +0 -6
  37. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/README.md +0 -38
  38. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/__init__.py +0 -1
  39. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/asgi.py +0 -13
  40. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/settings.py +0 -87
  41. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/urls.py +0 -13
  42. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/wsgi.py +0 -13
  43. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/manage.py +0 -22
  44. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/requirements.txt +0 -1
  45. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/__init__.py +0 -1
  46. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/admin.py +0 -3
  47. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/apps.py +0 -6
  48. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/migrations/__init__.py +0 -1
  49. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/models.py +0 -11
  50. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/tests.py +0 -15
  51. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace/treats/urls.py +0 -9
  52. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode +0 -15
  53. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode.pub +0 -6
  54. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/README.md +0 -38
  55. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/__init__.py +0 -1
  56. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/asgi.py +0 -13
  57. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/settings.py +0 -87
  58. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/urls.py +0 -13
  59. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/wsgi.py +0 -13
  60. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/manage.py +0 -22
  61. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/requirements.txt +0 -1
  62. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/templates/treats/home.html +0 -85
  63. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/__init__.py +0 -1
  64. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/admin.py +0 -3
  65. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/apps.py +0 -6
  66. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/menu.py +0 -43
  67. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/migrations/__init__.py +0 -1
  68. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/models.py +0 -11
  69. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/tests.py +0 -15
  70. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/urls.py +0 -9
  71. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-03/workspace/treats/views.py +0 -22
  72. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode +0 -15
  73. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode.pub +0 -6
  74. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/README.md +0 -38
  75. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/__init__.py +0 -1
  76. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/asgi.py +0 -13
  77. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/settings.py +0 -87
  78. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/urls.py +0 -13
  79. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/wsgi.py +0 -13
  80. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/manage.py +0 -22
  81. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/requirements.txt +0 -1
  82. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/templates/treats/home.html +0 -85
  83. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/__init__.py +0 -1
  84. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/admin.py +0 -3
  85. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/apps.py +0 -6
  86. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/menu.py +0 -43
  87. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/migrations/__init__.py +0 -1
  88. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/models.py +0 -11
  89. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/tests.py +0 -15
  90. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/urls.py +0 -9
  91. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-04/workspace/treats/views.py +0 -22
  92. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode +0 -15
  93. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode.pub +0 -6
  94. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/README.md +0 -38
  95. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/__init__.py +0 -1
  96. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/asgi.py +0 -13
  97. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/settings.py +0 -87
  98. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/urls.py +0 -13
  99. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/wsgi.py +0 -13
  100. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/manage.py +0 -22
  101. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/requirements.txt +0 -1
  102. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/templates/treats/home.html +0 -85
  103. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/__init__.py +0 -1
  104. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/admin.py +0 -3
  105. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/apps.py +0 -6
  106. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/menu.py +0 -43
  107. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/migrations/__init__.py +0 -1
  108. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/models.py +0 -11
  109. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/tests.py +0 -15
  110. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/urls.py +0 -9
  111. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-05/workspace/treats/views.py +0 -22
  112. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode +0 -15
  113. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode.pub +0 -6
  114. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/README.md +0 -38
  115. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/__init__.py +0 -1
  116. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/asgi.py +0 -13
  117. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/settings.py +0 -87
  118. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/urls.py +0 -13
  119. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/wsgi.py +0 -13
  120. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/manage.py +0 -22
  121. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/requirements.txt +0 -1
  122. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/templates/treats/home.html +0 -85
  123. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/__init__.py +0 -1
  124. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/admin.py +0 -3
  125. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/apps.py +0 -6
  126. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/menu.py +0 -43
  127. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/migrations/__init__.py +0 -1
  128. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/models.py +0 -11
  129. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/tests.py +0 -15
  130. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/urls.py +0 -9
  131. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-06/workspace/treats/views.py +0 -22
  132. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode +0 -15
  133. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode.pub +0 -6
  134. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/README.md +0 -38
  135. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/__init__.py +0 -1
  136. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/asgi.py +0 -13
  137. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/settings.py +0 -87
  138. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/urls.py +0 -13
  139. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/wsgi.py +0 -13
  140. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/manage.py +0 -22
  141. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/requirements.txt +0 -1
  142. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/templates/treats/home.html +0 -85
  143. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/__init__.py +0 -1
  144. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/admin.py +0 -3
  145. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/apps.py +0 -6
  146. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/menu.py +0 -43
  147. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/migrations/__init__.py +0 -1
  148. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/models.py +0 -11
  149. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/tests.py +0 -15
  150. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/urls.py +0 -9
  151. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-07/workspace/treats/views.py +0 -22
  152. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode +0 -15
  153. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode.pub +0 -6
  154. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/README.md +0 -38
  155. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/__init__.py +0 -1
  156. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/asgi.py +0 -13
  157. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/settings.py +0 -87
  158. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/urls.py +0 -13
  159. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/wsgi.py +0 -13
  160. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/manage.py +0 -22
  161. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/requirements.txt +0 -1
  162. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/templates/treats/home.html +0 -85
  163. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/__init__.py +0 -1
  164. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/admin.py +0 -3
  165. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/apps.py +0 -6
  166. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/menu.py +0 -43
  167. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/migrations/__init__.py +0 -1
  168. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/models.py +0 -11
  169. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/tests.py +0 -15
  170. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/urls.py +0 -9
  171. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-08/workspace/treats/views.py +0 -22
  172. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode +0 -15
  173. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode.pub +0 -6
  174. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/README.md +0 -38
  175. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/__init__.py +0 -1
  176. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/asgi.py +0 -13
  177. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/settings.py +0 -87
  178. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/urls.py +0 -13
  179. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/wsgi.py +0 -13
  180. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/manage.py +0 -22
  181. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/requirements.txt +0 -1
  182. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/templates/treats/home.html +0 -85
  183. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/__init__.py +0 -1
  184. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/admin.py +0 -3
  185. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/apps.py +0 -6
  186. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/menu.py +0 -43
  187. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/migrations/__init__.py +0 -1
  188. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/models.py +0 -11
  189. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/tests.py +0 -15
  190. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/urls.py +0 -9
  191. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-09/workspace/treats/views.py +0 -22
  192. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode +0 -15
  193. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode.pub +0 -6
  194. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/README.md +0 -38
  195. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/__init__.py +0 -1
  196. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/asgi.py +0 -13
  197. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/settings.py +0 -87
  198. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/urls.py +0 -13
  199. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/wsgi.py +0 -13
  200. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/manage.py +0 -22
  201. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/requirements.txt +0 -1
  202. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/templates/treats/home.html +0 -85
  203. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/__init__.py +0 -1
  204. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/admin.py +0 -3
  205. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/apps.py +0 -6
  206. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/menu.py +0 -43
  207. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/migrations/__init__.py +0 -1
  208. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/models.py +0 -11
  209. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/tests.py +0 -15
  210. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/urls.py +0 -9
  211. portacode-2.2.22.dev0/examples/workshop_fleet/data/student-10/workspace/treats/views.py +0 -22
  212. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/README.md +0 -38
  213. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/galactic_bakeshop/__init__.py +0 -1
  214. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/galactic_bakeshop/asgi.py +0 -13
  215. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/galactic_bakeshop/settings.py +0 -87
  216. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/galactic_bakeshop/urls.py +0 -13
  217. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/galactic_bakeshop/wsgi.py +0 -13
  218. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/manage.py +0 -22
  219. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/requirements.txt +0 -1
  220. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/templates/treats/home.html +0 -85
  221. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/__init__.py +0 -1
  222. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/admin.py +0 -3
  223. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/apps.py +0 -6
  224. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/menu.py +0 -43
  225. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/migrations/__init__.py +0 -1
  226. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/models.py +0 -11
  227. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/tests.py +0 -15
  228. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/urls.py +0 -9
  229. portacode-2.2.22.dev0/examples/workshop_fleet/initial_content/treats/views.py +0 -22
  230. portacode-2.2.22.dev0/portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
  231. portacode-2.2.22.dev0/portacode/link_capture/__pycache__/__init__.cpython-38.pyc +0 -0
  232. portacode-2.2.22.dev0/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
  233. portacode-2.2.22.dev0/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-38.pyc +0 -0
  234. portacode-2.2.22.dev0/portacode.egg-info/SOURCES.txt +0 -450
  235. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/.gitignore +0 -0
  236. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/LICENSE +0 -0
  237. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/MANIFEST.in +0 -0
  238. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/Makefile +0 -0
  239. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/README.md +0 -0
  240. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/build_android.sh +0 -0
  241. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/connect.py +0 -0
  242. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/connect.sh +0 -0
  243. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/cloudflared-domain-connect-containers-audit.md +0 -0
  244. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/creative-team-brief-portacode.md +0 -0
  245. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/device-health-alerting-plan.md +0 -0
  246. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/devops-messaging-ab-tests.md +0 -0
  247. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/guest-host-requests-plan.md +0 -0
  248. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/homepage-dashboard-positioning-fixes.md +0 -0
  249. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/docs/template-guide.html +0 -0
  250. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/README.md +0 -0
  251. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/simple_device/Dockerfile +0 -0
  252. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/simple_device/README.md +0 -0
  253. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/simple_device/docker-compose.yaml +0 -0
  254. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/workshop_fleet/Dockerfile +0 -0
  255. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/workshop_fleet/README.md +0 -0
  256. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/workshop_fleet/docker-compose.yaml +0 -0
  257. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/README.md +0 -0
  258. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/galactic_bakeshop/__init__.py +0 -0
  259. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/galactic_bakeshop/asgi.py +0 -0
  260. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/galactic_bakeshop/settings.py +0 -0
  261. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/galactic_bakeshop/urls.py +0 -0
  262. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/galactic_bakeshop/wsgi.py +0 -0
  263. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/manage.py +0 -0
  264. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/requirements.txt +0 -0
  265. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/templates/treats/home.html +0 -0
  266. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/__init__.py +0 -0
  267. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/admin.py +0 -0
  268. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/apps.py +0 -0
  269. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/menu.py +0 -0
  270. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/migrations/__init__.py +0 -0
  271. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/models.py +0 -0
  272. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/tests.py +0 -0
  273. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-01/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/urls.py +0 -0
  274. {portacode-2.2.22.dev0/examples/workshop_fleet/data/student-02/workspace → portacode-2.2.22.dev1/examples/workshop_fleet/initial_content}/treats/views.py +0 -0
  275. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/examples/workshop_fleet/instructions/WELCOME.md +0 -0
  276. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/README.md +0 -0
  277. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/__init__.py +0 -0
  278. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/__main__.py +0 -0
  279. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/assets/skills/portacode-github/SKILL.md +0 -0
  280. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/assets/skills/portacode-github/agents/openai.yaml +0 -0
  281. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/assets/skills/portacode-github/scripts/create_repository.py +0 -0
  282. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/assets/skills/portacode-image/SKILL.md +0 -0
  283. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/assets/skills/portacode-image/agents/openai.yaml +0 -0
  284. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/browser_cli.py +0 -0
  285. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/browser_runtime.py +0 -0
  286. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/cli.py +0 -0
  287. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/codex_loopback_proxy.py +0 -0
  288. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/codex_usage_limit.py +0 -0
  289. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/README.md +0 -0
  290. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/__init__.py +0 -0
  291. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/client.py +0 -0
  292. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/codex_app_server.py +0 -0
  293. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/guest_host_protocol.py +0 -0
  294. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/README.md +0 -0
  295. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
  296. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/__init__.py +0 -0
  297. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/automation_v2_handlers.py +0 -0
  298. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/base.py +0 -0
  299. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/browser_handlers.py +3 -3
  300. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/chunked_content.py +0 -0
  301. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/cloudflare_forwarding.py +0 -0
  302. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/cloudflare_tunnel.py +0 -0
  303. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/codex_handlers.py +0 -0
  304. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/diff_handlers.py +0 -0
  305. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/file_handlers.py +0 -0
  306. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/file_transfer_handlers.py +0 -0
  307. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/git_handlers.py +0 -0
  308. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
  309. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/README.md +0 -0
  310. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/__init__.py +0 -0
  311. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
  312. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/git_manager.py +0 -0
  313. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/handlers.py +0 -0
  314. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/manager.py +0 -0
  315. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/models.py +0 -0
  316. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/test_handlers.py +0 -0
  317. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state/utils.py +0 -0
  318. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/project_state_handlers.py +0 -0
  319. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/registry.py +0 -0
  320. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/resumable_transfer_handlers.py +0 -0
  321. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/runtime_user.py +0 -0
  322. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/session.py +0 -0
  323. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/system_handlers.py +0 -0
  324. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/tab_factory.py +0 -0
  325. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/terminal_handlers.py +0 -0
  326. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/test_cloudflare_forwarding.py +0 -0
  327. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/test_file_move_copy.py +0 -0
  328. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/test_git_handlers.py +0 -0
  329. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/test_runtime_user.py +0 -0
  330. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/handlers/update_handler.py +0 -0
  331. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/multiplex.py +0 -0
  332. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/terminal.py +0 -0
  333. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/test_guest_host_protocol.py +0 -0
  334. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/test_guest_host_terminal.py +0 -0
  335. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/test_webmin_proxy_config.py +0 -0
  336. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/connection/webmin_proxy_config.py +0 -0
  337. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/data.py +0 -0
  338. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/exit_codes.py +0 -0
  339. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/github_credential.py +0 -0
  340. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/image_cli.py +0 -0
  341. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/keypair.py +0 -0
  342. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/__init__.py +0 -0
  343. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/elinks +0 -0
  344. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/gio-open +0 -0
  345. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/gnome-open +0 -0
  346. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/gvfs-open +0 -0
  347. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/kde-open +0 -0
  348. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/kfmclient +0 -0
  349. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/link_capture_exec.sh +0 -0
  350. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/link_capture_wrapper.py +0 -0
  351. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/links +0 -0
  352. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/links2 +0 -0
  353. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/lynx +0 -0
  354. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/mate-open +0 -0
  355. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/netsurf +0 -0
  356. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/sensible-browser +0 -0
  357. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/w3m +0 -0
  358. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/x-www-browser +0 -0
  359. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/link_capture/bin/xdg-open +0 -0
  360. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/logging_categories.py +0 -0
  361. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/pairing.py +0 -0
  362. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/provisioning_cache.py +0 -0
  363. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/restart.py +0 -0
  364. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/service.py +0 -0
  365. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/singleton.py +0 -0
  366. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/static/js/test-ntp-clock.html +0 -0
  367. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/static/js/utils/ntp-clock.js +0 -0
  368. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/test_runtime_paths.py +0 -0
  369. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/test_service.py +0 -0
  370. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/test_singleton.py +0 -0
  371. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/test_terminal_exposed_services.py +0 -0
  372. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_automation_v2_inputs.py +0 -0
  373. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_browser_cli.py +0 -0
  374. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_cli_service_logs.py +0 -0
  375. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_codex_app_server.py +0 -0
  376. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_codex_handlers.py +0 -0
  377. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_codex_loopback_proxy.py +0 -0
  378. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_github_credential.py +0 -0
  379. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_image_cli.py +0 -0
  380. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_image_read_handler.py +0 -0
  381. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_resumable_transfer_handlers.py +0 -0
  382. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_system_handlers.py +0 -0
  383. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_terminal_periodic_system_info.py +0 -0
  384. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tests/test_terminal_session_shell.py +0 -0
  385. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/__init__.py +0 -0
  386. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/cloudflared_login.py +0 -0
  387. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/ensure_cloudflared.py +0 -0
  388. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/ensure_pyyaml.py +0 -0
  389. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/forwarding_state.py +0 -0
  390. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/get_domain.py +0 -0
  391. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/privileged.py +0 -0
  392. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/service_install.py +0 -0
  393. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/tunneling/state.py +0 -0
  394. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/updater.py +0 -0
  395. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
  396. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/utils/__init__.py +0 -0
  397. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/utils/diff_apply.py +0 -0
  398. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/utils/diff_renderer.py +0 -0
  399. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/utils/ntp_clock.py +0 -0
  400. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode/utils/runtime_paths.py +0 -0
  401. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode.egg-info/dependency_links.txt +0 -0
  402. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode.egg-info/entry_points.txt +0 -0
  403. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode.egg-info/requires.txt +0 -0
  404. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/portacode.egg-info/top_level.txt +0 -0
  405. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/pyproject.toml +0 -0
  406. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/run_tests.py +0 -0
  407. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/scripts/diagnose_codex_gateway.py +0 -0
  408. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/setup.cfg +0 -0
  409. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/setup.py +0 -0
  410. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test.sh +0 -0
  411. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/README.md +0 -0
  412. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/__init__.py +0 -0
  413. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_device_online.py +0 -0
  414. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_file_operations.py +0 -0
  415. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_git_status_ui.py +0 -0
  416. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_login_flow.py +0 -0
  417. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_navigate_testing_folder.py +0 -0
  418. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_play_store_screenshots.py +0 -0
  419. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_terminal_buffer_performance.py +0 -0
  420. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_terminal_interaction.py +0 -0
  421. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_terminal_loading_race_condition.py +0 -0
  422. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_modules/test_terminal_start.py +0 -0
  423. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_request_id.py +0 -0
  424. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/test_session_terminal_shutdown.py +0 -0
  425. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/.env.example +0 -0
  426. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/README.md +0 -0
  427. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/__init__.py +0 -0
  428. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/cli.py +0 -0
  429. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/__init__.py +0 -0
  430. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/base_test.py +0 -0
  431. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/cli_manager.py +0 -0
  432. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/hierarchical_runner.py +0 -0
  433. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/playwright_manager.py +0 -0
  434. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/runner.py +0 -0
  435. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/shared_cli_manager.py +0 -0
  436. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/core/test_discovery.py +0 -0
  437. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/testing_framework/requirements.txt +0 -0
  438. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md +0 -0
  439. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/UI_UX/server_occasionally_stops_communicating_with_all_devices.md +0 -0
  440. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/agent_context_management.md +0 -0
  441. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/django_server_time_sync.md +0 -0
  442. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/device_performance_degradation.md +0 -0
  443. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
  444. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/indefinite_resource_loading.md +0 -0
  445. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/portacode_service_silently_down.md +0 -0
  446. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/premature_terminal_exit.md +0 -0
  447. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/project_cpu_hotspots.md +0 -0
  448. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/terminals_exit_upon_starting.md +0 -0
  449. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/websocket_client_silently_dead.md +0 -0
  450. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/issues/wrong_item_classification_on_client_side.md +0 -0
  451. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/todo/smartphone_terminal_input_frustrations.md +0 -0
  452. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/tools/generate_play_store_assets.py +0 -0
  453. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/tools/pairing_tester.py +0 -0
  454. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/tools/run_screenshot_suite.sh +0 -0
  455. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/tools/test_python_ntp_clock.py +0 -0
  456. {portacode-2.2.22.dev0 → portacode-2.2.22.dev1}/validate.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 2.2.22.dev0
3
+ Version: 2.2.22.dev1
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
@@ -0,0 +1,414 @@
1
+ # Template engineering architecture roadmap
2
+
3
+ ## Goal
4
+
5
+ A user should be able to tell Dashboard AI, “create a reusable template for this
6
+ project.” Portacode should then derive a Portafile, provision clean containers,
7
+ execute and observe it, repair failures, repeat trials from controlled snapshots,
8
+ verify the real user journey, and save a versioned template with evidence of how
9
+ reliable it is. The same object should support private reuse, controlled sharing,
10
+ catalog publication, and optional screenshot/video capture for marketing.
11
+
12
+ This roadmap is ordered by the best ratio of user-visible progress to implementation
13
+ risk. Each step is independently useful and leaves a foundation for the next one.
14
+
15
+ ## What exists today
16
+
17
+ The product already has most of the execution primitives, but they are not assembled
18
+ into a template-engineering system:
19
+
20
+ - Published templates are Django CMS pages. `OneClickTemplateExtension` stores an
21
+ opaque `yaml_config` text field plus a description. Model validation proves only
22
+ that the value is non-empty, parseable YAML.
23
+ - Source-controlled catalog files under `content/one-click/` can be synchronized with
24
+ CMS and exported back to Markdown. This is a staff content workflow, not a user
25
+ template repository.
26
+ - Dashboard AI can search the published catalog and read a template's YAML, but it
27
+ has no create, update, clone, validate, test, or publish template operation.
28
+ - Dashboard AI can provision a container from a published template or arbitrary
29
+ customized YAML, start an automation on an existing device, inspect its state,
30
+ execute bounded terminal commands, delegate constrained Codex work, and operate a
31
+ browser.
32
+ - Managed Proxmox containers expose list/create/delete/rollback snapshot operations
33
+ to Dashboard AI. These operations are isolated host requests; there is no durable
34
+ experiment controller tying snapshots to a candidate template or trial.
35
+ - `AutomationTask` durably records instructions, metadata, the original YAML, current
36
+ step, status, and a bounded failure. It represents one execution, not a trial in a
37
+ template version's validation campaign.
38
+ - Portafile parsing accepts aliases and silently drops unrecognized/malformed steps
39
+ in places. Inputs receive stronger validation, but there is no single strict,
40
+ versioned Portafile schema or normalized intermediate representation shared by
41
+ CMS, provisioning, automation, and AI tools.
42
+ - Automation defaults to AI-assisted recovery for Dashboard AI runs, which is useful
43
+ operationally but can hide whether the submitted template itself is reproducible.
44
+ - `dashboard_browser_run` can assert a real browser journey and capture screenshots
45
+ or a low-resolution video. Media is returned for the current tool interaction or
46
+ offered as a device download; it is not attached to a template version with
47
+ provenance, consent, retention, or publication state.
48
+
49
+ In short, Portacode has an executor and a capable AI operator. It is missing the
50
+ domain model and scientific harness that turn trial-and-error into a trustworthy,
51
+ reusable artifact.
52
+
53
+ ## Architectural direction: a moderated template-baking session
54
+
55
+ The primary abstraction should optimize for the Dashboard AI, not for YAML authors.
56
+ From the AI's perspective, baking a template should feel like incrementally building
57
+ a project:
58
+
59
+ 1. start a baking session;
60
+ 2. propose the next logical step and its success checks;
61
+ 3. receive either actionable admission feedback or the executed result;
62
+ 4. on success, continue from the new checkpoint;
63
+ 5. on failure, receive detailed evidence with an explicit guarantee that the device
64
+ has already been rolled back and restarted at the previous successful checkpoint;
65
+ 6. finish the session and let Portacode compile the archived steps into a Portafile.
66
+
67
+ Snapshots, process state, retries, rollback, restart, logs, and archival should be
68
+ backend invariants. The AI must not have to call those tools in the right order or
69
+ retain that state in its context.
70
+
71
+ Here, deterministic means **contract-reliable, not output-identical**. A useful
72
+ template is a parameterized project generator. Different valid input sets may produce
73
+ different logos, copy, features, integrations, layouts, records, and AI-generated
74
+ customizations. Reliability means that each result honors its inputs, satisfies the
75
+ same declared structural and behavioral invariants, and remains operable. Tests should
76
+ therefore compare observable contracts and input-specific expectations, not complete
77
+ filesystem hashes or pixel-identical pages.
78
+
79
+ Keep Portafile as the portable output, but introduce a durable baking domain around
80
+ it:
81
+
82
+ ```text
83
+ TemplateBake
84
+ -> BakeRevision
85
+ -> BakeStep (proposed operation + semantic verdict + archived definition)
86
+ -> StepAttempt (snapshot, execution, observations, outcome)
87
+ -> AssertionResult / Artifact
88
+ -> Compiled TemplateVersion
89
+ ```
90
+
91
+ Use a deterministic state machine as the moderator. Dashboard AI decides what useful
92
+ project change to try next; the moderator owns admission, tool policy, snapshot
93
+ discipline, execution, rollback/start, evidence collection, retry count, and final
94
+ compilation. This is substantially safer and easier than exposing all primitives and
95
+ prompting the AI to orchestrate them correctly.
96
+
97
+ ## Prioritized implementation steps
98
+
99
+ ### 1. Add durable baking models and one composite `dashboard_bake_template_step` tool
100
+
101
+ This is the new smallest high-leverage vertical slice. Add `TemplateBake`,
102
+ `BakeRevision`, `BakeStep`, and `StepAttempt`. A bake is bound to one user, Dashboard
103
+ chat, managed disposable device, clean baseline snapshot, and a versioned input
104
+ contract. That contract supports typed free text, long text, number, boolean, select,
105
+ multiselect, secret, file/image, color, URL, and integration-reference inputs, with
106
+ labels, help text, constraints, defaults, and safe persistence policy. A step contains:
107
+
108
+ - a stable ID and human goal;
109
+ - a typed operation (`command`, `wait_for`, constrained `codex`, browser check, file
110
+ operation, or supported infrastructure declaration);
111
+ - deterministic success assertions;
112
+ - its semantic admission verdict and risk scores;
113
+ - the pre-step snapshot name;
114
+ - every attempt and bounded stdout/stderr/automation/browser evidence;
115
+ - final state (`proposed`, `rejected`, `running`, `archived`, `failed_rolled_back`).
116
+
117
+ Every value used by a step must be classified as a constant, declared template input,
118
+ Portacode runtime value, prior-step output, or secret reference. Derived values should
119
+ be recorded through typed output bindings rather than scraped informally from logs.
120
+ For example, a CRM bake can bind `brand_logo`, `industry`, `sales_pipeline`, and
121
+ `company_description`, while Portacode supplies the exposed URL and generated service
122
+ credentials at runtime.
123
+
124
+ Expose one composite tool. Internally it must:
125
+
126
+ 1. validate structure and permissions;
127
+ 2. run semantic admission;
128
+ 3. create a snapshot of the last successful state;
129
+ 4. execute through existing device/automation/browser services;
130
+ 5. evaluate assertions independently;
131
+ 6. archive the successful normalized step; or
132
+ 7. on failure, roll back, explicitly start the stopped container, wait for the device
133
+ to reconnect, verify the previous checkpoint, and only then return to the AI.
134
+
135
+ The failure result should lead with `ROLLED_BACK_AND_READY`, identify the last
136
+ successful step, and include command, exit code, timeout state, bounded stdout/stderr,
137
+ failed assertions, semantic warnings, and artifact references. If rollback/start or
138
+ reconnection fails, return `RECOVERY_INCOMPLETE` and block further steps; never tell
139
+ the AI it is safe to continue.
140
+
141
+ **Why first:** it immediately removes orchestration burden from the LLM and proves the
142
+ moderated workflow while reusing current provisioning, automation, snapshot, terminal,
143
+ Codex, and browser implementations.
144
+
145
+ **Exit criteria:** the AI can build a two-step project using only the baking tool; a
146
+ forced failure returns detailed evidence after verified rollback and restart, and a
147
+ subsequent corrected step proceeds from the last archived checkpoint.
148
+
149
+ ### 2. Add a dedicated semantic template-step admission engine
150
+
151
+ Factor the metered Responses API pattern used by `_semantic_validate_work_order` into
152
+ a reusable admission client, but give template steps a separate prompt, response
153
+ schema, usage nonce, audit record, and policy. Run deterministic checks first, then
154
+ send the normalized proposed step plus relevant bake context—not secrets or unbounded
155
+ logs—to `gpt-5.6-terra` in the same Dashboard thread budget.
156
+
157
+ The response must be strict JSON with:
158
+
159
+ - `decision`: `accept`, `accept_with_risk`, or `reject`;
160
+ - `template_suitability`: 0–100;
161
+ - `nondeterminism`: 0–100;
162
+ - `portability_risk`, `secret_risk`, and `destructive_risk`: 0–100;
163
+ - typed findings with exact field, evidence, explanation, and repair guidance;
164
+ - detected runtime-derived values that must become placeholders/inputs;
165
+ - input-usage findings, including undeclared values, ignored declared inputs, unsafe
166
+ interpolation, missing validation, and behavior that contradicts an input choice;
167
+ - required assertions and a recommended clean-success trial count from 1–5.
168
+
169
+ The prompt should detect at least hard-coded hostnames such as
170
+ `*.host.exposify.net`, device IDs, IPs, usernames/home paths, ports that should use
171
+ `[exposed:PORT]`, credentials/tokens, local absolute paths, ephemeral URLs, generated
172
+ resource names, interactive commands, unpinned moving dependencies, time/randomness,
173
+ external mutable services, and Codex/LLM execution. Hard-coding is not uniformly
174
+ wrong: `localhost`, conventional service paths, and an application's intentional
175
+ fixed port may be valid. The engine must explain contextual findings rather than
176
+ reject every literal.
177
+
178
+ Reject security violations, operations outside bake policy, steps that cannot be
179
+ represented portably, and steps without independently observable completion. Accept
180
+ nondeterministic steps when bounded and verifiable, then use their score to raise the
181
+ trial count. Semantic admission is defense in depth, not the sole security boundary;
182
+ allowlists, argument validation, and authorization remain deterministic.
183
+
184
+ Do not penalize legitimate parameterization or bounded generation merely because
185
+ outputs differ. Penalize unexplained variability, undeclared environmental dependence,
186
+ and lack of assertions. Semantic review should ask “does this operation reliably
187
+ transform every allowed input into an output satisfying the contract?” rather than
188
+ “will this operation produce identical bytes?”
189
+
190
+ **Exit criteria:** equivalent steps receive a typed, stored verdict; rejected steps
191
+ never execute or create a success archive; usage is charged and auditable in the same
192
+ thread; malformed model output fails closed.
193
+
194
+ ### 3. Enforce a baking-specific capability profile instead of rebuilding device tools
195
+
196
+ Add a bake-session capability filter at the Dashboard tool-selection and gateway
197
+ authorization layers. While a bake is active, hide/block direct mutation tools that
198
+ could bypass admission or checkpointing. The AI should normally retain only:
199
+
200
+ - the composite step tool;
201
+ - bake state/history and finish/abort tools;
202
+ - read-only device/file/image/automation inspection;
203
+ - template/docs search;
204
+ - user input and permission requests.
205
+
206
+ Direct terminal execution, file writes/deletes, Codex tasks, power control, resize,
207
+ snapshot mutation, automation start/retry, ingress/domain changes, transfers, and
208
+ repository publication should be denied during baking unless invoked internally by
209
+ the moderator under a capability scoped to the current step. Browser reads/assertions
210
+ are safe through the moderator; browser actions that mutate application state should
211
+ be declared in the step so reset behavior is known.
212
+
213
+ Use two layers because hiding tools is UX, not security. The service layer must reject
214
+ a direct call carrying a bake-bound device/session even if a stale model or client
215
+ still knows the tool name. Do not globally cripple the Dashboard AI: these restrictions
216
+ apply only to the disposable bake target while the bake is active.
217
+
218
+ **Exit criteria:** attempts to bypass moderation through every mutating device tool
219
+ fail server-side, while ordinary non-baking device work is unchanged.
220
+
221
+ ### 4. Make the checkpoint state machine crash-safe and snapshot-aware
222
+
223
+ Implement step execution as a durable worker/state machine with idempotency keys and
224
+ explicit phases: `admitting`, `snapshotting`, `executing`, `asserting`, `archiving`,
225
+ `rolling_back`, `starting`, `reconnecting`, and terminal states. Snapshot names should
226
+ derive from bake/step IDs, not model-generated strings.
227
+
228
+ Account explicitly for Proxmox rollback stopping the container. Recovery is complete
229
+ only after rollback succeeds, start succeeds, the device reconnects, and a checkpoint
230
+ probe passes. Resume correctly after worker, web, host, or device reconnects without
231
+ duplicating execution. Route snapshot/power requests through the existing
232
+ WebSocket-owning process/durable guest-host boundary; background workers must not call
233
+ process-local singleton waiters directly.
234
+
235
+ Successful steps become immutable archived definitions. Keep the current success
236
+ snapshot as the next baseline and garbage-collect superseded snapshots only after the
237
+ new checkpoint is proven. Failed attempt evidence remains linked even after rollback.
238
+
239
+ **Exit criteria:** faults injected at every phase converge to one correct state,
240
+ successful commands are not accidentally rerun, and no failure destroys its evidence
241
+ or strands a stopped container unnoticed.
242
+
243
+ ### 5. Turn input contracts and nondeterminism scores into automatic isolated trials
244
+
245
+ Separate exploratory baking from proof. Generate a compact validation matrix from the
246
+ declared input contract. It should include a representative/default persona, meaningful
247
+ select/boolean branches, boundary-valid text and numbers, alternate logos/files, empty
248
+ optional values, and safe Unicode/spacing cases. Authors may add named personas such
249
+ as `small_retail_crm` and `consulting_team_crm` with input-specific expectations.
250
+ Avoid the full Cartesian product; use pairwise/branch coverage plus explicitly critical
251
+ combinations.
252
+
253
+ After a step first succeeds, low-risk steps can be archived immediately but still
254
+ participate in final clean-room replay. Risky steps trigger automatic independent
255
+ attempts from their pre-step snapshot. Roll back before every attempt, start/reconnect,
256
+ apply a selected input fixture and fresh secrets, execute, assert, and reset again.
257
+
258
+ Cap required successful attempts at five. A sensible initial mapping is 1 success for
259
+ scores 0–19, 2 for 20–39, 3 for 40–59, 4 for 60–79, and 5 for 80–100. Also cap total
260
+ attempts (for example seven) so failures cannot loop indefinitely. Mark results as
261
+ `5/5 clean attempts`, not “almost always reliable”; five samples do not justify a
262
+ production reliability percentage. Any unexplained failure prevents a strong
263
+ validated status and is returned to the AI for repair.
264
+
265
+ Codex steps must be constrained work orders and must have deterministic external
266
+ postconditions. Their generated copy, layout, or implementation may differ across
267
+ attempts, but assertions must prove the selected logo/copy/options were honored and
268
+ the resulting application has the required flows, persistence, security, and health.
269
+ Use semantic or visual quality review only for criteria that genuinely cannot be
270
+ encoded deterministically, and store its rubric and verdict as evidence. Never count
271
+ the same post-success filesystem state multiple times, and never let AI auto-repair
272
+ inside an attempt count as a pass.
273
+
274
+ **Exit criteria:** the campaign covers declared input branches and representative
275
+ personas; nondeterministic success produces multiple isolated attempt records without
276
+ the Dashboard AI orchestrating retries; and the stored status reports both trial count
277
+ and input/branch coverage rather than implying that one fixture proves the template.
278
+
279
+ ### 6. Compile archived steps and run a final clean-room replay
280
+
281
+ When the AI finishes, compile only admitted, archived steps into a normalized,
282
+ versioned Portafile. Convert discovered runtime values into declared inputs or
283
+ Portacode placeholders. Compile the typed input contract, conditional behavior,
284
+ bindings, validation rules, and input-specific acceptance checks alongside stable step
285
+ IDs. Preserve the distinction between user-provided files, secrets, runtime-generated
286
+ values, and reusable non-secret defaults.
287
+
288
+ Provision a fresh container—do not use the incrementally baked one—and execute the
289
+ whole compiled template from zero with interactive repair disabled. Apply the
290
+ nondeterminism policy to the complete template as well as individual risky steps.
291
+ Only this clean-room replay can mark a version validated.
292
+
293
+ **Exit criteria:** the emitted Portafile reproduces the project on a new container and
294
+ has a digest linked to all admission decisions, step attempts, and final trials.
295
+
296
+ ### 7. Persist private user templates and immutable versions
297
+
298
+ Add `UserTemplate` and immutable `TemplateVersion` ownership, revision, visibility,
299
+ fork lineage, normalized manifest, digest, lifecycle, and reliability summary. The
300
+ bake compiles into a private draft by default. Secrets remain references to declared
301
+ inputs and are never copied from attempts into YAML, logs, or artifacts.
302
+
303
+ **Exit criteria:** Dashboard AI can finish a bake, save the resulting private version,
304
+ and deploy that exact digest again; cross-user access fails closed.
305
+
306
+ ### 8. Make reuse and controlled sharing a product workflow
307
+
308
+ Add clone/fork, export/import, archive, and visibility (`private`, `unlisted`,
309
+ `public`) operations. Deployments should always reference a version digest so later
310
+ author edits cannot change an old deployment. Sharing should exclude saved input
311
+ values, credentials, trial secrets, private logs, private URLs, and unpublished
312
+ artifacts.
313
+
314
+ Introduce explicit license/attribution metadata and moderation/security scanning for
315
+ public versions. A shared version is immutable; recipients fork to edit it. Add
316
+ revocation/deprecation without breaking the audit history of prior deployments.
317
+
318
+ **Exit criteria:** two users can safely reuse the same public/unlisted version, one
319
+ cannot modify the other's artifact, and export then import preserves its digest and
320
+ schema version.
321
+
322
+ ### 9. Promote validated versions into the public catalog
323
+
324
+ Replace the split authority gradually: render public one-click pages from approved
325
+ template versions or create a publication record that projects a version into CMS.
326
+ Keep editorial copy/localization in CMS, while deployment YAML, evidence, versioning,
327
+ and trust state come from the template domain.
328
+
329
+ Require publication gates: schema pass, campaign policy pass, security/license scan,
330
+ resource bounds, human approval where policy requires it, and a rollback/deprecation
331
+ plan. Show users version, last validated date, tested environments, pass/attempt
332
+ counts, required privileges, inputs, and known limitations.
333
+
334
+ **Exit criteria:** no public page can serve YAML different from its approved version
335
+ digest, and catalog updates do not require copying opaque YAML between CMS and source
336
+ files by hand.
337
+
338
+ ### 10. Add declarative Playwright journeys and durable marketing assets
339
+
340
+ Build on the existing bounded browser-operation vocabulary rather than embedding
341
+ arbitrary Playwright programs in YAML. Add authoring-only `journeys` composed of
342
+ semantic operations and assertions, plus named capture points and optional bounded
343
+ video recording. Separate `acceptance` journeys from `marketing` capture requests;
344
+ marketing capture must never determine deployment success.
345
+
346
+ Persist artifacts in managed object storage with template version, trial, step,
347
+ viewport, locale, timestamp, checksum, MIME type, provenance, consent/publication
348
+ state, and retention policy. Sanitize sessions and scan screenshots/video for secrets,
349
+ personal data, private hostnames, tokens, and debug overlays before publication.
350
+ Generate marketing assets only from a clean successful trial using deterministic seed
351
+ data and an explicitly publishable input profile.
352
+
353
+ **Exit criteria:** a version can reproducibly generate approved screenshots/video
354
+ from its declared journey, while failed/redacted/private captures remain inaccessible
355
+ to public catalog pages.
356
+
357
+ ### 11. Operate the system as a reliability service
358
+
359
+ Add campaign queues, per-user/node concurrency and cost limits, disposable-container
360
+ leases, orphan reconciliation, artifact retention jobs, dependency caching policy,
361
+ and dashboards for pass rate, flakiness, duration, AI spend, infra spend, and cleanup
362
+ failures. Periodically revalidate public templates against newer source images and
363
+ dependency versions without silently promoting results to a different template
364
+ version.
365
+
366
+ Use failure clustering to find common platform/template issues, but keep automated
367
+ recovery inside the owning service and preserve root-cause evidence. Publish status
368
+ only from durable records.
369
+
370
+ **Exit criteria:** interrupted campaigns converge to a correct terminal state,
371
+ resources are reclaimed, costs are bounded, and maintainers can distinguish platform
372
+ regressions from template regressions.
373
+
374
+ ## Recommended first delivery slice
375
+
376
+ Implement the narrow vertical path through steps 1–4:
377
+
378
+ 1. create a bake against an already provisioned managed disposable device;
379
+ 2. support only `command` and `wait_for` step types initially;
380
+ 3. run deterministic validation plus the dedicated semantic admission call;
381
+ 4. snapshot, execute, assert, archive on success;
382
+ 5. rollback, start, reconnect, and return structured evidence on failure;
383
+ 6. expose only create-bake, bake-step, bake-state, and abort/finish tools;
384
+ 7. compile the archived steps to YAML without publishing or sharing it.
385
+
386
+ This slice deliberately postpones automatic provisioning, Codex steps, browser media,
387
+ sharing, and CMS publication. It proves the most valuable user experience first: the
388
+ AI writes ordinary logical steps while Portacode invisibly supplies the safety rails.
389
+
390
+ ## Non-negotiable design rules
391
+
392
+ - Reliability is derived from independent observations, not an AI's confidence or
393
+ summary.
394
+ - Determinism means repeatable satisfaction of declared invariants for varied valid
395
+ inputs; it never means forcing every deployment to contain identical content.
396
+ - Inputs are typed, validated, redacted where necessary, and traced to the steps and
397
+ assertions they affect. A template is not validated if only one convenient input
398
+ fixture was tested.
399
+ - Every trial executes an immutable version from a known clean baseline.
400
+ - A retry after rollback is a new trial; a repair is a new template version.
401
+ - AI-assisted recovery during ordinary deployment must not count as template proof.
402
+ - Nondeterminism is declared, bounded, measured, and followed by deterministic
403
+ postconditions.
404
+ - YAML, logs, media, exports, and shared versions never contain saved secrets.
405
+ - Public/catalog state is an explicit promotion, never a side effect of a successful
406
+ private run.
407
+ - Long-running orchestration is durable and idempotent and respects the existing
408
+ WebSocket process-ownership boundary.
409
+ - Dashboard AI never has to manually pair snapshot, rollback, power, and reconnect
410
+ operations; those are atomic moderator responsibilities from its perspective.
411
+ - Semantic moderation informs risk and suitability, but deterministic capability and
412
+ authorization checks are always the enforcement boundary.
413
+ - Browser marketing directives are authoring metadata, not commands executed on every
414
+ end-user deployment.
@@ -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.22.dev0'
22
- __version_tuple__ = version_tuple = (2, 2, 22, 'dev0')
21
+ __version__ = version = '2.2.22.dev1'
22
+ __version_tuple__ = version_tuple = (2, 2, 22, 'dev1')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -0,0 +1,117 @@
1
+ """Idempotent browser preparation for managed provisioning guests."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import os
7
+ import shutil
8
+ import subprocess
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ from .browser_runtime import MANAGED_BROWSER_CACHE, find_system_browser
13
+
14
+
15
+ PACKAGE_MANAGERS = ("apt", "apk", "dnf", "yum", "zypper", "pacman")
16
+ _SMOKE_SCRIPT = """
17
+ from pathlib import Path
18
+ from tempfile import TemporaryDirectory
19
+ from portacode.browser_runtime import open_browser_page
20
+
21
+ with TemporaryDirectory(prefix='portacode-browser-check-') as directory:
22
+ options = {'viewport': {'width': 320, 'height': 240},
23
+ 'record_video_dir': directory,
24
+ 'record_video_size': {'width': 320, 'height': 240}}
25
+ with open_browser_page(options) as (browser, context, page):
26
+ page.set_content('<button onclick="this.textContent=\\'Ready\\'">Test</button>')
27
+ page.get_by_role('button').click()
28
+ assert page.get_by_role('button').inner_text() == 'Ready'
29
+ page.wait_for_timeout(300)
30
+ image = Path(directory) / 'screenshot.png'
31
+ page.screenshot(path=str(image))
32
+ video = page.video
33
+ context.close()
34
+ if not image.stat().st_size or video is None or not Path(video.path()).stat().st_size:
35
+ raise RuntimeError('Browser screenshot/video verification failed')
36
+ """
37
+
38
+
39
+ def _probe_browser(environment: dict[str, str]) -> subprocess.CompletedProcess:
40
+ return subprocess.run(
41
+ [sys.executable, "-c", _SMOKE_SCRIPT], env=environment,
42
+ text=True, capture_output=True, timeout=120,
43
+ )
44
+
45
+
46
+ def _require_browser(environment: dict[str, str]) -> None:
47
+ result = _probe_browser(environment)
48
+ if result.returncode:
49
+ detail = (result.stderr or result.stdout or "No diagnostic output")[-4000:]
50
+ raise RuntimeError(f"Browser screenshot/video verification failed:\n{detail}")
51
+
52
+
53
+ def _install_alpine_ffmpeg(cache: Path) -> None:
54
+ import playwright
55
+
56
+ package = Path(playwright.__file__).resolve().parent / "driver" / "package"
57
+ browsers = json.loads((package / "browsers.json").read_text())["browsers"]
58
+ ffmpeg = next(browser for browser in browsers if browser["name"] == "ffmpeg")
59
+ executable = shutil.which("ffmpeg")
60
+ if not executable:
61
+ raise RuntimeError("Alpine's ffmpeg package did not provide an executable")
62
+ target = cache / f"ffmpeg-{ffmpeg['revision']}" / "ffmpeg-linux"
63
+ target.parent.mkdir(parents=True, exist_ok=True)
64
+ if target.is_symlink() or target.exists():
65
+ target.unlink()
66
+ target.symlink_to(executable)
67
+
68
+
69
+ def prepare_browser(package_manager: str, *, check_only: bool = False) -> None:
70
+ """Install only missing guest assets, using this interpreter's Playwright."""
71
+ if package_manager not in PACKAGE_MANAGERS:
72
+ raise ValueError(f"Unsupported package manager: {package_manager}")
73
+ environment = {**os.environ, "PLAYWRIGHT_BROWSERS_PATH": str(MANAGED_BROWSER_CACHE)}
74
+ if check_only:
75
+ _require_browser(environment)
76
+ return
77
+ MANAGED_BROWSER_CACHE.mkdir(parents=True, exist_ok=True)
78
+
79
+ def run(*command: str) -> None:
80
+ subprocess.run(command, env=environment, check=True)
81
+
82
+ run("chmod", "-R", "a+rX", str(MANAGED_BROWSER_CACHE))
83
+ if _probe_browser(environment).returncode == 0:
84
+ return
85
+
86
+ if package_manager == "apt":
87
+ run(sys.executable, "-m", "playwright", "install", "--with-deps", "chromium", "ffmpeg")
88
+ elif package_manager == "apk":
89
+ run("apk", "add", "--no-cache", "chromium", "nss", "freetype", "harfbuzz",
90
+ "ca-certificates", "font-freefont", "ffmpeg")
91
+ _install_alpine_ffmpeg(MANAGED_BROWSER_CACHE)
92
+ else:
93
+ if not find_system_browser():
94
+ if package_manager in {"dnf", "yum"}:
95
+ release = Path("/etc/os-release").read_text().lower()
96
+ if "centos" in release:
97
+ run(package_manager, "install", "-y", "epel-release")
98
+ run(package_manager, "install", "-y", "chromium")
99
+ elif package_manager == "zypper":
100
+ run("zypper", "--non-interactive", "install", "-y", "chromium")
101
+ elif package_manager == "pacman":
102
+ run("pacman", "-S", "--noconfirm", "--needed", "chromium")
103
+ run(sys.executable, "-m", "playwright", "install", "ffmpeg")
104
+ run("chmod", "-R", "a+rX", str(MANAGED_BROWSER_CACHE))
105
+ _require_browser(environment)
106
+
107
+
108
+ def main() -> None:
109
+ parser = argparse.ArgumentParser(description=__doc__)
110
+ parser.add_argument("--package-manager", required=True, choices=PACKAGE_MANAGERS)
111
+ parser.add_argument("--check", action="store_true")
112
+ arguments = parser.parse_args()
113
+ prepare_browser(arguments.package_manager, check_only=arguments.check)
114
+
115
+
116
+ if __name__ == "__main__":
117
+ main()
@@ -179,12 +179,7 @@ def _install_node_if_needed() -> None:
179
179
  packages = ["npm"] if node_ready else ["nodejs", "npm"]
180
180
  _run([*_sudo_prefix(), "apk", "add", "--no-cache", *packages])
181
181
  else:
182
- if not shutil.which("curl") and any(name in release for name in ("debian", "ubuntu")):
183
- # Exit 100 is common on Proxmox when an optional enterprise
184
- # repository is unavailable; the required Ubuntu/Debian
185
- # packages can still be installed from the remaining mirrors.
186
- _run([*_sudo_prefix(), "apt-get", "update"], ok_returncodes=(0, 100))
187
- _run([*_sudo_prefix(), "apt-get", "install", "-y", "ca-certificates", "curl"])
182
+ _install_linux_node_prerequisites()
188
183
  _install_node_with_nvm()
189
184
  elif system == "darwin":
190
185
  _install_node_with_nvm()
@@ -210,6 +205,26 @@ def _install_node_if_needed() -> None:
210
205
  raise CodexPreparationError("Node.js installation completed but npm is not available in this session.")
211
206
 
212
207
 
208
+ def _install_linux_node_prerequisites() -> None:
209
+ if shutil.which("bash") and shutil.which("curl"):
210
+ return
211
+ packages = ["ca-certificates", "bash", "curl"]
212
+ commands = {
213
+ "apt-get": ["apt-get", "install", "-y", *packages],
214
+ "dnf": ["dnf", "install", "-y", *packages],
215
+ "yum": ["yum", "install", "-y", *packages],
216
+ "zypper": ["zypper", "--non-interactive", "install", "-y", *packages],
217
+ "pacman": ["pacman", "-S", "--noconfirm", "--needed", *packages],
218
+ }
219
+ for manager, command in commands.items():
220
+ if shutil.which(manager):
221
+ if manager == "apt-get":
222
+ _run([*_sudo_prefix(), manager, "update"], ok_returncodes=(0, 100))
223
+ _run([*_sudo_prefix(), *command])
224
+ return
225
+ raise CodexPreparationError("Installing Node.js requires bash and curl; no supported package manager was found.")
226
+
227
+
213
228
  def _install_codex() -> None:
214
229
  existing = _codex_path()
215
230
  if existing and _codex_works(existing):