mammoth-cli 2.2.18__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.18 → mammoth_cli-2.2.20}/PKG-INFO +2 -2
  2. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/__init__.py +1 -1
  3. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +2 -2
  4. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +10 -0
  5. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +1 -1
  6. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +14 -1
  7. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/dataset.py +42 -0
  8. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/registry.py +1 -0
  9. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/view.py +78 -11
  10. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/errors/envelope.py +1 -0
  11. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/command_contract.py +21 -0
  12. mammoth_cli-2.2.20/mammoth_cli/services/conditional_format.py +131 -0
  13. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/input_fields.py +6 -15
  14. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/positionals.py +10 -0
  15. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/pyproject.toml +2 -2
  16. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/dataset.yaml +40 -0
  17. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/view.yaml +6 -6
  18. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/sdk-methods.yaml +12 -0
  19. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/.gitignore +0 -0
  20. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/LICENSE +0 -0
  21. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/README.md +0 -0
  22. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/__main__.py +0 -0
  23. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/app.py +0 -0
  24. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +0 -0
  25. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
  26. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
  27. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
  28. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
  29. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
  30. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
  31. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
  32. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
  33. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
  34. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
  35. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
  36. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
  37. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
  38. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
  39. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
  40. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
  41. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
  42. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
  43. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
  44. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
  45. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
  46. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
  47. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-style.md +0 -0
  48. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-template.md +0 -0
  49. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
  50. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
  51. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
  52. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
  53. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
  54. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
  55. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
  56. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/link.md +0 -0
  57. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
  58. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
  59. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
  60. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
  61. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
  62. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
  63. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
  64. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
  65. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
  66. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
  67. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
  68. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
  69. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
  70. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
  71. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
  72. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
  73. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
  74. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
  75. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
  76. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
  77. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
  78. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
  79. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
  80. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
  81. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
  82. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
  83. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/database-import.md +0 -0
  84. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
  85. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
  86. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
  87. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
  88. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
  89. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +0 -0
  90. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
  91. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
  92. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
  93. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
  94. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
  95. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
  96. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
  97. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/__init__.py +0 -0
  98. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/activity.py +0 -0
  99. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/addon.py +0 -0
  100. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/agent.py +0 -0
  101. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/ai.py +0 -0
  102. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/annotation.py +0 -0
  103. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/auth.py +0 -0
  104. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/automation.py +0 -0
  105. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/batch.py +0 -0
  106. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/billing.py +0 -0
  107. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/browse.py +0 -0
  108. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/calc.py +0 -0
  109. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/capability.py +0 -0
  110. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/client_app.py +0 -0
  111. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/completion.py +0 -0
  112. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/config.py +0 -0
  113. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/connector.py +0 -0
  114. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/context.py +0 -0
  115. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/dashboard.py +0 -0
  116. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/data_app.py +0 -0
  117. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/doctor.py +0 -0
  118. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/external_key.py +0 -0
  119. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/file.py +0 -0
  120. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/folder.py +0 -0
  121. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/job.py +0 -0
  122. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/link.py +0 -0
  123. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/notification.py +0 -0
  124. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/parameter.py +0 -0
  125. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/project.py +0 -0
  126. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/report.py +0 -0
  127. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/schedule.py +0 -0
  128. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/schema.py +0 -0
  129. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/skill.py +0 -0
  130. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/snippet.py +0 -0
  131. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/support.py +0 -0
  132. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/template.py +0 -0
  133. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/trash.py +0 -0
  134. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/upgrade.py +0 -0
  135. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/user.py +0 -0
  136. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/view_ops.py +0 -0
  137. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/view_profile.py +0 -0
  138. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/webhook.py +0 -0
  139. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/workflow.py +0 -0
  140. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/commands/workspace.py +0 -0
  141. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/context/__init__.py +0 -0
  142. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/context/credentials.py +0 -0
  143. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/context/endpoint.py +0 -0
  144. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/context/profiles.py +0 -0
  145. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/context/resolver.py +0 -0
  146. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/contracts/__init__.py +0 -0
  147. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/contracts/auth.py +0 -0
  148. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/embed.py +0 -0
  149. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/errors/__init__.py +0 -0
  150. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/manifest/__init__.py +0 -0
  151. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/manifest/loader.py +0 -0
  152. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/messages/__init__.py +0 -0
  153. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/output/__init__.py +0 -0
  154. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/output/envelope.py +0 -0
  155. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/output/normalize.py +0 -0
  156. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/output/policy.py +0 -0
  157. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/output/progress.py +0 -0
  158. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/output/render.py +0 -0
  159. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/py.typed +0 -0
  160. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/__init__.py +0 -0
  161. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/confirm.py +0 -0
  162. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/dataset_health.py +0 -0
  163. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/dryrun.py +0 -0
  164. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/dryrun_targets.py +0 -0
  165. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/embedded.py +0 -0
  166. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/executor.py +0 -0
  167. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/input_loader.py +0 -0
  168. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/intent_only.py +0 -0
  169. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/invocation.py +0 -0
  170. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/new_data.py +0 -0
  171. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/options.py +0 -0
  172. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/parents.py +0 -0
  173. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/runlog.py +0 -0
  174. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/session.py +0 -0
  175. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/state.py +0 -0
  176. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/strict.py +0 -0
  177. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/updates.py +0 -0
  178. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/validate.py +0 -0
  179. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/runtime/verify.py +0 -0
  180. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/__init__.py +0 -0
  181. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/argspec.py +0 -0
  182. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/board_values.py +0 -0
  183. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/coerce.py +0 -0
  184. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/conditions.py +0 -0
  185. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/dashboard_filters.py +0 -0
  186. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/dashboard_pages.py +0 -0
  187. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/dashboard_review.py +0 -0
  188. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/data_profile.py +0 -0
  189. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/data_quality.py +0 -0
  190. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/dispatch.py +0 -0
  191. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/factory.py +0 -0
  192. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/listing.py +0 -0
  193. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/local_time.py +0 -0
  194. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/mapping.py +0 -0
  195. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/openapi_types.py +0 -0
  196. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/protocol.py +0 -0
  197. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/read_queries.py +0 -0
  198. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/sdk_service.py +0 -0
  199. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/stored_stats.py +0 -0
  200. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/testing.py +0 -0
  201. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/text_dates.py +0 -0
  202. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/type_system.py +0 -0
  203. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/services/write_impact.py +0 -0
  204. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/skills/__init__.py +0 -0
  205. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/skills/installer.py +0 -0
  206. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/skills/steering.py +0 -0
  207. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/mammoth_cli/testing.py +0 -0
  208. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/activity.yaml +0 -0
  209. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/addon.yaml +0 -0
  210. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/agent.yaml +0 -0
  211. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/ai.yaml +0 -0
  212. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/annotation.yaml +0 -0
  213. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/auth.yaml +0 -0
  214. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/automation.yaml +0 -0
  215. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/batch.yaml +0 -0
  216. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/billing.yaml +0 -0
  217. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/browse.yaml +0 -0
  218. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/calc.yaml +0 -0
  219. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/capability.yaml +0 -0
  220. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/client-app.yaml +0 -0
  221. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/completion.yaml +0 -0
  222. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/config.yaml +0 -0
  223. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/connector.yaml +0 -0
  224. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/context.yaml +0 -0
  225. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/dashboard.yaml +0 -0
  226. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/data-app.yaml +0 -0
  227. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/doctor.yaml +0 -0
  228. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/external-key.yaml +0 -0
  229. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/file.yaml +0 -0
  230. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/folder.yaml +0 -0
  231. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/job.yaml +0 -0
  232. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/link.yaml +0 -0
  233. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/log.yaml +0 -0
  234. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/notification.yaml +0 -0
  235. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/parameter.yaml +0 -0
  236. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/project.yaml +0 -0
  237. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/report.yaml +0 -0
  238. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/schedule.yaml +0 -0
  239. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/schema.yaml +0 -0
  240. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/skill.yaml +0 -0
  241. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/snippet.yaml +0 -0
  242. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/support.yaml +0 -0
  243. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/template.yaml +0 -0
  244. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/trash.yaml +0 -0
  245. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/upgrade.yaml +0 -0
  246. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/user.yaml +0 -0
  247. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/version.yaml +0 -0
  248. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/webhook.yaml +0 -0
  249. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/workflow.yaml +0 -0
  250. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/commands/workspace.yaml +0 -0
  251. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/edits-target.source.yaml +0 -0
  252. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/openapi-operations.yaml +0 -0
  253. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/schema-v1.json +0 -0
  254. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/manifests/sdk-catalog.source.yaml +0 -0
  255. {mammoth_cli-2.2.18 → mammoth_cli-2.2.20}/spec/openapi/metadata.json +0 -0
  256. {mammoth_cli-2.2.18 → 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.18
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
@@ -17,7 +17,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
17
  Requires-Python: <3.15,>=3.12
18
18
  Requires-Dist: jsonschema>=4.20
19
19
  Requires-Dist: keyring<26,>=25.7
20
- Requires-Dist: mammoth-io<0.9,>=0.8.15
20
+ Requires-Dist: mammoth-io<0.9,>=0.8.16
21
21
  Requires-Dist: platformdirs<5,>=4.10
22
22
  Requires-Dist: pydantic<3,>=2.12.5
23
23
  Requires-Dist: pyyaml<7,>=6
@@ -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.18"
9
+ __version__ = "2.2.20"
10
10
 
11
11
  # The versioned machine output envelope contract.
12
12
  SCHEMA_VERSION = 1
@@ -1,6 +1,6 @@
1
1
  # Published CLI command catalog
2
2
 
3
- This generated catalog is a lookup table for every command in the published CLI manifest, currently 645; each entry carries its release status line. It is a command-contract index, not an assertion that every backend/OpenAPI operation has a CLI binding. For an exact local CLI contract, run `mammoth schema get COMMAND_ID`; `mammoth capability list` is an API-binding inventory and can omit typed/local CLI routes. For focused workflows, read the [recipes index](recipes/index.md). Sensitive structured input must come from a private file or pipe; never put secrets in literal argv.
3
+ This generated catalog is a lookup table for every command in the published CLI manifest, currently 646; each entry carries its release status line. It is a command-contract index, not an assertion that every backend/OpenAPI operation has a CLI binding. For an exact local CLI contract, run `mammoth schema get COMMAND_ID`; `mammoth capability list` is an API-binding inventory and can omit typed/local CLI routes. For focused workflows, read the [recipes index](recipes/index.md). Sensitive structured input must come from a private file or pipe; never put secrets in literal argv.
4
4
 
5
5
  Load only the applicable domain file:
6
6
 
@@ -26,7 +26,7 @@ Load only the applicable domain file:
26
26
  - [dashboard-style](commands/dashboard-style.md) — 10 published commands
27
27
  - [dashboard](commands/dashboard.md) — 96 published commands
28
28
  - [data-app](commands/data-app.md) — 12 published commands
29
- - [dataset](commands/dataset.md) — 21 published commands
29
+ - [dataset](commands/dataset.md) — 22 published commands
30
30
  - [doctor](commands/doctor.md) — 1 published commands
31
31
  - [external-key](commands/external-key.md) — 4 published commands
32
32
  - [file](commands/file.md) — 9 published commands
@@ -192,6 +192,16 @@ Result: `DatasetRestoreResult`; mutation `benign_mutation`, confirmation `none`,
192
192
 
193
193
  Status on release: ran once on CLI 2.0.14 — write sweep 2026-09-18: exit 0 on release with CLI 2.0.14. job 312 restore_datasource -> status success. dataset list --project 21 confirms dataset 49 (name 'stores.csv 2') is back and visible alongside 48. Single invocation only.
194
194
 
195
+ ### `dataset.search`
196
+
197
+ Run: `mammoth dataset search`. Exact input fields: `mammoth schema get dataset.search`.
198
+
199
+ Example: `mammoth dataset search 'New Year Sale'`. Placeholders are illustrative; resolve IDs and input from observed reads.
200
+
201
+ Result: `DatasetSearchResult`; mutation `read`, confirmation `none`, wait policy `not_async`.
202
+
203
+ Status on release: untried; no live run recorded.
204
+
195
205
  ### `dataset.trash`
196
206
 
197
207
  Run: `mammoth dataset trash`. Exact input fields: `mammoth schema get dataset.trash`.
@@ -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
 
@@ -38,7 +38,11 @@ case-insensitive substring match over every page, returned as short rows
38
38
  (id, name, rows, cols) with `matched`. Do not page `dataset list` by hand;
39
39
  `limit` is at most 100. To find the dataset that holds given columns, pass
40
40
  `dataset find --input '{"columns": ["Order ID", "Region"]}'` (the name is then
41
- optional). A `browse` search hit carries `dataset_id` or `view_id`: use those,
41
+ optional). To find the dataset that holds a value you were given (a campaign,
42
+ a region, a product) when its name does not say, run `dataset search TERM`: it
43
+ returns the project's datasets whose name, column names or sampled column
44
+ values contain TERM, each with the matched column and value. `dataset find`
45
+ and `browse` search match names only. A `browse` search hit carries `dataset_id` or `view_id`: use those,
42
46
  never the tree `id`.
