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,650 @@
1
+ """Semantic-layer endpoints — 18 routes covering 30 CLI subcommands.
2
+
3
+ Mirrors the per-subcommand surface of
4
+ :class:`keboola_agent_cli.services.semantic_layer_service.SemanticLayerService`.
5
+ The 15 ``add.*``/``edit.*``/``remove.*`` CLI leaves collapse into three
6
+ ``{kind}``-parameterized routes (``POST/PUT/DELETE /items/{kind}``) for
7
+ RESTful semantics; per-kind Pydantic body validation happens inside the
8
+ handler. This is a deliberate departure from the CONTRIBUTING.md "1:1
9
+ endpoint per command" guideline — the parameterization preserves
10
+ discoverability while keeping the route count manageable.
11
+
12
+ Pattern: Pydantic body models for routes that the CLI flags with multiple
13
+ options, query parameters for read endpoints. ``--yes`` is implicit on
14
+ every REST destructive call (the body / DELETE request IS the confirmation).
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import contextlib
20
+ import json as _json
21
+ import tempfile
22
+ from pathlib import Path
23
+ from typing import Any, Literal
24
+
25
+ from fastapi import APIRouter, Depends, HTTPException, Query
26
+ from pydantic import BaseModel, Field, model_validator
27
+
28
+ from ...errors import ErrorCode
29
+ from ..dependencies import ServiceRegistry, get_registry
30
+
31
+ router = APIRouter(prefix="/semantic-layer", tags=["semantic-layer"])
32
+
33
+
34
+ # Closed set of remove/edit/add kinds, mirroring the CLI surface.
35
+ ItemKind = Literal["metric", "dataset", "relationship", "constraint", "glossary"]
36
+
37
+
38
+ # ── Pydantic body models ───────────────────────────────────────────
39
+
40
+
41
+ class ModelCreate(BaseModel):
42
+ project: str
43
+ name: str
44
+ description: str = ""
45
+ sql_dialect: str = "Snowflake"
46
+
47
+
48
+ class DiffRequest(BaseModel):
49
+ """Diff body — exactly one of project_a/file_a and one of project_b/file_b."""
50
+
51
+ project_a: str | None = None
52
+ project_b: str | None = None
53
+ model_a: str | None = None
54
+ model_b: str | None = None
55
+ file_a: dict[str, Any] | None = None
56
+ file_b: dict[str, Any] | None = None
57
+
58
+ @model_validator(mode="before")
59
+ @classmethod
60
+ def _exactly_one_per_side(cls, data: Any) -> Any:
61
+ # Pydantic v2 calls this with the raw input dict in "before" mode.
62
+ if not isinstance(data, dict):
63
+ return data
64
+ left = (data.get("project_a") is not None, data.get("file_a") is not None)
65
+ right = (data.get("project_b") is not None, data.get("file_b") is not None)
66
+ if sum(left) != 1:
67
+ raise ValueError("Exactly one of project_a or file_a must be set.")
68
+ if sum(right) != 1:
69
+ raise ValueError("Exactly one of project_b or file_b must be set.")
70
+ return data
71
+
72
+
73
+ class AddMetric(BaseModel):
74
+ project: str
75
+ model: str | None = None
76
+ name: str
77
+ sql: str
78
+ dataset: str
79
+ description: str = ""
80
+
81
+
82
+ class AddDataset(BaseModel):
83
+ project: str
84
+ model: str | None = None
85
+ name: str
86
+ table_id: str
87
+ description: str = ""
88
+ grain: str = ""
89
+ primary_key: list[str] | None = None
90
+ deep_fields: bool = False
91
+
92
+
93
+ class AddRelationship(BaseModel):
94
+ project: str
95
+ model: str | None = None
96
+ name: str
97
+ from_: str = Field(alias="from")
98
+ to: str
99
+ on: str
100
+ type_: str = Field(alias="type", default="left")
101
+
102
+ model_config = {"populate_by_name": True}
103
+
104
+
105
+ class AddConstraint(BaseModel):
106
+ project: str
107
+ model: str | None = None
108
+ name: str
109
+ constraint_type: str
110
+ rule: str
111
+ metrics: list[str]
112
+ severity: str = "warning"
113
+
114
+
115
+ class AddGlossary(BaseModel):
116
+ project: str
117
+ model: str | None = None
118
+ term: str
119
+ definition: str = ""
120
+
121
+
122
+ class EditMetric(BaseModel):
123
+ project: str
124
+ model: str | None = None
125
+ new_name: str | None = None
126
+ new_sql: str | None = None
127
+ new_dataset: str | None = None
128
+ new_description: str | None = None
129
+
130
+
131
+ class EditDataset(BaseModel):
132
+ project: str
133
+ model: str | None = None
134
+ new_name: str | None = None
135
+ new_description: str | None = None
136
+ new_grain: str | None = None
137
+
138
+
139
+ class EditRelationship(BaseModel):
140
+ project: str
141
+ model: str | None = None
142
+ new_name: str | None = None
143
+ new_from: str | None = None
144
+ new_to: str | None = None
145
+ new_on: str | None = None
146
+ new_type: str | None = None
147
+
148
+
149
+ class EditConstraint(BaseModel):
150
+ project: str
151
+ model: str | None = None
152
+ new_name: str | None = None
153
+ new_rule: str | None = None
154
+ new_constraint_type: str | None = None
155
+ new_severity: str | None = None
156
+ new_metrics: list[str] | None = None
157
+
158
+
159
+ class EditGlossary(BaseModel):
160
+ project: str
161
+ model: str | None = None
162
+ new_term: str | None = None
163
+ new_definition: str | None = None
164
+
165
+
166
+ class ImportRequest(BaseModel):
167
+ project: str
168
+ model: str | None = None
169
+ snapshot: dict[str, Any]
170
+ types: list[str] | None = None
171
+ dry_run: bool = False
172
+ overwrite: bool = False
173
+
174
+
175
+ class PromoteRequest(BaseModel):
176
+ from_project: str
177
+ to_project: str
178
+ from_model: str | None = None
179
+ to_model: str | None = None
180
+ types: list[str] | None = None
181
+ dry_run: bool = False
182
+
183
+
184
+ class BuildRequest(BaseModel):
185
+ project: str
186
+ model: str | None = None
187
+ tables: list[str]
188
+ name: str | None = None
189
+ dry_run: bool = False
190
+ keep_on_failure: bool = False
191
+
192
+
193
+ class TokenEncryptRequest(BaseModel):
194
+ project: str
195
+ component_id: str
196
+
197
+
198
+ class RefDataSet(BaseModel):
199
+ """Create-or-replace body for ``PUT /reference-data`` (idempotent on dimension)."""
200
+
201
+ project: str
202
+ model: str | None = None
203
+ dimension: str
204
+ members: list[dict[str, Any]]
205
+ dataset_id: str | None = None
206
+ description: str | None = None
207
+
208
+
209
+ # ── Routes (14 declarations, in the order from the plan) ────────────
210
+
211
+
212
+ @router.get("/models", summary="List semantic-layer models")
213
+ def list_models(
214
+ project: str,
215
+ registry: ServiceRegistry = Depends(get_registry),
216
+ ) -> dict[str, Any]:
217
+ """List every semantic-layer model in a project."""
218
+ return registry.semantic_layer.list_models(project)
219
+
220
+
221
+ @router.post("/models", summary="Create a semantic-layer model")
222
+ def create_model(
223
+ body: ModelCreate, registry: ServiceRegistry = Depends(get_registry)
224
+ ) -> dict[str, Any]:
225
+ """Create a semantic-layer model (POST /repository/semantic-model)."""
226
+ return registry.semantic_layer.create_model(
227
+ alias=body.project,
228
+ name=body.name,
229
+ description=body.description,
230
+ sql_dialect=body.sql_dialect,
231
+ )
232
+
233
+
234
+ @router.delete("/models/{model}", summary="Delete a semantic-layer model")
235
+ def delete_model(
236
+ model: str,
237
+ project: str,
238
+ registry: ServiceRegistry = Depends(get_registry),
239
+ ) -> dict[str, Any]:
240
+ """Delete a semantic-layer model (--yes implicit on REST)."""
241
+ return registry.semantic_layer.delete_model(alias=project, model_name_or_uuid=model)
242
+
243
+
244
+ @router.get("/show", summary="Show model entities")
245
+ def show(
246
+ project: str,
247
+ model: str | None = None,
248
+ type: str | None = None,
249
+ registry: ServiceRegistry = Depends(get_registry),
250
+ ) -> dict[str, Any]:
251
+ """Show all entities (datasets, metrics, ...) for a model."""
252
+ return registry.semantic_layer.show_model(
253
+ alias=project, model_name_or_uuid=model, type_filter=type
254
+ )
255
+
256
+
257
+ @router.get("/validate", summary="Validate a semantic-layer model")
258
+ def validate(
259
+ project: str,
260
+ model: str | None = None,
261
+ deep: bool = False,
262
+ registry: ServiceRegistry = Depends(get_registry),
263
+ ) -> dict[str, Any]:
264
+ """Validate a model — basic checks (always) + Snowflake schema probes (``deep``)."""
265
+ return registry.semantic_layer.validate_model(
266
+ alias=project, model_name_or_uuid=model, deep=deep
267
+ )
268
+
269
+
270
+ @router.get("/search-context", summary="Search semantic contexts by name pattern")
271
+ def search_context(
272
+ project: str,
273
+ pattern: list[str] = Query(default=["*"]),
274
+ type: str = "all",
275
+ limit: int | None = None,
276
+ registry: ServiceRegistry = Depends(get_registry),
277
+ ) -> dict[str, Any]:
278
+ """Project-wide glob search across semantic-layer entities.
279
+
280
+ Mirrors ``kbagent semantic-layer search-context``. See the service-layer
281
+ docstring for matching semantics and the returned envelope shape.
282
+ """
283
+ return registry.semantic_layer.search_context(
284
+ alias=project, patterns=pattern, type_filter=type, limit=limit
285
+ )
286
+
287
+
288
+ @router.get("/get-context", summary="Fetch one semantic context by id")
289
+ def get_context(
290
+ project: str,
291
+ context_id: str,
292
+ registry: ServiceRegistry = Depends(get_registry),
293
+ ) -> dict[str, Any]:
294
+ """Single-entry fetch by id; probes every type until found."""
295
+ return registry.semantic_layer.get_context(alias=project, context_id=context_id)
296
+
297
+
298
+ @router.get("/export", summary="Export model snapshot")
299
+ def export(
300
+ project: str,
301
+ model: str | None = None,
302
+ registry: ServiceRegistry = Depends(get_registry),
303
+ ) -> dict[str, Any]:
304
+ """Export a model + every child entity as an inline JSON snapshot.
305
+
306
+ Unlike the CLI which writes to disk by default, the HTTP route returns
307
+ the snapshot in the response body (no file is written server-side).
308
+ """
309
+ # output_path=None on the service writes to a default file path; we
310
+ # need to avoid that for REST. We bypass via export_model + pop the
311
+ # transient path. Simpler: route through the service and let the
312
+ # caller ignore the `path` field. Using a tmp-dir export keeps the
313
+ # service contract intact while avoiding pollution of the CWD.
314
+
315
+ with tempfile.TemporaryDirectory(prefix="kbagent-sl-export-") as tmp:
316
+ out = Path(tmp) / "snapshot.json"
317
+ result = registry.semantic_layer.export_model(
318
+ alias=project, model_name_or_uuid=model, output_path=out
319
+ )
320
+ # Strip the now-deleted tmp path from the wire response (the bytes
321
+ # are already captured in the dict).
322
+ result.pop("path", None)
323
+ return result
324
+
325
+
326
+ @router.post("/diff", summary="Diff two semantic-layer snapshots")
327
+ def diff(body: DiffRequest, registry: ServiceRegistry = Depends(get_registry)) -> dict[str, Any]:
328
+ """Diff two snapshots — project↔project, project↔file, file↔file.
329
+
330
+ File-backed sides carry the snapshot inline in the body (``file_a`` /
331
+ ``file_b``). When a file side is set we serialize it to a temp file so
332
+ the existing service contract (``Path``) keeps working.
333
+ """
334
+
335
+ def _write_tmp(payload: dict[str, Any]) -> Path:
336
+ # `delete=False` is required because we close the handle before
337
+ # the service reads the file (the open handle would let us read
338
+ # but the service takes a Path, not a file object). Cleanup is
339
+ # done explicitly in the finally below.
340
+ fd, tmp_name = tempfile.mkstemp(suffix=".json", prefix="kbagent-sl-diff-")
341
+ try:
342
+ with open(fd, "w", encoding="utf-8") as fh:
343
+ fh.write(_json.dumps(payload))
344
+ except Exception:
345
+ with contextlib.suppress(OSError):
346
+ Path(tmp_name).unlink()
347
+ raise
348
+ return Path(tmp_name)
349
+
350
+ file_a_path: Path | None = None
351
+ file_b_path: Path | None = None
352
+ tmps: list[Path] = []
353
+ try:
354
+ if body.file_a is not None:
355
+ file_a_path = _write_tmp(body.file_a)
356
+ tmps.append(file_a_path)
357
+ if body.file_b is not None:
358
+ file_b_path = _write_tmp(body.file_b)
359
+ tmps.append(file_b_path)
360
+
361
+ return registry.semantic_layer.diff(
362
+ project_a=body.project_a,
363
+ project_b=body.project_b,
364
+ model_a=body.model_a,
365
+ model_b=body.model_b,
366
+ file_a=file_a_path,
367
+ file_b=file_b_path,
368
+ )
369
+ finally:
370
+ for p in tmps:
371
+ with contextlib.suppress(OSError):
372
+ p.unlink()
373
+
374
+
375
+ @router.post("/items/{kind}", summary="Add an entity to a model")
376
+ def add_item(
377
+ kind: ItemKind,
378
+ body: dict[str, Any],
379
+ registry: ServiceRegistry = Depends(get_registry),
380
+ ) -> dict[str, Any]:
381
+ """Add an entity to a model. ``kind`` selects the entity type.
382
+
383
+ Per-kind Pydantic body validation is done downstream by binding the
384
+ raw body to the right model before delegating to the service.
385
+ FastAPI rejects unknown ``kind`` values at the framework layer (422)
386
+ via the :data:`ItemKind` ``Literal`` alias.
387
+ """
388
+ svc = registry.semantic_layer
389
+ if kind == "metric":
390
+ m = AddMetric.model_validate(body)
391
+ return svc.add_metric(
392
+ alias=m.project,
393
+ model_name_or_uuid=m.model,
394
+ name=m.name,
395
+ sql=m.sql,
396
+ dataset=m.dataset,
397
+ description=m.description,
398
+ assume_yes=True,
399
+ is_tty=False,
400
+ )
401
+ if kind == "dataset":
402
+ d = AddDataset.model_validate(body)
403
+ return svc.add_dataset(
404
+ alias=d.project,
405
+ model_name_or_uuid=d.model,
406
+ name=d.name,
407
+ table_id=d.table_id,
408
+ description=d.description,
409
+ grain=d.grain,
410
+ primary_key=d.primary_key,
411
+ deep_fields=d.deep_fields,
412
+ )
413
+ if kind == "relationship":
414
+ r = AddRelationship.model_validate(body)
415
+ return svc.add_relationship(
416
+ alias=r.project,
417
+ model_name_or_uuid=r.model,
418
+ name=r.name,
419
+ from_=r.from_,
420
+ to=r.to,
421
+ on=r.on,
422
+ type_=r.type_,
423
+ )
424
+ if kind == "constraint":
425
+ c = AddConstraint.model_validate(body)
426
+ return svc.add_constraint(
427
+ alias=c.project,
428
+ model_name_or_uuid=c.model,
429
+ name=c.name,
430
+ constraint_type=c.constraint_type,
431
+ rule=c.rule,
432
+ metrics=c.metrics,
433
+ severity=c.severity,
434
+ )
435
+ if kind == "glossary":
436
+ g = AddGlossary.model_validate(body)
437
+ return svc.add_glossary(
438
+ alias=g.project,
439
+ model_name_or_uuid=g.model,
440
+ term=g.term,
441
+ definition=g.definition,
442
+ )
443
+ raise HTTPException(
444
+ status_code=404,
445
+ detail=(
446
+ f"Unknown item kind {kind!r}. "
447
+ f"Must be one of: metric, dataset, relationship, constraint, glossary."
448
+ ),
449
+ )
450
+
451
+
452
+ @router.put("/items/{kind}/{name}", summary="Edit a model entity")
453
+ def edit_item(
454
+ kind: ItemKind,
455
+ name: str,
456
+ body: dict[str, Any],
457
+ registry: ServiceRegistry = Depends(get_registry),
458
+ ) -> dict[str, Any]:
459
+ """Edit an entity. ``name`` is the current identifier; new-* fields live in the body.
460
+
461
+ For ``kind="glossary"``, ``name`` is the current ``term`` (not a stored
462
+ field called ``name``). FastAPI rejects unknown ``kind`` values at the
463
+ framework layer (422) via the :data:`ItemKind` ``Literal`` alias.
464
+ """
465
+ svc = registry.semantic_layer
466
+ if kind == "metric":
467
+ m = EditMetric.model_validate(body)
468
+ return svc.edit_metric(
469
+ alias=m.project,
470
+ model_name_or_uuid=m.model,
471
+ current_name=name,
472
+ new_name=m.new_name,
473
+ new_sql=m.new_sql,
474
+ new_dataset=m.new_dataset,
475
+ new_description=m.new_description,
476
+ assume_yes=True,
477
+ is_tty=False,
478
+ )
479
+ if kind == "dataset":
480
+ d = EditDataset.model_validate(body)
481
+ return svc.edit_dataset(
482
+ alias=d.project,
483
+ model_name_or_uuid=d.model,
484
+ current_name=name,
485
+ new_name=d.new_name,
486
+ new_description=d.new_description,
487
+ new_grain=d.new_grain,
488
+ )
489
+ if kind == "relationship":
490
+ r = EditRelationship.model_validate(body)
491
+ return svc.edit_relationship(
492
+ alias=r.project,
493
+ model_name_or_uuid=r.model,
494
+ current_name=name,
495
+ new_name=r.new_name,
496
+ new_from=r.new_from,
497
+ new_to=r.new_to,
498
+ new_on=r.new_on,
499
+ new_type=r.new_type,
500
+ )
501
+ if kind == "constraint":
502
+ c = EditConstraint.model_validate(body)
503
+ return svc.edit_constraint(
504
+ alias=c.project,
505
+ model_name_or_uuid=c.model,
506
+ current_name=name,
507
+ new_name=c.new_name,
508
+ new_rule=c.new_rule,
509
+ new_constraint_type=c.new_constraint_type,
510
+ new_severity=c.new_severity,
511
+ new_metrics=c.new_metrics,
512
+ )
513
+ if kind == "glossary":
514
+ g = EditGlossary.model_validate(body)
515
+ return svc.edit_glossary(
516
+ alias=g.project,
517
+ model_name_or_uuid=g.model,
518
+ current_term=name,
519
+ new_term=g.new_term,
520
+ new_definition=g.new_definition,
521
+ )
522
+ raise HTTPException(
523
+ status_code=404,
524
+ detail=(
525
+ f"Unknown item kind {kind!r}. "
526
+ f"Must be one of: metric, dataset, relationship, constraint, glossary."
527
+ ),
528
+ )
529
+
530
+
531
+ @router.delete("/items/{kind}/{name}", summary="Remove a model entity")
532
+ def remove_item(
533
+ kind: ItemKind,
534
+ name: str,
535
+ project: str,
536
+ model: str | None = None,
537
+ registry: ServiceRegistry = Depends(get_registry),
538
+ ) -> dict[str, Any]:
539
+ """Remove a child entity (``--yes`` implicit on REST).
540
+
541
+ For ``kind="glossary"``, ``name`` is the term to remove. FastAPI
542
+ rejects unknown ``kind`` values at the framework layer (422) via the
543
+ :data:`ItemKind` ``Literal`` alias.
544
+ """
545
+ return registry.semantic_layer.remove_item(
546
+ alias=project, model_name_or_uuid=model, kind=kind, name=name
547
+ )
548
+
549
+
550
+ @router.post("/import", summary="Import a snapshot into a project")
551
+ def import_snapshot(
552
+ body: ImportRequest, registry: ServiceRegistry = Depends(get_registry)
553
+ ) -> dict[str, Any]:
554
+ """Replay an inline snapshot into a project. Default: skip on conflict."""
555
+ return registry.semantic_layer.import_snapshot_from_dict(
556
+ body.project,
557
+ snapshot=body.snapshot,
558
+ model_name_or_uuid=body.model,
559
+ types=body.types,
560
+ dry_run=body.dry_run,
561
+ overwrite=body.overwrite,
562
+ )
563
+
564
+
565
+ @router.post("/promote", summary="Promote a model between projects")
566
+ def promote(
567
+ body: PromoteRequest, registry: ServiceRegistry = Depends(get_registry)
568
+ ) -> dict[str, Any]:
569
+ """Promote a model from one project to another (additive + overwrite)."""
570
+ return registry.semantic_layer.promote_model(
571
+ from_project=body.from_project,
572
+ to_project=body.to_project,
573
+ from_model=body.from_model,
574
+ to_model=body.to_model,
575
+ types=body.types,
576
+ dry_run=body.dry_run,
577
+ )
578
+
579
+
580
+ @router.post("/build", summary="Build a model from tables")
581
+ def build(body: BuildRequest, registry: ServiceRegistry = Depends(get_registry)) -> dict[str, Any]:
582
+ """Heuristic greenfield builder — synthesize a model from a list of tables."""
583
+ return registry.semantic_layer.build_model(
584
+ alias=body.project,
585
+ table_ids=body.tables,
586
+ model_name=body.name,
587
+ model_name_or_uuid=body.model,
588
+ dry_run=body.dry_run,
589
+ keep_on_failure=body.keep_on_failure,
590
+ )
591
+
592
+
593
+ @router.post("/token/encrypt", summary="Encrypt storage token for transformation")
594
+ def token_encrypt(
595
+ body: TokenEncryptRequest, registry: ServiceRegistry = Depends(get_registry)
596
+ ) -> dict[str, Any]:
597
+ """Encrypt the project's storage token for transformation ``user_properties``."""
598
+ return registry.semantic_layer.encrypt_token(alias=body.project, component_id=body.component_id)
599
+
600
+
601
+ # ── reference-data (dimension-member records, e.g. a Chart of Accounts) ──
602
+
603
+
604
+ @router.get("/reference-data", summary="List reference-data records")
605
+ def list_reference_data(
606
+ project: str,
607
+ model: str | None = None,
608
+ registry: ServiceRegistry = Depends(get_registry),
609
+ ) -> dict[str, Any]:
610
+ """List dimension-member records (summaries; use the by-id route for members)."""
611
+ return registry.semantic_layer.list_reference_data(alias=project, model_name_or_uuid=model)
612
+
613
+
614
+ @router.get("/reference-data/{record_id}", summary="Get one reference-data record")
615
+ def get_reference_data(
616
+ record_id: str,
617
+ project: str,
618
+ registry: ServiceRegistry = Depends(get_registry),
619
+ ) -> dict[str, Any]:
620
+ """Fetch one record (all members) by UUID."""
621
+ return registry.semantic_layer.get_reference_data(alias=project, record_id=record_id)
622
+
623
+
624
+ @router.put("/reference-data", summary="Create or replace a reference-data record")
625
+ def set_reference_data(
626
+ body: RefDataSet, registry: ServiceRegistry = Depends(get_registry)
627
+ ) -> dict[str, Any]:
628
+ """Create or replace (by model + dimension) a record. Idempotent; PUT semantics."""
629
+ return registry.semantic_layer.set_reference_data(
630
+ alias=body.project,
631
+ model_name_or_uuid=body.model,
632
+ dimension=body.dimension,
633
+ members=body.members,
634
+ dataset_id=body.dataset_id,
635
+ description=body.description,
636
+ )
637
+
638
+
639
+ @router.delete("/reference-data/{record_id}", summary="Delete a reference-data record")
640
+ def delete_reference_data(
641
+ record_id: str,
642
+ project: str,
643
+ registry: ServiceRegistry = Depends(get_registry),
644
+ ) -> dict[str, Any]:
645
+ """Delete a record by UUID (``--yes`` implicit on REST; server-side soft-delete)."""
646
+ return registry.semantic_layer.delete_reference_data(alias=project, record_id=record_id)
647
+
648
+
649
+ # Re-export the closed set of kinds for tests / docs.
650
+ __all__ = ["ErrorCode", "ItemKind", "router"]