datex-studio-cli 0.2.1__tar.gz → 0.3.0__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 (118) hide show
  1. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/.gitignore +1 -0
  2. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/PKG-INFO +14 -11
  3. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/README.md +12 -10
  4. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/pyproject.toml +6 -1
  5. datex_studio_cli-0.3.0/report-creator.skill +0 -0
  6. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/__init__.py +1 -1
  7. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/cli.py +5 -122
  8. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/auth.py +234 -33
  9. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/branch.py +3 -1
  10. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/crm.py +40 -0
  11. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/datasource.py +314 -89
  12. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/env.py +3 -1
  13. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/odata.py +148 -22
  14. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/proxy.py +4 -9
  15. datex_studio_cli-0.3.0/src/dxs/commands/release_notes.py +376 -0
  16. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/report.py +319 -54
  17. datex_studio_cli-0.3.0/src/dxs/commands/schema.py +5050 -0
  18. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/servicepack.py +3 -1
  19. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/source.py +246 -162
  20. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/studio.py +1 -3
  21. datex_studio_cli-0.3.0/src/dxs/context.py +133 -0
  22. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/api/client.py +123 -43
  23. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/api/endpoints.py +124 -34
  24. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/api/metadata_models.py +9 -3
  25. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/auth/token_cache.py +72 -2
  26. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/datasource/generator.py +134 -34
  27. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/datasource/models.py +5 -4
  28. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/datasource/validator.py +67 -13
  29. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/dynamics/client.py +34 -1
  30. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/footprint/client.py +39 -12
  31. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/footprint/edmx_parser.py +2 -1
  32. datex_studio_cli-0.3.0/src/dxs/core/release_notes.py +324 -0
  33. datex_studio_cli-0.3.0/src/dxs/report/datasource_binding.py +108 -0
  34. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/engine.py +6 -2
  35. {datex_studio_cli-0.2.1/src/dxs/core/report_data → datex_studio_cli-0.3.0/src/dxs/report}/field_parser.py +3 -1
  36. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/preview.py +97 -43
  37. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/schema.py +2 -5
  38. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/validator.py +111 -80
  39. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/config.py +5 -3
  40. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/resolvers.py +25 -9
  41. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/app.py +36 -12
  42. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/proxy_app.py +49 -28
  43. datex_studio_cli-0.2.1/code-review-process.md +0 -206
  44. datex_studio_cli-0.2.1/release-notes-process.md +0 -273
  45. datex_studio_cli-0.2.1/release_notes/2026-01-15_summary.md +0 -107
  46. datex_studio_cli-0.2.1/src/dxs/commands/report_data.py +0 -704
  47. datex_studio_cli-0.2.1/src/dxs/commands/schema.py +0 -3199
  48. datex_studio_cli-0.2.1/src/dxs/core/report_data/__init__.py +0 -5
  49. datex_studio_cli-0.2.1/src/dxs/core/report_data/generator.py +0 -802
  50. datex_studio_cli-0.2.1/walmart-mixed-pallet-v2.rdlx-json +0 -123
  51. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/__main__.py +0 -0
  52. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/__init__.py +0 -0
  53. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/api.py +0 -0
  54. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/config.py +0 -0
  55. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/devops.py +0 -0
  56. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/document.py +0 -0
  57. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/explore.py +0 -0
  58. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/marketplace.py +0 -0
  59. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/organization.py +0 -0
  60. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/repo.py +0 -0
  61. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/commands/user.py +0 -0
  62. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/__init__.py +0 -0
  63. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/api/__init__.py +0 -0
  64. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/api/models.py +0 -0
  65. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/auth/__init__.py +0 -0
  66. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/auth/decorators.py +0 -0
  67. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/auth/msal_client.py +0 -0
  68. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/cache.py +0 -0
  69. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/datasource/__init__.py +0 -0
  70. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/devops/__init__.py +0 -0
  71. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/devops/client.py +0 -0
  72. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/devops/models.py +0 -0
  73. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/dynamics/__init__.py +0 -0
  74. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/footprint/__init__.py +0 -0
  75. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/footprint/metadata.py +0 -0
  76. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/graph.py +0 -0
  77. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/output/__init__.py +0 -0
  78. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/output/csv_fmt.py +0 -0
  79. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/output/formatter.py +0 -0
  80. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/output/json_fmt.py +0 -0
  81. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/output/yaml_fmt.py +0 -0
  82. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/core/responses.py +0 -0
  83. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/models/__init__.py +0 -0
  84. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/__init__.py +0 -0
  85. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/models.py +0 -0
  86. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/templates/__init__.py +0 -0
  87. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/templates/bill_of_lading.rdlx-json +0 -0
  88. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/templates/shipping_label.rdlx-json +0 -0
  89. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/report/wrapper.py +0 -0
  90. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/__init__.py +0 -0
  91. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/click_options.py +0 -0
  92. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/errors.py +0 -0
  93. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/filtering.py +0 -0
  94. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/paths.py +0 -0
  95. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/responses.py +0 -0
  96. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/restricted.py +0 -0
  97. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/utils/sorting.py +0 -0
  98. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/__init__.py +0 -0
  99. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/404.html +0 -0
  100. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/RIG3nV-yzLdq0OlVxUM6i/_buildManifest.js +0 -0
  101. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/RIG3nV-yzLdq0OlVxUM6i/_ssgManifest.js +0 -0
  102. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/255-67e8754147461423.js +0 -0
  103. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +0 -0
  104. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/841-8775e8c75ff8c949.js +0 -0
  105. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/871-370fd7261c4ea9bc.js +0 -0
  106. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/app/_not-found/page-ea1be7001c230704.js +0 -0
  107. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/app/layout-fb92e6e3144d6d3a.js +0 -0
  108. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/app/page-b5e545d0d4880f6f.js +0 -0
  109. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/framework-de98b93a850cfc71.js +0 -0
  110. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/main-1a0dcce460eb61ce.js +0 -0
  111. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/main-app-b69998d8941231d8.js +0 -0
  112. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/pages/_app-7d307437aca18ad4.js +0 -0
  113. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +0 -0
  114. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
  115. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/chunks/webpack-2b297ada5306c17f.js +0 -0
  116. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/_next/static/css/686bbface7277f83.css +0 -0
  117. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/index.html +0 -0
  118. {datex_studio_cli-0.2.1 → datex_studio_cli-0.3.0}/src/dxs/web/static/index.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  exclude/
