datex-studio-cli 0.3.3__tar.gz → 0.3.4__tar.gz

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 (170) hide show
  1. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/.gitignore +7 -0
  2. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/PKG-INFO +2 -1
  3. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/pyproject.toml +3 -2
  4. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/__init__.py +1 -1
  5. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/cli.py +4 -0
  6. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/branch.py +173 -49
  7. datex_studio_cli-0.3.4/src/dxs/commands/datasource.py +1250 -0
  8. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/devops.py +62 -4
  9. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/document.py +252 -144
  10. datex_studio_cli-0.3.4/src/dxs/commands/endpoint.py +609 -0
  11. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/explore.py +856 -240
  12. datex_studio_cli-0.3.4/src/dxs/commands/function.py +424 -0
  13. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/release_notes.py +2 -2
  14. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/__init__.py +29 -14
  15. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/add_cmds.py +50 -52
  16. datex_studio_cli-0.3.4/src/dxs/commands/report/api.py +427 -0
  17. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/batch.py +1 -1
  18. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/create.py +77 -45
  19. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/data.py +1 -1
  20. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/dataset.py +80 -11
  21. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/edit.py +3 -3
  22. datex_studio_cli-0.3.4/src/dxs/commands/report/folder.py +472 -0
  23. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/preview.py +0 -2
  24. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/schema.py +102 -971
  25. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/servicepack.py +5 -5
  26. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/source.py +3 -2
  27. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/studio.py +8 -1
  28. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/api/endpoints.py +35 -4
  29. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/api/models.py +7 -7
  30. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/cache.py +106 -106
  31. datex_studio_cli-0.3.4/src/dxs/core/datasource/__init__.py +19 -0
  32. datex_studio_cli-0.3.4/src/dxs/core/datasource/flow_generator.py +184 -0
  33. datex_studio_cli-0.3.4/src/dxs/core/datasource/flow_models.py +45 -0
  34. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/datasource/generator.py +36 -17
  35. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/datasource/models.py +25 -28
  36. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/datasource/parsers.py +95 -101
  37. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/datasource/resolver.py +59 -24
  38. datex_studio_cli-0.3.4/src/dxs/core/datasource/type_def_parser.py +9 -0
  39. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/datasource/validator.py +43 -37
  40. datex_studio_cli-0.3.4/src/dxs/core/designer/flow_models.py +34 -0
  41. datex_studio_cli-0.3.4/src/dxs/core/designer/models.py +36 -0
  42. datex_studio_cli-0.3.4/src/dxs/core/designer/parsers.py +224 -0
  43. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/devops/models.py +24 -1
  44. datex_studio_cli-0.3.4/src/dxs/core/function/__init__.py +0 -0
  45. datex_studio_cli-0.3.4/src/dxs/core/function/generator.py +143 -0
  46. datex_studio_cli-0.3.4/src/dxs/core/function/models.py +45 -0
  47. datex_studio_cli-0.3.4/src/dxs/core/function/validator.py +98 -0
  48. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/graph.py +88 -54
  49. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/datasource_binding.py +18 -20
  50. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/engine.py +120 -86
  51. datex_studio_cli-0.3.4/src/dxs/report/folder.py +469 -0
  52. datex_studio_cli-0.3.4/src/dxs/report/manifest.py +126 -0
  53. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/models.py +6 -21
  54. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/preview.py +12 -4
  55. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/preview_arjs.py +29 -3
  56. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/schema.py +8 -3
  57. datex_studio_cli-0.3.4/src/dxs/report/templates/__init__.py +0 -0
  58. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/validator.py +304 -13
  59. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/wrapper.py +0 -23
  60. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/click_options.py +142 -1
  61. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/paths.py +26 -22
  62. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/resolvers.py +82 -0
  63. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/404/index.html +1 -1
  64. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/404.html +1 -1
  65. datex_studio_cli-0.3.4/src/dxs/web/static/_next/static/chunks/538-84e2e111415f1fda.js +1 -0
  66. datex_studio_cli-0.3.3/src/dxs/web/static/_next/static/css/a4597027cb06b77d.css → datex_studio_cli-0.3.4/src/dxs/web/static/_next/static/css/360c657de5e04df8.css +1 -1
  67. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/design/capture/index.html +1 -1
  68. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/design/capture/index.txt +3 -3
  69. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/design/index.html +1 -1
  70. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/design/index.txt +3 -3
  71. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/index.html +1 -1
  72. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/index.txt +2 -2
  73. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/render-cli.js +200 -71
  74. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/report-preview.html +53 -1
  75. datex_studio_cli-0.3.3/examples/bill-of-lading/01-schema-exploration.md +0 -303
  76. datex_studio_cli-0.3.3/examples/bill-of-lading/02-field-mapping.md +0 -192
  77. datex_studio_cli-0.3.3/examples/bill-of-lading/bill-of-lading.data.json +0 -105
  78. datex_studio_cli-0.3.3/examples/bill-of-lading/bill-of-lading.rdlx-json +0 -857
  79. datex_studio_cli-0.3.3/src/dxs/commands/datasource.py +0 -564
  80. datex_studio_cli-0.3.3/src/dxs/commands/report/api.py +0 -716
  81. datex_studio_cli-0.3.3/src/dxs/core/datasource/__init__.py +0 -10
  82. datex_studio_cli-0.3.3/src/dxs/report/owned_datasource.py +0 -340
  83. datex_studio_cli-0.3.3/src/dxs/web/static/_next/static/chunks/538-0c48d257061c2519.js +0 -1
  84. datex_studio_cli-0.3.3/test-preview.svg +0 -1
  85. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/README.md +0 -0
  86. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/report-creator.skill +0 -0
  87. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/scripts/analyze_corpus.py +0 -0
  88. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/scripts/generate_rdlx_schema.py +0 -0
  89. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/__main__.py +0 -0
  90. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/__init__.py +0 -0
  91. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/api.py +0 -0
  92. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/auth.py +0 -0
  93. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/config.py +0 -0
  94. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/crm.py +0 -0
  95. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/env.py +0 -0
  96. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/marketplace.py +0 -0
  97. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/odata.py +0 -0
  98. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/organization.py +0 -0
  99. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/proxy.py +0 -0
  100. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/repo.py +0 -0
  101. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/report/schema_cmds.py +0 -0
  102. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/commands/user.py +0 -0
  103. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/context.py +0 -0
  104. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/__init__.py +0 -0
  105. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/api/__init__.py +0 -0
  106. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/api/client.py +0 -0
  107. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/api/metadata_models.py +0 -0
  108. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/auth/__init__.py +0 -0
  109. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/auth/decorators.py +0 -0
  110. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/auth/msal_client.py +0 -0
  111. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/auth/token_cache.py +0 -0
  112. {datex_studio_cli-0.3.3/src/dxs/report/templates → datex_studio_cli-0.3.4/src/dxs/core/designer}/__init__.py +0 -0
  113. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/devops/__init__.py +0 -0
  114. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/devops/client.py +0 -0
  115. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/devops/helpers.py +0 -0
  116. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/dynamics/__init__.py +0 -0
  117. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/dynamics/client.py +0 -0
  118. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/footprint/__init__.py +0 -0
  119. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/footprint/client.py +0 -0
  120. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/footprint/edmx_parser.py +0 -0
  121. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/footprint/metadata.py +0 -0
  122. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/output/__init__.py +0 -0
  123. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/output/csv_fmt.py +0 -0
  124. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/output/formatter.py +0 -0
  125. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/output/json_fmt.py +0 -0
  126. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/output/redaction.py +0 -0
  127. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/output/yaml_fmt.py +0 -0
  128. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/release_notes.py +0 -0
  129. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/core/responses.py +0 -0
  130. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/models/__init__.py +0 -0
  131. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/__init__.py +0 -0
  132. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/field_parser.py +0 -0
  133. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/svg_renderer.py +0 -0
  134. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/templates/bill_of_lading.rdlx-json +0 -0
  135. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/templates/shipping_label.rdlx-json +0 -0
  136. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/report/validate_arjs.py +0 -0
  137. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/__init__.py +0 -0
  138. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/config.py +0 -0
  139. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/errors.py +0 -0
  140. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/filtering.py +0 -0
  141. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/image.py +0 -0
  142. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/responses.py +0 -0
  143. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/restricted.py +0 -0
  144. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/utils/sorting.py +0 -0
  145. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/__init__.py +0 -0
  146. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/app.py +0 -0
  147. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/design.py +0 -0
  148. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/proxy_app.py +0 -0
  149. {datex_studio_cli-0.3.3/src/dxs/web/static/_next/static/tKckXNZJLjE7JZyWX_89t → datex_studio_cli-0.3.4/src/dxs/web/static/_next/static/UgyAMtPjH-Pt0RYWOHzIT}/_buildManifest.js +0 -0
  150. {datex_studio_cli-0.3.3/src/dxs/web/static/_next/static/tKckXNZJLjE7JZyWX_89t → datex_studio_cli-0.3.4/src/dxs/web/static/_next/static/UgyAMtPjH-Pt0RYWOHzIT}/_ssgManifest.js +0 -0
  151. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/0b24cca5-c1e1c8810348f107.js +0 -0
  152. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/255-102f2e5b2e3dc2ef.js +0 -0
  153. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +0 -0
  154. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/697-0e000ab410d9f470.js +0 -0
  155. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/871-1acacdb7b4022abf.js +0 -0
  156. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/8b8f67fc-6295949a4b5485a4.js +0 -0
  157. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/909-c88abba3cf0caec3.js +0 -0
  158. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/app/_not-found/page-ea1be7001c230704.js +0 -0
  159. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/app/design/capture/page-a5e129c2d223432c.js +0 -0
  160. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/app/design/page-21ba66a3dd3b03f0.js +0 -0
  161. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/app/layout-2cc6eac09e476c91.js +0 -0
  162. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/app/page-20c358395882cdac.js +0 -0
  163. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/framework-de98b93a850cfc71.js +0 -0
  164. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/main-0f18f91200dac003.js +0 -0
  165. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/main-app-b69998d8941231d8.js +0 -0
  166. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/pages/_app-7d307437aca18ad4.js +0 -0
  167. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +0 -0
  168. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  169. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/_next/static/chunks/webpack-2b297ada5306c17f.js +0 -0
  170. {datex_studio_cli-0.3.3 → datex_studio_cli-0.3.4}/src/dxs/web/static/report-validate.html +0 -0
