mammoth-cli 2.2.19__tar.gz → 2.2.20__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 (256) hide show
  1. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/PKG-INFO +1 -1
  2. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/__init__.py +1 -1
  3. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +1 -1
  4. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +9 -0
  5. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/view.py +78 -11
  6. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/errors/envelope.py +1 -0
  7. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/command_contract.py +20 -0
  8. mammoth_cli-2.2.20/mammoth_cli/services/conditional_format.py +131 -0
  9. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/input_fields.py +6 -15
  10. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/pyproject.toml +1 -1
  11. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/view.yaml +6 -6
  12. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/.gitignore +0 -0
  13. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/LICENSE +0 -0
  14. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/README.md +0 -0
  15. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/__main__.py +0 -0
  16. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/app.py +0 -0
  17. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +0 -0
  18. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
  19. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
  20. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
  21. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
  22. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
  23. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
  24. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
  25. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
  26. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
  27. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
  28. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
  29. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
  30. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
  31. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
  32. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
  33. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
  34. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
  35. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
  36. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
  37. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
  38. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
  39. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
  40. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
  41. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-style.md +0 -0
  42. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-template.md +0 -0
  43. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
  44. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
  45. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
  46. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
  47. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
  48. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
  49. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
  50. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
  51. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/link.md +0 -0
  52. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
  53. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
  54. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
  55. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
  56. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
  57. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
  58. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
  59. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
  60. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
  61. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
  62. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
  63. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
  64. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
  65. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
  66. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
  67. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
  68. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
  69. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
  70. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
  71. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
  72. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
  73. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
  74. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
  75. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
  76. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
  77. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
  78. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/database-import.md +0 -0
  79. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
  80. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
  81. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
  82. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
  83. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
  84. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +0 -0
  85. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
  86. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
  87. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
  88. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
  89. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
  90. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
  91. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
  92. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/__init__.py +0 -0
  93. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/activity.py +0 -0
  94. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/addon.py +0 -0
  95. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/agent.py +0 -0
  96. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/ai.py +0 -0
  97. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/annotation.py +0 -0
  98. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/auth.py +0 -0
  99. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/automation.py +0 -0
  100. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/batch.py +0 -0
  101. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/billing.py +0 -0
  102. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/browse.py +0 -0
  103. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/calc.py +0 -0
  104. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/capability.py +0 -0
  105. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/client_app.py +0 -0
  106. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/completion.py +0 -0
  107. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/config.py +0 -0
  108. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/connector.py +0 -0
  109. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/context.py +0 -0
  110. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/dashboard.py +0 -0
  111. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/data_app.py +0 -0
  112. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/dataset.py +0 -0
  113. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/doctor.py +0 -0
  114. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/external_key.py +0 -0
  115. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/file.py +0 -0
  116. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/folder.py +0 -0
  117. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/job.py +0 -0
  118. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/link.py +0 -0
  119. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/notification.py +0 -0
  120. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/parameter.py +0 -0
  121. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/project.py +0 -0
  122. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/registry.py +0 -0
  123. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/report.py +0 -0
  124. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/schedule.py +0 -0
  125. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/schema.py +0 -0
  126. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/skill.py +0 -0
  127. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/snippet.py +0 -0
  128. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/support.py +0 -0
  129. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/template.py +0 -0
  130. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/trash.py +0 -0
  131. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/upgrade.py +0 -0
  132. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/user.py +0 -0
  133. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/view_ops.py +0 -0
  134. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/view_profile.py +0 -0
  135. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/webhook.py +0 -0
  136. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/workflow.py +0 -0
  137. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/commands/workspace.py +0 -0
  138. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/context/__init__.py +0 -0
  139. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/context/credentials.py +0 -0
  140. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/context/endpoint.py +0 -0
  141. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/context/profiles.py +0 -0
  142. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/context/resolver.py +0 -0
  143. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/contracts/__init__.py +0 -0
  144. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/contracts/auth.py +0 -0
  145. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/embed.py +0 -0
  146. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/errors/__init__.py +0 -0
  147. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/manifest/__init__.py +0 -0
  148. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/manifest/loader.py +0 -0
  149. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/messages/__init__.py +0 -0
  150. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/output/__init__.py +0 -0
  151. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/output/envelope.py +0 -0
  152. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/output/normalize.py +0 -0
  153. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/output/policy.py +0 -0
  154. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/output/progress.py +0 -0
  155. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/output/render.py +0 -0
  156. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/py.typed +0 -0
  157. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/__init__.py +0 -0
  158. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/confirm.py +0 -0
  159. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/dataset_health.py +0 -0
  160. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/dryrun.py +0 -0
  161. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/dryrun_targets.py +0 -0
  162. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/embedded.py +0 -0
  163. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/executor.py +0 -0
  164. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/input_loader.py +0 -0
  165. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/intent_only.py +0 -0
  166. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/invocation.py +0 -0
  167. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/new_data.py +0 -0
  168. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/options.py +0 -0
  169. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/parents.py +0 -0
  170. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/runlog.py +0 -0
  171. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/session.py +0 -0
  172. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/state.py +0 -0
  173. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/strict.py +0 -0
  174. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/updates.py +0 -0
  175. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/validate.py +0 -0
  176. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/runtime/verify.py +0 -0
  177. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/__init__.py +0 -0
  178. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/argspec.py +0 -0
  179. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/board_values.py +0 -0
  180. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/coerce.py +0 -0
  181. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/conditions.py +0 -0
  182. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/dashboard_filters.py +0 -0
  183. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/dashboard_pages.py +0 -0
  184. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/dashboard_review.py +0 -0
  185. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/data_profile.py +0 -0
  186. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/data_quality.py +0 -0
  187. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/dispatch.py +0 -0
  188. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/factory.py +0 -0
  189. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/listing.py +0 -0
  190. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/local_time.py +0 -0
  191. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/mapping.py +0 -0
  192. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/openapi_types.py +0 -0
  193. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/positionals.py +0 -0
  194. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/protocol.py +0 -0
  195. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/read_queries.py +0 -0
  196. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/sdk_service.py +0 -0
  197. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/stored_stats.py +0 -0
  198. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/testing.py +0 -0
  199. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/text_dates.py +0 -0
  200. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/type_system.py +0 -0
  201. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/services/write_impact.py +0 -0
  202. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/skills/__init__.py +0 -0
  203. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/skills/installer.py +0 -0
  204. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/skills/steering.py +0 -0
  205. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/mammoth_cli/testing.py +0 -0
  206. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/activity.yaml +0 -0
  207. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/addon.yaml +0 -0
  208. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/agent.yaml +0 -0
  209. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/ai.yaml +0 -0
  210. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/annotation.yaml +0 -0
  211. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/auth.yaml +0 -0
  212. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/automation.yaml +0 -0
  213. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/batch.yaml +0 -0
  214. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/billing.yaml +0 -0
  215. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/browse.yaml +0 -0
  216. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/calc.yaml +0 -0
  217. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/capability.yaml +0 -0
  218. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/client-app.yaml +0 -0
  219. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/completion.yaml +0 -0
  220. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/config.yaml +0 -0
  221. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/connector.yaml +0 -0
  222. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/context.yaml +0 -0
  223. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/dashboard.yaml +0 -0
  224. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/data-app.yaml +0 -0
  225. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/dataset.yaml +0 -0
  226. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/doctor.yaml +0 -0
  227. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/external-key.yaml +0 -0
  228. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/file.yaml +0 -0
  229. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/folder.yaml +0 -0
  230. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/job.yaml +0 -0
  231. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/link.yaml +0 -0
  232. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/log.yaml +0 -0
  233. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/notification.yaml +0 -0
  234. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/parameter.yaml +0 -0
  235. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/project.yaml +0 -0
  236. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/report.yaml +0 -0
  237. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/schedule.yaml +0 -0
  238. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/schema.yaml +0 -0
  239. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/skill.yaml +0 -0
  240. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/snippet.yaml +0 -0
  241. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/support.yaml +0 -0
  242. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/template.yaml +0 -0
  243. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/trash.yaml +0 -0
  244. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/upgrade.yaml +0 -0
  245. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/user.yaml +0 -0
  246. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/version.yaml +0 -0
  247. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/webhook.yaml +0 -0
  248. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/workflow.yaml +0 -0
  249. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/commands/workspace.yaml +0 -0
  250. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/edits-target.source.yaml +0 -0
  251. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/openapi-operations.yaml +0 -0
  252. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/schema-v1.json +0 -0
  253. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/sdk-catalog.source.yaml +0 -0
  254. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/manifests/sdk-methods.yaml +0 -0
  255. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/openapi/metadata.json +0 -0
  256. {mammoth_cli-2.2.19 → mammoth_cli-2.2.20}/spec/openapi/openapi.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mammoth-cli
