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,324 @@
1
+ """Keboola Manage API client with retry, timeouts, and token masking.
2
+
3
+ This module communicates with the Keboola Manage API for organization-level
4
+ operations like listing projects and creating Storage API tokens.
5
+ Uses a different auth header (X-KBC-ManageApiToken) than the Storage API client.
6
+
7
+ Inherits shared retry/error logic from BaseHttpClient.
8
+ """
9
+
10
+ from typing import Any
11
+ from urllib.parse import quote
12
+
13
+ from .constants import DEFAULT_TIMEOUT
14
+ from .http_base import BaseHttpClient
15
+
16
+
17
+ class ManageClient(BaseHttpClient):
18
+ """HTTP client for the Keboola Manage API.
19
+
20
+ Provides methods to list organization projects and create Storage API
21
+ tokens, with built-in retry logic (exponential backoff for 429/5xx),
22
+ timeouts, and automatic token masking in error messages.
23
+
24
+ Inherits _do_request() and _raise_api_error() from BaseHttpClient.
25
+ """
26
+
27
+ def __init__(self, stack_url: str, manage_token: str) -> None:
28
+ self._stack_url = stack_url.rstrip("/")
29
+ headers = {
30
+ "X-KBC-ManageApiToken": manage_token,
31
+ }
32
+ super().__init__(
33
+ base_url=self._stack_url,
34
+ token=manage_token,
35
+ headers=headers,
36
+ timeout=DEFAULT_TIMEOUT,
37
+ )
38
+
39
+ def __enter__(self) -> "ManageClient":
40
+ return self
41
+
42
+ def __exit__(self, *args: Any) -> None:
43
+ self.close()
44
+
45
+ def verify_token(self) -> dict[str, Any]:
46
+ """Verify the manage token and return token/user metadata.
47
+
48
+ Calls GET /manage/tokens/verify to retrieve information about
49
+ the manage token owner, including user name and email.
50
+
51
+ Returns:
52
+ Dict with token info including 'user' block (id, name, email).
53
+
54
+ Raises:
55
+ KeboolaApiError: On API errors.
56
+ """
57
+ response = self._do_request("GET", "/manage/tokens/verify")
58
+ return response.json()
59
+
60
+ def get_project(self, project_id: int) -> dict[str, Any]:
61
+ """Get project details by ID.
62
+
63
+ Works with Personal Access Tokens (PAT) for projects where the
64
+ token owner is a member -- does NOT require organization admin.
65
+
66
+ Args:
67
+ project_id: The project ID.
68
+
69
+ Returns:
70
+ Project dict with at least 'id', 'name', and 'organization' fields.
71
+
72
+ Raises:
73
+ KeboolaApiError: On API errors (e.g. 403 if not a member).
74
+ """
75
+ response = self._do_request("GET", f"/manage/projects/{project_id}")
76
+ return response.json()
77
+
78
+ def get_organization(self, org_id: int) -> dict[str, Any]:
79
+ """Get organization details by ID.
80
+
81
+ Used to resolve the organization name from its ID (e.g. during
82
+ `org setup`, where only the org_id is known up front).
83
+
84
+ Args:
85
+ org_id: The organization ID.
86
+
87
+ Returns:
88
+ Organization dict with at least 'id' and 'name' fields.
89
+
90
+ Raises:
91
+ KeboolaApiError: On API errors (e.g. 403 if not an org member).
92
+ """
93
+ response = self._do_request("GET", f"/manage/organizations/{org_id}")
94
+ return response.json()
95
+
96
+ def list_organization_projects(self, org_id: int) -> list[dict[str, Any]]:
97
+ """List all projects in an organization.
98
+
99
+ Args:
100
+ org_id: The organization ID.
101
+
102
+ Returns:
103
+ List of project dicts with at least 'id' and 'name' fields.
104
+
105
+ Raises:
106
+ KeboolaApiError: On API errors.
107
+ """
108
+ response = self._do_request("GET", f"/manage/organizations/{org_id}/projects")
109
+ return response.json()
110
+
111
+ def create_project_token(
112
+ self,
113
+ project_id: int,
114
+ description: str,
115
+ can_manage_buckets: bool = True,
116
+ can_read_all_file_uploads: bool = True,
117
+ can_read_all_project_events: bool = True,
118
+ can_manage_dev_branches: bool = True,
119
+ can_manage_tokens: bool = True,
120
+ expires_in: int | None = None,
121
+ ) -> dict[str, Any]:
122
+ """Create a new Storage API token for a project.
123
+
124
+ Args:
125
+ project_id: The project ID.
126
+ description: Token description.
127
+ can_manage_buckets: Whether the token can manage buckets.
128
+ can_read_all_file_uploads: Whether the token can read all file uploads.
129
+ can_read_all_project_events: Whether the token can read all project events.
130
+ can_manage_dev_branches: Whether the token can manage development branches.
131
+ can_manage_tokens: Whether the token can create/manage other tokens.
132
+ Required for Scheduler (Orchestrator) to create run tokens.
133
+ expires_in: Token lifetime in seconds. None means the token never expires.
134
+
135
+ Returns:
136
+ Token dict including the 'token' field (shown only once).
137
+
138
+ Raises:
139
+ KeboolaApiError: On API errors.
140
+ """
141
+ payload: dict[str, Any] = {
142
+ "description": description,
143
+ "canManageBuckets": can_manage_buckets,
144
+ "canReadAllFileUploads": can_read_all_file_uploads,
145
+ "canReadAllProjectEvents": can_read_all_project_events,
146
+ "canManageDevBranches": can_manage_dev_branches,
147
+ "canManageTokens": can_manage_tokens,
148
+ }
149
+ if expires_in is not None:
150
+ payload["expiresIn"] = expires_in
151
+ response = self._do_request("POST", f"/manage/projects/{project_id}/tokens", json=payload)
152
+ return response.json()
153
+
154
+ # ------------------------------------------------------------------
155
+ # Project members & invitations (verified 2026-05-01 against the
156
+ # us-east4.gcp.keboola.com Manage API; see plan-of-record §"Verifications").
157
+ # ------------------------------------------------------------------
158
+
159
+ def create_project_invitation(
160
+ self,
161
+ project_id: int,
162
+ email: str,
163
+ role: str,
164
+ reason: str | None = None,
165
+ ) -> dict[str, Any]:
166
+ """Send an invitation email to add ``email`` as a project member.
167
+
168
+ Returns the invitation object on success (HTTP 201). On HTTP 400 with
169
+ the error message ``"This user has already been invited..."`` or
170
+ ``"...is already a member..."`` the caller should treat the call as a
171
+ no-op rather than an error -- the higher layer encodes that policy.
172
+
173
+ Args:
174
+ project_id: Numeric project ID.
175
+ email: Email of the user to invite.
176
+ role: One of ``admin``, ``guest``, ``readOnly``, ``share``.
177
+ reason: Optional human-readable note attached to the invitation.
178
+
179
+ Returns:
180
+ Invitation dict: ``{id, created, expires, reason, role, user, creator}``.
181
+ """
182
+ payload: dict[str, Any] = {"email": email, "role": role}
183
+ if reason:
184
+ payload["reason"] = reason
185
+ response = self._do_request(
186
+ "POST", f"/manage/projects/{project_id}/invitations", json=payload
187
+ )
188
+ return response.json()
189
+
190
+ def list_project_invitations(self, project_id: int) -> list[dict[str, Any]]:
191
+ """List pending (not-yet-accepted) invitations for a project.
192
+
193
+ Returns a plain list. Each item has shape
194
+ ``{id, created, expires, reason, role, user: {id, name, email}, creator: {...}}``.
195
+ """
196
+ response = self._do_request("GET", f"/manage/projects/{project_id}/invitations")
197
+ return response.json()
198
+
199
+ def cancel_project_invitation(self, project_id: int, invitation_id: int) -> None:
200
+ """Cancel a pending invitation by ID. Returns 204 No Content on success."""
201
+ self._do_request("DELETE", f"/manage/projects/{project_id}/invitations/{invitation_id}")
202
+
203
+ def list_project_members(self, project_id: int) -> list[dict[str, Any]]:
204
+ """List active project members.
205
+
206
+ Returns a plain list. Each user dict carries the project role at the
207
+ top level (``role`` field) -- not nested under a ``user`` key.
208
+ """
209
+ response = self._do_request("GET", f"/manage/projects/{project_id}/users")
210
+ return response.json()
211
+
212
+ def remove_project_member(self, project_id: int, user_id: int) -> None:
213
+ """Remove a member from a project. Returns 204 No Content on success."""
214
+ self._do_request("DELETE", f"/manage/projects/{project_id}/users/{user_id}")
215
+
216
+ def update_project_member_role(
217
+ self, project_id: int, user_id: int, role: str
218
+ ) -> dict[str, Any]:
219
+ """Change an existing member's role.
220
+
221
+ The Manage API uses **PATCH** here -- ``PUT`` returns 404 even on real
222
+ members. Returns the updated user dict on success (HTTP 200).
223
+ """
224
+ response = self._do_request(
225
+ "PATCH",
226
+ f"/manage/projects/{project_id}/users/{user_id}",
227
+ json={"role": role},
228
+ )
229
+ return response.json()
230
+
231
+ # ------------------------------------------------------------------
232
+ # Feature flags (super-admin manage token required).
233
+ #
234
+ # The stack-wide catalogue lives at GET /manage/features. Features
235
+ # assigned to a single project/user are NOT a dedicated endpoint --
236
+ # they are read from the ``features`` array on the project/user object.
237
+ # Endpoint + payload shapes mirror the curl recipes verified by the
238
+ # platform team: the POST body is ``{"feature": "<name>"}`` and the
239
+ # DELETE targets ``.../features/{name}``.
240
+ # ------------------------------------------------------------------
241
+
242
+ def list_features(self) -> list[dict[str, Any]]:
243
+ """List all features defined on the stack (the catalogue).
244
+
245
+ Returns:
246
+ List of feature dicts. Field set is not contractually fixed;
247
+ callers should treat unknown keys as opaque. ``name`` is the
248
+ stable identifier used by the add/remove endpoints.
249
+
250
+ Raises:
251
+ KeboolaApiError: On API errors (e.g. 403 without super admin).
252
+ """
253
+ response = self._do_request("GET", "/manage/features")
254
+ return response.json()
255
+
256
+ def add_project_feature(self, project_id: int, feature: str) -> dict[str, Any]:
257
+ """Enable a feature on a project.
258
+
259
+ Args:
260
+ project_id: The numeric project ID.
261
+ feature: The feature name (as listed by :meth:`list_features`).
262
+
263
+ Returns:
264
+ The API response body (project or feature payload, stack-dependent).
265
+
266
+ Raises:
267
+ KeboolaApiError: On API errors.
268
+ """
269
+ response = self._do_request(
270
+ "POST", f"/manage/projects/{project_id}/features", json={"feature": feature}
271
+ )
272
+ # Most stacks return 201 with a JSON body, but some return 204 No
273
+ # Content; guard against JSONDecodeError on an empty body.
274
+ return response.json() if response.content else {}
275
+
276
+ def remove_project_feature(self, project_id: int, feature: str) -> None:
277
+ """Disable a feature on a project. Returns 204 No Content on success."""
278
+ self._do_request(
279
+ "DELETE",
280
+ f"/manage/projects/{project_id}/features/{quote(feature, safe='')}",
281
+ )
282
+
283
+ def get_user(self, email: str) -> dict[str, Any]:
284
+ """Get a user by email, including the ``features`` array.
285
+
286
+ Args:
287
+ email: The user's email address (the public-facing key).
288
+
289
+ Returns:
290
+ User dict with at least ``id``, ``email`` and ``features``.
291
+
292
+ Raises:
293
+ KeboolaApiError: On API errors (e.g. 404 if the user is unknown).
294
+ """
295
+ response = self._do_request("GET", f"/manage/users/{quote(email, safe='@')}")
296
+ return response.json()
297
+
298
+ def add_user_feature(self, email: str, feature: str) -> dict[str, Any]:
299
+ """Enable a feature on a user.
300
+
301
+ Args:
302
+ email: The user's email address.
303
+ feature: The feature name (as listed by :meth:`list_features`).
304
+
305
+ Returns:
306
+ The API response body (user or feature payload, stack-dependent).
307
+
308
+ Raises:
309
+ KeboolaApiError: On API errors.
310
+ """
311
+ response = self._do_request(
312
+ "POST",
313
+ f"/manage/users/{quote(email, safe='@')}/features",
314
+ json={"feature": feature},
315
+ )
316
+ # See add_project_feature: tolerate a 204 No Content body.
317
+ return response.json() if response.content else {}
318
+
319
+ def remove_user_feature(self, email: str, feature: str) -> None:
320
+ """Disable a feature on a user. Returns 204 No Content on success."""
321
+ self._do_request(
322
+ "DELETE",
323
+ f"/manage/users/{quote(email, safe='@')}/features/{quote(feature, safe='')}",
324
+ )
@@ -0,0 +1,214 @@
1
+ """Keboola Metastore API client for the semantic layer.
2
+
3
+ Communicates with the Keboola Metastore at ``metastore.{stack-suffix}`` (derived
4
+ from the Storage API stack URL by replacing ``connection.`` with ``metastore.``
5
+ in the hostname). Same ``X-StorageApi-Token`` credential as the Storage API.
6
+
7
+ Inherits shared retry, timeout, and error handling from :class:`BaseHttpClient`.
8
+
9
+ Verified contract (probed 2026-05-14 against e2e-1143):
10
+
11
+ - ``GET /api/v1/repository/{type}`` → 200 with body ``{"data": [item, ...]}``.
12
+ - ``POST /api/v1/repository/{type}`` → 201 with body ``{"data": {type, id,
13
+ attributes, meta}}``. Envelope: ``{name, data, branch, schemaVersion, scope}``.
14
+ - ``DELETE /api/v1/repository/{type}/{id}`` → 204 empty body. Missing ID → 404
15
+ with the standard error envelope.
16
+ - Duplicate ``name`` on POST → **409 Conflict** with message ``"Object with
17
+ this name already exists in this project"`` (after go-monorepo PR #513).
18
+ Legacy metastore deployments still return **500** with exception ``"Failed
19
+ to create meta object"``. We normalize both into
20
+ :data:`ErrorCode.ALREADY_EXISTS`.
21
+ - Error envelope has top-level ``error``, ``code``, ``exception``, ``status``,
22
+ ``context.path``, and an ``errors[]`` list for 422 validation failures.
23
+ """
24
+
25
+ import logging
26
+ from typing import Any, Literal
27
+
28
+ from .errors import ErrorCode, KeboolaApiError
29
+ from .http_base import BaseHttpClient
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ SemanticType = Literal[
35
+ "semantic-model",
36
+ "semantic-dataset",
37
+ "semantic-metric",
38
+ "semantic-relationship",
39
+ "semantic-constraint",
40
+ "semantic-glossary",
41
+ "semantic-reference-data",
42
+ ]
43
+
44
+
45
+ SEMANTIC_TYPES: tuple[str, ...] = (
46
+ "semantic-model",
47
+ "semantic-dataset",
48
+ "semantic-metric",
49
+ "semantic-relationship",
50
+ "semantic-constraint",
51
+ "semantic-glossary",
52
+ "semantic-reference-data",
53
+ )
54
+
55
+
56
+ # Envelope fields kept constant across every POST (per metastore contract).
57
+ _ENVELOPE_BRANCH = "main"
58
+ _ENVELOPE_SCHEMA_VERSION = "1.0.0"
59
+ _ENVELOPE_SCOPE = "project"
60
+
61
+
62
+ class MetastoreClient(BaseHttpClient):
63
+ """HTTP client for the Keboola Metastore (semantic layer repository).
64
+
65
+ Provides minimal verb-level primitives that the
66
+ :class:`SemanticLayerService` composes into business operations. This
67
+ client deliberately stays thin: no business logic, no model resolution,
68
+ no in-memory caching. All such concerns live in the service layer.
69
+ """
70
+
71
+ def __init__(self, stack_url: str, token: str) -> None:
72
+ self._stack_url = stack_url.rstrip("/")
73
+ base_url = self._derive_service_url(self._stack_url, "metastore")
74
+ headers = {
75
+ "X-StorageApi-Token": token,
76
+ }
77
+ super().__init__(base_url=base_url, token=token, headers=headers)
78
+
79
+ def __enter__(self) -> "MetastoreClient":
80
+ return self
81
+
82
+ def __exit__(self, *args: Any) -> None:
83
+ self.close()
84
+
85
+ # ------------------------------------------------------------------
86
+ # Primitive verb methods
87
+ # ------------------------------------------------------------------
88
+
89
+ def list_items(
90
+ self,
91
+ item_type: SemanticType,
92
+ model_uuid: str | None = None,
93
+ ) -> list[dict[str, Any]]:
94
+ """List all items of ``item_type`` and (optionally) filter by model.
95
+
96
+ Returns the **raw item shape**: ``{"type", "id", "attributes",
97
+ "meta"}``. Callers typically only want ``attributes`` plus ``id``;
98
+ we keep the full shape so audit fields stay reachable.
99
+
100
+ Filtering: client-side on ``attributes.modelUUID == model_uuid``. The
101
+ server's ``?modelId=`` query param works in the probe but sl-builder
102
+ reports it as historically unreliable — defensive filter wins.
103
+ """
104
+ response = self._do_request("GET", f"/api/v1/repository/{item_type}")
105
+ body = response.json()
106
+ items: list[dict[str, Any]] = body.get("data", []) if isinstance(body, dict) else []
107
+ if model_uuid is None:
108
+ return items
109
+ return [i for i in items if (i.get("attributes") or {}).get("modelUUID") == model_uuid]
110
+
111
+ def get_item(self, item_type: SemanticType, item_id: str) -> dict[str, Any]:
112
+ """Fetch a single item by its UUID.
113
+
114
+ Raises :class:`KeboolaApiError` with ``error_code=NOT_FOUND`` on 404.
115
+ """
116
+ response = self._do_request("GET", f"/api/v1/repository/{item_type}/{item_id}")
117
+ body = response.json()
118
+ return body.get("data", body) if isinstance(body, dict) else body
119
+
120
+ def post_item(
121
+ self,
122
+ item_type: SemanticType,
123
+ name: str,
124
+ data: dict[str, Any],
125
+ ) -> dict[str, Any]:
126
+ """Create an item. Returns the server's stored representation.
127
+
128
+ ``data`` is the inner ``attributes`` payload (including ``modelUUID``
129
+ for non-model types). The outer envelope is added here.
130
+
131
+ Normalizes the duplicate-name conflict into a clean
132
+ :data:`ErrorCode.ALREADY_EXISTS`, accepting both shapes the metastore
133
+ has used: HTTP 409 (post go-monorepo PR #513) and HTTP 500 with
134
+ ``"Failed to create meta object"`` (legacy / pre-fix deployments).
135
+ """
136
+ envelope = {
137
+ "name": name,
138
+ "data": data,
139
+ "branch": _ENVELOPE_BRANCH,
140
+ "schemaVersion": _ENVELOPE_SCHEMA_VERSION,
141
+ "scope": _ENVELOPE_SCOPE,
142
+ }
143
+ try:
144
+ response = self._do_request(
145
+ "POST",
146
+ f"/api/v1/repository/{item_type}",
147
+ json=envelope,
148
+ )
149
+ except KeboolaApiError as exc:
150
+ # Surface a clean ALREADY_EXISTS so command-layer error mapping
151
+ # lands it on the right exit code. Two server-side shapes are
152
+ # accepted because the metastore fix rolls out per-stack:
153
+ # * post go-monorepo PR #513: 409 Conflict (any 409 on this
154
+ # endpoint is by construction a uniqueness violation -- see
155
+ # services/metastore/api/handlers/repository_errors.go).
156
+ # * legacy / pre-fix: 500 with "Failed to create meta
157
+ # object" in the body (gated on the substring so unrelated
158
+ # 500s -- e.g. a DB outage -- still surface as API_ERROR and
159
+ # stay retryable).
160
+ is_duplicate = exc.status_code == 409 or (
161
+ exc.status_code == 500 and "Failed to create meta object" in exc.message
162
+ )
163
+ if is_duplicate:
164
+ raise KeboolaApiError(
165
+ message=(
166
+ f"{item_type} with name {name!r} already exists in the "
167
+ "target model. Use `edit` to update, or `remove` first."
168
+ ),
169
+ status_code=exc.status_code,
170
+ error_code=ErrorCode.ALREADY_EXISTS,
171
+ retryable=False,
172
+ ) from exc
173
+ raise
174
+ body = response.json()
175
+ return body.get("data", body) if isinstance(body, dict) else body
176
+
177
+ def put_item(
178
+ self,
179
+ item_type: SemanticType,
180
+ item_id: str,
181
+ name: str,
182
+ data: dict[str, Any],
183
+ ) -> dict[str, Any]:
184
+ """Replace an item in place via ``PUT`` (revisioned update).
185
+
186
+ Unlike the DELETE+POST pattern the higher-level ``edit`` operations
187
+ use, ``PUT`` updates the record in place and increments
188
+ ``meta.revision`` server-side, preserving the metastore's revision
189
+ history. ``data`` is the inner ``attributes`` payload; the outer
190
+ envelope is added here (identical shape to :meth:`post_item`).
191
+
192
+ Raises :class:`KeboolaApiError` with ``error_code=NOT_FOUND`` on 404.
193
+ """
194
+ envelope = {
195
+ "name": name,
196
+ "data": data,
197
+ "branch": _ENVELOPE_BRANCH,
198
+ "schemaVersion": _ENVELOPE_SCHEMA_VERSION,
199
+ "scope": _ENVELOPE_SCOPE,
200
+ }
201
+ response = self._do_request(
202
+ "PUT",
203
+ f"/api/v1/repository/{item_type}/{item_id}",
204
+ json=envelope,
205
+ )
206
+ body = response.json()
207
+ return body.get("data", body) if isinstance(body, dict) else body
208
+
209
+ def delete_item(self, item_type: SemanticType, item_id: str) -> None:
210
+ """Delete an item by its UUID. Returns silently on 204.
211
+
212
+ Raises :class:`KeboolaApiError` with ``error_code=NOT_FOUND`` on 404.
213
+ """
214
+ self._do_request("DELETE", f"/api/v1/repository/{item_type}/{item_id}")