abstra 3.23.11__py3-none-any.whl → 3.24.0__py3-none-any.whl

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.

Potentially problematic release.


This version of abstra might be problematic. Click here for more details.

Files changed (268) hide show
  1. abstra/ai.py +2 -0
  2. abstra/cli.py +8 -3
  3. {abstra-3.23.11.dist-info → abstra-3.24.0.dist-info}/METADATA +2 -1
  4. {abstra-3.23.11.dist-info → abstra-3.24.0.dist-info}/RECORD +201 -191
  5. abstra_internals/consts/filepaths.py +1 -1
  6. abstra_internals/contracts_generated.py +5382 -5233
  7. abstra_internals/controllers/ai.py +23 -15
  8. abstra_internals/controllers/git.py +305 -0
  9. abstra_internals/controllers/main.py +10 -6
  10. abstra_internals/entities/forms/template.py +2 -2
  11. abstra_internals/environment.py +6 -0
  12. abstra_internals/interface/cli/deploy.py +1 -1
  13. abstra_internals/interface/sdk/ai.py +157 -19
  14. abstra_internals/repositories/git/__init__.py +38 -0
  15. abstra_internals/repositories/git/dulwich.py +1353 -0
  16. abstra_internals/repositories/git/git_test.py +1572 -0
  17. abstra_internals/repositories/git/native.py +578 -0
  18. abstra_internals/repositories/git/types.py +267 -0
  19. abstra_internals/repositories/linter/rules/env_in_bundle.py +5 -5
  20. abstra_internals/repositories/linter/rules/env_in_bundle_test.py +6 -6
  21. abstra_internals/repositories/linter/rules/venv_in_bundle.py +9 -16
  22. abstra_internals/server/blueprints/editor.py +4 -0
  23. abstra_internals/server/routes/ai.py +1 -18
  24. abstra_internals/server/routes/git.py +190 -0
  25. abstra_internals/server/routes/workspace.py +1 -1
  26. abstra_internals/services/file_watcher.py +32 -13
  27. abstra_internals/services/fs.py +8 -5
  28. abstra_internals/services/fs_test.py +4 -6
  29. abstra_internals/templates/__init__.py +0 -11
  30. abstra_statics/dist/assets/AbstraButton.vue_vue_type_script_setup_true_lang.eb8ccb64.js +2 -0
  31. abstra_statics/dist/assets/AbstraLogo.vue_vue_type_script_setup_true_lang.9f98292e.js +2 -0
  32. abstra_statics/dist/assets/ApiKeys.e975c4f3.js +2 -0
  33. abstra_statics/dist/assets/App.f62faff6.js +2 -0
  34. abstra_statics/dist/assets/App.vue_vue_type_style_index_0_lang.5aa45ac1.js +2 -0
  35. abstra_statics/dist/assets/BaseLayout.1ec2c96d.js +2 -0
  36. abstra_statics/dist/assets/Billing.60adc9fa.js +2 -0
  37. abstra_statics/dist/assets/{Breadcrumb.f11a16d0.js → Breadcrumb.26dec5f7.js} +2 -2
  38. abstra_statics/dist/assets/{Builds.2bf5dad8.js → Builds.f86210bc.js} +2 -2
  39. abstra_statics/dist/assets/{Card.6caecaa4.js → Card.6cfffb80.js} +2 -2
  40. abstra_statics/dist/assets/{CircularLoading.bc88c029.js → CircularLoading.a13d6a76.js} +2 -2
  41. abstra_statics/dist/assets/CloseCircleOutlined.30bc25a8.js +2 -0
  42. abstra_statics/dist/assets/{ConnectorsView.aeb00ce8.css → ConnectorsView.33c5380f.css} +1 -1
  43. abstra_statics/dist/assets/ConnectorsView.eb4c769f.js +2 -0
  44. abstra_statics/dist/assets/ConsoleOmniChat.vue_vue_type_script_setup_true_lang.8d2e4672.js +2 -0
  45. abstra_statics/dist/assets/ContentLayout.d03fee5b.js +2 -0
  46. abstra_statics/dist/assets/{CrudView.79588134.js → CrudView.c0824225.js} +2 -2
  47. abstra_statics/dist/assets/{DocsButton.vue_vue_type_script_setup_true_lang.6566ff97.js → DocsButton.vue_vue_type_script_setup_true_lang.3668aee4.js} +2 -2
  48. abstra_statics/dist/assets/{EditorLogin.e704b2ee.js → EditorLogin.46db248f.js} +2 -2
  49. abstra_statics/dist/assets/EditorsView.e72621fa.js +2 -0
  50. abstra_statics/dist/assets/EnvVars.f9f9d61f.js +2 -0
  51. abstra_statics/dist/assets/{Error.f378696f.js → Error.864f05b3.js} +2 -2
  52. abstra_statics/dist/assets/ExclamationCircleOutlined.a489b996.js +2 -0
  53. abstra_statics/dist/assets/{Files.06a52abd.js → Files.afe615e1.js} +2 -2
  54. abstra_statics/dist/assets/Form.556d0de2.js +2 -0
  55. abstra_statics/dist/assets/{FormRunner.2b75fd4d.js → FormRunner.7f56a8c6.js} +2 -2
  56. abstra_statics/dist/assets/Home.287d17f8.js +2 -0
  57. abstra_statics/dist/assets/Home.5b7e9c23.js +2 -0
  58. abstra_statics/dist/assets/{Live.08670b33.js → Live.50bacfea.js} +2 -2
  59. abstra_statics/dist/assets/LoadingContainer.ebace8de.js +2 -0
  60. abstra_statics/dist/assets/{LoadingOutlined.659d6aae.js → LoadingOutlined.9e949112.js} +2 -2
  61. abstra_statics/dist/assets/{Login.8491c4b7.js → Login.536a3067.js} +2 -2
  62. abstra_statics/dist/assets/Login.bec408c9.js +2 -0
  63. abstra_statics/dist/assets/{Login.vue_vue_type_script_setup_true_lang.eb94ecc3.js → Login.vue_vue_type_script_setup_true_lang.1c3f108d.js} +2 -2
  64. abstra_statics/dist/assets/{Logo.a32d36e7.js → Logo.82d6ab70.js} +2 -2
  65. abstra_statics/dist/assets/{Logs.030c8a19.js → Logs.f6135084.js} +2 -2
  66. abstra_statics/dist/assets/{LogsController.7e2c0c7a.js → LogsController.6b666816.js} +2 -2
  67. abstra_statics/dist/assets/Main.77b115f8.js +2 -0
  68. abstra_statics/dist/assets/{MockForm.8b56fd25.js → MockForm.deda9355.js} +2 -2
  69. abstra_statics/dist/assets/Navbar.4a6f2b09.js +2 -0
  70. abstra_statics/dist/assets/NewEditor.5f84de86.css +1 -0
  71. abstra_statics/dist/assets/NewEditor.e558e47d.js +8 -0
  72. abstra_statics/dist/assets/OidcLoginCallback.7f514b45.js +2 -0
  73. abstra_statics/dist/assets/OidcLogoutCallback.038813a1.js +2 -0
  74. abstra_statics/dist/assets/OmniChat.05ba8d8a.css +1 -0
  75. abstra_statics/dist/assets/OmniChat.60d98deb.js +6 -0
  76. abstra_statics/dist/assets/{OnboardingView.262e82cc.js → OnboardingView.9413ee50.js} +2 -2
  77. abstra_statics/dist/assets/{Organization.4f3ccb55.js → Organization.7203cc0b.js} +2 -2
  78. abstra_statics/dist/assets/Organizations.91220ca0.js +2 -0
  79. abstra_statics/dist/assets/{PhArrowCounterClockwise.vue.a1a917b9.js → PhArrowCounterClockwise.vue.8090d021.js} +2 -2
  80. abstra_statics/dist/assets/{PhArrowSquareOut.vue.eb4455ba.js → PhArrowSquareOut.vue.26582195.js} +2 -2
  81. abstra_statics/dist/assets/{PhBookBookmark.vue.7bb66888.js → PhBookBookmark.vue.5b7ab079.js} +2 -2
  82. abstra_statics/dist/assets/{PhChats.vue.88d84608.js → PhChats.vue.b5df7174.js} +2 -2
  83. abstra_statics/dist/assets/{PhClockCounterClockwise.vue.02d85ea5.js → PhClockCounterClockwise.vue.812311ad.js} +2 -2
  84. abstra_statics/dist/assets/{PhCopy.vue.5664181e.js → PhCopy.vue.59b0f1b4.js} +2 -2
  85. abstra_statics/dist/assets/{PhCopySimple.vue.beb69d1f.js → PhCopySimple.vue.d41d9160.js} +2 -2
  86. abstra_statics/dist/assets/{PhCube.vue.8de1132a.js → PhCube.vue.63ae7d32.js} +2 -2
  87. abstra_statics/dist/assets/PhDatabase.vue.edfcb96b.js +2 -0
  88. abstra_statics/dist/assets/{PhDotsThreeVertical.vue.9e306480.js → PhDotsThreeVertical.vue.ab4580a5.js} +2 -2
  89. abstra_statics/dist/assets/PhDownloadSimple.vue.c2eaaad1.js +2 -0
  90. abstra_statics/dist/assets/{PhFolderPlus.vue.658105d4.js → PhFolderPlus.vue.05ba4a5c.js} +2 -2
  91. abstra_statics/dist/assets/{PhGear.vue.68bce043.js → PhGear.vue.0e4a6135.js} +2 -2
  92. abstra_statics/dist/assets/{PhKey.vue.3f5192b6.js → PhKey.vue.b2c184d1.js} +2 -2
  93. abstra_statics/dist/assets/{PhPencil.vue.ee28fb6e.js → PhPencil.vue.2f2fe576.js} +2 -2
  94. abstra_statics/dist/assets/{PhPencilSimple.vue.148807f6.js → PhPencilSimple.vue.cc8620ae.js} +2 -2
  95. abstra_statics/dist/assets/{PhRocket.vue.7ba12859.js → PhRocket.vue.e397203c.js} +2 -2
  96. abstra_statics/dist/assets/{PhSignOut.vue.aa78b6eb.js → PhSignOut.vue.a271f14b.js} +2 -2
  97. abstra_statics/dist/assets/{PhSparkle.vue.7820be45.js → PhSparkle.vue.726defa2.js} +2 -2
  98. abstra_statics/dist/assets/{PhUserList.vue.04f21cbe.js → PhUserList.vue.6a29f16d.js} +2 -2
  99. abstra_statics/dist/assets/{PhUsersThree.vue.8b11b97d.js → PhUsersThree.vue.275d13ab.js} +2 -2
  100. abstra_statics/dist/assets/PhWarningCircle.vue.3b1aca1b.js +2 -0
  101. abstra_statics/dist/assets/{PhWebhooksLogo.vue.9e20d559.js → PhWebhooksLogo.vue.5e772aac.js} +2 -2
  102. abstra_statics/dist/assets/{PlayerConfigProvider.0915b29f.js → PlayerConfigProvider.e90a2b41.js} +2 -2
  103. abstra_statics/dist/assets/{PlayerNavbar.78cf73f2.js → PlayerNavbar.11ec1844.js} +2 -2
  104. abstra_statics/dist/assets/Project.c16740fb.js +2 -0
  105. abstra_statics/dist/assets/ProjectLogin.e7a6f444.js +2 -0
  106. abstra_statics/dist/assets/{ProjectSettings.f9bf9124.js → ProjectSettings.52c19693.js} +2 -2
  107. abstra_statics/dist/assets/{ProjectsView.407ea382.js → ProjectsView.22fa7a8e.js} +2 -2
  108. abstra_statics/dist/assets/{SaveButton.e70cd09e.js → SaveButton.719393d2.js} +2 -2
  109. abstra_statics/dist/assets/{ScrollArea.vue_vue_type_script_setup_true_lang.cf352882.js → ScrollArea.vue_vue_type_script_setup_true_lang.d4028954.js} +2 -2
  110. abstra_statics/dist/assets/{Sidebar.e69f49bd.css → Sidebar.29baeab0.css} +1 -1
  111. abstra_statics/dist/assets/{Sidebar.ce129494.js → Sidebar.5cb8e04e.js} +2 -2
  112. abstra_statics/dist/assets/Sql.23d80bad.js +5 -0
  113. abstra_statics/dist/assets/Sql.90e6e2ba.css +1 -0
  114. abstra_statics/dist/assets/Steps.8e5d201a.js +2 -0
  115. abstra_statics/dist/assets/TableCard.529112b9.css +1 -0
  116. abstra_statics/dist/assets/TableCard.59f95f8f.js +2 -0
  117. abstra_statics/dist/assets/TableEditor.5853a363.css +1 -0
  118. abstra_statics/dist/assets/TableEditor.8539f984.js +2 -0
  119. abstra_statics/dist/assets/Tables.44d953f7.js +2 -0
  120. abstra_statics/dist/assets/TablesDiagram.8e47383c.js +15 -0
  121. abstra_statics/dist/assets/TablesDiagram.a588e7ff.css +1 -0
  122. abstra_statics/dist/assets/TablesTabs.vue_vue_type_script_setup_true_lang.6866fb32.js +2 -0
  123. abstra_statics/dist/assets/{Tasks.c9ba3095.js → Tasks.09551b19.js} +2 -2
  124. abstra_statics/dist/assets/{UploadOutlined.c563b054.js → UploadOutlined.eab75eb0.js} +2 -2
  125. abstra_statics/dist/assets/View.5fd7ddf0.js +2 -0
  126. abstra_statics/dist/assets/{View.vue_vue_type_script_setup_true_lang.a00f21c8.js → View.vue_vue_type_script_setup_true_lang.a904f400.js} +2 -2
  127. abstra_statics/dist/assets/{Watermark.c71c105b.js → Watermark.ab3d818f.js} +2 -2
  128. abstra_statics/dist/assets/WebEditor.d6ec6392.js +2 -0
  129. abstra_statics/dist/assets/{WidgetPreview.8bd406f7.js → WidgetPreview.86b31dec.js} +2 -2
  130. abstra_statics/dist/assets/{ant-design.06b818ab.js → ant-design.a865486e.js} +2 -2
  131. abstra_statics/dist/assets/apiKey.72f497ca.js +2 -0
  132. abstra_statics/dist/assets/{asyncComputed.bfb7341c.js → asyncComputed.cf5282fc.js} +2 -2
  133. abstra_statics/dist/assets/{build.aef51d48.js → build.df2d55cc.js} +2 -2
  134. abstra_statics/dist/assets/colorHelpers.37d9932b.js +2 -0
  135. abstra_statics/dist/assets/console.2bf7f04d.js +17 -0
  136. abstra_statics/dist/assets/{constants.b75d9567.js → constants.7d38ec8b.js} +2 -2
  137. abstra_statics/dist/assets/contracts.generated.590b1102.js +2 -0
  138. abstra_statics/dist/assets/{cssMode.0aa24dcd.js → cssMode.7133c7cb.js} +2 -2
  139. abstra_statics/dist/assets/{datetime.46141396.js → datetime.8de2ff28.js} +2 -2
  140. abstra_statics/dist/assets/dayjs.f18bbbca.js +2 -0
  141. abstra_statics/dist/assets/editor.3a4714e3.js +2 -0
  142. abstra_statics/dist/assets/editor.main.9c635b9a.js +2 -0
  143. abstra_statics/dist/assets/fetch.89fd5b7b.js +2 -0
  144. abstra_statics/dist/assets/{folder.fe6adcd2.js → folder.d8e23009.js} +2 -2
  145. abstra_statics/dist/assets/{freemarker2.8bd96640.js → freemarker2.6698d1ea.js} +2 -2
  146. abstra_statics/dist/assets/{handlebars.e5dd9b19.js → handlebars.a6c42dc0.js} +2 -2
  147. abstra_statics/dist/assets/{html.7bcef916.js → html.493a5410.js} +2 -2
  148. abstra_statics/dist/assets/{htmlMode.ce91c230.js → htmlMode.a28b2fca.js} +2 -2
  149. abstra_statics/dist/assets/{index.fe015dd3.js → index.2af3391c.js} +2 -2
  150. abstra_statics/dist/assets/{index.57a61691.js → index.4176fe88.js} +2 -2
  151. abstra_statics/dist/assets/{index.16664500.js → index.4d20c159.js} +2 -2
  152. abstra_statics/dist/assets/{index.ee218f7a.js → index.5d6b1e62.js} +2 -2
  153. abstra_statics/dist/assets/{index.06cad1f2.js → index.79ce3bf1.js} +2 -2
  154. abstra_statics/dist/assets/{index.161ccee5.js → index.c34a405a.js} +2 -2
  155. abstra_statics/dist/assets/index.fb182bd1.js +2 -0
  156. abstra_statics/dist/assets/{index.005bab7f.js → index.fb49354b.js} +2 -2
  157. abstra_statics/dist/assets/{javascript.4d5c0a37.js → javascript.3a36cf17.js} +2 -2
  158. abstra_statics/dist/assets/{jsonMode.0942a255.js → jsonMode.bead6ac8.js} +2 -2
  159. abstra_statics/dist/assets/{jwt-decode.esm.e1e8e181.js → jwt-decode.esm.d4517a10.js} +8 -8
  160. abstra_statics/dist/assets/{linters.39cc198f.js → linters.2f3141cb.js} +2 -2
  161. abstra_statics/dist/assets/{liquid.884b015e.js → liquid.0c337fae.js} +3 -3
  162. abstra_statics/dist/assets/member.48d6f2cd.js +2 -0
  163. abstra_statics/dist/assets/{metadata.034775c8.js → metadata.c3aed6e1.js} +2 -2
  164. abstra_statics/dist/assets/omniChatStore.c53bcca2.js +8 -0
  165. abstra_statics/dist/assets/{organization.a29009bc.js → organization.928c9bef.js} +2 -2
  166. abstra_statics/dist/assets/player.d3aeafc5.js +2 -0
  167. abstra_statics/dist/assets/{plotly.min.df1e817c.js → plotly.min.7225d3a0.js} +2 -2
  168. abstra_statics/dist/assets/{polling.84bf96db.js → polling.82ee6b45.js} +2 -2
  169. abstra_statics/dist/assets/{project.a9ad86e9.js → project.619b7244.js} +2 -2
  170. abstra_statics/dist/assets/{python.17c791bf.js → python.05764499.js} +3 -3
  171. abstra_statics/dist/assets/{razor.4b071c3b.js → razor.81a45581.js} +2 -2
  172. abstra_statics/dist/assets/record.7f43486c.js +2 -0
  173. abstra_statics/dist/assets/{redirect.cd158e43.js → redirect.f028a879.js} +2 -2
  174. abstra_statics/dist/assets/repository.9534db4b.js +2 -0
  175. abstra_statics/dist/assets/repository.c15239ce.js +2 -0
  176. abstra_statics/dist/assets/router.262190ec.js +2 -0
  177. abstra_statics/dist/assets/router.424f7da9.js +18 -0
  178. abstra_statics/dist/assets/string.0acf5572.js +2 -0
  179. abstra_statics/dist/assets/{tables.928d4c4a.js → tables.1f68ec62.js} +2 -2
  180. abstra_statics/dist/assets/{tasksController.95334db5.js → tasksController.371896de.js} +2 -2
  181. abstra_statics/dist/assets/{toggleHighContrast.67a76682.js → toggleHighContrast.0d0e5662.js} +7 -7
  182. abstra_statics/dist/assets/{tsMode.bd4befb2.js → tsMode.6eadbf06.js} +2 -2
  183. abstra_statics/dist/assets/{typescript.b5722de7.js → typescript.1670e287.js} +2 -2
  184. abstra_statics/dist/assets/url.e8732f77.js +2 -0
  185. abstra_statics/dist/assets/{useCodebaseEvents.47e4fcfe.js → useCodebaseEvents.53dec1f2.js} +2 -2
  186. abstra_statics/dist/assets/useTables.4f034cf8.js +2 -0
  187. abstra_statics/dist/assets/userStore.31024da3.js +2 -0
  188. abstra_statics/dist/assets/uuid.bde15ce7.js +2 -0
  189. abstra_statics/dist/assets/vue-flow-background.818c7852.js +2 -0
  190. abstra_statics/dist/assets/vue-flow-core.1180ec83.js +22 -0
  191. abstra_statics/dist/assets/{vue-quill.esm-bundler.d6a7c536.js → vue-quill.esm-bundler.c4f04985.js} +2 -2
  192. abstra_statics/dist/assets/{workspaceStore.cca10750.js → workspaceStore.6244d03d.js} +2 -2
  193. abstra_statics/dist/assets/{xml.0a62ffce.js → xml.f2867af8.js} +3 -3
  194. abstra_statics/dist/assets/{yaml.1efc213f.js → yaml.5427bb1b.js} +3 -3
  195. abstra_statics/dist/console.html +14 -15
  196. abstra_statics/dist/editor.html +13 -13
  197. abstra_statics/dist/player.html +9 -9
  198. tests/e2e/test_crud_files.py +1 -0
  199. abstra_internals/templates/abstraignore +0 -8
  200. abstra_statics/dist/assets/AbstraButton.vue_vue_type_script_setup_true_lang.3fce0fbb.js +0 -2
  201. abstra_statics/dist/assets/AbstraLogo.vue_vue_type_script_setup_true_lang.4fb1f88a.js +0 -2
  202. abstra_statics/dist/assets/ApiKeys.56b97ced.js +0 -2
  203. abstra_statics/dist/assets/App.bd5ec032.js +0 -2
  204. abstra_statics/dist/assets/App.vue_vue_type_style_index_0_lang.79524273.js +0 -2
  205. abstra_statics/dist/assets/BaseLayout.ac22ef55.js +0 -2
  206. abstra_statics/dist/assets/Billing.2c39d133.js +0 -2
  207. abstra_statics/dist/assets/CloseCircleOutlined.12f63f77.js +0 -2
  208. abstra_statics/dist/assets/ConnectorsView.97a8c63b.js +0 -2
  209. abstra_statics/dist/assets/ConsoleOmniChat.vue_vue_type_script_setup_true_lang.48b29302.js +0 -2
  210. abstra_statics/dist/assets/ContentLayout.072b3790.js +0 -2
  211. abstra_statics/dist/assets/EditorsView.987a7eda.js +0 -2
  212. abstra_statics/dist/assets/EnvVars.c5e84d82.js +0 -2
  213. abstra_statics/dist/assets/ExclamationCircleOutlined.f9a25080.js +0 -2
  214. abstra_statics/dist/assets/Form.4633ab8e.js +0 -2
  215. abstra_statics/dist/assets/Home.a883da25.js +0 -2
  216. abstra_statics/dist/assets/Home.d122da63.js +0 -2
  217. abstra_statics/dist/assets/LoadingContainer.b11f052c.js +0 -2
  218. abstra_statics/dist/assets/Login.84d39327.js +0 -2
  219. abstra_statics/dist/assets/Main.70db8614.js +0 -2
  220. abstra_statics/dist/assets/Navbar.6acd9007.js +0 -2
  221. abstra_statics/dist/assets/NewEditor.15e29eac.js +0 -8
  222. abstra_statics/dist/assets/NewEditor.6dd8f03b.css +0 -1
  223. abstra_statics/dist/assets/OidcLoginCallback.b65a6f9f.js +0 -2
  224. abstra_statics/dist/assets/OidcLogoutCallback.dabd09cf.js +0 -2
  225. abstra_statics/dist/assets/OmniChat.078af315.css +0 -1
  226. abstra_statics/dist/assets/OmniChat.6ed96f8e.js +0 -6
  227. abstra_statics/dist/assets/Organizations.d90dd629.js +0 -2
  228. abstra_statics/dist/assets/PhDownloadSimple.vue.6192bb0e.js +0 -2
  229. abstra_statics/dist/assets/PhPencilSimpleLine.vue.af76e884.js +0 -2
  230. abstra_statics/dist/assets/Project.34c75b7c.js +0 -2
  231. abstra_statics/dist/assets/ProjectLogin.9b8cb3d1.js +0 -2
  232. abstra_statics/dist/assets/Sql.3cdc910a.css +0 -1
  233. abstra_statics/dist/assets/Sql.4e31662a.js +0 -5
  234. abstra_statics/dist/assets/Steps.4c850501.js +0 -2
  235. abstra_statics/dist/assets/TableEditor.1e680eaf.css +0 -1
  236. abstra_statics/dist/assets/TableEditor.e7371677.js +0 -2
  237. abstra_statics/dist/assets/Tables.f2c23e20.js +0 -2
  238. abstra_statics/dist/assets/TablesDiagram.1ec45dd9.css +0 -1
  239. abstra_statics/dist/assets/TablesDiagram.8297ec4b.js +0 -15
  240. abstra_statics/dist/assets/TablesTabs.vue_vue_type_script_setup_true_lang.ec94f9e7.js +0 -2
  241. abstra_statics/dist/assets/View.4c3c38ba.js +0 -2
  242. abstra_statics/dist/assets/WebEditor.4ef39590.js +0 -2
  243. abstra_statics/dist/assets/apiKey.e3aa9e16.js +0 -2
  244. abstra_statics/dist/assets/colorHelpers.e94da383.js +0 -2
  245. abstra_statics/dist/assets/console.86947afb.js +0 -25
  246. abstra_statics/dist/assets/contracts.generated.7508e893.js +0 -2
  247. abstra_statics/dist/assets/dayjs.b4dc8227.js +0 -2
  248. abstra_statics/dist/assets/editor.4f4b7594.js +0 -2
  249. abstra_statics/dist/assets/editor.main.340c0a2d.js +0 -2
  250. abstra_statics/dist/assets/fetch.cfa094a0.js +0 -2
  251. abstra_statics/dist/assets/index.a884598f.js +0 -2
  252. abstra_statics/dist/assets/index.eb8f01b7.js +0 -2
  253. abstra_statics/dist/assets/member.af05829c.js +0 -2
  254. abstra_statics/dist/assets/omniChatStore.19fcae1a.js +0 -8
  255. abstra_statics/dist/assets/player.b9e54e21.js +0 -2
  256. abstra_statics/dist/assets/record.06867f70.js +0 -2
  257. abstra_statics/dist/assets/repository.40cf87c6.js +0 -2
  258. abstra_statics/dist/assets/repository.ecf19994.js +0 -2
  259. abstra_statics/dist/assets/router.8ccbba96.js +0 -10
  260. abstra_statics/dist/assets/router.c00c99d7.js +0 -2
  261. abstra_statics/dist/assets/string.ea3b2597.js +0 -2
  262. abstra_statics/dist/assets/url.62ce842c.js +0 -2
  263. abstra_statics/dist/assets/userStore.51f1e2d0.js +0 -2
  264. abstra_statics/dist/assets/uuid.f4308f15.js +0 -2
  265. abstra_statics/dist/assets/vue-flow-background.03bf6b4b.js +0 -22
  266. {abstra-3.23.11.dist-info → abstra-3.24.0.dist-info}/WHEEL +0 -0
  267. {abstra-3.23.11.dist-info → abstra-3.24.0.dist-info}/entry_points.txt +0 -0
  268. {abstra-3.23.11.dist-info → abstra-3.24.0.dist-info}/top_level.txt +0 -0
