mammoth-cli 2.2.90__tar.gz → 2.2.92__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 (313) hide show
  1. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/PKG-INFO +1 -1
  2. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/__init__.py +1 -1
  3. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/app.py +26 -1
  4. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +1 -1
  5. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +4 -2
  6. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/browse.py +40 -3
  7. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/dashboard.py +31 -1
  8. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/dataset.py +45 -4
  9. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/help_summaries.json +1 -1
  10. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_ops.py +137 -22
  11. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/errors/envelope.py +3 -0
  12. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/dataset_health.py +12 -1
  13. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/input_loader.py +42 -4
  14. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/shared.py +1 -3
  15. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/state.py +11 -7
  16. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/strict.py +45 -0
  17. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/validate.py +11 -2
  18. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/coerce.py +48 -4
  19. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/delete_check.py +4 -2
  20. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/field_enums.py +9 -1
  21. mammoth_cli-2.2.92/mammoth_cli/services/poll.py +22 -0
  22. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/sdk_service.py +32 -2
  23. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/pyproject.toml +1 -1
  24. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/view.yaml +10 -6
  25. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/.gitignore +0 -0
  26. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/LICENSE +0 -0
  27. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/README.md +0 -0
  28. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/__main__.py +0 -0
  29. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
  30. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
  31. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
  32. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
  33. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
  34. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
  35. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
  36. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
  37. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
  38. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
  39. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
  40. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
  41. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
  42. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
  43. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
  44. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
  45. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capabilities.md +0 -0
  46. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
  47. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
  48. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/collection.md +0 -0
  49. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
  50. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
  51. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
  52. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
  53. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-embed.md +0 -0
  54. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-published.md +0 -0
  55. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
  56. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-style.md +0 -0
  57. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-template.md +0 -0
  58. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
  59. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
  60. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
  61. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
  62. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
  63. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
  64. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
  65. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/how.md +0 -0
  66. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
  67. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/link.md +0 -0
  68. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
  69. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
  70. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
  71. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
  72. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
  73. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/resolve.md +0 -0
  74. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
  75. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
  76. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
  77. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
  78. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
  79. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
  80. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/token.md +0 -0
  81. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
  82. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
  83. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
  84. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
  85. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
  86. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +0 -0
  87. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
  88. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
  89. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
  90. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
  91. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
  92. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
  93. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
  94. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
  95. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/build-an-agent.md +0 -0
  96. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
  97. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
  98. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/database-import.md +0 -0
  99. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
  100. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
  101. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/file-import.md +0 -0
  102. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
  103. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
  104. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
  105. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/rest-api-import.md +0 -0
  106. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +0 -0
  107. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
  108. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
  109. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
  110. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
  111. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
  112. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
  113. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
  114. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/__init__.py +0 -0
  115. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/_lazy.py +0 -0
  116. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/activity.py +0 -0
  117. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/addon.py +0 -0
  118. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/agent.py +0 -0
  119. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/ai.py +0 -0
  120. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/annotation.py +0 -0
  121. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/auth.py +0 -0
  122. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/automation.py +0 -0
  123. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/batch.py +0 -0
  124. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/billing.py +0 -0
  125. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/calc.py +0 -0
  126. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/capabilities.py +0 -0
  127. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/capability.py +0 -0
  128. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/client_app.py +0 -0
  129. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/completion.py +0 -0
  130. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/config.py +0 -0
  131. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/connector.py +0 -0
  132. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/context.py +0 -0
  133. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/data_app.py +0 -0
  134. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/doctor.py +0 -0
  135. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/external_key.py +0 -0
  136. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/file.py +0 -0
  137. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/folder.py +0 -0
  138. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/how.py +0 -0
  139. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/job.py +0 -0
  140. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/link.py +0 -0
  141. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/notification.py +0 -0
  142. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/parameter.py +0 -0
  143. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/project.py +0 -0
  144. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/registry.py +0 -0
  145. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/report.py +0 -0
  146. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/resolve.py +0 -0
  147. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/schedule.py +0 -0
  148. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/schema.py +0 -0
  149. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/skill.py +0 -0
  150. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/snippet.py +0 -0
  151. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/support.py +0 -0
  152. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/template.py +0 -0
  153. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/trash.py +0 -0
  154. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/upgrade.py +0 -0
  155. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/user.py +0 -0
  156. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view.py +0 -0
  157. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_drivers.py +0 -0
  158. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_explore.py +0 -0
  159. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_forecast.py +0 -0
  160. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_profile.py +0 -0
  161. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/webhook.py +0 -0
  162. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/workflow.py +0 -0
  163. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/workspace.py +0 -0
  164. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/__init__.py +0 -0
  165. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/credentials.py +0 -0
  166. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/endpoint.py +0 -0
  167. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/keyring_backend.py +0 -0
  168. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/oauth.py +0 -0
  169. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/profiles.py +0 -0
  170. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/resolver.py +0 -0
  171. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/contracts/__init__.py +0 -0
  172. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/contracts/auth.py +0 -0
  173. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/__init__.py +0 -0
  174. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/limitations.json +0 -0
  175. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/next_commands.json +0 -0
  176. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/recipes.json +0 -0
  177. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/embed.py +0 -0
  178. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/errors/__init__.py +0 -0
  179. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/manifest/__init__.py +0 -0
  180. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/manifest/loader.py +0 -0
  181. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/messages/__init__.py +0 -0
  182. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/__init__.py +0 -0
  183. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/envelope.py +0 -0
  184. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/normalize.py +0 -0
  185. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/policy.py +0 -0
  186. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/progress.py +0 -0
  187. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/render.py +0 -0
  188. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/py.typed +0 -0
  189. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/__init__.py +0 -0
  190. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/compact.py +0 -0
  191. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/confirm.py +0 -0
  192. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/dryrun.py +0 -0
  193. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/dryrun_targets.py +0 -0
  194. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/embedded.py +0 -0
  195. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/executor.py +0 -0
  196. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/intent_only.py +0 -0
  197. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/invocation.py +0 -0
  198. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/labels.py +0 -0
  199. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/locked_files.py +0 -0
  200. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/new_data.py +0 -0
  201. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/next_commands.py +0 -0
  202. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/opens.py +0 -0
  203. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/options.py +0 -0
  204. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/parents.py +0 -0
  205. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/runlog.py +0 -0
  206. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/session.py +0 -0
  207. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/token_scope.py +0 -0
  208. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/updates.py +0 -0
  209. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/verify.py +0 -0
  210. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/__init__.py +0 -0
  211. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/append_blank_columns.py +0 -0
  212. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/argspec.py +0 -0
  213. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/board_values.py +0 -0
  214. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/column_type_guard.py +0 -0
  215. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/command_contract.py +0 -0
  216. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/conditional_format.py +0 -0
  217. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/conditions.py +0 -0
  218. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_figures.py +0 -0
  219. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_filters.py +0 -0
  220. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_pages.py +0 -0
  221. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_review.py +0 -0
  222. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/data_profile.py +0 -0
  223. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/data_quality.py +0 -0
  224. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dispatch.py +0 -0
  225. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_card_edit.py +0 -0
  226. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_cards.py +0 -0
  227. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_to_figure.py +0 -0
  228. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_to_image.py +0 -0
  229. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/factory.py +0 -0
  230. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/folder_ids.py +0 -0
  231. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/input_fields.py +0 -0
  232. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/job_outcome.py +0 -0
  233. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/listing.py +0 -0
  234. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/local_files.py +0 -0
  235. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/local_time.py +0 -0
  236. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/mapping.py +0 -0
  237. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/openapi_types.py +0 -0
  238. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/paging.py +0 -0
  239. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/period_analysis.py +0 -0
  240. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/positionals.py +0 -0
  241. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/protocol.py +0 -0
  242. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/read_memo.py +0 -0
  243. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/read_queries.py +0 -0
  244. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/schema_diff.py +0 -0
  245. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/sql_check.py +0 -0
  246. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/stored_stats.py +0 -0
  247. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/suggest.py +0 -0
  248. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/testing.py +0 -0
  249. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/text_dates.py +0 -0
  250. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/type_system.py +0 -0
  251. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/view_analysis.py +0 -0
  252. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/view_variants.py +0 -0
  253. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/write_impact.py +0 -0
  254. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/skills/__init__.py +0 -0
  255. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/skills/installer.py +0 -0
  256. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/skills/steering.py +0 -0
  257. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/testing.py +0 -0
  258. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/activity.yaml +0 -0
  259. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/addon.yaml +0 -0
  260. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/agent.yaml +0 -0
  261. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/ai.yaml +0 -0
  262. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/annotation.yaml +0 -0
  263. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/auth.yaml +0 -0
  264. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/automation.yaml +0 -0
  265. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/batch.yaml +0 -0
  266. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/billing.yaml +0 -0
  267. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/browse.yaml +0 -0
  268. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/calc.yaml +0 -0
  269. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/capabilities.yaml +0 -0
  270. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/capability.yaml +0 -0
  271. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/client-app.yaml +0 -0
  272. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/collection.yaml +0 -0
  273. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/completion.yaml +0 -0
  274. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/config.yaml +0 -0
  275. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/connector.yaml +0 -0
  276. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/context.yaml +0 -0
  277. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/dashboard.yaml +0 -0
  278. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/data-app.yaml +0 -0
  279. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/dataset.yaml +0 -0
  280. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/doctor.yaml +0 -0
  281. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/external-key.yaml +0 -0
  282. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/file.yaml +0 -0
  283. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/folder.yaml +0 -0
  284. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/how.yaml +0 -0
  285. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/job.yaml +0 -0
  286. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/link.yaml +0 -0
  287. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/log.yaml +0 -0
  288. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/notification.yaml +0 -0
  289. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/parameter.yaml +0 -0
  290. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/project.yaml +0 -0
  291. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/report.yaml +0 -0
  292. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/resolve.yaml +0 -0
  293. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/schedule.yaml +0 -0
  294. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/schema.yaml +0 -0
  295. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/skill.yaml +0 -0
  296. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/snippet.yaml +0 -0
  297. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/support.yaml +0 -0
  298. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/template.yaml +0 -0
  299. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/token.yaml +0 -0
  300. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/trash.yaml +0 -0
  301. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/upgrade.yaml +0 -0
  302. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/user.yaml +0 -0
  303. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/version.yaml +0 -0
  304. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/webhook.yaml +0 -0
  305. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/workflow.yaml +0 -0
  306. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/workspace.yaml +0 -0
  307. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/edits-target.source.yaml +0 -0
  308. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/openapi-operations.yaml +0 -0
  309. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/schema-v1.json +0 -0
  310. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/sdk-catalog.source.yaml +0 -0
  311. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/sdk-methods.yaml +0 -0
  312. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/openapi/metadata.json +0 -0
  313. {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/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.90
3
+ Version: 2.2.92
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.90"
9
+ __version__ = "2.2.92"
10
10
 
11
11
  # The versioned machine output envelope contract.
12
12
  SCHEMA_VERSION = 1
@@ -428,6 +428,29 @@ def _global_option_flags() -> tuple[frozenset[str], frozenset[str]]:
428
428
  return frozenset(every), frozenset(valued)
429
429
 
430
430
 
431
+ def missing_argument_hint(tokens: Sequence[str]) -> str:
432
+ """The command's usage line and runnable example, for a ``missing_argument`` error.
433
+
434
+ The command is the longest run of leading words that names one; with none, the
435
+ generic pointer to the schema.
436
+ """
437
+ generic = "Check the command schema with 'mammoth schema get'."
438
+ path_to_command, _ = _command_tree()
439
+ words = [token for token in tokens if not token.startswith("-")]
440
+ for length in range(len(words), 0, -1):
441
+ command_id = path_to_command.get(tuple(words[:length]))
442
+ if command_id is None:
443
+ continue
444
+ slots = " ".join(
445
+ spec.metavar if spec.required else f"[{spec.metavar}]"
446
+ for spec in resolve_positionals(command_id)
447
+ )
448
+ usage = " ".join(part for part in ("mammoth", *words[:length], slots) if part)
449
+ example = (command_by_id(command_id) or {}).get("agent_example")
450
+ return f"Usage: {usage}." + (f" Example: {example}" if example else "")
451
+ return generic
452
+
453
+
431
454
  def _corrected_command(tokens: Sequence[str]) -> str | None:
432
455
  """Rebuild an invocation with leading global options moved after the command.
433
456
 
@@ -747,7 +770,7 @@ class _EnvelopeGroup(TyperGroup):
747
770
  code="missing_argument",
748
771
  message=error_message,
749
772
  exit_status=EXIT_USAGE,
750
- hint="Check the command schema with 'mammoth schema get'.",
773
+ hint=missing_argument_hint(tokens),
751
774
  )
752
775
  elif isinstance(error, _typer_click_exceptions.NoSuchOption):
753
776
  option = getattr(error, "option_name", None) or "unknown"
@@ -779,6 +802,8 @@ class _EnvelopeGroup(TyperGroup):
779
802
  executor.emit_error(report, machine=True)
780
803
  elif report is None:
781
804
  error.show()
805
+ if is_missing_parameter:
806
+ typer.echo(missing_argument_hint(tokens), err=True)
782
807
  else:
783
808
  # A no-subcommand error arrives with the help text already on
784
809
  # screen, so repeating "run --help" below it would be noise.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mammoth-cli
3
- version: 2.2.90
3
+ version: 2.2.92
4
4
  description: "Use Mammoth Analytics from a terminal: install or authenticate the CLI, discover its live command contract, and safely manage projects, data, views, pipelines (join, merge, pivot, filter, clean), dashboards, exports, and handoffs."
5
5
  ---
6
6
 
@@ -98,8 +98,10 @@ When several transforms go on the same view in a row (for example filter, sort,
98
98
  limit-rows), send them in one `view transform batch VIEW_ID --input '{"steps": [{"op":
99
99
  "filter", "input": {...}}, ...]}'` instead of one command each: the pipeline runs once and
100
100
  one verified outcome comes back (`row_check`, and `tasks` with each new task's status).
101
- Each `input` is what that `view transform` command takes. A step cannot use a column an
102
- earlier step of the batch creates: run those steps first. If a task fails, the batch's tasks
101
+ Each `input` is what that `view transform` command takes. A step can use the columns an
102
+ earlier step adds (`split`, `copy-columns`, or the `new_column` of `substring`, `extract-date`,
103
+ `increment-date`). `split`, `unnest` and `pivot` can be
104
+ batch steps too; `unnest` and `pivot` replace the view's columns, so they go last (and no `sort` step before them). If a task fails, the batch's tasks
103
105
  are removed and the error names `steps[i]`.
104
106
 
105
107
  Prefer a typed `view transform <operation>` command. Its schema is the
@@ -17,6 +17,7 @@ from mammoth_cli.errors.envelope import (
17
17
  CODE_INVALID_ARGUMENT,
18
18
  CODE_MISSING_ARGUMENT,
19
19
  CODE_MISSING_FIELD,
20
+ CODE_RESOURCE_NOT_FOUND,
20
21
  CODE_SDK_SYMBOL_UNRESOLVED,
21
22
  EXIT_USAGE,
22
23
  CliError,
@@ -28,6 +29,31 @@ from mammoth_cli.services.folder_ids import FolderIds
28
29
 
29
30
  HandlerResult = tuple[Any, dict[str, Any]]
30
31
 
32
+ #: The route's resource types are datasource, dataview, label, file_object, report and webhook;
33
+ #: these are the names a caller reaches for instead.
34
+ _RESOURCE_TYPE_ALIASES = {"dataset": "datasource", "folder": "label"}
35
+
36
+
37
+ def canonical_resource_type(value: str) -> str:
38
+ """``value`` (one type, or several joined by commas) with each alias as the route's name."""
39
+ return ",".join(
40
+ _RESOURCE_TYPE_ALIASES.get(part.strip(), part.strip()) for part in value.split(",")
41
+ )
42
+
43
+
44
+ def ancestors_needs_a_folder(error: CliError) -> CliError:
45
+ """``error`` (the 404 for an id that is no folder) as a message saying what to pass."""
46
+ return CliError(
47
+ code=error.code,
48
+ message="browse ancestors needs a FOLDER id; this id is not a folder.",
49
+ exit_status=error.exit_status,
50
+ hint=(
51
+ "A dataset or view has no ancestors of its own: run `mammoth browse resource "
52
+ "dataset ID` (or `dataview ID`) and pass the parent_resource_id it returns."
53
+ ),
54
+ details=error.details,
55
+ )
56
+
31
57
 
32
58
  def _symbol(invocation: Invocation) -> str:
33
59
  """Return the reviewed backing SDK symbol for this command."""
@@ -213,7 +239,8 @@ def browse_resource(invocation: Invocation) -> HandlerResult:
213
239
  )
