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,635 @@
|
|
|
1
|
+
"""Workspace commands - create, list, detail, delete, load, query, and from-transformation.
|
|
2
|
+
|
|
3
|
+
Thin CLI layer: parses arguments, calls WorkspaceService, formats output.
|
|
4
|
+
No business logic belongs here.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from rich.markup import escape
|
|
11
|
+
|
|
12
|
+
from ..config_store import ConfigStore
|
|
13
|
+
from ..constants import QUERY_RESULTS_DEFAULT_LIMIT
|
|
14
|
+
from ..errors import ConfigError, ErrorCode, KeboolaApiError
|
|
15
|
+
from ..output import format_query_results, format_workspaces_table
|
|
16
|
+
from ._helpers import (
|
|
17
|
+
check_cli_permission,
|
|
18
|
+
emit_project_warnings,
|
|
19
|
+
get_formatter,
|
|
20
|
+
get_service,
|
|
21
|
+
map_error_to_exit_code,
|
|
22
|
+
resolve_branch,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
workspace_app = typer.Typer(help="Workspace lifecycle for SQL debugging")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@workspace_app.callback(invoke_without_command=True)
|
|
29
|
+
def _workspace_permission_check(ctx: typer.Context) -> None:
|
|
30
|
+
check_cli_permission(ctx, "workspace")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@workspace_app.command("create")
|
|
34
|
+
def workspace_create(
|
|
35
|
+
ctx: typer.Context,
|
|
36
|
+
project: str = typer.Option(
|
|
37
|
+
...,
|
|
38
|
+
"--project",
|
|
39
|
+
help="Project alias to create the workspace in",
|
|
40
|
+
),
|
|
41
|
+
name: str = typer.Option(
|
|
42
|
+
"",
|
|
43
|
+
"--name",
|
|
44
|
+
help="Name for the workspace (shown in Keboola UI)",
|
|
45
|
+
),
|
|
46
|
+
backend: str | None = typer.Option(
|
|
47
|
+
None,
|
|
48
|
+
"--backend",
|
|
49
|
+
help="Workspace backend (auto-detected from project if omitted)",
|
|
50
|
+
),
|
|
51
|
+
read_only: bool = typer.Option(
|
|
52
|
+
True,
|
|
53
|
+
"--read-only/--no-read-only",
|
|
54
|
+
help="Whether the workspace has read-only storage access",
|
|
55
|
+
),
|
|
56
|
+
ui: bool = typer.Option(
|
|
57
|
+
False,
|
|
58
|
+
"--ui",
|
|
59
|
+
help="Create via Queue job (slower ~15s, visible in Keboola UI)",
|
|
60
|
+
),
|
|
61
|
+
) -> None:
|
|
62
|
+
"""Create a new workspace.
|
|
63
|
+
|
|
64
|
+
Default: fast headless mode via Storage API (~1s).
|
|
65
|
+
With --ui: creates via Queue job (~15s), visible in Keboola UI Workspaces tab.
|
|
66
|
+
"""
|
|
67
|
+
formatter = get_formatter(ctx)
|
|
68
|
+
service = get_service(ctx, "workspace_service")
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
result = service.create_workspace(
|
|
72
|
+
alias=project, name=name, backend=backend, read_only=read_only, ui_mode=ui
|
|
73
|
+
)
|
|
74
|
+
formatter.output(
|
|
75
|
+
result,
|
|
76
|
+
lambda c, d: (
|
|
77
|
+
c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
78
|
+
c.print(f"\n[bold]Workspace ID:[/bold] {d['workspace_id']}"),
|
|
79
|
+
c.print(f"[bold]Name:[/bold] {d.get('name', '')}"),
|
|
80
|
+
c.print(f"[bold]Host:[/bold] {d['host']}"),
|
|
81
|
+
c.print(f"[bold]Schema:[/bold] {d['schema']}"),
|
|
82
|
+
c.print(f"[bold]User:[/bold] {d['user']}"),
|
|
83
|
+
c.print(
|
|
84
|
+
f"[bold yellow]Private key:[/bold yellow]\n{d['private_key']}"
|
|
85
|
+
if d.get("private_key")
|
|
86
|
+
else f"[bold yellow]Password:[/bold yellow] {d['password']}"
|
|
87
|
+
),
|
|
88
|
+
c.print(
|
|
89
|
+
"\n[bold yellow]Warning:[/bold yellow] Save the private key now -- it cannot be retrieved later!"
|
|
90
|
+
if d.get("private_key")
|
|
91
|
+
else "\n[bold yellow]Warning:[/bold yellow] Save the password now -- it cannot be retrieved later!"
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
except KeboolaApiError as exc:
|
|
96
|
+
exit_code = map_error_to_exit_code(exc)
|
|
97
|
+
formatter.error(
|
|
98
|
+
message=exc.message,
|
|
99
|
+
error_code=exc.error_code,
|
|
100
|
+
retryable=exc.retryable,
|
|
101
|
+
)
|
|
102
|
+
raise typer.Exit(code=exit_code) from None
|
|
103
|
+
except ConfigError as exc:
|
|
104
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
105
|
+
raise typer.Exit(code=5) from None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@workspace_app.command("list")
|
|
109
|
+
def workspace_list(
|
|
110
|
+
ctx: typer.Context,
|
|
111
|
+
project: list[str] | None = typer.Option(
|
|
112
|
+
None,
|
|
113
|
+
"--project",
|
|
114
|
+
help="Project alias to query (can be repeated for multiple projects)",
|
|
115
|
+
),
|
|
116
|
+
orphaned: bool = typer.Option(
|
|
117
|
+
False,
|
|
118
|
+
"--orphaned",
|
|
119
|
+
help="Show only orphaned workspaces (keboola.sandboxes config missing)",
|
|
120
|
+
),
|
|
121
|
+
branch: int | None = typer.Option(
|
|
122
|
+
None,
|
|
123
|
+
"--branch",
|
|
124
|
+
help="Dev branch ID. Read-only command -- ignores the alias's active branch "
|
|
125
|
+
"by default (mirrors `storage buckets`); pass --branch to opt in. "
|
|
126
|
+
"Requires exactly one --project.",
|
|
127
|
+
),
|
|
128
|
+
qs_compatible: bool = typer.Option(
|
|
129
|
+
False,
|
|
130
|
+
"--qs-compatible",
|
|
131
|
+
help="Show only workspaces whose loginType is known to work with the Query "
|
|
132
|
+
"Service AND that are read-only -- the canonical shape for a data-app.",
|
|
133
|
+
),
|
|
134
|
+
) -> None:
|
|
135
|
+
"""List workspaces from connected projects.
|
|
136
|
+
|
|
137
|
+
Branch handling: this is a read command and follows the same pattern as
|
|
138
|
+
`storage buckets` / `config list` -- when an alias is pinned to a dev
|
|
139
|
+
branch via `branch use`, the production endpoint is used (with a visible
|
|
140
|
+
`Info: ...` banner) instead of silently scoping the listing to the
|
|
141
|
+
pinned branch. Pass `--branch ID` to query a specific dev branch.
|
|
142
|
+
|
|
143
|
+
Each workspace entry exposes `login_type`, `read_only` and
|
|
144
|
+
`qs_compatible` so data-app developers can pick a Query-Service-compatible
|
|
145
|
+
workspace without firing a probe query (closes #304).
|
|
146
|
+
"""
|
|
147
|
+
formatter = get_formatter(ctx)
|
|
148
|
+
service = get_service(ctx, "workspace_service")
|
|
149
|
+
config_store: ConfigStore = ctx.obj["config_store"]
|
|
150
|
+
|
|
151
|
+
if branch is not None and (not project or len(project) != 1):
|
|
152
|
+
formatter.error(
|
|
153
|
+
message="--branch requires exactly one --project (branch ID is per-project)",
|
|
154
|
+
error_code=ErrorCode.INVALID_ARGUMENT,
|
|
155
|
+
)
|
|
156
|
+
raise typer.Exit(code=2)
|
|
157
|
+
|
|
158
|
+
effective_branch: int | None = branch
|
|
159
|
+
if branch is None and project and len(project) == 1:
|
|
160
|
+
_, effective_branch = resolve_branch(
|
|
161
|
+
config_store, formatter, project[0], None, ignore_active_branch=True
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
result = service.list_workspaces(
|
|
166
|
+
aliases=project,
|
|
167
|
+
orphaned_only=orphaned,
|
|
168
|
+
branch_id=effective_branch,
|
|
169
|
+
qs_compatible_only=qs_compatible,
|
|
170
|
+
)
|
|
171
|
+
except KeboolaApiError as exc:
|
|
172
|
+
exit_code = map_error_to_exit_code(exc)
|
|
173
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
174
|
+
raise typer.Exit(code=exit_code) from None
|
|
175
|
+
except ConfigError as exc:
|
|
176
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
177
|
+
raise typer.Exit(code=5) from None
|
|
178
|
+
|
|
179
|
+
if formatter.json_mode:
|
|
180
|
+
formatter.output(result)
|
|
181
|
+
else:
|
|
182
|
+
format_workspaces_table(formatter.console, result)
|
|
183
|
+
emit_project_warnings(formatter, result)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@workspace_app.command("detail")
|
|
187
|
+
def workspace_detail(
|
|
188
|
+
ctx: typer.Context,
|
|
189
|
+
project: str = typer.Option(
|
|
190
|
+
...,
|
|
191
|
+
"--project",
|
|
192
|
+
help="Project alias",
|
|
193
|
+
),
|
|
194
|
+
workspace_id: int = typer.Option(
|
|
195
|
+
...,
|
|
196
|
+
"--workspace-id",
|
|
197
|
+
help="Workspace ID",
|
|
198
|
+
),
|
|
199
|
+
branch: int | None = typer.Option(
|
|
200
|
+
None,
|
|
201
|
+
"--branch",
|
|
202
|
+
help="Dev branch ID. Read-only command -- ignores the alias's active branch "
|
|
203
|
+
"by default (mirrors `storage bucket-detail`); pass --branch to opt in.",
|
|
204
|
+
),
|
|
205
|
+
) -> None:
|
|
206
|
+
"""Show workspace details (password NOT included).
|
|
207
|
+
|
|
208
|
+
Includes `login_type`, `read_only` and `qs_compatible` so callers can
|
|
209
|
+
verify a workspace is Query-Service-compatible before issuing a query
|
|
210
|
+
(closes #304).
|
|
211
|
+
"""
|
|
212
|
+
formatter = get_formatter(ctx)
|
|
213
|
+
service = get_service(ctx, "workspace_service")
|
|
214
|
+
config_store: ConfigStore = ctx.obj["config_store"]
|
|
215
|
+
|
|
216
|
+
_, effective_branch = resolve_branch(
|
|
217
|
+
config_store, formatter, project, branch, ignore_active_branch=True
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
result = service.get_workspace(
|
|
222
|
+
alias=project, workspace_id=workspace_id, branch_id=effective_branch
|
|
223
|
+
)
|
|
224
|
+
formatter.output(
|
|
225
|
+
result,
|
|
226
|
+
lambda c, d: (
|
|
227
|
+
c.print(f"\n[bold]Workspace ID:[/bold] {d['workspace_id']}"),
|
|
228
|
+
c.print(f"[bold]Project:[/bold] {d['project_alias']}"),
|
|
229
|
+
c.print(f"[bold]Backend:[/bold] {d['backend']}"),
|
|
230
|
+
c.print(f"[bold]Host:[/bold] {d['host']}"),
|
|
231
|
+
c.print(f"[bold]Warehouse:[/bold] {d.get('warehouse', '')}"),
|
|
232
|
+
c.print(f"[bold]Database:[/bold] {d.get('database', '')}"),
|
|
233
|
+
c.print(f"[bold]Schema:[/bold] {d['schema']}"),
|
|
234
|
+
c.print(f"[bold]User:[/bold] {d['user']}"),
|
|
235
|
+
c.print(
|
|
236
|
+
f"[bold]Login type:[/bold] {d.get('login_type', '') or '[dim](unknown)[/dim]'}"
|
|
237
|
+
),
|
|
238
|
+
c.print(f"[bold]Read-only:[/bold] {'yes' if d.get('read_only') else 'no'}"),
|
|
239
|
+
c.print(
|
|
240
|
+
f"[bold]Query Service compatible:[/bold] "
|
|
241
|
+
f"{'[green]yes[/green]' if d.get('qs_compatible') else '[yellow]no (loginType not on the confirmed whitelist; query may still work, try `kbagent workspace query`)[/yellow]'}"
|
|
242
|
+
),
|
|
243
|
+
c.print(f"[bold]Created:[/bold] {d.get('created', '')}"),
|
|
244
|
+
),
|
|
245
|
+
)
|
|
246
|
+
except KeboolaApiError as exc:
|
|
247
|
+
exit_code = map_error_to_exit_code(exc)
|
|
248
|
+
formatter.error(
|
|
249
|
+
message=exc.message,
|
|
250
|
+
error_code=exc.error_code,
|
|
251
|
+
retryable=exc.retryable,
|
|
252
|
+
)
|
|
253
|
+
raise typer.Exit(code=exit_code) from None
|
|
254
|
+
except ConfigError as exc:
|
|
255
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
256
|
+
raise typer.Exit(code=5) from None
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@workspace_app.command("delete")
|
|
260
|
+
def workspace_delete(
|
|
261
|
+
ctx: typer.Context,
|
|
262
|
+
project: str = typer.Option(
|
|
263
|
+
...,
|
|
264
|
+
"--project",
|
|
265
|
+
help="Project alias",
|
|
266
|
+
),
|
|
267
|
+
workspace_id: int = typer.Option(
|
|
268
|
+
...,
|
|
269
|
+
"--workspace-id",
|
|
270
|
+
help="Workspace ID to delete",
|
|
271
|
+
),
|
|
272
|
+
) -> None:
|
|
273
|
+
"""Delete a workspace."""
|
|
274
|
+
formatter = get_formatter(ctx)
|
|
275
|
+
service = get_service(ctx, "workspace_service")
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
result = service.delete_workspace(alias=project, workspace_id=workspace_id)
|
|
279
|
+
formatter.output(
|
|
280
|
+
result,
|
|
281
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
282
|
+
)
|
|
283
|
+
except KeboolaApiError as exc:
|
|
284
|
+
exit_code = map_error_to_exit_code(exc)
|
|
285
|
+
formatter.error(
|
|
286
|
+
message=exc.message,
|
|
287
|
+
error_code=exc.error_code,
|
|
288
|
+
retryable=exc.retryable,
|
|
289
|
+
)
|
|
290
|
+
raise typer.Exit(code=exit_code) from None
|
|
291
|
+
except ConfigError as exc:
|
|
292
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
293
|
+
raise typer.Exit(code=5) from None
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
@workspace_app.command("password")
|
|
297
|
+
def workspace_password(
|
|
298
|
+
ctx: typer.Context,
|
|
299
|
+
project: str = typer.Option(
|
|
300
|
+
...,
|
|
301
|
+
"--project",
|
|
302
|
+
help="Project alias",
|
|
303
|
+
),
|
|
304
|
+
workspace_id: int = typer.Option(
|
|
305
|
+
...,
|
|
306
|
+
"--workspace-id",
|
|
307
|
+
help="Workspace ID",
|
|
308
|
+
),
|
|
309
|
+
) -> None:
|
|
310
|
+
"""Reset workspace password and show the new one."""
|
|
311
|
+
formatter = get_formatter(ctx)
|
|
312
|
+
service = get_service(ctx, "workspace_service")
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
result = service.reset_password(alias=project, workspace_id=workspace_id)
|
|
316
|
+
formatter.output(
|
|
317
|
+
result,
|
|
318
|
+
lambda c, d: (
|
|
319
|
+
c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
320
|
+
c.print(f"\n[bold yellow]New Password:[/bold yellow] {d['password']}"),
|
|
321
|
+
),
|
|
322
|
+
)
|
|
323
|
+
except KeboolaApiError as exc:
|
|
324
|
+
exit_code = map_error_to_exit_code(exc)
|
|
325
|
+
formatter.error(
|
|
326
|
+
message=exc.message,
|
|
327
|
+
error_code=exc.error_code,
|
|
328
|
+
retryable=exc.retryable,
|
|
329
|
+
)
|
|
330
|
+
raise typer.Exit(code=exit_code) from None
|
|
331
|
+
except ConfigError as exc:
|
|
332
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
333
|
+
raise typer.Exit(code=5) from None
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
@workspace_app.command("load")
|
|
337
|
+
def workspace_load(
|
|
338
|
+
ctx: typer.Context,
|
|
339
|
+
project: str = typer.Option(
|
|
340
|
+
...,
|
|
341
|
+
"--project",
|
|
342
|
+
help="Project alias",
|
|
343
|
+
),
|
|
344
|
+
workspace_id: int = typer.Option(
|
|
345
|
+
...,
|
|
346
|
+
"--workspace-id",
|
|
347
|
+
help="Workspace ID",
|
|
348
|
+
),
|
|
349
|
+
tables: list[str] = typer.Option(
|
|
350
|
+
...,
|
|
351
|
+
"--tables",
|
|
352
|
+
help="Table ID to load (can be repeated, e.g. in.c-bucket.table-name)",
|
|
353
|
+
),
|
|
354
|
+
preserve: bool = typer.Option(
|
|
355
|
+
False,
|
|
356
|
+
"--preserve",
|
|
357
|
+
help="Keep existing tables in the workspace (default: clear before loading)",
|
|
358
|
+
),
|
|
359
|
+
) -> None:
|
|
360
|
+
"""Load tables into a workspace.
|
|
361
|
+
|
|
362
|
+
Waits for the async load job to complete.
|
|
363
|
+
"""
|
|
364
|
+
formatter = get_formatter(ctx)
|
|
365
|
+
service = get_service(ctx, "workspace_service")
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
result = service.load_tables(
|
|
369
|
+
alias=project, workspace_id=workspace_id, tables=tables, preserve=preserve
|
|
370
|
+
)
|
|
371
|
+
formatter.output(
|
|
372
|
+
result,
|
|
373
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
374
|
+
)
|
|
375
|
+
except KeboolaApiError as exc:
|
|
376
|
+
exit_code = map_error_to_exit_code(exc)
|
|
377
|
+
formatter.error(
|
|
378
|
+
message=exc.message,
|
|
379
|
+
error_code=exc.error_code,
|
|
380
|
+
retryable=exc.retryable,
|
|
381
|
+
)
|
|
382
|
+
raise typer.Exit(code=exit_code) from None
|
|
383
|
+
except ConfigError as exc:
|
|
384
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
385
|
+
raise typer.Exit(code=5) from None
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
@workspace_app.command("query")
|
|
389
|
+
def workspace_query(
|
|
390
|
+
ctx: typer.Context,
|
|
391
|
+
project: str = typer.Option(
|
|
392
|
+
...,
|
|
393
|
+
"--project",
|
|
394
|
+
help="Project alias",
|
|
395
|
+
),
|
|
396
|
+
workspace_id: int = typer.Option(
|
|
397
|
+
...,
|
|
398
|
+
"--workspace-id",
|
|
399
|
+
help="Workspace ID",
|
|
400
|
+
),
|
|
401
|
+
sql: str | None = typer.Option(
|
|
402
|
+
None,
|
|
403
|
+
"--sql",
|
|
404
|
+
help="SQL statement to execute",
|
|
405
|
+
),
|
|
406
|
+
file: Path | None = typer.Option(
|
|
407
|
+
None,
|
|
408
|
+
"--file",
|
|
409
|
+
help="Path to a .sql file to execute",
|
|
410
|
+
exists=True,
|
|
411
|
+
readable=True,
|
|
412
|
+
),
|
|
413
|
+
transactional: bool = typer.Option(
|
|
414
|
+
False,
|
|
415
|
+
"--transactional",
|
|
416
|
+
help="Wrap query in a transaction",
|
|
417
|
+
),
|
|
418
|
+
full: bool = typer.Option(
|
|
419
|
+
False,
|
|
420
|
+
"--full",
|
|
421
|
+
help="Fetch the complete result set via CSV export (slower). "
|
|
422
|
+
"Default fetches a fast inline page capped by --limit.",
|
|
423
|
+
),
|
|
424
|
+
limit: int = typer.Option(
|
|
425
|
+
QUERY_RESULTS_DEFAULT_LIMIT,
|
|
426
|
+
"--limit",
|
|
427
|
+
min=1,
|
|
428
|
+
help="Max rows to fetch via the fast inline path (ignored with --full).",
|
|
429
|
+
),
|
|
430
|
+
) -> None:
|
|
431
|
+
"""Execute SQL query in a workspace via Query Service.
|
|
432
|
+
|
|
433
|
+
Provide SQL via --sql or --file (exactly one required).
|
|
434
|
+
|
|
435
|
+
By default kbagent reads results inline (fast). For a result set larger than
|
|
436
|
+
--limit, pass --full to export the complete CSV instead.
|
|
437
|
+
"""
|
|
438
|
+
formatter = get_formatter(ctx)
|
|
439
|
+
service = get_service(ctx, "workspace_service")
|
|
440
|
+
|
|
441
|
+
# Validate: exactly one of --sql or --file
|
|
442
|
+
if sql and file:
|
|
443
|
+
formatter.error(
|
|
444
|
+
message="Specify either --sql or --file, not both.",
|
|
445
|
+
error_code=ErrorCode.USAGE_ERROR,
|
|
446
|
+
)
|
|
447
|
+
raise typer.Exit(code=2)
|
|
448
|
+
if not sql and not file:
|
|
449
|
+
formatter.error(
|
|
450
|
+
message="Specify either --sql or --file.",
|
|
451
|
+
error_code=ErrorCode.USAGE_ERROR,
|
|
452
|
+
)
|
|
453
|
+
raise typer.Exit(code=2)
|
|
454
|
+
|
|
455
|
+
# Read SQL from file if needed.
|
|
456
|
+
# After the guards above: either sql is truthy, or (not sql and file is non-None).
|
|
457
|
+
if sql:
|
|
458
|
+
effective_sql = sql
|
|
459
|
+
else:
|
|
460
|
+
assert file is not None # guaranteed: guard above exits if both sql and file absent
|
|
461
|
+
effective_sql = file.read_text(encoding="utf-8")
|
|
462
|
+
|
|
463
|
+
try:
|
|
464
|
+
result = service.execute_query(
|
|
465
|
+
alias=project,
|
|
466
|
+
workspace_id=workspace_id,
|
|
467
|
+
sql=effective_sql,
|
|
468
|
+
transactional=transactional,
|
|
469
|
+
full=full,
|
|
470
|
+
limit=limit,
|
|
471
|
+
)
|
|
472
|
+
if formatter.json_mode:
|
|
473
|
+
formatter.output(result)
|
|
474
|
+
else:
|
|
475
|
+
format_query_results(formatter.console, result)
|
|
476
|
+
except KeboolaApiError as exc:
|
|
477
|
+
exit_code = map_error_to_exit_code(exc)
|
|
478
|
+
formatter.error(
|
|
479
|
+
message=exc.message,
|
|
480
|
+
error_code=exc.error_code,
|
|
481
|
+
retryable=exc.retryable,
|
|
482
|
+
)
|
|
483
|
+
raise typer.Exit(code=exit_code) from None
|
|
484
|
+
except ConfigError as exc:
|
|
485
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
486
|
+
raise typer.Exit(code=5) from None
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
@workspace_app.command("gc")
|
|
490
|
+
def workspace_gc(
|
|
491
|
+
ctx: typer.Context,
|
|
492
|
+
project: list[str] | None = typer.Option(
|
|
493
|
+
None,
|
|
494
|
+
"--project",
|
|
495
|
+
help="Project alias to query (can be repeated). None = all projects.",
|
|
496
|
+
),
|
|
497
|
+
dry_run: bool = typer.Option(
|
|
498
|
+
False,
|
|
499
|
+
"--dry-run",
|
|
500
|
+
help="List orphaned workspaces without deleting them",
|
|
501
|
+
),
|
|
502
|
+
yes: bool = typer.Option(
|
|
503
|
+
False,
|
|
504
|
+
"--yes",
|
|
505
|
+
"-y",
|
|
506
|
+
help="Skip confirmation prompt",
|
|
507
|
+
),
|
|
508
|
+
) -> None:
|
|
509
|
+
"""Garbage-collect orphaned workspaces.
|
|
510
|
+
|
|
511
|
+
An orphaned workspace is one backed by keboola.sandboxes whose
|
|
512
|
+
sandbox config no longer exists. Running gc deletes those workspaces
|
|
513
|
+
(and any lingering sandbox configs). Use --dry-run to preview first.
|
|
514
|
+
"""
|
|
515
|
+
formatter = get_formatter(ctx)
|
|
516
|
+
service = get_service(ctx, "workspace_service")
|
|
517
|
+
|
|
518
|
+
if (
|
|
519
|
+
not dry_run
|
|
520
|
+
and not yes
|
|
521
|
+
and not formatter.json_mode
|
|
522
|
+
and not typer.confirm("Delete all orphaned workspaces in the selected project(s)?")
|
|
523
|
+
):
|
|
524
|
+
formatter.console.print("Aborted.")
|
|
525
|
+
raise typer.Exit(code=0)
|
|
526
|
+
|
|
527
|
+
try:
|
|
528
|
+
result = service.gc_workspaces(aliases=project, dry_run=dry_run)
|
|
529
|
+
except KeboolaApiError as exc:
|
|
530
|
+
exit_code = map_error_to_exit_code(exc)
|
|
531
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
532
|
+
raise typer.Exit(code=exit_code) from None
|
|
533
|
+
except ConfigError as exc:
|
|
534
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
535
|
+
raise typer.Exit(code=5) from None
|
|
536
|
+
|
|
537
|
+
if formatter.json_mode:
|
|
538
|
+
formatter.output(result)
|
|
539
|
+
else:
|
|
540
|
+
formatter.console.print(result.get("message", ""))
|
|
541
|
+
if dry_run:
|
|
542
|
+
would_delete = result.get("would_delete", [])
|
|
543
|
+
for ws in would_delete:
|
|
544
|
+
formatter.console.print(
|
|
545
|
+
f" [dim]would delete[/dim] workspace {ws['id']} "
|
|
546
|
+
f"([cyan]{escape(ws.get('name', ''))}[/cyan]) in '{escape(ws['project_alias'])}'"
|
|
547
|
+
)
|
|
548
|
+
else:
|
|
549
|
+
for ws in result.get("deleted", []):
|
|
550
|
+
formatter.console.print(
|
|
551
|
+
f" [green]deleted[/green] workspace {ws['id']} in '{escape(ws['project_alias'])}'"
|
|
552
|
+
)
|
|
553
|
+
for err in result.get("errors", []):
|
|
554
|
+
formatter.console.print(
|
|
555
|
+
f" [red]error[/red] workspace {err.get('workspace_id', '?')}: {escape(err.get('error', ''))}"
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
@workspace_app.command("from-transformation")
|
|
560
|
+
def workspace_from_transformation(
|
|
561
|
+
ctx: typer.Context,
|
|
562
|
+
project: str = typer.Option(
|
|
563
|
+
...,
|
|
564
|
+
"--project",
|
|
565
|
+
help="Project alias",
|
|
566
|
+
),
|
|
567
|
+
component_id: str = typer.Option(
|
|
568
|
+
...,
|
|
569
|
+
"--component-id",
|
|
570
|
+
help="Transformation component ID (e.g. keboola.snowflake-transformation)",
|
|
571
|
+
),
|
|
572
|
+
config_id: str = typer.Option(
|
|
573
|
+
...,
|
|
574
|
+
"--config-id",
|
|
575
|
+
help="Configuration ID",
|
|
576
|
+
),
|
|
577
|
+
row_id: str | None = typer.Option(
|
|
578
|
+
None,
|
|
579
|
+
"--row-id",
|
|
580
|
+
help="Optional row ID for row-based transformations",
|
|
581
|
+
),
|
|
582
|
+
backend: str | None = typer.Option(
|
|
583
|
+
None,
|
|
584
|
+
"--backend",
|
|
585
|
+
help="Workspace backend (auto-detected from project if omitted)",
|
|
586
|
+
),
|
|
587
|
+
) -> None:
|
|
588
|
+
"""Create a workspace from a transformation config.
|
|
589
|
+
|
|
590
|
+
Reads the transformation, creates a config-tied workspace, and loads
|
|
591
|
+
all input tables. Returns credentials ready for SQL debugging.
|
|
592
|
+
"""
|
|
593
|
+
formatter = get_formatter(ctx)
|
|
594
|
+
service = get_service(ctx, "workspace_service")
|
|
595
|
+
|
|
596
|
+
try:
|
|
597
|
+
result = service.create_from_transformation(
|
|
598
|
+
alias=project,
|
|
599
|
+
component_id=component_id,
|
|
600
|
+
config_id=config_id,
|
|
601
|
+
row_id=row_id,
|
|
602
|
+
backend=backend,
|
|
603
|
+
)
|
|
604
|
+
formatter.output(
|
|
605
|
+
result,
|
|
606
|
+
lambda c, d: (
|
|
607
|
+
c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
608
|
+
c.print(f"\n[bold]Workspace ID:[/bold] {d['workspace_id']}"),
|
|
609
|
+
c.print(f"[bold]Host:[/bold] {d['host']}"),
|
|
610
|
+
c.print(f"[bold]Schema:[/bold] {d['schema']}"),
|
|
611
|
+
c.print(f"[bold]User:[/bold] {d['user']}"),
|
|
612
|
+
c.print(
|
|
613
|
+
f"[bold yellow]Private key:[/bold yellow]\n{d['private_key']}"
|
|
614
|
+
if d.get("private_key")
|
|
615
|
+
else f"[bold yellow]Password:[/bold yellow] {d['password']}"
|
|
616
|
+
),
|
|
617
|
+
c.print(f"[bold]Tables loaded:[/bold] {', '.join(d.get('tables_loaded', []))}"),
|
|
618
|
+
c.print(
|
|
619
|
+
"\n[bold yellow]Warning:[/bold yellow] Save the private key now -- it cannot be retrieved later!"
|
|
620
|
+
if d.get("private_key")
|
|
621
|
+
else "\n[bold yellow]Warning:[/bold yellow] Save the password now -- it cannot be retrieved later!"
|
|
622
|
+
),
|
|
623
|
+
),
|
|
624
|
+
)
|
|
625
|
+
except KeboolaApiError as exc:
|
|
626
|
+
exit_code = map_error_to_exit_code(exc)
|
|
627
|
+
formatter.error(
|
|
628
|
+
message=exc.message,
|
|
629
|
+
error_code=exc.error_code,
|
|
630
|
+
retryable=exc.retryable,
|
|
631
|
+
)
|
|
632
|
+
raise typer.Exit(code=exit_code) from None
|
|
633
|
+
except ConfigError as exc:
|
|
634
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
635
|
+
raise typer.Exit(code=5) from None
|