2
2
  exploration/
3
3
  reviews/
4
+ .tap/
4
5
 
5
6
  # Environment
6
7
  .env
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datex-studio-cli
3
- Version: 0.2.1
3
+ Version: 0.3.0
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
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
21
21
  Requires-Python: >=3.10
22
22
  Requires-Dist: click>=8.1.0
23
+ Requires-Dist: defusedxml>=0.7.0
23
24
  Requires-Dist: httpx>=0.27.0
24
25
  Requires-Dist: markdownify>=0.13.0
25
26
  Requires-Dist: msal>=1.28.0
@@ -487,7 +488,7 @@ dxs crm metadata incident --relationships
487
488
  | Command | Description | Performance |
488
489
  |---------|-------------|-------------|
489
490
  | `search <keyword>` | Search entities by name (server-side filtered) | ~200 tokens, <1s |
490
- | `list` | List all entities in the model | ~5000 tokens, <1s |
491
+ | `entities` | List all entities in the model | ~5000 tokens, <1s |
491
492
  | `enums` | List enumeration types | ~500 tokens, <1s |
492
493
  | `actions` | List server-side actions (POST operations) | ~300 tokens, <1s |
493
494
  | `functions` | List server-side functions (GET operations) | ~300 tokens, <1s |
@@ -498,8 +499,10 @@ dxs crm metadata incident --relationships
498
499
 