3
- Version: 2.2.19
3
+ Version: 2.2.20
4
4
  Summary: Command-line interface for the Mammoth Analytics platform
5
5
  Project-URL: homepage, https://mammoth.io
6
6
  Project-URL: repository, https://github.com/EdgeMetric/mammothsdk
@@ -6,7 +6,7 @@ not implement a second HTTP client and does not call private SDK members.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- __version__ = "2.2.19"
9
+ __version__ = "2.2.20"
10
10
 
11
11
  # The versioned machine output envelope contract.
12
12
  SCHEMA_VERSION = 1
@@ -116,7 +116,7 @@ Status on release: ran once on CLI 2.0.18 — fixture-lifecycle sweep 2026-09-19
116
116
 
117
117
  Run: `mammoth view conditional-format create`. Exact input fields: `mammoth schema get view.conditional-format.create`.
118
118
 
119
- Example: `mammoth view conditional-format create 123 123 --input '{"rule": {"cf_type": "RULE", "payload": {"FORMAT": {"name": "Flag open orders", "color": "red", "applies_to": "row", "column_ids": "[]"}, "CONDITION": {"OR": [{"column_1": {"CONTAINS": {"VALUE": ["Open"]}}}]}}}}'`. Placeholders are illustrative; resolve IDs and input from observed reads.
119
+ Example: `mammoth view conditional-format create 123 123 --input '{"columns": ["Q1", "Q2", "Q3"], "operator": "<", "value": 55, "color": "red"}'`. Placeholders are illustrative; resolve IDs and input from observed reads.
120
120
 
