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.
- keboola_agent_cli/__init__.py +34 -0
- keboola_agent_cli/__main__.py +5 -0
- keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js +2 -0
- keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/architecture-7EHR7CIX-hNCijx_H.js +1 -0
- keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js +37 -0
- keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js +2 -0
- keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js +133 -0
- keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js +11 -0
- keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js +2 -0
- keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js +63 -0
- keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js +3 -0
- keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js +207 -0
- keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js +232 -0
- keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js +124 -0
- keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js +16 -0
- keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js +160 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js +71 -0
- keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js +2 -0
- keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js +2 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js +2 -0
- keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js +2 -0
- keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js +322 -0
- keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js +5 -0
- keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js +2 -0
- keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js +2 -0
- keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js +44 -0
- keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js +11 -0
- keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js +4 -0
- keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js +25 -0
- keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js +25 -0
- keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js +2 -0
- keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js +86 -0
- keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/eventmodeling-FCH6USID-BrJMIks8.js +1 -0
- keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js +163 -0
- keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js +293 -0
- keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/gitGraph-WXDBUCRP-COacYjo-.js +1 -0
- keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js +107 -0
- keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js +2 -0
- keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/index-CMq50kkV.css +1 -0
- keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js +118 -0
- keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/info-J43DQDTF-DdCTRIzU.js +1 -0
- keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js +3 -0
- keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js +2 -0
- keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js +71 -0
- keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js +140 -0
- keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js +90 -0
- keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js +258 -0
- keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js +2 -0
- keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js +2 -0
- keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js +5 -0
- keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js +97 -0
- keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js +2 -0
- keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/packet-YPE3B663-DLiiw_B2.js +1 -0
- keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js +2 -0
- keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/pie-LRSECV5Y-CRoO8G1g.js +1 -0
- keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js +31 -0
- keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js +8 -0
- keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/radar-GUYGQ44K-DAlLVJHm.js +1 -0
- keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js +85 -0
- keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js +2 -0
- keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js +41 -0
- keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js +163 -0
- keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js +2 -0
- keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js +2 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js +2 -0
- keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js +121 -0
- keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/treeView-BLDUP644-DbLYl23-.js +1 -0
- keboola_agent_cli/_ui_dist/assets/treemap-LRROVOQU-Bp0eGlOt.js +1 -0
- keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js +35 -0
- keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/wardley-L42UT6IY-D4yH4jqS.js +1 -0
- keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js +79 -0
- keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js +8 -0
- keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js.map +1 -0
- keboola_agent_cli/_ui_dist/index.html +50 -0
- keboola_agent_cli/ai_client.py +83 -0
- keboola_agent_cli/auto_update.py +550 -0
- keboola_agent_cli/changelog.py +1198 -0
- keboola_agent_cli/cli.py +448 -0
- keboola_agent_cli/client.py +3422 -0
- keboola_agent_cli/commands/__init__.py +0 -0
- keboola_agent_cli/commands/_data_app_git.py +343 -0
- keboola_agent_cli/commands/_helpers.py +377 -0
- keboola_agent_cli/commands/_metadata_input.py +49 -0
- keboola_agent_cli/commands/_semantic_layer_crud.py +632 -0
- keboola_agent_cli/commands/_semantic_layer_helpers.py +44 -0
- keboola_agent_cli/commands/_semantic_layer_reference_data.py +247 -0
- keboola_agent_cli/commands/agent.py +968 -0
- keboola_agent_cli/commands/branch.py +423 -0
- keboola_agent_cli/commands/changelog.py +168 -0
- keboola_agent_cli/commands/component.py +216 -0
- keboola_agent_cli/commands/config.py +2442 -0
- keboola_agent_cli/commands/context.py +1481 -0
- keboola_agent_cli/commands/data_app.py +1279 -0
- keboola_agent_cli/commands/dev_portal.py +584 -0
- keboola_agent_cli/commands/doctor.py +37 -0
- keboola_agent_cli/commands/encrypt.py +145 -0
- keboola_agent_cli/commands/feature.py +311 -0
- keboola_agent_cli/commands/flow.py +948 -0
- keboola_agent_cli/commands/http_client.py +157 -0
- keboola_agent_cli/commands/init.py +279 -0
- keboola_agent_cli/commands/job.py +661 -0
- keboola_agent_cli/commands/kai.py +301 -0
- keboola_agent_cli/commands/lineage.py +1464 -0
- keboola_agent_cli/commands/org.py +292 -0
- keboola_agent_cli/commands/permissions.py +360 -0
- keboola_agent_cli/commands/project.py +1192 -0
- keboola_agent_cli/commands/repl.py +243 -0
- keboola_agent_cli/commands/schedule.py +340 -0
- keboola_agent_cli/commands/search.py +178 -0
- keboola_agent_cli/commands/semantic_layer.py +939 -0
- keboola_agent_cli/commands/serve.py +272 -0
- keboola_agent_cli/commands/sharing.py +340 -0
- keboola_agent_cli/commands/storage.py +2630 -0
- keboola_agent_cli/commands/stream.py +266 -0
- keboola_agent_cli/commands/sync.py +1277 -0
- keboola_agent_cli/commands/tool.py +206 -0
- keboola_agent_cli/commands/version.py +186 -0
- keboola_agent_cli/commands/workspace.py +635 -0
- keboola_agent_cli/config_store.py +582 -0
- keboola_agent_cli/constants.py +528 -0
- keboola_agent_cli/data_science_client.py +342 -0
- keboola_agent_cli/dev_portal_client.py +323 -0
- keboola_agent_cli/errors.py +248 -0
- keboola_agent_cli/http_base.py +315 -0
- keboola_agent_cli/json_utils.py +126 -0
- keboola_agent_cli/lib.py +536 -0
- keboola_agent_cli/manage_client.py +324 -0
- keboola_agent_cli/metastore_client.py +214 -0
- keboola_agent_cli/models.py +427 -0
- keboola_agent_cli/output.py +1084 -0
- keboola_agent_cli/permissions.py +469 -0
- keboola_agent_cli/py.typed +3 -0
- keboola_agent_cli/result_models.py +271 -0
- keboola_agent_cli/server/__init__.py +34 -0
- keboola_agent_cli/server/agent_runner.py +1289 -0
- keboola_agent_cli/server/agents_store.py +325 -0
- keboola_agent_cli/server/app.py +764 -0
- keboola_agent_cli/server/auth.py +117 -0
- keboola_agent_cli/server/dependencies.py +149 -0
- keboola_agent_cli/server/pricing.py +303 -0
- keboola_agent_cli/server/routers/__init__.py +1 -0
- keboola_agent_cli/server/routers/agents.py +616 -0
- keboola_agent_cli/server/routers/ai_chat.py +129 -0
- keboola_agent_cli/server/routers/branches.py +133 -0
- keboola_agent_cli/server/routers/components.py +48 -0
- keboola_agent_cli/server/routers/configs.py +507 -0
- keboola_agent_cli/server/routers/data_apps.py +384 -0
- keboola_agent_cli/server/routers/dev_portal.py +67 -0
- keboola_agent_cli/server/routers/encrypt.py +35 -0
- keboola_agent_cli/server/routers/feature.py +179 -0
- keboola_agent_cli/server/routers/flows.py +204 -0
- keboola_agent_cli/server/routers/health.py +53 -0
- keboola_agent_cli/server/routers/jobs.py +175 -0
- keboola_agent_cli/server/routers/kai.py +80 -0
- keboola_agent_cli/server/routers/lineage.py +226 -0
- keboola_agent_cli/server/routers/mcp.py +70 -0
- keboola_agent_cli/server/routers/members.py +170 -0
- keboola_agent_cli/server/routers/org.py +96 -0
- keboola_agent_cli/server/routers/projects.py +106 -0
- keboola_agent_cli/server/routers/schedules.py +54 -0
- keboola_agent_cli/server/routers/search.py +30 -0
- keboola_agent_cli/server/routers/semantic_layer.py +650 -0
- keboola_agent_cli/server/routers/sharing.py +86 -0
- keboola_agent_cli/server/routers/storage.py +574 -0
- keboola_agent_cli/server/routers/stream.py +100 -0
- keboola_agent_cli/server/routers/workspaces.py +302 -0
- keboola_agent_cli/server/run_broadcaster.py +329 -0
- keboola_agent_cli/server/sse.py +25 -0
- keboola_agent_cli/services/__init__.py +0 -0
- keboola_agent_cli/services/_encryption.py +217 -0
- keboola_agent_cli/services/_semantic_layer_cascade.py +147 -0
- keboola_agent_cli/services/_semantic_layer_crud.py +382 -0
- keboola_agent_cli/services/_semantic_layer_internals.py +1078 -0
- keboola_agent_cli/services/_semantic_layer_lookup.py +181 -0
- keboola_agent_cli/services/_semantic_layer_reference_data.py +217 -0
- keboola_agent_cli/services/_sync_bindings.py +456 -0
- keboola_agent_cli/services/_sync_branch.py +191 -0
- keboola_agent_cli/services/_sync_bulk.py +228 -0
- keboola_agent_cli/services/_sync_clone.py +163 -0
- keboola_agent_cli/services/_sync_models.py +97 -0
- keboola_agent_cli/services/_sync_push_ops.py +369 -0
- keboola_agent_cli/services/_sync_storage.py +376 -0
- keboola_agent_cli/services/_sync_writeback.py +167 -0
- keboola_agent_cli/services/agent_service.py +458 -0
- keboola_agent_cli/services/base.py +175 -0
- keboola_agent_cli/services/branch_service.py +588 -0
- keboola_agent_cli/services/component_service.py +694 -0
- keboola_agent_cli/services/config_service.py +2099 -0
- keboola_agent_cli/services/data_app_git_service.py +224 -0
- keboola_agent_cli/services/data_app_service.py +2082 -0
- keboola_agent_cli/services/deep_lineage_service.py +1322 -0
- keboola_agent_cli/services/dev_portal_service.py +345 -0
- keboola_agent_cli/services/doctor_service.py +445 -0
- keboola_agent_cli/services/encrypt_service.py +87 -0
- keboola_agent_cli/services/feature_service.py +268 -0
- keboola_agent_cli/services/flow_service.py +769 -0
- keboola_agent_cli/services/flow_validation.py +188 -0
- keboola_agent_cli/services/http_forwarder_service.py +236 -0
- keboola_agent_cli/services/job_idempotency_store.py +285 -0
- keboola_agent_cli/services/job_service.py +797 -0
- keboola_agent_cli/services/kai_service.py +367 -0
- keboola_agent_cli/services/lineage_service.py +274 -0
- keboola_agent_cli/services/mcp_service.py +1498 -0
- keboola_agent_cli/services/mcp_transport.py +259 -0
- keboola_agent_cli/services/member_service.py +593 -0
- keboola_agent_cli/services/org_service.py +619 -0
- keboola_agent_cli/services/project_service.py +947 -0
- keboola_agent_cli/services/repo_validate_service.py +767 -0
- keboola_agent_cli/services/schedule_service.py +731 -0
- keboola_agent_cli/services/search_service.py +331 -0
- keboola_agent_cli/services/semantic_layer_service.py +1497 -0
- keboola_agent_cli/services/sharing_service.py +307 -0
- keboola_agent_cli/services/storage_service.py +2524 -0
- keboola_agent_cli/services/stream_service.py +395 -0
- keboola_agent_cli/services/sync_service.py +2244 -0
- keboola_agent_cli/services/variables_service.py +447 -0
- keboola_agent_cli/services/version_service.py +1038 -0
- keboola_agent_cli/services/workspace_service.py +1103 -0
- keboola_agent_cli/stream_client.py +217 -0
- keboola_agent_cli/sync/__init__.py +1 -0
- keboola_agent_cli/sync/branch_mapping.py +174 -0
- keboola_agent_cli/sync/clone.py +211 -0
- keboola_agent_cli/sync/code_extraction.py +655 -0
- keboola_agent_cli/sync/config_format.py +290 -0
- keboola_agent_cli/sync/diff_engine.py +566 -0
- keboola_agent_cli/sync/git_utils.py +93 -0
- keboola_agent_cli/sync/manifest.py +162 -0
- keboola_agent_cli/sync/naming.py +90 -0
- keboola_agent_cli/sync/secrets.py +62 -0
- keboola_agent_cli/sync/sql_split.py +134 -0
- keboola_cli-0.63.4.dist-info/METADATA +308 -0
- keboola_cli-0.63.4.dist-info/RECORD +306 -0
- keboola_cli-0.63.4.dist-info/WHEEL +4 -0
- keboola_cli-0.63.4.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Bucket sharing endpoints."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, Depends, Query
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from ..dependencies import ServiceRegistry, get_registry
|
|
11
|
+
|
|
12
|
+
router = APIRouter(prefix="/sharing", tags=["sharing"])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ShareBucket(BaseModel):
|
|
16
|
+
bucket_id: str
|
|
17
|
+
type: str
|
|
18
|
+
target_project_ids: list[int] | None = None
|
|
19
|
+
target_users: list[str] | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LinkBucket(BaseModel):
|
|
23
|
+
source_project_id: int
|
|
24
|
+
bucket_id: str
|
|
25
|
+
name: str | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@router.get("", summary="List shared buckets")
|
|
29
|
+
def list_shared(
|
|
30
|
+
project: list[str] | None = Query(None),
|
|
31
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
32
|
+
) -> dict[str, Any]:
|
|
33
|
+
"""List buckets shared by or to the given projects. Mirrors `kbagent sharing list`."""
|
|
34
|
+
return registry.sharing.list_shared(aliases=project)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@router.get("/edges", summary="List cross-project sharing edges")
|
|
38
|
+
def edges(
|
|
39
|
+
project: list[str] | None = Query(None),
|
|
40
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
41
|
+
) -> dict[str, Any]:
|
|
42
|
+
"""Cross-project lineage edges via shared buckets. Mirrors `kbagent sharing edges`."""
|
|
43
|
+
return registry.lineage.get_lineage(aliases=project)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@router.post("/{project}/share", summary="Share a bucket")
|
|
47
|
+
def share(
|
|
48
|
+
project: str, body: ShareBucket, registry: ServiceRegistry = Depends(get_registry)
|
|
49
|
+
) -> dict[str, Any]:
|
|
50
|
+
"""Expose a bucket to other projects or users. Mirrors `kbagent sharing share`."""
|
|
51
|
+
return registry.sharing.share(
|
|
52
|
+
alias=project,
|
|
53
|
+
bucket_id=body.bucket_id,
|
|
54
|
+
sharing_type=body.type,
|
|
55
|
+
target_project_ids=body.target_project_ids,
|
|
56
|
+
target_users=body.target_users,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@router.post("/{project}/unshare/{bucket_id:path}", summary="Unshare a bucket")
|
|
61
|
+
def unshare(
|
|
62
|
+
project: str, bucket_id: str, registry: ServiceRegistry = Depends(get_registry)
|
|
63
|
+
) -> dict[str, Any]:
|
|
64
|
+
"""Revoke sharing on a bucket. Mirrors `kbagent sharing unshare`."""
|
|
65
|
+
return registry.sharing.unshare(alias=project, bucket_id=bucket_id)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@router.post("/{project}/link", summary="Link a shared bucket")
|
|
69
|
+
def link(
|
|
70
|
+
project: str, body: LinkBucket, registry: ServiceRegistry = Depends(get_registry)
|
|
71
|
+
) -> dict[str, Any]:
|
|
72
|
+
"""Link a shared bucket from another project. Mirrors `kbagent sharing link`."""
|
|
73
|
+
return registry.sharing.link(
|
|
74
|
+
alias=project,
|
|
75
|
+
source_project_id=body.source_project_id,
|
|
76
|
+
source_bucket_id=body.bucket_id,
|
|
77
|
+
name=body.name,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@router.post("/{project}/unlink/{bucket_id:path}", summary="Unlink a shared bucket")
|
|
82
|
+
def unlink(
|
|
83
|
+
project: str, bucket_id: str, registry: ServiceRegistry = Depends(get_registry)
|
|
84
|
+
) -> dict[str, Any]:
|
|
85
|
+
"""Remove a linked shared bucket. Mirrors `kbagent sharing unlink`."""
|
|
86
|
+
return registry.sharing.unlink(alias=project, bucket_id=bucket_id)
|
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
"""Storage endpoints (buckets, tables, files, describe)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import tempfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, UploadFile
|
|
10
|
+
from fastapi.responses import FileResponse
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from ..dependencies import ServiceRegistry, get_registry
|
|
14
|
+
|
|
15
|
+
router = APIRouter(prefix="/storage", tags=["storage"])
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CreateBucket(BaseModel):
|
|
19
|
+
stage: str
|
|
20
|
+
name: str
|
|
21
|
+
description: str | None = None
|
|
22
|
+
backend: str | None = None
|
|
23
|
+
branch_id: int | None = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CreateTable(BaseModel):
|
|
27
|
+
bucket_id: str
|
|
28
|
+
name: str
|
|
29
|
+
columns: list[str]
|
|
30
|
+
primary_key: list[str] | None = None
|
|
31
|
+
not_null_columns: list[str] | None = None
|
|
32
|
+
defaults: list[str] | None = None
|
|
33
|
+
branch_id: int | None = None
|
|
34
|
+
if_not_exists: bool = False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DescribeBucket(BaseModel):
|
|
38
|
+
description: str
|
|
39
|
+
branch_id: int | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class DescribeTable(BaseModel):
|
|
43
|
+
description: str
|
|
44
|
+
branch_id: int | None = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class DescribeColumns(BaseModel):
|
|
48
|
+
columns: dict[str, str]
|
|
49
|
+
branch_id: int | None = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TagFile(BaseModel):
|
|
53
|
+
add: list[str] | None = None
|
|
54
|
+
remove: list[str] | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class LoadFileToTable(BaseModel):
|
|
58
|
+
file_id: int
|
|
59
|
+
table_id: str
|
|
60
|
+
incremental: bool = False
|
|
61
|
+
delimiter: str = ","
|
|
62
|
+
enclosure: str = '"'
|
|
63
|
+
branch_id: int | None = None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class SwapTables(BaseModel):
|
|
67
|
+
target_table_id: str
|
|
68
|
+
branch_id: int
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CloneTable(BaseModel):
|
|
72
|
+
branch_id: int
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@router.get("/buckets", summary="List storage buckets")
|
|
76
|
+
def list_buckets(
|
|
77
|
+
project: str | None = None,
|
|
78
|
+
branch_id: int | None = None,
|
|
79
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
80
|
+
) -> dict[str, Any]:
|
|
81
|
+
"""List storage buckets in one or more projects. Mirrors `kbagent storage buckets`."""
|
|
82
|
+
aliases = [project] if project else None
|
|
83
|
+
return registry.storage.list_buckets(aliases=aliases, branch_id=branch_id)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@router.get("/buckets/{project}/{bucket_id:path}", summary="Get bucket detail")
|
|
87
|
+
def bucket_detail(
|
|
88
|
+
project: str,
|
|
89
|
+
bucket_id: str,
|
|
90
|
+
branch_id: int | None = None,
|
|
91
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
92
|
+
) -> dict[str, Any]:
|
|
93
|
+
"""Fetch detail for a single bucket. Mirrors `kbagent storage bucket-detail`."""
|
|
94
|
+
return registry.storage.get_bucket_detail(
|
|
95
|
+
alias=project, bucket_id=bucket_id, branch_id=branch_id
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@router.post("/buckets/{project}", summary="Create a bucket")
|
|
100
|
+
def create_bucket(
|
|
101
|
+
project: str, body: CreateBucket, registry: ServiceRegistry = Depends(get_registry)
|
|
102
|
+
) -> dict[str, Any]:
|
|
103
|
+
"""Create a new storage bucket. Mirrors `kbagent storage create-bucket`."""
|
|
104
|
+
return registry.storage.create_bucket(
|
|
105
|
+
alias=project,
|
|
106
|
+
stage=body.stage,
|
|
107
|
+
name=body.name,
|
|
108
|
+
description=body.description,
|
|
109
|
+
backend=body.backend,
|
|
110
|
+
branch_id=body.branch_id,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@router.delete("/buckets/{project}", summary="Delete buckets")
|
|
115
|
+
def delete_buckets(
|
|
116
|
+
project: str,
|
|
117
|
+
bucket_id: list[str] = Query(...),
|
|
118
|
+
force: bool = False,
|
|
119
|
+
dry_run: bool = False,
|
|
120
|
+
branch_id: int | None = None,
|
|
121
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
122
|
+
) -> dict[str, Any]:
|
|
123
|
+
"""Delete one or more storage buckets. Mirrors `kbagent storage delete-bucket`."""
|
|
124
|
+
return registry.storage.delete_buckets(
|
|
125
|
+
alias=project,
|
|
126
|
+
bucket_ids=bucket_id,
|
|
127
|
+
force=force,
|
|
128
|
+
dry_run=dry_run,
|
|
129
|
+
branch_id=branch_id,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@router.post("/buckets/{project}/{bucket_id:path}/describe", summary="Set bucket description")
|
|
134
|
+
def describe_bucket(
|
|
135
|
+
project: str,
|
|
136
|
+
bucket_id: str,
|
|
137
|
+
body: DescribeBucket,
|
|
138
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
139
|
+
) -> dict[str, Any]:
|
|
140
|
+
"""Set or update a bucket's description. Mirrors `kbagent storage describe-bucket`."""
|
|
141
|
+
return registry.storage.describe_bucket(
|
|
142
|
+
alias=project,
|
|
143
|
+
bucket_id=bucket_id,
|
|
144
|
+
description=body.description,
|
|
145
|
+
branch_id=body.branch_id,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@router.get("/tables", summary="List storage tables")
|
|
150
|
+
def list_tables(
|
|
151
|
+
project: list[str] | None = Query(None),
|
|
152
|
+
bucket_id: str | None = None,
|
|
153
|
+
branch_id: int | None = None,
|
|
154
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
155
|
+
) -> dict[str, Any]:
|
|
156
|
+
"""List tables across one or more projects. Mirrors `kbagent storage tables`."""
|
|
157
|
+
return registry.storage.list_tables(aliases=project, bucket_id=bucket_id, branch_id=branch_id)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@router.get("/table-detail/{project}/{table_id:path}", summary="Get table detail")
|
|
161
|
+
def table_detail(
|
|
162
|
+
project: str,
|
|
163
|
+
table_id: str,
|
|
164
|
+
branch_id: int | None = None,
|
|
165
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
166
|
+
) -> dict[str, Any]:
|
|
167
|
+
"""Fetch detail for a single table. Mirrors `kbagent storage table-detail`."""
|
|
168
|
+
return registry.storage.get_table_detail(alias=project, table_id=table_id, branch_id=branch_id)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@router.get("/table-preview/{project}/{table_id:path}", summary="Preview table rows")
|
|
172
|
+
def preview_table_v2(
|
|
173
|
+
project: str,
|
|
174
|
+
table_id: str,
|
|
175
|
+
limit: int = 100,
|
|
176
|
+
columns: list[str] | None = Query(None),
|
|
177
|
+
where_column: str | None = None,
|
|
178
|
+
where_operator: str = "eq",
|
|
179
|
+
where_value: list[str] | None = Query(None),
|
|
180
|
+
changed_since: str | None = None,
|
|
181
|
+
changed_until: str | None = None,
|
|
182
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
183
|
+
) -> dict[str, Any]:
|
|
184
|
+
"""Return up to ``limit`` rows via the synchronous data-preview endpoint.
|
|
185
|
+
|
|
186
|
+
Uses ``/v2/storage/tables/{id}/data-preview`` -- synchronous, capped at
|
|
187
|
+
a few hundred rows, no async export job. Storage API caps sync preview
|
|
188
|
+
at 30 columns max.
|
|
189
|
+
|
|
190
|
+
Lives under ``/table-preview`` (not ``/tables/.../preview``) because
|
|
191
|
+
``{table_id:path}`` is greedy and would conflict with sibling routes.
|
|
192
|
+
"""
|
|
193
|
+
import csv as _csv
|
|
194
|
+
import io as _io
|
|
195
|
+
|
|
196
|
+
projects = registry.storage.resolve_projects([project])
|
|
197
|
+
proj = projects[project]
|
|
198
|
+
client = registry.storage._client_factory(proj.stack_url, proj.token)
|
|
199
|
+
try:
|
|
200
|
+
text = client.get_table_data_preview(
|
|
201
|
+
table_id=table_id,
|
|
202
|
+
limit=limit,
|
|
203
|
+
columns=columns,
|
|
204
|
+
where_column=where_column,
|
|
205
|
+
where_operator=where_operator,
|
|
206
|
+
where_values=where_value,
|
|
207
|
+
changed_since=changed_since,
|
|
208
|
+
changed_until=changed_until,
|
|
209
|
+
)
|
|
210
|
+
finally:
|
|
211
|
+
client.close()
|
|
212
|
+
reader = _csv.reader(_io.StringIO(text))
|
|
213
|
+
rows = list(reader)
|
|
214
|
+
if not rows:
|
|
215
|
+
return {"header": [], "rows": [], "row_count": 0}
|
|
216
|
+
return {"header": rows[0], "rows": rows[1:], "row_count": len(rows) - 1}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@router.get("/table-download/{project}/{table_id:path}", summary="Download table as CSV")
|
|
220
|
+
def download_table_v2(
|
|
221
|
+
project: str,
|
|
222
|
+
table_id: str,
|
|
223
|
+
columns: list[str] | None = Query(None),
|
|
224
|
+
limit: int | None = None,
|
|
225
|
+
branch_id: int | None = None,
|
|
226
|
+
where_column: str | None = None,
|
|
227
|
+
where_operator: str = "eq",
|
|
228
|
+
where_value: list[str] | None = Query(None),
|
|
229
|
+
changed_since: str | None = None,
|
|
230
|
+
changed_until: str | None = None,
|
|
231
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
232
|
+
) -> FileResponse:
|
|
233
|
+
"""Download the table as CSV (uses async export). Optional where/changed filters."""
|
|
234
|
+
out_path = Path(tempfile.mkstemp(suffix=".csv", prefix="kbagent-")[1])
|
|
235
|
+
registry.storage.download_table(
|
|
236
|
+
alias=project,
|
|
237
|
+
table_id=table_id,
|
|
238
|
+
output_path=str(out_path),
|
|
239
|
+
columns=columns,
|
|
240
|
+
limit=limit,
|
|
241
|
+
branch_id=branch_id,
|
|
242
|
+
where_column=where_column,
|
|
243
|
+
where_operator=where_operator,
|
|
244
|
+
where_values=where_value,
|
|
245
|
+
changed_since=changed_since,
|
|
246
|
+
changed_until=changed_until,
|
|
247
|
+
)
|
|
248
|
+
return FileResponse(
|
|
249
|
+
path=str(out_path),
|
|
250
|
+
media_type="text/csv",
|
|
251
|
+
filename=f"{table_id.replace('.', '_')}.csv",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@router.post("/tables/{project}", summary="Create a table")
|
|
256
|
+
def create_table(
|
|
257
|
+
project: str, body: CreateTable, registry: ServiceRegistry = Depends(get_registry)
|
|
258
|
+
) -> dict[str, Any]:
|
|
259
|
+
"""Create a typed storage table. Mirrors `kbagent storage create-table`."""
|
|
260
|
+
return registry.storage.create_table(
|
|
261
|
+
alias=project,
|
|
262
|
+
bucket_id=body.bucket_id,
|
|
263
|
+
name=body.name,
|
|
264
|
+
columns=body.columns,
|
|
265
|
+
primary_key=body.primary_key,
|
|
266
|
+
branch_id=body.branch_id,
|
|
267
|
+
not_null_columns=body.not_null_columns,
|
|
268
|
+
defaults=body.defaults,
|
|
269
|
+
if_not_exists=body.if_not_exists,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@router.post("/tables/{project}/upload", summary="Upload data into a table")
|
|
274
|
+
async def upload_table(
|
|
275
|
+
project: str,
|
|
276
|
+
table_id: str = Form(...),
|
|
277
|
+
incremental: bool = Form(False),
|
|
278
|
+
branch_id: int | None = Form(None),
|
|
279
|
+
file: UploadFile = File(...),
|
|
280
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
281
|
+
) -> dict[str, Any]:
|
|
282
|
+
"""Upload a CSV file into an existing table. Mirrors `kbagent storage upload-table`."""
|
|
283
|
+
with tempfile.NamedTemporaryFile(delete=False, suffix=Path(file.filename or "x").suffix) as tmp:
|
|
284
|
+
tmp.write(await file.read())
|
|
285
|
+
tmp_path = Path(tmp.name)
|
|
286
|
+
try:
|
|
287
|
+
return registry.storage.upload_table(
|
|
288
|
+
alias=project,
|
|
289
|
+
table_id=table_id,
|
|
290
|
+
file_path=str(tmp_path),
|
|
291
|
+
incremental=incremental,
|
|
292
|
+
branch_id=branch_id,
|
|
293
|
+
)
|
|
294
|
+
finally:
|
|
295
|
+
tmp_path.unlink(missing_ok=True)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@router.delete("/tables/{project}", summary="Delete tables")
|
|
299
|
+
def delete_tables(
|
|
300
|
+
project: str,
|
|
301
|
+
table_id: list[str] = Query(...),
|
|
302
|
+
force: bool = False,
|
|
303
|
+
dry_run: bool = False,
|
|
304
|
+
branch_id: int | None = None,
|
|
305
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
306
|
+
) -> dict[str, Any]:
|
|
307
|
+
"""Delete one or more storage tables. Mirrors `kbagent storage delete-table`."""
|
|
308
|
+
return registry.storage.delete_tables(
|
|
309
|
+
alias=project,
|
|
310
|
+
table_ids=table_id,
|
|
311
|
+
force=force,
|
|
312
|
+
dry_run=dry_run,
|
|
313
|
+
branch_id=branch_id,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@router.post("/tables/{project}/truncate", summary="Truncate tables")
|
|
318
|
+
def truncate_tables(
|
|
319
|
+
project: str,
|
|
320
|
+
table_id: list[str] = Query(...),
|
|
321
|
+
dry_run: bool = False,
|
|
322
|
+
branch_id: int | None = None,
|
|
323
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
324
|
+
) -> dict[str, Any]:
|
|
325
|
+
"""Truncate (empty) one or more storage tables. Mirrors `kbagent storage truncate-table`."""
|
|
326
|
+
return registry.storage.truncate_tables(
|
|
327
|
+
alias=project,
|
|
328
|
+
table_ids=table_id,
|
|
329
|
+
dry_run=dry_run,
|
|
330
|
+
branch_id=branch_id,
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@router.delete("/columns/{project}/{table_id:path}", summary="Delete table columns")
|
|
335
|
+
def delete_columns(
|
|
336
|
+
project: str,
|
|
337
|
+
table_id: str,
|
|
338
|
+
column: list[str] = Query(...),
|
|
339
|
+
force: bool = False,
|
|
340
|
+
dry_run: bool = False,
|
|
341
|
+
branch_id: int | None = None,
|
|
342
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
343
|
+
) -> dict[str, Any]:
|
|
344
|
+
"""Delete columns from a table. Mirrors `kbagent storage delete-column`."""
|
|
345
|
+
return registry.storage.delete_columns(
|
|
346
|
+
alias=project,
|
|
347
|
+
table_id=table_id,
|
|
348
|
+
columns=column,
|
|
349
|
+
force=force,
|
|
350
|
+
dry_run=dry_run,
|
|
351
|
+
branch_id=branch_id,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
@router.post("/tables/{project}/{table_id:path}/swap", summary="Swap two tables")
|
|
356
|
+
def swap_tables(
|
|
357
|
+
project: str,
|
|
358
|
+
table_id: str,
|
|
359
|
+
body: SwapTables,
|
|
360
|
+
dry_run: bool = False,
|
|
361
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
362
|
+
) -> dict[str, Any]:
|
|
363
|
+
"""Atomically swap two storage tables. Mirrors `kbagent storage swap-tables`."""
|
|
364
|
+
return registry.storage.swap_tables(
|
|
365
|
+
alias=project,
|
|
366
|
+
table_id=table_id,
|
|
367
|
+
target_table_id=body.target_table_id,
|
|
368
|
+
branch_id=body.branch_id,
|
|
369
|
+
dry_run=dry_run,
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
@router.post(
|
|
374
|
+
"/tables/{project}/{table_id:path}/pull",
|
|
375
|
+
summary="Clone a table into a dev branch",
|
|
376
|
+
)
|
|
377
|
+
def clone_table(
|
|
378
|
+
project: str,
|
|
379
|
+
table_id: str,
|
|
380
|
+
body: CloneTable,
|
|
381
|
+
dry_run: bool = False,
|
|
382
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
383
|
+
) -> dict[str, Any]:
|
|
384
|
+
"""Pull (clone) a production table into a dev branch.
|
|
385
|
+
|
|
386
|
+
Mirrors `kbagent storage clone-table`.
|
|
387
|
+
"""
|
|
388
|
+
return registry.storage.clone_table(
|
|
389
|
+
alias=project,
|
|
390
|
+
table_id=table_id,
|
|
391
|
+
branch_id=body.branch_id,
|
|
392
|
+
dry_run=dry_run,
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
@router.post("/tables/{project}/{table_id:path}/describe", summary="Set table description")
|
|
397
|
+
def describe_table(
|
|
398
|
+
project: str,
|
|
399
|
+
table_id: str,
|
|
400
|
+
body: DescribeTable,
|
|
401
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
402
|
+
) -> dict[str, Any]:
|
|
403
|
+
"""Set or update a table's description. Mirrors `kbagent storage describe-table`."""
|
|
404
|
+
return registry.storage.describe_table(
|
|
405
|
+
alias=project,
|
|
406
|
+
table_id=table_id,
|
|
407
|
+
description=body.description,
|
|
408
|
+
branch_id=body.branch_id,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
@router.post("/columns/{project}/{table_id:path}/describe", summary="Set column descriptions")
|
|
413
|
+
def describe_columns(
|
|
414
|
+
project: str,
|
|
415
|
+
table_id: str,
|
|
416
|
+
body: DescribeColumns,
|
|
417
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
418
|
+
) -> dict[str, Any]:
|
|
419
|
+
"""Set descriptions for table columns. Mirrors `kbagent storage describe-column`."""
|
|
420
|
+
return registry.storage.describe_columns(
|
|
421
|
+
alias=project,
|
|
422
|
+
table_id=table_id,
|
|
423
|
+
columns=body.columns,
|
|
424
|
+
branch_id=body.branch_id,
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
# Registered AFTER the more specific /columns/.../describe route above: the
|
|
429
|
+
# greedy {table_id:path} would otherwise shadow that POST and swallow a
|
|
430
|
+
# ".../describe" suffix as part of the table id.
|
|
431
|
+
@router.post("/columns/{project}/{table_id:path}", summary="Add a table column")
|
|
432
|
+
def add_column(
|
|
433
|
+
project: str,
|
|
434
|
+
table_id: str,
|
|
435
|
+
column: str = Query(...),
|
|
436
|
+
not_null: bool = False,
|
|
437
|
+
default: str | None = None,
|
|
438
|
+
branch_id: int | None = None,
|
|
439
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
440
|
+
) -> dict[str, Any]:
|
|
441
|
+
"""Add a single column to a table. Mirrors `kbagent storage add-column`."""
|
|
442
|
+
return registry.storage.add_column(
|
|
443
|
+
alias=project,
|
|
444
|
+
table_id=table_id,
|
|
445
|
+
column=column,
|
|
446
|
+
not_null=not_null,
|
|
447
|
+
default=default,
|
|
448
|
+
branch_id=branch_id,
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
# ---- Files ----
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
@router.get("/files", summary="List storage files")
|
|
456
|
+
def list_files(
|
|
457
|
+
project: str,
|
|
458
|
+
tag: list[str] | None = Query(None),
|
|
459
|
+
limit: int = 50,
|
|
460
|
+
offset: int = 0,
|
|
461
|
+
query: str | None = None,
|
|
462
|
+
branch_id: int | None = None,
|
|
463
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
464
|
+
) -> dict[str, Any]:
|
|
465
|
+
"""List files in a project's Storage Files API. Mirrors `kbagent storage files`."""
|
|
466
|
+
return registry.storage.list_files(
|
|
467
|
+
alias=project,
|
|
468
|
+
tags=tag,
|
|
469
|
+
limit=limit,
|
|
470
|
+
offset=offset,
|
|
471
|
+
query=query,
|
|
472
|
+
branch_id=branch_id,
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
@router.post("/files/upload", summary="Upload a file to Storage")
|
|
477
|
+
async def upload_file(
|
|
478
|
+
project: str = Form(...),
|
|
479
|
+
name: str | None = Form(None),
|
|
480
|
+
permanent: bool = Form(False),
|
|
481
|
+
tag: list[str] = Form([]),
|
|
482
|
+
branch_id: int | None = Form(None),
|
|
483
|
+
file: UploadFile = File(...),
|
|
484
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
485
|
+
) -> dict[str, Any]:
|
|
486
|
+
"""Upload a file into Storage Files. Mirrors `kbagent storage file-upload`."""
|
|
487
|
+
with tempfile.NamedTemporaryFile(delete=False, suffix=Path(file.filename or "x").suffix) as tmp:
|
|
488
|
+
tmp.write(await file.read())
|
|
489
|
+
tmp_path = Path(tmp.name)
|
|
490
|
+
try:
|
|
491
|
+
return registry.storage.upload_file(
|
|
492
|
+
alias=project,
|
|
493
|
+
file_path=str(tmp_path),
|
|
494
|
+
name=name or file.filename,
|
|
495
|
+
tags=tag,
|
|
496
|
+
is_permanent=permanent,
|
|
497
|
+
branch_id=branch_id,
|
|
498
|
+
)
|
|
499
|
+
finally:
|
|
500
|
+
tmp_path.unlink(missing_ok=True)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
@router.get("/files/{project}/{file_id}", summary="Get file detail")
|
|
504
|
+
def file_detail(
|
|
505
|
+
project: str,
|
|
506
|
+
file_id: int,
|
|
507
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
508
|
+
) -> dict[str, Any]:
|
|
509
|
+
"""Fetch detail for a single Storage file. Mirrors `kbagent storage file-detail`."""
|
|
510
|
+
return registry.storage.get_file_info(alias=project, file_id=file_id)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
@router.get("/files/{project}/{file_id}/download", summary="Download a file")
|
|
514
|
+
def file_download(
|
|
515
|
+
project: str,
|
|
516
|
+
file_id: int,
|
|
517
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
518
|
+
) -> FileResponse:
|
|
519
|
+
"""Download a Storage file. Mirrors `kbagent storage file-download`."""
|
|
520
|
+
out_dir = Path(tempfile.mkdtemp(prefix="kbagent-file-"))
|
|
521
|
+
result = registry.storage.download_file(
|
|
522
|
+
alias=project, file_id=file_id, output_path=str(out_dir)
|
|
523
|
+
)
|
|
524
|
+
file_path = result.get("local_path") if isinstance(result, dict) else None
|
|
525
|
+
if not file_path or not Path(file_path).exists():
|
|
526
|
+
raise HTTPException(status_code=500, detail="Download produced no file.")
|
|
527
|
+
return FileResponse(
|
|
528
|
+
path=file_path, media_type="application/octet-stream", filename=Path(file_path).name
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
@router.delete("/files/{project}", summary="Delete files")
|
|
533
|
+
def delete_files(
|
|
534
|
+
project: str,
|
|
535
|
+
file_id: list[int] = Query(...),
|
|
536
|
+
dry_run: bool = False,
|
|
537
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
538
|
+
) -> dict[str, Any]:
|
|
539
|
+
"""Delete one or more Storage files. Mirrors `kbagent storage file-delete`."""
|
|
540
|
+
return registry.storage.delete_files(alias=project, file_ids=file_id, dry_run=dry_run)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
@router.post("/files/{project}/{file_id}/tag", summary="Add or remove file tags")
|
|
544
|
+
def tag_file(
|
|
545
|
+
project: str,
|
|
546
|
+
file_id: int,
|
|
547
|
+
body: TagFile,
|
|
548
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
549
|
+
) -> dict[str, Any]:
|
|
550
|
+
"""Add or remove tags on a Storage file. Mirrors `kbagent storage file-tag`."""
|
|
551
|
+
return registry.storage.tag_file(
|
|
552
|
+
alias=project,
|
|
553
|
+
file_id=file_id,
|
|
554
|
+
add_tags=body.add,
|
|
555
|
+
remove_tags=body.remove,
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
@router.post("/files/{project}/load-to-table", summary="Load a file into a table")
|
|
560
|
+
def load_file_to_table(
|
|
561
|
+
project: str,
|
|
562
|
+
body: LoadFileToTable,
|
|
563
|
+
registry: ServiceRegistry = Depends(get_registry),
|
|
564
|
+
) -> dict[str, Any]:
|
|
565
|
+
"""Load a Storage file's contents into a table. Mirrors `kbagent storage load-file`."""
|
|
566
|
+
return registry.storage.load_file_to_table(
|
|
567
|
+
alias=project,
|
|
568
|
+
file_id=body.file_id,
|
|
569
|
+
table_id=body.table_id,
|
|
570
|
+
incremental=body.incremental,
|
|
571
|
+
delimiter=body.delimiter,
|
|
572
|
+
enclosure=body.enclosure,
|
|
573
|
+
branch_id=body.branch_id,
|
|
574
|
+
)
|