mammoth-cli 2.0.29__tar.gz → 2.0.31__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.
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/PKG-INFO +1 -1
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/__init__.py +1 -1
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/app.py +196 -61
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +3 -1
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +2 -2
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +2 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +8 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +4 -1
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +7 -3
- mammoth_cli-2.0.31/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +73 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/view.py +7 -3
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/view_ops.py +61 -1
- mammoth_cli-2.0.31/mammoth_cli/manifest/loader.py +164 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/confirm.py +4 -0
- mammoth_cli-2.0.31/mammoth_cli/runtime/dryrun.py +133 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/invocation.py +32 -1
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/session.py +7 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/command_contract.py +10 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/input_fields.py +12 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/sdk_service.py +12 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/testing.py +11 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/pyproject.toml +1 -1
- mammoth_cli-2.0.29/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -33
- mammoth_cli-2.0.29/mammoth_cli/manifest/loader.py +0 -96
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/.gitignore +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/LICENSE +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/README.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/__main__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/activity.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/addon.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/agent.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/ai.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/annotation.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/auth.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/automation.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/batch.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/billing.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/browse.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/capability.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/client_app.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/completion.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/config.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/connector.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/context.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/dashboard.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/data_app.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/dataset.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/doctor.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/external_key.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/file.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/folder.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/job.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/notification.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/parameter.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/project.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/registry.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/report.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/schedule.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/schema.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/skill.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/snippet.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/support.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/template.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/trash.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/upgrade.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/user.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/webhook.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/workflow.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/commands/workspace.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/context/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/context/credentials.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/context/endpoint.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/context/profiles.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/context/resolver.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/contracts/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/contracts/auth.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/errors/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/errors/envelope.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/manifest/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/messages/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/output/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/output/envelope.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/output/normalize.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/output/policy.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/output/progress.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/output/render.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/py.typed +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/executor.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/input_loader.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/options.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/parents.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/runlog.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/strict.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/updates.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/runtime/validate.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/argspec.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/coerce.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/conditions.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/dispatch.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/factory.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/mapping.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/openapi_types.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/positionals.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/protocol.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/services/type_system.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/skills/__init__.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/skills/installer.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/skills/steering.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/testing.py +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/activity.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/addon.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/agent.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/ai.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/annotation.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/auth.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/automation.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/batch.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/billing.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/browse.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/capability.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/client-app.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/completion.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/config.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/connector.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/context.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/dashboard.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/data-app.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/dataset.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/doctor.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/external-key.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/file.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/folder.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/job.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/log.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/notification.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/parameter.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/project.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/report.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/schedule.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/schema.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/skill.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/snippet.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/support.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/template.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/trash.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/upgrade.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/user.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/version.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/view.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/webhook.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/workflow.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/commands/workspace.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/openapi-operations.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/schema-v1.json +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/sdk-catalog.source.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/manifests/sdk-methods.yaml +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/openapi/metadata.json +0 -0
- {mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/spec/openapi/openapi.json +0 -0
|
@@ -29,7 +29,7 @@ from typer.core import TyperGroup
|
|
|
29
29
|
|
|
30
30
|
from mammoth_cli import __version__
|
|
31
31
|
from mammoth_cli.commands import BESPOKE
|
|
32
|
-
from mammoth_cli.commands.registry import HANDLERS
|
|
32
|
+
from mammoth_cli.commands.registry import HANDLERS, Handler
|
|
33
33
|
from mammoth_cli.context import profiles
|
|
34
34
|
from mammoth_cli.errors.envelope import EXIT_USAGE, CliError, not_implemented_error
|
|
35
35
|
from mammoth_cli.manifest.loader import command_by_id, load_commands
|
|
@@ -330,6 +330,13 @@ class _LeafGroup(TyperGroup):
|
|
|
330
330
|
class _EnvelopeGroup(TyperGroup):
|
|
331
331
|
"""Root group that renders Click usage errors as the machine error envelope.
|
|
332
332
|
|
|
333
|
+
It also materialises top-level command groups lazily (see
|
|
334
|
+
:func:`_load_top_level_group`): ``list_commands`` and ``get_command`` know
|
|
335
|
+
every group by name from the manifest, but a group's Click tree is only
|
|
336
|
+
built when it is invoked, completed or listed in ``--help``. Reading
|
|
337
|
+
``commands`` directly materialises them all, so tools that walk the tree
|
|
338
|
+
still see the full surface.
|
|
339
|
+
|
|
333
340
|
Click's standalone error handling prints a human ``Usage: ... Error: ...``
|
|
334
341
|
message and exits, even under ``--output json``: an agent driving the CLI
|
|
335
342
|
then receives un-parseable prose (or, for a leaf that also parents
|
|
@@ -345,6 +352,28 @@ class _EnvelopeGroup(TyperGroup):
|
|
|
345
352
|
on.
|
|
346
353
|
"""
|
|
347
354
|
|
|
355
|
+
@property # type: ignore[override]
|
|
356
|
+
def commands(self) -> dict[str, Any]:
|
|
357
|
+
loaded: dict[str, Any] = self.__dict__.setdefault("_eager_commands", {})
|
|
358
|
+
for name in _LAZY_GROUP_NAMES:
|
|
359
|
+
if name not in loaded:
|
|
360
|
+
loaded[name] = _load_top_level_group(name)
|
|
361
|
+
return loaded
|
|
362
|
+
|
|
363
|
+
@commands.setter
|
|
364
|
+
def commands(self, value: Any) -> None:
|
|
365
|
+
self.__dict__["_eager_commands"] = dict(value or {})
|
|
366
|
+
|
|
367
|
+
def list_commands(self, ctx: Any) -> list[str]:
|
|
368
|
+
eager = self.__dict__.get("_eager_commands", {})
|
|
369
|
+
return [*eager, *(name for name in _LAZY_GROUP_NAMES if name not in eager)]
|
|
370
|
+
|
|
371
|
+
def get_command(self, ctx: Any, cmd_name: str) -> Any:
|
|
372
|
+
eager: dict[str, Any] = self.__dict__.setdefault("_eager_commands", {})
|
|
373
|
+
if cmd_name not in eager and cmd_name in _LAZY_GROUP_NAMES:
|
|
374
|
+
eager[cmd_name] = _load_top_level_group(cmd_name)
|
|
375
|
+
return eager.get(cmd_name)
|
|
376
|
+
|
|
348
377
|
def main(self, *args: Any, **kwargs: Any) -> Any:
|
|
349
378
|
if not kwargs.get("standalone_mode", True):
|
|
350
379
|
return super().main(*args, **kwargs)
|
|
@@ -629,6 +658,18 @@ def _shared_option_params() -> list[inspect.Parameter]:
|
|
|
629
658
|
),
|
|
630
659
|
],
|
|
631
660
|
),
|
|
661
|
+
opt(
|
|
662
|
+
"dry_run",
|
|
663
|
+
False,
|
|
664
|
+
Annotated[
|
|
665
|
+
bool,
|
|
666
|
+
typer.Option(
|
|
667
|
+
"--dry-run",
|
|
668
|
+
help="Resolve and validate, then report the request instead of sending it.",
|
|
669
|
+
rich_help_panel="Safety",
|
|
670
|
+
),
|
|
671
|
+
],
|
|
672
|
+
),
|
|
632
673
|
opt(
|
|
633
674
|
"input_file",
|
|
634
675
|
None,
|
|
@@ -777,6 +818,8 @@ def _execute(invocation: Invocation) -> None:
|
|
|
777
818
|
record = command_by_id(invocation.command_id)
|
|
778
819
|
sdk_symbol = record.get("sdk_symbol", "") if record else ""
|
|
779
820
|
raise not_implemented_error(invocation.command_id, sdk_symbol)
|
|
821
|
+
if invocation.dry_run:
|
|
822
|
+
return _dry_run(handler, invocation)
|
|
780
823
|
return handler(invocation)
|
|
781
824
|
|
|
782
825
|
executor.run(
|
|
@@ -789,6 +832,25 @@ def _execute(invocation: Invocation) -> None:
|
|
|
789
832
|
)
|
|
790
833
|
|
|
791
834
|
|
|
835
|
+
def _dry_run(handler: Handler, invocation: Invocation) -> tuple[Any, dict[str, Any]]:
|
|
836
|
+
"""Run ``handler`` until its request would leave; report that request.
|
|
837
|
+
|
|
838
|
+
Local commands never open a service, so a dry run of one is the real run.
|
|
839
|
+
An API-backed handler that returns normally under ``--dry-run`` made no
|
|
840
|
+
gated SDK call at all (a pure read path); its result is returned as is.
|
|
841
|
+
"""
|
|
842
|
+
from mammoth_cli.runtime.dryrun import DryRunStop
|
|
843
|
+
from mammoth_cli.runtime.session import resolved_project
|
|
844
|
+
|
|
845
|
+
try:
|
|
846
|
+
return handler(invocation)
|
|
847
|
+
except DryRunStop as stop:
|
|
848
|
+
return stop.record, {
|
|
849
|
+
"profile": invocation.profile,
|
|
850
|
+
"project_id": resolved_project(invocation),
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
|
|
792
854
|
def _command_help(command_id: str, record: dict[str, Any] | None) -> str | None:
|
|
793
855
|
"""Build a command's user-facing ``--help`` summary.
|
|
794
856
|
|
|
@@ -855,68 +917,55 @@ def _short_type(type_name: str) -> str:
|
|
|
855
917
|
return " | ".join(part.strip().rsplit(".", 1)[-1] for part in text.split("|"))[:40]
|
|
856
918
|
|
|
857
919
|
|
|
858
|
-
def
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
920
|
+
def _command_records() -> list[dict[str, Any]]:
|
|
921
|
+
return [r for r in load_commands() if r.get("disposition") != "alias"]
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
@cache
|
|
925
|
+
def _command_tree() -> tuple[dict[tuple[str, ...], str], frozenset[tuple[str, ...]]]:
|
|
926
|
+
"""Map every command path to its id, and name the container nodes.
|
|
927
|
+
|
|
928
|
+
A "container command" sits at a node that also has deeper subcommands
|
|
929
|
+
(e.g. ``dataset file-settings``, which also has ``... undo`` / ``... update``).
|
|
930
|
+
"""
|
|
931
|
+
path_to_command = {
|
|
932
|
+
tuple(r["command_path"].split()): r["command_id"] for r in _command_records()
|
|
933
|
+
}
|
|
934
|
+
prefixes: set[tuple[str, ...]] = set()
|
|
935
|
+
for tokens in path_to_command:
|
|
936
|
+
for depth in range(1, len(tokens)):
|
|
937
|
+
prefixes.add(tokens[:depth])
|
|
938
|
+
return path_to_command, frozenset(prefixes & path_to_command.keys())
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
def _group_typer(tokens: tuple[str, ...], command_id: str | None) -> typer.Typer:
|
|
942
|
+
if command_id is not None:
|
|
943
|
+
# This node is both a group and an invocable command.
|
|
944
|
+
sub = typer.Typer(
|
|
945
|
+
cls=_LeafGroup,
|
|
946
|
+
no_args_is_help=False,
|
|
947
|
+
invoke_without_command=True,
|
|
948
|
+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
949
|
+
)
|
|
950
|
+
sub.callback()(_build_leaf(command_id, is_group_callback=True))
|
|
951
|
+
return sub
|
|
952
|
+
return typer.Typer(
|
|
953
|
+
help=_GROUP_DESCRIPTIONS.get(tokens[0], f"Commands for {' '.join(tokens)}."),
|
|
867
954
|
no_args_is_help=True,
|
|
868
|
-
add_completion=True,
|
|
869
|
-
cls=_EnvelopeGroup,
|
|
870
955
|
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
871
956
|
)
|
|
872
957
|
|
|
873
|
-
@root.callback()
|
|
874
|
-
def _root(
|
|
875
|
-
version: bool = typer.Option(
|
|
876
|
-
False, "--version", callback=_version_callback, is_eager=True, help="Show version."
|
|
877
|
-
),
|
|
878
|
-
) -> None:
|
|
879
|
-
"""Root callback holding eager global options."""
|
|
880
958
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
}
|
|
885
|
-
all_paths = set(path_to_command)
|
|
886
|
-
# A "container command" sits at a node that also has deeper subcommands
|
|
887
|
-
# (e.g. `dataset file-settings`, which also has `... undo` / `... update`).
|
|
888
|
-
containers = {
|
|
889
|
-
tokens
|
|
890
|
-
for tokens in all_paths
|
|
891
|
-
if any(other != tokens and other[: len(tokens)] == tokens for other in all_paths)
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
groups: dict[tuple[str, ...], typer.Typer] = {(): root}
|
|
895
|
-
|
|
896
|
-
def _make_group(tokens: tuple[str, ...]) -> typer.Typer:
|
|
897
|
-
command_id = path_to_command.get(tokens)
|
|
898
|
-
if command_id is not None:
|
|
899
|
-
# This node is both a group and an invocable command.
|
|
900
|
-
sub = typer.Typer(
|
|
901
|
-
cls=_LeafGroup,
|
|
902
|
-
no_args_is_help=False,
|
|
903
|
-
invoke_without_command=True,
|
|
904
|
-
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
905
|
-
)
|
|
906
|
-
sub.callback()(_build_leaf(command_id, is_group_callback=True))
|
|
907
|
-
else:
|
|
908
|
-
sub = typer.Typer(
|
|
909
|
-
help=_GROUP_DESCRIPTIONS.get(tokens[0], f"Commands for {' '.join(tokens)}."),
|
|
910
|
-
no_args_is_help=True,
|
|
911
|
-
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
912
|
-
)
|
|
913
|
-
return sub
|
|
959
|
+
def _populate(base: tuple[str, ...], group: typer.Typer) -> None:
|
|
960
|
+
"""Register every command below ``base`` (exclusive) on ``group``."""
|
|
961
|
+
path_to_command, containers = _command_tree()
|
|
962
|
+
groups: dict[tuple[str, ...], typer.Typer] = {base: group}
|
|
914
963
|
|
|
915
964
|
def _group_for(tokens: tuple[str, ...]) -> typer.Typer:
|
|
916
965
|
if tokens in groups:
|
|
917
966
|
return groups[tokens]
|
|
918
967
|
parent = _group_for(tokens[:-1])
|
|
919
|
-
sub =
|
|
968
|
+
sub = _group_typer(tokens, path_to_command.get(tokens))
|
|
920
969
|
top_level = tokens[0]
|
|
921
970
|
parent.add_typer(
|
|
922
971
|
sub,
|
|
@@ -927,15 +976,16 @@ def build_app() -> typer.Typer:
|
|
|
927
976
|
groups[tokens] = sub
|
|
928
977
|
return sub
|
|
929
978
|
|
|
979
|
+
below = {t: c for t, c in path_to_command.items() if t[: len(base)] == base and t != base}
|
|
930
980
|
# Ensure every container group exists (parents before children).
|
|
931
|
-
for tokens in sorted(containers, key=len):
|
|
981
|
+
for tokens in sorted((t for t in below if t in containers), key=len):
|
|
932
982
|
_group_for(tokens)
|
|
933
983
|
|
|
934
984
|
# Register every non-container command as a leaf under its parent group.
|
|
935
985
|
# A command_id with a bespoke, fully-typed callback overrides the generic
|
|
936
986
|
# leaf at the same registered name and path; the manifest-driven surface
|
|
937
987
|
# is otherwise unchanged.
|
|
938
|
-
for tokens, command_id in sorted(
|
|
988
|
+
for tokens, command_id in sorted(below.items()):
|
|
939
989
|
if tokens in containers:
|
|
940
990
|
continue
|
|
941
991
|
record = command_by_id(command_id)
|
|
@@ -947,11 +997,88 @@ def build_app() -> typer.Typer:
|
|
|
947
997
|
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
948
998
|
)(callback)
|
|
949
999
|
|
|
1000
|
+
|
|
1001
|
+
@cache
|
|
1002
|
+
def _top_level_typer(name: str) -> typer.Typer:
|
|
1003
|
+
"""Build (once) the Typer sub-app for one top-level command group."""
|
|
1004
|
+
path_to_command, _ = _command_tree()
|
|
1005
|
+
sub = _group_typer((name,), path_to_command.get((name,)))
|
|
1006
|
+
_populate((name,), sub)
|
|
1007
|
+
return sub
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
# Top-level groups are converted to Click on first use. Building the leaf
|
|
1011
|
+
# callbacks and ``--help`` text for all ~550 commands, then letting Typer
|
|
1012
|
+
# convert every one of them, used to cost most of the CLI's start-up time on
|
|
1013
|
+
# every invocation; a run touches one group.
|
|
1014
|
+
_LAZY_GROUP_NAMES: list[str] = []
|
|
1015
|
+
_LAZY_SETTINGS: dict[str, Any] = {}
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
def _load_top_level_group(name: str) -> Any:
|
|
1019
|
+
from typer.models import TyperInfo
|
|
1020
|
+
|
|
1021
|
+
info = TyperInfo(
|
|
1022
|
+
_top_level_typer(name),
|
|
1023
|
+
name=name,
|
|
1024
|
+
help=_GROUP_DESCRIPTIONS.get(name, f"Commands for {name}."),
|
|
1025
|
+
rich_help_panel=_ROOT_HELP_PANELS.get(name),
|
|
1026
|
+
)
|
|
1027
|
+
return typer.main.get_group_from_info(info, **_LAZY_SETTINGS)
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
def build_app() -> typer.Typer:
|
|
1031
|
+
"""Construct the Typer command tree from the command manifests.
|
|
1032
|
+
|
|
1033
|
+
Top-level leaves (``doctor``, ``version``, ...) are registered here; every
|
|
1034
|
+
top-level group is materialised by :class:`_EnvelopeGroup` on demand.
|
|
1035
|
+
"""
|
|
1036
|
+
root = typer.Typer(
|
|
1037
|
+
name="mammoth",
|
|
1038
|
+
help=(
|
|
1039
|
+
"Command-line interface for the Mammoth Analytics platform.\n\n"
|
|
1040
|
+
"Start with 'mammoth doctor' to check access, 'mammoth schema find QUERY' "
|
|
1041
|
+
"to locate a command, and 'mammoth schema get COMMAND_ID' for its full input schema."
|
|
1042
|
+
),
|
|
1043
|
+
no_args_is_help=True,
|
|
1044
|
+
add_completion=True,
|
|
1045
|
+
cls=_EnvelopeGroup,
|
|
1046
|
+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
@root.callback()
|
|
1050
|
+
def _root(
|
|
1051
|
+
version: bool = typer.Option(
|
|
1052
|
+
False, "--version", callback=_version_callback, is_eager=True, help="Show version."
|
|
1053
|
+
),
|
|
1054
|
+
) -> None:
|
|
1055
|
+
"""Root callback holding eager global options."""
|
|
1056
|
+
|
|
1057
|
+
path_to_command, containers = _command_tree()
|
|
1058
|
+
top_names = sorted({tokens[0] for tokens in path_to_command})
|
|
1059
|
+
lazy: list[str] = []
|
|
1060
|
+
for name in top_names:
|
|
1061
|
+
if (name,) in containers or (name,) not in path_to_command:
|
|
1062
|
+
lazy.append(name)
|
|
1063
|
+
continue
|
|
1064
|
+
command_id = path_to_command[(name,)]
|
|
1065
|
+
root.command(
|
|
1066
|
+
name=name,
|
|
1067
|
+
help=_command_help(command_id, command_by_id(command_id)),
|
|
1068
|
+
rich_help_panel=_ROOT_HELP_PANELS.get(name),
|
|
1069
|
+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
1070
|
+
)(BESPOKE.get(command_id) or _build_leaf(command_id))
|
|
1071
|
+
_LAZY_GROUP_NAMES[:] = lazy
|
|
1072
|
+
_LAZY_SETTINGS.update(
|
|
1073
|
+
pretty_exceptions_short=root.pretty_exceptions_short,
|
|
1074
|
+
rich_markup_mode=root.rich_markup_mode,
|
|
1075
|
+
suggest_commands=root.suggest_commands,
|
|
1076
|
+
)
|
|
950
1077
|
return root
|
|
951
1078
|
|
|
952
1079
|
|
|
953
1080
|
def registered_command_paths() -> set[str]:
|
|
954
|
-
"""Return every registered command path by walking the built Typer
|
|
1081
|
+
"""Return every registered command path by walking the built Typer trees.
|
|
955
1082
|
|
|
956
1083
|
Container commands (a node that is both a group and invocable) are counted
|
|
957
1084
|
by their own path as well as their subcommands.
|
|
@@ -965,14 +1092,20 @@ def registered_command_paths() -> set[str]:
|
|
|
965
1092
|
paths.add(" ".join((*prefix, name)))
|
|
966
1093
|
for group in instance.registered_groups:
|
|
967
1094
|
sub = group.typer_instance
|
|
968
|
-
|
|
1095
|
+
name = group.name
|
|
1096
|
+
if sub is None or not name:
|
|
969
1097
|
continue
|
|
970
|
-
node = (*prefix,
|
|
971
|
-
if
|
|
1098
|
+
node = (*prefix, name)
|
|
1099
|
+
if sub.registered_callback is not None:
|
|
972
1100
|
paths.add(" ".join(node))
|
|
973
1101
|
walk(sub, node)
|
|
974
1102
|
|
|
975
|
-
walk(
|
|
1103
|
+
walk(app, ())
|
|
1104
|
+
for name in _LAZY_GROUP_NAMES:
|
|
1105
|
+
sub = _top_level_typer(name)
|
|
1106
|
+
if sub.registered_callback is not None:
|
|
1107
|
+
paths.add(name)
|
|
1108
|
+
walk(sub, (name,))
|
|
976
1109
|
return paths
|
|
977
1110
|
|
|
978
1111
|
|
|
@@ -987,7 +1120,9 @@ def _root_click_command() -> Any:
|
|
|
987
1120
|
the tree is fixed for the process lifetime (:data:`app` is built once at
|
|
988
1121
|
import time).
|
|
989
1122
|
"""
|
|
990
|
-
|
|
1123
|
+
root: Any = typer.main.get_command(app)
|
|
1124
|
+
root.commands # noqa: B018 -- materialise every lazy top-level group
|
|
1125
|
+
return root
|
|
991
1126
|
|
|
992
1127
|
|
|
993
1128
|
def command_option_names(command_path: str) -> set[str]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mammoth-cli
|
|
3
|
-
version: 2.0.
|
|
3
|
+
version: 2.0.31
|
|
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, dashboards, exports, and handoffs."
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -60,6 +60,8 @@ before the next step.
|
|
|
60
60
|
'{"full": true}'` returns the dependency and display trees too.
|
|
61
61
|
- Column inputs and expressions use the exact **display names** the view
|
|
62
62
|
returns, never backend aliases.
|
|
63
|
+
- `--dry-run` on any API-backed command resolves everything and reports the
|
|
64
|
+
request instead of sending it; use it before a write you are not sure of.
|
|
63
65
|
- Destructive commands need `--yes --confirm ID`. Preserve requested
|
|
64
66
|
deliverables; cleanup is exact-ID authorized and
|
|
65
67
|
never means delete-all-owned-resources: delete only ids this run created,
|
|
@@ -932,7 +932,7 @@ Example: `mammoth view transform extract-date 123 --input '{"column": "Status",
|
|
|
932
932
|
|
|
933
933
|
Result: `ViewTransformExtractDateResult`; mutation `reversible_pipeline`, confirmation `none`, wait policy `always_wait`.
|
|
934
934
|
|
|
935
|
-
Status on release:
|
|
935
|
+
Status on release: ran once on CLI 2.0.18 through `view.task.add` and was read back with `view data get`; other inputs for this transform are untried.
|
|
936
936
|
|
|
937
937
|
### `view.transform.fill-missing`
|
|
938
938
|
|
|
@@ -1112,7 +1112,7 @@ Example: `mammoth view transform window 123 --input '{"function": "ROW_NUMBER",
|
|
|
1112
1112
|
|
|
1113
1113
|
Result: `ViewTransformWindowResult`; mutation `reversible_pipeline`, confirmation `none`, wait policy `always_wait`.
|
|
1114
1114
|
|
|
1115
|
-
Status on release:
|
|
1115
|
+
Status on release: ran once on CLI 2.0.18 through `view.task.add` and was read back with `view data get`; other inputs for this transform are untried.
|
|
1116
1116
|
|
|
1117
1117
|
### `view.trash`
|
|
1118
1118
|
|
{mammoth_cli-2.0.29 → mammoth_cli-2.0.31}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md
RENAMED
|
@@ -13,6 +13,8 @@ mammoth view transform filter 1039 --project 180 \
|
|
|
13
13
|
- `--input FILE` (or `--input @FILE`) reads a JSON or YAML file; the format
|
|
14
14
|
is inferred from the extension.
|
|
15
15
|
- `--input -` reads stdin; then `--input-format json|yaml` is required.
|
|
16
|
+
- `--dry-run` admits and resolves the document, then reports the SDK call
|
|
17
|
+
instead of making it ([safety](safety.md)).
|
|
16
18
|
- The top level must be a mapping. A bad path, format, or shape fails with exit
|
|
17
19
|
code 2 and a stable error code.
|
|
18
20
|
- Column references use display names returned by the exact view schema. Do not
|
|
@@ -90,6 +90,14 @@ task/list or pipeline/items result back after a successful write. Without that
|
|
|
90
90
|
independent specification, report the route as unsupported/ambiguous and stop
|
|
91
91
|
safely.
|
|
92
92
|
|
|
93
|
+
Typed transforms and `view task add` append at the end of the pipeline and
|
|
94
|
+
never reorder or delete an existing step. On a pipeline other people or
|
|
95
|
+
agents also edit, make that checkable: read `view task list VIEW_ID`, plan,
|
|
96
|
+
then write with `"expected_task_count": N` in the input; the CLI re-reads
|
|
97
|
+
the list just before the write and refuses with `pipeline_changed` when the
|
|
98
|
+
count moved ([safety](safety.md)). `--dry-run` on the same command shows the
|
|
99
|
+
resolved call first.
|
|
100
|
+
|
|
93
101
|
For a new workflow (a container for automation), discover and then read it
|
|
94
102
|
back; workflow creation is not the same as adding a view pipeline task:
|
|
95
103
|
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
```bash
|
|
4
4
|
mammoth schema find "view export"
|
|
5
5
|
mammoth schema get view.export.csv
|
|
6
|
-
mammoth view export csv VIEW_ID --project PROJECT_ID
|
|
6
|
+
mammoth view export csv VIEW_ID --project PROJECT_ID --input '{"dataset_id": DATASET_ID, "output_path": "out.csv"}'
|
|
7
7
|
mammoth view export list VIEW_ID DATASET_ID --project PROJECT_ID
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
+
`view export csv` takes one positional (the view); `dataset_id` and
|
|
11
|
+
`output_path` go in `--input`. It is a download, not a pipeline step.
|
|
12
|
+
|
|
10
13
|
If the export or its source dataset/view is requested as a deliverable, mark
|
|
11
14
|
both as retained before starting. Wait/reconcile returned jobs. Verify local
|
|
12
15
|
artifact headers, rows and hash;
|
|
@@ -30,9 +30,13 @@ mammoth dataset file-settings update DATASET_ID --project PROJECT_ID \
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
The response is a job (`operation: "understand_csv"`). Poll `dataset get`
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
(the record is under `data.dataset`, so read `data.dataset.status`) until
|
|
34
|
+
the status leaves `need_action`. It usually reaches `ready` within seconds;
|
|
35
|
+
on prague an ISO `YYYY-MM-DD` column was flagged ambiguous and took about
|
|
36
|
+
three minutes, so poll for up to five minutes before treating it as stuck.
|
|
37
|
+
Then `view list` returns the generated view and typed transforms can
|
|
38
|
+
proceed. Which environments ask differs: release processed the same file
|
|
39
|
+
straight to `ready`. If the status becomes `error`, read `status_info`
|
|
36
40
|
and stop; do not retry with guessed settings.
|
|
37
41
|
|
|
38
42
|
## All-text CSV: `ready` without a view
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Safe mutation
|
|
2
|
+
|
|
3
|
+
Each command carries a reviewed confirmation policy:
|
|
4
|
+
|
|
5
|
+
| policy | how to satisfy it noninteractively |
|
|
6
|
+
|---|---|
|
|
7
|
+
| none | nothing required |
|
|
8
|
+
| prompt_or_yes | pass `--yes` |
|
|
9
|
+
| yes_always | pass `--yes` (always, even at a terminal) |
|
|
10
|
+
| confirm_target | pass `--yes` and `--confirm TARGET` (exact match) |
|
|
11
|
+
|
|
12
|
+
Under `--no-input` (and in `json`/`ndjson` modes) there is no prompt: a missing
|
|
13
|
+
`--yes`/`--confirm` fails with exit code 2 and error code
|
|
14
|
+
`confirmation_required` or `confirmation_target_mismatch`.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# normal delete
|
|
18
|
+
mammoth folder delete 7 --project 180 --yes
|
|
19
|
+
|
|
20
|
+
# high-impact: target must equal the resource
|
|
21
|
+
mammoth project user remove --project 180 \
|
|
22
|
+
--yes --confirm 180 --input '{"user_ids": ["u_123"]}'
|
|
23
|
+
|
|
24
|
+
# project delete cascades to every dataset, view, export and dashboard in it
|
|
25
|
+
mammoth project delete 180 --yes --confirm 180
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Discover a command's policy with `mammoth schema get <command.id>`.
|
|
29
|
+
|
|
30
|
+
## Rehearse before you write
|
|
31
|
+
|
|
32
|
+
`--dry-run` on any API-backed command does everything but send the request:
|
|
33
|
+
input admission, parent resolution, display-name and condition checks, then
|
|
34
|
+
it stops at the SDK call and reports it as `data.would_call` (`sdk_symbol`,
|
|
35
|
+
resolved `arguments`, `view_id`/`dataset_id`) with `data.dry_run: true`. No
|
|
36
|
+
confirmation flag is needed for a dry run; the real run still needs its
|
|
37
|
+
`--yes`/`--confirm`. Use it before a mutation on a shared or production
|
|
38
|
+
resource, and whenever you are unsure which view or column an input resolves
|
|
39
|
+
to.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
mammoth view transform filter 144 --dry-run \
|
|
43
|
+
--input '{"filter_type": "REMOVE", "condition": {"column": "Location", "operator": "EQ", "value": "Total"}}'
|
|
44
|
+
# data.would_call.sdk_symbol = ...FilterOpsMixin.filter_rows, view_id 144, dataset_id 122
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
A dry run is a full process with the same reads as the real run. On a
|
|
48
|
+
hosted environment budget roughly 2 s per request (about 0.7 s of it TLS
|
|
49
|
+
setup from a cold process, the rest server time), so `view task list` →
|
|
50
|
+
`--dry-run` → write costs about 30–40 s per pipeline step. That is the
|
|
51
|
+
price of the procedure, not a hang; do not shorten `--timeout` below the
|
|
52
|
+
default to speed it up.
|
|
53
|
+
|
|
54
|
+
## Add-only edits to a pipeline someone else may touch
|
|
55
|
+
|
|
56
|
+
Every `view transform *` and `view task add` accepts `expected_task_count`:
|
|
57
|
+
the number of tasks your last `view task list VIEW_ID` returned. The CLI
|
|
58
|
+
re-reads the task list right before the write and refuses with
|
|
59
|
+
`pipeline_changed` (exit 2, `details.actual_task_count`, `task_ids`) when the
|
|
60
|
+
count differs, so a plan made against a stale read cannot land on a pipeline
|
|
61
|
+
that changed under you. Read → decide → write with the count, one edit at a
|
|
62
|
+
time; on `pipeline_changed`, re-read and re-decide rather than retrying with
|
|
63
|
+
the new number blindly.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mammoth view task list 144 # data.tasks has 3 entries
|
|
67
|
+
mammoth view transform filter 144 --input '{"expected_task_count": 3, "filter_type": "REMOVE", "condition": {...}}'
|
|
68
|
+
```
|
|
69
|
+
Use exact observed resource scope and display names before mutation. A known job
|
|
70
|
+
handle should be inspected or waited, not submitted again. `outcome_unknown`
|
|
71
|
+
means a mutation may have committed without a terminal response: reconcile the
|
|
72
|
+
target before any replay. A retryable read can honor `Retry-After`; exit 7 is
|
|
73
|
+
not blanket permission to retry a mutation.
|
|
@@ -1445,11 +1445,15 @@ def view_task_add(invocation: Invocation) -> HandlerResult:
|
|
|
1445
1445
|
kwargs: dict[str, Any] = {"dataview_id": dataview_id, "task_spec": task_spec}
|
|
1446
1446
|
assert document is not None
|
|
1447
1447
|
_forward_optional(document, kwargs, ("dataset_id",))
|
|
1448
|
+
# Imported here: view_ops imports this module for the brief record helpers.
|
|
1449
|
+
from mammoth_cli.commands.view_ops import (
|
|
1450
|
+
reject_pipeline_reference_errors,
|
|
1451
|
+
require_expected_task_count,
|
|
1452
|
+
)
|
|
1453
|
+
|
|
1448
1454
|
with open_service(invocation) as (service, auth):
|
|
1455
|
+
require_expected_task_count(service, dataview_id, kwargs.get("dataset_id"), document)
|
|
1449
1456
|
data = service.call(_symbol(invocation), **kwargs)
|
|
1450
|
-
# Imported here: view_ops imports this module for the brief record helpers.
|
|
1451
|
-
from mammoth_cli.commands.view_ops import reject_pipeline_reference_errors
|
|
1452
|
-
|
|
1453
1457
|
reject_pipeline_reference_errors(service, dataview_id, kwargs.get("dataset_id"), data)
|
|
1454
1458
|
return data, _meta(invocation, auth.workspace_id, None)
|
|
1455
1459
|
|
|
@@ -43,6 +43,7 @@ from mammoth_cli.runtime.invocation import Invocation
|
|
|
43
43
|
from mammoth_cli.runtime.session import open_service, resolved_project
|
|
44
44
|
from mammoth_cli.services.command_contract import bind_command_inputs
|
|
45
45
|
from mammoth_cli.services.conditions import CONDITION_KWARG
|
|
46
|
+
from mammoth_cli.services.input_fields import TASK_COUNT_FIELD
|
|
46
47
|
|
|
47
48
|
HandlerResult = tuple[Any, dict[str, Any]]
|
|
48
49
|
|
|
@@ -251,6 +252,7 @@ def _dispatch_view(
|
|
|
251
252
|
with open_service(invocation) as (service, auth):
|
|
252
253
|
if dataset_id is None:
|
|
253
254
|
dataset_id = parents.lookup(_profile_name(invocation), auth.workspace_id, view_id)
|
|
255
|
+
require_expected_task_count(service, view_id, dataset_id, document)
|
|
254
256
|
try:
|
|
255
257
|
if dataset_id is None:
|
|
256
258
|
_require_discovery_allowed(invocation, view_id)
|
|
@@ -266,6 +268,60 @@ def _dispatch_view(
|
|
|
266
268
|
return data, _meta(invocation, auth.workspace_id)
|
|
267
269
|
|
|
268
270
|
|
|
271
|
+
CODE_PIPELINE_CHANGED = "pipeline_changed"
|
|
272
|
+
_TASK_LIST_SYMBOL = "mammoth.api.pipeline.PipelineAPI.list_tasks"
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def require_expected_task_count(
|
|
276
|
+
service: Any, view_id: int, dataset_id: Any, document: dict[str, Any] | None
|
|
277
|
+
) -> None:
|
|
278
|
+
"""Refuse a pipeline write when the view's task count is not the one read.
|
|
279
|
+
|
|
280
|
+
``expected_task_count`` is the count from the caller's last ``view task
|
|
281
|
+
list``. A different live count means the pipeline changed since that read
|
|
282
|
+
(another agent, a person in the web app), and an append planned against
|
|
283
|
+
the old shape must not land. Without the field nothing is checked.
|
|
284
|
+
"""
|
|
285
|
+
if not document or TASK_COUNT_FIELD not in document:
|
|
286
|
+
return
|
|
287
|
+
expected = int(document[TASK_COUNT_FIELD])
|
|
288
|
+
kwargs: dict[str, Any] = {"dataview_id": view_id}
|
|
289
|
+
if dataset_id is not None:
|
|
290
|
+
kwargs["dataset_id"] = int(dataset_id)
|
|
291
|
+
listing = service.call(_TASK_LIST_SYMBOL, **kwargs)
|
|
292
|
+
tasks = listing.get("tasks") if isinstance(listing, dict) else None
|
|
293
|
+
if not isinstance(tasks, list):
|
|
294
|
+
raise CliError(
|
|
295
|
+
code=CODE_PIPELINE_CHANGED,
|
|
296
|
+
message=f"Could not read the task list of view {view_id} to check the precondition.",
|
|
297
|
+
exit_status=EXIT_USAGE,
|
|
298
|
+
details={"view_id": view_id, "expected_task_count": expected, "response": listing},
|
|
299
|
+
)
|
|
300
|
+
actual = len(tasks)
|
|
301
|
+
if actual == expected:
|
|
302
|
+
return
|
|
303
|
+
raise CliError(
|
|
304
|
+
code=CODE_PIPELINE_CHANGED,
|
|
305
|
+
message=(
|
|
306
|
+
f"View {view_id} has {actual} pipeline task(s), not the {expected} expected; "
|
|
307
|
+
"the pipeline changed since it was read, so nothing was written."
|
|
308
|
+
),
|
|
309
|
+
exit_status=EXIT_USAGE,
|
|
310
|
+
hint=(
|
|
311
|
+
"Re-read the pipeline, decide whether the plan still holds, and retry "
|
|
312
|
+
f"with expected_task_count {actual}."
|
|
313
|
+
),
|
|
314
|
+
details={
|
|
315
|
+
"view_id": view_id,
|
|
316
|
+
"dataset_id": int(dataset_id) if dataset_id is not None else None,
|
|
317
|
+
"expected_task_count": expected,
|
|
318
|
+
"actual_task_count": actual,
|
|
319
|
+
"task_ids": [t.get("id") for t in tasks if isinstance(t, dict)],
|
|
320
|
+
},
|
|
321
|
+
recovery_commands=[f"mammoth view task list {view_id}"],
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
269
325
|
def _compact_reference_error(entry: Any) -> dict[str, Any]:
|
|
270
326
|
if not isinstance(entry, dict):
|
|
271
327
|
return {"reason": str(entry)}
|
|
@@ -362,7 +418,11 @@ def _without_resource_context(document: dict[str, Any]) -> dict[str, Any]:
|
|
|
362
418
|
# mapping. These identifiers select the View receiver and are not method
|
|
363
419
|
# kwargs; strip both parent and receiver identities before the transform
|
|
364
420
|
# adapter forwards the document.
|
|
365
|
-
return {
|
|
421
|
+
return {
|
|
422
|
+
key: value
|
|
423
|
+
for key, value in document.items()
|
|
424
|
+
if key not in {"dataset_id", "view_id", TASK_COUNT_FIELD}
|
|
425
|
+
}
|
|
366
426
|
|
|
367
427
|
|
|
368
428
|
def _bind_transform_inputs(invocation: Invocation, document: dict[str, Any]) -> dict[str, Any]:
|