@@ -3,6 +3,7 @@ exploration/
3
3
  reviews/
4
4
  .tap/
5
5
  .superpowers/
6
+ .worktrees/
6
7
 
7
8
  node_modules/
8
9
 
@@ -92,3 +93,9 @@ Thumbs.db
92
93
 
93
94
  #Claude
94
95
  .claude/settings.local.json
96
+ .claude/skills
97
+
98
+ # Report generation assets
99
+ /reports/
100
+ test-preview.svg
101
+ test-preview.svg
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datex-studio-cli
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: CLI for Datex Studio low-code platform, designed for LLM-based AI agents
5
5
  Project-URL: Homepage, https://github.com/datex/datex-studio-cli
6
6
  Project-URL: Documentation, https://github.com/datex/datex-studio-cli
@@ -29,6 +29,7 @@ Requires-Dist: pydantic>=2.5.0
29
29
  Requires-Dist: pyyaml>=6.0
30
30
  Provides-Extra: dev
31
31
  Requires-Dist: fastapi>=0.115.0; extra == 'dev'
32
+ Requires-Dist: jsonschema>=4.20.0; extra == 'dev'
32
33
  Requires-Dist: mypy>=1.8.0; extra == 'dev'
33
34
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
34
35
  Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "datex-studio-cli"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "CLI for Datex Studio low-code platform, designed for LLM-based AI agents"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -59,6 +59,7 @@ dev = [
59
59
  "ruff>=0.4.0",
60
60
  "mypy>=1.8.0",
61
61
  "types-PyYAML>=6.0.0",
62
+ "jsonschema>=4.20.0",
62
63
  # Include studio dependencies for testing studio/proxy commands
63
64
  "fastapi>=0.115.0",
64
65
  "uvicorn[standard]>=0.32.0",
@@ -81,7 +82,7 @@ exclude = ["src/dxs/web/frontend/", "example-reports/"]
81
82
  artifacts = ["src/dxs/web/static/"]
82
83
  exclude = [
83
84
  ".claude/",
84
- "example-reports/",
85
+ "examples/",
85
86
  ".mypy_cache/",
86
87
  ".pytest_cache/",
87
88
  ".ruff_cache/",
@@ -1,4 +1,4 @@
1
1
  """Datex Studio CLI - Command-line interface for Datex Studio platform."""
2
2
 
3
- __version__ = "0.3.3"
3
+ __version__ = "0.3.4"
4
4
  __app_name__ = "dxs"
@@ -328,7 +328,9 @@ def register_commands() -> None:
328
328
  crm,
329
329
  datasource,
330
330
  devops,
331
+ endpoint,
331
332
  env,
333
+ function,
332
334
  marketplace,
333
335
  odata,
334
336
  organization,
@@ -345,7 +347,9 @@ def register_commands() -> None:
345
347
  cli.add_command(crm.crm)
346
348
  cli.add_command(datasource.datasource)
347
349
  cli.add_command(devops.devops)
350
+ cli.add_command(endpoint.endpoint)
348
351
  cli.add_command(env.env)
352
+ cli.add_command(function.function)
349
353
  cli.add_command(marketplace.marketplace)
350
354
  cli.add_command(odata.odata)
351
355
  cli.add_command(organization.organization)
@@ -15,9 +15,11 @@ from dxs.core.api import (
15
15
  SourceControlEndpoints,
16
16
  )
17
17
  from dxs.core.api.models import (
18
+ APPLICATION_DEFINITION_TYPE_NAMES,
18
19
  BRANCH_STATUS_ALIASES,
19
20
  BRANCH_STATUS_CONTEXT,
20
21
  BRANCH_STATUS_NAMES,
22
+ ApplicationDefinitionType,
21
23
  BranchStatus,
22
24
  )
23
25
  from dxs.core.auth import require_auth, verify_org_match
@@ -44,10 +46,14 @@ def enrich_branch_with_status(branch: dict[str, Any]) -> dict[str, Any]:
44
46
  - statusName: Human-readable status (e.g., "Main", "WorkspaceActive")
45
47
  - statusContext: Semantic description for LLM understanding
46
48
  - isCommit: True if this is a commit snapshot (WorkspaceHistory)
47
- - isRelease: True if this is a published release (PublishedMain or Inactive)
48
- - isCurrentRelease: True if this is the current release (PublishedMain)
49
+ - isRelease: True if this is a published release (PublishedMain)
50
+ - isCurrentRelease: True if this is the latest release (PublishedMain with isLatest=true)
49
51
  - isFeatureBranch: True if this is a feature branch (WorkspaceActive)
50
52
  - isMainBranch: True if this is the main branch (Main)
53
+ - appTypeName: Human-readable application type (e.g., "API", "Web", "Mobile").
54
+ Only set when the upstream payload carries applicationDefinition.applicationDefinitionTypeId
55
+ (e.g. `branch show`); omitted on payloads that don't (e.g. `branch list`).
56
+ - isApiApplication: True if this is an API application (type 6). Same presence rule as appTypeName.
51
57
 
52
58
  Args:
53
59
  branch: Branch data dictionary from the API
@@ -62,11 +68,21 @@ def enrich_branch_with_status(branch: dict[str, Any]) -> dict[str, Any]:
62
68
 
63
69
  # Add semantic flags for easy LLM filtering/understanding
64
70
  branch["isCommit"] = status_id == BranchStatus.WORKSPACE_HISTORY
65
- branch["isRelease"] = status_id in (BranchStatus.PUBLISHED_MAIN, BranchStatus.INACTIVE)
66
- branch["isCurrentRelease"] = status_id == BranchStatus.PUBLISHED_MAIN
71
+ branch["isRelease"] = status_id == BranchStatus.PUBLISHED_MAIN
72
+ branch["isCurrentRelease"] = status_id == BranchStatus.PUBLISHED_MAIN and branch.get(
73
+ "isLatest", False
74
+ )
67
75
  branch["isFeatureBranch"] = status_id == BranchStatus.WORKSPACE_ACTIVE
68
76
  branch["isMainBranch"] = status_id == BranchStatus.MAIN
69
77
 
78
+ # Add application type info only when the upstream payload carries it.
79
+ app_def = branch.get("applicationDefinition") or {}
80
+ app_type_id = app_def.get("applicationDefinitionTypeId")
81
+ if app_type_id is not None:
82
+ app_type_id_int = int(app_type_id)
83
+ branch["appTypeName"] = APPLICATION_DEFINITION_TYPE_NAMES.get(app_type_id_int, "Unknown")
84
+ branch["isApiApplication"] = app_type_id_int == ApplicationDefinitionType.API
85
+
70
86
  return branch
71
87
 
72
88
 
@@ -230,40 +246,67 @@ def _fetch_branches_for_repo(
230
246
  client: ApiClient,
231
247
  repo_id: int,
232
248
  status_ids: list[int] | None = None,
249
+ group_id: int | None = None,
250
+ default_group_only: bool = False,
233
251
  ) -> list[dict[str, Any]]:
234
252
  """Fetch branches for a repository via its application groups.
235
253
 
236
254
  The API requires fetching branches through application groups, not directly
237
255
  via repository ID. Each repository has one or more groups (typically a
238
- "Default" group) that contain its branches.
256
+ "Default" group plus zero-or-more Service Pack groups).
239
257
 
240
258
  Args:
241
259
  client: API client instance
242
260
  repo_id: Repository (ApplicationDefinition) ID
243
261
  status_ids: Optional list of status IDs for server-side filtering
262
+ group_id: If provided, fetch branches only from this application group
263
+ (skipping the "iterate all groups" flow). Mutually exclusive with
264
+ default_group_only.
265
+ default_group_only: If True, fetch branches only from the repository's
266
+ Default group (applicationGroupTypeId=1). Takes precedence when
267
+ group_id is also provided.
244
268
 
245
269
  Returns:
246
- List of branch dictionaries
270
+ List of branch dictionaries. Each branch is stamped with the
271
+ ``applicationGroupId`` of the group it was fetched from — the server's
272
+ ``applicationGroupId`` field in list responses is unreliable (it sometimes
273
+ points at a child Service Pack group instead of the branch's own group).
247
274
  """
248
- # First, fetch all groups for this repository
249
- groups = client.get(*ApplicationGroupEndpoints.list(repo_id))
250
- if not isinstance(groups, list):
251
- groups = [groups] if groups else []
275
+ # Resolve the target groups. Three modes:
276
+ # 1. group_id given + default_group_only False -> fetch from that one group
277
+ # 2. default_group_only True -> find Default group, fetch only that
278
+ # 3. Neither -> iterate all groups (legacy flow)
279
+ target_groups: list[dict[str, Any]]
280
+
281
+ if default_group_only:
282
+ groups = client.get(*ApplicationGroupEndpoints.list(repo_id, group_type_id=1))
283
+ if not isinstance(groups, list):
284
+ groups = [groups] if groups else []
285
+ target_groups = [g for g in groups if g.get("id")]
286
+ elif group_id is not None:
287
+ target_groups = [{"id": group_id}]
288
+ else:
289
+ groups = client.get(*ApplicationGroupEndpoints.list(repo_id))
290
+ if not isinstance(groups, list):
291
+ groups = [groups] if groups else []
292
+ target_groups = [g for g in groups if g.get("id")]
252
293
 
253
- if not groups:
294
+ if not target_groups:
254
295
  return []
255
296
 
256
- # Fetch branches from all groups
257
297
  all_branches: list[dict[str, Any]] = []
258
- for group in groups:
259
- group_id = group.get("id")
260
- if not group_id:
261
- continue
262
-
263
- branches = client.get(*BranchEndpoints.list(group_id, status_ids))
298
+ for group in target_groups:
299
+ gid = group["id"]
300
+ branches = client.get(*BranchEndpoints.list(gid, status_ids))
264
301
  if not isinstance(branches, list):
265
302
  branches = [branches] if branches else []
266
303
 
304
+ # Stamp the known group id on each branch — overrides the server's
305
+ # sometimes-misleading applicationGroupId field (which can reference a
306
+ # descendant Service Pack group rather than the branch's own group).
307
+ for branch in branches:
308
+ branch["applicationGroupId"] = gid
309
+
267
310
  all_branches.extend(branches)
268
311
 
269
312
  return all_branches
@@ -296,11 +339,25 @@ def _fetch_branches_for_repo(
296
339
  "--status",
297
340
  "status_filter",
298
341
  type=click.Choice(
299
- ["main", "inactive", "published", "history", "feature", "all"],
342
+ ["main", "published", "history", "feature", "all"],
300
343
  case_sensitive=False,
301
344
  ),
302
345
  default=None,
303
- help="Filter by branch status type (main, inactive, published, history, feature)",
346
+ help="Filter by branch status type (main, published, history, feature)",
347
+ )
348
+ @click.option(
349
+ "--group-id",
350
+ type=int,
351
+ default=None,
352
+ help="Filter to a specific application group ID (skips iterating all groups). "
353
+ "Incompatible with --all-repos.",
354
+ )
355
+ @click.option(
356
+ "--default-group",
357
+ is_flag=True,
358
+ default=False,
359
+ help="Filter to the repository's Default application group only (excludes "
360
+ "Service Pack groups). Incompatible with --all-repos and --group-id.",
304
361
  )
305
362
  @pagination_options(default_limit=10)
306
363
  @sorting_options(
@@ -325,6 +382,8 @@ def branch_list(
325
382
  org: str | None,
326
383
  all_repos: bool,
327
384
  status_filter: str | None,
385
+ group_id: int | None,
386
+ default_group: bool,
328
387
  limit: int,
329
388
  sort: str,
330
389
  sort_direction: str | None,
@@ -344,8 +403,7 @@ def branch_list(
344
403
  \b
345
404
  Status Types:
346
405
  main Main development branch (receives commits)
347
- inactive Previous published releases
348
- published Current published release
406
+ published Published releases (multiple can coexist in a group; use isLatest to find the current one)
349
407
  history Commit snapshots (frozen after commit)
350
408
  feature Feature branches (active development)
351
409
  all All branches (default if not specified)
@@ -357,6 +415,8 @@ def branch_list(
357
415
  --org Organization to scope repo search
358
416
  --all-repos Search across all repositories
359
417
  --status Filter by status type
418
+ --group-id Filter to a specific application group ID
419
+ --default-group Filter to the repository's Default group only (excludes Service Packs)
360
420
  --limit, -n Maximum results (default: 10, 0 for unlimited)
361
421
  --with-changes Include change counts (enables --sort changes)
362
422
  --sort Sort by: name, created, modified, commit-date, status, changes
@@ -371,6 +431,8 @@ def branch_list(
371
431
  Examples:
372
432
  dxs source branch list --repo 10
373
433
  dxs source branch list --repo 10 --status feature
434
+ dxs source branch list --repo 10 --default-group --status published
435
+ dxs source branch list --repo 10 --group-id 42 --status published
374
436
  dxs source branch list --all-repos --status feature --modified-after 2024-01-01
375
437
  dxs source branch list --repo 10 --status history --sort commit-date
376
438
  dxs source branch list --repo-name "MyApp" --org "Datex"
@@ -382,6 +444,24 @@ def branch_list(
382
444
  resolver = EntityResolver()
383
445
  client = ApiClient()
384
446
 
447
+ # Validate mutually-exclusive group flags.
448
+ if all_repos and (group_id is not None or default_group):
449
+ raise ValidationError(
450
+ message="--group-id and --default-group cannot be combined with --all-repos",
451
+ code="DXS-VAL-002",
452
+ suggestions=[
453
+ "Drop --all-repos and scope to a single repo with --repo",
454
+ ],
455
+ )
456
+ if group_id is not None and default_group:
457
+ raise ValidationError(
458
+ message="--group-id and --default-group are mutually exclusive",
459
+ code="DXS-VAL-002",
460
+ suggestions=[
461
+ "Pick one: --group-id <id> (explicit) or --default-group (auto-resolved)",
462
+ ],
463
+ )
464
+
385
465
  # Handle --all-repos mode
386
466
  if all_repos:
387
467
  # Scope to org if provided via --org or active org from config
@@ -436,7 +516,13 @@ def branch_list(
436
516
  ctx.log(f"Filtering by status: {status_filter} (id={status_id})...")
437
517
 
438
518
  # Fetch branches via application groups (API requires this flow)
439
- branches = _fetch_branches_for_repo(client, repo_id, server_status_ids)
519
+ branches = _fetch_branches_for_repo(
520
+ client,
521
+ repo_id,
522
+ server_status_ids,
523
+ group_id=group_id,
524
+ default_group_only=default_group,
525
+ )
440
526
 
441
527
  total_count = len(branches)
442
528
 
@@ -551,6 +637,10 @@ def branch_list(
551
637
  # Add applied filters to metadata if any
552
638
  if status_filter and status_filter.lower() != "all":
553
639
  metadata_kwargs["status_filter"] = status_filter
640
+ if group_id is not None:
641
+ metadata_kwargs["group_id_filter"] = group_id
642
+ if default_group:
643
+ metadata_kwargs["default_group_only"] = True
554
644
  if created_after:
555
645
  metadata_kwargs["created_after"] = created_after.isoformat()
556
646
  if created_before:
@@ -799,63 +889,96 @@ def delete(ctx: DxsContext, branch_id: int, force: bool) -> None:
799
889
  def baseline(ctx: DxsContext, branch_id: int) -> None:
800
890
  """Find the baseline (previous release) for a branch.
801
891
 
802
- Returns the most recent Inactive branch from the same repository,
803
- which represents the previous published version. This is useful for
804
- generating release notes comparing the new version to the baseline.
892
+ Among PublishedMain branches in the same application group as the target branch,
893
+ returns the one with the largest `releaseDate` strictly less than the target's
894
+ `releaseDate`. Useful for generating release notes comparing a release to its
895
+ predecessor.
896
+
897
+ Scoping by application group (rather than repository-wide) ensures that Service
898
+ Pack maintenance releases are compared against the previous SP release, and
899
+ Default group releases are compared against the previous Default release.
805
900
 
806
901
  \b
807
902
  Arguments:
808
- BRANCH_ID Branch ID of the target version
903
+ BRANCH_ID Branch ID of the target release
809
904
 
810
905
  \b
811
906
  Returns:
812
- The most recent Inactive branch for the same repository
907
+ The most recent PublishedMain branch released before the target within the
908
+ same application group, or a message if no prior release exists.
813
909
 
814
910
  \b
815
911
  Example:
816
912
  dxs source branch baseline 63338
817
- # Returns branch 62582 (the previous published version)
913
+ # Returns branch 62582 (the previous published version in the same group)
818
914
  """
819
915
  client = ApiClient()
820
916
  ctx.log(f"Finding baseline for branch {branch_id}...")
821
917
 
822
- # Get the target branch to find its repo ID
823
- branch_data = client.get(BranchEndpoints.get(branch_id))
824
- repo_id = branch_data.get("applicationDefinitionId")
918
+ # Get the target branch to find its group.
919
+ target_branch = client.get(BranchEndpoints.get(branch_id))
920
+ repo_id = target_branch.get("applicationDefinitionId")
921
+ group_id = target_branch.get("applicationGroupId")
825
922
 
826
- if not repo_id:
923
+ if not repo_id or not group_id:
827
924
  raise ValidationError(
828
- message=f"Could not determine repository for branch {branch_id}",
925
+ message=f"Could not determine repository/group for branch {branch_id}",
829
926
  code="DXS-VAL-001",
830
927
  )
831
928
 
832
- ctx.log(f"Fetching inactive branches for repository {repo_id}...")
929
+ if target_branch.get("applicationStatusId") != BranchStatus.PUBLISHED_MAIN:
930
+ raise ValidationError(
931
+ message=f"Branch {branch_id} is not a published release",
932
+ code="DXS-VAL-002",
933
+ suggestions=[
934
+ "baseline is only meaningful for PublishedMain branches",
935
+ "Use `dxs source branch show <id>` to inspect a branch's status",
936
+ ],
937
+ )
938
+
939
+ ctx.log(f"Fetching PublishedMain branches in group {group_id}...")
940
+
941
+ # Fetch all PublishedMain branches in the same application group. The list
942
+ # endpoint includes releaseDate (the single-branch GET does not), so we use
943
+ # releaseDate when present and fall back to createdDate otherwise.
944
+ group_releases = client.get(*BranchEndpoints.list(group_id, [int(BranchStatus.PUBLISHED_MAIN)]))
945
+ if not isinstance(group_releases, list):
946
+ group_releases = [group_releases] if group_releases else []
947
+
948
+ def _sort_key(branch: dict) -> str:
949
+ return branch.get("releaseDate") or branch.get("createdDate") or ""
833
950
 
834
- # Get inactive branches directly using server-side filtering
835
- inactive_status_id = BRANCH_STATUS_ALIASES.get("inactive")
836
- inactive_branches = _fetch_branches_for_repo(
837
- client, repo_id, [inactive_status_id] if inactive_status_id else None
951
+ target_key = next(
952
+ (_sort_key(b) for b in group_releases if b.get("id") == branch_id),
953
+ "",
838
954
  )
955
+ if not target_key:
956
+ raise ValidationError(
957
+ message=f"Branch {branch_id} has no releaseDate or createdDate in group listing",
958
+ code="DXS-VAL-003",
959
+ )
960
+
961
+ # Keep only releases older than the target, sorted desc by the same key.
962
+ older = [
963
+ b
964
+ for b in group_releases
965
+ if b.get("id") != branch_id and _sort_key(b) and _sort_key(b) < target_key
966
+ ]
839
967
 
840
- if not inactive_branches:
968
+ if not older:
841
969
  ctx.output(
842
970
  single(
843
- item={"message": "No baseline found (no inactive branches)"},
971
+ item={"message": "No baseline found (no prior release in this group)"},
844
972
  semantic_key="baseline",
845
973
  branch_id=branch_id,
846
974
  repository_id=repo_id,
975
+ application_group_id=group_id,
847
976
  )
848
977
  )
849
978
  return
850
979
 
851
- # Sort by createdDate descending to get the most recent
852
- inactive_branches = sort_items(inactive_branches, "createdDate", "desc")
853
-
854
- # Get the most recent inactive branch
855
- baseline_branch = inactive_branches[0]
856
-
857
- # Enrich with status info
858
- baseline_branch = enrich_branch_with_status(baseline_branch)
980
+ older.sort(key=_sort_key, reverse=True)
981
+ baseline_branch = enrich_branch_with_status(older[0])
859
982
 
860
983
  ctx.output(
861
984
  single(
@@ -863,6 +986,7 @@ def baseline(ctx: DxsContext, branch_id: int) -> None:
863
986
  semantic_key="baseline",
864
987
  target_branch_id=branch_id,
865
988
  repository_id=repo_id,
989
+ application_group_id=group_id,
866
990
  )
867
991
  )
868
992