43
47
 
44
48
  ```bash
@@ -172,6 +176,15 @@ them, so never report them as access denied. Pass `include_non_members: true`
172
176
  only when the user asks about projects they are not in; each row then carries
173
177
  `member`.
174
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
+
175
188
  ## Exports
176
189
 
177
190
  First inspect `view.export.list/get` for existing configuration and the exact
@@ -395,6 +395,48 @@ def dataset_find(invocation: Invocation) -> HandlerResult:
395
395
  return result, meta
396
396
 
397
397
 
398
+ #: Matches kept per dataset in a ``dataset search`` row; the rest are counted, not listed.
399
+ _SEARCH_MATCHES_PER_DATASET = 5
400
+
401
+
402
+ def _search_row(hit: dict[str, Any]) -> dict[str, Any]:
403
+ """One ``dataset search`` row: the dataset and the first places its content matched."""
404
+ matches = hit.get("matches") or []
405
+ row: dict[str, Any] = {
406
+ "id": hit.get("id"),
407
+ "name": hit.get("name"),
408
+ "matches": matches[:_SEARCH_MATCHES_PER_DATASET],
409
+ }
410
+ if len(matches) > _SEARCH_MATCHES_PER_DATASET:
411
+ row["more_matches"] = len(matches) - _SEARCH_MATCHES_PER_DATASET
412
+ return row
413
+
414
+
415
+ def dataset_search(invocation: Invocation) -> HandlerResult:
416
+ """Find the project's datasets whose name, column names or sampled values hold TERM.
417
+
418
+ Read-only: one server call. Each match names where the term was found (``name``,
419
+ ``column`` or ``value``) with the column and the sampled value, so the dataset that
420
+ holds "New Year Sale" in a ``campaign`` column is found without knowing its name.
421
+ Sampled values come from the profile, which keeps up to 30 per text column, so a
422
+ dataset never profiled matches on name and columns only.
423
+ """
424
+ term = _require_string_positional(invocation, "term")
425
+ project_id = require_project(invocation)
426
+ with open_service(invocation) as (service, auth):
427
+ data = service.call(
428
+ "mammoth.api.datasets.DatasetsAPI.search", term=term, project_id=project_id
429
+ )
430
+ hits = data.get("datasets", []) if isinstance(data, dict) else []
431
+ kept, omitted = fit_budget([_search_row(h) for h in hits if isinstance(h, dict)])
432
+ result: dict[str, Any] = {"term": term, "datasets": kept, "matched": len(hits)}
433
+ if omitted:
434
+ result["omitted"] = omitted
435
+ if note := ambiguity_note(len(hits), term):
436
+ result["note"] = note
437
+ return result, _meta(invocation, auth.workspace_id, project_id)
438
+
439
+
398
440
  def dataset_list(invocation: Invocation) -> HandlerResult:
399
441
  """List datasets in the active project, newest first, each with what tells them apart.
400
442
 
@@ -318,6 +318,7 @@ HANDLERS: dict[str, Handler] = {
318
318
  # dataset family
319
319
  "dataset.find": dataset_cmd.dataset_find,
320
320
  "dataset.list": dataset_cmd.dataset_list,
321
+ "dataset.search": dataset_cmd.dataset_search,
321
322
  "dataset.get": dataset_cmd.dataset_get,
322
323
  "dataset.batch-data": dataset_cmd.dataset_batch_data,
323
324
  "dataset.data": dataset_cmd.dataset_data,
@@ -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.
@@ -388,6 +406,7 @@ _LOCAL_COMMANDS = frozenset(
388
406
  "context.project.status",
389
407
  "context.project.use",
390
408
  "dataset.find",
409
+ "dataset.search",
391
410
  "doctor",
392
411
  "project.check",
393
412
  "project.ensure",
@@ -759,6 +778,8 @@ def resolve_command_contract(command_id: str) -> ResolvedCommandContract | None:
759
778
  special_fields = _DASHBOARD_FILTER_ADD_FIELDS
760
779
  elif command_id == "dashboard.filter.remove":
761
780
  special_fields = _DASHBOARD_FILTER_REMOVE_FIELDS
781
+ elif command_id == "view.conditional-format.create":
782
+ special_fields = _VIEW_CF_CREATE_FIELDS
762
783
  elif command_id == "dashboard.filter.list":
763
784
  special_fields = ()
764
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]},
@@ -650,6 +650,16 @@ POSITIONAL_OVERRIDES: dict[str, tuple[PositionalSpec, ...]] = {
650
650
  example_value="sales",
651
651
  ),
652
652
  ),
653
+ "dataset.search": (
654
+ PositionalSpec(
655
+ name="term",
656
+ type=str,
657
+ required=True,
658
+ help="Text to find in dataset names, column names or sampled column values "
659
+ "(case-insensitive, at least 2 characters).",
660
+ example_value="New Year Sale",
661
+ ),
662
+ ),
653
663
  "folder.find": (
654
664
  PositionalSpec(
655
665
  name="name_substring",
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "mammoth-cli"
3
- version = "2.2.18"
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"
7
7
  license = "LicenseRef-Proprietary"
8
8
  requires-python = ">=3.12,<3.15"
9
9
  dependencies = [
10
- "mammoth-io (>=0.8.15,<0.9)",
10
+ "mammoth-io (>=0.8.16,<0.9)",
11
11
  "typer (>=0.27,<0.28)",
12
12
  "rich (>=15,<16)",
13
13
  "platformdirs (>=4.10,<5)",
@@ -818,6 +818,46 @@ commands:
818
818
  undo_test: null
819
819
  known_restrictions: null
820
820
  reviewed_by: primary
821
+ - command_id: dataset.search
822
+ command_path: dataset search
823
+ disposition: command
824
+ alias_of: null
825
+ operation_ids: []
826
+ positionals:
827
+ - name: term
828
+ type: str
829
+ required: true
830
+ metavar: TERM
831
+ falls_back_to_field: null
832
+ help: Text to find in dataset names, column names or sampled column values (case-insensitive,
833
+ at least 2 characters).
834
+ options: []
835
+ sdk_symbol: mammoth_cli.commands.dataset.search
836
+ sdk_conversion: Call mammoth_cli.commands.dataset.search with validated request fields.
837
+ request_model: DatasetSearchRequest
838
+ result_model: DatasetSearchResult
839
+ mutation_class: read
840
+ confirmation: none
841
+ wait_policy: not_async
842
+ pagination_policy: none
843
+ acceptance_evidence: live_read_only
844
+ live_test: null
845
+ live_exemption_reason: Read-only composite over the project's datasets search route.
846
+ contract_fixture: null
847
+ required_fixture_guard: null
848
+ secret_fields: []
849
+ human_example: mammoth dataset search TERM --help
850
+ agent_example: mammoth dataset search 'New Year Sale'
851
+ unit_tests:
852
+ - UT-DATASET-SEARCH
853
+ contract_tests:
854
+ - CT-DATASET-SEARCH-HUMAN
855
+ - CT-DATASET-SEARCH-JSON
856
+ - CT-DATASET-SEARCH-ERROR
857
+ draft_test: null
858
+ undo_test: null
859
+ known_restrictions: null
860
+ reviewed_by: primary
821
861
  - command_id: dataset.trash
822
862
  command_path: dataset trash
823
863
  disposition: command
@@ -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
@@ -3833,6 +3833,18 @@ methods:
3833
3833
  pagination_policy: null
3834
3834
  secret_fields: []
3835
3835
  reviewed_by: primary
3836
+ - sdk_symbol: mammoth.api.datasets.DatasetsAPI.search
3837
+ implementation_origin: mammoth.api.datasets.DatasetsAPI.search
3838
+ signature: 'search(self, term: ''str'', workspace_id: ''int | None'' = None, project_id: ''int | None'' = None) -> ''dict[str, Any]'''
3839
+ openapi_operation_ids: []
3840
+ canonical_command: null
3841
+ alias_of: null
3842
+ no_command_reason: SDK-only helper; no reviewed CLI command.
3843
+ mutation_class: null
3844
+ wait_policy: null
3845
+ pagination_policy: null
3846
+ secret_fields: []
3847
+ reviewed_by: primary
3836
3848
  - sdk_symbol: mammoth.api.datasets.DatasetsAPI.trash
3837
3849
  implementation_origin: mammoth.api.datasets.DatasetsAPI.trash
3838
3850
  signature: 'trash(self, dataset_id: ''int'', workspace_id: ''int | None'' = None, project_id: ''int | None'' = None) -> ''dict[str, Any]'''
File without changes
File without changes
File without changes