121
121
  Result: `ViewConditionalFormatCreateResult`; mutation `benign_mutation`, confirmation `none`, wait policy `not_async`.
122
122
 
@@ -176,6 +176,15 @@ them, so never report them as access denied. Pass `include_non_members: true`
176
176
  only when the user asks about projects they are not in; each row then carries
177
177
  `member`.
178
178
 
179
+ ## Conditional formatting
180
+
181
+ Colour cells in many columns by one threshold in a single command:
182
+ `view conditional-format create --input '{"columns": ["Q1", "Q2"], "operator": "<", "value": 55, "color": "red"}'`
183
+ (display names). Each cell is judged by its own value, so this makes one rule
184
+ per column in that one call and returns every created rule id. `applies_to: "row"`
185
+ makes one rule that colours whole rows when any (`match: "any"`, default) or all
186
+ (`"all"`) of the columns match. A raw `rule` body still works.
187
+
179
188
  ## Exports
180
189
 
181
190
  First inspect `view.export.list/get` for existing configuration and the exact
@@ -50,8 +50,10 @@ from mammoth_cli.runtime.confirm import (
50
50
  POLICY_YES_ALWAYS,
51
51
  enforce_confirmation,
52
52
  )
53
+ from mammoth_cli.runtime.dryrun import DryRunStop
53
54
  from mammoth_cli.runtime.invocation import Invocation