214
240
  with open_service(invocation) as (service, auth):
215
241
  folders = FolderIds(service)
216
- if str(resource_type) == "label":
242
+ resource_type = canonical_resource_type(str(resource_type))
243
+ if resource_type == "label":
217
244
  object_id = folders.label(project_id, int(object_id))
218
245
  data = service.call(
219
246
  _symbol(invocation),
@@ -230,7 +257,14 @@ def browse_ancestors(invocation: Invocation) -> HandlerResult:
230
257
  project_id = require_project(invocation)
231
258
  resource_id = _require_int_positional(invocation, "resource id")
232
259
  with open_service(invocation) as (service, auth):
233
- found = service.call(_symbol(invocation), resource_id=resource_id, project_id=project_id)
260
+ try:
261
+ found = service.call(
262
+ _symbol(invocation), resource_id=resource_id, project_id=project_id
263
+ )
264
+ except CliError as exc:
265
+ if exc.code != CODE_RESOURCE_NOT_FOUND:
266
+ raise
267
+ raise ancestors_needs_a_folder(exc) from exc
234
268
  data = FolderIds(service).open_data(found, project_id)
235
269
  return data, _meta(invocation, auth.workspace_id, project_id)
236
270
 
@@ -238,7 +272,8 @@ def browse_ancestors(invocation: Invocation) -> HandlerResult:
238
272
  def browse_search(invocation: Invocation) -> HandlerResult:
239
273
  """Search resources across every project of the workspace (resources v2).
240
274
 
241
- ``resource_type`` ``dataset`` means the route's ``datasource``. Each dataset hit
275
+ ``resource_type`` ``dataset`` means the route's ``datasource``, ``folder`` its ``label``.
276
+ Each dataset hit
242
277
  carries ``dataset_id`` and each view hit ``view_id``: pass those, never the tree ``id``.
243
278
  """
244
279
  document = invocation.load_input() or {}
@@ -246,6 +281,8 @@ def browse_search(invocation: Invocation) -> HandlerResult:
246
281
  _forward_optional(
247
282
  document, kwargs, ("search", "resource_type", "cursor", "limit", "sort", "fields")
248
283
  )
284
+ if isinstance(kwargs.get("resource_type"), str):
285
+ kwargs["resource_type"] = canonical_resource_type(kwargs["resource_type"])
249
286
  with open_service(invocation) as (service, auth):
250
287
  data = FolderIds(service).open_data(service.call(_symbol(invocation), **kwargs), None)
251
288
  return _with_object_ids(data), _meta(invocation, auth.workspace_id, None)
@@ -618,10 +618,13 @@ def dashboard_share(invocation: Invocation) -> HandlerResult:
618
618
  assert document is not None
619
619
  _forward_optional(document, kwargs, ("users",))
620
620
  with open_service(invocation) as (service, auth):
621
+ was_published = _was_published(service, dashboard_id)
622
+ if not was_published:
623
+ refuse_viewer_share_before_publish(dashboard_id, type_of_auth, kwargs.get("users"))
621
624
  unpublished = (
622
625
  " (not published yet: sharing alone does not publish it; run dashboard action "
623
626
  'with {"action":"publish-presentation"} to publish)'
624
- if not _was_published(service, dashboard_id)
627
+ if not was_published
625
628
  else ""
626
629
  )
627
630
  enforce_confirmation(
@@ -638,6 +641,33 @@ def dashboard_share(invocation: Invocation) -> HandlerResult:
638
641
  return data, _meta(invocation, auth.workspace_id)
639
642
 
640
643
 
644
+ def refuse_viewer_share_before_publish(
645
+ dashboard_id: int, type_of_auth: str, users: list[dict[str, Any]] | None
646
+ ) -> None:
647
+ """Refuse, as the server does, a ``mammoth`` share that gives viewer access before a publish.
648
+
649
+ The server (``_apply_mammoth_recipients``) refuses the whole request when any user is
650
+ shared as a viewer (the default role) and the board has no published version.
651
+ """
652
+ if type_of_auth != "mammoth":
653
+ return
654
+ for user in users or []:
655
+ shared = user.get("shared", True)
656
+ shared = shared.lower() in ("true", "1", "yes", "on") if isinstance(shared, str) else shared
657
+ if shared and user.get("role") != "dashboard_editor":
658
+ raise CliError(
659
+ code="dashboard_not_published",
660
+ message=f"Dashboard {dashboard_id} is not published; viewers cannot be invited.",
661
+ exit_status=EXIT_USAGE,
662
+ hint=(
663
+ "Publish it first: mammoth dashboard action "
664
+ f'{dashboard_id} --input \'{{"action": "publish-presentation"}}\' --yes, '
665
+ "then share. Or share only users with role dashboard_editor."
666
+ ),
667
+ details={"dashboard_id": dashboard_id},
668
+ )
669
+
670
+
641
671
  def _share_readback(service: Any, dashboard_id: int) -> dict[str, Any]:
642
672
  """The board's share state as ``dashboard get`` reports it after a share."""
643
673
  board = _dump_model(service.call(_DASHBOARD_GET, dashboard_id=dashboard_id))
@@ -35,7 +35,7 @@ from mammoth_cli.runtime.confirm import (
35
35
  )
36
36
  from mammoth_cli.runtime.invocation import Invocation
37
37
  from mammoth_cli.runtime.new_data import with_file_upload_path
38
- from mammoth_cli.runtime.session import open_service, require_project
38
+ from mammoth_cli.runtime.session import open_service, require_project, resolved_project
39
39
  from mammoth_cli.services.delete_check import ensure_deleted, find_dependents
40
40
  from mammoth_cli.services.field_enums import DATA_PULL_FILE_VALUES, allowed_values_text
41
41
  from mammoth_cli.services.listing import (
@@ -761,17 +761,22 @@ def dataset_list(invocation: Invocation) -> HandlerResult:
761
761
  datasets" never needs paging: read ``total`` with the first page's newest names.
762
762
  For a list of names (e.g. "which files can I see?") pass ``names: true``: ONE call
763
763
  returns up to 500 bare ``{id, name}`` rows, newest first, with ``total`` and ``more``.
764
+ With no project set it returns ``{project_id, project_name, id, name}`` rows from every
765
+ project the caller can open, from one workspace search (the newest 500 at most).
764
766
  ``full: true`` returns the raw ``{id, name}`` list instead. ``name`` keeps only datasets
765
767
  whose name contains it (case-insensitive) across every page, as short rows without
766
768
  column lists; ``limit``/``offset`` then page over the matches.
767
769
  """
768
- project_id = require_project(invocation)
769
770
  document = invocation.load_input() or {}
771
+ name = document.get("name")
772
+ wants_names = document.get("names") and not (isinstance(name, str) and name.strip())
773
+ if wants_names and resolved_project(invocation) is None:
774
+ return _dataset_names_everywhere(invocation)
775
+ project_id = require_project(invocation)
770
776
  _validate_paging(document)
771
777
  kwargs: dict[str, Any] = {"project_id": project_id}
772
778
  _forward_optional(document, kwargs, ("limit", "offset", "sort"))
773
- name = document.get("name")
774
- if document.get("names") and not (isinstance(name, str) and name.strip()):
779
+ if wants_names:
775
780
  return _dataset_names(invocation, project_id, document)
776
781
  if isinstance(name, str) and name.strip():
777
782
  return _dataset_name_search(invocation, project_id, name.strip(), document)
@@ -817,6 +822,42 @@ def _dataset_names(
817
822
  return result, _meta(invocation, auth.workspace_id, project_id)
818
823
 
819
824
 
825
+ def _dataset_names_everywhere(invocation: Invocation) -> HandlerResult:
826
+ """``dataset list`` with ``names`` and no project: the names of every reachable project.
827
+
828
+ One workspace search (100 hits a page, the route's cap) lists the datasets of the
829
+ projects the caller can open, under the same access rules as ``project list``; one
830
+ ``project list`` read supplies the project names. Capped at ``_SEARCH_PAGES`` pages.
831
+ """
832
+ with open_service(invocation) as (service, auth):
833
+ hits, cut = search_hits(service, "datasource", "", fields="minimal")
834
+ names = {p.get("id"): p.get("name") for p in _visible_projects(service)}
835
+ rows = [
836
+ {
837
+ "project_id": hit["project_id"],
838
+ "project_name": names[hit["project_id"]],
839
+ "id": hit["object_id"],
840
+ "name": hit.get("name"),
841
+ }
842
+ for hit in hits
843
+ if hit.get("project_id") in names
844
+ ]
845
+ kept, _cut = fit_budget(rows[:NAMES_MAX_ROWS], budget=NAMES_DATA_BUDGET)
846
+ result: dict[str, Any] = {
847
+ "datasets": kept,
848
+ "shown": len(kept),
849
+ "total": len(rows),
850
+ "projects": len({row["project_id"] for row in rows}),
851
+ }
852
+ if cut or len(kept) < len(rows):
853
+ result["more"] = True
854
+ result["note"] = (
855
+ f"Only the newest {len(kept)} names were read; pass --project to list one "
856
+ "project's names, or name to find one."
857
+ )
858
+ return result, _meta(invocation, auth.workspace_id, None)
859
+
860
+
820
861
  def _dataset_total(service: Any, project_id: int, page: dict[str, Any], offset: int) -> int:
821
862
  """The project's whole dataset count. The list route sends none, so a page that
822
863
  is the last one counts itself; otherwise the ids are read once, here, in one call."""
@@ -689,7 +689,7 @@
689
689
  "view.transform.increment-date": "Increment a date column. 'column'/'delta' required.",
690
690
  "view.transform.join": "Join another view. 'foreign_view'/'join_type'/'on'/'select' required.",
691
691
  "view.transform.json-extract": "Extract fields from a JSON column. 'column' is required.",
692
- "view.transform.limit-rows": "Limit the row count. 'n' is required.",
692
+ "view.transform.limit-rows": "Limit the row count. 'n' (or its alias 'limit') is required.",
693
693
  "view.transform.lookup": "Look up values from another view. 'source'/'lookup_view_id'/'key'/",
694
694
  "view.transform.math": "Evaluate a math expression into a column. 'expression' is required.",
695
695
  "view.transform.pivot": "Pivot with aggregations. 'group_by'/'aggregations' required.",
@@ -68,7 +68,7 @@ from mammoth_cli.runtime.confirm import POLICY_PROMPT_OR_YES, enforce_confirmati
68
68
  from mammoth_cli.runtime.dryrun import DryRunStop
69
69
  from mammoth_cli.runtime.invocation import Invocation
70
70
  from mammoth_cli.runtime.session import open_service, resolved_project
71
- from mammoth_cli.runtime.strict import validate_input_fields
71
+ from mammoth_cli.runtime.strict import apply_input_aliases, validate_input_fields
72
72
  from mammoth_cli.runtime.verify import export_stamps, export_stamps_read
73
73
  from mammoth_cli.services.column_type_guard import (
74
74
  DATE,
@@ -80,8 +80,9 @@ from mammoth_cli.services.column_type_guard import (
80
80
  from mammoth_cli.services.command_contract import bind_command_inputs, resolve_command_contract
81
81
  from mammoth_cli.services.conditions import CONDITION_KWARG, compile_condition
82
82
  from mammoth_cli.services.delete_check import ensure_deleted
83
- from mammoth_cli.services.field_enums import BATCH_OPS, allowed_values_text
83
+ from mammoth_cli.services.field_enums import BATCH_LAST_OPS, BATCH_OPS, allowed_values_text
84
84
  from mammoth_cli.services.input_fields import TASK_COUNT_FIELD
85
+ from mammoth_cli.services.poll import poll_delays
85
86
  from mammoth_cli.services.read_memo import prefetch
86
87
  from mammoth_cli.services.sql_check import check_sql_binds
87
88
  from mammoth_cli.services.suggest import nearest_one
@@ -484,16 +485,27 @@ def _dispatch_view(
484
485
  data = {key: value for key, value in data.items() if key != "message"}
485
486
  data["status"] = "done"
486
487
  data["draft_applied"] = True
488
+ settled = _settled_write(service, data) if dataset_id is not None else None
489
+ if settled is not None:
490
+ _forget_reads(service) # the state read-back must see the view as the write left it
487
491
  if after is not None and dataset_id is not None:
488
- run, run_error = (
489
- wait_for_added_task_run(service, int(dataset_id), view_id, task_ids_before)
490
- if task_ids_before is not None and not _is_staged(data)
491
- else (None, None)
492
- )
492
+ if settled is not None:
493
+ run: dict[str, Any] | None = {
494
+ "task_id": settled["task_id"],
495
+ "transform_status": settled["task_run_status"],
496
+ }
497
+ run_error = None
498
+ else:
499
+ run, run_error = (
500
+ wait_for_added_task_run(service, int(dataset_id), view_id, task_ids_before)
501
+ if task_ids_before is not None and not _is_staged(data)
502
+ else (None, None)
503
+ )
493
504
  reject_unrun_task_with_reference_errors(service, view_id, dataset_id, run_error)
494
505
  sdk_ready = sdk_saw_pipeline_ready(data)
495
506
  data = after(service, int(dataset_id), state, data)
496
- _flag_unsettled_pipeline(service, int(dataset_id), view_id, data, sdk_ready)
507
+ if settled is None:
508
+ _flag_unsettled_pipeline(service, int(dataset_id), view_id, data, sdk_ready)
497
509
  if isinstance(data, dict) and run is not None:
498
510
  data["run"] = run
499
511
  if run_error is not None:
@@ -508,8 +520,12 @@ def _dispatch_view(
508
520
  # recomputing and read back no row_count at all; wait for it to
509
521
  # settle (bounded) before trusting this one. A staged draft never
510
522
  # ran the pipeline, so there is nothing to wait for or read.
511
- rows_after, pipeline_error = wait_for_view_row_count(
512
- service, int(dataset_id), view_id, invocation.project, write_result=data
523
+ rows_after, pipeline_error = (
524
+ (settled["row_count"], None)
525
+ if settled is not None
526
+ else wait_for_view_row_count(
527
+ service, int(dataset_id), view_id, invocation.project, write_result=data
528
+ )
513
529
  )
514
530
  data["row_check"] = {"rows_before": rows_before, "rows_after": rows_after}
515
531
  if reduces_rows and not invocation.standing_noop:
@@ -547,6 +563,8 @@ _RUN_FAILED_STATUSES = _RUN_OVER_STATUSES - {_RUN_DONE_STATUS}
547
563
  #: Bounded wait for the run of a task just added: it starts after the add returns.
548
564
  _RUN_ATTEMPTS = 40
549
565
  _RUN_RETRY_S = 0.5
566
+ #: Most seconds the wait for a task's run sleeps in all.
567
+ _RUN_WAIT_S = _RUN_ATTEMPTS * _RUN_RETRY_S
550
568
 
551
569
 
552
570
  def _tasks(service: Any, dataset_id: int, view_id: int) -> list[dict[str, Any]]:
@@ -603,7 +621,7 @@ def wait_for_added_task_run(
603
621
  else the pipeline_error that keeps the write from reading verified.
604
622
  """
605
623
  run: dict[str, Any] = {}
606
- for _ in range(_RUN_ATTEMPTS):
624
+ for delay in poll_delays(_RUN_WAIT_S, _RUN_RETRY_S):
607
625
  added = [
608
626
  task
609
627
  for task in _tasks(service, dataset_id, view_id)
@@ -621,7 +639,7 @@ def wait_for_added_task_run(
621
639
  "task_id": run["task_id"],
622
640
  "transform_status": status,
623
641
  }
624
- time.sleep(_RUN_RETRY_S)
642
+ time.sleep(delay)
625
643
  return run, {
626
644
  "execution_state": UNFINISHED_STATE,
627
645
  "task_id": run.get("task_id"),
@@ -632,6 +650,44 @@ def wait_for_added_task_run(
632
650
  }
633
651
 
634
652
 
653
+ def clean_write_result(job_response: Any) -> dict[str, Any] | None:
654
+ """The ``write_result`` of a run job when it says the write ran and settled cleanly.
655
+
656
+ A newer server adds it to the run job's response. ``None`` (read the task, the
657
+ pipeline and the row count as before) when it is absent, or says anything but a
658
+ finished task on a ``ready`` pipeline with a row count: those reads name the failure.
659
+ """
660
+ result = job_response.get("write_result") if isinstance(job_response, dict) else None
661
+ if (
662
+ isinstance(result, dict)
663
+ and result.get("task_id") is not None
664
+ and result.get("task_run_status") == _RUN_DONE_STATUS
665
+ and result.get("pipeline_state") == "ready"
666
+ and result.get("row_count") is not None
667
+ ):
668
+ return result
669
+ return None
670
+
671
+
672
+ def _settled_write(service: Any, data: Any) -> dict[str, Any] | None:
673
+ """The clean ``write_result`` of the run job a write names (``future_id``), read once."""
674
+ future_id = data.get("future_id") if isinstance(data, dict) else None
675
+ if not isinstance(future_id, int) or _is_staged(data):
676
+ return None
677
+ try:
678
+ job = service.wait_if_job({"future_id": future_id})
679
+ except CliError:
680
+ return None # the reads that follow report the failed or unfinished job
681
+ return clean_write_result(job)
682
+
683
+
684
+ def _forget_reads(service: Any) -> None:
685
+ """Drop the reads made ahead of a write (see :mod:`mammoth_cli.services.read_memo`)."""
686
+ memo = getattr(service, "memo", None)
687
+ if memo is not None:
688
+ memo.clear()
689
+
690
+
635
691
  def _is_staged(data: Any) -> bool:
636
692
  """Whether a write only staged its step in a draft, so no run is to be waited on."""
637
693
  return isinstance(data, dict) and data.get("status") == "staged"
@@ -2059,7 +2115,7 @@ def view_transform_json_extract(invocation: Invocation) -> HandlerResult:
2059
2115
 
2060
2116
 
2061
2117
  def view_transform_limit_rows(invocation: Invocation) -> HandlerResult:
2062
- """Limit the row count. ``n`` is required."""
2118
+ """Limit the row count. ``n`` (or its alias ``limit``) is required."""
2063
2119
  view_id = _view_id(invocation)
2064
2120
  document = invocation.load_input()
2065
2121
  _require_field(document, "n")
@@ -2079,7 +2135,10 @@ def view_transform_rename_columns(invocation: Invocation) -> HandlerResult:
2079
2135
 
2080
2136
 
2081
2137
  def view_transform_sort(invocation: Invocation) -> HandlerResult:
2082
- """Set the view's row order (a display setting, not a task). ``order_by`` is required."""
2138
+ """Set the view's row order (a display setting, not a task). ``order_by`` is required.
2139
+
2140
+ ``sort_by`` is accepted as its alias.
2141
+ """
2083
2142
  view_id = _view_id(invocation)
2084
2143
  document = invocation.load_input()
2085
2144
  _require_field(document, "order_by")
@@ -2342,9 +2401,9 @@ _TASK_DELETE_SYMBOL = "mammoth.api.pipeline.PipelineAPI.delete_task"
2342
2401
  CODE_BATCH_STEP_FAILED = "batch_step_failed"
2343
2402
  CODE_UNKNOWN_COLUMN = "unknown_column"
2344
2403
  _BATCH_COLUMN_HINT = (
2345
- "A batch is built against the view's columns as they are now, so a step cannot use a "
2346
- "column an earlier step of the same batch creates. Run the steps that create columns "
2347
- "first (their own `view transform` command or a batch), then batch the rest."
2404
+ "A batch is built against the view's columns plus the ones the earlier steps of the batch "
2405
+ "add (split, copy-columns, and any new_column of substring, extract-date, increment-date). "
2406
+ "A column in neither is unknown: check its name, or run the step that creates it first."
2348
2407
  )
2349
2408
 
2350
2409
 
@@ -2357,6 +2416,9 @@ class _BatchPlan:
2357
2416
  task_steps: list[tuple[int, str]] = dataclass_field(default_factory=list)
2358
2417
  #: The bound ``sort`` inputs, applied after the tasks have run.
2359
2418
  sorts: list[dict[str, Any]] = dataclass_field(default_factory=list)
2419
+ #: The columns the tasks add; the sort is built after they ran but on metadata that may not
2420
+ #: list them yet.
2421
+ created: list[dict[str, str]] = dataclass_field(default_factory=list)
2360
2422
 
2361
2423
 
2362
2424
  def _batch_steps(document: dict[str, Any] | None) -> list[dict[str, Any]]:
@@ -2386,7 +2448,7 @@ def _batch_steps(document: dict[str, Any] | None) -> list[dict[str, Any]]:
2386
2448
  exit_status=EXIT_USAGE,
2387
2449
  hint=(
2388
2450
  f"Allowed ops: {allowed_values_text(_BATCH_OPS)}. Run any other "
2389
- "transform (pivot, join, math, ...) as its own `view transform` command."
2451
+ "transform (join, math, ...) as its own `view transform` command."
2390
2452
  ),
2391
2453
  details={
2392
2454
  "step": index,
@@ -2395,6 +2457,32 @@ def _batch_steps(document: dict[str, Any] | None) -> list[dict[str, Any]]:
2395
2457
  "did_you_mean": near,
2396
2458
  },
2397
2459
  )
2460
+ if step["op"] == _BATCH_SORT_OP and any(
2461
+ isinstance(later, dict) and later.get("op") in BATCH_LAST_OPS
2462
+ for later in steps[index + 1 :]
2463
+ ):
2464
+ raise CliError(
2465
+ code=CODE_INVALID_ARGUMENT,
2466
+ message=(
2467
+ f"steps[{index}] (sort) comes before a step that replaces the view's columns, "
2468
+ "so its columns would no longer exist when the sort is applied."
2469
+ ),
2470
+ exit_status=EXIT_USAGE,
2471
+ hint="Run the sort after the batch, as its own `view transform sort` command.",
2472
+ details={"step": index, "op": _BATCH_SORT_OP},
2473
+ )
2474
+ if step["op"] in BATCH_LAST_OPS and index != len(steps) - 1:
2475
+ raise CliError(
2476
+ code=CODE_INVALID_ARGUMENT,
2477
+ message=(
2478
+ f"steps[{index}] ({step['op']}) replaces the view's columns, so it must be "
2479
+ "the last step of a batch."
2480
+ ),
2481
+ exit_status=EXIT_USAGE,
2482
+ hint=f"Move steps[{index}] to the end, or run the steps after it as their own "
2483
+ "`view transform` commands.",
2484
+ details={"step": index, "op": step["op"]},
2485
+ )
2398
2486
  return steps
2399
2487
 
2400
2488
 
@@ -2412,17 +2500,34 @@ def _step_error(index: int, op: str, error: CliError) -> CliError:
2412
2500
  )
2413
2501
 
2414
2502
 
2503
+ def _created_columns(task_spec: dict[str, Any]) -> list[dict[str, str]]:
2504
+ """The ``{COLUMN, TYPE, INTERNAL_NAME}`` columns a built task adds, from its ``AS`` outputs.
2505
+
2506
+ ``AS`` is one column (substring, extract-date, increment-date), a list of them (split) or
2507
+ sits on each item of the task's list (copy-columns).
2508
+ """
2509
+ columns: list[dict[str, str]] = []
2510
+ for body in task_spec.values():
2511
+ for item in body if isinstance(body, list) else [body]:
2512
+ made = item.get("AS") if isinstance(item, dict) else None
2513
+ if made is not None:
2514
+ columns.extend(made if isinstance(made, list) else [made])
2515
+ return columns
2516
+
2517
+
2415
2518
  def _build_batch(
2416
2519
  invocation: Invocation, service: Any, view_id: int, dataset_id: int, steps: list[dict[str, Any]]
2417
2520
  ) -> _BatchPlan:
2418
2521
  """Bind and build every step against the view's current columns; send nothing."""
2419
2522
  plan = _BatchPlan()
2523
+ created = plan.created
2420
2524
  for index, step in enumerate(steps):
2421
2525
  op = step["op"]
2422
2526
  command_id = f"view.transform.{op}"
2423
2527
  contract = resolve_command_contract(command_id)
2424
2528
  assert contract is not None
2425
2529
  try:
2530
+ apply_input_aliases(command_id, step["input"])
2426
2531
  for spec in contract.fields:
2427
2532
  if spec.required:
2428
2533
  _require_field(step["input"], spec.name)
@@ -2438,7 +2543,12 @@ def _build_batch(
2438
2543
  method = str((command_by_id(command_id) or {})["sdk_symbol"]).rsplit(".", 1)[-1]
2439
2544
  try:
2440
2545
  built = service.call_view(
2441
- view_id, method, dataset_id=dataset_id, build_only=True, **kwargs
2546
+ view_id,
2547
+ method,
2548
+ dataset_id=dataset_id,
2549
+ build_only=True,
2550
+ added_columns=created,
2551
+ **kwargs,
2442
2552
  )
2443
2553
  except CliError as exc:
2444
2554
  raise _step_error(index, op, exc) from exc
@@ -2446,6 +2556,7 @@ def _build_batch(
2446
2556
  plan.sorts.append(kwargs)
2447
2557
  else:
2448
2558
  plan.specs.append(built["task_spec"])
2559
+ created.extend(_created_columns(built["task_spec"]))
2449
2560
  plan.task_steps.append((index, op))
2450
2561
  return plan
2451
2562
 
@@ -2461,7 +2572,7 @@ def wait_for_added_tasks_run(
2461
2572
  ``count`` may be listed.
2462
2573
  """
2463
2574
  runs: list[dict[str, Any]] = []
2464
- for _ in range(_RUN_ATTEMPTS):
2575
+ for delay in poll_delays(_RUN_WAIT_S, _RUN_RETRY_S):
2465
2576
  added = sorted(
2466
2577
  (t for t in _tasks(service, dataset_id, view_id) if t.get("id") not in task_ids_before),
2467
2578
  key=lambda task: task.get("id") or 0,
@@ -2475,7 +2586,7 @@ def wait_for_added_tasks_run(
2475
2586
  return runs
2476
2587
  if len(runs) >= count and all(status == _RUN_DONE_STATUS for status in statuses):
2477
2588
  return runs
2478
- time.sleep(_RUN_RETRY_S)
2589
+ time.sleep(delay)
2479
2590
  return runs
2480
2591
 
2481
2592
 
@@ -2591,7 +2702,11 @@ def _apply_batch(
2591
2702
  try:
2592
2703
  for kwargs in plan.sorts:
2593
2704
  data["sort"] = service.call_view(
2594
- view_id, _SORT_METHOD, dataset_id=dataset_id, **kwargs
2705
+ view_id,
2706
+ _SORT_METHOD,
2707
+ dataset_id=dataset_id,
2708
+ added_columns=plan.created,
2709
+ **kwargs,
2595
2710
  )["sort"]
2596
2711
  except CliError as exc:
2597
2712
  raise _batch_failure(service, dataset_id, view_id, task_ids_before, plan, exc) from exc
@@ -37,6 +37,7 @@ CODE_INVALID_ARGUMENT = "invalid_argument"
37
37
  CODE_UPLOAD_REFUSED = "upload_refused"
38
38
  CODE_INVALID_ARGUMENTS = "invalid_arguments"
39
39
  CODE_INVALID_CONFIG_VALUE = "invalid_config_value"
40
+ CODE_INVALID_INPUT = "invalid_input"
40
41
  CODE_INVALID_INPUT_DOCUMENT = "invalid_input_document"
41
42
  CODE_INVALID_INPUT_FORMAT = "invalid_input_format"
42
43
  CODE_INVALID_WORKSPACE_ID = "invalid_workspace_id"
@@ -147,6 +148,8 @@ ERROR_SUMMARIES: dict[str, str] = {
147
148
  "invalid_config_value": _S_SETUP,
148
149
  "invalid_credentials": "The sign-in details weren't accepted.",
149
150
  "invalid_input_document": _S_BAD_INPUT,
151
+ "invalid_input": _S_BAD_INPUT,
152
+ "dashboard_not_published": "The dashboard has to be published before viewers can be invited.",
150
153
  "invalid_input_encoding": _S_BAD_INPUT,
151
154
  "invalid_input_field_type": _S_BAD_INPUT,
152
155
  "invalid_input_format": _S_BAD_INPUT,