@@ -14,6 +14,8 @@ from abstra_internals.utils.file import silent_traverse_code
14
14
  from abstra_internals.utils.packages import get_local_package_version
15
15
  from abstra_internals.utils.paths import get_relative_path
16
16
 
17
+ RETRY_FLAG = "abstra__trigger__retry"
18
+
17
19
 
18
20
  @dataclass
19
21
  class PythonFile:
@@ -73,22 +75,28 @@ class AiController:
73
75
  self,
74
76
  body: AbstraLibApiAiStreamRequest,
75
77
  ):
76
- yield from self.repos.ai.get_ai_messages(
77
- CloudApiCliAiV2StreamRequest(
78
- conversation_id=body.conversation_id,
79
- content=body.content,
80
- context={
81
- **body.context,
82
- "libVersion": str(get_local_package_version()),
83
- "knownIssues": [
84
- i.to_dict() for i in self.repos.linter.find_issues_in_codebase()
85
- ],
86
- },
87
- secret_key=get_tunnel_secret_key(),
88
- tunnel_session_path=get_session_path(),
89
- human_approval=body.human_approval,
78
+ try:
79
+ yield from self.repos.ai.get_ai_messages(
80
+ CloudApiCliAiV2StreamRequest(
81
+ conversation_id=body.conversation_id,
82
+ content=body.content,
83
+ context={
84
+ **body.context,
85
+ "libVersion": str(get_local_package_version()),
86
+ "knownIssues": [
87
+ i.to_dict()
88
+ for i in self.repos.linter.find_issues_in_codebase()
89
+ ],
90
+ },
91
+ secret_key=get_tunnel_secret_key(),
92
+ tunnel_session_path=get_session_path(),
93
+ human_approval=body.human_approval,
94
+ )
90
95
  )
91
- )
96
+ except Exception as e:
97
+ print(f"Error in send_ai_message: {e}")
98
+ yield RETRY_FLAG
99
+ return
92
100
 
93
101
  def get_history(self, limit: int, offset: int):
94
102
  headers = resolve_headers()
@@ -0,0 +1,305 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Dict, Optional
3
+
4
+ import requests
5
+
6
+ from abstra_internals.credentials import get_credentials
7
+ from abstra_internals.environment import CLOUD_API_CLI_URL, REMOTE_GIT_URL, REMOTE_NAME
8
+ from abstra_internals.repositories.git import (
9
+ AheadBehindInfo,
10
+ GitCommit,
11
+ GitStatusResponse,
12
+ RemoteGitStatus,
13
+ create_git_repository,
14
+ )
15
+ from abstra_internals.settings import Settings
16
+
17
+
18
+ class EmailProvider(ABC):
19
+ """Interface that requires a get_email method."""
20
+
21
+ @abstractmethod
22
+ def get_email(self) -> str:
23
+ pass
24
+
25
+
26
+ class DefaultEmailProvider(EmailProvider):
27
+ """Concrete implementation with a default email."""
28
+
29
+ def get_email(self) -> str:
30
+ return "abstra@mail.com"
31
+
32
+
33
+ class GitController:
34
+ def __init__(self, email_provider: EmailProvider = DefaultEmailProvider()):
35
+ self.git_repository = create_git_repository(Settings.root_path)
36
+ self.email_provider = email_provider
37
+ self.git_email = email_provider.get_email()
38
+
39
+ def _ensure_authentication(self) -> bool:
40
+ try:
41
+ if self.git_email is None:
42
+ self.git_email = self.email_provider.get_email()
43
+
44
+ if self.git_email is None:
45
+ print("No email available for git configuration")
46
+ return False
47
+
48
+ self.git_repository.configure_git_user(
49
+ fallback_email=self.git_email,
50
+ fallback_name=self.git_email.split("@")[0],
51
+ )
52
+
53
+ credentials = get_credentials()
54
+ if not credentials:
55
+ return False
56
+
57
+ if self.git_repository.has_remote(REMOTE_NAME):
58
+ if not self.git_repository.set_remote_url(REMOTE_NAME, REMOTE_GIT_URL):
59
+ return False
60
+ else:
61
+ if not self.git_repository.add_remote(REMOTE_NAME, REMOTE_GIT_URL):
62
+ return False
63
+
64
+ config_key = f"http.{REMOTE_GIT_URL}.extraHeader"
65
+ config_value = f"Api-Authorization: Bearer {credentials}"
66
+
67
+ if self.git_repository.get_git_config(config_key) == config_value:
68
+ return True
69
+
70
+ return self.git_repository.set_git_config(config_key, config_value)
71
+
72
+ except Exception as e:
73
+ print(f"Authentication setup failed: {e}")
74
+ return False
75
+
76
+ def _fetch_remote_status(self, branch: str = "main") -> RemoteGitStatus:
77
+ try:
78
+ credentials = get_credentials()
79
+ if not credentials:
80
+ return RemoteGitStatus(
81
+ success=False, message="No authentication credentials available"
82
+ )
83
+
84
+ api_url = f"{CLOUD_API_CLI_URL}/git/status"
85
+ headers = {"Api-Authorization": f"Bearer {credentials}"}
86
+ params = {"branch": branch}
87
+
88
+ response = requests.get(api_url, headers=headers, params=params, timeout=10)
89
+
90
+ if response.status_code == 200:
91
+ try:
92
+ data = response.json()
93
+
94
+ if not isinstance(data, dict):
95
+ return RemoteGitStatus(
96
+ success=False,
97
+ message=f"Unexpected response format. Expected dict, got {type(data).__name__}",
98
+ )
99
+
100
+ return RemoteGitStatus(
101
+ success=data.get("success", True),
102
+ remote_commit=data.get("remote_commit"),
103
+ branch=data.get("branch", branch),
104
+ has_commits=data.get("has_commits", False),
105
+ available_branches=data.get("available_branches", [branch]),
106
+ message=data.get("message"),
107
+ ahead_behind=None,
108
+ )
109
+ except ValueError as json_error:
110
+ return RemoteGitStatus(
111
+ success=False, message=f"Invalid JSON response: {json_error}"
112
+ )
113
+ else:
114
+ response_text = (
115
+ response.text[:200] if response.text else "No response body"
116
+ )
117
+ return RemoteGitStatus(
118
+ success=False,
119
+ message=f"API call failed with status {response.status_code}: {response_text}",
120
+ )
121
+
122
+ except Exception as e:
123
+ return RemoteGitStatus(
124
+ success=False, message=f"Error fetching remote status: {str(e)}"
125
+ )
126
+
127
+ def get_status(self) -> Dict[str, Any]:
128
+ self._ensure_authentication()
129
+
130
+ status = self.git_repository.get_repository_status()
131
+
132
+ remote_status = None
133
+
134
+ if status.available:
135
+ remote_status = self._fetch_remote_status()
136
+
137
+ if (
138
+ remote_status.success
139
+ and remote_status.remote_commit
140
+ and status.last_commit
141
+ and remote_status.remote_commit != status.last_commit.hash
142
+ ):
143
+ try:
144
+ ahead, behind = self.git_repository.get_ahead_behind_count(
145
+ status.last_commit.hash, remote_status.remote_commit
146
+ )
147
+ remote_status.ahead_behind = AheadBehindInfo(
148
+ ahead=ahead, behind=behind
149
+ )
150
+ except Exception as e:
151
+ print(f"Failed to calculate ahead/behind: {e}")
152
+
153
+ remote_status.has_conflicts = self.git_repository.check_merge_conflicts(
154
+ remote_status.remote_commit
155
+ )
156
+
157
+ if remote_status.ahead_behind:
158
+ remote_status.has_remote_changes = (
159
+ remote_status.ahead_behind.behind > 0
160
+ )
161
+ else:
162
+ remote_status.has_remote_changes = (
163
+ remote_status.remote_commit != status.last_commit.hash
164
+ )
165
+
166
+ status_response = GitStatusResponse(
167
+ available=status.available,
168
+ branch=status.branch,
169
+ branches=status.branches,
170
+ last_commit=status.last_commit,
171
+ has_changes=status.has_changes,
172
+ changed_files=status.changed_files,
173
+ changed_files_with_status=status.changed_files_with_status,
174
+ remote_status=remote_status,
175
+ )
176
+
177
+ return status_response.to_dict()
178
+
179
+ def checkout_branch(self, branch_name: str) -> Dict[str, Any]:
180
+ success = self.git_repository.checkout_branch(branch_name)
181
+
182
+ message = (
183
+ f"Switched to branch '{branch_name}'"
184
+ if success
185
+ else f"Failed to switch to branch '{branch_name}'"
186
+ )
187
+
188
+ return {"success": success, "message": message}
189
+
190
+ def checkout_commit(self, commit_hash: str) -> Dict[str, Any]:
191
+ success = self.git_repository.checkout_commit(commit_hash)
192
+
193
+ message = (
194
+ f"Switched to commit '{commit_hash[:8]}'"
195
+ if success
196
+ else f"Failed to switch to commit '{commit_hash[:8]}'"
197
+ )
198
+
199
+ return {"success": success, "message": message}
200
+
201
+ def pull_changes(
202
+ self, strategy: str, allow_unrelated: bool, conflict_resolution: Optional[str]
203
+ ) -> Dict[str, Any]:
204
+ self._ensure_authentication()
205
+
206
+ success = self.git_repository.pull_changes(
207
+ strategy=strategy,
208
+ allow_unrelated=allow_unrelated,
209
+ conflict_resolution=conflict_resolution,
210
+ )
211
+
212
+ message = "Successfully pulled changes" if success else "Failed to pull changes"
213
+
214
+ return {"success": success, "message": message}
215
+
216
+ def commit_changes(self, message: str) -> Dict[str, Any]:
217
+ commit_message = message.strip()
218
+ if not commit_message:
219
+ return {"success": False, "message": "Commit message cannot be empty"}
220
+
221
+ success = self.git_repository.commit_changes(commit_message)
222
+
223
+ message = (
224
+ f"Successfully committed changes: {commit_message}"
225
+ if success
226
+ else "Failed to commit changes"
227
+ )
228
+
229
+ return {"success": success, "message": message}
230
+
231
+ def stash_changes(self, message: str = "WIP") -> Dict[str, Any]:
232
+ success = self.git_repository.stash_changes(message)
233
+
234
+ message = (
235
+ "Successfully stashed changes" if success else "Failed to stash changes"
236
+ )
237
+
238
+ return {"success": success, "message": message}
239
+
240
+ def get_commit_history(
241
+ self, limit: int = 10, offset: int = 0, branch: Optional[str] = None
242
+ ) -> Dict[str, Any]:
243
+ commits = self.git_repository.get_commit_history(
244
+ limit=limit, offset=offset, branch=branch
245
+ )
246
+
247
+ return {
248
+ "commits": [self._format_commit(commit) for commit in commits],
249
+ "hasMore": len(commits) == limit,
250
+ }
251
+
252
+ def push_and_deploy(self, branch: str = "main") -> Dict[str, Any]:
253
+ self._ensure_authentication()
254
+
255
+ success = self.git_repository.push_and_deploy(branch)
256
+
257
+ message = (
258
+ f"Successfully deployed branch '{branch}' to Abstra"
259
+ if success
260
+ else f"Failed to deploy branch '{branch}' to Abstra. Push operation failed."
261
+ )
262
+
263
+ return {"success": success, "message": message}
264
+
265
+ def get_remotes(self) -> Dict[str, Any]:
266
+ remotes = self.git_repository.get_remotes()
267
+
268
+ return {"remotes": remotes, "hasAbstraRemote": REMOTE_NAME in remotes}
269
+
270
+ def revert_commit(self, commit_hash: str) -> Dict[str, Any]:
271
+ if not commit_hash.strip():
272
+ return {"success": False, "message": "Commit hash is required"}
273
+
274
+ commits = self.git_repository.get_commit_history(limit=200)
275
+ commit_to_revert = next(
276
+ (c for c in commits if c.hash.startswith(commit_hash)), None
277
+ )
278
+
279
+ if not commit_to_revert:
280
+ return {"success": False, "message": f"Commit {commit_hash[:8]} not found"}
281
+
282
+ try:
283
+ success = self.git_repository.revert_commit(commit_hash)
284
+
285
+ message = (
286
+ f"Successfully restored content from commit: {commit_to_revert.message}. A new commit was created with the content from that version."
287
+ if success
288
+ else f"Failed to restore content from commit {commit_hash[:8]}. Make sure there are no uncommitted changes and the commit exists."
289
+ )
290
+
291
+ return {"success": success, "message": message}
292
+
293
+ except Exception as e:
294
+ return {
295
+ "success": False,
296
+ "message": f"Error restoring content from commit {commit_hash[:8]}: {str(e)}",
297
+ }
298
+
299
+ def _format_commit(self, commit: GitCommit) -> Dict[str, str]:
300
+ return {
301
+ "hash": commit.hash,
302
+ "message": commit.message,
303
+ "author": commit.author,
304
+ "date": commit.date,
305
+ }
@@ -26,7 +26,7 @@ from abstra_internals.entities.execution_context import (
26
26
  Response,
27
27
  ScriptContext,
28
28
  )
29
- from abstra_internals.interface.cli.deploy import deploy
29
+ from abstra_internals.interface.cli.deploy import deploy_without_git
30
30
  from abstra_internals.logger import AbstraLogger
31
31
  from abstra_internals.repositories.email import EmailRepository
32
32
  from abstra_internals.repositories.execution import ExecutionFilter, ExecutionRepository
@@ -54,7 +54,6 @@ from abstra_internals.services.fs import FileSystemService
54
54
  from abstra_internals.services.requirements import RequirementsRepository
55
55
  from abstra_internals.settings import Settings
56
56
  from abstra_internals.templates import (
57
- ensure_abstraignore,
58
57
  ensure_dotenv,
59
58
  ensure_gitignore,
60
59
  new_form_code,
@@ -126,7 +125,6 @@ class MainController:
126
125
  repositories.project.initialize_or_migrate()
127
126
 
128
127
  RequirementsRepository.ensure("abstra")
129
- ensure_abstraignore(Settings.root_path)
130
128
  ensure_gitignore(Settings.root_path)
131
129
  ensure_dotenv(Settings.root_path)
132
130
 
@@ -143,7 +141,7 @@ class MainController:
143
141
  self.execution_logs_repository = repositories.execution_logs
144
142
  self.linter_repository = repositories.linter
145
143
 
146
- def deploy(self):
144
+ def deploy_without_git(self):
147
145
  self.linter_repository.update_checks()
148
146
  issues = self.linter_repository.get_blocking_checks()
149
147
 
@@ -152,7 +150,7 @@ class MainController:
152
150
  "Please fix all linter issues before deploying your project."
153
151
  )
154
152
 
155
- deploy()
153
+ deploy_without_git()
156
154
 
157
155
  def reset_repositories(self):
158
156
  self.execution_repository.clear()
@@ -541,7 +539,7 @@ class MainController:
541
539
  ```
542
540
 
543
541
  Note:
544
- - Respects .gitignore and .gitignore patterns when use_ignore=True
542
+ - Respects .gitignore patterns when use_ignore=True
545
543
  - Image mode supports: .png, .jpg, .jpeg, .gif, .svg, .webp, .jfif, .pjp, .pjpeg
546
544
  - Module mode uses Python's pkgutil.iter_modules for discovery
547
545
  - Paths are always relative to the project root directory
@@ -1432,6 +1430,12 @@ class MainController:
1432
1430
  return {"logged": False, "reason": "NO_API_TOKEN"}
1433
1431
  return get_api_key_info(headers)
1434
1432
 
1433
+ def get_email(self):
1434
+ login = self.get_login()
1435
+ if login.get("logged"):
1436
+ return login.get("info", {}).get("email")
1437
+ return None
1438
+
1435
1439
  def create_login(self, token):
1436
1440
  set_credentials(token)
1437
1441
  return self.get_login()
@@ -24,11 +24,11 @@ class Button:
24
24
 
25
25
  Unlike automatic navigation buttons (NextButton/BackButton), custom Button widgets give you full control over widget behavior within a page and can be used to implement complex conditional logic based on user choices.
26
26
 
27
- ## How Button State Works
27
+ ## How Button State Works ##
28
28
 
29
29
  When a user clicks a button, the button's key is set to `True` in the form state. You can then check this state using `state.get("button_key")` to determine which button was pressed and conditionally render different widgets or forms.
30
30
 
31
- ## Usage Pattern
31
+ ## Usage Pattern ##
32
32
 
33
33
  Buttons are optionally returned from your Page function (a function that returns a list of widgets). You have two options:
34
34
 
@@ -110,3 +110,9 @@ SERVER_UUID = lambda: os.getenv(__SERVER_UUID_ENV__) # noqa: E731
110
110
 
111
111
  def set_SERVER_UUID(server_uuid: str):
112
112
  os.environ[__SERVER_UUID_ENV__] = server_uuid
113
+
114
+
115
+ # GIT
116
+ FORCE_GIT_CLIENT = os.getenv("ABSTRA_FORCE_GIT_CLIENT")
117
+ REMOTE_GIT_URL = f"{CLOUD_API_CLI_URL}/git/repo.git"
118
+ REMOTE_NAME = "abstra"
@@ -28,7 +28,7 @@ def _upload_file(url: str, file_path: pathlib.Path):
28
28
  requests.put(url=url, data=f.read())
29
29
 
30
30
 
31
- def deploy():
31
+ def deploy_without_git():
32
32
  headers = resolve_headers()
33
33
  if not headers:
34
34
  print(