54
55
  from mammoth_cli.runtime.session import open_service, require_project
56
+ from mammoth_cli.services import conditional_format as cf_rules
55
57
  from mammoth_cli.services import read_queries, text_dates
56
58
  from mammoth_cli.services.conditions import CONDITION_KWARG, compile_condition
57
59
  from mammoth_cli.services.dashboard_review import UPLOAD_NOTE, upload_hints
@@ -2132,24 +2134,89 @@ def view_exportable_config_apply(invocation: Invocation) -> HandlerResult:
2132
2134
 
2133
2135
 
2134
2136
  def view_conditional_format_create(invocation: Invocation) -> HandlerResult:
2135
- """Create a conditional-format rule on a dataview. ``rule`` is required."""
2137
+ """Colour cells in many columns by one threshold in a single command (columns + operator + value + color): each cell is judged by its own value. applies_to=row colours whole rows when any/all of the columns match.
2138
+
2139
+ Per-cell means one rule per column, all made in this one call. A raw ``rule`` body still
2140
+ works instead.
2141
+ """ # noqa: E501
2136
2142
  project_id = require_project(invocation)
2137
2143
  dataview_id = _require_int_positional_at(invocation, 0, "view id")
2138
- document = invocation.load_input()
2139
- rule = _require_field(document, "rule")
2140
- assert document is not None
2144
+ document = invocation.load_input() or {}
2145
+ has_typed = any(field in document for field in cf_rules.TYPED_FIELDS)
2146
+ if "rule" in document and has_typed:
2147
+ raise CliError(
2148
+ code=cf_rules.CODE_INVALID_RULE,
2149
+ message="Pass either 'rule' or the typed fields (columns, operator, value, color).",
2150
+ exit_status=EXIT_USAGE,
2151
+ )
2152
+ if "rule" not in document and not has_typed:
2153
+ _require_field(document, "rule")
2141
2154
  with open_service(invocation) as (service, auth):
2142
2155
  dataset_id = _resolve_dataset_id(service, invocation, dataview_id, document)
2143
- data = service.call(
2144
- _symbol(invocation),
2145
- dataset_id=dataset_id,
2146
- dataview_id=dataview_id,
2147
- rule=rule,
2148
- project_id=project_id,
2149
- )
2156
+ if has_typed:
2157
+ metadata = _dataview_metadata(service, dataset_id, dataview_id, project_id)
2158
+ column_map, column_types = _column_maps(metadata)
2159
+ rules = cf_rules.build_rules(document, column_map, column_types)
2160
+ else:
2161
+ cf_rules.validate_rule(document["rule"])
2162
+ rules = [document["rule"]]
2163
+ data = _create_cf_rules(service, invocation, rules, (dataset_id, dataview_id, project_id))
2150
2164
  return data, _meta(invocation, auth.workspace_id, project_id)
2151
2165
 
2152
2166
 
