keboola-cli 0.63.4__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.
Files changed (306) hide show
  1. keboola_agent_cli/__init__.py +34 -0
  2. keboola_agent_cli/__main__.py +5 -0
  3. keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js +2 -0
  4. keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js.map +1 -0
  5. keboola_agent_cli/_ui_dist/assets/architecture-7EHR7CIX-hNCijx_H.js +1 -0
  6. keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js +37 -0
  7. keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js.map +1 -0
  8. keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js +2 -0
  9. keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js.map +1 -0
  10. keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js +133 -0
  11. keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js.map +1 -0
  12. keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js +11 -0
  13. keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js.map +1 -0
  14. keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js +2 -0
  15. keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js.map +1 -0
  16. keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js +2 -0
  17. keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js.map +1 -0
  18. keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js +63 -0
  19. keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js.map +1 -0
  20. keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js +2 -0
  21. keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js.map +1 -0
  22. keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js +2 -0
  23. keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js.map +1 -0
  24. keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js +3 -0
  25. keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js.map +1 -0
  26. keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js +207 -0
  27. keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js.map +1 -0
  28. keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js +232 -0
  29. keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js.map +1 -0
  30. keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js +2 -0
  31. keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js.map +1 -0
  32. keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js +124 -0
  33. keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js.map +1 -0
  34. keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js +16 -0
  35. keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js.map +1 -0
  36. keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js +2 -0
  37. keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js.map +1 -0
  38. keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js +2 -0
  39. keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js.map +1 -0
  40. keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js +160 -0
  41. keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js.map +1 -0
  42. keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js +2 -0
  43. keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js.map +1 -0
  44. keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js +71 -0
  45. keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js.map +1 -0
  46. keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js +2 -0
  47. keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js.map +1 -0
  48. keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js +2 -0
  49. keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js.map +1 -0
  50. keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js +2 -0
  51. keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js.map +1 -0
  52. keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js +2 -0
  53. keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js.map +1 -0
  54. keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js +322 -0
  55. keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js.map +1 -0
  56. keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js +5 -0
  57. keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js.map +1 -0
  58. keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js +2 -0
  59. keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js.map +1 -0
  60. keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js +2 -0
  61. keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js.map +1 -0
  62. keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js +44 -0
  63. keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js.map +1 -0
  64. keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js +11 -0
  65. keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js.map +1 -0
  66. keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js +4 -0
  67. keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js.map +1 -0
  68. keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js +25 -0
  69. keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js.map +1 -0
  70. keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js +25 -0
  71. keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js.map +1 -0
  72. keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js +2 -0
  73. keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js.map +1 -0
  74. keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js +86 -0
  75. keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js.map +1 -0
  76. keboola_agent_cli/_ui_dist/assets/eventmodeling-FCH6USID-BrJMIks8.js +1 -0
  77. keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js +163 -0
  78. keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js.map +1 -0
  79. keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js +293 -0
  80. keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js.map +1 -0
  81. keboola_agent_cli/_ui_dist/assets/gitGraph-WXDBUCRP-COacYjo-.js +1 -0
  82. keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js +107 -0
  83. keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js.map +1 -0
  84. keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js +2 -0
  85. keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js.map +1 -0
  86. keboola_agent_cli/_ui_dist/assets/index-CMq50kkV.css +1 -0
  87. keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js +118 -0
  88. keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js.map +1 -0
  89. keboola_agent_cli/_ui_dist/assets/info-J43DQDTF-DdCTRIzU.js +1 -0
  90. keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js +3 -0
  91. keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js.map +1 -0
  92. keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js +2 -0
  93. keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js.map +1 -0
  94. keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js +71 -0
  95. keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js.map +1 -0
  96. keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js +140 -0
  97. keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js.map +1 -0
  98. keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js +90 -0
  99. keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js.map +1 -0
  100. keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js +258 -0
  101. keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js.map +1 -0
  102. keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js +2 -0
  103. keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js.map +1 -0
  104. keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js +2 -0
  105. keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js.map +1 -0
  106. keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js +5 -0
  107. keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js.map +1 -0
  108. keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js +97 -0
  109. keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js.map +1 -0
  110. keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js +2 -0
  111. keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js.map +1 -0
  112. keboola_agent_cli/_ui_dist/assets/packet-YPE3B663-DLiiw_B2.js +1 -0
  113. keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js +2 -0
  114. keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js.map +1 -0
  115. keboola_agent_cli/_ui_dist/assets/pie-LRSECV5Y-CRoO8G1g.js +1 -0
  116. keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js +31 -0
  117. keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js.map +1 -0
  118. keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js +8 -0
  119. keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js.map +1 -0
  120. keboola_agent_cli/_ui_dist/assets/radar-GUYGQ44K-DAlLVJHm.js +1 -0
  121. keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js +85 -0
  122. keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js.map +1 -0
  123. keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js +2 -0
  124. keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js.map +1 -0
  125. keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js +41 -0
  126. keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js.map +1 -0
  127. keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js +163 -0
  128. keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js.map +1 -0
  129. keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js +2 -0
  130. keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js.map +1 -0
  131. keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js +2 -0
  132. keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js.map +1 -0
  133. keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js +2 -0
  134. keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js.map +1 -0
  135. keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js +121 -0
  136. keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js.map +1 -0
  137. keboola_agent_cli/_ui_dist/assets/treeView-BLDUP644-DbLYl23-.js +1 -0
  138. keboola_agent_cli/_ui_dist/assets/treemap-LRROVOQU-Bp0eGlOt.js +1 -0
  139. keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js +35 -0
  140. keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js.map +1 -0
  141. keboola_agent_cli/_ui_dist/assets/wardley-L42UT6IY-D4yH4jqS.js +1 -0
  142. keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js +79 -0
  143. keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js.map +1 -0
  144. keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js +8 -0
  145. keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js.map +1 -0
  146. keboola_agent_cli/_ui_dist/index.html +50 -0
  147. keboola_agent_cli/ai_client.py +83 -0
  148. keboola_agent_cli/auto_update.py +550 -0
  149. keboola_agent_cli/changelog.py +1198 -0
  150. keboola_agent_cli/cli.py +448 -0
  151. keboola_agent_cli/client.py +3422 -0
  152. keboola_agent_cli/commands/__init__.py +0 -0
  153. keboola_agent_cli/commands/_data_app_git.py +343 -0
  154. keboola_agent_cli/commands/_helpers.py +377 -0
  155. keboola_agent_cli/commands/_metadata_input.py +49 -0
  156. keboola_agent_cli/commands/_semantic_layer_crud.py +632 -0
  157. keboola_agent_cli/commands/_semantic_layer_helpers.py +44 -0
  158. keboola_agent_cli/commands/_semantic_layer_reference_data.py +247 -0
  159. keboola_agent_cli/commands/agent.py +968 -0
  160. keboola_agent_cli/commands/branch.py +423 -0
  161. keboola_agent_cli/commands/changelog.py +168 -0
  162. keboola_agent_cli/commands/component.py +216 -0
  163. keboola_agent_cli/commands/config.py +2442 -0
  164. keboola_agent_cli/commands/context.py +1481 -0
  165. keboola_agent_cli/commands/data_app.py +1279 -0
  166. keboola_agent_cli/commands/dev_portal.py +584 -0
  167. keboola_agent_cli/commands/doctor.py +37 -0
  168. keboola_agent_cli/commands/encrypt.py +145 -0
  169. keboola_agent_cli/commands/feature.py +311 -0
  170. keboola_agent_cli/commands/flow.py +948 -0
  171. keboola_agent_cli/commands/http_client.py +157 -0
  172. keboola_agent_cli/commands/init.py +279 -0
  173. keboola_agent_cli/commands/job.py +661 -0
  174. keboola_agent_cli/commands/kai.py +301 -0
  175. keboola_agent_cli/commands/lineage.py +1464 -0
  176. keboola_agent_cli/commands/org.py +292 -0
  177. keboola_agent_cli/commands/permissions.py +360 -0
  178. keboola_agent_cli/commands/project.py +1192 -0
  179. keboola_agent_cli/commands/repl.py +243 -0
  180. keboola_agent_cli/commands/schedule.py +340 -0
  181. keboola_agent_cli/commands/search.py +178 -0
  182. keboola_agent_cli/commands/semantic_layer.py +939 -0
  183. keboola_agent_cli/commands/serve.py +272 -0
  184. keboola_agent_cli/commands/sharing.py +340 -0
  185. keboola_agent_cli/commands/storage.py +2630 -0
  186. keboola_agent_cli/commands/stream.py +266 -0
  187. keboola_agent_cli/commands/sync.py +1277 -0
  188. keboola_agent_cli/commands/tool.py +206 -0
  189. keboola_agent_cli/commands/version.py +186 -0
  190. keboola_agent_cli/commands/workspace.py +635 -0
  191. keboola_agent_cli/config_store.py +582 -0
  192. keboola_agent_cli/constants.py +528 -0
  193. keboola_agent_cli/data_science_client.py +342 -0
  194. keboola_agent_cli/dev_portal_client.py +323 -0
  195. keboola_agent_cli/errors.py +248 -0
  196. keboola_agent_cli/http_base.py +315 -0
  197. keboola_agent_cli/json_utils.py +126 -0
  198. keboola_agent_cli/lib.py +536 -0
  199. keboola_agent_cli/manage_client.py +324 -0
  200. keboola_agent_cli/metastore_client.py +214 -0
  201. keboola_agent_cli/models.py +427 -0
  202. keboola_agent_cli/output.py +1084 -0
  203. keboola_agent_cli/permissions.py +469 -0
  204. keboola_agent_cli/py.typed +3 -0
  205. keboola_agent_cli/result_models.py +271 -0
  206. keboola_agent_cli/server/__init__.py +34 -0
  207. keboola_agent_cli/server/agent_runner.py +1289 -0
  208. keboola_agent_cli/server/agents_store.py +325 -0
  209. keboola_agent_cli/server/app.py +764 -0
  210. keboola_agent_cli/server/auth.py +117 -0
  211. keboola_agent_cli/server/dependencies.py +149 -0
  212. keboola_agent_cli/server/pricing.py +303 -0
  213. keboola_agent_cli/server/routers/__init__.py +1 -0
  214. keboola_agent_cli/server/routers/agents.py +616 -0
  215. keboola_agent_cli/server/routers/ai_chat.py +129 -0
  216. keboola_agent_cli/server/routers/branches.py +133 -0
  217. keboola_agent_cli/server/routers/components.py +48 -0
  218. keboola_agent_cli/server/routers/configs.py +507 -0
  219. keboola_agent_cli/server/routers/data_apps.py +384 -0
  220. keboola_agent_cli/server/routers/dev_portal.py +67 -0
  221. keboola_agent_cli/server/routers/encrypt.py +35 -0
  222. keboola_agent_cli/server/routers/feature.py +179 -0
  223. keboola_agent_cli/server/routers/flows.py +204 -0
  224. keboola_agent_cli/server/routers/health.py +53 -0
  225. keboola_agent_cli/server/routers/jobs.py +175 -0
  226. keboola_agent_cli/server/routers/kai.py +80 -0
  227. keboola_agent_cli/server/routers/lineage.py +226 -0
  228. keboola_agent_cli/server/routers/mcp.py +70 -0
  229. keboola_agent_cli/server/routers/members.py +170 -0
  230. keboola_agent_cli/server/routers/org.py +96 -0
  231. keboola_agent_cli/server/routers/projects.py +106 -0
  232. keboola_agent_cli/server/routers/schedules.py +54 -0
  233. keboola_agent_cli/server/routers/search.py +30 -0
  234. keboola_agent_cli/server/routers/semantic_layer.py +650 -0
  235. keboola_agent_cli/server/routers/sharing.py +86 -0
  236. keboola_agent_cli/server/routers/storage.py +574 -0
  237. keboola_agent_cli/server/routers/stream.py +100 -0
  238. keboola_agent_cli/server/routers/workspaces.py +302 -0
  239. keboola_agent_cli/server/run_broadcaster.py +329 -0
  240. keboola_agent_cli/server/sse.py +25 -0
  241. keboola_agent_cli/services/__init__.py +0 -0
  242. keboola_agent_cli/services/_encryption.py +217 -0
  243. keboola_agent_cli/services/_semantic_layer_cascade.py +147 -0
  244. keboola_agent_cli/services/_semantic_layer_crud.py +382 -0
  245. keboola_agent_cli/services/_semantic_layer_internals.py +1078 -0
  246. keboola_agent_cli/services/_semantic_layer_lookup.py +181 -0
  247. keboola_agent_cli/services/_semantic_layer_reference_data.py +217 -0
  248. keboola_agent_cli/services/_sync_bindings.py +456 -0
  249. keboola_agent_cli/services/_sync_branch.py +191 -0
  250. keboola_agent_cli/services/_sync_bulk.py +228 -0
  251. keboola_agent_cli/services/_sync_clone.py +163 -0
  252. keboola_agent_cli/services/_sync_models.py +97 -0
  253. keboola_agent_cli/services/_sync_push_ops.py +369 -0
  254. keboola_agent_cli/services/_sync_storage.py +376 -0
  255. keboola_agent_cli/services/_sync_writeback.py +167 -0
  256. keboola_agent_cli/services/agent_service.py +458 -0
  257. keboola_agent_cli/services/base.py +175 -0
  258. keboola_agent_cli/services/branch_service.py +588 -0
  259. keboola_agent_cli/services/component_service.py +694 -0
  260. keboola_agent_cli/services/config_service.py +2099 -0
  261. keboola_agent_cli/services/data_app_git_service.py +224 -0
  262. keboola_agent_cli/services/data_app_service.py +2082 -0
  263. keboola_agent_cli/services/deep_lineage_service.py +1322 -0
  264. keboola_agent_cli/services/dev_portal_service.py +345 -0
  265. keboola_agent_cli/services/doctor_service.py +445 -0
  266. keboola_agent_cli/services/encrypt_service.py +87 -0
  267. keboola_agent_cli/services/feature_service.py +268 -0
  268. keboola_agent_cli/services/flow_service.py +769 -0
  269. keboola_agent_cli/services/flow_validation.py +188 -0
  270. keboola_agent_cli/services/http_forwarder_service.py +236 -0
  271. keboola_agent_cli/services/job_idempotency_store.py +285 -0
  272. keboola_agent_cli/services/job_service.py +797 -0
  273. keboola_agent_cli/services/kai_service.py +367 -0
  274. keboola_agent_cli/services/lineage_service.py +274 -0
  275. keboola_agent_cli/services/mcp_service.py +1498 -0
  276. keboola_agent_cli/services/mcp_transport.py +259 -0
  277. keboola_agent_cli/services/member_service.py +593 -0
  278. keboola_agent_cli/services/org_service.py +619 -0
  279. keboola_agent_cli/services/project_service.py +947 -0
  280. keboola_agent_cli/services/repo_validate_service.py +767 -0
  281. keboola_agent_cli/services/schedule_service.py +731 -0
  282. keboola_agent_cli/services/search_service.py +331 -0
  283. keboola_agent_cli/services/semantic_layer_service.py +1497 -0
  284. keboola_agent_cli/services/sharing_service.py +307 -0
  285. keboola_agent_cli/services/storage_service.py +2524 -0
  286. keboola_agent_cli/services/stream_service.py +395 -0
  287. keboola_agent_cli/services/sync_service.py +2244 -0
  288. keboola_agent_cli/services/variables_service.py +447 -0
  289. keboola_agent_cli/services/version_service.py +1038 -0
  290. keboola_agent_cli/services/workspace_service.py +1103 -0
  291. keboola_agent_cli/stream_client.py +217 -0
  292. keboola_agent_cli/sync/__init__.py +1 -0
  293. keboola_agent_cli/sync/branch_mapping.py +174 -0
  294. keboola_agent_cli/sync/clone.py +211 -0
  295. keboola_agent_cli/sync/code_extraction.py +655 -0
  296. keboola_agent_cli/sync/config_format.py +290 -0
  297. keboola_agent_cli/sync/diff_engine.py +566 -0
  298. keboola_agent_cli/sync/git_utils.py +93 -0
  299. keboola_agent_cli/sync/manifest.py +162 -0
  300. keboola_agent_cli/sync/naming.py +90 -0
  301. keboola_agent_cli/sync/secrets.py +62 -0
  302. keboola_agent_cli/sync/sql_split.py +134 -0
  303. keboola_cli-0.63.4.dist-info/METADATA +308 -0
  304. keboola_cli-0.63.4.dist-info/RECORD +306 -0
  305. keboola_cli-0.63.4.dist-info/WHEEL +4 -0
  306. keboola_cli-0.63.4.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,635 @@
