portacode 1.5.6.dev1__tar.gz → 1.5.6.dev3__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 (416) hide show
  1. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/PKG-INFO +1 -1
  2. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/_version.py +2 -2
  3. portacode-1.5.6.dev3/portacode/connection/handlers/file_transfer_handlers.py +206 -0
  4. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/git_manager.py +44 -18
  5. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/terminal.py +3 -0
  6. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode.egg-info/PKG-INFO +1 -1
  7. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode.egg-info/SOURCES.txt +1 -0
  8. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/.claude/agents/communication-manager.md +0 -0
  9. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/.claude/settings.local.json +0 -0
  10. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/.gitignore +0 -0
  11. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/.gitmodules +0 -0
  12. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/LICENSE +0 -0
  13. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/MANIFEST.in +0 -0
  14. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/Makefile +0 -0
  15. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/README.md +0 -0
  16. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/backup.sh +0 -0
  17. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/build_android.sh +0 -0
  18. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/connect.py +0 -0
  19. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/connect.sh +0 -0
  20. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docker-compose.yaml +0 -0
  21. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/cloudflared-domain-connect-containers-audit.md +0 -0
  22. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/creative-team-brief-portacode.md +0 -0
  23. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/devops-messaging-ab-tests.md +0 -0
  24. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/homepage-dashboard-positioning-fixes.md +0 -0
  25. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/images/device-transfer-button.png +0 -0
  26. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/images/device-transfer-modal.png +0 -0
  27. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/images/pair-device-button.png +0 -0
  28. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/images/pairing-request.png +0 -0
  29. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/images/student-workspace.png +0 -0
  30. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/docs/template-guide.html +0 -0
  31. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/README.md +0 -0
  32. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/simple_device/Dockerfile +0 -0
  33. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/simple_device/README.md +0 -0
  34. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode +0 -0
  35. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/simple_device/data/device-01/.local/share/portacode/keys/id_portacode.pub +0 -0
  36. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/simple_device/docker-compose.yaml +0 -0
  37. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/Dockerfile +0 -0
  38. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/README.md +0 -0
  39. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode +0 -0
  40. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/.local/share/portacode/keys/id_portacode.pub +0 -0
  41. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/.local/share/portacode/run/gateway.pid +0 -0
  42. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/.gitignore +0 -0
  43. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/README.md +0 -0
  44. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/db.sqlite3 +0 -0
  45. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__init__.py +0 -0
  46. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/__init__.cpython-311.pyc +0 -0
  47. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/settings.cpython-311.pyc +0 -0
  48. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/urls.cpython-311.pyc +0 -0
  49. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/__pycache__/wsgi.cpython-311.pyc +0 -0
  50. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/asgi.py +0 -0
  51. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/settings.py +0 -0
  52. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/urls.py +0 -0
  53. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/galactic_bakeshop/wsgi.py +0 -0
  54. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/manage.py +0 -0
  55. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/requirements.txt +0 -0
  56. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/templates/treats/home.html +0 -0
  57. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__init__.py +0 -0
  58. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/__init__.cpython-311.pyc +0 -0
  59. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/admin.cpython-311.pyc +0 -0
  60. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/apps.cpython-311.pyc +0 -0
  61. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/menu.cpython-311.pyc +0 -0
  62. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/models.cpython-311.pyc +0 -0
  63. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/urls.cpython-311.pyc +0 -0
  64. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/__pycache__/views.cpython-311.pyc +0 -0
  65. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/admin.py +0 -0
  66. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/apps.py +0 -0
  67. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/menu.py +0 -0
  68. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__init__.py +0 -0
  69. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
  70. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/models.py +0 -0
  71. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/tests.py +0 -0
  72. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/urls.py +0 -0
  73. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-01/workspace/treats/views.py +0 -0
  74. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode +0 -0
  75. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/.local/share/portacode/keys/id_portacode.pub +0 -0
  76. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/README.md +0 -0
  77. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/__init__.py +0 -0
  78. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/asgi.py +0 -0
  79. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/settings.py +0 -0
  80. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/urls.py +0 -0
  81. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/galactic_bakeshop/wsgi.py +0 -0
  82. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/manage.py +0 -0
  83. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/requirements.txt +0 -0
  84. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/templates/treats/home.html +0 -0
  85. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/__init__.py +0 -0
  86. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/admin.py +0 -0
  87. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/apps.py +0 -0
  88. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/menu.py +0 -0
  89. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/migrations/__init__.py +0 -0
  90. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/models.py +0 -0
  91. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/tests.py +0 -0
  92. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/urls.py +0 -0
  93. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-02/workspace/treats/views.py +0 -0
  94. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode +0 -0
  95. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/.local/share/portacode/keys/id_portacode.pub +0 -0
  96. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/README.md +0 -0
  97. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/__init__.py +0 -0
  98. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/asgi.py +0 -0
  99. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/settings.py +0 -0
  100. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/urls.py +0 -0
  101. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/galactic_bakeshop/wsgi.py +0 -0
  102. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/manage.py +0 -0
  103. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/requirements.txt +0 -0
  104. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/templates/treats/home.html +0 -0
  105. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/__init__.py +0 -0
  106. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/admin.py +0 -0
  107. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/apps.py +0 -0
  108. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/menu.py +0 -0
  109. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/migrations/__init__.py +0 -0
  110. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/models.py +0 -0
  111. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/tests.py +0 -0
  112. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/urls.py +0 -0
  113. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-03/workspace/treats/views.py +0 -0
  114. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode +0 -0
  115. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/.local/share/portacode/keys/id_portacode.pub +0 -0
  116. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/README.md +0 -0
  117. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/__init__.py +0 -0
  118. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/asgi.py +0 -0
  119. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/settings.py +0 -0
  120. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/urls.py +0 -0
  121. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/galactic_bakeshop/wsgi.py +0 -0
  122. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/manage.py +0 -0
  123. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/requirements.txt +0 -0
  124. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/templates/treats/home.html +0 -0
  125. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/__init__.py +0 -0
  126. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/admin.py +0 -0
  127. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/apps.py +0 -0
  128. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/menu.py +0 -0
  129. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/migrations/__init__.py +0 -0
  130. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/models.py +0 -0
  131. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/tests.py +0 -0
  132. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/urls.py +0 -0
  133. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-04/workspace/treats/views.py +0 -0
  134. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode +0 -0
  135. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/.local/share/portacode/keys/id_portacode.pub +0 -0
  136. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/README.md +0 -0
  137. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/__init__.py +0 -0
  138. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/asgi.py +0 -0
  139. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/settings.py +0 -0
  140. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/urls.py +0 -0
  141. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/galactic_bakeshop/wsgi.py +0 -0
  142. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/manage.py +0 -0
  143. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/requirements.txt +0 -0
  144. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/templates/treats/home.html +0 -0
  145. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/__init__.py +0 -0
  146. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/admin.py +0 -0
  147. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/apps.py +0 -0
  148. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/menu.py +0 -0
  149. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/migrations/__init__.py +0 -0
  150. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/models.py +0 -0
  151. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/tests.py +0 -0
  152. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/urls.py +0 -0
  153. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-05/workspace/treats/views.py +0 -0
  154. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode +0 -0
  155. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/.local/share/portacode/keys/id_portacode.pub +0 -0
  156. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/README.md +0 -0
  157. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/__init__.py +0 -0
  158. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/asgi.py +0 -0
  159. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/settings.py +0 -0
  160. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/urls.py +0 -0
  161. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/galactic_bakeshop/wsgi.py +0 -0
  162. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/manage.py +0 -0
  163. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/requirements.txt +0 -0
  164. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/templates/treats/home.html +0 -0
  165. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/__init__.py +0 -0
  166. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/admin.py +0 -0
  167. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/apps.py +0 -0
  168. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/menu.py +0 -0
  169. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/migrations/__init__.py +0 -0
  170. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/models.py +0 -0
  171. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/tests.py +0 -0
  172. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/urls.py +0 -0
  173. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-06/workspace/treats/views.py +0 -0
  174. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode +0 -0
  175. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/.local/share/portacode/keys/id_portacode.pub +0 -0
  176. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/README.md +0 -0
  177. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/__init__.py +0 -0
  178. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/asgi.py +0 -0
  179. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/settings.py +0 -0
  180. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/urls.py +0 -0
  181. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/galactic_bakeshop/wsgi.py +0 -0
  182. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/manage.py +0 -0
  183. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/requirements.txt +0 -0
  184. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/templates/treats/home.html +0 -0
  185. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/__init__.py +0 -0
  186. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/admin.py +0 -0
  187. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/apps.py +0 -0
  188. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/menu.py +0 -0
  189. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/migrations/__init__.py +0 -0
  190. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/models.py +0 -0
  191. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/tests.py +0 -0
  192. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/urls.py +0 -0
  193. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-07/workspace/treats/views.py +0 -0
  194. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode +0 -0
  195. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/.local/share/portacode/keys/id_portacode.pub +0 -0
  196. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/README.md +0 -0
  197. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/__init__.py +0 -0
  198. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/asgi.py +0 -0
  199. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/settings.py +0 -0
  200. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/urls.py +0 -0
  201. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/galactic_bakeshop/wsgi.py +0 -0
  202. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/manage.py +0 -0
  203. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/requirements.txt +0 -0
  204. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/templates/treats/home.html +0 -0
  205. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/__init__.py +0 -0
  206. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/admin.py +0 -0
  207. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/apps.py +0 -0
  208. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/menu.py +0 -0
  209. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/migrations/__init__.py +0 -0
  210. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/models.py +0 -0
  211. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/tests.py +0 -0
  212. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/urls.py +0 -0
  213. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-08/workspace/treats/views.py +0 -0
  214. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode +0 -0
  215. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/.local/share/portacode/keys/id_portacode.pub +0 -0
  216. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/README.md +0 -0
  217. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/__init__.py +0 -0
  218. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/asgi.py +0 -0
  219. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/settings.py +0 -0
  220. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/urls.py +0 -0
  221. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/galactic_bakeshop/wsgi.py +0 -0
  222. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/manage.py +0 -0
  223. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/requirements.txt +0 -0
  224. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/templates/treats/home.html +0 -0
  225. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/__init__.py +0 -0
  226. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/admin.py +0 -0
  227. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/apps.py +0 -0
  228. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/menu.py +0 -0
  229. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/migrations/__init__.py +0 -0
  230. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/models.py +0 -0
  231. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/tests.py +0 -0
  232. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/urls.py +0 -0
  233. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-09/workspace/treats/views.py +0 -0
  234. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode +0 -0
  235. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/.local/share/portacode/keys/id_portacode.pub +0 -0
  236. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/README.md +0 -0
  237. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/__init__.py +0 -0
  238. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/asgi.py +0 -0
  239. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/settings.py +0 -0
  240. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/urls.py +0 -0
  241. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/galactic_bakeshop/wsgi.py +0 -0
  242. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/manage.py +0 -0
  243. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/requirements.txt +0 -0
  244. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/templates/treats/home.html +0 -0
  245. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/__init__.py +0 -0
  246. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/admin.py +0 -0
  247. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/apps.py +0 -0
  248. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/menu.py +0 -0
  249. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/migrations/__init__.py +0 -0
  250. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/models.py +0 -0
  251. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/tests.py +0 -0
  252. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/urls.py +0 -0
  253. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/data/student-10/workspace/treats/views.py +0 -0
  254. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/docker-compose.yaml +0 -0
  255. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/README.md +0 -0
  256. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/galactic_bakeshop/__init__.py +0 -0
  257. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/galactic_bakeshop/asgi.py +0 -0
  258. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/galactic_bakeshop/settings.py +0 -0
  259. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/galactic_bakeshop/urls.py +0 -0
  260. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/galactic_bakeshop/wsgi.py +0 -0
  261. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/manage.py +0 -0
  262. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/requirements.txt +0 -0
  263. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/templates/treats/home.html +0 -0
  264. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/__init__.py +0 -0
  265. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/admin.py +0 -0
  266. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/apps.py +0 -0
  267. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/menu.py +0 -0
  268. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/migrations/__init__.py +0 -0
  269. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/models.py +0 -0
  270. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/tests.py +0 -0
  271. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/urls.py +0 -0
  272. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/initial_content/treats/views.py +0 -0
  273. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/examples/workshop_fleet/instructions/WELCOME.md +0 -0
  274. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/README.md +0 -0
  275. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/__init__.py +0 -0
  276. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/__main__.py +0 -0
  277. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/cli.py +0 -0
  278. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/README.md +0 -0
  279. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/__init__.py +0 -0
  280. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/client.py +0 -0
  281. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/README.md +0 -0
  282. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +0 -0
  283. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/__init__.py +0 -0
  284. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/automation_v2_handlers.py +0 -0
  285. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/base.py +0 -0
  286. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/chunked_content.py +0 -0
  287. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/cloudflare_forwarding.py +0 -0
  288. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/cloudflare_tunnel.py +0 -0
  289. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/diff_handlers.py +0 -0
  290. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/file_handlers.py +0 -0
  291. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_aware_file_handlers.py +0 -0
  292. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/README.md +0 -0
  293. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/__init__.py +0 -0
  294. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
  295. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/handlers.py +0 -0
  296. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/manager.py +0 -0
  297. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/models.py +0 -0
  298. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state/utils.py +0 -0
  299. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/project_state_handlers.py +0 -0
  300. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/proxmox_infra.py +0 -0
  301. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/registry.py +0 -0
  302. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/runtime_user.py +0 -0
  303. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/session.py +0 -0
  304. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/system_handlers.py +0 -0
  305. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/tab_factory.py +0 -0
  306. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/terminal_handlers.py +0 -0
  307. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/test_cloudflare_forwarding.py +0 -0
  308. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/test_proxmox_infra.py +0 -0
  309. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/test_runtime_user.py +0 -0
  310. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/handlers/update_handler.py +0 -0
  311. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/multiplex.py +0 -0
  312. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/test_webmin_proxy_config.py +0 -0
  313. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/connection/webmin_proxy_config.py +0 -0
  314. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/data.py +0 -0
  315. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/exit_codes.py +0 -0
  316. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/keypair.py +0 -0
  317. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/__init__.py +0 -0
  318. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
  319. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
  320. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/elinks +0 -0
  321. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/gio-open +0 -0
  322. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/gnome-open +0 -0
  323. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/gvfs-open +0 -0
  324. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/kde-open +0 -0
  325. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/kfmclient +0 -0
  326. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/link_capture_exec.sh +0 -0
  327. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/link_capture_wrapper.py +0 -0
  328. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/links +0 -0
  329. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/links2 +0 -0
  330. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/lynx +0 -0
  331. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/mate-open +0 -0
  332. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/netsurf +0 -0
  333. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/sensible-browser +0 -0
  334. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/w3m +0 -0
  335. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/x-www-browser +0 -0
  336. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/link_capture/bin/xdg-open +0 -0
  337. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/logging_categories.py +0 -0
  338. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/pairing.py +0 -0
  339. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/restart.py +0 -0
  340. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/service.py +0 -0
  341. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/static/js/test-ntp-clock.html +0 -0
  342. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/static/js/utils/ntp-clock.js +0 -0
  343. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/test_runtime_paths.py +0 -0
  344. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/test_service.py +0 -0
  345. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/test_terminal_exposed_services.py +0 -0
  346. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/__init__.py +0 -0
  347. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/cloudflared_login.py +0 -0
  348. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/ensure_cloudflared.py +0 -0
  349. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/ensure_pyyaml.py +0 -0
  350. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/forwarding_state.py +0 -0
  351. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/get_domain.py +0 -0
  352. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/privileged.py +0 -0
  353. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/service_install.py +0 -0
  354. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/tunneling/state.py +0 -0
  355. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/updater.py +0 -0
  356. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/utils/NTP_ARCHITECTURE.md +0 -0
  357. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/utils/__init__.py +0 -0
  358. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/utils/diff_apply.py +0 -0
  359. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/utils/diff_renderer.py +0 -0
  360. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/utils/ntp_clock.py +0 -0
  361. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode/utils/runtime_paths.py +0 -0
  362. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode.egg-info/dependency_links.txt +0 -0
  363. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode.egg-info/entry_points.txt +0 -0
  364. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode.egg-info/requires.txt +0 -0
  365. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/portacode.egg-info/top_level.txt +0 -0
  366. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/pyproject.toml +0 -0
  367. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/restore.sh +0 -0
  368. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/run_tests.py +0 -0
  369. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/setup.cfg +0 -0
  370. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/setup.py +0 -0
  371. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test.sh +0 -0
  372. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/README.md +0 -0
  373. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/__init__.py +0 -0
  374. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_device_online.py +0 -0
  375. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_file_operations.py +0 -0
  376. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_git_status_ui.py +0 -0
  377. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_login_flow.py +0 -0
  378. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_navigate_testing_folder.py +0 -0
  379. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_play_store_screenshots.py +0 -0
  380. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_terminal_buffer_performance.py +0 -0
  381. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_terminal_interaction.py +0 -0
  382. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_terminal_loading_race_condition.py +0 -0
  383. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_modules/test_terminal_start.py +0 -0
  384. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/test_request_id.py +0 -0
  385. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/.env.example +0 -0
  386. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/README.md +0 -0
  387. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/__init__.py +0 -0
  388. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/cli.py +0 -0
  389. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/__init__.py +0 -0
  390. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/base_test.py +0 -0
  391. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/cli_manager.py +0 -0
  392. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/hierarchical_runner.py +0 -0
  393. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/playwright_manager.py +0 -0
  394. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/runner.py +0 -0
  395. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/shared_cli_manager.py +0 -0
  396. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/core/test_discovery.py +0 -0
  397. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/testing_framework/requirements.txt +0 -0
  398. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/UI_UX/opening_a_file_on_desktop_results_in_nothing.md +0 -0
  399. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/UI_UX/server_occasionally_stops_communicating_with_all_devices.md +0 -0
  400. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/agent_context_management.md +0 -0
  401. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/django_server_time_sync.md +0 -0
  402. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/device_performance_degradation.md +0 -0
  403. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/git_data_not_captured_in_proxmox.md +0 -0
  404. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/indefinite_resource_loading.md +0 -0
  405. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/portacode_service_silently_down.md +0 -0
  406. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/premature_terminal_exit.md +0 -0
  407. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/project_cpu_hotspots.md +0 -0
  408. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/terminals_exit_upon_starting.md +0 -0
  409. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/websocket_client_silently_dead.md +0 -0
  410. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/issues/wrong_item_classification_on_client_side.md +0 -0
  411. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/todo/smartphone_terminal_input_frustrations.md +0 -0
  412. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/tools/generate_play_store_assets.py +0 -0
  413. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/tools/pairing_tester.py +0 -0
  414. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/tools/run_screenshot_suite.sh +0 -0
  415. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/tools/test_python_ntp_clock.py +0 -0
  416. {portacode-1.5.6.dev1 → portacode-1.5.6.dev3}/validate.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 1.5.6.dev1