2167
+ def _cf_sequence(rule: Any) -> int:
2168
+ return rule.get("SEQUENCE", -1) if isinstance(rule, dict) else -1
2169
+
2170
+
2171
+ def _create_cf_rules(
2172
+ service: Any, invocation: Invocation, rules: list[dict[str, Any]], scope: tuple[Any, ...]
2173
+ ) -> Any:
2174
+ """POST each rule in turn; a mid-way failure names the rule ids already created.
2175
+
2176
+ Every response is the dataview's whole rule map; the new rule has the highest SEQUENCE.
2177
+ """
2178
+ dataset_id, dataview_id, project_id = scope
2179
+ ids: list[str] = []
2180
+ data: Any = None
2181
+ for rule in rules:
2182
+ try:
2183
+ data = service.call(
2184
+ _symbol(invocation),
2185
+ dataset_id=dataset_id,
2186
+ dataview_id=dataview_id,
2187
+ rule=rule,
2188
+ project_id=project_id,
2189
+ )
2190
+ except DryRunStop as stop:
2191
+ stop.record["rules"] = rules # every body that would be sent, not just the first
2192
+ raise
2193
+ except CliError as error:
2194
+ if ids:
2195
+ error.details = {**error.details, "created_rule_ids": ids}
2196
+ error.message += f" Rules already created before the failure: {ids}."
2197
+ raise
2198
+ if isinstance(data, dict) and data:
2199
+ ids.append(max(data, key=lambda k: _cf_sequence(data[k])))
2200
+ if len(rules) == 1:
2201
+ return data
2202
+ note = f"{len(rules)} rules, one per column, so each cell is coloured by its own value."
2203
+ return {"created_rule_ids": ids, "rules_created": len(rules), "note": note}
2204
+
2205
+
2206
+ def _column_maps(metadata: list[dict[str, Any]]) -> tuple[dict[str, str], dict[str, str]]:
2207
+ """Display -> internal name and display -> type maps from a view's column metadata."""
2208
+ names: dict[str, str] = {}
2209
+ types: dict[str, str] = {}
2210
+ for column in metadata:
2211
+ internal = column.get(_INTERNAL_NAME_KEY)
2212
+ display = column.get(_DISPLAY_NAME_KEY)
2213
+ if isinstance(internal, str) and isinstance(display, str):
2214
+ names[display] = internal
2215
+ if isinstance(column.get("type"), str):
2216
+ types[display] = column["type"]
2217
+ return names, types
2218
+
2219
+
2153
2220
  def view_conditional_format_delete_all(invocation: Invocation) -> HandlerResult:
