mammoth-cli 2.2.53__tar.gz → 2.2.54__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 (268) hide show
  1. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/PKG-INFO +2 -2
  2. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/__init__.py +1 -1
  3. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/__main__.py +9 -2
  4. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/app.py +52 -3
  5. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +2 -0
  6. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/auth.py +67 -16
  7. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/client_app.py +34 -0
  8. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/dashboard.py +2 -1
  9. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/project.py +20 -1
  10. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/registry.py +6 -7
  11. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/schema.py +6 -3
  12. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/upgrade.py +1 -0
  13. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/view.py +59 -14
  14. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/view_ops.py +85 -0
  15. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/context/credentials.py +13 -3
  16. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/context/oauth.py +7 -2
  17. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/context/resolver.py +3 -3
  18. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/errors/envelope.py +1 -0
  19. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/confirm.py +7 -1
  20. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/executor.py +1 -1
  21. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/updates.py +37 -0
  22. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/verify.py +2 -0
  23. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/argspec.py +26 -1
  24. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/coerce.py +7 -5
  25. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/command_contract.py +32 -27
  26. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/dispatch.py +13 -0
  27. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/mapping.py +8 -1
  28. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/sdk_service.py +2 -1
  29. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/type_system.py +14 -10
  30. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/pyproject.toml +6 -4
  31. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/view.yaml +8 -8
  32. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/.gitignore +0 -0
  33. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/LICENSE +0 -0
  34. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/README.md +0 -0
  35. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +0 -0
  36. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
  37. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
  38. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
  39. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
  40. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
  41. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
  42. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
  43. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
  44. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
  45. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
  46. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
  47. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
  48. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
  49. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
  50. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
  51. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
  52. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
  53. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
  54. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
  55. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
  56. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
  57. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
  58. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
  59. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-style.md +0 -0
  60. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-template.md +0 -0
  61. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
  62. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
  63. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
  64. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
  65. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
  66. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
  67. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
  68. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
  69. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/link.md +0 -0
  70. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
  71. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
  72. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
  73. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
  74. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
  75. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/resolve.md +0 -0
  76. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
  77. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
  78. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
  79. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
  80. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
  81. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
  82. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/token.md +0 -0
  83. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
  84. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
  85. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
  86. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
  87. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
  88. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
  89. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
  90. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
  91. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
  92. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
  93. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
  94. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
  95. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +0 -0
  96. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
  97. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
  98. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
  99. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/database-import.md +0 -0
  100. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
  101. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
  102. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
  103. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
  104. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
  105. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +0 -0
  106. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
  107. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
  108. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
  109. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
  110. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
  111. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
  112. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
  113. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/__init__.py +0 -0
  114. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/activity.py +0 -0
  115. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/addon.py +0 -0
  116. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/agent.py +0 -0
  117. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/ai.py +0 -0
  118. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/annotation.py +0 -0
  119. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/automation.py +0 -0
  120. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/batch.py +0 -0
  121. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/billing.py +0 -0
  122. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/browse.py +0 -0
  123. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/calc.py +0 -0
  124. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/capability.py +0 -0
  125. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/completion.py +0 -0
  126. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/config.py +0 -0
  127. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/connector.py +0 -0
  128. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/context.py +0 -0
  129. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/data_app.py +0 -0
  130. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/dataset.py +0 -0
  131. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/doctor.py +0 -0
  132. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/external_key.py +0 -0
  133. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/file.py +0 -0
  134. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/folder.py +0 -0
  135. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/job.py +0 -0
  136. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/link.py +0 -0
  137. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/notification.py +0 -0
  138. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/parameter.py +0 -0
  139. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/report.py +0 -0
  140. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/resolve.py +0 -0
  141. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/schedule.py +0 -0
  142. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/skill.py +0 -0
  143. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/snippet.py +0 -0
  144. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/support.py +0 -0
  145. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/template.py +0 -0
  146. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/trash.py +0 -0
  147. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/user.py +0 -0
  148. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/view_profile.py +0 -0
  149. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/webhook.py +0 -0
  150. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/workflow.py +0 -0
  151. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/commands/workspace.py +0 -0
  152. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/context/__init__.py +0 -0
  153. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/context/endpoint.py +0 -0
  154. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/context/profiles.py +0 -0
  155. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/contracts/__init__.py +0 -0
  156. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/contracts/auth.py +0 -0
  157. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/embed.py +0 -0
  158. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/errors/__init__.py +0 -0
  159. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/manifest/__init__.py +0 -0
  160. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/manifest/loader.py +0 -0
  161. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/messages/__init__.py +0 -0
  162. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/output/__init__.py +0 -0
  163. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/output/envelope.py +0 -0
  164. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/output/normalize.py +0 -0
  165. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/output/policy.py +0 -0
  166. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/output/progress.py +0 -0
  167. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/output/render.py +0 -0
  168. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/py.typed +0 -0
  169. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/__init__.py +0 -0
  170. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/dataset_health.py +0 -0
  171. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/dryrun.py +0 -0
  172. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/dryrun_targets.py +0 -0
  173. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/embedded.py +0 -0
  174. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/input_loader.py +0 -0
  175. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/intent_only.py +0 -0
  176. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/invocation.py +0 -0
  177. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/locked_files.py +0 -0
  178. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/new_data.py +0 -0
  179. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/options.py +0 -0
  180. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/parents.py +0 -0
  181. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/runlog.py +0 -0
  182. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/session.py +0 -0
  183. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/state.py +0 -0
  184. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/strict.py +0 -0
  185. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/runtime/validate.py +0 -0
  186. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/__init__.py +0 -0
  187. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/append_blank_columns.py +0 -0
  188. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/board_values.py +0 -0
  189. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/conditional_format.py +0 -0
  190. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/conditions.py +0 -0
  191. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/dashboard_filters.py +0 -0
  192. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/dashboard_pages.py +0 -0
  193. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/dashboard_review.py +0 -0
  194. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/data_profile.py +0 -0
  195. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/data_quality.py +0 -0
  196. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/factory.py +0 -0
  197. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/input_fields.py +0 -0
  198. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/job_outcome.py +0 -0
  199. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/listing.py +0 -0
  200. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/local_time.py +0 -0
  201. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/openapi_types.py +0 -0
  202. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/positionals.py +0 -0
  203. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/protocol.py +0 -0
  204. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/read_queries.py +0 -0
  205. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/sql_check.py +0 -0
  206. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/stored_stats.py +0 -0
  207. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/testing.py +0 -0
  208. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/text_dates.py +0 -0
  209. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/view_analysis.py +0 -0
  210. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/view_variants.py +0 -0
  211. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/services/write_impact.py +0 -0
  212. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/skills/__init__.py +0 -0
  213. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/skills/installer.py +0 -0
  214. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/skills/steering.py +0 -0
  215. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/mammoth_cli/testing.py +0 -0
  216. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/activity.yaml +0 -0
  217. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/addon.yaml +0 -0
  218. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/agent.yaml +0 -0
  219. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/ai.yaml +0 -0
  220. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/annotation.yaml +0 -0
  221. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/auth.yaml +0 -0
  222. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/automation.yaml +0 -0
  223. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/batch.yaml +0 -0
  224. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/billing.yaml +0 -0
  225. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/browse.yaml +0 -0
  226. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/calc.yaml +0 -0
  227. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/capability.yaml +0 -0
  228. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/client-app.yaml +0 -0
  229. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/completion.yaml +0 -0
  230. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/config.yaml +0 -0
  231. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/connector.yaml +0 -0
  232. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/context.yaml +0 -0
  233. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/dashboard.yaml +0 -0
  234. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/data-app.yaml +0 -0
  235. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/dataset.yaml +0 -0
  236. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/doctor.yaml +0 -0
  237. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/external-key.yaml +0 -0
  238. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/file.yaml +0 -0
  239. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/folder.yaml +0 -0
  240. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/job.yaml +0 -0
  241. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/link.yaml +0 -0
  242. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/log.yaml +0 -0
  243. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/notification.yaml +0 -0
  244. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/parameter.yaml +0 -0
  245. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/project.yaml +0 -0
  246. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/report.yaml +0 -0
  247. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/resolve.yaml +0 -0
  248. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/schedule.yaml +0 -0
  249. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/schema.yaml +0 -0
  250. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/skill.yaml +0 -0
  251. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/snippet.yaml +0 -0
  252. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/support.yaml +0 -0
  253. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/template.yaml +0 -0
  254. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/token.yaml +0 -0
  255. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/trash.yaml +0 -0
  256. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/upgrade.yaml +0 -0
  257. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/user.yaml +0 -0
  258. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/version.yaml +0 -0
  259. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/webhook.yaml +0 -0
  260. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/workflow.yaml +0 -0
  261. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/commands/workspace.yaml +0 -0
  262. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/edits-target.source.yaml +0 -0
  263. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/openapi-operations.yaml +0 -0
  264. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/schema-v1.json +0 -0
  265. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/sdk-catalog.source.yaml +0 -0
  266. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/manifests/sdk-methods.yaml +0 -0
  267. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/spec/openapi/metadata.json +0 -0
  268. {mammoth_cli-2.2.53 → mammoth_cli-2.2.54}/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.53