3
+ Version: 1.5.6.dev3
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.5.6.dev1'
32
- __version_tuple__ = version_tuple = (1, 5, 6, 'dev1')
31
+ __version__ = version = '1.5.6.dev3'
32
+ __version_tuple__ = version_tuple = (1, 5, 6, 'dev3')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -0,0 +1,206 @@
1
+ """Isolated handlers for websocket file upload and download transfers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import base64
7
+ import logging
8
+ import os
9
+ import pwd
10
+ import stat
11
+ from pathlib import Path
12
+ from typing import Any, Dict, Optional
13
+
14
+ from .base import AsyncHandler, SyncHandler
15
+ from .chunked_content import ChunkAssembler, create_chunked_response
16
+ from .project_state.manager import get_or_create_project_state_manager
17
+ from .runtime_user import get_default_runtime_user
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ def _schedule_project_state_refresh(handler, changed_path: str) -> None:
23
+ try:
24
+ manager = get_or_create_project_state_manager(handler.context, handler.control_channel)
25
+ loop = asyncio.get_event_loop()
26
+ if loop.is_running():
27
+ loop.create_task(manager.refresh_project_state_for_file_change(str(changed_path)))
28
+ except Exception as exc:
29
+ logger.warning("Failed to refresh project state after transfer for %s: %s", changed_path, exc)
30
+
31
+
32
+ def _chown_path_if_possible(path: str | Path, user: Optional[str]) -> None:
33
+ if not user or os.name == "nt":
34
+ return
35
+ try:
36
+ pw_entry = pwd.getpwnam(user)
37
+ os.chown(path, pw_entry.pw_uid, pw_entry.pw_gid)
38
+ except Exception:
39
+ return
40
+
41
+
42
+ def _restore_metadata(path: Path, original_stat: Optional[os.stat_result]) -> None:
43
+ if original_stat is None:
44
+ return
45
+ try:
46
+ os.chmod(path, stat.S_IMODE(original_stat.st_mode))
47
+ except OSError:
48
+ pass
49
+ try:
50
+ os.chown(path, original_stat.st_uid, original_stat.st_gid)
51
+ except OSError:
52
+ pass
53
+
54
+
55
+ def _write_bytes_preserve_metadata(path: str | Path, content: bytes, *, create_user: Optional[str] = None) -> int:
56
+ target = Path(path)
57
+ target.parent.mkdir(parents=True, exist_ok=True)
58
+ existed = target.exists()
59
+ original_stat = target.stat() if existed else None
60
+
61
+ with open(target, "wb") as file_obj:
62
+ file_obj.write(content)
63
+
64
+ if existed:
65
+ _restore_metadata(target, original_stat)
66
+ else:
67
+ _chown_path_if_possible(target, create_user)
68
+
69
+ return len(content)
70
+
71
+
72
+ class FileUploadHandler(SyncHandler):
73
+ """Upload a file to disk, optionally across multiple websocket chunks."""
74
+
75
+ def __init__(self, control_channel, context):
76
+ super().__init__(control_channel, context)
77
+ self._chunk_assembler = ChunkAssembler()
78
+
79
+ @property
80
+ def command_name(self) -> str:
81
+ return "file_upload"
82
+
83
+ def execute(self, message: Dict[str, Any]) -> Dict[str, Any]:
84
+ path = message.get("path")
85
+ file_name = message.get("file_name") or (Path(path).name if path else None)
86
+ mime_type = message.get("mime_type") or "application/octet-stream"
87
+ chunked = bool(message.get("chunked", False))
88
+
89
+ try:
90
+ self._chunk_assembler.cleanup_stale_transfers()
91
+ if not path:
92
+ raise ValueError("path parameter is required")
93
+
94
+ content_base64 = message.get("content_base64")
95
+ if chunked:
96
+ content_base64 = self._chunk_assembler.add_chunk(message, "content_base64")
97
+ if content_base64 is None:
98
+ return {
99
+ "event": "file_upload_response",
100
+ "path": path,
101
+ "file_name": file_name,
102
+ "mime_type": mime_type,
103
+ "transfer_id": message.get("transfer_id"),
104
+ "chunked": True,
105
+ "chunk_received": True,
106
+ "success": True,
107
+ "complete": False,
108
+ }
109
+
110
+ if content_base64 is None:
111
+ raise ValueError("content_base64 parameter is required")
112
+
113
+ overwrite = bool(message.get("overwrite", False))
114
+ file_path = Path(path)
115
+ parent_dir = file_path.parent
116
+ if not parent_dir.exists():
117
+ raise ValueError(f"Parent directory does not exist: {parent_dir}")
118
+ if not parent_dir.is_dir():
119
+ raise ValueError(f"Parent path is not a directory: {parent_dir}")
120
+ if file_path.exists() and not overwrite:
121
+ raise ValueError(f"Target already exists: {file_path}")
122
+
123
+ try:
124
+ content_bytes = base64.b64decode(content_base64.encode("ascii"), validate=True)
125
+ except Exception as exc:
126
+ raise ValueError(f"Invalid base64 file content: {exc}") from exc
127
+
128
+ bytes_written = _write_bytes_preserve_metadata(
129
+ file_path,
130
+ content_bytes,
131
+ create_user=get_default_runtime_user(message),
132
+ )
133
+ _schedule_project_state_refresh(self, str(file_path))
134
+
135
+ return {
136
+ "event": "file_upload_response",
137
+ "path": str(file_path),
138
+ "file_name": file_name,
139
+ "mime_type": mime_type,
140
+ "bytes_written": bytes_written,
141
+ "file_size": len(content_bytes),
142
+ "chunked": chunked,
143
+ "success": True,
144
+ "complete": True,
145
+ }
146
+ except Exception as exc:
147
+ return {
148
+ "event": "file_upload_response",
149
+ "path": path,
150
+ "file_name": file_name,
151
+ "mime_type": mime_type,
152
+ "chunked": chunked,
153
+ "success": False,
154
+ "complete": True,
155
+ "error": str(exc),
156
+ "message": str(exc),
157
+ }
158
+
159
+
160
+ class FileDownloadHandler(AsyncHandler):
161
+ """Read a file from disk and send it as base64, chunked when large."""
162
+
163
+ @property
164
+ def command_name(self) -> str:
165
+ return "file_download"
166
+
167
+ async def execute(self, message: Dict[str, Any]) -> Dict[str, Any]:
168
+ path = message.get("path")
169
+ try:
170
+ if not path:
171
+ raise ValueError("path parameter is required")
172
+
173
+ file_path = Path(path)
174
+ if not file_path.exists():
175
+ raise ValueError(f"File not found: {path}")
176
+ if not file_path.is_file():
177
+ raise ValueError(f"Path is not a file: {path}")
178
+
179
+ content_bytes = file_path.read_bytes()
180
+ content_base64 = base64.b64encode(content_bytes).decode("ascii")
181
+ base_response = {
182
+ "event": "file_download_response",
183
+ "path": str(file_path),
184
+ "file_name": file_path.name,
185
+ "mime_type": message.get("mime_type") or "application/octet-stream",
186
+ "file_size": len(content_bytes),
187
+ "success": True,
188
+ }
189
+ if "request_id" in message:
190
+ base_response["request_id"] = message["request_id"]
191
+
192
+ for response in create_chunked_response(base_response, "content_base64", content_base64):
193
+ await self.send_response(response, project_id=message.get("project_id"))
194
+ return None
195
+ except Exception as exc:
196
+ response = {
197
+ "event": "file_download_response",
198
+ "path": path,
199
+ "success": False,
200
+ "chunked": False,
201
+ "error": str(exc),
202
+ "message": str(exc),
203
+ }
204
+ if "request_id" in message:
205
+ response["request_id"] = message["request_id"]
206
+ return response
@@ -16,6 +16,7 @@ from pathlib import Path
16
16
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
17
17
 
18
18
  from .models import GitDetailedStatus, GitFileChange
19
+ from ..runtime_user import get_default_runtime_user, wrap_argv_for_user
19
20
 
20
21
  logger = logging.getLogger(__name__)
21
22
 
@@ -138,6 +139,30 @@ class GitManager:
138
139
  continue
139
140
  except Exception as e:
140
141
  logger.debug("Error tracking git processes: %s", e)
142
+
143
+ def _run_git_write(self, args: List[str]) -> subprocess.CompletedProcess:
144
+ """Run a mutating git command as the configured runtime user."""
145
+ runtime_user = get_default_runtime_user()
146
+ cwd = self.repo.working_tree_dir if self.repo and self.repo.working_tree_dir else self.project_path
147
+ argv = wrap_argv_for_user(["git", *args], runtime_user, cwd=cwd)
148
+ return subprocess.run(
149
+ argv,
150
+ cwd=cwd,
151
+ check=True,
152
+ capture_output=True,
153
+ text=True,
154
+ )
155
+
156
+ def _remove_file_as_runtime_user(self, file_path: str) -> None:
157
+ runtime_user = get_default_runtime_user()
158
+ argv = wrap_argv_for_user(["rm", "-f", file_path], runtime_user, cwd=os.path.dirname(file_path) or None)
159
+ subprocess.run(
160
+ argv,
161
+ cwd=os.path.dirname(file_path) or None,
162
+ check=True,
163
+ capture_output=True,
164
+ text=True,
165
+ )
141
166
 
142
167
  def reinitialize(self):
143
168
  """Reinitialize git repo detection (useful when .git directory is created after initialization)."""
@@ -992,10 +1017,10 @@ class GitManager:
992
1017
  if self._is_submodule(file_path):
993
1018
  logger.info("Detected submodule, using git add command directly: %s", rel_path)
994
1019
  # For submodules, use git add directly to stage only the submodule reference
995
- self.repo.git.add(rel_path)
1020
+ self._run_git_write(["add", rel_path])
996
1021
  else:
997
1022
  # Use git add -A on the specific file to handle deletions as well
998
- self.repo.git.add('-A', '--', rel_path)
1023
+ self._run_git_write(["add", "-A", "--", rel_path])
999
1024
 
1000
1025
  logger.info("Successfully staged file: %s", rel_path)
1001
1026
  return True
@@ -1017,7 +1042,7 @@ class GitManager:
1017
1042
  if self._is_submodule(file_path):
1018
1043
  logger.info("Detected submodule, using git restore for unstaging: %s", rel_path)
1019
1044
  # For submodules, always use git restore --staged (works with submodules)
1020
- self.repo.git.restore('--staged', rel_path)
1045
+ self._run_git_write(["restore", "--staged", rel_path])
1021
1046
  else:
1022
1047
  # Check if repository has any commits (HEAD exists)
1023
1048
  try:
@@ -1028,10 +1053,10 @@ class GitManager:
1028
1053
 
1029
1054
  if has_head:
1030
1055
  # Reset the file from HEAD (unstage) - for repos with commits
1031
- self.repo.git.restore('--staged', rel_path)
1056
+ self._run_git_write(["restore", "--staged", rel_path])
1032
1057
  else:
1033
1058
  # For repositories with no commits, use git rm --cached to unstage
1034
- self.repo.git.rm('--cached', rel_path)
1059
+ self._run_git_write(["rm", "--cached", rel_path])
1035
1060
 
1036
1061
  logger.info("Successfully unstaged file: %s", rel_path)
1037
1062
  return True
@@ -1058,13 +1083,13 @@ class GitManager:
1058
1083
 
1059
1084
  if has_head:
1060
1085
  # Restore both index and working tree from HEAD
1061
- self.repo.git.restore('--staged', '--worktree', '--', rel_path)
1086
+ self._run_git_write(["restore", "--staged", "--worktree", "--", rel_path])
1062
1087
  logger.info("Successfully reverted file: %s", rel_path)
1063
1088
  else:
1064
1089
  # For repositories with no commits, we can't revert to HEAD
1065
1090
  # Instead, just remove the file to "revert" it to non-existence
1066
1091
  if os.path.exists(file_path):
1067
- os.remove(file_path)
1092
+ self._remove_file_as_runtime_user(file_path)
1068
1093
  logger.info("Successfully removed file (no HEAD to revert to): %s", rel_path)
1069
1094
  else:
1070
1095
  logger.info("File already does not exist (no HEAD to revert to): %s", rel_path)
@@ -1100,12 +1125,12 @@ class GitManager:
1100
1125
  if submodule_paths:
1101
1126
  logger.info("Staging submodules using git add directly: %s", submodule_paths)
1102
1127
  for submodule_path in submodule_paths:
1103
- self.repo.git.add(submodule_path)
1128
+ self._run_git_write(["add", submodule_path])
1104
1129
 
1105
1130
  # Stage regular files using git add -A to capture deletions
1106
1131
  if rel_paths:
1107
1132
  logger.info("Staging regular files: %s", rel_paths)
1108
- self.repo.git.add('-A', '--', *rel_paths)
1133
+ self._run_git_write(["add", "-A", "--", *rel_paths])
1109
1134
 
1110
1135
  logger.info("Successfully staged %d files (%d submodules, %d regular)",
1111
1136
  len(file_paths), len(submodule_paths), len(rel_paths))
@@ -1149,11 +1174,11 @@ class GitManager:
1149
1174
  if has_head:
1150
1175
  # Use git restore --staged for all files (works for both regular files and submodules)
1151
1176
  if all_rel_paths:
1152
- self.repo.git.restore('--staged', *all_rel_paths)
1177
+ self._run_git_write(["restore", "--staged", *all_rel_paths])
1153
1178
  else:
1154
1179
  # For repositories with no commits, use git rm --cached
1155
1180
  if all_rel_paths:
1156
- self.repo.git.rm('--cached', *all_rel_paths)
1181
+ self._run_git_write(["rm", "--cached", *all_rel_paths])
1157
1182
 
1158
1183
  logger.info("Successfully unstaged %d files (%d submodules, %d regular)",
1159
1184
  len(file_paths), len(submodule_paths), len(rel_paths))
@@ -1190,14 +1215,14 @@ class GitManager:
1190
1215
  regular_files.append(rel_paths[i])
1191
1216
 
1192
1217
  if regular_files:
1193
- self.repo.git.restore('--staged', '--worktree', '--', *regular_files)
1218
+ self._run_git_write(["restore", "--staged", "--worktree", "--", *regular_files])
1194
1219
  logger.info("Successfully reverted %d files", len(regular_files))
1195
1220
  else:
1196
1221
  # For repositories with no commits, remove files to "revert" them
1197
1222
  removed_count = 0
1198
1223
  for file_path in file_paths:
1199
1224
  if not self._is_submodule(file_path) and os.path.exists(file_path):
1200
- os.remove(file_path)
1225
+ self._remove_file_as_runtime_user(file_path)
1201
1226
  removed_count += 1
1202
1227
  logger.info("Successfully removed %d files (no HEAD to revert to)", removed_count)
1203
1228
 
@@ -1214,7 +1239,7 @@ class GitManager:
1214
1239
 
1215
1240
  try:
1216
1241
  # Use git add . to stage everything - this is the most efficient way
1217
- self.repo.git.add('.')
1242
+ self._run_git_write(["add", "."])
1218
1243
  logger.info("Successfully staged all changes using 'git add .'")
1219
1244
  return True
1220
1245
 
@@ -1237,10 +1262,10 @@ class GitManager:
1237
1262
 
1238
1263
  if has_head:
1239
1264
  # Use git restore --staged . to unstage everything
1240
- self.repo.git.restore('--staged', '.')
1265
+ self._run_git_write(["restore", "--staged", "."])
1241
1266
  else:
1242
1267
  # For repositories with no commits, remove everything from index
1243
- self.repo.git.rm('--cached', '-r', '.')
1268
+ self._run_git_write(["rm", "--cached", "-r", "."])
1244
1269
 
1245
1270
  logger.info("Successfully unstaged all changes")
1246
1271
  return True
@@ -1264,7 +1289,7 @@ class GitManager:
1264
1289
 
1265
1290
  if has_head:
1266
1291
  # Use git restore . to revert all working directory changes
1267
- self.repo.git.restore('.')
1292
+ self._run_git_write(["restore", "."])
1268
1293
  logger.info("Successfully reverted all working directory changes")
1269
1294
  else:
1270
1295
  logger.warning("Cannot revert changes in repository with no commits")
@@ -1308,7 +1333,8 @@ class GitManager:
1308
1333
  raise RuntimeError("No staged changes to commit")
1309
1334
 
1310
1335
  # Perform the commit
1311
- commit = self.repo.index.commit(message.strip())
1336
+ self._run_git_write(["commit", "-m", message.strip()])
1337
+ commit = self.repo.head.commit
1312
1338
  logger.info("Successfully committed changes with hash: %s", commit.hexsha)
1313
1339
  logger.info("Commit message: %s", message.strip())
1314
1340
 
@@ -74,6 +74,7 @@ from .handlers.project_aware_file_handlers import (
74
74
  ProjectAwareFileCreateHandler,
75
75
  ProjectAwareFolderCreateHandler,
76
76
  )
77
+ from .handlers.file_transfer_handlers import FileUploadHandler, FileDownloadHandler
77
78
  from .handlers.session import SessionManager
78
79
  from .webmin_proxy_config import apply_turnkey_webmin_proxy_config
79
80
  from portacode.tunneling.privileged import read_text, run, write_text
@@ -512,6 +513,8 @@ class TerminalManager:
512
513
  self._command_registry.register(ProjectAwareFileCreateHandler) # Use project-aware version
513
514
  self._command_registry.register(ProjectAwareFolderCreateHandler) # Use project-aware version
514
515
  self._command_registry.register(FileRenameHandler)
516
+ self._command_registry.register(FileUploadHandler)
517
+ self._command_registry.register(FileDownloadHandler)
515
518
  self._command_registry.register(FileSearchHandler)
516
519
  self._command_registry.register(ContentRequestHandler)
517
520
  self._command_registry.register(FileApplyDiffHandler)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 1.5.6.dev1
3
+ Version: 1.5.6.dev3
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -310,6 +310,7 @@ portacode/connection/handlers/cloudflare_forwarding.py
310
310
  portacode/connection/handlers/cloudflare_tunnel.py
311
311
  portacode/connection/handlers/diff_handlers.py
312
312
  portacode/connection/handlers/file_handlers.py
313
+ portacode/connection/handlers/file_transfer_handlers.py
313
314
  portacode/connection/handlers/project_aware_file_handlers.py
314
315
  portacode/connection/handlers/project_state_handlers.py
315
316
  portacode/connection/handlers/proxmox_infra.py
File without changes
File without changes
File without changes
File without changes