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,764 @@
1
+ """FastAPI HTTP server for kbagent.
2
+
3
+ Wraps all services as REST endpoints. Designed to be consumed by the
4
+ web/backend Node.js BFF (which in turn serves the React UI in web/frontend).
5
+
6
+ Key design choices:
7
+ - Bearer token auth (random secret generated at startup, printed to stdout)
8
+ - Localhost-only by default (bind 127.0.0.1)
9
+ - Per-request X-Manage-Token header for write ops requiring manage token
10
+ - Reuses existing services with their existing dict return shapes
11
+ - SSE for streaming: job log tail, branch reset progress, kai chat
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import asyncio
17
+ import contextlib
18
+ import logging
19
+ import secrets
20
+ from contextlib import asynccontextmanager
21
+
22
+ from fastapi import FastAPI
23
+ from fastapi.middleware.cors import CORSMiddleware
24
+ from fastapi.openapi.utils import get_openapi
25
+ from fastapi.responses import JSONResponse
26
+ from starlette.exceptions import HTTPException as StarletteHTTPException
27
+
28
+ from .. import __version__
29
+ from ..config_store import ConfigStore, resolve_config_dir
30
+ from ..errors import ConfigError, ErrorCode, KeboolaApiError
31
+ from .agents_store import AgentStore
32
+ from .auth import PUBLIC_PATHS, AuthSettings, install_auth
33
+ from .dependencies import ServiceRegistry, install_registry
34
+ from .routers import (
35
+ agents,
36
+ ai_chat,
37
+ branches,
38
+ components,
39
+ configs,
40
+ data_apps,
41
+ dev_portal,
42
+ encrypt,
43
+ feature,
44
+ flows,
45
+ health,
46
+ jobs,
47
+ kai,
48
+ lineage,
49
+ mcp,
50
+ members,
51
+ org,
52
+ projects,
53
+ schedules,
54
+ search,
55
+ semantic_layer,
56
+ sharing,
57
+ storage,
58
+ stream,
59
+ workspaces,
60
+ )
61
+
62
+ logger = logging.getLogger(__name__)
63
+
64
+
65
+ # OpenAPI tag metadata. Order matches the CLI groupings printed by
66
+ # ``kbagent --help`` so the Swagger UI sidebar reads top-down the same
67
+ # way users explore commands on the terminal:
68
+ #
69
+ # Project Management -> Configurations -> Data -> Execution ->
70
+ # Development -> AI & Tools -> System
71
+ #
72
+ # FastAPI uses this list both for ordering and for the per-section
73
+ # descriptions. The names below MUST match the ``tags=[...]`` value on
74
+ # each ``APIRouter`` in ``server/routers/`` -- a typo silently demotes
75
+ # a section to the end of the sidebar with no description.
76
+ OPENAPI_TAGS: list[dict[str, str]] = [
77
+ # ---- Project Management ----
78
+ {
79
+ "name": "projects",
80
+ "description": (
81
+ "**Project Management.** "
82
+ "Register, list, edit, and remove Keboola project aliases. "
83
+ "Mirrors `kbagent project add|list|remove|edit|status|use|current|info`."
84
+ ),
85
+ },
86
+ {
87
+ "name": "members",
88
+ "description": (
89
+ "**Project Management.** "
90
+ "Invite users, list members and pending invitations, "
91
+ "change roles, and remove members. "
92
+ "Mirrors `kbagent project invite|member-*|invitation-*`."
93
+ ),
94
+ },
95
+ {
96
+ "name": "org",
97
+ "description": (
98
+ "**Project Management.** "
99
+ "Bulk-onboard an entire organization (Manage API). Requires "
100
+ "the `X-Manage-Token` header on every request -- the manage "
101
+ "token is never persisted in config. "
102
+ "Mirrors `kbagent org setup|refresh`."
103
+ ),
104
+ },
105
+ {
106
+ "name": "feature",
107
+ "description": (
108
+ "**Project Management.** "
109
+ "List the stack feature-flag catalogue and enable/disable "
110
+ "features on projects and users (Manage API). Requires the "
111
+ "`X-Manage-Token` header (super-admin) on every request -- the "
112
+ "manage token is never persisted in config. "
113
+ "Mirrors `kbagent feature list|project-*|user-*`."
114
+ ),
115
+ },
116
+ # ---- Configurations ----
117
+ {
118
+ "name": "configs",
119
+ "description": (
120
+ "**Configurations.** "
121
+ "Browse, search, update, and manage component configurations "
122
+ "and rows (variables, metadata, folder, default bucket, "
123
+ "OAuth URL). "
124
+ "Mirrors `kbagent config *`."
125
+ ),
126
+ },
127
+ {
128
+ "name": "components",
129
+ "description": (
130
+ "**Configurations.** "
131
+ "Discover components (extractors, writers, applications, "
132
+ "transformations) and fetch their JSON schemas. "
133
+ "Mirrors `kbagent component list|detail`."
134
+ ),
135
+ },
136
+ {
137
+ "name": "encrypt",
138
+ "description": (
139
+ "**Configurations.** "
140
+ "Encrypt secret values for a specific project + component "
141
+ "using the Keboola encryption API. "
142
+ "Mirrors `kbagent encrypt values`."
143
+ ),
144
+ },
145
+ # ---- Data ----
146
+ {
147
+ "name": "storage",
148
+ "description": (
149
+ "**Data.** "
150
+ "Buckets, tables, columns, files. Create, upload, download, "
151
+ "describe, swap, delete. "
152
+ "Mirrors `kbagent storage *`."
153
+ ),
154
+ },
155
+ {
156
+ "name": "stream",
157
+ "description": (
158
+ "**Data.** "
159
+ "Data Streams (OpenTelemetry / OTLP) -- list, create, and "
160
+ "delete ingest sources and retrieve their endpoints. The OTLP "
161
+ "URL embeds a secret that is masked unless `reveal=true`. "
162
+ "Mirrors `kbagent stream list|create-source|detail|delete`."
163
+ ),
164
+ },
165
+ {
166
+ "name": "search",
167
+ "description": (
168
+ "**Data.** "
169
+ "Cross-resource search over tables, buckets, configs, "
170
+ "flows, data-apps, and transformations. "
171
+ "Mirrors `kbagent search`."
172
+ ),
173
+ },
174
+ {
175
+ "name": "sharing",
176
+ "description": (
177
+ "**Data.** "
178
+ "Share buckets across projects and inspect the sharing "
179
+ "graph (edges). "
180
+ "Mirrors `kbagent sharing *`."
181
+ ),
182
+ },
183
+ # ---- Execution ----
184
+ {
185
+ "name": "jobs",
186
+ "description": (
187
+ "**Execution.** "
188
+ "Run components, inspect job history, terminate running "
189
+ "jobs. "
190
+ "Mirrors `kbagent job list|detail|run|terminate`."
191
+ ),
192
+ },
193
+ {
194
+ "name": "flows",
195
+ "description": (
196
+ "**Execution.** "
197
+ "Orchestrator and Flow CRUD, scheduling, run history. "
198
+ "Mirrors `kbagent flow *`."
199
+ ),
200
+ },
201
+ {
202
+ "name": "schedules",
203
+ "description": (
204
+ "**Execution.** "
205
+ "Cron-style schedules attached to flows / configurations. "
206
+ "Mirrors `kbagent schedule list|detail|find`."
207
+ ),
208
+ },
209
+ {
210
+ "name": "data-apps",
211
+ "description": (
212
+ "**Execution.** "
213
+ "Streamlit / R / Python data apps -- create, deploy, "
214
+ "start/stop, manage secrets. "
215
+ "Mirrors `kbagent data-app *`."
216
+ ),
217
+ },
218
+ {
219
+ "name": "dev-portal",
220
+ "description": (
221
+ "**Read-only.** "
222
+ "Developer Portal app discovery -- list a vendor's apps, get one "
223
+ "app's full entry. Mirrors `kbagent dev-portal list|get`. Writes "
224
+ "and identity management are CLI-only (TTY-confirmed)."
225
+ ),
226
+ },
227
+ {
228
+ "name": "workspaces",
229
+ "description": (
230
+ "**Execution.** "
231
+ "Snowflake / BigQuery workspaces -- CRUD, load tables, "
232
+ "run SQL via Query Service, GC orphans. "
233
+ "Mirrors `kbagent workspace *`."
234
+ ),
235
+ },
236
+ # ---- Development ----
237
+ {
238
+ "name": "branches",
239
+ "description": (
240
+ "**Development.** "
241
+ "Dev branch lifecycle (create / use / reset / delete / "
242
+ "merge) and branch metadata. "
243
+ "Mirrors `kbagent branch *`."
244
+ ),
245
+ },
246
+ {
247
+ "name": "lineage",
248
+ "description": (
249
+ "**Development.** "
250
+ "Build and query cross-project data lineage (table-level "
251
+ "and column-level). "
252
+ "Mirrors `kbagent lineage build|show|info`."
253
+ ),
254
+ },
255
+ {
256
+ "name": "semantic-layer",
257
+ "description": (
258
+ "**Development.** "
259
+ "Model, validate, import/export, diff, promote, and build "
260
+ "semantic layer artifacts (datasets, metrics, "
261
+ "relationships, constraints, glossary). "
262
+ "Mirrors `kbagent semantic-layer *`."
263
+ ),
264
+ },
265
+ # ---- AI & Tools ----
266
+ {
267
+ "name": "mcp",
268
+ "description": (
269
+ "**AI & Tools.** "
270
+ "List and call MCP tools across one or all projects. "
271
+ "Mirrors `kbagent tool list|call`."
272
+ ),
273
+ },
274
+ {
275
+ "name": "kai",
276
+ "description": (
277
+ "**AI & Tools.** "
278
+ "Keboola AI (Kai) -- ping, preflight, single-shot ask, "
279
+ "chat with history. "
280
+ "Mirrors `kbagent kai *`."
281
+ ),
282
+ },
283
+ {
284
+ "name": "ai-chat",
285
+ "description": (
286
+ "**AI & Tools.** "
287
+ "Server-side streaming AI chat (SSE) used by the kbagent "
288
+ "web UI. No CLI equivalent."
289
+ ),
290
+ },
291
+ {
292
+ "name": "agents",
293
+ "description": (
294
+ "**AI & Tools.** "
295
+ "Scheduled / on-demand AI agent tasks. Server-only feature "
296
+ "(no CLI equivalent) -- the scheduler loop runs inside "
297
+ "`kbagent serve` and persists tasks + runs to the config "
298
+ "directory."
299
+ ),
300
+ },
301
+ # ---- System ----
302
+ {
303
+ "name": "health",
304
+ "description": (
305
+ "**System.** "
306
+ "Liveness ping, auth-info bootstrap, version, changelog, "
307
+ "and doctor checks. `/health/ping` is the only public "
308
+ "endpoint -- everything else requires Bearer auth."
309
+ ),
310
+ },
311
+ ]
312
+
313
+
314
+ APP_DESCRIPTION = """\
315
+ HTTP API surface for **kbagent**. Wraps every CLI command as a REST
316
+ endpoint so the kbagent web UI and any HTTP client (curl, the
317
+ `kbagent http` proxy, scheduled agents, Node BFFs, ...) can drive
318
+ Keboola the same way the terminal does.
319
+
320
+ ## Authentication
321
+
322
+ Every endpoint except `GET /health/ping`, `GET /docs`, `GET /redoc`,
323
+ and `GET /openapi.json` requires a bearer token. The token is
324
+ generated when `kbagent serve` starts and printed to stdout -- click
325
+ **Authorize** at the top right of this page and paste it once.
326
+
327
+ Endpoints under **org** additionally require an `X-Manage-Token`
328
+ header (the Keboola Manage API token). It is never persisted; pass
329
+ it per request.
330
+
331
+ ## Layout
332
+
333
+ Sections below are grouped roughly the same way `kbagent --help` groups
334
+ its command tree:
335
+
336
+ - **Project Management** -- projects, members, org, feature flags
337
+ - **Configurations** -- configs, components, encrypt
338
+ - **Data** -- storage, search, sharing
339
+ - **Execution** -- jobs, flows, schedules, data-apps, workspaces
340
+ - **Development** -- branches, lineage, semantic-layer
341
+ - **AI & Tools** -- mcp, kai, ai-chat, agents
342
+ - **System** -- health
343
+
344
+ Most endpoints accept a `project` alias either in the body or as a
345
+ query parameter; multi-project endpoints accept `project` repeatedly.
346
+ """
347
+
348
+
349
+ def _build_custom_openapi(app: FastAPI):
350
+ """Return a closure that generates the OpenAPI schema with auth schemes.
351
+
352
+ FastAPI's default ``get_openapi(...)`` does not know about the
353
+ ``BearerAuthMiddleware`` (it's an ASGI middleware, not a per-route
354
+ dependency), so the generated schema has no ``securitySchemes`` and
355
+ Swagger UI shows no **Authorize** button. We patch the schema after
356
+ generation:
357
+
358
+ 1. Declare a ``BearerAuth`` HTTP scheme (the global default for every
359
+ endpoint that is not in ``PUBLIC_PATHS``).
360
+ 2. Declare a ``ManageToken`` API-key scheme (header ``X-Manage-Token``)
361
+ used by the ``org`` router and any future endpoint that requires the
362
+ Manage API token. Endpoints opt in by listing it in their
363
+ ``openapi_extra={"security": [{"BearerAuth": [], "ManageToken": []}]}``.
364
+ 3. Apply ``BearerAuth`` globally and clear ``security`` for public paths
365
+ so Swagger UI shows them as unsecured (matching the actual middleware
366
+ behavior).
367
+
368
+ The result is cached on ``app.openapi_schema`` per FastAPI convention.
369
+ """
370
+
371
+ def custom_openapi() -> dict:
372
+ if app.openapi_schema:
373
+ return app.openapi_schema
374
+ schema = get_openapi(
375
+ title=app.title,
376
+ version=app.version,
377
+ description=app.description,
378
+ routes=app.routes,
379
+ tags=app.openapi_tags,
380
+ )
381
+ components = schema.setdefault("components", {})
382
+ components["securitySchemes"] = {
383
+ "BearerAuth": {
384
+ "type": "http",
385
+ "scheme": "bearer",
386
+ "description": (
387
+ "Bearer token printed to stdout when `kbagent serve` starts. "
388
+ "Paste it once and Swagger UI will attach it to every request."
389
+ ),
390
+ },
391
+ "ManageToken": {
392
+ "type": "apiKey",
393
+ "in": "header",
394
+ "name": "X-Manage-Token",
395
+ "description": (
396
+ "Keboola Manage API token. Required only by `/org/*` "
397
+ "endpoints. Never persisted; passed per request."
398
+ ),
399
+ },
400
+ }
401
+ schema["security"] = [{"BearerAuth": []}]
402
+ # Public paths in PUBLIC_PATHS are exempt from the bearer-auth
403
+ # middleware. Reflect that in the schema so Swagger UI does not
404
+ # mislabel them as locked.
405
+ for path in PUBLIC_PATHS:
406
+ path_item = schema.get("paths", {}).get(path)
407
+ if not path_item:
408
+ continue
409
+ for op in path_item.values():
410
+ if isinstance(op, dict):
411
+ op["security"] = []
412
+ app.openapi_schema = schema
413
+ return schema
414
+
415
+ return custom_openapi
416
+
417
+
418
+ def _format_error(
419
+ message: str, error_code: ErrorCode | str, *, http_status: int = 400
420
+ ) -> JSONResponse:
421
+ """Render a kbagent-style error envelope at the given HTTP status.
422
+
423
+ ``error_code`` accepts both :class:`ErrorCode` enum members (the canonical
424
+ surface; matches CLI error envelopes byte-for-byte) and raw strings (for
425
+ forward compatibility when a router wraps a third-party exception whose
426
+ code is not yet in the enum). The :class:`ErrorCode` mixes in ``str``, so
427
+ both shapes serialise as plain strings in the JSON body.
428
+ """
429
+ return JSONResponse(
430
+ status_code=http_status,
431
+ content={
432
+ "status": "error",
433
+ "error": {
434
+ "code": str(error_code),
435
+ "message": message,
436
+ },
437
+ },
438
+ )
439
+
440
+
441
+ def create_app(
442
+ *,
443
+ config_dir: str | None = None,
444
+ auth_token: str | None = None,
445
+ cors_origins: list[str] | None = None,
446
+ serve_url: str | None = None,
447
+ ui_dist: str | None = None,
448
+ ) -> FastAPI:
449
+ """Build and configure the FastAPI application.
450
+
451
+ Args:
452
+ config_dir: Override config directory (matches kbagent --config-dir).
453
+ auth_token: Bearer token clients must send. If None, generates one.
454
+ cors_origins: Allowed CORS origins. Default: localhost dev ports.
455
+ serve_url: Self-URL (``http://host:port``) of this server. Stored on
456
+ the registry so agent subprocesses can be told where to call back.
457
+ If None, defaults are still injected into subprocess env using
458
+ ``127.0.0.1:8001`` -- the serve_command default.
459
+ ui_dist: Optional absolute path to a built React ``dist/`` directory
460
+ (the output of ``npm run build`` in ``web/frontend``). When set,
461
+ the FastAPI app additionally:
462
+
463
+ 1) accepts ``/api/<path>`` as an alias for the bare ``<path>``
464
+ (the BFF used to re-strip this prefix; in single-process mode
465
+ we do it server-side via an ASGI path-rewrite middleware),
466
+ 2) mounts the dist directory at ``/`` so static assets and the
467
+ SPA fallback are served by uvicorn directly,
468
+ 3) intercepts ``GET /`` to inject ``window.__KBAGENT_TOKEN`` into
469
+ ``index.html`` so the SPA boots already authenticated -- no
470
+ BFF and no manual paste step.
471
+
472
+ If the path does not exist, the UI mount is skipped silently and
473
+ a warning is logged so ``--ui`` typos don't break the API path.
474
+
475
+ Returns:
476
+ Configured FastAPI app ready for uvicorn.
477
+ """
478
+ resolved_token = auth_token or secrets.token_urlsafe(32)
479
+
480
+ @asynccontextmanager
481
+ async def _lifespan(app_: FastAPI):
482
+ # Start the agent scheduler loop in the background once services
483
+ # exist (registry is installed below before include_router calls).
484
+ from .agent_runner import scheduler_loop
485
+
486
+ scheduler_task = None
487
+ store = getattr(app_.state, "agent_store", None)
488
+ registry_ = getattr(app_.state, "registry", None)
489
+ if store is not None and registry_ is not None:
490
+ scheduler_task = asyncio.create_task(scheduler_loop(store, registry_))
491
+ logger.info("Agent scheduler task spawned")
492
+ try:
493
+ yield
494
+ finally:
495
+ if scheduler_task is not None:
496
+ scheduler_task.cancel()
497
+ with contextlib.suppress(asyncio.CancelledError):
498
+ await scheduler_task
499
+
500
+ app = FastAPI(
501
+ lifespan=_lifespan, # type: ignore[arg-type]
502
+ title="kbagent serve",
503
+ description=APP_DESCRIPTION,
504
+ version=__version__,
505
+ docs_url="/docs",
506
+ redoc_url="/redoc",
507
+ openapi_tags=OPENAPI_TAGS,
508
+ swagger_ui_parameters={
509
+ # Keep the bearer token across page refreshes so the user only
510
+ # has to paste it once per browser session. The token is held in
511
+ # the Swagger UI in-memory store (and localStorage when persist
512
+ # is true) -- safe for a localhost-only dev tool, and a major
513
+ # ergonomics win for exploring the API.
514
+ "persistAuthorization": True,
515
+ # Default tag ordering follows ``openapi_tags`` above; this
516
+ # toggle just keeps Swagger from re-sorting operations within
517
+ # each tag alphabetically (we want them in router declaration
518
+ # order, which usually mirrors a logical workflow).
519
+ "operationsSorter": None,
520
+ "docExpansion": "none",
521
+ },
522
+ )
523
+ app.openapi = _build_custom_openapi(app) # type: ignore[method-assign]
524
+
525
+ app.add_middleware(
526
+ CORSMiddleware,
527
+ allow_origins=cors_origins
528
+ or [
529
+ "http://localhost:5173", # Vite dev default
530
+ "http://localhost:8000", # Node BFF
531
+ "http://127.0.0.1:5173",
532
+ "http://127.0.0.1:8000",
533
+ ],
534
+ allow_credentials=True,
535
+ allow_methods=["*"],
536
+ allow_headers=["*"],
537
+ )
538
+
539
+ install_auth(app, AuthSettings(token=resolved_token))
540
+
541
+ resolved_dir, source = resolve_config_dir(cli_config_dir=config_dir)
542
+ config_store = ConfigStore(config_dir=resolved_dir, source=source)
543
+ registry = ServiceRegistry(
544
+ config_store=config_store,
545
+ serve_url=serve_url,
546
+ serve_token=resolved_token,
547
+ )
548
+ install_registry(app, registry)
549
+
550
+ app.state.agent_store = AgentStore(resolved_dir)
551
+
552
+ from .run_broadcaster import install_broadcaster
553
+
554
+ install_broadcaster(app)
555
+
556
+ @app.exception_handler(ConfigError)
557
+ async def _config_error_handler(_request, exc: ConfigError):
558
+ return _format_error(str(exc), ErrorCode.CONFIG_ERROR, http_status=400)
559
+
560
+ @app.exception_handler(KeboolaApiError)
561
+ async def _api_error_handler(_request, exc: KeboolaApiError):
562
+ code = getattr(exc, "error_code", ErrorCode.API_ERROR)
563
+ msg = getattr(exc, "message", str(exc)) or str(exc)
564
+ return _format_error(msg, code, http_status=502)
565
+
566
+ @app.exception_handler(StarletteHTTPException)
567
+ async def _starlette_handler(_request, exc: StarletteHTTPException):
568
+ return _format_error(
569
+ exc.detail or "HTTP error", ErrorCode.HTTP_ERROR, http_status=exc.status_code
570
+ )
571
+
572
+ @app.exception_handler(Exception)
573
+ async def _generic_handler(_request, exc: Exception):
574
+ logger.exception("Unhandled error: %s", exc)
575
+ return _format_error(str(exc) or repr(exc), ErrorCode.INTERNAL_ERROR, http_status=500)
576
+
577
+ app.include_router(health.router)
578
+ app.include_router(projects.router)
579
+ app.include_router(members.router)
580
+ app.include_router(feature.router)
581
+ app.include_router(configs.router)
582
+ app.include_router(components.router)
583
+ app.include_router(storage.router)
584
+ app.include_router(stream.router)
585
+ app.include_router(jobs.router)
586
+ app.include_router(branches.router)
587
+ app.include_router(workspaces.router)
588
+ app.include_router(flows.router)
589
+ app.include_router(schedules.router)
590
+ app.include_router(lineage.router)
591
+ app.include_router(sharing.router)
592
+ app.include_router(data_apps.router)
593
+ app.include_router(dev_portal.router)
594
+ app.include_router(mcp.router)
595
+ app.include_router(kai.router)
596
+ app.include_router(ai_chat.router)
597
+ app.include_router(encrypt.router)
598
+ app.include_router(search.router)
599
+ app.include_router(semantic_layer.router)
600
+ app.include_router(org.router)
601
+ app.include_router(agents.router)
602
+
603
+ app.state.auth_token = resolved_token
604
+
605
+ if ui_dist:
606
+ _install_ui(app, ui_dist=ui_dist, token=resolved_token)
607
+
608
+ return app
609
+
610
+
611
+ _SESSION_COOKIE_NAME = "kbagent_session"
612
+
613
+
614
+ def _install_ui(app: FastAPI, *, ui_dist: str, token: str) -> None:
615
+ """Mount the built React SPA at ``/`` and bridge ``/api/*`` to bare routes.
616
+
617
+ Three pieces:
618
+
619
+ 1) **Path-rewrite middleware** for ``/api/<rest>`` -> ``<rest>``. Mounted
620
+ BEFORE auth so the auth header check runs against the rewritten path
621
+ (auth doesn't care about path, but PUBLIC_PATHS exact-matches do).
622
+ 2) **Cookie-setting** ``GET /`` and ``GET /index.html``: read the built
623
+ ``index.html``, return it with a ``Set-Cookie: kbagent_session=<token>;
624
+ HttpOnly; SameSite=Strict; Path=/`` header. Public (no auth) so the
625
+ SPA can bootstrap. The browser then attaches the cookie to every
626
+ same-origin REST + SSE request automatically. The token is HttpOnly
627
+ (no JS access -- XSS-resistant), SameSite=Strict (no cross-origin
628
+ sends -- CSRF-resistant), and lives only for the browser session.
629
+
630
+ This replaces the older "inject ``window.__KBAGENT_TOKEN`` into a
631
+ ``<script>`` tag" approach. The injected token landed in the JS heap
632
+ (XSS-readable) and the EventSource fallback (``?_kbagent_token=...``
633
+ query param) put it into uvicorn's access log -- both attack surfaces
634
+ are gone with the cookie-only design.
635
+ 3) **StaticFiles mount at ``/``** with ``html=True`` so missing paths fall
636
+ through to ``index.html`` for SPA client-side routing.
637
+
638
+ The mount is appended *after* all API routers, so any registered route
639
+ (``/projects``, ``/configs``, ``/agents``, ...) wins over a hypothetical
640
+ static file with the same name.
641
+ """
642
+ from pathlib import Path
643
+
644
+ from fastapi.responses import HTMLResponse
645
+ from fastapi.staticfiles import StaticFiles
646
+ from starlette.middleware.base import BaseHTTPMiddleware
647
+
648
+ dist = Path(ui_dist).expanduser().resolve()
649
+ if not dist.exists() or not (dist / "index.html").exists():
650
+ logger.warning(
651
+ "UI dist path %s missing index.html -- skipping UI mount. "
652
+ "Did you run `make web-build`?",
653
+ dist,
654
+ )
655
+ return
656
+
657
+ class _ApiAliasMiddleware(BaseHTTPMiddleware):
658
+ """Rewrite ``/api/<path>`` -> ``/<path>`` so the SPA can keep its
659
+ existing ``/api/*`` calls unchanged when the BFF is removed.
660
+
661
+ Done in middleware (not via APIRouter prefix) so we can flip a single
662
+ scope key and reuse every existing router unchanged.
663
+ """
664
+
665
+ async def dispatch(self, request, call_next): # type: ignore[override]
666
+ path = request.scope.get("path", "")
667
+ if path.startswith("/api/") or path == "/api":
668
+ stripped = path[4:] or "/"
669
+ request.scope["path"] = stripped
670
+ # raw_path is bytes; some Starlette internals consult it.
671
+ request.scope["raw_path"] = stripped.encode("utf-8")
672
+ return await call_next(request)
673
+
674
+ app.add_middleware(_ApiAliasMiddleware)
675
+
676
+ # Allow unauthenticated access to the bootstrap HTML so the browser can
677
+ # load it and pick up the session cookie. Static assets (JS/CSS/icons)
678
+ # under /assets/* are also public -- they carry no secrets. The shared
679
+ # PUBLIC_PATHS set is already imported at module scope; the SPA's
680
+ # extended public surface is bolted on via ``_allow_static_through_auth``
681
+ # below.
682
+
683
+ @app.get("/", include_in_schema=False)
684
+ @app.get("/index.html", include_in_schema=False)
685
+ async def _serve_ui_index() -> HTMLResponse:
686
+ html = (dist / "index.html").read_text(encoding="utf-8")
687
+ response = HTMLResponse(html)
688
+ # Browser session cookie: HttpOnly + SameSite=Strict + Path=/. No
689
+ # ``Secure`` flag because kbagent serve defaults to plain http on
690
+ # 127.0.0.1; setting Secure would prevent the cookie from ever being
691
+ # set on a localhost dev install. Operators running `--host 0.0.0.0`
692
+ # behind TLS termination should layer Secure via the proxy.
693
+ # ``max_age`` deliberately omitted -> cookie is a session cookie
694
+ # (cleared when the browser closes), matching the token's
695
+ # one-per-process lifecycle.
696
+ response.set_cookie(
697
+ key=_SESSION_COOKIE_NAME,
698
+ value=token,
699
+ httponly=True,
700
+ samesite="strict",
701
+ path="/",
702
+ )
703
+ return response
704
+
705
+ # SPA fallback + assets. ``html=True`` makes StaticFiles serve index.html
706
+ # for unknown paths (so /workspaces, /jobs, etc. client-side routes work
707
+ # on direct navigation). The auth middleware will still gate API calls;
708
+ # static files are served before it sees them only because StaticFiles
709
+ # is the LAST mount and middleware runs on the unified scope -- so we
710
+ # widen PUBLIC_PATHS via prefix logic in the auth middleware itself.
711
+ # Quick path: short-circuit auth for non-/api GETs by extending the
712
+ # bypass list at install time.
713
+ _allow_static_through_auth(app)
714
+
715
+ app.mount("/", StaticFiles(directory=str(dist), html=True), name="ui")
716
+
717
+
718
+ def _allow_static_through_auth(app: FastAPI) -> None:
719
+ """Mark the SPA's GET-only static surface as auth-public.
720
+
721
+ The auth middleware exempts ``PUBLIC_PATHS`` (docs, openapi, health). In UI
722
+ mode the SPA also needs ``GET /``, ``GET /index.html``, ``GET /assets/*``,
723
+ favicons, and the SPA's client-side routes (which resolve to index.html via
724
+ the StaticFiles ``html=True`` fallback) to load without a token.
725
+
726
+ Route-aware (GHSA-ffpq-prmh-3gx2): a real endpoint must authenticate; only
727
+ genuine client-side SPA routes fall through to the public index.html shell.
728
+ We ask the router whether a GET resolves to a registered route via the
729
+ routing match protocol, NOT a flat scan of ``app.routes``: fastapi >=0.137
730
+ nests included routers into a lazy tree (``_IncludedRouter``), so a flat scan
731
+ misses nested endpoints and would serve them unauthenticated. ``matches()``
732
+ is the same resolution a real request uses, so it cannot miss a live
733
+ endpoint. Fails CLOSED -- any error treats the path as protected, never
734
+ silently public.
735
+
736
+ Stashed on ``app.state`` for the auth middleware to consult (avoids an
737
+ import cycle with the auth module).
738
+ """
739
+ from starlette.routing import Match
740
+
741
+ static_paths = frozenset({"/", "/index.html", "/favicon.svg", "/favicon.ico", "/manifest.json"})
742
+
743
+ def _is_ui_public(method: str, path: str) -> bool:
744
+ if method != "GET":
745
+ return False
746
+ # SPA shell + built assets are always public so the browser can bootstrap.
747
+ if path in static_paths or path.startswith("/assets/"):
748
+ return True
749
+ try:
750
+ scope = {"type": "http", "method": "GET", "path": path, "headers": []}
751
+ for route in app.router.routes:
752
+ if getattr(route, "name", None) == "ui": # the SPA StaticFiles catch-all
753
+ continue
754
+ match, _ = route.matches(scope)
755
+ if match is not Match.NONE:
756
+ return False # resolves to a real endpoint -> require auth
757
+ return True # no endpoint matched -> genuine SPA client route
758
+ except Exception:
759
+ return False # fail closed
760
+
761
+ app.state.is_ui_public = _is_ui_public
762
+
763
+
764
+ __all__ = ["create_app"]