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,272 @@
|
|
|
1
|
+
"""kbagent serve - launch the FastAPI HTTP server.
|
|
2
|
+
|
|
3
|
+
Wraps all kbagent services as REST endpoints. Print the bearer token to
|
|
4
|
+
stdout on startup so the Node.js BFF (or any other client) can read it.
|
|
5
|
+
|
|
6
|
+
With ``--ui`` the same process additionally serves the built React SPA
|
|
7
|
+
from ``web/frontend/dist`` and pre-injects the bearer token into the
|
|
8
|
+
HTML, so end-users don't need to spawn a Node BFF or paste tokens.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import os
|
|
15
|
+
import secrets
|
|
16
|
+
import sys
|
|
17
|
+
from datetime import UTC, datetime
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
import typer
|
|
21
|
+
|
|
22
|
+
from ..constants import ENV_CONVERSATION_ID
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
ENV_AUTH_TOKEN = "KBAGENT_SERVE_TOKEN"
|
|
27
|
+
ENV_UI_DIST = "KBAGENT_UI_DIST"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _default_conversation_id() -> str:
|
|
31
|
+
"""Generate a conversation ID for a fresh ``kbagent serve`` session.
|
|
32
|
+
|
|
33
|
+
Format: ``serve-<UTC-timestamp>-<8 hex>``. The timestamp prefix makes
|
|
34
|
+
log scanning by start time trivial; the hex suffix disambiguates
|
|
35
|
+
rapid restarts in the same minute. The ``serve-`` prefix is how
|
|
36
|
+
observability dashboards filter "human-driven session" vs other
|
|
37
|
+
integrations.
|
|
38
|
+
|
|
39
|
+
Reads ``KBAGENT_CONVERSATION_ID`` and reuses it when present so a
|
|
40
|
+
caller that pre-set the var (CI, supervisor scripts, debugging across
|
|
41
|
+
a restart) keeps a stable session ID across kbagent serve restarts.
|
|
42
|
+
"""
|
|
43
|
+
existing = os.environ.get(ENV_CONVERSATION_ID, "").strip()
|
|
44
|
+
if existing:
|
|
45
|
+
return existing
|
|
46
|
+
stamp = datetime.now(UTC).strftime("%Y%m%dT%H%M%SZ")
|
|
47
|
+
return f"serve-{stamp}-{secrets.token_hex(4)}"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _autodetect_ui_dist() -> Path | None:
|
|
51
|
+
"""Find the built React SPA across install layouts.
|
|
52
|
+
|
|
53
|
+
Search order (first match wins):
|
|
54
|
+
1) ``$KBAGENT_UI_DIST`` env var -- explicit override, never auto-overridden.
|
|
55
|
+
2) ``keboola_agent_cli/_ui_dist`` *inside the installed package* --
|
|
56
|
+
populated at wheel build time by the ``hatch_build.py`` hook. This
|
|
57
|
+
is what ``uv tool install git+...`` and ``pip install`` from PyPI
|
|
58
|
+
both produce when Node is available (or a maintainer pre-built it).
|
|
59
|
+
3) ``<repo>/web/frontend/dist`` resolved relative to this source file --
|
|
60
|
+
editable installs (``uv pip install -e .``) plus local clones.
|
|
61
|
+
4) ``<cwd>/web/frontend/dist`` -- last-resort for unusual layouts.
|
|
62
|
+
|
|
63
|
+
Returns ``None`` if no candidate exists; the caller then surfaces a
|
|
64
|
+
"no UI bundled" error with rebuild instructions tailored to the
|
|
65
|
+
likely install method.
|
|
66
|
+
"""
|
|
67
|
+
env = os.environ.get(ENV_UI_DIST)
|
|
68
|
+
if env:
|
|
69
|
+
p = Path(env).expanduser().resolve()
|
|
70
|
+
return p if (p / "index.html").exists() else None
|
|
71
|
+
|
|
72
|
+
# commands/serve.py -> commands -> keboola_agent_cli/ -> _ui_dist
|
|
73
|
+
bundled = Path(__file__).resolve().parent.parent / "_ui_dist"
|
|
74
|
+
if (bundled / "index.html").exists():
|
|
75
|
+
return bundled
|
|
76
|
+
|
|
77
|
+
# commands/serve.py -> commands -> keboola_agent_cli -> src -> repo
|
|
78
|
+
repo_dist = Path(__file__).resolve().parents[3] / "web" / "frontend" / "dist"
|
|
79
|
+
if (repo_dist / "index.html").exists():
|
|
80
|
+
return repo_dist
|
|
81
|
+
|
|
82
|
+
cwd_dist = Path.cwd() / "web" / "frontend" / "dist"
|
|
83
|
+
if (cwd_dist / "index.html").exists():
|
|
84
|
+
return cwd_dist
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def serve_command(
|
|
89
|
+
host: str = typer.Option(
|
|
90
|
+
"127.0.0.1",
|
|
91
|
+
"--host",
|
|
92
|
+
help="Bind host. Default 127.0.0.1 (localhost-only).",
|
|
93
|
+
),
|
|
94
|
+
port: int = typer.Option(
|
|
95
|
+
8001,
|
|
96
|
+
"--port",
|
|
97
|
+
help="Bind port. Default 8001 to leave 8000 for the Node BFF.",
|
|
98
|
+
),
|
|
99
|
+
reload: bool = typer.Option(
|
|
100
|
+
False,
|
|
101
|
+
"--reload",
|
|
102
|
+
help="Auto-reload on code changes (uvicorn --reload).",
|
|
103
|
+
),
|
|
104
|
+
log_level: str = typer.Option(
|
|
105
|
+
"info",
|
|
106
|
+
"--log-level",
|
|
107
|
+
help="uvicorn log level: critical, error, warning, info, debug, trace.",
|
|
108
|
+
),
|
|
109
|
+
cors_origin: list[str] = typer.Option(
|
|
110
|
+
None,
|
|
111
|
+
"--cors-origin",
|
|
112
|
+
help="Add a CORS origin (repeatable). Default: localhost:5173 / 8000.",
|
|
113
|
+
),
|
|
114
|
+
config_dir: str | None = typer.Option(
|
|
115
|
+
None,
|
|
116
|
+
"--config-dir",
|
|
117
|
+
help="Override config directory path (matches kbagent --config-dir).",
|
|
118
|
+
),
|
|
119
|
+
ui: bool = typer.Option(
|
|
120
|
+
False,
|
|
121
|
+
"--ui",
|
|
122
|
+
help=(
|
|
123
|
+
"Mount the built React SPA at / so a single uvicorn process serves "
|
|
124
|
+
"both the API and the UI. ``GET /`` sets an HttpOnly `kbagent_session` "
|
|
125
|
+
"cookie (SameSite=Strict, Path=/) so the browser boots already "
|
|
126
|
+
"authenticated -- no Node BFF, no paste step, no token in the JS "
|
|
127
|
+
"heap or URL. Run `make web-build` once to produce the dist/ folder."
|
|
128
|
+
),
|
|
129
|
+
),
|
|
130
|
+
ui_dist: str | None = typer.Option(
|
|
131
|
+
None,
|
|
132
|
+
"--ui-dist",
|
|
133
|
+
help=(
|
|
134
|
+
"Override the path to the built React dist/ directory. Defaults to "
|
|
135
|
+
"<repo>/web/frontend/dist relative to the package, or $KBAGENT_UI_DIST. "
|
|
136
|
+
"Implies --ui."
|
|
137
|
+
),
|
|
138
|
+
),
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Launch the kbagent HTTP API server.
|
|
141
|
+
|
|
142
|
+
The server prints a bearer token on startup. Set ``KBAGENT_SERVE_TOKEN``
|
|
143
|
+
in advance to pin a value (useful for the Node BFF dev workflow).
|
|
144
|
+
"""
|
|
145
|
+
# Probe the optional server extras up front so users get a friendly
|
|
146
|
+
# install hint instead of a Python traceback. We catch BOTH imports
|
|
147
|
+
# (uvicorn AND the FastAPI surface that ``..server`` pulls in) because
|
|
148
|
+
# a partial install (one extra present, the other not) was producing
|
|
149
|
+
# the legacy "ModuleNotFoundError: No module named 'fastapi'" raw
|
|
150
|
+
# traceback in 0.40.0 -- the previous guard only watched uvicorn.
|
|
151
|
+
try:
|
|
152
|
+
import uvicorn
|
|
153
|
+
|
|
154
|
+
from ..server import create_app
|
|
155
|
+
except ModuleNotFoundError as exc: # pragma: no cover
|
|
156
|
+
missing = exc.name or "server extras"
|
|
157
|
+
typer.echo(
|
|
158
|
+
f"\nkbagent serve requires the optional 'server' extras "
|
|
159
|
+
f"(missing: {missing}).\n\n"
|
|
160
|
+
"Reinstall with the [server] extras:\n\n"
|
|
161
|
+
" # If you installed via uv tool install (recommended for end users):\n"
|
|
162
|
+
" uv tool install --force --with 'keboola-cli[server]' \\\n"
|
|
163
|
+
" git+https://github.com/keboola/cli\n\n"
|
|
164
|
+
" # If you have a local checkout (development):\n"
|
|
165
|
+
" uv pip install -e '.[server]'\n",
|
|
166
|
+
err=True,
|
|
167
|
+
)
|
|
168
|
+
raise typer.Exit(code=1) from None
|
|
169
|
+
|
|
170
|
+
auth_token = os.environ.get(ENV_AUTH_TOKEN) or secrets.token_urlsafe(32)
|
|
171
|
+
os.environ[ENV_AUTH_TOKEN] = auth_token
|
|
172
|
+
|
|
173
|
+
# Generate a stable conversation ID for this serve session and export it
|
|
174
|
+
# to env so child processes (MCP subprocess, AI agent CLI invocations,
|
|
175
|
+
# scheduled `kbagent http` calls) inherit it and emit X-Conversation-ID
|
|
176
|
+
# on every Keboola API request. Otherwise observability shows
|
|
177
|
+
# "Conversation ID not set" in `kbagent doctor`.
|
|
178
|
+
conversation_id = _default_conversation_id()
|
|
179
|
+
os.environ[ENV_CONVERSATION_ID] = conversation_id
|
|
180
|
+
|
|
181
|
+
cors = list(cors_origin) if cors_origin else None
|
|
182
|
+
|
|
183
|
+
serve_url = f"http://{host}:{port}"
|
|
184
|
+
|
|
185
|
+
# Resolve --ui/--ui-dist. Either flag opts in; --ui-dist additionally
|
|
186
|
+
# pins the path. If --ui is on but no dist found, abort with the
|
|
187
|
+
# "run make web-build" hint instead of silently launching API-only.
|
|
188
|
+
resolved_ui_dist: str | None = None
|
|
189
|
+
if ui or ui_dist:
|
|
190
|
+
candidate = Path(ui_dist).expanduser().resolve() if ui_dist else _autodetect_ui_dist()
|
|
191
|
+
if candidate is None or not (candidate / "index.html").exists():
|
|
192
|
+
bundled = Path(__file__).resolve().parent.parent / "_ui_dist"
|
|
193
|
+
repo_dist = Path(__file__).resolve().parents[3] / "web" / "frontend" / "dist"
|
|
194
|
+
cwd_dist = Path.cwd() / "web" / "frontend" / "dist"
|
|
195
|
+
typer.echo(
|
|
196
|
+
"--ui: no built React SPA found.\n"
|
|
197
|
+
"\n"
|
|
198
|
+
" Searched these locations (none had index.html):\n"
|
|
199
|
+
f" 1. $KBAGENT_UI_DIST {os.environ.get(ENV_UI_DIST, '(unset)')}\n"
|
|
200
|
+
f" 2. installed package {bundled}\n"
|
|
201
|
+
f" 3. repo checkout {repo_dist}\n"
|
|
202
|
+
f" 4. cwd {cwd_dist}\n"
|
|
203
|
+
"\n"
|
|
204
|
+
" How to fix:\n"
|
|
205
|
+
" - From git checkout: `make web-build` then re-run.\n"
|
|
206
|
+
" - From `uv tool install git+...`: re-install with Node 20+\n"
|
|
207
|
+
" on PATH; the build hook will compile the SPA automatically.\n"
|
|
208
|
+
" - Or pin a path: `kbagent serve --ui-dist /path/to/dist`.",
|
|
209
|
+
err=True,
|
|
210
|
+
)
|
|
211
|
+
raise typer.Exit(code=1) from None
|
|
212
|
+
resolved_ui_dist = str(candidate)
|
|
213
|
+
|
|
214
|
+
app = create_app(
|
|
215
|
+
config_dir=config_dir,
|
|
216
|
+
auth_token=auth_token,
|
|
217
|
+
cors_origins=cors,
|
|
218
|
+
serve_url=serve_url,
|
|
219
|
+
ui_dist=resolved_ui_dist,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
if resolved_ui_dist:
|
|
223
|
+
# UI mode: the user opens the browser directly; there is no BFF to
|
|
224
|
+
# paste the token into. The token is still printed so scripted
|
|
225
|
+
# callers / curl one-liners keep working.
|
|
226
|
+
sys.stdout.write(
|
|
227
|
+
"\n"
|
|
228
|
+
" kbagent serve (single-process UI mode)\n"
|
|
229
|
+
f" ├─ open: http://{host}:{port}/\n"
|
|
230
|
+
f" ├─ api docs: http://{host}:{port}/docs\n"
|
|
231
|
+
f" ├─ ui dist: {resolved_ui_dist}\n"
|
|
232
|
+
f" ├─ conv id: {conversation_id}\n"
|
|
233
|
+
f" └─ token: {auth_token}\n"
|
|
234
|
+
"\n"
|
|
235
|
+
" Browser is auto-authenticated via an HttpOnly kbagent_session cookie\n"
|
|
236
|
+
" set on GET /. Token never enters the JS heap or the URL.\n"
|
|
237
|
+
f" For curl / scripts: Authorization: Bearer {auth_token}\n"
|
|
238
|
+
"\n"
|
|
239
|
+
" For `kbagent http` in another terminal (bash/zsh):\n"
|
|
240
|
+
f" export KBAGENT_SERVE_URL=http://{host}:{port}\n"
|
|
241
|
+
f" export KBAGENT_SERVE_TOKEN={auth_token}\n"
|
|
242
|
+
f" export KBAGENT_CONVERSATION_ID={conversation_id}\n"
|
|
243
|
+
"\n"
|
|
244
|
+
)
|
|
245
|
+
else:
|
|
246
|
+
sys.stdout.write(
|
|
247
|
+
"\n"
|
|
248
|
+
" kbagent serve\n"
|
|
249
|
+
f" ├─ host: http://{host}:{port}\n"
|
|
250
|
+
f" ├─ docs: http://{host}:{port}/docs\n"
|
|
251
|
+
f" ├─ openapi: http://{host}:{port}/openapi.json\n"
|
|
252
|
+
f" ├─ conv id: {conversation_id}\n"
|
|
253
|
+
f" └─ token: {auth_token}\n"
|
|
254
|
+
"\n"
|
|
255
|
+
f" Set {ENV_AUTH_TOKEN}={auth_token} for the Node BFF.\n"
|
|
256
|
+
" Tip: `kbagent serve --ui` mounts the React SPA on the same port.\n"
|
|
257
|
+
"\n"
|
|
258
|
+
" For `kbagent http` in another terminal (bash/zsh):\n"
|
|
259
|
+
f" export KBAGENT_SERVE_URL=http://{host}:{port}\n"
|
|
260
|
+
f" export KBAGENT_SERVE_TOKEN={auth_token}\n"
|
|
261
|
+
f" export KBAGENT_CONVERSATION_ID={conversation_id}\n"
|
|
262
|
+
"\n"
|
|
263
|
+
)
|
|
264
|
+
sys.stdout.flush()
|
|
265
|
+
|
|
266
|
+
uvicorn.run(
|
|
267
|
+
app,
|
|
268
|
+
host=host,
|
|
269
|
+
port=port,
|
|
270
|
+
reload=reload,
|
|
271
|
+
log_level=log_level,
|
|
272
|
+
)
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"""Sharing commands - cross-project bucket sharing and linking.
|
|
2
|
+
|
|
3
|
+
Enable data sharing between Keboola projects:
|
|
4
|
+
- share/unshare: control bucket visibility (requires master token)
|
|
5
|
+
- link/unlink: create/remove linked buckets in target projects
|
|
6
|
+
- list: browse available shared buckets
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ..errors import ConfigError, ErrorCode, KeboolaApiError
|
|
12
|
+
from ._helpers import (
|
|
13
|
+
check_cli_permission,
|
|
14
|
+
emit_project_warnings,
|
|
15
|
+
get_formatter,
|
|
16
|
+
get_service,
|
|
17
|
+
map_error_to_exit_code,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
sharing_app = typer.Typer(
|
|
21
|
+
help=(
|
|
22
|
+
"Cross-project bucket sharing and linking.\n\n"
|
|
23
|
+
"share/unshare require a master token (org membership). "
|
|
24
|
+
"Set via KBC_MASTER_TOKEN_{ALIAS} or KBC_MASTER_TOKEN env var.\n\n"
|
|
25
|
+
"list/link/unlink work with the regular project token."
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@sharing_app.callback(invoke_without_command=True)
|
|
31
|
+
def _sharing_permission_check(ctx: typer.Context) -> None:
|
|
32
|
+
check_cli_permission(ctx, "sharing")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@sharing_app.command("list")
|
|
36
|
+
def sharing_list(
|
|
37
|
+
ctx: typer.Context,
|
|
38
|
+
project: list[str] | None = typer.Option(
|
|
39
|
+
None,
|
|
40
|
+
"--project",
|
|
41
|
+
help="Project alias (repeatable). Omit to query all projects.",
|
|
42
|
+
),
|
|
43
|
+
) -> None:
|
|
44
|
+
"""List shared buckets available for linking.
|
|
45
|
+
|
|
46
|
+
Shows buckets shared within your organization that can be linked
|
|
47
|
+
into your projects. Uses the regular project token.
|
|
48
|
+
"""
|
|
49
|
+
formatter = get_formatter(ctx)
|
|
50
|
+
service = get_service(ctx, "sharing_service")
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
result = service.list_shared(aliases=project)
|
|
54
|
+
except ConfigError as exc:
|
|
55
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
56
|
+
raise typer.Exit(code=5) from None
|
|
57
|
+
|
|
58
|
+
if formatter.json_mode:
|
|
59
|
+
formatter.output(result)
|
|
60
|
+
else:
|
|
61
|
+
from rich.table import Table
|
|
62
|
+
|
|
63
|
+
buckets = result["shared_buckets"]
|
|
64
|
+
if not buckets:
|
|
65
|
+
formatter.console.print("[dim]No shared buckets found.[/dim]")
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
table = Table(title="Shared Buckets")
|
|
69
|
+
table.add_column("Source Project", style="bold")
|
|
70
|
+
table.add_column("Bucket ID", style="cyan")
|
|
71
|
+
table.add_column("Sharing Type", style="dim")
|
|
72
|
+
table.add_column("Backend", style="dim")
|
|
73
|
+
table.add_column("Tables", justify="right")
|
|
74
|
+
table.add_column("Rows", justify="right")
|
|
75
|
+
|
|
76
|
+
for b in buckets:
|
|
77
|
+
table.add_row(
|
|
78
|
+
f"{b['source_project_name']} (#{b['source_project_id']})",
|
|
79
|
+
b["source_bucket_id"],
|
|
80
|
+
b["sharing"],
|
|
81
|
+
b["backend"],
|
|
82
|
+
str(len(b.get("tables", []))),
|
|
83
|
+
str(b["rows_count"]),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
formatter.console.print(table)
|
|
87
|
+
emit_project_warnings(formatter, result)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@sharing_app.command("share")
|
|
91
|
+
def sharing_share(
|
|
92
|
+
ctx: typer.Context,
|
|
93
|
+
project: str = typer.Option(
|
|
94
|
+
...,
|
|
95
|
+
"--project",
|
|
96
|
+
help="Project alias that owns the bucket to share.",
|
|
97
|
+
),
|
|
98
|
+
bucket_id: str = typer.Option(
|
|
99
|
+
...,
|
|
100
|
+
"--bucket-id",
|
|
101
|
+
help="Bucket ID to share (e.g. out.c-data).",
|
|
102
|
+
),
|
|
103
|
+
sharing_type: str = typer.Option(
|
|
104
|
+
...,
|
|
105
|
+
"--type",
|
|
106
|
+
help=(
|
|
107
|
+
"Sharing type: 'organization' (all org members), "
|
|
108
|
+
"'organization-project' (all project members in org), "
|
|
109
|
+
"'selected-projects' (specific projects, use --target-project-ids), "
|
|
110
|
+
"'selected-users' (specific users, use --target-users)."
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
target_project_ids: str | None = typer.Option(
|
|
114
|
+
None,
|
|
115
|
+
"--target-project-ids",
|
|
116
|
+
help="Comma-separated project IDs (required for --type selected-projects).",
|
|
117
|
+
),
|
|
118
|
+
target_users: str | None = typer.Option(
|
|
119
|
+
None,
|
|
120
|
+
"--target-users",
|
|
121
|
+
help="Comma-separated email addresses (required for --type selected-users).",
|
|
122
|
+
),
|
|
123
|
+
) -> None:
|
|
124
|
+
"""Enable sharing on a bucket.
|
|
125
|
+
|
|
126
|
+
Requires a master token with organization membership. Set via env var:
|
|
127
|
+
|
|
128
|
+
KBC_MASTER_TOKEN_{ALIAS} (project-specific, e.g. KBC_MASTER_TOKEN_PROD)
|
|
129
|
+
KBC_MASTER_TOKEN (global fallback)
|
|
130
|
+
|
|
131
|
+
Falls back to the project's configured token if no master token is set.
|
|
132
|
+
"""
|
|
133
|
+
formatter = get_formatter(ctx)
|
|
134
|
+
service = get_service(ctx, "sharing_service")
|
|
135
|
+
|
|
136
|
+
# Parse target lists
|
|
137
|
+
parsed_project_ids: list[int] | None = None
|
|
138
|
+
parsed_users: list[str] | None = None
|
|
139
|
+
|
|
140
|
+
if sharing_type == "selected-projects":
|
|
141
|
+
if not target_project_ids:
|
|
142
|
+
formatter.error(
|
|
143
|
+
message="--target-project-ids is required for --type selected-projects",
|
|
144
|
+
error_code=ErrorCode.USAGE_ERROR,
|
|
145
|
+
)
|
|
146
|
+
raise typer.Exit(code=2)
|
|
147
|
+
parsed_project_ids = [int(pid.strip()) for pid in target_project_ids.split(",")]
|
|
148
|
+
|
|
149
|
+
if sharing_type == "selected-users":
|
|
150
|
+
if not target_users:
|
|
151
|
+
formatter.error(
|
|
152
|
+
message="--target-users is required for --type selected-users",
|
|
153
|
+
error_code=ErrorCode.USAGE_ERROR,
|
|
154
|
+
)
|
|
155
|
+
raise typer.Exit(code=2)
|
|
156
|
+
parsed_users = [u.strip() for u in target_users.split(",")]
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
result = service.share(
|
|
160
|
+
alias=project,
|
|
161
|
+
bucket_id=bucket_id,
|
|
162
|
+
sharing_type=sharing_type,
|
|
163
|
+
target_project_ids=parsed_project_ids,
|
|
164
|
+
target_users=parsed_users,
|
|
165
|
+
)
|
|
166
|
+
except ConfigError as exc:
|
|
167
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
168
|
+
raise typer.Exit(code=5) from None
|
|
169
|
+
except KeboolaApiError as exc:
|
|
170
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
171
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
172
|
+
|
|
173
|
+
if formatter.json_mode:
|
|
174
|
+
formatter.output(result)
|
|
175
|
+
else:
|
|
176
|
+
formatter.success(result["message"])
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@sharing_app.command("unshare")
|
|
180
|
+
def sharing_unshare(
|
|
181
|
+
ctx: typer.Context,
|
|
182
|
+
project: str = typer.Option(
|
|
183
|
+
...,
|
|
184
|
+
"--project",
|
|
185
|
+
help="Project alias that owns the shared bucket.",
|
|
186
|
+
),
|
|
187
|
+
bucket_id: str = typer.Option(
|
|
188
|
+
...,
|
|
189
|
+
"--bucket-id",
|
|
190
|
+
help="Bucket ID to stop sharing (e.g. out.c-data).",
|
|
191
|
+
),
|
|
192
|
+
) -> None:
|
|
193
|
+
"""Disable sharing on a bucket.
|
|
194
|
+
|
|
195
|
+
Fails if other projects still have linked buckets pointing to it.
|
|
196
|
+
|
|
197
|
+
Requires a master token (see 'sharing share --help' for env var details).
|
|
198
|
+
"""
|
|
199
|
+
formatter = get_formatter(ctx)
|
|
200
|
+
service = get_service(ctx, "sharing_service")
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
result = service.unshare(alias=project, bucket_id=bucket_id)
|
|
204
|
+
except ConfigError as exc:
|
|
205
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
206
|
+
raise typer.Exit(code=5) from None
|
|
207
|
+
except KeboolaApiError as exc:
|
|
208
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
209
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
210
|
+
|
|
211
|
+
if formatter.json_mode:
|
|
212
|
+
formatter.output(result)
|
|
213
|
+
else:
|
|
214
|
+
formatter.success(result["message"])
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@sharing_app.command("link")
|
|
218
|
+
def sharing_link(
|
|
219
|
+
ctx: typer.Context,
|
|
220
|
+
project: str = typer.Option(
|
|
221
|
+
...,
|
|
222
|
+
"--project",
|
|
223
|
+
help="Target project alias where the linked bucket will be created.",
|
|
224
|
+
),
|
|
225
|
+
source_project_id: int = typer.Option(
|
|
226
|
+
...,
|
|
227
|
+
"--source-project-id",
|
|
228
|
+
help="ID of the project that owns the shared bucket.",
|
|
229
|
+
),
|
|
230
|
+
bucket_id: str = typer.Option(
|
|
231
|
+
...,
|
|
232
|
+
"--bucket-id",
|
|
233
|
+
help="Source bucket ID to link (e.g. out.c-data).",
|
|
234
|
+
),
|
|
235
|
+
name: str | None = typer.Option(
|
|
236
|
+
None,
|
|
237
|
+
"--name",
|
|
238
|
+
help="Display name for the linked bucket. Auto-generated if omitted.",
|
|
239
|
+
),
|
|
240
|
+
) -> None:
|
|
241
|
+
"""Link a shared bucket into a project.
|
|
242
|
+
|
|
243
|
+
Creates a read-only linked bucket in the target project that mirrors
|
|
244
|
+
the source bucket's tables. Uses the regular project token
|
|
245
|
+
(no master token needed).
|
|
246
|
+
|
|
247
|
+
Use 'sharing list' to discover available shared buckets.
|
|
248
|
+
"""
|
|
249
|
+
formatter = get_formatter(ctx)
|
|
250
|
+
service = get_service(ctx, "sharing_service")
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
result = service.link(
|
|
254
|
+
alias=project,
|
|
255
|
+
source_project_id=source_project_id,
|
|
256
|
+
source_bucket_id=bucket_id,
|
|
257
|
+
name=name,
|
|
258
|
+
)
|
|
259
|
+
except ConfigError as exc:
|
|
260
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
261
|
+
raise typer.Exit(code=5) from None
|
|
262
|
+
except KeboolaApiError as exc:
|
|
263
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
264
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
265
|
+
|
|
266
|
+
if formatter.json_mode:
|
|
267
|
+
formatter.output(result)
|
|
268
|
+
else:
|
|
269
|
+
formatter.success(result["message"])
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@sharing_app.command("unlink")
|
|
273
|
+
def sharing_unlink(
|
|
274
|
+
ctx: typer.Context,
|
|
275
|
+
project: str = typer.Option(
|
|
276
|
+
...,
|
|
277
|
+
"--project",
|
|
278
|
+
help="Project alias containing the linked bucket.",
|
|
279
|
+
),
|
|
280
|
+
bucket_id: str = typer.Option(
|
|
281
|
+
...,
|
|
282
|
+
"--bucket-id",
|
|
283
|
+
help="Linked bucket ID to remove (e.g. in.c-shared-data).",
|
|
284
|
+
),
|
|
285
|
+
) -> None:
|
|
286
|
+
"""Remove a linked bucket from a project.
|
|
287
|
+
|
|
288
|
+
Deletes the linked bucket. Does not affect the source bucket or
|
|
289
|
+
other projects that have linked it. Uses the regular project token.
|
|
290
|
+
"""
|
|
291
|
+
formatter = get_formatter(ctx)
|
|
292
|
+
service = get_service(ctx, "sharing_service")
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
result = service.unlink(alias=project, bucket_id=bucket_id)
|
|
296
|
+
except ConfigError as exc:
|
|
297
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
298
|
+
raise typer.Exit(code=5) from None
|
|
299
|
+
except KeboolaApiError as exc:
|
|
300
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
301
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
302
|
+
|
|
303
|
+
if formatter.json_mode:
|
|
304
|
+
formatter.output(result)
|
|
305
|
+
else:
|
|
306
|
+
formatter.success(result["message"])
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@sharing_app.command("edges")
|
|
310
|
+
def sharing_edges(
|
|
311
|
+
ctx: typer.Context,
|
|
312
|
+
project: list[str] | None = typer.Option(
|
|
313
|
+
None,
|
|
314
|
+
"--project",
|
|
315
|
+
help="Project alias to query (can be repeated for multiple projects).",
|
|
316
|
+
),
|
|
317
|
+
) -> None:
|
|
318
|
+
"""Show cross-project data flow edges via bucket sharing.
|
|
319
|
+
|
|
320
|
+
Lists how data flows between projects through shared and linked buckets.
|
|
321
|
+
Each edge represents a source bucket shared to a target project.
|
|
322
|
+
|
|
323
|
+
For column-level lineage, use `lineage build` + `lineage show`.
|
|
324
|
+
"""
|
|
325
|
+
formatter = get_formatter(ctx)
|
|
326
|
+
service = get_service(ctx, "lineage_service")
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
result = service.get_lineage(aliases=project)
|
|
330
|
+
except ConfigError as exc:
|
|
331
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
332
|
+
raise typer.Exit(code=5) from None
|
|
333
|
+
|
|
334
|
+
if formatter.json_mode:
|
|
335
|
+
formatter.output(result)
|
|
336
|
+
else:
|
|
337
|
+
from ..output import format_lineage_table
|
|
338
|
+
|
|
339
|
+
format_lineage_table(formatter.console, result)
|
|
340
|
+
emit_project_warnings(formatter, result)
|