2154
2221
  """Delete a conditional-format rule on a dataview. Prompt or ``--yes``.
2155
2222
 
@@ -111,6 +111,7 @@ ERROR_SUMMARIES: dict[str, str] = {
111
111
  "invalid_argument": _S_BAD_REQUEST,
112
112
  "invalid_argument_combination": _S_BAD_REQUEST,
113
113
  "invalid_arguments": _S_BAD_REQUEST,
114
+ "invalid_rule": "A conditional-format rule wasn't valid.",
114
115
  "invalid_condition": "A filter condition wasn't valid.",
115
116
  "invalid_condition_value": "A filter condition used a value that isn't valid.",
116
117
  "invalid_config_value": _S_SETUP,
@@ -350,6 +350,24 @@ _VIEW_DATA_PROFILE_FIELDS = (
350
350
  FieldSpec("limit", required=False, annotation=int, default=50),
351
351
  )
352
352
 
353
+ # view.conditional-format.create: ``rule`` (raw body) stays accepted; the typed fields build one
354
+ # rule per column (per-cell threshold) or one row rule (see
355
+ # mammoth_cli.services.conditional_format). ``rule`` is therefore optional here -- the handler
356
+ # requires one form or the other.
357
+ _VIEW_CF_CREATE_FIELDS = (
358
+ FieldSpec("dataset_id", required=True, annotation=int),
359
+ FieldSpec("rule", required=False, annotation=dict[str, Any] | None, default=None),
360
+ FieldSpec("columns", required=False, annotation=list[str] | None, default=None),
361
+ FieldSpec("operator", required=False, annotation=str | None, default=None),
362
+ FieldSpec("value", required=False, annotation=Any, default=None),
363
+ FieldSpec("color", required=False, annotation=str | None, default=None),
364
+ FieldSpec("name", required=False, annotation=str | None, default=None),
365
+ FieldSpec(
366
+ "applies_to", required=False, annotation=Literal["row", "columns"] | None, default=None
367
+ ),
368
+ FieldSpec("match", required=False, annotation=Literal["any", "all"] | None, default=None),
369
+ )
370
+
353
371
  # dashboard.filter.add/remove are CLI composites over canvas get + canvas save
354
372
  # (DashboardsAPI.canvas_save is named in the manifest as the SDK anchor); the
355
373
  # canvas body is built by the handler, so the document carries only the filter.
@@ -760,6 +778,8 @@ def resolve_command_contract(command_id: str) -> ResolvedCommandContract | None:
760
778
  special_fields = _DASHBOARD_FILTER_ADD_FIELDS
761
779
  elif command_id == "dashboard.filter.remove":
762
780
  special_fields = _DASHBOARD_FILTER_REMOVE_FIELDS
781
+ elif command_id == "view.conditional-format.create":
782
+ special_fields = _VIEW_CF_CREATE_FIELDS
763
783
  elif command_id == "dashboard.filter.list":
764
784
  special_fields = ()
765
785
  local_fields = _LOCAL_CONTRACT_FIELDS.get(command_id, ()) if is_local else None
@@ -0,0 +1,131 @@
1
+ """Build and check the conditional-format rule body ``view conditional-format create`` sends.
2
+
3
+ The release route takes ``{"cf_type": "RULE", "payload": {"FORMAT", "CONDITION"}}``. One
4
+ rule is ``FORMAT.applies_to`` ``"columns"`` with ``column_ids`` (a JSON-encoded list of
5
+ internal names) or ``"row"``, plus a ``CONDITION`` group. The evaluator checks CONDITION per row
6
+ and colours every ``column_ids`` cell, so the typed fields build one rule per column for a
7
+ per-cell threshold, or one row rule.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ from typing import Any
14
+
15
+ from mammoth_cli.errors.envelope import EXIT_USAGE, CliError
16
+ from mammoth_cli.services.conditions import compile_condition
17
+
18
+ CODE_INVALID_RULE = "invalid_rule"
19
+ APPLIES_TO = ("row", "columns")
20
+ _EMPTY_COLUMN_IDS = "[]"
21
+ MATCH = ("any", "all")
22
+ TYPED_FIELDS = ("columns", "operator", "value", "color", "name", "applies_to", "match")
23
+ _NO_VALUE_OPERATORS = frozenset({"IS_EMPTY", "IS_NOT_EMPTY"})
24
+
25
+
26
+ def _invalid(message: str, hint: str | None = None) -> CliError:
27
+ return CliError(code=CODE_INVALID_RULE, message=message, exit_status=EXIT_USAGE, hint=hint)
28
+
29
+
30
+ def _check_format(fmt: Any) -> None:
31
+ """Mirror the backend's FORMAT validation so a bad rule fails before any request."""
32
+ if not isinstance(fmt, dict):
33
+ raise _invalid("A RULE payload needs a FORMAT object.")
34
+ applies_to = fmt.get("applies_to")
35
+ if applies_to not in APPLIES_TO:
36
+ raise _invalid(
37
+ f"FORMAT.applies_to must be one of {', '.join(APPLIES_TO)}; got {applies_to!r}.",
38
+ "Use 'row' to colour whole rows, or 'columns' with column_ids.",
39
+ )
40
+ column_ids = fmt.get("column_ids", _EMPTY_COLUMN_IDS)
41
+ empty = column_ids == _EMPTY_COLUMN_IDS
42
+ if applies_to == "row" and not empty:
43
+ raise _invalid("FORMAT.column_ids must be '[]' when applies_to is 'row'.")
44
+ if applies_to == "columns" and empty:
45
+ raise _invalid("FORMAT.column_ids must not be '[]' when applies_to is 'columns'.")
46
+
47
+
48
+ def validate_rule(rule: Any) -> None:
49
+ """Raise ``invalid_rule`` when a raw rule's FORMAT has a bad ``applies_to``/``column_ids``.
50
+
51
+ Everything else about the body (cf_type, CONDITION) is left to the backend, which
52
+ owns those shapes; only the FORMAT enum was reaching it unchecked.
53
+ """
54
+ payload = rule.get("payload") if isinstance(rule, dict) else None
55
+ if isinstance(payload, dict) and "FORMAT" in payload:
56
+ _check_format(payload["FORMAT"])
57
+
58
+
59
+ def _resolve_columns(names: Any, column_map: dict[str, str]) -> list[str]:
60
+ if not isinstance(names, list) or not names or not all(isinstance(n, str) for n in names):
61
+ raise _invalid("'columns' must be a non-empty list of column names.")
62
+ missing = [name for name in names if name not in column_map]
63
+ if missing:
64
+ raise _invalid(
65
+ f"Unknown column(s): {', '.join(missing)}.",
66
+ "Use display names of the view's columns: " + ", ".join(sorted(column_map)),
67
+ )
68
+ return list(dict.fromkeys(names))
69
+
70
+
71
+ def _leaf(column: str, document: dict[str, Any]) -> dict[str, Any]:
72
+ leaf: dict[str, Any] = {"column": column, "operator": document["operator"]}
73
+ if "value" in document:
74
+ leaf["value"] = document["value"]
75
+ return leaf
76
+
77
+
78
+ def _require_typed(document: dict[str, Any]) -> None:
79
+ for field in ("columns", "operator", "color"):
80
+ if document.get(field) is None:
81
+ raise _invalid(
82
+ f"The typed form needs '{field}'.",
83
+ 'Many columns, one command: --input \'{"columns": ["A", "B"], '
84
+ '"operator": "<", "value": 55, "color": "red"}\'.',
85
+ )
86
+
87
+
88
+ def _label(document: dict[str, Any]) -> str:
89
+ operator = str(document["operator"])
90
+ if operator.upper() in _NO_VALUE_OPERATORS:
91
+ return operator
92
+ return f"{operator} {document.get('value')}"
93
+
94
+
95
+ def _rule(fmt: dict[str, Any], condition: dict[str, Any]) -> dict[str, Any]:
96
+ rule = {"cf_type": "RULE", "payload": {"FORMAT": fmt, "CONDITION": condition}}
97
+ validate_rule(rule)
98
+ return rule
99
+
100
+
101
+ def build_rules(
102
+ document: dict[str, Any], column_map: dict[str, str], column_types: dict[str, str]
103
+ ) -> list[dict[str, Any]]:
104
+ """RULE entries for the typed fields.
105
+
106
+ The evaluator judges CONDITION once per ROW and then colours every ``column_ids`` cell, so a
107
+ threshold per cell needs one rule per column (each condition on its own column). Only
108
+ ``applies_to: row`` is one rule: ``match`` any (OR, default) or all (AND) of the columns.
109
+ """
110
+ _require_typed(document)
111
+ names = _resolve_columns(document["columns"], column_map)
112
+ color, label = document["color"], _label(document)
113
+
114
+ def condition(name: str) -> dict[str, Any]:
115
+ return compile_condition(_leaf(name, document)).build(column_map, column_types)
116
+
117
+ if document.get("applies_to") == "row":
118
+ match = document.get("match") or "any"
119
+ if match not in MATCH:
120
+ raise _invalid(f"match must be one of {', '.join(MATCH)}; got {match!r}.")
121
+ fmt = {"name": document.get("name") or f"{', '.join(names)} {label}"[:80]}
122
+ fmt |= {"color": color, "applies_to": "row", "column_ids": "[]"}
123
+ group = {"OR" if match == "any" else "AND": [condition(n) for n in names]}
124
+ return [_rule(fmt, group)]
125
+ rules = []
126
+ for name in names:
127
+ title = f"{document['name']}: {name}" if document.get("name") else f"{name} {label}"
128
+ fmt = {"name": title, "color": color, "applies_to": "columns"}
129
+ fmt["column_ids"] = json.dumps([column_map[name]])
130
+ rules.append(_rule(fmt, {"OR": [condition(name)]}))
131
+ return rules
@@ -226,22 +226,13 @@ _EXAMPLE_INPUT_HINTS: dict[str, dict[str, Any]] = {
226
226
  },
