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,423 @@
|
|
|
1
|
+
"""Branch commands - list, create, use, reset, delete, and merge development branches.
|
|
2
|
+
|
|
3
|
+
Thin CLI layer: parses arguments, calls BranchService, formats output.
|
|
4
|
+
No business logic belongs here.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from ..errors import ConfigError, ErrorCode, KeboolaApiError
|
|
12
|
+
from ..output import format_branch_metadata_table, format_branches_table
|
|
13
|
+
from ._helpers import (
|
|
14
|
+
check_cli_permission,
|
|
15
|
+
emit_project_warnings,
|
|
16
|
+
get_formatter,
|
|
17
|
+
get_service,
|
|
18
|
+
map_error_to_exit_code,
|
|
19
|
+
)
|
|
20
|
+
from ._metadata_input import resolve_text_input
|
|
21
|
+
|
|
22
|
+
branch_app = typer.Typer(help="Manage development branches")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@branch_app.callback(invoke_without_command=True)
|
|
26
|
+
def _branch_permission_check(ctx: typer.Context) -> None:
|
|
27
|
+
check_cli_permission(ctx, "branch")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@branch_app.command("list")
|
|
31
|
+
def branch_list(
|
|
32
|
+
ctx: typer.Context,
|
|
33
|
+
project: list[str] | None = typer.Option(
|
|
34
|
+
None,
|
|
35
|
+
"--project",
|
|
36
|
+
help="Project alias to query (can be repeated for multiple projects)",
|
|
37
|
+
),
|
|
38
|
+
) -> None:
|
|
39
|
+
"""List development branches from connected projects."""
|
|
40
|
+
formatter = get_formatter(ctx)
|
|
41
|
+
service = get_service(ctx, "branch_service")
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
result = service.list_branches(aliases=project)
|
|
45
|
+
except ConfigError as exc:
|
|
46
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
47
|
+
raise typer.Exit(code=5) from None
|
|
48
|
+
|
|
49
|
+
if formatter.json_mode:
|
|
50
|
+
formatter.output(result)
|
|
51
|
+
else:
|
|
52
|
+
format_branches_table(formatter.console, result)
|
|
53
|
+
emit_project_warnings(formatter, result)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@branch_app.command("create")
|
|
57
|
+
def branch_create(
|
|
58
|
+
ctx: typer.Context,
|
|
59
|
+
project: str = typer.Option(
|
|
60
|
+
...,
|
|
61
|
+
"--project",
|
|
62
|
+
help="Project alias to create the branch in",
|
|
63
|
+
),
|
|
64
|
+
name: str = typer.Option(
|
|
65
|
+
...,
|
|
66
|
+
"--name",
|
|
67
|
+
help="Name for the new development branch",
|
|
68
|
+
),
|
|
69
|
+
description: str = typer.Option(
|
|
70
|
+
"",
|
|
71
|
+
"--description",
|
|
72
|
+
help="Optional description for the branch",
|
|
73
|
+
),
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Create a new development branch and auto-activate it.
|
|
76
|
+
|
|
77
|
+
The created branch becomes the active branch for the project,
|
|
78
|
+
so subsequent tool calls will automatically use it.
|
|
79
|
+
"""
|
|
80
|
+
formatter = get_formatter(ctx)
|
|
81
|
+
service = get_service(ctx, "branch_service")
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
result = service.create_branch(alias=project, name=name, description=description)
|
|
85
|
+
formatter.output(
|
|
86
|
+
result,
|
|
87
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
88
|
+
)
|
|
89
|
+
except KeboolaApiError as exc:
|
|
90
|
+
exit_code = map_error_to_exit_code(exc)
|
|
91
|
+
formatter.error(
|
|
92
|
+
message=exc.message,
|
|
93
|
+
error_code=exc.error_code,
|
|
94
|
+
retryable=exc.retryable,
|
|
95
|
+
)
|
|
96
|
+
raise typer.Exit(code=exit_code) from None
|
|
97
|
+
except ConfigError as exc:
|
|
98
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
99
|
+
raise typer.Exit(code=5) from None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@branch_app.command("use")
|
|
103
|
+
def branch_use(
|
|
104
|
+
ctx: typer.Context,
|
|
105
|
+
project: str = typer.Option(
|
|
106
|
+
...,
|
|
107
|
+
"--project",
|
|
108
|
+
help="Project alias to set the active branch for",
|
|
109
|
+
),
|
|
110
|
+
branch: int = typer.Option(
|
|
111
|
+
...,
|
|
112
|
+
"--branch",
|
|
113
|
+
help="Branch ID to activate",
|
|
114
|
+
),
|
|
115
|
+
) -> None:
|
|
116
|
+
"""Set an existing development branch as active.
|
|
117
|
+
|
|
118
|
+
Validates the branch exists via the API before activating it.
|
|
119
|
+
Subsequent tool calls will automatically use this branch.
|
|
120
|
+
"""
|
|
121
|
+
formatter = get_formatter(ctx)
|
|
122
|
+
service = get_service(ctx, "branch_service")
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
result = service.set_active_branch(alias=project, branch_id=branch)
|
|
126
|
+
formatter.output(
|
|
127
|
+
result,
|
|
128
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
129
|
+
)
|
|
130
|
+
except KeboolaApiError as exc:
|
|
131
|
+
exit_code = map_error_to_exit_code(exc)
|
|
132
|
+
formatter.error(
|
|
133
|
+
message=exc.message,
|
|
134
|
+
error_code=exc.error_code,
|
|
135
|
+
retryable=exc.retryable,
|
|
136
|
+
)
|
|
137
|
+
raise typer.Exit(code=exit_code) from None
|
|
138
|
+
except ConfigError as exc:
|
|
139
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
140
|
+
raise typer.Exit(code=5) from None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@branch_app.command("reset")
|
|
144
|
+
def branch_reset(
|
|
145
|
+
ctx: typer.Context,
|
|
146
|
+
project: str = typer.Option(
|
|
147
|
+
...,
|
|
148
|
+
"--project",
|
|
149
|
+
help="Project alias to reset the active branch for",
|
|
150
|
+
),
|
|
151
|
+
) -> None:
|
|
152
|
+
"""Reset the active branch back to main/production.
|
|
153
|
+
|
|
154
|
+
Clears the active development branch so subsequent tool calls
|
|
155
|
+
operate on the main branch.
|
|
156
|
+
"""
|
|
157
|
+
formatter = get_formatter(ctx)
|
|
158
|
+
service = get_service(ctx, "branch_service")
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
result = service.reset_branch(alias=project)
|
|
162
|
+
formatter.output(
|
|
163
|
+
result,
|
|
164
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
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
|
+
|
|
170
|
+
|
|
171
|
+
@branch_app.command("delete")
|
|
172
|
+
def branch_delete(
|
|
173
|
+
ctx: typer.Context,
|
|
174
|
+
project: str = typer.Option(
|
|
175
|
+
...,
|
|
176
|
+
"--project",
|
|
177
|
+
help="Project alias to delete the branch from",
|
|
178
|
+
),
|
|
179
|
+
branch: int = typer.Option(
|
|
180
|
+
...,
|
|
181
|
+
"--branch",
|
|
182
|
+
help="Branch ID to delete",
|
|
183
|
+
),
|
|
184
|
+
) -> None:
|
|
185
|
+
"""Delete a development branch.
|
|
186
|
+
|
|
187
|
+
If the deleted branch was the active branch, it is automatically
|
|
188
|
+
reset to main/production.
|
|
189
|
+
"""
|
|
190
|
+
formatter = get_formatter(ctx)
|
|
191
|
+
service = get_service(ctx, "branch_service")
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
result = service.delete_branch(alias=project, branch_id=branch)
|
|
195
|
+
formatter.output(
|
|
196
|
+
result,
|
|
197
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
198
|
+
)
|
|
199
|
+
except KeboolaApiError as exc:
|
|
200
|
+
exit_code = map_error_to_exit_code(exc)
|
|
201
|
+
formatter.error(
|
|
202
|
+
message=exc.message,
|
|
203
|
+
error_code=exc.error_code,
|
|
204
|
+
retryable=exc.retryable,
|
|
205
|
+
)
|
|
206
|
+
raise typer.Exit(code=exit_code) from None
|
|
207
|
+
except ConfigError as exc:
|
|
208
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
209
|
+
raise typer.Exit(code=5) from None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@branch_app.command("merge")
|
|
213
|
+
def branch_merge(
|
|
214
|
+
ctx: typer.Context,
|
|
215
|
+
project: str = typer.Option(
|
|
216
|
+
...,
|
|
217
|
+
"--project",
|
|
218
|
+
help="Project alias",
|
|
219
|
+
),
|
|
220
|
+
branch: int | None = typer.Option(
|
|
221
|
+
None,
|
|
222
|
+
"--branch",
|
|
223
|
+
help="Branch ID to merge (uses active branch if not set)",
|
|
224
|
+
),
|
|
225
|
+
) -> None:
|
|
226
|
+
"""Get the KBC UI merge URL for a development branch.
|
|
227
|
+
|
|
228
|
+
Does NOT perform the merge via API. Instead, generates the URL
|
|
229
|
+
to the Keboola UI where you can review and merge safely.
|
|
230
|
+
After displaying the URL, resets the active branch to main.
|
|
231
|
+
"""
|
|
232
|
+
formatter = get_formatter(ctx)
|
|
233
|
+
service = get_service(ctx, "branch_service")
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
result = service.get_merge_url(alias=project, branch_id=branch)
|
|
237
|
+
formatter.output(
|
|
238
|
+
result,
|
|
239
|
+
lambda c, d: (
|
|
240
|
+
c.print(f"\n[bold]Merge URL:[/bold] {d['url']}"),
|
|
241
|
+
c.print(f"\n{d['message']}"),
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
except ConfigError as exc:
|
|
245
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
246
|
+
raise typer.Exit(code=5) from None
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ── Branch metadata commands ──────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@branch_app.command("metadata-list")
|
|
253
|
+
def branch_metadata_list(
|
|
254
|
+
ctx: typer.Context,
|
|
255
|
+
project: str = typer.Option(
|
|
256
|
+
...,
|
|
257
|
+
"--project",
|
|
258
|
+
help="Project alias to query",
|
|
259
|
+
),
|
|
260
|
+
branch: str = typer.Option(
|
|
261
|
+
"default",
|
|
262
|
+
"--branch",
|
|
263
|
+
help='Branch ID or "default" for the main branch',
|
|
264
|
+
),
|
|
265
|
+
) -> None:
|
|
266
|
+
"""List all metadata entries on a branch.
|
|
267
|
+
|
|
268
|
+
Metadata lives on a branch (not on the project) and is keyed by
|
|
269
|
+
arbitrary strings like ``KBC.projectDescription``.
|
|
270
|
+
"""
|
|
271
|
+
formatter = get_formatter(ctx)
|
|
272
|
+
service = get_service(ctx, "branch_service")
|
|
273
|
+
|
|
274
|
+
try:
|
|
275
|
+
result = service.list_branch_metadata(alias=project, branch_id=branch)
|
|
276
|
+
except KeboolaApiError as exc:
|
|
277
|
+
exit_code = map_error_to_exit_code(exc)
|
|
278
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
279
|
+
raise typer.Exit(code=exit_code) from None
|
|
280
|
+
except ConfigError as exc:
|
|
281
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
282
|
+
raise typer.Exit(code=5) from None
|
|
283
|
+
|
|
284
|
+
if formatter.json_mode:
|
|
285
|
+
formatter.output(result)
|
|
286
|
+
else:
|
|
287
|
+
format_branch_metadata_table(formatter.console, result)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
@branch_app.command("metadata-get")
|
|
291
|
+
def branch_metadata_get(
|
|
292
|
+
ctx: typer.Context,
|
|
293
|
+
project: str = typer.Option(..., "--project", help="Project alias to query"),
|
|
294
|
+
key: str = typer.Option(..., "--key", help="Metadata key to read"),
|
|
295
|
+
branch: str = typer.Option(
|
|
296
|
+
"default",
|
|
297
|
+
"--branch",
|
|
298
|
+
help='Branch ID or "default" for the main branch',
|
|
299
|
+
),
|
|
300
|
+
) -> None:
|
|
301
|
+
"""Read a single metadata value by key.
|
|
302
|
+
|
|
303
|
+
Exits with code 1 (NOT_FOUND) if the key is not present on the branch.
|
|
304
|
+
"""
|
|
305
|
+
formatter = get_formatter(ctx)
|
|
306
|
+
service = get_service(ctx, "branch_service")
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
result = service.get_branch_metadata(alias=project, key=key, branch_id=branch)
|
|
310
|
+
except KeboolaApiError as exc:
|
|
311
|
+
exit_code = map_error_to_exit_code(exc)
|
|
312
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
313
|
+
raise typer.Exit(code=exit_code) from None
|
|
314
|
+
except ConfigError as exc:
|
|
315
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
316
|
+
raise typer.Exit(code=5) from None
|
|
317
|
+
|
|
318
|
+
formatter.output(
|
|
319
|
+
result,
|
|
320
|
+
lambda c, d: c.print(d["value"]),
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@branch_app.command("metadata-set")
|
|
325
|
+
def branch_metadata_set(
|
|
326
|
+
ctx: typer.Context,
|
|
327
|
+
project: str = typer.Option(..., "--project", help="Project alias"),
|
|
328
|
+
key: str = typer.Option(..., "--key", help="Metadata key to set"),
|
|
329
|
+
text: str | None = typer.Option(None, "--text", help="Inline string value"),
|
|
330
|
+
file: Path | None = typer.Option(
|
|
331
|
+
None,
|
|
332
|
+
"--file",
|
|
333
|
+
help="Read value from a UTF-8 text file",
|
|
334
|
+
exists=False, # validated in helper with a clearer error message
|
|
335
|
+
),
|
|
336
|
+
stdin: bool = typer.Option(
|
|
337
|
+
False,
|
|
338
|
+
"--stdin",
|
|
339
|
+
help="Read value from standard input",
|
|
340
|
+
),
|
|
341
|
+
branch: str = typer.Option(
|
|
342
|
+
"default",
|
|
343
|
+
"--branch",
|
|
344
|
+
help='Branch ID or "default" for the main branch',
|
|
345
|
+
),
|
|
346
|
+
) -> None:
|
|
347
|
+
"""Set a metadata key/value on a branch.
|
|
348
|
+
|
|
349
|
+
The value is taken from exactly one of --text, --file, or --stdin.
|
|
350
|
+
"""
|
|
351
|
+
formatter = get_formatter(ctx)
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
value = resolve_text_input(text=text, file=file, stdin=stdin)
|
|
355
|
+
except ConfigError as exc:
|
|
356
|
+
formatter.error(message=exc.message, error_code=ErrorCode.INVALID_ARGUMENT)
|
|
357
|
+
raise typer.Exit(code=2) from None
|
|
358
|
+
|
|
359
|
+
service = get_service(ctx, "branch_service")
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
result = service.set_branch_metadata(alias=project, key=key, value=value, branch_id=branch)
|
|
363
|
+
formatter.output(
|
|
364
|
+
result,
|
|
365
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
366
|
+
)
|
|
367
|
+
except KeboolaApiError as exc:
|
|
368
|
+
exit_code = map_error_to_exit_code(exc)
|
|
369
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
370
|
+
raise typer.Exit(code=exit_code) from None
|
|
371
|
+
except ConfigError as exc:
|
|
372
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
373
|
+
raise typer.Exit(code=5) from None
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
@branch_app.command("metadata-delete")
|
|
377
|
+
def branch_metadata_delete(
|
|
378
|
+
ctx: typer.Context,
|
|
379
|
+
project: str = typer.Option(..., "--project", help="Project alias"),
|
|
380
|
+
metadata_id: int = typer.Option(
|
|
381
|
+
...,
|
|
382
|
+
"--metadata-id",
|
|
383
|
+
help="Numeric ID of the metadata entry (from metadata-list)",
|
|
384
|
+
),
|
|
385
|
+
yes: bool = typer.Option(
|
|
386
|
+
False,
|
|
387
|
+
"--yes",
|
|
388
|
+
"-y",
|
|
389
|
+
help="Skip confirmation prompt",
|
|
390
|
+
),
|
|
391
|
+
branch: str = typer.Option(
|
|
392
|
+
"default",
|
|
393
|
+
"--branch",
|
|
394
|
+
help='Branch ID or "default" for the main branch',
|
|
395
|
+
),
|
|
396
|
+
) -> None:
|
|
397
|
+
"""Delete a branch metadata entry by its numeric ID."""
|
|
398
|
+
formatter = get_formatter(ctx)
|
|
399
|
+
service = get_service(ctx, "branch_service")
|
|
400
|
+
|
|
401
|
+
if (
|
|
402
|
+
not yes
|
|
403
|
+
and not formatter.json_mode
|
|
404
|
+
and not typer.confirm(f"Delete metadata entry {metadata_id} from project '{project}'?")
|
|
405
|
+
):
|
|
406
|
+
formatter.console.print("Aborted.")
|
|
407
|
+
raise typer.Exit(code=0)
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
result = service.delete_branch_metadata(
|
|
411
|
+
alias=project, metadata_id=metadata_id, branch_id=branch
|
|
412
|
+
)
|
|
413
|
+
formatter.output(
|
|
414
|
+
result,
|
|
415
|
+
lambda c, d: c.print(f"[bold green]Success:[/bold green] {d['message']}"),
|
|
416
|
+
)
|
|
417
|
+
except KeboolaApiError as exc:
|
|
418
|
+
exit_code = map_error_to_exit_code(exc)
|
|
419
|
+
formatter.error(message=exc.message, error_code=exc.error_code, retryable=exc.retryable)
|
|
420
|
+
raise typer.Exit(code=exit_code) from None
|
|
421
|
+
except ConfigError as exc:
|
|
422
|
+
formatter.error(message=exc.message, error_code=ErrorCode.CONFIG_ERROR)
|
|
423
|
+
raise typer.Exit(code=5) from None
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""Changelog command -- show recent version history.
|
|
2
|
+
|
|
3
|
+
Thin CLI layer: reads changelog data and formats output.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
from functools import partial
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.text import Text
|
|
14
|
+
|
|
15
|
+
from ..changelog import DEFAULT_CHANGELOG_LIMIT, get_changelog, headline
|
|
16
|
+
from ._helpers import get_formatter
|
|
17
|
+
|
|
18
|
+
# Map each known prefix word to a Rich style. Order does not matter; the
|
|
19
|
+
# regex below recognises the prefix regardless of trailing decorations like
|
|
20
|
+
# ``(#274)`` or `` (sec-20 follow-up)``.
|
|
21
|
+
_PREFIX_STYLES: dict[str, str] = {
|
|
22
|
+
"breaking": "bold red",
|
|
23
|
+
"new": "bold green",
|
|
24
|
+
"fix": "bold yellow",
|
|
25
|
+
"change": "bold blue",
|
|
26
|
+
"ux": "bold magenta",
|
|
27
|
+
"note": "bold cyan",
|
|
28
|
+
"security": "bold red",
|
|
29
|
+
"closed": "bold blue",
|
|
30
|
+
"tests": "dim",
|
|
31
|
+
"plugin docs": "dim",
|
|
32
|
+
"internal": "dim",
|
|
33
|
+
"observability": "dim",
|
|
34
|
+
"e2e": "dim",
|
|
35
|
+
"review fixes": "dim",
|
|
36
|
+
"why": "dim",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Match a leading "Word:" or "Word (extra):" prefix on a changelog note. The
|
|
40
|
+
# alternation is anchored to the longest match first so "Plugin docs" wins
|
|
41
|
+
# over "Plugin". Case-insensitive; we look up the style by lowercase key.
|
|
42
|
+
_PREFIX_RE = re.compile(
|
|
43
|
+
r"^(Plugin docs|Review fixes|Observability|Breaking|Security|Closed|Tests|"
|
|
44
|
+
r"Internal|Change|Note|Fix|New|UX|E2E|Why)"
|
|
45
|
+
r"(\s*\([^)]*\))?" # optional "(#274)" or "(sec-20 follow-up)" decoration
|
|
46
|
+
r":\s+",
|
|
47
|
+
re.IGNORECASE,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Split text by inline backtick spans while preserving the delimiters so we
|
|
51
|
+
# can colour them. ``"foo `bar` baz"`` -> ``["foo ", "`bar`", " baz"]``.
|
|
52
|
+
_BACKTICK_SPLIT = re.compile(r"(`[^`\n]+`)")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _styled_note(note: str) -> Text:
|
|
56
|
+
"""Build a Rich ``Text`` for one changelog bullet.
|
|
57
|
+
|
|
58
|
+
Prefix words (``New:``, ``Fix:``, ...) are coloured according to
|
|
59
|
+
``_PREFIX_STYLES``; inline ``backtick`` spans are rendered in cyan.
|
|
60
|
+
"""
|
|
61
|
+
text = Text()
|
|
62
|
+
m = _PREFIX_RE.match(note)
|
|
63
|
+
if m:
|
|
64
|
+
base = m.group(1).lower()
|
|
65
|
+
style = _PREFIX_STYLES.get(base, "bold white")
|
|
66
|
+
# Render the full prefix (including any "(#274)" decoration and the
|
|
67
|
+
# trailing colon-space) in the prefix style so the eye latches onto
|
|
68
|
+
# the action verb instantly.
|
|
69
|
+
text.append(m.group(0).rstrip() + " ", style=style)
|
|
70
|
+
rest = note[m.end() :]
|
|
71
|
+
else:
|
|
72
|
+
rest = note
|
|
73
|
+
|
|
74
|
+
for part in _BACKTICK_SPLIT.split(rest):
|
|
75
|
+
if not part:
|
|
76
|
+
continue
|
|
77
|
+
if part.startswith("`") and part.endswith("`") and len(part) >= 2:
|
|
78
|
+
text.append(part[1:-1], style="cyan")
|
|
79
|
+
else:
|
|
80
|
+
text.append(part)
|
|
81
|
+
return text
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _print_bullet(console: Console, styled: Text, body_width: int) -> None:
|
|
85
|
+
"""Word-wrap a styled bullet and print it with a manual gutter.
|
|
86
|
+
|
|
87
|
+
Bullet glyph on the first line, two-space indent on continuations. This
|
|
88
|
+
preserves per-span styling without the right-side padding Table cells emit.
|
|
89
|
+
"""
|
|
90
|
+
for j, line in enumerate(styled.wrap(console, body_width)):
|
|
91
|
+
# rstrip in place -- Rich keeps the word-break space at the end of each
|
|
92
|
+
# wrapped row, which shows up as trailing whitespace on copy/paste.
|
|
93
|
+
line.rstrip()
|
|
94
|
+
# The gutter is a styleless Text so the body keeps its own spans; dim
|
|
95
|
+
# applies only to the bullet glyph, not to everything that follows.
|
|
96
|
+
row = Text()
|
|
97
|
+
row.append(" • " if j == 0 else " ", style="dim" if j == 0 else None)
|
|
98
|
+
row.append_text(line)
|
|
99
|
+
console.print(row)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _format_changelog_human(console: Console, data: dict, *, full: bool) -> None:
|
|
103
|
+
"""Render the changelog.
|
|
104
|
+
|
|
105
|
+
Default (``full=False``): one headline bullet per version -- the first
|
|
106
|
+
note's first sentence, plus a dim ``(+N more)`` when a version carries
|
|
107
|
+
extra notes. ``full=True``: every note, word-wrapped in full.
|
|
108
|
+
"""
|
|
109
|
+
# Body width = terminal width minus the 4-char bullet gutter. Floor at
|
|
110
|
+
# 40 to stay readable on pathologically narrow terminals and to handle
|
|
111
|
+
# Console.width == 0 when stdout is piped to /dev/null.
|
|
112
|
+
body_width = max(40, console.width - 4)
|
|
113
|
+
entries = list(data["entries"].items())
|
|
114
|
+
has_hidden_detail = False
|
|
115
|
+
for i, (version, notes) in enumerate(entries):
|
|
116
|
+
console.print(f"v{version}", style="bold cyan")
|
|
117
|
+
if full:
|
|
118
|
+
for note in notes:
|
|
119
|
+
_print_bullet(console, _styled_note(note), body_width)
|
|
120
|
+
else:
|
|
121
|
+
head = headline(notes[0])
|
|
122
|
+
styled = _styled_note(head)
|
|
123
|
+
extra = len(notes) - 1
|
|
124
|
+
if extra > 0:
|
|
125
|
+
styled.append(f" (+{extra} more)", style="dim")
|
|
126
|
+
if extra > 0 or head != notes[0].strip():
|
|
127
|
+
has_hidden_detail = True
|
|
128
|
+
_print_bullet(console, styled, body_width)
|
|
129
|
+
if i < len(entries) - 1:
|
|
130
|
+
console.print("")
|
|
131
|
+
if not full and has_hidden_detail:
|
|
132
|
+
console.print("")
|
|
133
|
+
console.print("Run with --full (-v) to see complete notes.", style="dim")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def changelog_command(
|
|
137
|
+
ctx: typer.Context,
|
|
138
|
+
limit: int = typer.Option(
|
|
139
|
+
DEFAULT_CHANGELOG_LIMIT,
|
|
140
|
+
"--limit",
|
|
141
|
+
"-n",
|
|
142
|
+
help="Number of versions to show.",
|
|
143
|
+
min=1,
|
|
144
|
+
max=100,
|
|
145
|
+
),
|
|
146
|
+
full: bool = typer.Option(
|
|
147
|
+
False,
|
|
148
|
+
"--full",
|
|
149
|
+
"-v",
|
|
150
|
+
help="Show complete notes for each version (default: one-line summary).",
|
|
151
|
+
),
|
|
152
|
+
) -> None:
|
|
153
|
+
"""Show recent changelog (what changed in each version).
|
|
154
|
+
|
|
155
|
+
By default each version is summarised as a single headline; pass --full
|
|
156
|
+
(-v) for the complete notes.
|
|
157
|
+
|
|
158
|
+
After auto-update, kbagent automatically prints "What's new" for the
|
|
159
|
+
new version. To see changes for a specific version manually, set
|
|
160
|
+
KBAGENT_UPDATED_FROM to any older version:
|
|
161
|
+
|
|
162
|
+
KBAGENT_UPDATED_FROM=0.17.0 kbagent version
|
|
163
|
+
"""
|
|
164
|
+
formatter = get_formatter(ctx)
|
|
165
|
+
entries = get_changelog(limit)
|
|
166
|
+
# Bind ``full`` via partial so the JSON payload stays ``{"entries": ...}``
|
|
167
|
+
# (the flag is a presentation concern, not data).
|
|
168
|
+
formatter.output({"entries": entries}, partial(_format_changelog_human, full=full))
|