499
500
  | Command | Description | Performance |
500
501
  |---------|-------------|-------------|
501
- | `describe <entity>` | Show full entity schema (properties, types, navigation) | 1,000-50,000 tokens, <2s |
502
- | `relationships <entity>` | Show navigation properties and relationships | ~1000 tokens, <2s |
502
+ | `describe-entity <entity>` | Show full entity schema (properties, types, navigation) | 1,000-50,000 tokens, <2s |
503
+ | `describe-relationships <entity>` | Show navigation properties and relationships | ~1000 tokens, <2s |
504
+ | `describe-properties <type> <prop>` | Show details for a specific property (by composite key) | ~100 tokens, <1s |
505
+ | `describe-navigation-properties <type> <prop>` | Show details for a specific navigation property (by composite key) | ~100 tokens, <1s |
503
506
  | `describe-enum <enum>` | Show enum members and values | ~200 tokens, <1s |
504
507
  | `describe-action <action>` | Show action parameters and return type | ~300 tokens, <1s |
505
508
  | `describe-function <func>` | Show function parameters and return type | ~300 tokens, <1s |
@@ -519,10 +522,10 @@ dxs crm metadata incident --relationships
519
522
  dxs schema search "invoice" -c 1
520
523
 
521
524
  # 2. DESCRIBE structure (understand properties and keys)
522
- dxs schema describe Invoices -c 1 | grep -A 50 "navigation_properties:"
525
+ dxs schema describe-entity Invoices -c 1 | grep -A 50 "navigation_properties:"
523
526
 
524
527
  # 3. EXPLORE relationships (find what can be expanded)
525
- dxs schema relationships Invoices -c 1
528
+ dxs schema describe-relationships Invoices -c 1
526
529
 
527
530
  # 4. TEST queries incrementally (avoid 400 errors)
528
531
  dxs odata execute -c 1 -q "Invoices(123)?\$expand=InvoiceLines"
@@ -550,20 +553,20 @@ This nested expansion returns:
550
553
 
551
554
  ```bash
552
555
  # DON'T: List all entities (returns thousands)
553
- dxs schema list -c 1 # ~5000 tokens
556
+ dxs schema entities -c 1 # ~5000 tokens
554
557
 
555
558
  # DO: Search for specific entities (returns ~20 matches)
556
559
  dxs schema search "order" -c 1 # ~200 tokens
557
560
 
558
561
  # Use --count flag for count-only queries (minimal tokens)
559
- dxs schema list --count -c 1 # Returns: count: 150
562
+ dxs schema entities --count -c 1 # Returns: count: 150
560
563
  dxs schema search "invoice" --count -c 1 # Returns: count: 10
561
564
 
562
565
  # Filter large describe output with grep
563
- dxs schema describe EntityName -c 1 | grep -A 50 "navigation_properties:"
566
+ dxs schema describe-entity EntityName -c 1 | grep -A 50 "navigation_properties:"
564
567
 
565
568
  # Save large schemas to file for analysis
566
- dxs schema describe EntityName -c 1 > schema.yaml 2>&1
569
+ dxs schema describe-entity EntityName -c 1 > schema.yaml 2>&1
567
570
  ```
568
571
 
569
572
  **Query Building Best Practices:**
@@ -572,7 +575,7 @@ dxs schema describe EntityName -c 1 > schema.yaml 2>&1
572
575
  ✅ Test `$expand` incrementally: single → multiple → nested
573
576
  ✅ Use `$select` to limit fields: `Entity?$select=Id,Name,Date`
574
577
  ✅ Use bulk queries: `Entity?$filter=Id in (1,2,3)` vs one-by-one
575
- ✅ Start with `schema search` (not `list`) when looking for entities
578
+ ✅ Start with `schema search` (not `entities`) when looking for entities
576
579
 