3
+ Version: 2.2.54
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.27
20
+ Requires-Dist: mammoth-io<0.9,>=0.8.28
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.53"
9
+ __version__ = "2.2.54"
10
10
 
11
11
  # The versioned machine output envelope contract.
12
12
  SCHEMA_VERSION = 1
@@ -8,10 +8,9 @@ launch symbol that does not change when the application wiring moves.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ import sys
11
12
  from typing import Any
12
13
 
13
- from mammoth_cli.app import app
14
-
15
14
 
16
15
  def main() -> Any:
17
16
  """Run the Mammoth CLI application.
@@ -20,6 +19,14 @@ def main() -> Any:
20
19
  The value returned by the Typer application, which the runtime uses as
21
20
  the process exit code.
22
21
  """
22
+ if sys.argv[1:] == ["--version"]:
23
+ # The answer needs none of the command tree; skip building it.
24
+ from mammoth_cli import __version__
25
+
26
+ sys.stdout.write(f"{__version__}\n")
27
+ return 0
28
+ from mammoth_cli.app import app
29
+
23
30
  return app()
24
31
 
25
32
 
@@ -19,6 +19,7 @@ import re
19
19
  import sys
20
20
  from collections.abc import Callable, Sequence
21
21
  from dataclasses import replace
22
+ from difflib import get_close_matches
22
23
  from functools import cache
23
24
  from typing import Annotated, Any
24
25
 