227
227
  "view.ai.profile": {"dataset_id": 456, "action": "insights"},
228
228
  "connector.query.generate": {"query": "Total sales for January"},
229
- # HighlightEntry: cf_type + payload{FORMAT, CONDITION keyed by internal
230
- # column name}; the create response and ``conditional-format list`` carry
231
- # the generated rule_id that delete-all needs.
229
+ # One rule over many columns; the create response and ``conditional-format
230
+ # list`` carry the generated rule_id that delete-all needs.
232
231
  "view.conditional-format.create": {
233
- "rule": {
234
- "cf_type": "RULE",
235
- "payload": {
236
- "FORMAT": {
237
- "name": "Flag open orders",
238
- "color": "red",
239
- "applies_to": "row",
240
- "column_ids": "[]",
241
- },
242
- "CONDITION": {"OR": [{"column_1": {"CONTAINS": {"VALUE": ["Open"]}}}]},
243
- },
244
- }
232
+ "columns": ["Q1", "Q2", "Q3"],
233
+ "operator": "<",
234
+ "value": 55,
235
+ "color": "red",
245
236
  },
246
237
  "view.conditional-format.delete-all": {"rule_id": "bca0ff33bd6f8ed1"},
247
238
  "dataset.bulk-delete": {"dataset_ids": [456, 457]},
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mammoth-cli"
3
- version = "2.2.19"
3
+ version = "2.2.20"
4
4
  description = "Command-line interface for the Mammoth Analytics platform"
