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,584 @@
|
|
|
1
|
+
"""`kbagent dev-portal` — Developer Portal command surface.
|
|
2
|
+
|
|
3
|
+
Identity management mirrors `kbagent project`; portal writes are gated by
|
|
4
|
+
`require_random_code_confirmation()` from _helpers — there is no `--yes`
|
|
5
|
+
bypass and no env-var override.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import getpass
|
|
11
|
+
import sys
|
|
12
|
+
from enum import StrEnum
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
14
|
+
|
|
15
|
+
import typer
|
|
16
|
+
|
|
17
|
+
from ..errors import ConfigError, ErrorCode, KeboolaApiError
|
|
18
|
+
from ..models import DeveloperPortalIdentity
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from ..output import OutputFormatter
|
|
22
|
+
from ..services.dev_portal_service import PendingWrite
|
|
23
|
+
from ._helpers import (
|
|
24
|
+
check_cli_permission,
|
|
25
|
+
get_dev_portal_service,
|
|
26
|
+
get_formatter,
|
|
27
|
+
map_error_to_exit_code,
|
|
28
|
+
resolve_identity_alias,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# CLI-layer enforcement of the role_hint enum. The Pydantic validator on
|
|
33
|
+
# DeveloperPortalIdentity intentionally silent-downgrades unknown values to
|
|
34
|
+
# "vendor" for backwards compatibility with pre-0.51.1 config.json files
|
|
35
|
+
# that may carry arbitrary free-text strings. That tolerance is wrong at the
|
|
36
|
+
# CLI surface, where the user just typed a value RIGHT NOW -- a typo should
|
|
37
|
+
# fail loudly, not silently land as "vendor" and confuse the next operation.
|
|
38
|
+
# A StrEnum option type gives the Typer-level rejection (exit 2 + usage error)
|
|
39
|
+
# before any model construction.
|
|
40
|
+
class RoleHint(StrEnum):
|
|
41
|
+
vendor = "vendor"
|
|
42
|
+
admin = "admin"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
dev_portal_app = typer.Typer(
|
|
46
|
+
help="Keboola Developer Portal — multi-identity, production-safe writes.",
|
|
47
|
+
no_args_is_help=True,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
identity_app = typer.Typer(help="Manage Developer Portal identities (login credentials).")
|
|
51
|
+
dev_portal_app.add_typer(identity_app, name="identity")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dev_portal_app.callback()
|
|
55
|
+
def _dev_portal_callback(ctx: typer.Context) -> None:
|
|
56
|
+
"""Permission gate for `kbagent dev-portal …`."""
|
|
57
|
+
check_cli_permission(ctx, "dev-portal")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@identity_app.callback()
|
|
61
|
+
def _identity_callback(ctx: typer.Context) -> None:
|
|
62
|
+
"""Permission gate for `kbagent dev-portal identity …`."""
|
|
63
|
+
check_cli_permission(ctx, "dev-portal.identity")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _split_app(app: str) -> tuple[str, str]:
|
|
67
|
+
"""Split `VENDOR.APP_ID` into (vendor, app_id)."""
|
|
68
|
+
if "." not in app:
|
|
69
|
+
raise typer.BadParameter(
|
|
70
|
+
f"--app must be in VENDOR.APP_ID form (e.g. keboola.ex-foo), got: {app!r}"
|
|
71
|
+
)
|
|
72
|
+
vendor, _ = app.split(".", 1)
|
|
73
|
+
return vendor, app
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _read_password_stdin() -> str:
|
|
77
|
+
"""Read a password from stdin.
|
|
78
|
+
|
|
79
|
+
TTY -> getpass (hidden, line-based, Enter to confirm).
|
|
80
|
+
Pipe/redirected -> read to EOF, strip whitespace.
|
|
81
|
+
Using `sys.stdin.read()` unconditionally would hang interactively
|
|
82
|
+
until the user sent EOF (Ctrl-D); getpass on TTY fixes that.
|
|
83
|
+
"""
|
|
84
|
+
if sys.stdin.isatty():
|
|
85
|
+
return getpass.getpass("Password: ").strip()
|
|
86
|
+
return sys.stdin.read().strip()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ----- Identity subcommands -----
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@identity_app.command(
|
|
93
|
+
"add", help="Add a Developer Portal identity (verifies creds before persisting)."
|
|
94
|
+
)
|
|
95
|
+
def identity_add(
|
|
96
|
+
ctx: typer.Context,
|
|
97
|
+
alias: str = typer.Option(..., "--alias"),
|
|
98
|
+
username: str = typer.Option(..., "--username"),
|
|
99
|
+
password: str | None = typer.Option(None, "--password"),
|
|
100
|
+
password_stdin: bool = typer.Option(
|
|
101
|
+
False,
|
|
102
|
+
"--password-stdin",
|
|
103
|
+
help="Read password from stdin. On a TTY this is a hidden prompt (Enter to confirm); on a pipe it reads until EOF (e.g. `echo $PASS | … --password-stdin`).",
|
|
104
|
+
),
|
|
105
|
+
role_hint: RoleHint = typer.Option(
|
|
106
|
+
RoleHint.vendor,
|
|
107
|
+
"--role-hint",
|
|
108
|
+
help="Identity role: 'vendor' (default) or 'admin'. Routes write commands to different apps-api endpoints -- admin uses PATCH /admin/apps/{app} which accepts complexity/categories/forwardToken/processTimeout/etc. that the vendor endpoint forbids.",
|
|
109
|
+
),
|
|
110
|
+
vendor: str | None = typer.Option(None, "--vendor"),
|
|
111
|
+
portal_url: str = typer.Option(
|
|
112
|
+
"https://apps-api.keboola.com",
|
|
113
|
+
"--portal-url",
|
|
114
|
+
),
|
|
115
|
+
) -> None:
|
|
116
|
+
formatter = get_formatter(ctx)
|
|
117
|
+
if password_stdin:
|
|
118
|
+
password = _read_password_stdin()
|
|
119
|
+
if not password:
|
|
120
|
+
raise typer.BadParameter("Pass --password or --password-stdin.")
|
|
121
|
+
identity = DeveloperPortalIdentity(
|
|
122
|
+
username=username,
|
|
123
|
+
password=password,
|
|
124
|
+
role_hint=role_hint,
|
|
125
|
+
vendor=vendor,
|
|
126
|
+
portal_url=portal_url,
|
|
127
|
+
)
|
|
128
|
+
svc = get_dev_portal_service(ctx)
|
|
129
|
+
try:
|
|
130
|
+
svc.add_identity(alias, identity)
|
|
131
|
+
except (ConfigError, KeboolaApiError) as exc:
|
|
132
|
+
formatter.error(
|
|
133
|
+
message=str(exc),
|
|
134
|
+
error_code=getattr(exc, "error_code", ErrorCode.CONFIG_ERROR),
|
|
135
|
+
)
|
|
136
|
+
raise typer.Exit(
|
|
137
|
+
code=map_error_to_exit_code(exc) if isinstance(exc, KeboolaApiError) else 5
|
|
138
|
+
) from None
|
|
139
|
+
formatter.output({"status": "ok", "alias": alias, "username": username})
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@identity_app.command("list", help="List configured Developer Portal identities.")
|
|
143
|
+
def identity_list(ctx: typer.Context) -> None:
|
|
144
|
+
formatter = get_formatter(ctx)
|
|
145
|
+
svc = get_dev_portal_service(ctx)
|
|
146
|
+
identities = svc.list_identities()
|
|
147
|
+
default = svc.current_identity()
|
|
148
|
+
rows = [
|
|
149
|
+
{
|
|
150
|
+
"alias": alias,
|
|
151
|
+
"username": ident.username,
|
|
152
|
+
"vendor": ident.vendor or "",
|
|
153
|
+
"role_hint": ident.role_hint,
|
|
154
|
+
"portal_url": ident.portal_url,
|
|
155
|
+
"default": alias == default,
|
|
156
|
+
}
|
|
157
|
+
for alias, ident in identities.items()
|
|
158
|
+
]
|
|
159
|
+
formatter.output(rows)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@identity_app.command("remove", help="Remove a Developer Portal identity.")
|
|
163
|
+
def identity_remove(
|
|
164
|
+
ctx: typer.Context,
|
|
165
|
+
alias: str = typer.Option(..., "--alias"),
|
|
166
|
+
) -> None:
|
|
167
|
+
formatter = get_formatter(ctx)
|
|
168
|
+
svc = get_dev_portal_service(ctx)
|
|
169
|
+
try:
|
|
170
|
+
svc.remove_identity(alias)
|
|
171
|
+
except ConfigError as exc:
|
|
172
|
+
formatter.error(message=str(exc), error_code=ErrorCode.CONFIG_ERROR)
|
|
173
|
+
raise typer.Exit(code=5) from None
|
|
174
|
+
formatter.output({"status": "ok", "removed": alias})
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@identity_app.command("edit", help="Edit fields on a Developer Portal identity (or rename it).")
|
|
178
|
+
def identity_edit(
|
|
179
|
+
ctx: typer.Context,
|
|
180
|
+
alias: str = typer.Option(..., "--alias"),
|
|
181
|
+
username: str | None = typer.Option(None, "--username"),
|
|
182
|
+
password: str | None = typer.Option(None, "--password"),
|
|
183
|
+
password_stdin: bool = typer.Option(False, "--password-stdin"),
|
|
184
|
+
role_hint: RoleHint | None = typer.Option(
|
|
185
|
+
None,
|
|
186
|
+
"--role-hint",
|
|
187
|
+
),
|
|
188
|
+
vendor: str | None = typer.Option(None, "--vendor"),
|
|
189
|
+
new_alias: str | None = typer.Option(None, "--new-alias"),
|
|
190
|
+
) -> None:
|
|
191
|
+
formatter = get_formatter(ctx)
|
|
192
|
+
svc = get_dev_portal_service(ctx)
|
|
193
|
+
if password_stdin:
|
|
194
|
+
password = _read_password_stdin()
|
|
195
|
+
try:
|
|
196
|
+
if new_alias:
|
|
197
|
+
svc.rename_identity(alias, new_alias)
|
|
198
|
+
alias = new_alias
|
|
199
|
+
svc.edit_identity(
|
|
200
|
+
alias,
|
|
201
|
+
username=username,
|
|
202
|
+
password=password,
|
|
203
|
+
role_hint=role_hint,
|
|
204
|
+
vendor=vendor,
|
|
205
|
+
)
|
|
206
|
+
except ConfigError as exc:
|
|
207
|
+
formatter.error(message=str(exc), error_code=ErrorCode.CONFIG_ERROR)
|
|
208
|
+
raise typer.Exit(code=5) from None
|
|
209
|
+
formatter.output({"status": "ok", "alias": alias})
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@identity_app.command("use", help="Set the default Developer Portal identity.")
|
|
213
|
+
def identity_use(
|
|
214
|
+
ctx: typer.Context,
|
|
215
|
+
alias: str = typer.Argument(..., help="Identity alias to set as default"),
|
|
216
|
+
) -> None:
|
|
217
|
+
formatter = get_formatter(ctx)
|
|
218
|
+
svc = get_dev_portal_service(ctx)
|
|
219
|
+
try:
|
|
220
|
+
svc.use_identity(alias)
|
|
221
|
+
except ConfigError as exc:
|
|
222
|
+
formatter.error(message=str(exc), error_code=ErrorCode.CONFIG_ERROR)
|
|
223
|
+
raise typer.Exit(code=5) from None
|
|
224
|
+
formatter.output({"status": "ok", "default": alias})
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@identity_app.command("current", help="Show the alias of the default Developer Portal identity.")
|
|
228
|
+
def identity_current(ctx: typer.Context) -> None:
|
|
229
|
+
formatter = get_formatter(ctx)
|
|
230
|
+
svc = get_dev_portal_service(ctx)
|
|
231
|
+
formatter.output({"default": svc.current_identity()})
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@identity_app.command("verify", help="Probe a Developer Portal identity by logging in.")
|
|
235
|
+
def identity_verify(
|
|
236
|
+
ctx: typer.Context,
|
|
237
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
238
|
+
) -> None:
|
|
239
|
+
formatter = get_formatter(ctx)
|
|
240
|
+
svc = get_dev_portal_service(ctx)
|
|
241
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
242
|
+
try:
|
|
243
|
+
info = svc.verify_identity(alias)
|
|
244
|
+
except KeboolaApiError as exc:
|
|
245
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
246
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
247
|
+
formatter.output({"status": "ok", **info})
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# ----- Read commands -----
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@dev_portal_app.command("list", help="List Developer Portal apps for a vendor.")
|
|
254
|
+
def list_apps(
|
|
255
|
+
ctx: typer.Context,
|
|
256
|
+
vendor: str = typer.Option(..., "--vendor"),
|
|
257
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
258
|
+
) -> None:
|
|
259
|
+
formatter = get_formatter(ctx)
|
|
260
|
+
svc = get_dev_portal_service(ctx)
|
|
261
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
262
|
+
try:
|
|
263
|
+
apps = svc.list_apps(alias, vendor)
|
|
264
|
+
except KeboolaApiError as exc:
|
|
265
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
266
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
267
|
+
formatter.output(apps)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@dev_portal_app.command("get", help="Show the full Developer Portal entry for one app.")
|
|
271
|
+
def get_app_cmd(
|
|
272
|
+
ctx: typer.Context,
|
|
273
|
+
app: str = typer.Option(..., "--app", help="VENDOR.APP_ID, e.g. keboola.ex-foo"),
|
|
274
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
275
|
+
) -> None:
|
|
276
|
+
formatter = get_formatter(ctx)
|
|
277
|
+
svc = get_dev_portal_service(ctx)
|
|
278
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
279
|
+
vendor, app_id = _split_app(app)
|
|
280
|
+
try:
|
|
281
|
+
result = svc.get_app(alias, vendor, app_id)
|
|
282
|
+
except KeboolaApiError as exc:
|
|
283
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
284
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
285
|
+
formatter.output(result)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# ----- Write commands -----
|
|
289
|
+
|
|
290
|
+
import json # noqa: E402
|
|
291
|
+
from dataclasses import asdict # noqa: E402
|
|
292
|
+
from pathlib import Path # noqa: E402
|
|
293
|
+
|
|
294
|
+
from ..constants import EXIT_PERMISSION_DENIED # noqa: E402
|
|
295
|
+
from ._helpers import require_random_code_confirmation # noqa: E402
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _assert_tty(action_description: str) -> None:
|
|
299
|
+
"""Refuse immediately on non-TTY; called before any payload I/O.
|
|
300
|
+
|
|
301
|
+
This is the *first* guard in every write command so that CI/CD shells
|
|
302
|
+
and AI agents are rejected before any file or stdin access happens.
|
|
303
|
+
The full random-code prompt fires later (after the preview) on TTY.
|
|
304
|
+
"""
|
|
305
|
+
is_tty = hasattr(sys.stdin, "isatty") and sys.stdin.isatty()
|
|
306
|
+
if not is_tty:
|
|
307
|
+
sys.stderr.write(
|
|
308
|
+
f"\nRefusing to {action_description}: this action requires a "
|
|
309
|
+
"real terminal so a human can type the confirmation code. "
|
|
310
|
+
"There is no --yes bypass by design.\n"
|
|
311
|
+
)
|
|
312
|
+
raise typer.Exit(code=EXIT_PERMISSION_DENIED)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _load_payload(data: str | None) -> dict:
|
|
316
|
+
if data is None:
|
|
317
|
+
raise typer.BadParameter("--data is required")
|
|
318
|
+
if data == "-":
|
|
319
|
+
return json.loads(sys.stdin.read())
|
|
320
|
+
return json.loads(Path(data).read_text())
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _render_pending(formatter: OutputFormatter, pending: PendingWrite) -> None:
|
|
324
|
+
"""Write a stderr-only preview of the pending write."""
|
|
325
|
+
from ..services.dev_portal_service import (
|
|
326
|
+
PendingCreate,
|
|
327
|
+
PendingDeprecate,
|
|
328
|
+
PendingIconUpload,
|
|
329
|
+
PendingPatch,
|
|
330
|
+
PendingPublish,
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
err = formatter.err_console
|
|
334
|
+
if isinstance(pending, PendingPatch):
|
|
335
|
+
err.print(f"[bold]PATCH[/bold] /vendors/{pending.vendor}/apps/{pending.app_id}")
|
|
336
|
+
for d in pending.diff:
|
|
337
|
+
err.print(f" [yellow]{d.key}[/yellow]: {d.current!r} -> {d.new!r}")
|
|
338
|
+
if not pending.diff:
|
|
339
|
+
err.print(" [dim]no field-level changes (payload matches current state)[/dim]")
|
|
340
|
+
elif isinstance(pending, PendingCreate):
|
|
341
|
+
err.print(f"[bold]POST[/bold] /vendors/{pending.vendor}/apps")
|
|
342
|
+
err.print_json(json.dumps(pending.payload))
|
|
343
|
+
elif isinstance(pending, PendingIconUpload):
|
|
344
|
+
err.print(
|
|
345
|
+
f"[bold]UPLOAD ICON[/bold] {pending.png_path} -> "
|
|
346
|
+
f"{pending.vendor}/{pending.app_id} ({len(pending.png_bytes)} bytes)"
|
|
347
|
+
)
|
|
348
|
+
elif isinstance(pending, PendingPublish):
|
|
349
|
+
err.print(
|
|
350
|
+
f"[bold red]PUBLISH[/bold red] /vendors/{pending.vendor}/apps/"
|
|
351
|
+
f"{pending.app_id}/publish (requests Keboola review)"
|
|
352
|
+
)
|
|
353
|
+
elif isinstance(pending, PendingDeprecate):
|
|
354
|
+
err.print(
|
|
355
|
+
f"[bold red]DEPRECATE[/bold red] /vendors/{pending.vendor}/apps/"
|
|
356
|
+
f"{pending.app_id}/deprecate (hides app, blocks new configs)"
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _pending_as_json(pending: PendingWrite) -> dict[str, Any]:
|
|
361
|
+
"""Serialise a pending write for --json --dry-run output."""
|
|
362
|
+
raw = asdict(pending)
|
|
363
|
+
if "png_bytes" in raw:
|
|
364
|
+
raw["png_bytes"] = f"<{len(raw['png_bytes'])} bytes>"
|
|
365
|
+
if "png_path" in raw:
|
|
366
|
+
raw["png_path"] = str(raw["png_path"])
|
|
367
|
+
return {"status": "dry-run", "pending": raw}
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@dev_portal_app.command(
|
|
371
|
+
"create",
|
|
372
|
+
help="Create (register) a new app in the Developer Portal. Requires TTY confirm; --dry-run for preview.",
|
|
373
|
+
)
|
|
374
|
+
def create_cmd(
|
|
375
|
+
ctx: typer.Context,
|
|
376
|
+
vendor: str = typer.Option(..., "--vendor"),
|
|
377
|
+
data: str = typer.Option(..., "--data", help="Path to JSON payload, or '-' for stdin"),
|
|
378
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
379
|
+
dry_run: bool = typer.Option(False, "--dry-run"),
|
|
380
|
+
) -> None:
|
|
381
|
+
if not dry_run:
|
|
382
|
+
_assert_tty(f"create app in vendor '{vendor}'")
|
|
383
|
+
formatter = get_formatter(ctx)
|
|
384
|
+
svc = get_dev_portal_service(ctx)
|
|
385
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
386
|
+
try:
|
|
387
|
+
pending = svc.prepare_create(alias, vendor, _load_payload(data))
|
|
388
|
+
except KeboolaApiError as exc:
|
|
389
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
390
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
391
|
+
_render_pending(formatter, pending)
|
|
392
|
+
if dry_run:
|
|
393
|
+
formatter.output(_pending_as_json(pending))
|
|
394
|
+
return
|
|
395
|
+
require_random_code_confirmation(f"create app in vendor '{vendor}'")
|
|
396
|
+
try:
|
|
397
|
+
result = svc.apply(pending)
|
|
398
|
+
except KeboolaApiError as exc:
|
|
399
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
400
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
401
|
+
formatter.output({"status": "ok", "created": result})
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
@dev_portal_app.command(
|
|
405
|
+
"patch",
|
|
406
|
+
help="Patch one or more properties of an existing Developer Portal app. Requires TTY confirm; --dry-run for preview.",
|
|
407
|
+
)
|
|
408
|
+
def patch_cmd(
|
|
409
|
+
ctx: typer.Context,
|
|
410
|
+
app: str = typer.Option(..., "--app"),
|
|
411
|
+
data: str | None = typer.Option(None, "--data"),
|
|
412
|
+
property_: str | None = typer.Option(None, "--property"),
|
|
413
|
+
value: str | None = typer.Option(None, "--value"),
|
|
414
|
+
value_file: str | None = typer.Option(None, "--value-file"),
|
|
415
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
416
|
+
dry_run: bool = typer.Option(
|
|
417
|
+
False,
|
|
418
|
+
"--dry-run",
|
|
419
|
+
help=(
|
|
420
|
+
"Preview the diff without writing. NOTE: still logs in and GETs the "
|
|
421
|
+
"current app to compute the diff, so it needs portal connectivity; "
|
|
422
|
+
"on a personal (MFA) identity it will prompt for an MFA code. Use a "
|
|
423
|
+
"service.{vendor}.{id} identity for a fully non-interactive preview."
|
|
424
|
+
),
|
|
425
|
+
),
|
|
426
|
+
) -> None:
|
|
427
|
+
if not dry_run:
|
|
428
|
+
_assert_tty(f"patch {app}")
|
|
429
|
+
formatter = get_formatter(ctx)
|
|
430
|
+
svc = get_dev_portal_service(ctx)
|
|
431
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
432
|
+
vendor, app_id = _split_app(app)
|
|
433
|
+
|
|
434
|
+
if data:
|
|
435
|
+
payload = _load_payload(data)
|
|
436
|
+
elif property_:
|
|
437
|
+
if value_file:
|
|
438
|
+
raw = Path(value_file).read_text()
|
|
439
|
+
elif value is not None:
|
|
440
|
+
raw = value
|
|
441
|
+
else:
|
|
442
|
+
raise typer.BadParameter("--property requires --value or --value-file")
|
|
443
|
+
try:
|
|
444
|
+
parsed = json.loads(raw) if raw.strip()[:1] in "[{" else raw
|
|
445
|
+
except json.JSONDecodeError:
|
|
446
|
+
parsed = raw
|
|
447
|
+
payload = {property_: parsed}
|
|
448
|
+
else:
|
|
449
|
+
raise typer.BadParameter("Provide --data, or --property with --value/--value-file")
|
|
450
|
+
|
|
451
|
+
try:
|
|
452
|
+
pending = svc.prepare_patch(alias, vendor, app_id, payload)
|
|
453
|
+
except KeboolaApiError as exc:
|
|
454
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
455
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
456
|
+
_render_pending(formatter, pending)
|
|
457
|
+
if dry_run:
|
|
458
|
+
formatter.output(_pending_as_json(pending))
|
|
459
|
+
return
|
|
460
|
+
require_random_code_confirmation(f"patch {app}")
|
|
461
|
+
try:
|
|
462
|
+
svc.apply(pending)
|
|
463
|
+
except KeboolaApiError as exc:
|
|
464
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
465
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
466
|
+
formatter.output(
|
|
467
|
+
{
|
|
468
|
+
"status": "ok",
|
|
469
|
+
"app": app,
|
|
470
|
+
"patched_keys": [d.key for d in pending.diff],
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
@dev_portal_app.command(
|
|
476
|
+
"upload-icon",
|
|
477
|
+
help="Upload a 128x128 PNG icon for a Developer Portal app. Requires TTY confirm; --dry-run for preview.",
|
|
478
|
+
)
|
|
479
|
+
def upload_icon_cmd(
|
|
480
|
+
ctx: typer.Context,
|
|
481
|
+
app: str = typer.Option(..., "--app"),
|
|
482
|
+
file: str = typer.Option(..., "--file"),
|
|
483
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
484
|
+
dry_run: bool = typer.Option(False, "--dry-run"),
|
|
485
|
+
) -> None:
|
|
486
|
+
if not dry_run:
|
|
487
|
+
_assert_tty(f"upload icon for {app}")
|
|
488
|
+
formatter = get_formatter(ctx)
|
|
489
|
+
svc = get_dev_portal_service(ctx)
|
|
490
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
491
|
+
vendor, app_id = _split_app(app)
|
|
492
|
+
try:
|
|
493
|
+
pending = svc.prepare_upload_icon(alias, vendor, app_id, file)
|
|
494
|
+
except KeboolaApiError as exc:
|
|
495
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
496
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
497
|
+
_render_pending(formatter, pending)
|
|
498
|
+
if dry_run:
|
|
499
|
+
formatter.output(_pending_as_json(pending))
|
|
500
|
+
return
|
|
501
|
+
require_random_code_confirmation(f"upload icon for {app}")
|
|
502
|
+
try:
|
|
503
|
+
result = svc.apply(pending)
|
|
504
|
+
except KeboolaApiError as exc:
|
|
505
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
506
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
507
|
+
formatter.output(result)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
@dev_portal_app.command(
|
|
511
|
+
"publish",
|
|
512
|
+
help="Publish an app in the Developer Portal (requests Keboola review). Requires TTY confirm; --dry-run for preview.",
|
|
513
|
+
)
|
|
514
|
+
def publish_cmd(
|
|
515
|
+
ctx: typer.Context,
|
|
516
|
+
app: str = typer.Option(..., "--app"),
|
|
517
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
518
|
+
dry_run: bool = typer.Option(
|
|
519
|
+
False,
|
|
520
|
+
"--dry-run",
|
|
521
|
+
help=(
|
|
522
|
+
"Preview without writing. NOTE: still logs in and GETs the app to "
|
|
523
|
+
"run the publish pre-flight check, so it needs portal connectivity; "
|
|
524
|
+
"a personal (MFA) identity will prompt for an MFA code. Use a "
|
|
525
|
+
"service.{vendor}.{id} identity for a non-interactive preview."
|
|
526
|
+
),
|
|
527
|
+
),
|
|
528
|
+
) -> None:
|
|
529
|
+
if not dry_run:
|
|
530
|
+
_assert_tty(f"publish {app}")
|
|
531
|
+
formatter = get_formatter(ctx)
|
|
532
|
+
svc = get_dev_portal_service(ctx)
|
|
533
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
534
|
+
vendor, app_id = _split_app(app)
|
|
535
|
+
try:
|
|
536
|
+
pending = svc.prepare_publish(alias, vendor, app_id)
|
|
537
|
+
except KeboolaApiError as exc:
|
|
538
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
539
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
540
|
+
_render_pending(formatter, pending)
|
|
541
|
+
if dry_run:
|
|
542
|
+
formatter.output(_pending_as_json(pending))
|
|
543
|
+
return
|
|
544
|
+
require_random_code_confirmation(f"publish {app}")
|
|
545
|
+
try:
|
|
546
|
+
result = svc.apply(pending)
|
|
547
|
+
except KeboolaApiError as exc:
|
|
548
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
549
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
550
|
+
formatter.output({"status": "ok", "published": result})
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
@dev_portal_app.command(
|
|
554
|
+
"deprecate",
|
|
555
|
+
help="Deprecate an app in the Developer Portal (hides it, blocks new configs). Requires TTY confirm; --dry-run for preview.",
|
|
556
|
+
)
|
|
557
|
+
def deprecate_cmd(
|
|
558
|
+
ctx: typer.Context,
|
|
559
|
+
app: str = typer.Option(..., "--app"),
|
|
560
|
+
identity: str | None = typer.Option(None, "--identity"),
|
|
561
|
+
dry_run: bool = typer.Option(False, "--dry-run"),
|
|
562
|
+
) -> None:
|
|
563
|
+
if not dry_run:
|
|
564
|
+
_assert_tty(f"deprecate {app}")
|
|
565
|
+
formatter = get_formatter(ctx)
|
|
566
|
+
svc = get_dev_portal_service(ctx)
|
|
567
|
+
alias = resolve_identity_alias(ctx, identity)
|
|
568
|
+
vendor, app_id = _split_app(app)
|
|
569
|
+
try:
|
|
570
|
+
pending = svc.prepare_deprecate(alias, vendor, app_id)
|
|
571
|
+
except KeboolaApiError as exc:
|
|
572
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
573
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
574
|
+
_render_pending(formatter, pending)
|
|
575
|
+
if dry_run:
|
|
576
|
+
formatter.output(_pending_as_json(pending))
|
|
577
|
+
return
|
|
578
|
+
require_random_code_confirmation(f"deprecate {app}")
|
|
579
|
+
try:
|
|
580
|
+
result = svc.apply(pending)
|
|
581
|
+
except KeboolaApiError as exc:
|
|
582
|
+
formatter.error(message=str(exc), error_code=exc.error_code)
|
|
583
|
+
raise typer.Exit(code=map_error_to_exit_code(exc)) from None
|
|
584
|
+
formatter.output({"status": "ok", "deprecated": result})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Doctor command - thin CLI wrapper over DoctorService.
|
|
2
|
+
|
|
3
|
+
Delegates all health check logic to DoctorService (3-layer architecture).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
from ..output import format_doctor_panel
|
|
10
|
+
from ._helpers import get_formatter, get_service
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def doctor_command(
|
|
14
|
+
ctx: typer.Context,
|
|
15
|
+
fix: bool = typer.Option(
|
|
16
|
+
False,
|
|
17
|
+
"--fix",
|
|
18
|
+
help="Auto-fix issues: install MCP server binary for faster startup.",
|
|
19
|
+
),
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Run health checks on CLI configuration and project connectivity."""
|
|
22
|
+
formatter = get_formatter(ctx)
|
|
23
|
+
doctor_service = get_service(ctx, "doctor_service")
|
|
24
|
+
|
|
25
|
+
# If --fix, run warmup before checks
|
|
26
|
+
if fix:
|
|
27
|
+
console = Console()
|
|
28
|
+
console.print("[bold]Running auto-fix...[/bold]")
|
|
29
|
+
warmup_result = doctor_service.warmup()
|
|
30
|
+
if warmup_result["installed"]:
|
|
31
|
+
console.print(f"[green]OK[/green] {warmup_result['message']}")
|
|
32
|
+
else:
|
|
33
|
+
console.print(f"[dim]{warmup_result['message']}[/dim]")
|
|
34
|
+
console.print()
|
|
35
|
+
|
|
36
|
+
result = doctor_service.run_checks()
|
|
37
|
+
formatter.output(result, format_doctor_panel)
|