@@ -383,9 +384,33 @@ class _EnvelopeGroup(TyperGroup):
383
384
  def get_command(self, ctx: Any, cmd_name: str) -> Any:
384
385
  eager: dict[str, Any] = self.__dict__.setdefault("_eager_commands", {})
385
386
  if cmd_name not in eager and cmd_name in _LAZY_GROUP_NAMES:
387
+ if self.__dict__.get("_listing_help"):
388
+ return _group_stub(cmd_name)
386
389
  eager[cmd_name] = _load_top_level_group(cmd_name)
387
390
  return eager.get(cmd_name)
388
391
 
392
+ def resolve_command(self, ctx: Any, args: list[str]) -> Any:
393
+ # Typer's override suggests close names from ``self.commands``, which
394
+ # builds every group; the names alone are all a suggestion needs.
395
+ try:
396
+ return self._click_resolve_command(ctx, args)
397
+ except _typer_click_exceptions.UsageError as error:
398
+ if self.suggest_commands and args:
399
+ matches = get_close_matches(args[0], self.list_commands(ctx))
400
+ if matches:
401
+ suggestions = ", ".join(f"{m!r}" for m in matches)
402
+ error.message = f"{error.message.rstrip('.')}. Did you mean {suggestions}?"
403
+ raise
404
+
405
+ def format_help(self, ctx: Any, formatter: Any) -> None:
406
+ # Root ``--help`` only needs each group's name, panel and one-line
407
+ # description; building all ~550 commands to print them cost seconds.
408
+ self.__dict__["_listing_help"] = True
409
+ try:
410
+ super().format_help(ctx, formatter)
411
+ finally:
412
+ self.__dict__["_listing_help"] = False
413
+
389
414
  def main(self, *args: Any, **kwargs: Any) -> Any:
390
415
  if not kwargs.get("standalone_mode", True):
391
416
  return super().main(*args, **kwargs)
@@ -447,11 +472,16 @@ class _EnvelopeGroup(TyperGroup):
447
472
  )
448
473
  elif isinstance(error, _typer_click_exceptions.NoSuchOption):
449
474
  option = getattr(error, "option_name", None) or "unknown"
475
+ close = getattr(error, "possibilities", None) or []
450
476
  report = CliError(
451
477
  code="unknown_option",
452
478
  message=f"Unknown option '{option}'.",
453
479
  exit_status=EXIT_USAGE,
454
- hint="Check the command schema with 'mammoth schema get'.",
480
+ hint=(
481
+ f"Did you mean {' or '.join(sorted(close))}?"
482
+ if close
483
+ else "Check the command schema with 'mammoth schema get'."
484
+ ),
455
485
  details={"option": option},
456
486
  )
457
487
  elif isinstance(error, _typer_click_exceptions.BadParameter):
