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,162 @@
|
|
|
1
|
+
"""Pydantic v2 models for .keboola/manifest.json (v2, camelCase via aliases).
|
|
2
|
+
|
|
3
|
+
Mirrors the manifest format used by the Keboola Go CLI so that
|
|
4
|
+
directories written by kbagent are compatible with `kbc` tooling.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
14
|
+
|
|
15
|
+
from ..constants import KEBOOLA_DIR_NAME, MANIFEST_FILENAME, MANIFEST_VERSION
|
|
16
|
+
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
# Sub-models
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ManifestProject(BaseModel):
|
|
23
|
+
"""Project identification inside the manifest."""
|
|
24
|
+
|
|
25
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
26
|
+
|
|
27
|
+
id: int
|
|
28
|
+
api_host: str = Field(alias="apiHost")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ManifestGitBranching(BaseModel):
|
|
32
|
+
"""Git branching settings."""
|
|
33
|
+
|
|
34
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
35
|
+
|
|
36
|
+
enabled: bool = False
|
|
37
|
+
default_branch: str = Field(default="main", alias="defaultBranch")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ManifestNaming(BaseModel):
|
|
41
|
+
"""Naming templates that control the filesystem layout."""
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
44
|
+
|
|
45
|
+
branch: str = "{branch_name}"
|
|
46
|
+
config: str = "{component_type}/{component_id}/{config_name}"
|
|
47
|
+
config_row: str = Field(default="rows/{config_row_name}", alias="configRow")
|
|
48
|
+
scheduler_config: str = Field(default="schedules/{config_name}", alias="schedulerConfig")
|
|
49
|
+
shared_code_config: str = Field(
|
|
50
|
+
default="_shared/{target_component_id}", alias="sharedCodeConfig"
|
|
51
|
+
)
|
|
52
|
+
shared_code_config_row: str = Field(
|
|
53
|
+
default="codes/{config_row_name}", alias="sharedCodeConfigRow"
|
|
54
|
+
)
|
|
55
|
+
variables_config: str = Field(default="variables", alias="variablesConfig")
|
|
56
|
+
variables_values_row: str = Field(
|
|
57
|
+
default="values/{config_row_name}", alias="variablesValuesRow"
|
|
58
|
+
)
|
|
59
|
+
data_app_config: str = Field(default="app/{component_id}/{config_name}", alias="dataAppConfig")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ManifestBranch(BaseModel):
|
|
63
|
+
"""A branch entry in the manifest."""
|
|
64
|
+
|
|
65
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
66
|
+
|
|
67
|
+
id: int
|
|
68
|
+
path: str
|
|
69
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ManifestConfigRow(BaseModel):
|
|
73
|
+
"""A single configuration row reference.
|
|
74
|
+
|
|
75
|
+
``metadata`` mirrors :class:`ManifestConfiguration.metadata` and stores
|
|
76
|
+
pull-time hashes (``pull_hash``, ``pull_config_hash``) so the row-level
|
|
77
|
+
diff can distinguish local-changed, remote-changed, and conflict states.
|
|
78
|
+
Older manifests that lack the field load with an empty dict and upgrade
|
|
79
|
+
on the next successful pull.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
83
|
+
|
|
84
|
+
id: str
|
|
85
|
+
path: str
|
|
86
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ManifestConfiguration(BaseModel):
|
|
90
|
+
"""A single configuration reference inside the manifest."""
|
|
91
|
+
|
|
92
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
93
|
+
|
|
94
|
+
branch_id: int = Field(alias="branchId")
|
|
95
|
+
component_id: str = Field(alias="componentId")
|
|
96
|
+
id: str
|
|
97
|
+
path: str
|
|
98
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
99
|
+
rows: list[ManifestConfigRow] = Field(default_factory=list)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ---------------------------------------------------------------------------
|
|
103
|
+
# Root manifest
|
|
104
|
+
# ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class Manifest(BaseModel):
|
|
108
|
+
"""Root model for .keboola/manifest.json (schema version 3)."""
|
|
109
|
+
|
|
110
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
111
|
+
|
|
112
|
+
version: int = MANIFEST_VERSION
|
|
113
|
+
project: ManifestProject
|
|
114
|
+
allow_target_env: bool = Field(default=True, alias="allowTargetEnv")
|
|
115
|
+
git_branching: ManifestGitBranching = Field(
|
|
116
|
+
default_factory=ManifestGitBranching, alias="gitBranching"
|
|
117
|
+
)
|
|
118
|
+
sort_by: str = Field(default="id", alias="sortBy")
|
|
119
|
+
naming: ManifestNaming
|
|
120
|
+
allowed_branches: list[str] = Field(default_factory=list, alias="allowedBranches")
|
|
121
|
+
ignored_components: list[str] = Field(default_factory=list, alias="ignoredComponents")
|
|
122
|
+
branches: list[ManifestBranch] = Field(default_factory=list)
|
|
123
|
+
configurations: list[ManifestConfiguration] = Field(default_factory=list)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
# Load / Save helpers
|
|
128
|
+
# ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def load_manifest(project_root: Path) -> Manifest:
|
|
132
|
+
"""Load .keboola/manifest.json from *project_root*.
|
|
133
|
+
|
|
134
|
+
Raises:
|
|
135
|
+
FileNotFoundError: if the manifest file does not exist.
|
|
136
|
+
ValueError: if the JSON cannot be parsed into a valid Manifest.
|
|
137
|
+
"""
|
|
138
|
+
manifest_path = project_root / KEBOOLA_DIR_NAME / MANIFEST_FILENAME
|
|
139
|
+
if not manifest_path.exists():
|
|
140
|
+
raise FileNotFoundError(
|
|
141
|
+
f"Manifest not found at {manifest_path}. Is this a Keboola project directory?"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
raw = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
145
|
+
return Manifest.model_validate(raw)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def save_manifest(project_root: Path, manifest: Manifest) -> None:
|
|
149
|
+
"""Save *manifest* to .keboola/manifest.json.
|
|
150
|
+
|
|
151
|
+
Uses ``by_alias=True`` so all keys are written in camelCase,
|
|
152
|
+
matching the format expected by the Go CLI.
|
|
153
|
+
"""
|
|
154
|
+
keboola_dir = project_root / KEBOOLA_DIR_NAME
|
|
155
|
+
keboola_dir.mkdir(parents=True, exist_ok=True)
|
|
156
|
+
|
|
157
|
+
manifest_path = keboola_dir / MANIFEST_FILENAME
|
|
158
|
+
payload = manifest.model_dump(mode="json", by_alias=True)
|
|
159
|
+
manifest_path.write_text(
|
|
160
|
+
json.dumps(payload, indent=4, ensure_ascii=False) + "\n",
|
|
161
|
+
encoding="utf-8",
|
|
162
|
+
)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Path generation from naming templates.
|
|
2
|
+
|
|
3
|
+
The naming templates (stored in ``manifest.json``) use placeholders like
|
|
4
|
+
``{component_type}`` and ``{config_name}`` to produce deterministic
|
|
5
|
+
filesystem paths for each configuration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
from ..constants import SANITIZE_NAME_MAX_LENGTH
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def config_path(
|
|
16
|
+
naming_template: str,
|
|
17
|
+
component_type: str,
|
|
18
|
+
component_id: str,
|
|
19
|
+
config_name: str,
|
|
20
|
+
) -> str:
|
|
21
|
+
"""Apply *naming_template* to generate a filesystem path for a configuration.
|
|
22
|
+
|
|
23
|
+
Example template: ``"{component_type}/{component_id}/{config_name}"``
|
|
24
|
+
|
|
25
|
+
All template inputs are passed through sanitizers so that an API-controlled
|
|
26
|
+
``component_id`` like ``"../../etc"`` cannot escape the sync workspace
|
|
27
|
+
(issue #269 sec-01/sec-07). Legitimate component IDs (e.g.
|
|
28
|
+
``keboola.python-transformation-v2``) preserve their dots and hyphens.
|
|
29
|
+
"""
|
|
30
|
+
return naming_template.format(
|
|
31
|
+
component_type=sanitize_path_segment(component_type),
|
|
32
|
+
component_id=sanitize_path_segment(component_id),
|
|
33
|
+
config_name=sanitize_name(config_name),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def config_row_path(naming_template: str, row_name: str) -> str:
|
|
38
|
+
"""Apply *naming_template* to generate a path segment for a config row.
|
|
39
|
+
|
|
40
|
+
Example template: ``"rows/{config_row_name}"``
|
|
41
|
+
"""
|
|
42
|
+
return naming_template.format(
|
|
43
|
+
config_row_name=sanitize_name(row_name),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def sanitize_name(name: str) -> str:
|
|
48
|
+
"""Sanitize *name* for use in filesystem paths.
|
|
49
|
+
|
|
50
|
+
Rules:
|
|
51
|
+
- Lowercase the string
|
|
52
|
+
- Replace spaces and non-alphanumeric characters (except hyphens)
|
|
53
|
+
with hyphens
|
|
54
|
+
- Collapse consecutive hyphens
|
|
55
|
+
- Strip leading and trailing hyphens
|
|
56
|
+
- Truncate to ``SANITIZE_NAME_MAX_LENGTH`` characters
|
|
57
|
+
"""
|
|
58
|
+
result = name.lower()
|
|
59
|
+
# Replace anything that is not alphanumeric or a hyphen
|
|
60
|
+
result = re.sub(r"[^a-z0-9-]", "-", result)
|
|
61
|
+
# Collapse multiple hyphens
|
|
62
|
+
result = re.sub(r"-{2,}", "-", result)
|
|
63
|
+
# Strip leading/trailing hyphens
|
|
64
|
+
result = result.strip("-")
|
|
65
|
+
# Enforce max length
|
|
66
|
+
return result[:SANITIZE_NAME_MAX_LENGTH]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def sanitize_path_segment(token: str) -> str:
|
|
70
|
+
"""Sanitize an API-supplied token for use as a single path segment.
|
|
71
|
+
|
|
72
|
+
Stricter-than-``sanitize_name`` defense against path traversal: rejects
|
|
73
|
+
``/``, ``\\``, parent-directory references (``..``), and other directory
|
|
74
|
+
separators while preserving the dots, hyphens, and underscores commonly
|
|
75
|
+
found in legitimate component IDs (e.g. ``keboola.ex-db-mysql``,
|
|
76
|
+
``kds-team.app-custom-python``). Returns ``"_"`` if the input would
|
|
77
|
+
sanitize to empty so the resulting path always has a non-empty segment
|
|
78
|
+
(issue #269 sec-01).
|
|
79
|
+
"""
|
|
80
|
+
# Replace path separators and whitespace with a single hyphen
|
|
81
|
+
result = re.sub(r"[/\\\s]", "-", token)
|
|
82
|
+
# Replace any run of 2+ dots (which would form parent refs) with
|
|
83
|
+
# a single underscore. Single dots are preserved for legitimate IDs.
|
|
84
|
+
result = re.sub(r"\.{2,}", "_", result)
|
|
85
|
+
# Strip leading dots that could be reintroduced as ``./...`` traversal
|
|
86
|
+
# if the template happens to put us at a directory boundary.
|
|
87
|
+
result = result.lstrip(".")
|
|
88
|
+
# Collapse repeated hyphens introduced by the substitutions
|
|
89
|
+
result = re.sub(r"-{2,}", "-", result).strip("-")
|
|
90
|
+
return result or "_"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Encrypted value detection for Keboola configurations.
|
|
2
|
+
|
|
3
|
+
Keboola stores secrets as encrypted markers (e.g.
|
|
4
|
+
``KBC::ProjectSecure::...``). This module provides helpers to detect
|
|
5
|
+
such values and locate them inside arbitrarily nested configuration dicts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
ENCRYPTED_PREFIXES: tuple[str, ...] = (
|
|
13
|
+
"KBC::ProjectSecure::",
|
|
14
|
+
"KBC::ComponentSecure::",
|
|
15
|
+
"KBC::ConfigSecure::",
|
|
16
|
+
"KBC::ProjectWideSecure::",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def is_encrypted_value(value: Any) -> bool:
|
|
21
|
+
"""Return ``True`` if *value* is a Keboola encrypted marker string."""
|
|
22
|
+
if not isinstance(value, str):
|
|
23
|
+
return False
|
|
24
|
+
return any(value.startswith(prefix) for prefix in ENCRYPTED_PREFIXES)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_secret_key(key: str) -> bool:
|
|
28
|
+
"""Return ``True`` if *key* indicates an encrypted field.
|
|
29
|
+
|
|
30
|
+
By Keboola convention, encrypted parameter keys start with ``#``.
|
|
31
|
+
"""
|
|
32
|
+
return key.startswith("#")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def find_encrypted_paths(obj: Any, prefix: str = "") -> list[str]:
|
|
36
|
+
"""Walk *obj* recursively and return dot-separated paths of all encrypted values.
|
|
37
|
+
|
|
38
|
+
Both *encrypted marker values* and *secret keys* (starting with ``#``)
|
|
39
|
+
are reported.
|
|
40
|
+
|
|
41
|
+
Examples::
|
|
42
|
+
|
|
43
|
+
>>> find_encrypted_paths({"#token": "KBC::ProjectSecure::abc"})
|
|
44
|
+
['#token']
|
|
45
|
+
>>> find_encrypted_paths({"a": {"#key": "val"}})
|
|
46
|
+
['a.#key']
|
|
47
|
+
"""
|
|
48
|
+
paths: list[str] = []
|
|
49
|
+
|
|
50
|
+
if isinstance(obj, dict):
|
|
51
|
+
for key, value in obj.items():
|
|
52
|
+
current = f"{prefix}.{key}" if prefix else key
|
|
53
|
+
if is_secret_key(key) or is_encrypted_value(value):
|
|
54
|
+
paths.append(current)
|
|
55
|
+
else:
|
|
56
|
+
paths.extend(find_encrypted_paths(value, prefix=current))
|
|
57
|
+
elif isinstance(obj, list):
|
|
58
|
+
for idx, item in enumerate(obj):
|
|
59
|
+
current = f"{prefix}[{idx}]"
|
|
60
|
+
paths.extend(find_encrypted_paths(item, prefix=current))
|
|
61
|
+
|
|
62
|
+
return paths
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Split and join SQL statements using a state machine.
|
|
2
|
+
|
|
3
|
+
Splits on semicolons while respecting:
|
|
4
|
+
- Single-quoted strings ('...')
|
|
5
|
+
- Double-quoted identifiers ("...")
|
|
6
|
+
- Dollar-quoted blocks ($$...$$)
|
|
7
|
+
- Line comments (--, #, //)
|
|
8
|
+
- Block comments (/* ... */)
|
|
9
|
+
|
|
10
|
+
Compatible with the Keboola UI splitter and the old keboola-as-code CLI.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from enum import Enum, auto
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _State(Enum):
|
|
19
|
+
NORMAL = auto()
|
|
20
|
+
SINGLE_QUOTE = auto()
|
|
21
|
+
DOUBLE_QUOTE = auto()
|
|
22
|
+
DOLLAR_QUOTE = auto()
|
|
23
|
+
LINE_COMMENT = auto()
|
|
24
|
+
BLOCK_COMMENT = auto()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def split_statements(sql: str) -> list[str]:
|
|
28
|
+
"""Split SQL text into individual statements on semicolons.
|
|
29
|
+
|
|
30
|
+
Returns a list of stripped, non-empty statements. Trailing
|
|
31
|
+
semicolons are preserved on each statement.
|
|
32
|
+
"""
|
|
33
|
+
sql = sql.rstrip()
|
|
34
|
+
if not sql:
|
|
35
|
+
return []
|
|
36
|
+
|
|
37
|
+
state = _State.NORMAL
|
|
38
|
+
statements: list[str] = []
|
|
39
|
+
buf: list[str] = []
|
|
40
|
+
i = 0
|
|
41
|
+
n = len(sql)
|
|
42
|
+
|
|
43
|
+
while i < n:
|
|
44
|
+
ch = sql[i]
|
|
45
|
+
nxt = sql[i + 1] if i + 1 < n else ""
|
|
46
|
+
two = ch + nxt
|
|
47
|
+
|
|
48
|
+
if state == _State.NORMAL:
|
|
49
|
+
if ch == ";":
|
|
50
|
+
buf.append(ch)
|
|
51
|
+
stmt = "".join(buf).strip()
|
|
52
|
+
if stmt.strip(";"):
|
|
53
|
+
statements.append(stmt)
|
|
54
|
+
buf = []
|
|
55
|
+
elif ch == "'":
|
|
56
|
+
buf.append(ch)
|
|
57
|
+
state = _State.SINGLE_QUOTE
|
|
58
|
+
elif ch == '"':
|
|
59
|
+
buf.append(ch)
|
|
60
|
+
state = _State.DOUBLE_QUOTE
|
|
61
|
+
elif two == "$$":
|
|
62
|
+
buf.append(two)
|
|
63
|
+
state = _State.DOLLAR_QUOTE
|
|
64
|
+
i += 1
|
|
65
|
+
elif two in ("--", "//"):
|
|
66
|
+
buf.append(two)
|
|
67
|
+
state = _State.LINE_COMMENT
|
|
68
|
+
i += 1
|
|
69
|
+
elif ch == "#":
|
|
70
|
+
buf.append(ch)
|
|
71
|
+
state = _State.LINE_COMMENT
|
|
72
|
+
elif two == "/*":
|
|
73
|
+
buf.append(two)
|
|
74
|
+
state = _State.BLOCK_COMMENT
|
|
75
|
+
i += 1
|
|
76
|
+
else:
|
|
77
|
+
buf.append(ch)
|
|
78
|
+
|
|
79
|
+
elif state == _State.SINGLE_QUOTE:
|
|
80
|
+
if ch == "\\" and nxt:
|
|
81
|
+
buf.append(two)
|
|
82
|
+
i += 1
|
|
83
|
+
elif ch == "'":
|
|
84
|
+
buf.append(ch)
|
|
85
|
+
state = _State.NORMAL
|
|
86
|
+
else:
|
|
87
|
+
buf.append(ch)
|
|
88
|
+
|
|
89
|
+
elif state == _State.DOUBLE_QUOTE:
|
|
90
|
+
if ch == "\\" and nxt:
|
|
91
|
+
buf.append(two)
|
|
92
|
+
i += 1
|
|
93
|
+
elif ch == '"':
|
|
94
|
+
buf.append(ch)
|
|
95
|
+
state = _State.NORMAL
|
|
96
|
+
else:
|
|
97
|
+
buf.append(ch)
|
|
98
|
+
|
|
99
|
+
elif state == _State.DOLLAR_QUOTE:
|
|
100
|
+
if two == "$$":
|
|
101
|
+
buf.append(two)
|
|
102
|
+
state = _State.NORMAL
|
|
103
|
+
i += 1
|
|
104
|
+
else:
|
|
105
|
+
buf.append(ch)
|
|
106
|
+
|
|
107
|
+
elif state == _State.LINE_COMMENT:
|
|
108
|
+
buf.append(ch)
|
|
109
|
+
if ch == "\n":
|
|
110
|
+
state = _State.NORMAL
|
|
111
|
+
|
|
112
|
+
elif state == _State.BLOCK_COMMENT:
|
|
113
|
+
if two == "*/":
|
|
114
|
+
buf.append(two)
|
|
115
|
+
state = _State.NORMAL
|
|
116
|
+
i += 1
|
|
117
|
+
else:
|
|
118
|
+
buf.append(ch)
|
|
119
|
+
|
|
120
|
+
i += 1
|
|
121
|
+
|
|
122
|
+
# Remaining content without trailing semicolon
|
|
123
|
+
remaining = "".join(buf).strip()
|
|
124
|
+
if remaining:
|
|
125
|
+
statements.append(remaining)
|
|
126
|
+
|
|
127
|
+
return statements
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def join_statements(statements: list[str]) -> str:
|
|
131
|
+
"""Join SQL statements with double newlines (matching Keboola convention)."""
|
|
132
|
+
if not statements:
|
|
133
|
+
return ""
|
|
134
|
+
return "\n\n".join(s.rstrip() for s in statements)
|