577
580
  See [Schema Discovery Guide](docs/schema-discovery-guide.md) for command reference and [Schema Discovery Examples](docs/schema-discovery-examples.md) for complete real-world walkthroughs.
578
581
 
@@ -443,7 +443,7 @@ dxs crm metadata incident --relationships
443
443
  | Command | Description | Performance |
444
444
  |---------|-------------|-------------|
445
445
  | `search <keyword>` | Search entities by name (server-side filtered) | ~200 tokens, <1s |
446
- | `list` | List all entities in the model | ~5000 tokens, <1s |
446
+ | `entities` | List all entities in the model | ~5000 tokens, <1s |
447
447
  | `enums` | List enumeration types | ~500 tokens, <1s |
448
448
  | `actions` | List server-side actions (POST operations) | ~300 tokens, <1s |
449
449
  | `functions` | List server-side functions (GET operations) | ~300 tokens, <1s |
@@ -454,8 +454,10 @@ dxs crm metadata incident --relationships
454
454
 
455
455
  | Command | Description | Performance |
456
456
  |---------|-------------|-------------|
457
- | `describe <entity>` | Show full entity schema (properties, types, navigation) | 1,000-50,000 tokens, <2s |
458
- | `relationships <entity>` | Show navigation properties and relationships | ~1000 tokens, <2s |
457
+ | `describe-entity <entity>` | Show full entity schema (properties, types, navigation) | 1,000-50,000 tokens, <2s |
458
+ | `describe-relationships <entity>` | Show navigation properties and relationships | ~1000 tokens, <2s |
459
+ | `describe-properties <type> <prop>` | Show details for a specific property (by composite key) | ~100 tokens, <1s |
460
+ | `describe-navigation-properties <type> <prop>` | Show details for a specific navigation property (by composite key) | ~100 tokens, <1s |
459
461
  | `describe-enum <enum>` | Show enum members and values | ~200 tokens, <1s |
460
462
  | `describe-action <action>` | Show action parameters and return type | ~300 tokens, <1s |
461
463
  | `describe-function <func>` | Show function parameters and return type | ~300 tokens, <1s |
@@ -475,10 +477,10 @@ dxs crm metadata incident --relationships
475
477
  dxs schema search "invoice" -c 1
476
478
 
477
479
  # 2. DESCRIBE structure (understand properties and keys)
478
- dxs schema describe Invoices -c 1 | grep -A 50 "navigation_properties:"
480
+ dxs schema describe-entity Invoices -c 1 | grep -A 50 "navigation_properties:"
479
481
 
480
482
  # 3. EXPLORE relationships (find what can be expanded)
481
- dxs schema relationships Invoices -c 1
483
+ dxs schema describe-relationships Invoices -c 1
482
484
 
483
485
  # 4. TEST queries incrementally (avoid 400 errors)
484
486
  dxs odata execute -c 1 -q "Invoices(123)?\$expand=InvoiceLines"
@@ -506,20 +508,20 @@ This nested expansion returns:
506
508
 
507
509
  ```bash
508
510
  # DON'T: List all entities (returns thousands)
509
- dxs schema list -c 1 # ~5000 tokens
511
+ dxs schema entities -c 1 # ~5000 tokens
510
512
 
511
513
  # DO: Search for specific entities (returns ~20 matches)
512
514
  dxs schema search "order" -c 1 # ~200 tokens
513
515
 
514
516
  # Use --count flag for count-only queries (minimal tokens)
515
- dxs schema list --count -c 1 # Returns: count: 150
517
+ dxs schema entities --count -c 1 # Returns: count: 150
516
518
  dxs schema search "invoice" --count -c 1 # Returns: count: 10
517
519
 
518
520
  # Filter large describe output with grep
519
- dxs schema describe EntityName -c 1 | grep -A 50 "navigation_properties:"
521
+ dxs schema describe-entity EntityName -c 1 | grep -A 50 "navigation_properties:"
520
522
 
521
523
  # Save large schemas to file for analysis
522
- dxs schema describe EntityName -c 1 > schema.yaml 2>&1
524
+ dxs schema describe-entity EntityName -c 1 > schema.yaml 2>&1
523
525
  ```