@@ -1032,6 +1062,15 @@ def _command_tree() -> tuple[dict[tuple[str, ...], str], frozenset[tuple[str, ..
1032
1062
  return path_to_command, frozenset(prefixes & path_to_command.keys())
1033
1063
 
1034
1064
 
1065
+ def _leaf_context_settings(command_id: str) -> dict[str, bool]:
1066
+ """Click settings for one command: a bespoke command declares every option it
1067
+ accepts, so Click itself rejects an unknown one; a generic leaf collects its
1068
+ trailing tokens and validates them in :func:`validate_extra_args`."""
1069
+ if command_id in BESPOKE:
1070
+ return {}
1071
+ return {"allow_extra_args": True, "ignore_unknown_options": True}
1072
+
1073
+
1035
1074
  def _group_typer(tokens: tuple[str, ...], command_id: str | None) -> typer.Typer:
1036
1075
  if command_id is not None:
1037
1076
  # This node is both a group and an invocable command.
@@ -1088,7 +1127,7 @@ def _populate(base: tuple[str, ...], group: typer.Typer) -> None:
1088
1127
  name=tokens[-1],
1089
1128
  help=_command_help(command_id, record),
1090
1129
  rich_help_panel=_ROOT_HELP_PANELS.get(tokens[0]) if len(tokens) == 1 else None,
1091
- context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
1130
+ context_settings=_leaf_context_settings(command_id),
1092
1131
  )(callback)
1093
1132
 
1094
1133
 
@@ -1121,6 +1160,16 @@ def _load_top_level_group(name: str) -> Any:
1121
1160
  return typer.main.get_group_from_info(info, **_LAZY_SETTINGS)
1122
1161
 
1123
1162
 
1163
+ def _group_stub(name: str) -> Any:
1164
+ """A placeholder group carrying only what the root ``--help`` listing prints."""
1165
+ return TyperGroup(
1166
+ name=name,
1167
+ help=_GROUP_DESCRIPTIONS.get(name, f"Commands for {name}."),
1168
+ rich_help_panel=_ROOT_HELP_PANELS.get(name),
1169
+ rich_markup_mode=_LAZY_SETTINGS["rich_markup_mode"],
1170
+ )
1171
+
1172
+
1124
1173
  def build_app() -> typer.Typer:
1125
1174
  """Construct the Typer command tree from the command manifests.
1126
1175
 
@@ -1160,7 +1209,7 @@ def build_app() -> typer.Typer:
1160
1209
  name=name,
1161
1210
  help=_command_help(command_id, command_by_id(command_id)),
1162
1211
  rich_help_panel=_ROOT_HELP_PANELS.get(name),
1163
- context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
1212
+ context_settings=_leaf_context_settings(command_id),
1164
1213
  )(BESPOKE.get(command_id) or _build_leaf(command_id))
1165
1214
  _LAZY_GROUP_NAMES[:] = lazy
1166
1215
  _LAZY_SETTINGS.update(
@@ -312,6 +312,8 @@ Result: `ViewDerivativeCreateResult`; mutation `benign_mutation`, confirmation `
312
312
 
313
313
  Status on release: ran once on CLI 2.0.24 — payload probe 2026-09-19: exit 0 on release with CLI 2.0.24. Created derivative id=6 on view 123 (project 52, dataset 104) with the column INTERNAL name as ARGUMENT; metric_status DONE on read-back. The same call with the display name reproduces the HTTP 500…
314
314
 
315
+ A METRIC shows as an explore-panel card via `display_properties`; the CLI defaults it to the metric card, and the result's `card` says whether one exists.
316
+
315
317
  ### `view.derivative.data`
316
318
 
317
319
  Run: `mammoth view derivative data`. Exact input fields: `mammoth schema get view.derivative.data`.
@@ -23,7 +23,7 @@ import typer
23
23
  from pydantic import ValidationError
24
24
 
25
25
  from mammoth_cli.context import credentials, oauth, profiles, resolver
26
- from mammoth_cli.context.endpoint import resolve_base_url
26
+ from mammoth_cli.context.endpoint import DEFAULT_SERVER_PREFIX, resolve_base_url
27
27
  from mammoth_cli.context.resolver import ResolvedAuth, resolve_auth
28
28
  from mammoth_cli.contracts.auth import LoginRequest
29
29
  from mammoth_cli.errors.envelope import (
@@ -143,6 +143,14 @@ def _masked_receipt(value: str) -> str:
143
143
  return f"{len(value)} characters, ending in …{value[-4:]}"
144
144
 
145
145
 
146
+ def _ask(label: str, **options: Any) -> str:
147
+ """Prompt once; a closed stdin (Ctrl-D, EOF) is a usage error, not a crash."""
148
+ try:
149
+ return str(typer.prompt(label, **options))
150
+ except typer.Abort:
151
+ raise _no_choice(label) from None
152
+
153
+
146
154
  def _prompt_secret(label: str) -> str:
147
155
  """Prompt for one secret with hidden input, then confirm what was captured.
148
156
 
@@ -152,7 +160,7 @@ def _prompt_secret(label: str) -> str:
152
160
  entry is rejected here, and a masked receipt (length and last four
153
161
  characters, never the value) is printed to stderr as feedback.
154
162
  """
155
- value = typer.prompt(label, hide_input=True).strip()
163
+ value = _ask(label, hide_input=True).strip()
156
164
  if not value:
157
165
  raise CliError(
158
166
  code="login_input_required",
@@ -298,22 +306,65 @@ def _choose_method(
298
306
  return method
299
307
  if invocation.input_file is not None or blockers:
300
308
  return "token"
301
- if not oauth.has_client_id(server_prefix):
302
- return "token"
309
+ available = oauth.has_client_id(server_prefix)
310
+ prefix = server_prefix if server_prefix is not None else DEFAULT_SERVER_PREFIX
311
+ browser_note = "recommended" if available else f"(not yet available on {prefix})"
312
+ device_note = "no browser on this machine" if available else browser_note
303
313
  typer.echo("How do you want to sign in?", err=True)
304
- typer.echo(" 1) Browser (OAuth) recommended", err=True)
305
- typer.echo(" 2) Device code no browser on this machine", err=True)
314
+ typer.echo(f" 1) Browser (OAuth) {browser_note}", err=True)
315
+ typer.echo(f" 2) Device code {device_note}", err=True)
306
316
  typer.echo(" 3) Paste an API token for CI and scripts", err=True)
307
- choice = typer.prompt("Choose", default="1", show_default=False).strip()
308
- methods = {"1": "oauth", "2": "device", "3": "token"}
309
- if choice not in methods:
310
- raise CliError(
311
- code="invalid_login_method",
312
- message=f"'{choice}' is not one of the choices.",
313
- exit_status=EXIT_USAGE,
314
- hint="Enter 1 for the browser, 2 for a device code or 3 to paste an API token.",
315
- )
316
- return methods[choice]
317
+ default = "1" if available else "3"
318
+ if sys.stdin.isatty():
319
+ return _choose_by_keypress(default)
320
+ choice = _ask("Choose", default=default, show_default=False).strip()
321
+ if choice not in _METHOD_KEYS:
322
+ raise _bad_choice(choice)
323
+ return _METHOD_KEYS[choice]
324
+
325
+
326
+ _METHOD_KEYS = {"1": "oauth", "2": "device", "3": "token"}
327
+ _METHOD_LABELS = {"1": "Browser (OAuth)", "2": "Device code", "3": "API token"}
328
+
329
+
330
+ def _bad_choice(choice: str) -> CliError:
331
+ return CliError(
332
+ code="invalid_login_method",
333
+ message=f"'{choice}' is not one of the choices.",
334
+ exit_status=EXIT_USAGE,
335
+ hint="Enter 1 for the browser, 2 for a device code or 3 to paste an API token.",
336
+ )
337
+
338
+
339
+ def _choose_by_keypress(default: str) -> str:
340
+ """Read one key on a terminal: 1, 2 or 3 selects at once, Enter takes ``default``.
341
+
342
+ Any other key asks once more, then errors; Ctrl-C and Ctrl-D are a usage error.
343
+ """
344
+ key = ""
345
+ for _attempt in range(2):
346
+ typer.echo("Choose: ", nl=False, err=True)
347
+ try:
348
+ key = typer.getchar()
349
+ except (KeyboardInterrupt, EOFError):
350
+ typer.echo("", err=True)
351
+ raise _no_choice() from None
352
+ if key in ("\r", "\n"):
353
+ key = default
354
+ if key in _METHOD_KEYS:
355
+ typer.echo(f"{key} {_METHOD_LABELS[key]}", err=True)
356
+ return _METHOD_KEYS[key]
357
+ typer.echo("", err=True)
358
+ raise _bad_choice(key)
359
+
360
+
361
+ def _no_choice(label: str = "choice") -> CliError:
362
+ return CliError(
363
+ code="login_input_required",
364
+ message=f"No {label} was entered.",
365
+ exit_status=EXIT_USAGE,
366
+ hint="Pass --method oauth|device|token, or --input FILE for a non-interactive login.",
367
+ )
317
368
 
318
369
 
319
370
  def _iso(epoch: int) -> str:
@@ -22,10 +22,13 @@ from typing import Any
22
22
 
23
23
  from mammoth.exceptions import MammothModelDriftWarning
24
24
 
25
+ from mammoth_cli.context import credentials, oauth, profiles
26
+ from mammoth_cli.context.endpoint import resolve_base_url
25
27
  from mammoth_cli.errors.envelope import (
26
28
  CODE_MISSING_ARGUMENT,
27
29
  CODE_MISSING_FIELD,
28
30
  CODE_SDK_SYMBOL_UNRESOLVED,
31
+ EXIT_API,
29
32
  EXIT_USAGE,
30
33
  CliError,
31
34
  )
@@ -254,6 +257,37 @@ def client_app_delete(invocation: Invocation) -> HandlerResult:
254
257
  enforce_confirmation(
255
258
  invocation, policy=POLICY_PROMPT_OR_YES, action=f"delete client app {client_key}"
256
259
  )
260
+ own = _own_oauth_session(invocation, client_key)
261
+ if own is not None:
262
+ return _revoke_own_grant(invocation, own)
257
263
  with open_service(invocation) as (service, auth):
258
264
  data = service.call(_symbol(invocation), client_key=client_key)
259
265
  return data, _meta(invocation, auth.workspace_id, resolved_project(invocation))
266
+
267
+
268
+ def _own_oauth_session(invocation: Invocation, client_key: str) -> credentials.OAuthSession | None:
269
+ """The caller's browser-login session when ``client_key`` is the client it signed in as."""
270
+ credential = credentials.load_credential(invocation.profile or profiles.get_selected())
271
+ session = credential.oauth if credential is not None else None
272
+ return session if session is not None and session.client_id == client_key else None
273
+
274
+
275
+ def _revoke_own_grant(invocation: Invocation, session: credentials.OAuthSession) -> HandlerResult:
276
+ """Disconnect the caller's own grant: the workspace client-app route does not know it."""
277
+ profile_name = invocation.profile or profiles.get_selected()
278
+ record = profiles.get_profile(profile_name)
279
+ if record is None:
280
+ raise CliError(
281
+ code=CODE_MISSING_ARGUMENT,
282
+ message=f"Profile {profile_name} is not configured.",
283
+ exit_status=EXIT_USAGE,
284
+ )
285
+ base_url = resolve_base_url(record.server_prefix)
286
+ if not oauth.is_fresh(session):
287
+ session = oauth.refresh_session(profile_name, base_url)
288
+ problem = oauth.revoke_grant(base_url, session)
289
+ if problem is not None:
290
+ raise CliError(code="oauth_grant_revoke_failed", message=problem, exit_status=EXIT_API)
291
+ return {"revoked": "own OAuth grant", "grant_id": session.grant_id}, _meta(
292
+ invocation, record.workspace_id, resolved_project(invocation)
293
+ )
@@ -14,7 +14,6 @@ from collections.abc import Callable
14
14
  from pathlib import Path
15
15
  from typing import Any, Literal, cast
16
16
 
17
- from mammoth.models.dashboards import AddPagesSpec
18
17
  from pydantic import ValidationError
19
18
 
20
19
  from mammoth_cli.commands.view import _FIND_DATASET_SYMBOL, view_profiles
@@ -733,6 +732,8 @@ def generated_dashboard(invocation: Invocation) -> HandlerResult:
733
732
  # AddPages has a release-level minItems constraint that must be enforced
734
733
  # before confirmation or transport.
735
734
  if invocation.command_id == "dashboard.pages.add" and "body" in kwargs:
735
+ from mammoth.models.dashboards import AddPagesSpec
736
+
736
737
  try:
737
738
  kwargs["body"] = AddPagesSpec.model_validate(kwargs["body"]).model_dump(
738
739
  mode="json", exclude_none=True
@@ -134,11 +134,25 @@ def project_list(invocation: Invocation) -> HandlerResult:
134
134
  return data, _meta(invocation, auth.workspace_id, resolved_project(invocation))
135
135
 
136
136
 
137
+ #: What ``project get`` reads: the project's own record, not what it holds.
138
+ _PROJECT_GET_COVERS = (
139
+ "the project's id and name only; its datasets and views are not counted here "
140
+ "(mammoth dataset list --project {project_id})"
141
+ )
142
+ #: What ``project resource-status`` reads: only work happening right now.
143
+ _RESOURCE_STATUS_COVERS = (
144
+ "resources with a task in flight right now; empty in_flight does not mean the project has "
145
+ "no resources (mammoth dataset list --project {project_id})"
146
+ )
147
+
148
+
137
149
  def project_get(invocation: Invocation) -> HandlerResult:
138
150
  """Get one project by id (positional or active project)."""
139
151
  project_id = _project_id(invocation)
140
152
  with open_service(invocation) as (service, auth):
141
153
  data = service.call(_symbol(invocation), project=project_id)
154
+ if isinstance(data, dict):
155
+ data = {**data, "covers": _PROJECT_GET_COVERS.format(project_id=project_id)}
142
156
  return data, _meta(invocation, auth.workspace_id, project_id)
143
157
 
144
158
 
@@ -185,10 +199,15 @@ def project_memory_remove(invocation: Invocation) -> HandlerResult:
185
199
 
186
200
 
187
201
  def project_resource_status(invocation: Invocation) -> HandlerResult:
188
- """Report the status of a project's resources."""
202
+ """Report the project's in-flight resource tasks, named as such."""
189
203
  project_id = _project_id(invocation)
190
204
  with open_service(invocation) as (service, auth):
191
205
  data = service.call(_symbol(invocation), project_id=project_id)
206
+ in_flight = data.get("status") if isinstance(data, dict) else None
207
+ data = {
208
+ "in_flight": in_flight if in_flight is not None else {},
209
+ "covers": _RESOURCE_STATUS_COVERS.format(project_id=project_id),
210
+ }
192
211
  return data, _meta(invocation, auth.workspace_id, project_id)
193
212
 
194
213
 
@@ -898,12 +898,11 @@ HANDLERS: dict[str, Handler] = {
898
898
  }
899
899
 
900
900
  # Dashboard operations generated from the reviewed OpenAPI inventory share one
901
- # manifest-driven handler. Existing authored handlers remain authoritative.
902
- from mammoth.api.dashboard_generated import GENERATED_METHODS # noqa: E402
903
-
904
- _GENERATED_DASHBOARD_SYMBOLS = {
905
- f"mammoth.api.dashboards.DashboardsAPI.{method}" for method in GENERATED_METHODS
906
- }
901
+ # manifest-driven handler. Existing authored handlers remain authoritative, so
902
+ # ``setdefault`` only fills the dashboard commands that have none. Matching on
903
+ # the SDK symbol prefix (rather than importing the generated method list) keeps
904
+ # the generated dashboard models off the startup import path.
905
+ _DASHBOARD_SDK_PREFIX = "mammoth.api.dashboards.DashboardsAPI."
907
906
  for _record in load_commands():
908
- if _record.get("sdk_symbol") in _GENERATED_DASHBOARD_SYMBOLS:
907
+ if str(_record.get("sdk_symbol", "")).startswith(_DASHBOARD_SDK_PREFIX):
909
908
  HANDLERS.setdefault(str(_record["command_id"]), dashboard_cmd.generated_dashboard)
@@ -337,8 +337,8 @@ _COMMAND_DISCOVERY_PURPOSES = {
337
337
  "window rank row number running total cumulative sum moving average lag lead "
338
338
  "previous next row partition"
339
339
  ),
340
- # The web app's column Explore cards: what is trending, how a column is
341
- # spread, its top values, a count over time.
340
+ # Reads a column's value distribution: what is trending, how a column is
341
+ # spread, its top values, a count over time. It opens no card in the UI.
342
342
  "view.data.explore": (
343
343
  "explore trend trends trending over time per day week month quarter year by date "
344
344
  "distribution spread histogram top most common frequent values breakdown share "
@@ -572,7 +572,10 @@ _COMMAND_DISCOVERY_PURPOSES = {
572
572
  "condition checkpoint value changes"
573
573
  ),
574
574
  "view.data-check.create": "data quality check rule validate rows match condition flag",
575
- "view.derivative.create": "metric kpi number single value to check track daily monitor",
575
+ "view.derivative.create": (
576
+ "metric kpi number single value to check track daily monitor add a metric "
577
+ "sum of column explore panel card metric card"
578
+ ),
576
579
  "view.draft.auto-run": (
577
580
  "stop prevent re-running rerun automatically when source changes auto run enable disable"
578
581
  ),
@@ -361,6 +361,7 @@ def perform(invocation: Invocation, *, check: bool, target_version: str | None)
361
361
  invocation,
362
362
  policy=POLICY_PROMPT_OR_YES,
363
363
  action=f"upgrade {PACKAGE_NAME} to {action_target} using {manager}",
364
+ default=True,
364
365
  )
365
366
  result = run_upgrade(command)
366
367
  if result.returncode != 0:
@@ -29,9 +29,6 @@ from datetime import UTC, datetime
29
29
  from decimal import Decimal, InvalidOperation
30
30
  from typing import Any
31
31
 
32
- from mammoth.models.exports import ExportStatus
33
- from mammoth.view import ViewExport
34
-
35
32
  from mammoth_cli.context import profiles
36
33
  from mammoth_cli.errors.envelope import (
37
34
  CODE_INVALID_ARGUMENT,
@@ -86,6 +83,7 @@ _DATASET_GET_SYMBOL = "mammoth.api.datasets.DatasetsAPI.get"
86
83
  # data-read commands can take the view id alone and fill the dataset for the
87
84
  # caller. See :data:`mammoth_cli.services.positionals.POSITIONAL_OVERRIDES`.
88
85
  _FIND_DATASET_SYMBOL = "mammoth.api.pipeline.PipelineAPI.find_dataset_for_dataview"
86
+ _EXPLORE_PANEL_GET_SYMBOL = "mammoth.api.dataviews.DataviewsAPI.explore_panel"
89
87
  _WAIT_FOR_PIPELINE_SYMBOL = "mammoth.api.pipeline.PipelineAPI.wait_for_pipeline"
90
88
  _DATASET_ID_FIELD = "dataset_id"
91
89
  _DRAFT_OPERATIONS = frozenset({"enter", "exit", "submit", "discard"})
@@ -368,6 +366,9 @@ def _read_meta(
368
366
  project_id=project_id,
369
367
  fields="__min",
370
368
  )
369
+ # The read just proved this dataset holds the view; keep the pair so the
370
+ # next command on it (a transform) needs no ``dataset_id`` of its own.
371
+ parents.remember(_profile_name(invocation), workspace_id, {view_id: dataset_id})
371
372
  dataset = service.call(
372
373
  _DATASET_GET_SYMBOL, dataset_id=dataset_id, project_id=project_id, fields="id,name"
373
374
  )
@@ -1115,6 +1116,15 @@ def view_update(invocation: Invocation) -> HandlerResult:
1115
1116
  return data, _meta(invocation, auth.workspace_id, project_id)
1116
1117
 
1117
1118
 
1119
+ def _read_explore_panel(
1120
+ service: Any, symbol: str, dataset_id: int, dataview_id: int, project_id: int
1121
+ ) -> Any:
1122
+ """The Explore panel the caller saved on a view (``{}`` when none is saved)."""
1123
+ return service.call(
1124
+ symbol, dataset_id=dataset_id, dataview_id=dataview_id, project_id=project_id
1125
+ )
1126
+
1127
+
1118
1128
  def view_explore_panel_get(invocation: Invocation) -> HandlerResult:
1119
1129
  """Read the Explore panel the caller saved on a view (empty when none is saved)."""
1120
1130
  project_id = require_project(invocation)
@@ -1122,17 +1132,14 @@ def view_explore_panel_get(invocation: Invocation) -> HandlerResult:
1122
1132
  document = invocation.load_input() or {}
1123
1133
  with open_service(invocation) as (service, auth):
1124
1134
  dataset_id = _resolve_dataset_id(service, invocation, dataview_id, document)
1125
- data = service.call(
1126
- _symbol(invocation),
1127
- dataset_id=dataset_id,
1128
- dataview_id=dataview_id,
1129
- project_id=project_id,
1135
+ data = _read_explore_panel(
1136
+ service, _symbol(invocation), dataset_id, dataview_id, project_id
1130
1137
  )
1131
1138
  return data, _meta(invocation, auth.workspace_id, project_id)
1132
1139
 
1133
1140
 
1134
1141
  def view_explore_panel_set(invocation: Invocation) -> HandlerResult:
1135
- """Replace the caller's saved Explore panel with the ``panel`` input field."""
1142
+ """Replace the caller's saved Explore panel; the result carries the panel read back after."""
1136
1143
  project_id = require_project(invocation)
1137
1144
  dataview_id = _require_int_positional_at(invocation, 0, "view id")
1138
1145
  document = invocation.load_input() or {}
@@ -1146,7 +1153,10 @@ def view_explore_panel_set(invocation: Invocation) -> HandlerResult:
1146
1153
  panel=panel,
1147
1154
  project_id=project_id,
1148
1155
  )
1149
- return data, _meta(invocation, auth.workspace_id, project_id)
1156
+ saved = _read_explore_panel(
1157
+ service, _EXPLORE_PANEL_GET_SYMBOL, dataset_id, dataview_id, project_id
1158
+ )
1159
+ return {**data, "panel": saved}, _meta(invocation, auth.workspace_id, project_id)
1150
1160
 
1151
1161
 
1152
1162
  def _untyped_patch_error(invocation: Invocation) -> CliError:
@@ -2204,7 +2214,7 @@ def _explore_range(
2204
2214
 
2205
2215
 
2206
2216
  def view_data_explore(invocation: Invocation) -> HandlerResult:
2207
- """Explore one column like the web app's Explore card (read-only): DATE counts per ``level`` bucket (AUTO, SECOND to MILLENNIUM), NUMERIC per power-of-10 ``level``, TEXT top values (``limit`` 20), each with ``count`` and ``percentage``; ``metric`` (a column plus SUM/AVG/MIN/MAX/STDDEV/COUNT/DISTINCT_COUNT) adds a per-bucket value, ``percentage_of`` "metric" shares by it, ``sort`` count_/value_/metric_ + asc/desc, ``condition`` filters first (include, exclude, blanks, range, contains; an exclude drops blank rows the card keeps, so or it with IS_EMPTY; drill down = finer ``level`` + ``condition`` on the bucket), ``limit``/``offset`` page, ``range`` true adds the exact earliest and latest value, ``cumulative`` a running total; ``-o csv`` saves the card's values; to put it on a dashboard say it in words to 'dashboard chat edit'.
2217
+ """Read one column's value distribution (read-only; opens and changes no card in the UI, that is ``view explore-panel set``): DATE counts per ``level`` bucket (AUTO, SECOND to MILLENNIUM), NUMERIC per power-of-10 ``level``, TEXT top values (``limit`` 20), each with ``count`` and ``percentage``; ``metric`` (a column plus SUM/AVG/MIN/MAX/STDDEV/COUNT/DISTINCT_COUNT) adds a per-bucket value, ``percentage_of`` "metric" shares by it, ``sort`` count_/value_/metric_ + asc/desc, ``condition`` filters first (include, exclude, blanks, range, contains; an exclude drops blank rows the card keeps, so or it with IS_EMPTY; drill down = finer ``level`` + ``condition`` on the bucket), ``limit``/``offset`` page, ``range`` true adds the exact earliest and latest value, ``cumulative`` a running total; ``-o csv`` saves the values; to put it on a dashboard say it in words to 'dashboard chat edit'.
2208
2218
 
2209
2219
  Read-only: computes and returns the result without adding a task to the
2210
2220
  view's pipeline or otherwise changing it. Buckets by the column's type --
@@ -2759,12 +2769,40 @@ def view_data_check_update(invocation: Invocation) -> HandlerResult:
2759
2769
  # ---------------------------------------------------------------------------
2760
2770
 
2761
2771
 
2772
+ _METRIC_CARD_BASE: dict[str, Any] = {
2773
+ "FORMAT_INFO": {"RESULT": {}},
2774
+ "IS_FORMAT_INFO_DIRTY": False,
2775
+ "LOCKED": False,
2776
+ "type": "metric",
2777
+ }
2778
+
2779
+
2780
+ def _with_metric_card(body: Any) -> Any:
2781
+ """Default a METRIC derivative's ``display_properties`` to its explore-panel card.
2782
+
2783
+ Without it the API stores ``display_properties: null``, which the explore
2784
+ panel reads as "no card". An explicit value (including ``{}``) is kept.
2785
+ """
2786
+ param = body.get("param") if isinstance(body, dict) else None
2787
+ metric = param.get("METRIC") if isinstance(param, dict) else None
2788
+ if not isinstance(metric, dict) or body.get("display_properties") is not None:
2789
+ return body
2790
+ return {
2791
+ **body,
2792
+ "display_properties": {**_METRIC_CARD_BASE, "info": {"title": metric.get("AS")}},
2793
+ }
2794
+
2795
+
2762
2796
  def view_derivative_create(invocation: Invocation) -> HandlerResult:
2763
- """Create a derivative on a dataview. ``body`` is required."""
2797
+ """Create a derivative on a dataview. ``body`` is required.
2798
+
2799
+ A METRIC with no ``display_properties`` gets the metric card config so it
2800
+ shows in the explore panel; the result's ``card`` says whether a card exists.
2801
+ """
2764
2802
  project_id = require_project(invocation)
2765
2803
  dataview_id = _require_int_positional_at(invocation, 0, "view id")
2766
2804
  document = invocation.load_input()
2767
- body = _require_field(document, "body")
2805
+ body = _with_metric_card(_require_field(document, "body"))
2768
2806
  assert document is not None
2769
2807
  with open_service(invocation) as (service, auth):
2770
2808
  dataset_id = _resolve_dataset_id(service, invocation, dataview_id, document)
@@ -2775,7 +2813,8 @@ def view_derivative_create(invocation: Invocation) -> HandlerResult:
2775
2813
  body=body,
2776
2814
  project_id=project_id,
2777
2815
  )
2778
- return data, _meta(invocation, auth.workspace_id, project_id)
2816
+ card = bool(body.get("display_properties")) if isinstance(body, dict) else False
2817
+ return {**data, "card": card}, _meta(invocation, auth.workspace_id, project_id)
2779
2818
 
2780
2819
 
2781
2820
  def view_derivative_data(invocation: Invocation) -> HandlerResult:
@@ -3275,6 +3314,8 @@ def _end_of_pipeline_exports(
3275
3314
  dataset_id=dataset_id,
3276
3315
  end_of_pipeline=True,
3277
3316
  )
3317
+ from mammoth.models.exports import ExportStatus
3318
+
3278
3319
  fired: list[dict[str, Any]] = []
3279
3320
  source_columns: Any = None
3280
3321
  for export in getattr(listing, "exports", None) or []:
@@ -3920,6 +3961,8 @@ def view_export_specialized(invocation: Invocation) -> HandlerResult:
3920
3961
  # reviewed trigger controls may flow through its **kwargs extension point;
3921
3962
  # using a union of every destination's fields would silently accept, for
3922
3963
  # example, email-only fields on a database export.
3964
+ from mammoth.view import ViewExport
3965
+
3923
3966
  signature = inspect.signature(getattr(ViewExport, method))
3924
3967
  explicit_fields = {
3925
3968
  name
@@ -4135,6 +4178,8 @@ def _existing_internal_dataset_export(
4135
4178
  and the list endpoint does not filter on status, so a deleted export
4136
4179
  would otherwise block every later export into that target forever.
4137
4180
  """
4181
+ from mammoth.models.exports import ExportStatus
4182
+
4138
4183
  listing = service.call(
4139
4184
  _EXPORTS_LIST_SYMBOL,
4140
4185
  dataview_id=dataview_id,