5
5
  authors = [{name = "Mammoth Analytics", email = "support@mammoth.io"}]
6
6
  readme = "README.md"
@@ -593,9 +593,8 @@ commands:
593
593
  required_fixture_guard: null
594
594
  secret_fields: []
595
595
  human_example: mammoth view conditional-format create VIEW_ID --help
596
- agent_example: 'mammoth view conditional-format create 123 123 --input ''{"rule": {"cf_type": "RULE",
597
- "payload": {"FORMAT": {"name": "Flag open orders", "color": "red", "applies_to": "row", "column_ids":
598
- "[]"}, "CONDITION": {"OR": [{"column_1": {"CONTAINS": {"VALUE": ["Open"]}}}]}}}}'''
596
+ agent_example: 'mammoth view conditional-format create 123 123 --input ''{"columns": ["Q1", "Q2",
597
+ "Q3"], "operator": "<", "value": 55, "color": "red"}'''
599
598
  unit_tests:
600
599
  - UT-VIEW-CONDITIONAL-FORMAT-CREATE
601
600
  contract_tests:
@@ -604,9 +603,10 @@ commands:
604
603
  - CT-VIEW-CONDITIONAL-FORMAT-CREATE-ERROR
605
604
  draft_test: null
606
605
  undo_test: null
607
- known_restrictions: 'rule is forwarded verbatim and dispatches. The release backend requires {"cf_type":
608
- "RULE"|"COLOR_SCALE", "payload": {...}} with a CONDITION (RULE) or scale (COLOR_SCALE) inside payload;
609
- other shapes return HTTP 400 4GENR007. Untyped; no working payload observed yet.'
606
+ known_restrictions: 'columns + operator + value + color colour each cell by its own value: one RULE
607
+ per column, created in this one call (applies_to columns, the default). applies_to row makes
608
+ one rule over any/all (match) of the columns. A raw rule body ({"cf_type": "RULE"|"COLOR_SCALE",
609
+ "payload": {...}}) still works instead; applies_to must be row or columns.'
610
610
  reviewed_by: primary
611
611
  - command_id: view.conditional-format.delete-all
612
612
  command_path: view conditional-format delete-all
File without changes
File without changes
File without changes