524
526
 
525
527
  **Query Building Best Practices:**
@@ -528,7 +530,7 @@ dxs schema describe EntityName -c 1 > schema.yaml 2>&1
528
530
  ✅ Test `$expand` incrementally: single → multiple → nested
529
531
  ✅ Use `$select` to limit fields: `Entity?$select=Id,Name,Date`
530
532
  ✅ Use bulk queries: `Entity?$filter=Id in (1,2,3)` vs one-by-one
531
- ✅ Start with `schema search` (not `list`) when looking for entities
533
+ ✅ Start with `schema search` (not `entities`) when looking for entities
532
534
 
533
535
  See [Schema Discovery Guide](docs/schema-discovery-guide.md) for command reference and [Schema Discovery Examples](docs/schema-discovery-examples.md) for complete real-world walkthroughs.
534
536
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "datex-studio-cli"
7
- version = "0.2.1"
7
+ version = "0.3.0"
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"
@@ -33,6 +33,7 @@ dependencies = [
33
33
  "pydantic>=2.5.0",
34
34
  "pydantic-settings>=2.0.0",
35
35
  "pyyaml>=6.0",
36
+ "defusedxml>=0.7.0",
36
37
  ]
37
38
 
38
39
  [project.optional-dependencies]
@@ -125,6 +126,10 @@ plugins = ["pydantic.mypy"]
125
126
  module = ["msal.*"]
126
127
  ignore_missing_imports = true
127
128
 
129
+ [[tool.mypy.overrides]]
130
+ module = ["defusedxml.*"]
131
+ ignore_missing_imports = true
132
+
128
133
  [[tool.mypy.overrides]]
129
134
  module = ["fastapi.*", "uvicorn.*"]
130
135
  ignore_missing_imports = true
@@ -1,4 +1,4 @@
1
1
  """Datex Studio CLI - Command-line interface for Datex Studio platform."""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.3.0"
4
4
  __app_name__ = "dxs"
@@ -7,10 +7,14 @@ from typing import Any, TypeVar, cast
7
7
  import click
8
8
 
9
9
  from dxs import __app_name__, __version__
10
- from dxs.core.output import OutputFormat, format_error, format_output
10
+ from dxs.context import DxsContext, pass_context # re-exported for backward compat
11
+ from dxs.core.output import OutputFormat, format_error
11
12
  from dxs.utils.config import get_settings
12
13
  from dxs.utils.errors import DxsError
13
14
 
15
+ # Re-export so that existing `from dxs.cli import DxsContext, pass_context` still works
16
+ __all__ = ["DxsContext", "pass_context"]
17
+
14
18
  F = TypeVar("F", bound=Callable[..., Any])
15
19
 
16
20
  # Fields to strip from author objects in concise mode
@@ -45,125 +49,6 @@ def _strip_concise(data: Any, parent_key: str | None = None) -> Any:
45
49
  return data
46
50
 
47
51
 