1
+ """Workspace commands - create, list, detail, delete, load, query, and from-transformation.
2
+
3
+ Thin CLI layer: parses arguments, calls WorkspaceService, formats output.
4
+ No business logic belongs here.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ import typer
10
+ from rich.markup import escape
11
+
12
+ from ..config_store import ConfigStore
13
+ from ..constants import QUERY_RESULTS_DEFAULT_LIMIT
14
+ from ..errors import ConfigError, ErrorCode, KeboolaApiError
15
+ from ..output import format_query_results, format_workspaces_table
16
+ from ._helpers import (
17
+ check_cli_permission,
18
+ emit_project_warnings,
19
+ get_formatter,
20
+ get_service,
21
+ map_error_to_exit_code,
22
+ resolve_branch,
23
+ )
24
+
25
+ workspace_app = typer.Typer(help="Workspace lifecycle for SQL debugging")
26
+
27
+
28
+ @workspace_app.callback(invoke_without_command=True)
29
+ def _workspace_permission_check(ctx: typer.Context) -> None:
30
+ check_cli_permission(ctx, "workspace")
31
+
32
+
33
+ @workspace_app.command("create")
34
+ def workspace_create(
35
+ ctx: typer.Context,
36
+ project: str = typer.Option(
37
+ ...,
38
+ "--project",
39
+ help="Project alias to create the workspace in",
40
+ ),
41
+ name: str = typer.Option(
42
+ "",
43
+ "--name",
44
+ help="Name for the workspace (shown in Keboola UI)",
45
+ ),
46
+ backend: str | None = typer.Option(
47
+ None,
48
+ "--backend",
49
+ help="Workspace backend (auto-detected from project if omitted)",
50
+ ),
51
+ read_only: bool = typer.Option(
52
+ True,
53
+ "--read-only/--no-read-only",
54
+ help="Whether the workspace has read-only storage access",
55
+ ),
56
+ ui: bool = typer.Option(
57
+ False,
58
+ "--ui",
59
+ help="Create via Queue job (slower ~15s, visible in Keboola UI)",
60
+ ),
61
+ ) -> None:
62
+ """Create a new workspace.
63
+
64
+ Default: fast headless mode via Storage API (~1s).
65
+ With --ui: creates via Queue job (~15s), visible in Keboola UI Workspaces tab.
66
+ """
67
+ formatter = get_formatter(ctx)
68
+ service = get_service(ctx, "workspace_service")
69
+
70
+ try:
71
+ result = service.create_workspace(
72
+ alias=project, name=name, backend=backend, read_only=read_only, ui_mode=ui
73
+ )
74
+ formatter.output(
75
+ result,
76
+ lambda c, d: (
77
+ c.print(f"[bold green]Success:[/bold green] {d['message']}"),
78
+ c.print(f"\n[bold]Workspace ID:[/bold] {d['workspace_id']}"),
79
+ c.print(f"[bold]Name:[/bold] {d.get('name', '')}"),
80
+ c.print(f"[bold]Host:[/bold] {d['host']}"),
81
+ c.print(f"[bold]Schema:[/bold] {d['schema']}"),
82
+ c.print(f"[bold]User:[/bold] {d['user']}"),
83
+ c.print(
84
+ f"[bold yellow]Private key:[/bold yellow]\n{d['private_key']}"
85
+ if d.get("private_key")
86
+ else f"[bold yellow]Password:[/bold yellow] {d['password']}"
87
+ ),
88
+ c.print(
89
+ "\n[bold yellow]Warning:[/bold yellow] Save the private key now -- it cannot be retrieved later!"
90
+ if d.get("private_key")
91
+ else "\n[bold yellow]Warning:[/bold yellow] Save the password now -- it cannot be retrieved later!"
92
+ ),
93
+ ),
94
+ )
95
+ except KeboolaApiError as exc:
96
+ exit_code = map_error_to_exit_code(exc)
97
+ formatter.error(
98
+ message=exc.message,
99
+ error_code=exc.error_code,
100
+ retryable=exc.retryable,
101
+ )
102
+ raise typer.Exit(code=exit_code) from None
103
+ except ConfigError as exc:
104
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
105
+ raise typer.Exit(code=5) from None
106
+
107
+
108
+ @workspace_app.command("list")
109
+ def workspace_list(
110
+ ctx: typer.Context,
111
+ project: list[str] | None = typer.Option(
112
+ None,
113
+ "--project",
114
+ help="Project alias to query (can be repeated for multiple projects)",
115
+ ),
116
+ orphaned: bool = typer.Option(
117
+ False,
118
+ "--orphaned",
119
+ help="Show only orphaned workspaces (keboola.sandboxes config missing)",
120
+ ),
121
+ branch: int | None = typer.Option(
122
+ None,
123
+ "--branch",
124
+ help="Dev branch ID. Read-only command -- ignores the alias's active branch "
125
+ "by default (mirrors `storage buckets`); pass --branch to opt in. "
126
+ "Requires exactly one --project.",
127
+ ),
128
+ qs_compatible: bool = typer.Option(
129
+ False,
130
+ "--qs-compatible",
131
+ help="Show only workspaces whose loginType is known to work with the Query "
132
+ "Service AND that are read-only -- the canonical shape for a data-app.",
133
+ ),
134
+ ) -> None:
135
+ """List workspaces from connected projects.
136
+
137
+ Branch handling: this is a read command and follows the same pattern as
138
+ `storage buckets` / `config list` -- when an alias is pinned to a dev
139
+ branch via `branch use`, the production endpoint is used (with a visible
140
+ `Info: ...` banner) instead of silently scoping the listing to the
141
+ pinned branch. Pass `--branch ID` to query a specific dev branch.
142
+
143
+ Each workspace entry exposes `login_type`, `read_only` and
144
+ `qs_compatible` so data-app developers can pick a Query-Service-compatible
145
+ workspace without firing a probe query (closes #304).
146
+ """
147
+ formatter = get_formatter(ctx)
148
+ service = get_service(ctx, "workspace_service")
149
+ config_store: ConfigStore = ctx.obj["config_store"]
150
+
151
+ if branch is not None and (not project or len(project) != 1):
152
+ formatter.error(
153
+ message="--branch requires exactly one --project (branch ID is per-project)",
154
+ error_code=ErrorCode.INVALID_ARGUMENT,
155
+ )
156
+ raise typer.Exit(code=2)
157
+
158
+ effective_branch: int | None = branch
159
+ if branch is None and project and len(project) == 1:
160
+ _, effective_branch = resolve_branch(
161
+ config_store, formatter, project[0], None, ignore_active_branch=True
162
+ )
163
+
164
+ try:
165
+ result = service.list_workspaces(
166
+ aliases=project,
167
+ orphaned_only=orphaned,
168
+ branch_id=effective_branch,
169
+ qs_compatible_only=qs_compatible,
170
+ )
171
+ except KeboolaApiError as exc:
172
+ exit_code = map_error_to_exit_code(exc)
173
+ formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
174
+ raise typer.Exit(code=exit_code) from None
175
+ except ConfigError as exc:
176
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
177
+ raise typer.Exit(code=5) from None
178
+
179
+ if formatter.json_mode:
180
+ formatter.output(result)
181
+ else:
182
+ format_workspaces_table(formatter.console, result)
183
+ emit_project_warnings(formatter, result)
184
+
185
+
186
+ @workspace_app.command("detail")
187
+ def workspace_detail(
188
+ ctx: typer.Context,
189
+ project: str = typer.Option(
190
+ ...,
191
+ "--project",
192
+ help="Project alias",
193
+ ),
194
+ workspace_id: int = typer.Option(
195
+ ...,
196
+ "--workspace-id",
197
+ help="Workspace ID",
198
+ ),
199
+ branch: int | None = typer.Option(
200
+ None,
201
+ "--branch",
202
+ help="Dev branch ID. Read-only command -- ignores the alias's active branch "
203
+ "by default (mirrors `storage bucket-detail`); pass --branch to opt in.",
204
+ ),
205
+ ) -> None:
206
+ """Show workspace details (password NOT included).
207
+
208
+ Includes `login_type`, `read_only` and `qs_compatible` so callers can
209
+ verify a workspace is Query-Service-compatible before issuing a query
210
+ (closes #304).
211
+ """
212
+ formatter = get_formatter(ctx)
213
+ service = get_service(ctx, "workspace_service")
214
+ config_store: ConfigStore = ctx.obj["config_store"]
215
+
216
+ _, effective_branch = resolve_branch(
217
+ config_store, formatter, project, branch, ignore_active_branch=True
218
+ )
219
+
220
+ try:
221
+ result = service.get_workspace(
222
+ alias=project, workspace_id=workspace_id, branch_id=effective_branch
223
+ )
224
+ formatter.output(
225
+ result,
226
+ lambda c, d: (
227
+ c.print(f"\n[bold]Workspace ID:[/bold] {d['workspace_id']}"),
228
+ c.print(f"[bold]Project:[/bold] {d['project_alias']}"),
229
+ c.print(f"[bold]Backend:[/bold] {d['backend']}"),
230
+ c.print(f"[bold]Host:[/bold] {d['host']}"),
231
+ c.print(f"[bold]Warehouse:[/bold] {d.get('warehouse', '')}"),
232
+ c.print(f"[bold]Database:[/bold] {d.get('database', '')}"),
233
+ c.print(f"[bold]Schema:[/bold] {d['schema']}"),
234
+ c.print(f"[bold]User:[/bold] {d['user']}"),
235
+ c.print(
236
+ f"[bold]Login type:[/bold] {d.get('login_type', '') or '[dim](unknown)[/dim]'}"
237
+ ),
238
+ c.print(f"[bold]Read-only:[/bold] {'yes' if d.get('read_only') else 'no'}"),
239
+ c.print(
240
+ f"[bold]Query Service compatible:[/bold] "
241
+ f"{'[green]yes[/green]' if d.get('qs_compatible') else '[yellow]no (loginType not on the confirmed whitelist; query may still work, try `kbagent workspace query`)[/yellow]'}"
242
+ ),
243
+ c.print(f"[bold]Created:[/bold] {d.get('created', '')}"),
244
+ ),
245
+ )
246
+ except KeboolaApiError as exc:
247
+ exit_code = map_error_to_exit_code(exc)
248
+ formatter.error(
249
+ message=exc.message,
250
+ error_code=exc.error_code,
251
+ retryable=exc.retryable,
252
+ )
253
+ raise typer.Exit(code=exit_code) from None
254
+ except ConfigError as exc:
255
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
256
+ raise typer.Exit(code=5) from None
257
+
258
+
259
+ @workspace_app.command("delete")
260
+ def workspace_delete(
261
+ ctx: typer.Context,
262
+ project: str = typer.Option(
263
+ ...,
264
+ "--project",
265
+ help="Project alias",
266
+ ),
267
+ workspace_id: int = typer.Option(
268
+ ...,
269
+ "--workspace-id",
270
+ help="Workspace ID to delete",
271
+ ),
272
+ ) -> None:
273
+ """Delete a workspace."""
274
+ formatter = get_formatter(ctx)
275
+ service = get_service(ctx, "workspace_service")
276
+
277
+ try:
278
+ result = service.delete_workspace(alias=project, workspace_id=workspace_id)
279
+ formatter.output(
280
+ result,
281
+ lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
282
+ )
283
+ except KeboolaApiError as exc:
284
+ exit_code = map_error_to_exit_code(exc)
285
+ formatter.error(
286
+ message=exc.message,
287
+ error_code=exc.error_code,
288
+ retryable=exc.retryable,
289
+ )
290
+ raise typer.Exit(code=exit_code) from None
291
+ except ConfigError as exc:
292
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
293
+ raise typer.Exit(code=5) from None
294
+
295
+
296
+ @workspace_app.command("password")
297
+ def workspace_password(
298
+ ctx: typer.Context,
299
+ project: str = typer.Option(
300
+ ...,
301
+ "--project",
302
+ help="Project alias",
303
+ ),
304
+ workspace_id: int = typer.Option(
305
+ ...,
306
+ "--workspace-id",
307
+ help="Workspace ID",
308
+ ),
309
+ ) -> None:
310
+ """Reset workspace password and show the new one."""
311
+ formatter = get_formatter(ctx)
312
+ service = get_service(ctx, "workspace_service")
313
+
314
+ try:
315
+ result = service.reset_password(alias=project, workspace_id=workspace_id)
316
+ formatter.output(
317
+ result,
318
+ lambda c, d: (
319
+ c.print(f"[bold green]Success:[/bold green] {d['message']}"),
320
+ c.print(f"\n[bold yellow]New Password:[/bold yellow] {d['password']}"),
321
+ ),
322
+ )
323
+ except KeboolaApiError as exc:
324
+ exit_code = map_error_to_exit_code(exc)
325
+ formatter.error(
326
+ message=exc.message,
327
+ error_code=exc.error_code,
328
+ retryable=exc.retryable,
329
+ )
330
+ raise typer.Exit(code=exit_code) from None
331
+ except ConfigError as exc:
332
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
333
+ raise typer.Exit(code=5) from None
334
+
335
+
336
+ @workspace_app.command("load")
337
+ def workspace_load(
338
+ ctx: typer.Context,
339
+ project: str = typer.Option(
340
+ ...,
341
+ "--project",
342
+ help="Project alias",
343
+ ),
344
+ workspace_id: int = typer.Option(
345
+ ...,
346
+ "--workspace-id",
347
+ help="Workspace ID",
348
+ ),
349
+ tables: list[str] = typer.Option(
350
+ ...,
351
+ "--tables",
352
+ help="Table ID to load (can be repeated, e.g. in.c-bucket.table-name)",
353
+ ),
354
+ preserve: bool = typer.Option(
355
+ False,
356
+ "--preserve",
357
+ help="Keep existing tables in the workspace (default: clear before loading)",
358
+ ),
359
+ ) -> None:
360
+ """Load tables into a workspace.
361
+
362
+ Waits for the async load job to complete.
363
+ """
364
+ formatter = get_formatter(ctx)
365
+ service = get_service(ctx, "workspace_service")
366
+
367
+ try:
368
+ result = service.load_tables(
369
+ alias=project, workspace_id=workspace_id, tables=tables, preserve=preserve
370
+ )
371
+ formatter.output(
372
+ result,
373
+ lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
374
+ )
375
+ except KeboolaApiError as exc:
376
+ exit_code = map_error_to_exit_code(exc)
377
+ formatter.error(
378
+ message=exc.message,
379
+ error_code=exc.error_code,
380
+ retryable=exc.retryable,
381
+ )
382
+ raise typer.Exit(code=exit_code) from None
383
+ except ConfigError as exc:
384
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
385
+ raise typer.Exit(code=5) from None
386
+
387
+
388
+ @workspace_app.command("query")
389
+ def workspace_query(
390
+ ctx: typer.Context,
391
+ project: str = typer.Option(
392
+ ...,
393
+ "--project",
394
+ help="Project alias",
395
+ ),
396
+ workspace_id: int = typer.Option(
397
+ ...,
398
+ "--workspace-id",
399
+ help="Workspace ID",
400
+ ),
401
+ sql: str | None = typer.Option(
402
+ None,
403
+ "--sql",
404
+ help="SQL statement to execute",
405
+ ),
406
+ file: Path | None = typer.Option(
407
+ None,
408
+ "--file",
409
+ help="Path to a .sql file to execute",
410
+ exists=True,
411
+ readable=True,
412
+ ),
413
+ transactional: bool = typer.Option(
414
+ False,
415
+ "--transactional",
416
+ help="Wrap query in a transaction",
417
+ ),
418
+ full: bool = typer.Option(
419
+ False,
420
+ "--full",
421
+ help="Fetch the complete result set via CSV export (slower). "
422
+ "Default fetches a fast inline page capped by --limit.",
423
+ ),
424
+ limit: int = typer.Option(
425
+ QUERY_RESULTS_DEFAULT_LIMIT,
426
+ "--limit",
427
+ min=1,
428
+ help="Max rows to fetch via the fast inline path (ignored with --full).",
429
+ ),
430
+ ) -> None:
431
+ """Execute SQL query in a workspace via Query Service.
432
+
433
+ Provide SQL via --sql or --file (exactly one required).
434
+
435
+ By default kbagent reads results inline (fast). For a result set larger than
436
+ --limit, pass --full to export the complete CSV instead.
437
+ """
438
+ formatter = get_formatter(ctx)
439
+ service = get_service(ctx, "workspace_service")
440
+
441
+ # Validate: exactly one of --sql or --file
442
+ if sql and file:
443
+ formatter.error(
444
+ message="Specify either --sql or --file, not both.",
445
+ error_code=ErrorCode.USAGE_ERROR,
446
+ )
447
+ raise typer.Exit(code=2)
448
+ if not sql and not file:
449
+ formatter.error(
450
+ message="Specify either --sql or --file.",
451
+ error_code=ErrorCode.USAGE_ERROR,
452
+ )
453
+ raise typer.Exit(code=2)
454
+
455
+ # Read SQL from file if needed.
456
+ # After the guards above: either sql is truthy, or (not sql and file is non-None).
457
+ if sql:
458
+ effective_sql = sql
459
+ else:
460
+ assert file is not None # guaranteed: guard above exits if both sql and file absent
461
+ effective_sql = file.read_text(encoding="utf-8")
462
+
463
+ try:
464
+ result = service.execute_query(
465
+ alias=project,
466
+ workspace_id=workspace_id,
467
+ sql=effective_sql,
468
+ transactional=transactional,
469
+ full=full,
470
+ limit=limit,
471
+ )
472
+ if formatter.json_mode:
473
+ formatter.output(result)
474
+ else:
475
+ format_query_results(formatter.console, result)
476
+ except KeboolaApiError as exc:
477
+ exit_code = map_error_to_exit_code(exc)
478
+ formatter.error(
479
+ message=exc.message,
480
+ error_code=exc.error_code,
481
+ retryable=exc.retryable,
482
+ )
483
+ raise typer.Exit(code=exit_code) from None
484
+ except ConfigError as exc:
485
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
486
+ raise typer.Exit(code=5) from None
487
+
488
+
489
+ @workspace_app.command("gc")
490
+ def workspace_gc(
491
+ ctx: typer.Context,
492
+ project: list[str] | None = typer.Option(
493
+ None,
494
+ "--project",
495
+ help="Project alias to query (can be repeated). None = all projects.",
496
+ ),
497
+ dry_run: bool = typer.Option(
498
+ False,
499
+ "--dry-run",
500
+ help="List orphaned workspaces without deleting them",
501
+ ),
502
+ yes: bool = typer.Option(
503
+ False,
504
+ "--yes",
505
+ "-y",
506
+ help="Skip confirmation prompt",
507
+ ),
508
+ ) -> None:
509
+ """Garbage-collect orphaned workspaces.
510
+
511
+ An orphaned workspace is one backed by keboola.sandboxes whose
512
+ sandbox config no longer exists. Running gc deletes those workspaces
513
+ (and any lingering sandbox configs). Use --dry-run to preview first.
514
+ """
515
+ formatter = get_formatter(ctx)
516
+ service = get_service(ctx, "workspace_service")
517
+
518
+ if (
519
+ not dry_run
520
+ and not yes
521
+ and not formatter.json_mode
522
+ and not typer.confirm("Delete all orphaned workspaces in the selected project(s)?")
523
+ ):
524
+ formatter.console.print("Aborted.")
525
+ raise typer.Exit(code=0)
526
+
527
+ try:
528
+ result = service.gc_workspaces(aliases=project, dry_run=dry_run)
529
+ except KeboolaApiError as exc:
530
+ exit_code = map_error_to_exit_code(exc)
531
+ formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
532
+ raise typer.Exit(code=exit_code) from None
533
+ except ConfigError as exc:
534
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
535
+ raise typer.Exit(code=5) from None
536
+
537
+ if formatter.json_mode:
538
+ formatter.output(result)
539
+ else:
540
+ formatter.console.print(result.get("message", ""))
541
+ if dry_run:
542
+ would_delete = result.get("would_delete", [])
543
+ for ws in would_delete:
544
+ formatter.console.print(
545
+ f" [dim]would delete[/dim] workspace {ws['id']} "
546
+ f"([cyan]{escape(ws.get('name', ''))}[/cyan]) in '{escape(ws['project_alias'])}'"
547
+ )
548
+ else:
549
+ for ws in result.get("deleted", []):
550
+ formatter.console.print(
551
+ f" [green]deleted[/green] workspace {ws['id']} in '{escape(ws['project_alias'])}'"
552
+ )
553
+ for err in result.get("errors", []):
554
+ formatter.console.print(
555
+ f" [red]error[/red] workspace {err.get('workspace_id', '?')}: {escape(err.get('error', ''))}"
556
+ )
557
+
558
+
559
+ @workspace_app.command("from-transformation")
560
+ def workspace_from_transformation(
561
+ ctx: typer.Context,
562
+ project: str = typer.Option(
563
+ ...,
564
+ "--project",
565
+ help="Project alias",
566
+ ),
567
+ component_id: str = typer.Option(
568
+ ...,
569
+ "--component-id",
570
+ help="Transformation component ID (e.g. keboola.snowflake-transformation)",
571
+ ),
572
+ config_id: str = typer.Option(
573
+ ...,
574
+ "--config-id",
575
+ help="Configuration ID",
576
+ ),
577
+ row_id: str | None = typer.Option(
578
+ None,
579
+ "--row-id",
580
+ help="Optional row ID for row-based transformations",
581
+ ),
582
+ backend: str | None = typer.Option(
583
+ None,
584
+ "--backend",
585
+ help="Workspace backend (auto-detected from project if omitted)",
586
+ ),
587
+ ) -> None:
588
+ """Create a workspace from a transformation config.
589
+
590
+ Reads the transformation, creates a config-tied workspace, and loads
591
+ all input tables. Returns credentials ready for SQL debugging.
592
+ """
593
+ formatter = get_formatter(ctx)
594
+ service = get_service(ctx, "workspace_service")
595
+
596
+ try:
597
+ result = service.create_from_transformation(
598
+ alias=project,
599
+ component_id=component_id,
600
+ config_id=config_id,
601
+ row_id=row_id,
602
+ backend=backend,
603
+ )
604
+ formatter.output(
605
+ result,
606
+ lambda c, d: (
607
+ c.print(f"[bold green]Success:[/bold green] {d['message']}"),
608
+ c.print(f"\n[bold]Workspace ID:[/bold] {d['workspace_id']}"),
609
+ c.print(f"[bold]Host:[/bold] {d['host']}"),
610
+ c.print(f"[bold]Schema:[/bold] {d['schema']}"),
611
+ c.print(f"[bold]User:[/bold] {d['user']}"),
612
+ c.print(
613
+ f"[bold yellow]Private key:[/bold yellow]\n{d['private_key']}"
614
+ if d.get("private_key")
615
+ else f"[bold yellow]Password:[/bold yellow] {d['password']}"
616
+ ),
617
+ c.print(f"[bold]Tables loaded:[/bold] {', '.join(d.get('tables_loaded', []))}"),
618
+ c.print(
619
+ "\n[bold yellow]Warning:[/bold yellow] Save the private key now -- it cannot be retrieved later!"
620
+ if d.get("private_key")
621
+ else "\n[bold yellow]Warning:[/bold yellow] Save the password now -- it cannot be retrieved later!"
622
+ ),
623
+ ),
624
+ )
625
+ except KeboolaApiError as exc:
626
+ exit_code = map_error_to_exit_code(exc)
627
+ formatter.error(
628
+ message=exc.message,
629
+ error_code=exc.error_code,
630
+ retryable=exc.retryable,
631
+ )
632
+ raise typer.Exit(code=exit_code) from None
633
+ except ConfigError as exc:
634
+ formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
635
+ raise typer.Exit(code=5) from None