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.
Files changed (306) hide show
  1. keboola_agent_cli/__init__.py +34 -0
  2. keboola_agent_cli/__main__.py +5 -0
  3. keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js +2 -0
  4. keboola_agent_cli/_ui_dist/assets/arc-DhFYIddx.js.map +1 -0
  5. keboola_agent_cli/_ui_dist/assets/architecture-7EHR7CIX-hNCijx_H.js +1 -0
  6. keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js +37 -0
  7. keboola_agent_cli/_ui_dist/assets/architectureDiagram-3BPJPVTR-C6hUlprM.js.map +1 -0
  8. keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js +2 -0
  9. keboola_agent_cli/_ui_dist/assets/array-BifhSqXX.js.map +1 -0
  10. keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js +133 -0
  11. keboola_agent_cli/_ui_dist/assets/blockDiagram-GPEHLZMM-DC7qY9i4.js.map +1 -0
  12. keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js +11 -0
  13. keboola_agent_cli/_ui_dist/assets/c4Diagram-AAUBKEIU-5Lh44evt.js.map +1 -0
  14. keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js +2 -0
  15. keboola_agent_cli/_ui_dist/assets/channel-DBMrXlxx.js.map +1 -0
  16. keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js +2 -0
  17. keboola_agent_cli/_ui_dist/assets/chunk-2J33WTMH-Coy82EBh.js.map +1 -0
  18. keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js +63 -0
  19. keboola_agent_cli/_ui_dist/assets/chunk-3OPIFGDE-BQC5CRHI.js.map +1 -0
  20. keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js +2 -0
  21. keboola_agent_cli/_ui_dist/assets/chunk-4BX2VUAB-DUuEt70o.js.map +1 -0
  22. keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js +2 -0
  23. keboola_agent_cli/_ui_dist/assets/chunk-55IACEB6-BvR-6chF.js.map +1 -0
  24. keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js +3 -0
  25. keboola_agent_cli/_ui_dist/assets/chunk-5ZQYHXKU-BjcTN7ul.js.map +1 -0
  26. keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js +207 -0
  27. keboola_agent_cli/_ui_dist/assets/chunk-727SXJPM-C0zxqqRN.js.map +1 -0
  28. keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js +232 -0
  29. keboola_agent_cli/_ui_dist/assets/chunk-AQP2D5EJ-CXf7rIlZ.js.map +1 -0
  30. keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js +2 -0
  31. keboola_agent_cli/_ui_dist/assets/chunk-BSJP7CBP-Oj_FO9Q7.js.map +1 -0
  32. keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js +124 -0
  33. keboola_agent_cli/_ui_dist/assets/chunk-CSCIHK7Q-CcTsLrFc.js.map +1 -0
  34. keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js +16 -0
  35. keboola_agent_cli/_ui_dist/assets/chunk-FMBD7UC4-FH-zLkkW.js.map +1 -0
  36. keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js +2 -0
  37. keboola_agent_cli/_ui_dist/assets/chunk-L5ZTLDWV-B1Ky_e7O.js.map +1 -0
  38. keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js +2 -0
  39. keboola_agent_cli/_ui_dist/assets/chunk-ND2GUHAM-BHz1rpbm.js.map +1 -0
  40. keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js +160 -0
  41. keboola_agent_cli/_ui_dist/assets/chunk-NNHCCRGN-DlpIbxXb.js.map +1 -0
  42. keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js +2 -0
  43. keboola_agent_cli/_ui_dist/assets/chunk-NZK2D7GU-tnrSoegS.js.map +1 -0
  44. keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js +71 -0
  45. keboola_agent_cli/_ui_dist/assets/chunk-O5CBEL6O-DxxqDH0l.js.map +1 -0
  46. keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js +2 -0
  47. keboola_agent_cli/_ui_dist/assets/chunk-QZHKN3VN-CSjc2gjj.js.map +1 -0
  48. keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js +2 -0
  49. keboola_agent_cli/_ui_dist/assets/classDiagram-4FO5ZUOK-BuZcZu85.js.map +1 -0
  50. keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js +2 -0
  51. keboola_agent_cli/_ui_dist/assets/classDiagram-v2-Q7XG4LA2-BuZcZu85.js.map +1 -0
  52. keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js +2 -0
  53. keboola_agent_cli/_ui_dist/assets/cose-bilkent-S5V4N54A-Y0L8LDMa.js.map +1 -0
  54. keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js +322 -0
  55. keboola_agent_cli/_ui_dist/assets/cytoscape.esm-C8YCVR3_.js.map +1 -0
  56. keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js +5 -0
  57. keboola_agent_cli/_ui_dist/assets/dagre-BM42HDAG-UZ-9BTqF.js.map +1 -0
  58. keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js +2 -0
  59. keboola_agent_cli/_ui_dist/assets/dagre-Bx709z4p.js.map +1 -0
  60. keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js +2 -0
  61. keboola_agent_cli/_ui_dist/assets/defaultLocale-C8Fc0cco.js.map +1 -0
  62. keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js +44 -0
  63. keboola_agent_cli/_ui_dist/assets/diagram-2AECGRRQ-DoDQ60wi.js.map +1 -0
  64. keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js +11 -0
  65. keboola_agent_cli/_ui_dist/assets/diagram-5GNKFQAL-CMGFxpUs.js.map +1 -0
  66. keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js +4 -0
  67. keboola_agent_cli/_ui_dist/assets/diagram-KO2AKTUF-1uGDa-Iu.js.map +1 -0
  68. keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js +25 -0
  69. keboola_agent_cli/_ui_dist/assets/diagram-LMA3HP47-XtFH7B51.js.map +1 -0
  70. keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js +25 -0
  71. keboola_agent_cli/_ui_dist/assets/diagram-OG6HWLK6-B4_Te1T5.js.map +1 -0
  72. keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js +2 -0
  73. keboola_agent_cli/_ui_dist/assets/dist-Di6zmlv0.js.map +1 -0
  74. keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js +86 -0
  75. keboola_agent_cli/_ui_dist/assets/erDiagram-TEJ5UH35-NjQkrdFt.js.map +1 -0
  76. keboola_agent_cli/_ui_dist/assets/eventmodeling-FCH6USID-BrJMIks8.js +1 -0
  77. keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js +163 -0
  78. keboola_agent_cli/_ui_dist/assets/flowDiagram-I6XJVG4X-CIr8DWl7.js.map +1 -0
  79. keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js +293 -0
  80. keboola_agent_cli/_ui_dist/assets/ganttDiagram-6RSMTGT7-C1VY_xbQ.js.map +1 -0
  81. keboola_agent_cli/_ui_dist/assets/gitGraph-WXDBUCRP-COacYjo-.js +1 -0
  82. keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js +107 -0
  83. keboola_agent_cli/_ui_dist/assets/gitGraphDiagram-PVQCEYII-DQT8-kg2.js.map +1 -0
  84. keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js +2 -0
  85. keboola_agent_cli/_ui_dist/assets/graphlib-B8gBHxth.js.map +1 -0
  86. keboola_agent_cli/_ui_dist/assets/index-CMq50kkV.css +1 -0
  87. keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js +118 -0
  88. keboola_agent_cli/_ui_dist/assets/index-D8W97DAz.js.map +1 -0
  89. keboola_agent_cli/_ui_dist/assets/info-J43DQDTF-DdCTRIzU.js +1 -0
  90. keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js +3 -0
  91. keboola_agent_cli/_ui_dist/assets/infoDiagram-5YYISTIA-C77rsoTp.js.map +1 -0
  92. keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js +2 -0
  93. keboola_agent_cli/_ui_dist/assets/init-D6jRqBbL.js.map +1 -0
  94. keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js +71 -0
  95. keboola_agent_cli/_ui_dist/assets/ishikawaDiagram-YF4QCWOH-BcTbXaLy.js.map +1 -0
  96. keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js +140 -0
  97. keboola_agent_cli/_ui_dist/assets/journeyDiagram-JHISSGLW-BejeAJQ_.js.map +1 -0
  98. keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js +90 -0
  99. keboola_agent_cli/_ui_dist/assets/kanban-definition-UN3LZRKU-BRNz_UrH.js.map +1 -0
  100. keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js +258 -0
  101. keboola_agent_cli/_ui_dist/assets/katex-C4eR7coU.js.map +1 -0
  102. keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js +2 -0
  103. keboola_agent_cli/_ui_dist/assets/line-CzAQKFbJ.js.map +1 -0
  104. keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js +2 -0
  105. keboola_agent_cli/_ui_dist/assets/linear-DUNFFdck.js.map +1 -0
  106. keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js +5 -0
  107. keboola_agent_cli/_ui_dist/assets/mermaid-parser.core-CpuBOkFa.js.map +1 -0
  108. keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js +97 -0
  109. keboola_agent_cli/_ui_dist/assets/mindmap-definition-RKZ34NQL-9EJQNjH0.js.map +1 -0
  110. keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js +2 -0
  111. keboola_agent_cli/_ui_dist/assets/ordinal-hYBb2elL.js.map +1 -0
  112. keboola_agent_cli/_ui_dist/assets/packet-YPE3B663-DLiiw_B2.js +1 -0
  113. keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js +2 -0
  114. keboola_agent_cli/_ui_dist/assets/path-BWPyau1x.js.map +1 -0
  115. keboola_agent_cli/_ui_dist/assets/pie-LRSECV5Y-CRoO8G1g.js +1 -0
  116. keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js +31 -0
  117. keboola_agent_cli/_ui_dist/assets/pieDiagram-4H26LBE5-XH4cy6Cb.js.map +1 -0
  118. keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js +8 -0
  119. keboola_agent_cli/_ui_dist/assets/quadrantDiagram-W4KKPZXB-fdhc93U8.js.map +1 -0
  120. keboola_agent_cli/_ui_dist/assets/radar-GUYGQ44K-DAlLVJHm.js +1 -0
  121. keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js +85 -0
  122. keboola_agent_cli/_ui_dist/assets/requirementDiagram-4Y6WPE33-a94eP3R9.js.map +1 -0
  123. keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js +2 -0
  124. keboola_agent_cli/_ui_dist/assets/rough.esm-CSKSodPl.js.map +1 -0
  125. keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js +41 -0
  126. keboola_agent_cli/_ui_dist/assets/sankeyDiagram-5OEKKPKP-jcBa02sp.js.map +1 -0
  127. keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js +163 -0
  128. keboola_agent_cli/_ui_dist/assets/sequenceDiagram-3UESZ5HK-A5-GGM-e.js.map +1 -0
  129. keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js +2 -0
  130. keboola_agent_cli/_ui_dist/assets/src-ZI-V_AF0.js.map +1 -0
  131. keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js +2 -0
  132. keboola_agent_cli/_ui_dist/assets/stateDiagram-AJRCARHV-BKAA5rqE.js.map +1 -0
  133. keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js +2 -0
  134. keboola_agent_cli/_ui_dist/assets/stateDiagram-v2-BHNVJYJU-DnJwJBsE.js.map +1 -0
  135. keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js +121 -0
  136. keboola_agent_cli/_ui_dist/assets/timeline-definition-PNZ67QCA-Cy39jp8b.js.map +1 -0
  137. keboola_agent_cli/_ui_dist/assets/treeView-BLDUP644-DbLYl23-.js +1 -0
  138. keboola_agent_cli/_ui_dist/assets/treemap-LRROVOQU-Bp0eGlOt.js +1 -0
  139. keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js +35 -0
  140. keboola_agent_cli/_ui_dist/assets/vennDiagram-CIIHVFJN-BGECKubd.js.map +1 -0
  141. keboola_agent_cli/_ui_dist/assets/wardley-L42UT6IY-D4yH4jqS.js +1 -0
  142. keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js +79 -0
  143. keboola_agent_cli/_ui_dist/assets/wardleyDiagram-YWT4CUSO-D6XRG3cZ.js.map +1 -0
  144. keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js +8 -0
  145. keboola_agent_cli/_ui_dist/assets/xychartDiagram-2RQKCTM6-DRre-pfZ.js.map +1 -0
  146. keboola_agent_cli/_ui_dist/index.html +50 -0
  147. keboola_agent_cli/ai_client.py +83 -0
  148. keboola_agent_cli/auto_update.py +550 -0
  149. keboola_agent_cli/changelog.py +1198 -0
  150. keboola_agent_cli/cli.py +448 -0
  151. keboola_agent_cli/client.py +3422 -0
  152. keboola_agent_cli/commands/__init__.py +0 -0
  153. keboola_agent_cli/commands/_data_app_git.py +343 -0
  154. keboola_agent_cli/commands/_helpers.py +377 -0
  155. keboola_agent_cli/commands/_metadata_input.py +49 -0
  156. keboola_agent_cli/commands/_semantic_layer_crud.py +632 -0
  157. keboola_agent_cli/commands/_semantic_layer_helpers.py +44 -0
  158. keboola_agent_cli/commands/_semantic_layer_reference_data.py +247 -0
  159. keboola_agent_cli/commands/agent.py +968 -0
  160. keboola_agent_cli/commands/branch.py +423 -0
  161. keboola_agent_cli/commands/changelog.py +168 -0
  162. keboola_agent_cli/commands/component.py +216 -0
  163. keboola_agent_cli/commands/config.py +2442 -0
  164. keboola_agent_cli/commands/context.py +1481 -0
  165. keboola_agent_cli/commands/data_app.py +1279 -0
  166. keboola_agent_cli/commands/dev_portal.py +584 -0
  167. keboola_agent_cli/commands/doctor.py +37 -0
  168. keboola_agent_cli/commands/encrypt.py +145 -0
  169. keboola_agent_cli/commands/feature.py +311 -0
  170. keboola_agent_cli/commands/flow.py +948 -0
  171. keboola_agent_cli/commands/http_client.py +157 -0
  172. keboola_agent_cli/commands/init.py +279 -0
  173. keboola_agent_cli/commands/job.py +661 -0
  174. keboola_agent_cli/commands/kai.py +301 -0
  175. keboola_agent_cli/commands/lineage.py +1464 -0
  176. keboola_agent_cli/commands/org.py +292 -0
  177. keboola_agent_cli/commands/permissions.py +360 -0
  178. keboola_agent_cli/commands/project.py +1192 -0
  179. keboola_agent_cli/commands/repl.py +243 -0
  180. keboola_agent_cli/commands/schedule.py +340 -0
  181. keboola_agent_cli/commands/search.py +178 -0
  182. keboola_agent_cli/commands/semantic_layer.py +939 -0
  183. keboola_agent_cli/commands/serve.py +272 -0
  184. keboola_agent_cli/commands/sharing.py +340 -0
  185. keboola_agent_cli/commands/storage.py +2630 -0
  186. keboola_agent_cli/commands/stream.py +266 -0
  187. keboola_agent_cli/commands/sync.py +1277 -0
  188. keboola_agent_cli/commands/tool.py +206 -0
  189. keboola_agent_cli/commands/version.py +186 -0
  190. keboola_agent_cli/commands/workspace.py +635 -0
  191. keboola_agent_cli/config_store.py +582 -0
  192. keboola_agent_cli/constants.py +528 -0
  193. keboola_agent_cli/data_science_client.py +342 -0
  194. keboola_agent_cli/dev_portal_client.py +323 -0
  195. keboola_agent_cli/errors.py +248 -0
  196. keboola_agent_cli/http_base.py +315 -0
  197. keboola_agent_cli/json_utils.py +126 -0
  198. keboola_agent_cli/lib.py +536 -0
  199. keboola_agent_cli/manage_client.py +324 -0
  200. keboola_agent_cli/metastore_client.py +214 -0
  201. keboola_agent_cli/models.py +427 -0
  202. keboola_agent_cli/output.py +1084 -0
  203. keboola_agent_cli/permissions.py +469 -0
  204. keboola_agent_cli/py.typed +3 -0
  205. keboola_agent_cli/result_models.py +271 -0
  206. keboola_agent_cli/server/__init__.py +34 -0
  207. keboola_agent_cli/server/agent_runner.py +1289 -0
  208. keboola_agent_cli/server/agents_store.py +325 -0
  209. keboola_agent_cli/server/app.py +764 -0
  210. keboola_agent_cli/server/auth.py +117 -0
  211. keboola_agent_cli/server/dependencies.py +149 -0
  212. keboola_agent_cli/server/pricing.py +303 -0
  213. keboola_agent_cli/server/routers/__init__.py +1 -0
  214. keboola_agent_cli/server/routers/agents.py +616 -0
  215. keboola_agent_cli/server/routers/ai_chat.py +129 -0
  216. keboola_agent_cli/server/routers/branches.py +133 -0
  217. keboola_agent_cli/server/routers/components.py +48 -0
  218. keboola_agent_cli/server/routers/configs.py +507 -0
  219. keboola_agent_cli/server/routers/data_apps.py +384 -0
  220. keboola_agent_cli/server/routers/dev_portal.py +67 -0
  221. keboola_agent_cli/server/routers/encrypt.py +35 -0
  222. keboola_agent_cli/server/routers/feature.py +179 -0
  223. keboola_agent_cli/server/routers/flows.py +204 -0
  224. keboola_agent_cli/server/routers/health.py +53 -0
  225. keboola_agent_cli/server/routers/jobs.py +175 -0
  226. keboola_agent_cli/server/routers/kai.py +80 -0
  227. keboola_agent_cli/server/routers/lineage.py +226 -0
  228. keboola_agent_cli/server/routers/mcp.py +70 -0
  229. keboola_agent_cli/server/routers/members.py +170 -0
  230. keboola_agent_cli/server/routers/org.py +96 -0
  231. keboola_agent_cli/server/routers/projects.py +106 -0
  232. keboola_agent_cli/server/routers/schedules.py +54 -0
  233. keboola_agent_cli/server/routers/search.py +30 -0
  234. keboola_agent_cli/server/routers/semantic_layer.py +650 -0
  235. keboola_agent_cli/server/routers/sharing.py +86 -0
  236. keboola_agent_cli/server/routers/storage.py +574 -0
  237. keboola_agent_cli/server/routers/stream.py +100 -0
  238. keboola_agent_cli/server/routers/workspaces.py +302 -0
  239. keboola_agent_cli/server/run_broadcaster.py +329 -0
  240. keboola_agent_cli/server/sse.py +25 -0
  241. keboola_agent_cli/services/__init__.py +0 -0
  242. keboola_agent_cli/services/_encryption.py +217 -0
  243. keboola_agent_cli/services/_semantic_layer_cascade.py +147 -0
  244. keboola_agent_cli/services/_semantic_layer_crud.py +382 -0
  245. keboola_agent_cli/services/_semantic_layer_internals.py +1078 -0
  246. keboola_agent_cli/services/_semantic_layer_lookup.py +181 -0
  247. keboola_agent_cli/services/_semantic_layer_reference_data.py +217 -0
  248. keboola_agent_cli/services/_sync_bindings.py +456 -0
  249. keboola_agent_cli/services/_sync_branch.py +191 -0
  250. keboola_agent_cli/services/_sync_bulk.py +228 -0
  251. keboola_agent_cli/services/_sync_clone.py +163 -0
  252. keboola_agent_cli/services/_sync_models.py +97 -0
  253. keboola_agent_cli/services/_sync_push_ops.py +369 -0
  254. keboola_agent_cli/services/_sync_storage.py +376 -0
  255. keboola_agent_cli/services/_sync_writeback.py +167 -0
  256. keboola_agent_cli/services/agent_service.py +458 -0
  257. keboola_agent_cli/services/base.py +175 -0
  258. keboola_agent_cli/services/branch_service.py +588 -0
  259. keboola_agent_cli/services/component_service.py +694 -0
  260. keboola_agent_cli/services/config_service.py +2099 -0
  261. keboola_agent_cli/services/data_app_git_service.py +224 -0
  262. keboola_agent_cli/services/data_app_service.py +2082 -0
  263. keboola_agent_cli/services/deep_lineage_service.py +1322 -0
  264. keboola_agent_cli/services/dev_portal_service.py +345 -0
  265. keboola_agent_cli/services/doctor_service.py +445 -0
  266. keboola_agent_cli/services/encrypt_service.py +87 -0
  267. keboola_agent_cli/services/feature_service.py +268 -0
  268. keboola_agent_cli/services/flow_service.py +769 -0
  269. keboola_agent_cli/services/flow_validation.py +188 -0
  270. keboola_agent_cli/services/http_forwarder_service.py +236 -0
  271. keboola_agent_cli/services/job_idempotency_store.py +285 -0
  272. keboola_agent_cli/services/job_service.py +797 -0
  273. keboola_agent_cli/services/kai_service.py +367 -0
  274. keboola_agent_cli/services/lineage_service.py +274 -0
  275. keboola_agent_cli/services/mcp_service.py +1498 -0
  276. keboola_agent_cli/services/mcp_transport.py +259 -0
  277. keboola_agent_cli/services/member_service.py +593 -0
  278. keboola_agent_cli/services/org_service.py +619 -0
  279. keboola_agent_cli/services/project_service.py +947 -0
  280. keboola_agent_cli/services/repo_validate_service.py +767 -0
  281. keboola_agent_cli/services/schedule_service.py +731 -0
  282. keboola_agent_cli/services/search_service.py +331 -0
  283. keboola_agent_cli/services/semantic_layer_service.py +1497 -0
  284. keboola_agent_cli/services/sharing_service.py +307 -0
  285. keboola_agent_cli/services/storage_service.py +2524 -0
  286. keboola_agent_cli/services/stream_service.py +395 -0
  287. keboola_agent_cli/services/sync_service.py +2244 -0
  288. keboola_agent_cli/services/variables_service.py +447 -0
  289. keboola_agent_cli/services/version_service.py +1038 -0
  290. keboola_agent_cli/services/workspace_service.py +1103 -0
  291. keboola_agent_cli/stream_client.py +217 -0
  292. keboola_agent_cli/sync/__init__.py +1 -0
  293. keboola_agent_cli/sync/branch_mapping.py +174 -0
  294. keboola_agent_cli/sync/clone.py +211 -0
  295. keboola_agent_cli/sync/code_extraction.py +655 -0
  296. keboola_agent_cli/sync/config_format.py +290 -0
  297. keboola_agent_cli/sync/diff_engine.py +566 -0
  298. keboola_agent_cli/sync/git_utils.py +93 -0
  299. keboola_agent_cli/sync/manifest.py +162 -0
  300. keboola_agent_cli/sync/naming.py +90 -0
  301. keboola_agent_cli/sync/secrets.py +62 -0
  302. keboola_agent_cli/sync/sql_split.py +134 -0
  303. keboola_cli-0.63.4.dist-info/METADATA +308 -0
  304. keboola_cli-0.63.4.dist-info/RECORD +306 -0
  305. keboola_cli-0.63.4.dist-info/WHEEL +4 -0
  306. 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))