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,694 @@
|
|
|
1
|
+
"""Component discovery and scaffold generation service.
|
|
2
|
+
|
|
3
|
+
Provides component search (via AI Service suggestions or Storage API listing),
|
|
4
|
+
detailed component inspection, and configuration scaffold generation for
|
|
5
|
+
local-first development workflows.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import yaml
|
|
13
|
+
|
|
14
|
+
from ..ai_client import AiServiceClient
|
|
15
|
+
from ..config_store import ConfigStore
|
|
16
|
+
from ..constants import SECRET_PLACEHOLDER
|
|
17
|
+
from ..errors import KeboolaApiError
|
|
18
|
+
from ..models import ComponentDetail, ComponentSuggestion, ProjectConfig
|
|
19
|
+
from .base import BaseService, ClientFactory
|
|
20
|
+
from .org_service import slugify
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
AiClientFactory = Callable[[str, str], AiServiceClient]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def default_ai_client_factory(stack_url: str, token: str) -> AiServiceClient:
|
|
28
|
+
"""Create an AiServiceClient with the given stack URL and token."""
|
|
29
|
+
return AiServiceClient(stack_url=stack_url, token=token)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# --- Component type detection ---
|
|
33
|
+
|
|
34
|
+
_SQL_TRANSFORMATION_FRAGMENTS = (
|
|
35
|
+
"snowflake-transformation",
|
|
36
|
+
"synapse-transformation",
|
|
37
|
+
"redshift-transformation",
|
|
38
|
+
"bigquery-transformation",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
_PYTHON_TRANSFORMATION_FRAGMENT = "python-transformation"
|
|
42
|
+
_CUSTOM_PYTHON_APP_ID = "kds-team.app-custom-python"
|
|
43
|
+
_FLOW_COMPONENT_IDS = ("keboola.flow",)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _detect_component_category(component_id: str) -> str:
|
|
47
|
+
"""Determine scaffold category from component_id.
|
|
48
|
+
|
|
49
|
+
Returns one of: sql_transformation, python_transformation,
|
|
50
|
+
custom_python, flow, generic.
|
|
51
|
+
"""
|
|
52
|
+
for fragment in _SQL_TRANSFORMATION_FRAGMENTS:
|
|
53
|
+
if fragment in component_id:
|
|
54
|
+
return "sql_transformation"
|
|
55
|
+
if _PYTHON_TRANSFORMATION_FRAGMENT in component_id:
|
|
56
|
+
return "python_transformation"
|
|
57
|
+
if component_id == _CUSTOM_PYTHON_APP_ID:
|
|
58
|
+
return "custom_python"
|
|
59
|
+
if component_id in _FLOW_COMPONENT_IDS:
|
|
60
|
+
return "flow"
|
|
61
|
+
return "generic"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# --- Scaffold file builders ---
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _build_config_yml(detail: ComponentDetail, name: str) -> str:
|
|
68
|
+
"""Generate _config.yml content with inline comments.
|
|
69
|
+
|
|
70
|
+
Priority for parameters section:
|
|
71
|
+
1. First rootConfigurationExample's parameters key
|
|
72
|
+
2. Schema-derived placeholders from configurationSchema
|
|
73
|
+
3. Empty parameters dict
|
|
74
|
+
"""
|
|
75
|
+
lines: list[str] = []
|
|
76
|
+
|
|
77
|
+
# Header comments
|
|
78
|
+
lines.append(f"# Component: {detail.component_name} ({detail.component_id})")
|
|
79
|
+
lines.append(f"# Type: {detail.component_type}")
|
|
80
|
+
if detail.documentation_url:
|
|
81
|
+
lines.append(f"# Documentation: {detail.documentation_url}")
|
|
82
|
+
lines.append("#")
|
|
83
|
+
lines.append("# NOTE: config_id will be assigned by Keboola on first push")
|
|
84
|
+
|
|
85
|
+
# Version and name
|
|
86
|
+
lines.append("version: 2")
|
|
87
|
+
lines.append(f'name: "{name}"')
|
|
88
|
+
lines.append("description: |")
|
|
89
|
+
lines.append(" TODO: describe this configuration")
|
|
90
|
+
lines.append("")
|
|
91
|
+
|
|
92
|
+
# Parameters section
|
|
93
|
+
params = _resolve_parameters(detail)
|
|
94
|
+
if params:
|
|
95
|
+
params_yaml = yaml.dump({"parameters": params}, default_flow_style=False, sort_keys=False)
|
|
96
|
+
# Post-process secret placeholders with inline comments
|
|
97
|
+
processed_lines: list[str] = []
|
|
98
|
+
for line in params_yaml.splitlines():
|
|
99
|
+
if SECRET_PLACEHOLDER in line and "# encrypted by Keboola on push" not in line:
|
|
100
|
+
line = f"{line} # encrypted by Keboola on push"
|
|
101
|
+
processed_lines.append(line)
|
|
102
|
+
lines.extend(processed_lines)
|
|
103
|
+
else:
|
|
104
|
+
lines.append("parameters: {}")
|
|
105
|
+
|
|
106
|
+
# Storage mappings based on component flags
|
|
107
|
+
storage_lines = _build_storage_section(detail)
|
|
108
|
+
if storage_lines:
|
|
109
|
+
lines.append("")
|
|
110
|
+
lines.extend(storage_lines)
|
|
111
|
+
|
|
112
|
+
# Configuration rows hint
|
|
113
|
+
if detail.configuration_row_schema:
|
|
114
|
+
lines.append("")
|
|
115
|
+
lines.append("# This component uses configuration rows. Add rows via 'rows/' subdirectory.")
|
|
116
|
+
|
|
117
|
+
# _keboola metadata (component_id required for sync push, config_id assigned on first push)
|
|
118
|
+
lines.append("")
|
|
119
|
+
lines.append("_keboola:")
|
|
120
|
+
lines.append(f" component_id: {detail.component_id}")
|
|
121
|
+
|
|
122
|
+
lines.append("")
|
|
123
|
+
return "\n".join(lines)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _resolve_parameters(detail: ComponentDetail) -> dict[str, Any]:
|
|
127
|
+
"""Extract parameters from examples or schema, applying secret masking."""
|
|
128
|
+
# Priority 1: examples
|
|
129
|
+
if detail.root_configuration_examples:
|
|
130
|
+
first_example = detail.root_configuration_examples[0]
|
|
131
|
+
raw_params = first_example.get("parameters", {})
|
|
132
|
+
if raw_params:
|
|
133
|
+
return _mask_secrets(raw_params)
|
|
134
|
+
|
|
135
|
+
# Priority 2: schema
|
|
136
|
+
schema = detail.configuration_schema
|
|
137
|
+
if schema and schema.get("properties"):
|
|
138
|
+
params_schema = schema.get("properties", {}).get("parameters", {})
|
|
139
|
+
if params_schema and params_schema.get("properties"):
|
|
140
|
+
return _generate_from_schema(params_schema)
|
|
141
|
+
# If parameters is not nested, try top-level properties
|
|
142
|
+
return _generate_from_schema(schema)
|
|
143
|
+
|
|
144
|
+
# Priority 3: empty
|
|
145
|
+
return {}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _mask_secrets(obj: Any) -> Any:
|
|
149
|
+
"""Recursively replace secret values with SECRET_PLACEHOLDER."""
|
|
150
|
+
if isinstance(obj, dict):
|
|
151
|
+
result = {}
|
|
152
|
+
for key, value in obj.items():
|
|
153
|
+
if key.startswith("#") or (isinstance(value, str) and value == "<secret>"):
|
|
154
|
+
result[key] = SECRET_PLACEHOLDER
|
|
155
|
+
else:
|
|
156
|
+
result[key] = _mask_secrets(value)
|
|
157
|
+
return result
|
|
158
|
+
if isinstance(obj, list):
|
|
159
|
+
return [_mask_secrets(item) for item in obj]
|
|
160
|
+
return obj
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _generate_from_schema(schema: dict[str, Any]) -> dict[str, Any]:
|
|
164
|
+
"""Generate placeholder values from a JSON schema."""
|
|
165
|
+
properties = schema.get("properties", {})
|
|
166
|
+
result: dict[str, Any] = {}
|
|
167
|
+
|
|
168
|
+
for prop_name, prop_schema in properties.items():
|
|
169
|
+
prop_type = prop_schema.get("type", "string")
|
|
170
|
+
|
|
171
|
+
if prop_name.startswith("#"):
|
|
172
|
+
result[prop_name] = SECRET_PLACEHOLDER
|
|
173
|
+
elif prop_type == "string":
|
|
174
|
+
result[prop_name] = prop_schema.get("default", "")
|
|
175
|
+
elif prop_type == "integer" or prop_type == "number":
|
|
176
|
+
result[prop_name] = prop_schema.get("default", 0)
|
|
177
|
+
elif prop_type == "boolean":
|
|
178
|
+
result[prop_name] = prop_schema.get("default", False)
|
|
179
|
+
elif prop_type == "array":
|
|
180
|
+
result[prop_name] = prop_schema.get("default", [])
|
|
181
|
+
elif prop_type == "object":
|
|
182
|
+
nested = prop_schema.get("properties")
|
|
183
|
+
if nested:
|
|
184
|
+
result[prop_name] = _generate_from_schema(prop_schema)
|
|
185
|
+
else:
|
|
186
|
+
result[prop_name] = prop_schema.get("default", {})
|
|
187
|
+
else:
|
|
188
|
+
result[prop_name] = ""
|
|
189
|
+
|
|
190
|
+
return result
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _build_storage_section(detail: ComponentDetail) -> list[str]:
|
|
194
|
+
"""Generate storage input/output mapping skeleton based on component flags."""
|
|
195
|
+
flags = detail.component_flags
|
|
196
|
+
lines: list[str] = []
|
|
197
|
+
has_input = "genericDockerUI-tableInput" in flags
|
|
198
|
+
has_output = "genericDockerUI-tableOutput" in flags
|
|
199
|
+
|
|
200
|
+
if not has_input and not has_output:
|
|
201
|
+
return lines
|
|
202
|
+
|
|
203
|
+
lines.append("storage:")
|
|
204
|
+
|
|
205
|
+
if has_input:
|
|
206
|
+
lines.append(" input:")
|
|
207
|
+
lines.append(" tables:")
|
|
208
|
+
lines.append(' - source: "in.c-bucket.table"')
|
|
209
|
+
lines.append(' destination: "input.csv"')
|
|
210
|
+
|
|
211
|
+
if has_output:
|
|
212
|
+
lines.append(" output:")
|
|
213
|
+
lines.append(" tables:")
|
|
214
|
+
lines.append(' - source: "output.csv"')
|
|
215
|
+
lines.append(' destination: "out.c-bucket.table"')
|
|
216
|
+
|
|
217
|
+
return lines
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _build_transform_sql(name: str) -> str:
|
|
221
|
+
"""Generate SQL transformation boilerplate."""
|
|
222
|
+
return (
|
|
223
|
+
"/* ===== BLOCK: 001-main ===== */\n"
|
|
224
|
+
"/* ===== CODE: 001-query ===== */\n"
|
|
225
|
+
"\n"
|
|
226
|
+
"-- TODO: write your SQL transformation here\n"
|
|
227
|
+
"-- Input tables are available as temporary tables\n"
|
|
228
|
+
"-- Output tables will be created from SELECT results\n"
|
|
229
|
+
"\n"
|
|
230
|
+
"SELECT 1;\n"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _build_transform_py(name: str) -> str:
|
|
235
|
+
"""Generate Python transformation boilerplate."""
|
|
236
|
+
return (
|
|
237
|
+
"# ===== BLOCK: 001-main =====\n"
|
|
238
|
+
"# ===== CODE: 001-script =====\n"
|
|
239
|
+
"\n"
|
|
240
|
+
"from keboola.component import CommonInterface\n"
|
|
241
|
+
"\n"
|
|
242
|
+
"ci = CommonInterface()\n"
|
|
243
|
+
"\n"
|
|
244
|
+
"# Read input tables\n"
|
|
245
|
+
'# input_table = ci.get_input_table_definition_by_name("input.csv")\n'
|
|
246
|
+
"# df = pd.read_csv(input_table.full_path)\n"
|
|
247
|
+
"\n"
|
|
248
|
+
"# Write output tables\n"
|
|
249
|
+
'# output_table = ci.create_out_table_definition("output.csv")\n'
|
|
250
|
+
"# df.to_csv(output_table.full_path, index=False)\n"
|
|
251
|
+
"\n"
|
|
252
|
+
'print("Transformation complete")\n'
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _build_code_py() -> str:
|
|
257
|
+
"""Generate custom Python application boilerplate."""
|
|
258
|
+
return (
|
|
259
|
+
"import logging\n"
|
|
260
|
+
"from keboola.component import CommonInterface\n"
|
|
261
|
+
"\n"
|
|
262
|
+
"logging.basicConfig(level=logging.INFO)\n"
|
|
263
|
+
"\n"
|
|
264
|
+
"ci = CommonInterface()\n"
|
|
265
|
+
"params = ci.configuration.parameters\n"
|
|
266
|
+
"\n"
|
|
267
|
+
"# TODO: implement your application logic here\n"
|
|
268
|
+
"\n"
|
|
269
|
+
'logging.info("Application complete")\n'
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _build_pyproject_toml(component_id: str, name: str, packages: list[str] | None = None) -> str:
|
|
274
|
+
"""Generate pyproject.toml for custom Python apps."""
|
|
275
|
+
slugified_name = slugify(name)
|
|
276
|
+
deps_lines = ""
|
|
277
|
+
if packages:
|
|
278
|
+
formatted = ",\n".join(f' "{pkg}"' for pkg in packages)
|
|
279
|
+
deps_lines = f"\ndependencies = [\n{formatted},\n]\n"
|
|
280
|
+
else:
|
|
281
|
+
deps_lines = "\ndependencies = [\n # Add your dependencies here\n]\n"
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
"[project]\n"
|
|
285
|
+
f'name = "{slugified_name}"\n'
|
|
286
|
+
'version = "1.0.0"\n'
|
|
287
|
+
'requires-python = ">=3.11"\n'
|
|
288
|
+
f"{deps_lines}"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _build_flow_config_yml(name: str, component_id: str = "keboola.flow") -> str:
|
|
293
|
+
"""Generate a conditional-flow (keboola.flow) configuration YAML skeleton.
|
|
294
|
+
|
|
295
|
+
IDs are strings; phases carry next[].goto transitions (a phase id or null)
|
|
296
|
+
and tasks are typed (job/notification/variable).
|
|
297
|
+
"""
|
|
298
|
+
lines = [
|
|
299
|
+
f'name: "{name}"',
|
|
300
|
+
"description: |",
|
|
301
|
+
" TODO: describe this flow",
|
|
302
|
+
"phases:",
|
|
303
|
+
' - id: "phase-1"',
|
|
304
|
+
' name: "Phase 1"',
|
|
305
|
+
" next:",
|
|
306
|
+
' - id: "default"',
|
|
307
|
+
" goto: null",
|
|
308
|
+
"tasks:",
|
|
309
|
+
' - id: "task-1"',
|
|
310
|
+
' name: "Task 1"',
|
|
311
|
+
' phase: "phase-1"',
|
|
312
|
+
" enabled: true",
|
|
313
|
+
" task:",
|
|
314
|
+
" type: job",
|
|
315
|
+
' componentId: "keboola.ex-http"',
|
|
316
|
+
' configId: "TODO"',
|
|
317
|
+
" mode: run",
|
|
318
|
+
]
|
|
319
|
+
return "\n".join(lines) + "\n"
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class ComponentService(BaseService):
|
|
323
|
+
"""Business logic for component discovery and scaffold generation.
|
|
324
|
+
|
|
325
|
+
Supports two discovery modes:
|
|
326
|
+
- AI-powered search via AiServiceClient (natural language query)
|
|
327
|
+
- Storage API listing via KeboolaClient (component type filter)
|
|
328
|
+
|
|
329
|
+
Scaffold generation creates ready-to-use configuration files based on
|
|
330
|
+
component schema, examples, and type-specific templates.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
def __init__(
|
|
334
|
+
self,
|
|
335
|
+
config_store: ConfigStore,
|
|
336
|
+
client_factory: ClientFactory | None = None,
|
|
337
|
+
ai_client_factory: AiClientFactory | None = None,
|
|
338
|
+
) -> None:
|
|
339
|
+
super().__init__(config_store, client_factory)
|
|
340
|
+
self._ai_client_factory = ai_client_factory or default_ai_client_factory
|
|
341
|
+
|
|
342
|
+
def list_components(
|
|
343
|
+
self,
|
|
344
|
+
aliases: list[str] | None = None,
|
|
345
|
+
component_type: str | None = None,
|
|
346
|
+
query: str | None = None,
|
|
347
|
+
) -> dict[str, Any]:
|
|
348
|
+
"""List or search components across projects.
|
|
349
|
+
|
|
350
|
+
Two modes of operation:
|
|
351
|
+
- With ``query``: Uses AI Service to suggest components matching a
|
|
352
|
+
natural language description. Enriches each suggestion with detail
|
|
353
|
+
from get_component_detail(). Runs against first/default project.
|
|
354
|
+
- Without ``query``: Uses Storage API list_components() across all
|
|
355
|
+
resolved projects in parallel, returning unique components.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
aliases: Project aliases to query. None means all projects.
|
|
359
|
+
component_type: Optional filter by component type
|
|
360
|
+
(extractor, writer, transformation, application).
|
|
361
|
+
query: Natural language search query for AI-powered discovery.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
Dict with keys:
|
|
365
|
+
- "components": list of component dicts
|
|
366
|
+
- "errors": list of error dicts
|
|
367
|
+
"""
|
|
368
|
+
if query:
|
|
369
|
+
return self._list_via_ai(aliases, component_type, query)
|
|
370
|
+
return self._list_via_storage(aliases, component_type)
|
|
371
|
+
|
|
372
|
+
def get_component_detail(self, alias: str, component_id: str) -> dict[str, Any]:
|
|
373
|
+
"""Fetch detailed component documentation via AI Service.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
alias: Project alias (used to derive stack URL and token).
|
|
377
|
+
component_id: The component identifier (e.g. 'keboola.ex-aws-s3').
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
Dict with component detail including schema summary,
|
|
381
|
+
examples count, and full documentation.
|
|
382
|
+
|
|
383
|
+
Raises:
|
|
384
|
+
ConfigError: If the alias is not found.
|
|
385
|
+
KeboolaApiError: If the AI Service call fails.
|
|
386
|
+
"""
|
|
387
|
+
projects = self.resolve_projects([alias])
|
|
388
|
+
project = projects[alias]
|
|
389
|
+
|
|
390
|
+
ai_client = self._ai_client_factory(project.stack_url, project.token)
|
|
391
|
+
try:
|
|
392
|
+
raw = ai_client.get_component_detail(component_id)
|
|
393
|
+
finally:
|
|
394
|
+
ai_client.close()
|
|
395
|
+
|
|
396
|
+
detail = ComponentDetail(**raw)
|
|
397
|
+
|
|
398
|
+
# Build schema summary
|
|
399
|
+
schema = detail.configuration_schema
|
|
400
|
+
schema_properties = schema.get("properties", {}) if schema else {}
|
|
401
|
+
schema_required = schema.get("required", []) if schema else []
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
"component_id": detail.component_id,
|
|
405
|
+
"component_name": detail.component_name,
|
|
406
|
+
"component_type": detail.component_type,
|
|
407
|
+
"categories": detail.component_categories,
|
|
408
|
+
"flags": detail.component_flags,
|
|
409
|
+
"description": detail.description,
|
|
410
|
+
"long_description": detail.long_description,
|
|
411
|
+
"documentation_url": detail.documentation_url,
|
|
412
|
+
"schema_summary": {
|
|
413
|
+
"property_count": len(schema_properties),
|
|
414
|
+
"required_count": len(schema_required),
|
|
415
|
+
"has_row_schema": bool(detail.configuration_row_schema),
|
|
416
|
+
},
|
|
417
|
+
"examples_count": len(detail.root_configuration_examples),
|
|
418
|
+
"row_examples_count": len(detail.row_configuration_examples),
|
|
419
|
+
"project_alias": alias,
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
def generate_scaffold(
|
|
423
|
+
self,
|
|
424
|
+
alias: str,
|
|
425
|
+
component_id: str,
|
|
426
|
+
name: str | None = None,
|
|
427
|
+
) -> dict[str, Any]:
|
|
428
|
+
"""Generate configuration scaffold files for a component.
|
|
429
|
+
|
|
430
|
+
Fetches component detail from AI Service, then generates appropriate
|
|
431
|
+
configuration files based on component type and schema.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
alias: Project alias (used to derive stack URL and token).
|
|
435
|
+
component_id: The component identifier.
|
|
436
|
+
name: Configuration name. If None, defaults to
|
|
437
|
+
"{component_name} Configuration".
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
Dict with scaffold metadata and generated files list.
|
|
441
|
+
|
|
442
|
+
Raises:
|
|
443
|
+
ConfigError: If the alias is not found.
|
|
444
|
+
KeboolaApiError: If the AI Service call fails.
|
|
445
|
+
"""
|
|
446
|
+
projects = self.resolve_projects([alias])
|
|
447
|
+
project = projects[alias]
|
|
448
|
+
|
|
449
|
+
ai_client = self._ai_client_factory(project.stack_url, project.token)
|
|
450
|
+
try:
|
|
451
|
+
raw = ai_client.get_component_detail(component_id)
|
|
452
|
+
finally:
|
|
453
|
+
ai_client.close()
|
|
454
|
+
|
|
455
|
+
detail = ComponentDetail(**raw)
|
|
456
|
+
|
|
457
|
+
config_name = name or f"{detail.component_name} Configuration"
|
|
458
|
+
category = _detect_component_category(component_id)
|
|
459
|
+
|
|
460
|
+
# Build directory path
|
|
461
|
+
dir_name = slugify(config_name)
|
|
462
|
+
directory = f"{detail.component_type}/{component_id}/{dir_name}"
|
|
463
|
+
|
|
464
|
+
# Generate files based on category
|
|
465
|
+
files = self._generate_files(detail, config_name, category)
|
|
466
|
+
|
|
467
|
+
return {
|
|
468
|
+
"component_id": component_id,
|
|
469
|
+
"component_name": detail.component_name,
|
|
470
|
+
"component_type": detail.component_type,
|
|
471
|
+
"config_name": config_name,
|
|
472
|
+
"directory": directory,
|
|
473
|
+
"documentation_url": detail.documentation_url,
|
|
474
|
+
"files": files,
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
# --- Private helpers ---
|
|
478
|
+
|
|
479
|
+
def _list_via_ai(
|
|
480
|
+
self,
|
|
481
|
+
aliases: list[str] | None,
|
|
482
|
+
component_type: str | None,
|
|
483
|
+
query: str,
|
|
484
|
+
) -> dict[str, Any]:
|
|
485
|
+
"""Search components via AI Service suggestions.
|
|
486
|
+
|
|
487
|
+
Uses first/default project for AI queries, then enriches each
|
|
488
|
+
suggestion with component detail.
|
|
489
|
+
"""
|
|
490
|
+
projects = self.resolve_projects(aliases)
|
|
491
|
+
# Use first project for AI queries
|
|
492
|
+
first_alias = next(iter(projects))
|
|
493
|
+
project = projects[first_alias]
|
|
494
|
+
|
|
495
|
+
ai_client = self._ai_client_factory(project.stack_url, project.token)
|
|
496
|
+
components: list[dict[str, Any]] = []
|
|
497
|
+
errors: list[dict[str, str]] = []
|
|
498
|
+
|
|
499
|
+
try:
|
|
500
|
+
suggestions_raw = ai_client.suggest_components(query)
|
|
501
|
+
suggestions = [ComponentSuggestion(**s) for s in suggestions_raw]
|
|
502
|
+
|
|
503
|
+
for suggestion in suggestions:
|
|
504
|
+
try:
|
|
505
|
+
raw_detail = ai_client.get_component_detail(suggestion.component_id)
|
|
506
|
+
detail = ComponentDetail(**raw_detail)
|
|
507
|
+
|
|
508
|
+
# Apply component_type filter if provided
|
|
509
|
+
if component_type and detail.component_type != component_type:
|
|
510
|
+
continue
|
|
511
|
+
|
|
512
|
+
components.append(
|
|
513
|
+
{
|
|
514
|
+
"component_id": detail.component_id,
|
|
515
|
+
"component_name": detail.component_name,
|
|
516
|
+
"component_type": detail.component_type,
|
|
517
|
+
"categories": detail.component_categories,
|
|
518
|
+
"description": detail.description,
|
|
519
|
+
"score": suggestion.score,
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
except KeboolaApiError as exc:
|
|
523
|
+
logger.debug(
|
|
524
|
+
"Failed to fetch detail for %s: %s",
|
|
525
|
+
suggestion.component_id,
|
|
526
|
+
exc.message,
|
|
527
|
+
)
|
|
528
|
+
errors.append(
|
|
529
|
+
{
|
|
530
|
+
"component_id": suggestion.component_id,
|
|
531
|
+
"error_code": exc.error_code,
|
|
532
|
+
"message": exc.message,
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
except Exception as exc:
|
|
536
|
+
logger.debug(
|
|
537
|
+
"Unexpected error fetching detail for %s: %s",
|
|
538
|
+
suggestion.component_id,
|
|
539
|
+
exc,
|
|
540
|
+
)
|
|
541
|
+
errors.append(
|
|
542
|
+
{
|
|
543
|
+
"component_id": suggestion.component_id,
|
|
544
|
+
"error_code": "UNEXPECTED_ERROR",
|
|
545
|
+
"message": str(exc),
|
|
546
|
+
}
|
|
547
|
+
)
|
|
548
|
+
except KeboolaApiError as exc:
|
|
549
|
+
errors.append(
|
|
550
|
+
{
|
|
551
|
+
"project_alias": first_alias,
|
|
552
|
+
"error_code": exc.error_code,
|
|
553
|
+
"message": exc.message,
|
|
554
|
+
}
|
|
555
|
+
)
|
|
556
|
+
except Exception as exc:
|
|
557
|
+
errors.append(
|
|
558
|
+
{
|
|
559
|
+
"project_alias": first_alias,
|
|
560
|
+
"error_code": "UNEXPECTED_ERROR",
|
|
561
|
+
"message": str(exc),
|
|
562
|
+
}
|
|
563
|
+
)
|
|
564
|
+
finally:
|
|
565
|
+
ai_client.close()
|
|
566
|
+
|
|
567
|
+
return {"components": components, "errors": errors}
|
|
568
|
+
|
|
569
|
+
def _list_via_storage(
|
|
570
|
+
self,
|
|
571
|
+
aliases: list[str] | None,
|
|
572
|
+
component_type: str | None,
|
|
573
|
+
) -> dict[str, Any]:
|
|
574
|
+
"""List components via Storage API across projects in parallel."""
|
|
575
|
+
projects = self.resolve_projects(aliases)
|
|
576
|
+
|
|
577
|
+
def worker(
|
|
578
|
+
alias: str, project: ProjectConfig
|
|
579
|
+
) -> tuple[str, list[dict[str, Any]], bool] | tuple[str, dict[str, str]]:
|
|
580
|
+
client = self._client_factory(project.stack_url, project.token)
|
|
581
|
+
try:
|
|
582
|
+
raw_components = client.list_components(component_type=component_type)
|
|
583
|
+
result: list[dict[str, Any]] = []
|
|
584
|
+
for comp in raw_components:
|
|
585
|
+
result.append(
|
|
586
|
+
{
|
|
587
|
+
"component_id": comp.get("id", ""),
|
|
588
|
+
"component_name": comp.get("name", ""),
|
|
589
|
+
"component_type": comp.get("type", ""),
|
|
590
|
+
"categories": comp.get("categories", []),
|
|
591
|
+
"description": comp.get("description", ""),
|
|
592
|
+
}
|
|
593
|
+
)
|
|
594
|
+
return (alias, result, True)
|
|
595
|
+
except KeboolaApiError as exc:
|
|
596
|
+
return (
|
|
597
|
+
alias,
|
|
598
|
+
{
|
|
599
|
+
"project_alias": alias,
|
|
600
|
+
"error_code": exc.error_code,
|
|
601
|
+
"message": exc.message,
|
|
602
|
+
},
|
|
603
|
+
)
|
|
604
|
+
except Exception as exc:
|
|
605
|
+
return (
|
|
606
|
+
alias,
|
|
607
|
+
{
|
|
608
|
+
"project_alias": alias,
|
|
609
|
+
"error_code": "UNEXPECTED_ERROR",
|
|
610
|
+
"message": str(exc),
|
|
611
|
+
},
|
|
612
|
+
)
|
|
613
|
+
finally:
|
|
614
|
+
client.close()
|
|
615
|
+
|
|
616
|
+
successes, errors = self._run_parallel(projects, worker)
|
|
617
|
+
|
|
618
|
+
# Deduplicate components across projects by component_id
|
|
619
|
+
seen: dict[str, dict[str, Any]] = {}
|
|
620
|
+
for _alias, components, _ok in successes:
|
|
621
|
+
for comp in components:
|
|
622
|
+
comp_id = comp["component_id"]
|
|
623
|
+
if comp_id not in seen:
|
|
624
|
+
seen[comp_id] = comp
|
|
625
|
+
|
|
626
|
+
unique_components = sorted(seen.values(), key=lambda c: c["component_id"])
|
|
627
|
+
errors.sort(key=lambda e: e.get("project_alias", ""))
|
|
628
|
+
|
|
629
|
+
return {"components": unique_components, "errors": errors}
|
|
630
|
+
|
|
631
|
+
def _generate_files(
|
|
632
|
+
self,
|
|
633
|
+
detail: ComponentDetail,
|
|
634
|
+
config_name: str,
|
|
635
|
+
category: str,
|
|
636
|
+
) -> list[dict[str, str]]:
|
|
637
|
+
"""Generate scaffold files based on component category.
|
|
638
|
+
|
|
639
|
+
Returns a list of file dicts with path, content, and description.
|
|
640
|
+
"""
|
|
641
|
+
files: list[dict[str, str]] = []
|
|
642
|
+
|
|
643
|
+
if category == "flow":
|
|
644
|
+
files.append(
|
|
645
|
+
{
|
|
646
|
+
"path": "_config.yml",
|
|
647
|
+
"content": _build_flow_config_yml(config_name, detail.component_id),
|
|
648
|
+
"description": "Conditional flow (keboola.flow) configuration",
|
|
649
|
+
}
|
|
650
|
+
)
|
|
651
|
+
return files
|
|
652
|
+
|
|
653
|
+
# All other categories get a _config.yml
|
|
654
|
+
files.append(
|
|
655
|
+
{
|
|
656
|
+
"path": "_config.yml",
|
|
657
|
+
"content": _build_config_yml(detail, config_name),
|
|
658
|
+
"description": "Configuration file",
|
|
659
|
+
}
|
|
660
|
+
)
|
|
661
|
+
|
|
662
|
+
if category == "sql_transformation":
|
|
663
|
+
files.append(
|
|
664
|
+
{
|
|
665
|
+
"path": "transform.sql",
|
|
666
|
+
"content": _build_transform_sql(config_name),
|
|
667
|
+
"description": "SQL transformation code",
|
|
668
|
+
}
|
|
669
|
+
)
|
|
670
|
+
elif category == "python_transformation":
|
|
671
|
+
files.append(
|
|
672
|
+
{
|
|
673
|
+
"path": "transform.py",
|
|
674
|
+
"content": _build_transform_py(config_name),
|
|
675
|
+
"description": "Python transformation code",
|
|
676
|
+
}
|
|
677
|
+
)
|
|
678
|
+
elif category == "custom_python":
|
|
679
|
+
files.append(
|
|
680
|
+
{
|
|
681
|
+
"path": "code.py",
|
|
682
|
+
"content": _build_code_py(),
|
|
683
|
+
"description": "Custom Python application code",
|
|
684
|
+
}
|
|
685
|
+
)
|
|
686
|
+
files.append(
|
|
687
|
+
{
|
|
688
|
+
"path": "pyproject.toml",
|
|
689
|
+
"content": _build_pyproject_toml(detail.component_id, config_name),
|
|
690
|
+
"description": "Python project configuration",
|
|
691
|
+
}
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
return files
|