48
- class DxsContext:
49
- """Shared context passed to all commands."""
50
-
51
- def __init__(self) -> None:
52
- self.output_format: OutputFormat = OutputFormat.YAML
53
- self.verbose: bool = False
54
- self.quiet: bool = False
55
- self.concise: bool = True # Concise output is default
56
- self.org: str | None = None
57
- self.env: str | None = None
58
- self.branch: int | None = None
59
- self.repo: int | None = None
60
- self.save_path: str | None = None
61
- self.force_overwrite: bool = False
62
- self.explicit_output_format: bool = False
63
-
64
- def output(self, data: Any, include_metadata: bool = True) -> None:
65
- """Output data in the configured format.
66
-
67
- Args:
68
- data: Data to output.
69
- include_metadata: Include timestamp and version metadata.
70
- """
71
- from dxs.core.output.formatter import detect_format_from_extension
72
-
73
- # Determine format: --output flag > file extension > default
74
- if self.save_path and not self.explicit_output_format:
75
- output_format = detect_format_from_extension(self.save_path, self.output_format)
76
- else:
77
- output_format = self.output_format
78
-
79
- formatted = format_output(data, output_format, include_metadata, self.concise)
80
-
81
- # Save to file if requested (suppresses stdout)
82
- if self.save_path:
83
- self._save_to_file(formatted)
84
- return
85
-
86
- click.echo(formatted)
87
-
88
- def _save_to_file(self, content: str) -> None:
89
- """Save content to file with overwrite protection.
90
-
91
- Args:
92
- content: Formatted content to save.
93
-
94
- Raises:
95
- ValidationError: If file exists and force_overwrite is False.
96
- DxsError: If file write fails.
97
- RestrictedModeError: If restricted mode is enabled.
98
- """
99
- from pathlib import Path
100
-
101
- from dxs.utils.config import is_restricted_mode
102
- from dxs.utils.errors import RestrictedModeError, ValidationError
103
-
104
- # Block file saving in restricted mode
105
- if is_restricted_mode():
106
- raise RestrictedModeError(
107
- command_name="--save option",
108
- reason="writes files to the filesystem",
109
- )
110
-
111
- assert self.save_path is not None # Caller checks this
112
- path = Path(self.save_path)
113
-
114
- if path.exists() and not self.force_overwrite:
115
- raise ValidationError(
116
- message=f"File '{self.save_path}' already exists",
117
- code="DXS-FILE-001",
118
- suggestions=[
119
- "Use --force flag to overwrite the file",
120
- "Specify a different filename with --save",
121
- ],
122
- )
123
-
124
- path.parent.mkdir(parents=True, exist_ok=True)
125
-
126
- try:
127
- path.write_text(content, encoding="utf-8")
128
- self.debug(f"Output saved to: {self.save_path}")
129
- except OSError as e:
130
- raise DxsError(
131
- code="DXS-FILE-002",
132
- message=f"Failed to write file '{self.save_path}': {e}",
133
- ) from e
134
-
135
- def output_error(self, error: DxsError | Exception) -> None:
136
- """Output an error in the configured format.
137
-
138
- Args:
139
- error: Error to output.
140
- """
141
- formatted = format_error(error, self.output_format)
142
- click.echo(formatted, err=True)
143
-
144
- def log(self, message: str) -> None:
145
- """Log a message (respects quiet flag).
146
-
147
- Args:
148
- message: Message to log.
149
- """
150
- if not self.quiet:
151
- click.echo(message, err=True)
152
-
153
- def debug(self, message: str) -> None:
154
- """Log a debug message (only in verbose mode).
155
-
156
- Args:
157
- message: Debug message to log.
158
- """
159
- if self.verbose:
160
- click.echo(f"[DEBUG] {message}", err=True)
161
-
162
-
163
- # Create a pass decorator for the context
164
- pass_context = click.make_pass_decorator(DxsContext, ensure=True)
165
-
166
-
167
52
  # Global options shared across all commands
168
53
  CONTEXT_SETTINGS = {
169
54
  "help_option_names": ["-h", "--help"],
@@ -459,7 +344,6 @@ def register_commands() -> None:
459
344
  organization,
460
345
  proxy,
461
346
  report,
462
- report_data,
463
347
  source,
464
348
  studio,
465
349
  user,
@@ -477,7 +361,6 @@ def register_commands() -> None:
477
361
  cli.add_command(organization.organization)
478
362
  cli.add_command(proxy.proxy)
479
363
  cli.add_command(report.report)
480
- cli.add_command(report_data.report_data)
481
364
  cli.add_command(source.source)
482
365
  cli.add_command(studio.studio)
483
366
  cli.add_command(user.user)