mammoth-cli 2.0.18__tar.gz → 2.0.19__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.18 → mammoth_cli-2.0.19}/PKG-INFO +7 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/README.md +6 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/__init__.py +1 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +1 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +1 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +2 -2
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +10 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +1 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +5 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +1 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +46 -4
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +6 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +3 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/doctor.py +17 -11
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/file.py +27 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/project.py +71 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/registry.py +1 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/upgrade.py +5 -2
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/output/envelope.py +4 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/executor.py +11 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/strict.py +28 -7
- mammoth_cli-2.0.19/mammoth_cli/runtime/updates.py +264 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/command_contract.py +2 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/input_fields.py +9 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/mapping.py +16 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/positionals.py +10 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/pyproject.toml +1 -1
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/file.yaml +8 -4
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/project.yaml +41 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/view.yaml +5 -2
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/.gitignore +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/LICENSE +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/__main__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/app.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/activity.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/addon.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/agent.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/ai.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/annotation.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/auth.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/automation.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/batch.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/billing.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/browse.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/capability.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/client_app.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/completion.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/config.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/connector.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/context.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/dashboard.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/data_app.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/dataset.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/external_key.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/folder.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/job.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/notification.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/parameter.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/report.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/schedule.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/schema.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/skill.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/snippet.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/support.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/template.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/trash.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/user.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/view.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/view_ops.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/webhook.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/workflow.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/commands/workspace.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/context/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/context/credentials.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/context/endpoint.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/context/profiles.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/context/resolver.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/contracts/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/contracts/auth.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/errors/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/errors/envelope.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/manifest/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/manifest/loader.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/messages/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/output/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/output/normalize.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/output/policy.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/output/progress.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/output/render.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/py.typed +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/confirm.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/input_loader.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/invocation.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/options.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/runlog.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/session.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/runtime/validate.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/argspec.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/coerce.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/conditions.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/dispatch.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/factory.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/openapi_types.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/protocol.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/sdk_service.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/testing.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/services/type_system.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/skills/__init__.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/skills/installer.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/mammoth_cli/testing.py +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/activity.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/addon.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/agent.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/ai.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/annotation.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/auth.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/automation.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/batch.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/billing.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/browse.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/capability.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/client-app.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/completion.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/config.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/connector.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/context.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/dashboard.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/data-app.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/dataset.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/doctor.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/external-key.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/folder.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/job.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/log.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/notification.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/parameter.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/report.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/schedule.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/schema.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/skill.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/snippet.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/support.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/template.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/trash.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/upgrade.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/user.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/version.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/webhook.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/workflow.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/commands/workspace.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/openapi-operations.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/schema-v1.json +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/sdk-catalog.source.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/manifests/sdk-methods.yaml +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/openapi/metadata.json +0 -0
- {mammoth_cli-2.0.18 → mammoth_cli-2.0.19}/spec/openapi/openapi.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mammoth-cli
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.19
|
|
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
|
|
@@ -217,6 +217,12 @@ mammoth skill install --input '{"agents": ["codex"], "scope": "project"}'
|
|
|
217
217
|
Use `mammoth skill update` after a CLI upgrade. It refreshes copies owned by the
|
|
218
218
|
installer and reports modified copies instead of silently replacing them.
|
|
219
219
|
|
|
220
|
+
The CLI checks PyPI for a newer release at most once a day, after a command
|
|
221
|
+
has finished: every JSON envelope carries `meta.update_available` and human
|
|
222
|
+
output adds one stderr line. Set `MAMMOTH_NO_UPDATE_CHECK=1` to turn it off,
|
|
223
|
+
or `MAMMOTH_AUTO_UPGRADE=1` to have it upgrade itself (opt-in; see
|
|
224
|
+
[Upgrade](https://github.com/EdgeMetric/mammothsdk/blob/main/mammoth-cli/docs/upgrade.md)).
|
|
225
|
+
|
|
220
226
|
## What you can do
|
|
221
227
|
|
|
222
228
|
| Area | Command families |
|
|
@@ -189,6 +189,12 @@ mammoth skill install --input '{"agents": ["codex"], "scope": "project"}'
|
|
|
189
189
|
Use `mammoth skill update` after a CLI upgrade. It refreshes copies owned by the
|
|
190
190
|
installer and reports modified copies instead of silently replacing them.
|
|
191
191
|
|
|
192
|
+
The CLI checks PyPI for a newer release at most once a day, after a command
|
|
193
|
+
has finished: every JSON envelope carries `meta.update_available` and human
|
|
194
|
+
output adds one stderr line. Set `MAMMOTH_NO_UPDATE_CHECK=1` to turn it off,
|
|
195
|
+
or `MAMMOTH_AUTO_UPGRADE=1` to have it upgrade itself (opt-in; see
|
|
196
|
+
[Upgrade](https://github.com/EdgeMetric/mammothsdk/blob/main/mammoth-cli/docs/upgrade.md)).
|
|
197
|
+
|
|
192
198
|
## What you can do
|
|
193
199
|
|
|
194
200
|
| Area | Command families |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mammoth-cli
|
|
3
|
-
version: 2.0.
|
|
3
|
+
version: 2.0.19
|
|
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
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# What is proven on release
|
|
2
2
|
|
|
3
3
|
Generated from `docs/release-capability-matrix.json`; do not edit by hand.
|
|
4
|
-
The CLI publishes
|
|
4
|
+
The CLI publishes 552 commands. 455 of them bind one of the 528 API operations in the matrix; the remainder are local commands (`schema`, `auth`, `doctor`, `log`, ...) or typed variants that share an operation (every `view transform *` command submits through `view.task.add`). 258 bound commands ran once successfully on release, 2 are not supported there, and the rest are untried. Untried is not broken: discover the contract with `mammoth schema get COMMAND_ID --output json --no-input`, run it, and treat the structured error envelope as the answer.
|
|
5
5
|
|
|
6
6
|
Status meanings:
|
|
7
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Published CLI command catalog
|
|
2
2
|
|
|
3
|
-
This generated catalog is a lookup table for every command in the published CLI manifest, currently
|
|
3
|
+
This generated catalog is a lookup table for every command in the published CLI manifest, currently 552; each entry carries its release status line. It is a command-contract index, not an assertion that every backend/OpenAPI operation has a CLI binding. For an exact local CLI contract, run `mammoth schema get COMMAND_ID --output json --no-input`; `mammoth capability list` is an API-binding inventory and can omit typed/local CLI routes. For focused workflows, read the [recipes index](recipes/index.md). Sensitive structured input must come from a private file or pipe; never put secrets in literal argv.
|
|
4
4
|
|
|
5
5
|
Load only the applicable domain file:
|
|
6
6
|
|
|
@@ -31,7 +31,7 @@ Load only the applicable domain file:
|
|
|
31
31
|
- [log](commands/log.md) — 2 published commands
|
|
32
32
|
- [notification](commands/notification.md) — 5 published commands
|
|
33
33
|
- [parameter](commands/parameter.md) — 14 published commands
|
|
34
|
-
- [project](commands/project.md) —
|
|
34
|
+
- [project](commands/project.md) — 19 published commands
|
|
35
35
|
- [report](commands/report.md) — 1 published commands
|
|
36
36
|
- [schedule](commands/schedule.md) — 5 published commands
|
|
37
37
|
- [schema](commands/schema.md) — 3 published commands
|
|
@@ -62,6 +62,16 @@ Result: `ProjectDeleteResult`; mutation `high_impact`, confirmation `confirm_tar
|
|
|
62
62
|
|
|
63
63
|
Status on release: ran once on CLI 2.0.18 — fixture-lifecycle sweep 2026-09-19: exit 0 on release with CLI 2.0.18. Deleted project 41 (sweep-218-1224), read back with project get 41 beforehand. Single invocation only.
|
|
64
64
|
|
|
65
|
+
### `project.ensure`
|
|
66
|
+
|
|
67
|
+
Run: `mammoth project ensure`. Exact input fields: `mammoth schema get project.ensure --output json --no-input`.
|
|
68
|
+
|
|
69
|
+
Example: `mammoth project ensure 'Revenue report' --output json --no-input`. Placeholders are illustrative; resolve IDs and input from observed reads.
|
|
70
|
+
|
|
71
|
+
Result: `ProjectEnsureResult`; mutation `benign_mutation`, confirmation `none`, wait policy `not_async`.
|
|
72
|
+
|
|
73
|
+
Status on release: untried; no live run recorded.
|
|
74
|
+
|
|
65
75
|
### `project.get`
|
|
66
76
|
|
|
67
77
|
Run: `mammoth project get`. Exact input fields: `mammoth schema get project.get --output json --no-input`.
|
|
@@ -66,7 +66,7 @@ Status on release: ran once on CLI 2.0.14 — write sweep 2026-09-18: exit 0 on
|
|
|
66
66
|
|
|
67
67
|
Run: `mammoth view checkpoint create`. Exact input fields: `mammoth schema get view.checkpoint.create --output json --no-input`.
|
|
68
68
|
|
|
69
|
-
Example: `mammoth view checkpoint create 123 123 --input '{"body": {"checkpoint_name": "Revenue report", "checkpoint_type": "alert"}}' --output json --no-input`. Placeholders are illustrative; resolve IDs and input from observed reads.
|
|
69
|
+
Example: `mammoth view checkpoint create 123 123 --input '{"body": {"checkpoint_name": "Revenue report", "checkpoint_type": "alert", "pinned_to_end": true}}' --output json --no-input`. Placeholders are illustrative; resolve IDs and input from observed reads.
|
|
70
70
|
|
|
71
71
|
Result: `ViewCheckpointCreateResult`; mutation `benign_mutation`, confirmation `none`, wait policy `not_async`.
|
|
72
72
|
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Success envelope (stdout)
|
|
4
4
|
```json
|
|
5
|
-
{"schema_version": 1, "data": <result>, "meta": {"command": "project list", "profile": "default", "workspace_id": 4, "project_id": 180, "pagination": null}}
|
|
5
|
+
{"schema_version": 1, "data": <result>, "meta": {"command": "project list", "profile": "default", "workspace_id": 4, "project_id": 180, "pagination": null, "update_available": null}}
|
|
6
6
|
```
|
|
7
7
|
|
|
8
|
+
`meta.update_available` is `null` or `{"current", "latest", "command"}` when a
|
|
9
|
+
newer CLI is on PyPI (checked once a day, after a command, never blocking).
|
|
10
|
+
Run its `command` before starting a task, not in the middle of one.
|
|
11
|
+
|
|
8
12
|
## Error envelope (stderr)
|
|
9
13
|
```json
|
|
10
14
|
{"schema_version": 1, "error": {"code": "resource_not_found", "message": "...", "hint": "...", "details": {}, "request_id": null, "retryable": false, "authorization_required": false, "recovery_commands": ["..."], "log_ref": {"file": ".../logs/2026-09-19.jsonl", "run_id": "b6bc6bf6d166"}}}
|
|
@@ -11,7 +11,7 @@ mammoth doctor --output json --no-input # must succeed
|
|
|
11
11
|
mammoth project list --output json --no-input # baseline: ids that exist before you start
|
|
12
12
|
|
|
13
13
|
# 1. own project, upload, find the view ids
|
|
14
|
-
mammoth project
|
|
14
|
+
mammoth project ensure 'From Claude' --output json --no-input # -> PROJECT_ID (data.project_id; reused next time)
|
|
15
15
|
mammoth file upload orders.csv --project PROJECT_ID --output json --no-input # -> data.datasets[].id/status
|
|
16
16
|
mammoth file upload customers.csv --project PROJECT_ID --output json --no-input
|
|
17
17
|
# a dataset in need_action is not usable yet: follow need-action.md (file-settings update), then re-read
|
|
@@ -6,11 +6,30 @@ id instead. Run `view list DATASET_ID --project PROJECT_ID` to get it. Do not
|
|
|
6
6
|
dig through `dataset get` and its `dependencies` field for a view id; `view
|
|
7
7
|
list` is the supported route.
|
|
8
8
|
|
|
9
|
-
Discover exact contracts, then upload and read back explicit parents.
|
|
10
|
-
|
|
9
|
+
Discover exact contracts, then upload and read back explicit parents.
|
|
10
|
+
|
|
11
|
+
## Where uploads land
|
|
12
|
+
|
|
13
|
+
Unless the task names a project, work in one project of your own and put
|
|
14
|
+
every dataset of the task there, so the user's real projects stay clean and
|
|
15
|
+
one sweep removes everything. `project ensure` is idempotent get-or-create
|
|
16
|
+
by exact name: re-running it (or a second task) returns the same id
|
|
17
|
+
(`created: false`) instead of making another project. A one-off task can
|
|
18
|
+
still use `project create NAME` for a throwaway project.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
mammoth project ensure 'From Claude' --output json --no-input # -> data.project_id, data.created
|
|
22
|
+
mammoth project ensure 'From Claude' --output json --no-input # same id again, created: false
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Moving a dataset between projects is not a single API call on release;
|
|
26
|
+
re-upload into the target project when the task asks for that. To sweep the
|
|
27
|
+
working project when the task says it was temporary, delete it (one id per
|
|
28
|
+
call, read back) with `project delete ID --yes --confirm ID`; otherwise delete
|
|
29
|
+
only the datasets you created and leave the project for the next task.
|
|
11
30
|
|
|
12
31
|
```bash
|
|
13
|
-
mammoth project
|
|
32
|
+
mammoth project ensure 'PROJECT NAME' --output json --no-input
|
|
14
33
|
mammoth schema get file.upload --output json --no-input
|
|
15
34
|
mammoth file upload ./SOURCE.csv --project PROJECT_ID --output json --no-input
|
|
16
35
|
mammoth dataset list --project PROJECT_ID --output json --no-input
|
|
@@ -18,8 +37,31 @@ mammoth view list DATASET_ID --project PROJECT_ID --output json --no-input
|
|
|
18
37
|
mammoth view get VIEW_ID --project PROJECT_ID --output json --no-input
|
|
19
38
|
```
|
|
20
39
|
|
|
40
|
+
## What `file upload` accepts
|
|
41
|
+
|
|
42
|
+
`file upload` reads the file from local disk and streams it; nothing passes
|
|
43
|
+
through your context, so size costs nothing but time. Two boundaries hold:
|
|
44
|
+
|
|
45
|
+
- Format, by extension: `csv tsv psv txt xls xlsx xml pdf tiff jpeg jpg png
|
|
46
|
+
heic webp`, or an archive of those (`zip gz bz2 tar 7z`). `.json` is not
|
|
47
|
+
accepted; convert to CSV first. Other extensions fail before any upload.
|
|
48
|
+
- Size, at the ingress in front of the API: a 60 MB upload is refused with
|
|
49
|
+
HTTP 413 (`invalid_argument`, "larger than Mammoth accepts") before the API
|
|
50
|
+
sees it; 16 MB is accepted. The exact cap between those was not pinned
|
|
51
|
+
down. Keep one upload well under 16 MB: split a larger file by rows and
|
|
52
|
+
upload the parts, or compress it (a `.zip`/`.gz` of a CSV is accepted and
|
|
53
|
+
expanded server-side).
|
|
54
|
+
|
|
55
|
+
Scanning and parsing time grows with size; pass `--timeout 300` on anything
|
|
56
|
+
past a few MB and, when the command returns `timeout` with a `job_handle`,
|
|
57
|
+
poll with the `job get` recovery command it prints instead of uploading
|
|
58
|
+
again. A bare HTTP 500 from this route (`outcome_unknown`, empty body) means
|
|
59
|
+
the upload service is degraded; check `job get` for a job first, do not
|
|
60
|
+
retry in a loop.
|
|
61
|
+
|
|
21
62
|
`file upload` takes the local path as its positional argument; there is no
|
|
22
|
-
`--source`/`--file` option.
|
|
63
|
+
`--source`/`--file` option. A path that does not exist is a usage error
|
|
64
|
+
(`Local file not found`) before any request. Its result carries the status the platform holds
|
|
23
65
|
for each created dataset: `ready`, or `need_action` with a `next_command`, in
|
|
24
66
|
which case follow [need-action](need-action.md) before looking for a view. `dataset delete` is asynchronous: re-read
|
|
25
67
|
`dataset list` (the id disappears once the job completes) before reporting.
|
|
@@ -89,6 +89,12 @@ but the copy answers every read with `4DTVW019` and its copied tasks never
|
|
|
89
89
|
execute. A plain `view create DATASET_ID` (no `clone_from`) gives a fresh view
|
|
90
90
|
of the raw upload, without the pipeline:
|
|
91
91
|
|
|
92
|
+
Every pivot `as_name` must be a display name that does not already exist on
|
|
93
|
+
the view (`4DTVW018 Same display name cannot be reused`): to carry a joined
|
|
94
|
+
column such as `monthly_target` into the summary, aggregate it under a new
|
|
95
|
+
name (`{"column": "monthly_target", "function": "MAX", "as_name": "target"}`)
|
|
96
|
+
or use the SQL task with `MAX(monthly_target) AS monthly_target`.
|
|
97
|
+
|
|
92
98
|
```bash
|
|
93
99
|
mammoth schema get view.transform.pivot --output json --no-input
|
|
94
100
|
mammoth view transform add-sql VIEW_ID --project PROJECT_ID \
|
|
@@ -16,7 +16,9 @@ or secrets in an argument, prompt, transcript, or checkpoint.
|
|
|
16
16
|
Pin `mammoth-cli==X.Y.Z` when the task names an approved release. Use the
|
|
17
17
|
host installer script (`installers/mammoth-install.sh` in the repository)
|
|
18
18
|
only when the operator names it; do not pipe a remote script to a shell on
|
|
19
|
-
your own initiative. The SDK (`mammoth-io`) comes with the CLI.
|
|
19
|
+
your own initiative. The SDK (`mammoth-io`) comes with the CLI. If a later
|
|
20
|
+
envelope shows `meta.update_available`, run the `command` it names before
|
|
21
|
+
the next task step, then continue on the new version.
|
|
20
22
|
2. Locate the installed guidance with `mammoth skill path --output json
|
|
21
23
|
--no-input` and read `SKILL.md`; open a reference only when the routing
|
|
22
24
|
table sends you there. `references/commands/*.md` are per-command lookups,
|
|
@@ -20,7 +20,7 @@ from mammoth_cli import __version__
|
|
|
20
20
|
from mammoth_cli.context import credentials, profiles
|
|
21
21
|
from mammoth_cli.context.resolver import resolve_auth
|
|
22
22
|
from mammoth_cli.errors.envelope import CliError
|
|
23
|
-
from mammoth_cli.runtime import runlog
|
|
23
|
+
from mammoth_cli.runtime import runlog, updates
|
|
24
24
|
from mammoth_cli.runtime.invocation import Invocation
|
|
25
25
|
from mammoth_cli.runtime.session import open_service, resolved_project
|
|
26
26
|
|
|
@@ -57,15 +57,13 @@ def _safe_connection_diagnostics(error: CliError, *, debug: bool) -> dict[str, A
|
|
|
57
57
|
if isinstance(retry_after, str):
|
|
58
58
|
if len(retry_after) > 10 or not retry_after.isascii() or not retry_after.isdigit():
|
|
59
59
|
retry_after = None
|
|
60
|
-
elif (
|
|
61
|
-
not isinstance(retry_after, int)
|
|
62
|
-
or isinstance(retry_after, bool)
|
|
63
|
-
or retry_after < 0
|
|
64
|
-
):
|
|
60
|
+
elif not isinstance(retry_after, int) or isinstance(retry_after, bool) or retry_after < 0:
|
|
65
61
|
retry_after = None
|
|
66
62
|
request_id = error.request_id or raw.get("request_id")
|
|
67
|
-
if
|
|
68
|
-
|
|
63
|
+
if (
|
|
64
|
+
not isinstance(request_id, str)
|
|
65
|
+
or len(request_id) > 128
|
|
66
|
+
or not re.fullmatch(r"[A-Za-z0-9._:-]+", request_id)
|
|
69
67
|
):
|
|
70
68
|
request_id = None
|
|
71
69
|
|
|
@@ -166,6 +164,16 @@ def doctor(invocation: Invocation) -> HandlerResult:
|
|
|
166
164
|
)
|
|
167
165
|
)
|
|
168
166
|
|
|
167
|
+
latest = updates.latest_from_pypi()
|
|
168
|
+
if latest is None:
|
|
169
|
+
version_detail = f"{__version__} installed; PyPI not reachable to compare"
|
|
170
|
+
elif updates.is_newer(latest):
|
|
171
|
+
version_detail = f"{__version__} installed; {latest} available: {updates.UPGRADE_COMMAND}"
|
|
172
|
+
else:
|
|
173
|
+
version_detail = f"{__version__} installed; latest on PyPI"
|
|
174
|
+
# Informational: an older CLI still works, so the check never fails.
|
|
175
|
+
checks.append(_check("cli_version", True, version_detail))
|
|
176
|
+
|
|
169
177
|
record = profiles.get_profile(profile_name)
|
|
170
178
|
checks.append(
|
|
171
179
|
_check(
|
|
@@ -266,9 +274,7 @@ def doctor(invocation: Invocation) -> HandlerResult:
|
|
|
266
274
|
recommendations.append("mammoth context project use PROJECT_ID")
|
|
267
275
|
if not connection_ok and auth_ok and not invocation.debug:
|
|
268
276
|
debug_profile = f" --profile {shlex.quote(profile_name)}" if profile_name else ""
|
|
269
|
-
recommendations.append(
|
|
270
|
-
f"mammoth doctor --debug{debug_profile} --output json --no-input"
|
|
271
|
-
)
|
|
277
|
+
recommendations.append(f"mammoth doctor --debug{debug_profile} --output json --no-input")
|
|
272
278
|
|
|
273
279
|
data = {
|
|
274
280
|
"cli_version": __version__,
|
|
@@ -12,6 +12,7 @@ SDK method named by the command's reviewed manifest ``sdk_symbol``.
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
from collections.abc import Callable
|
|
15
|
+
from pathlib import Path
|
|
15
16
|
from typing import Any
|
|
16
17
|
|
|
17
18
|
from mammoth_cli.errors.envelope import (
|
|
@@ -213,6 +214,7 @@ def file_upload(invocation: Invocation) -> HandlerResult:
|
|
|
213
214
|
document,
|
|
214
215
|
**({"files": list(invocation.extra_args)} if invocation.extra_args else {}),
|
|
215
216
|
)
|
|
217
|
+
_require_local_files(kwargs.get("files"))
|
|
216
218
|
with open_service(invocation) as (service, auth):
|
|
217
219
|
data = service.call(_symbol(invocation), **kwargs)
|
|
218
220
|
# The SDK waits for the upload job and returns the created dataset
|
|
@@ -227,6 +229,31 @@ def file_upload(invocation: Invocation) -> HandlerResult:
|
|
|
227
229
|
return result, _meta(invocation, auth.workspace_id, resolved_project(invocation))
|
|
228
230
|
|
|
229
231
|
|
|
232
|
+
def _require_local_files(files: Any) -> None:
|
|
233
|
+
"""Fail as a usage error, naming the path, when a local file is missing.
|
|
234
|
+
|
|
235
|
+
The SDK raises a bare ``ValueError`` for an unreadable path, which the
|
|
236
|
+
generic mapping renders as an opaque ``api_error``; a relative path from
|
|
237
|
+
the wrong working directory is the usual cause and must say so.
|
|
238
|
+
"""
|
|
239
|
+
candidates = files if isinstance(files, list) else [files] if files else []
|
|
240
|
+
for candidate in candidates:
|
|
241
|
+
if not isinstance(candidate, str):
|
|
242
|
+
continue
|
|
243
|
+
path = Path(candidate).expanduser()
|
|
244
|
+
if not path.is_file():
|
|
245
|
+
raise CliError(
|
|
246
|
+
code=CODE_INVALID_ARGUMENT,
|
|
247
|
+
message=f"Local file not found: {candidate}",
|
|
248
|
+
exit_status=EXIT_USAGE,
|
|
249
|
+
hint=(
|
|
250
|
+
f"Resolved against the working directory {Path.cwd()}; pass an absolute "
|
|
251
|
+
"path or run the command from the directory that holds the file."
|
|
252
|
+
),
|
|
253
|
+
details={"path": candidate, "cwd": str(Path.cwd())},
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
230
257
|
_DATASET_GET_SYMBOL = "mammoth.api.datasets.DatasetsAPI.get"
|
|
231
258
|
|
|
232
259
|
|
|
@@ -14,6 +14,7 @@ from __future__ import annotations
|
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
16
|
from mammoth_cli.errors.envelope import (
|
|
17
|
+
CODE_CONFLICT,
|
|
17
18
|
CODE_INVALID_ARGUMENT,
|
|
18
19
|
CODE_MISSING_ARGUMENT,
|
|
19
20
|
CODE_MISSING_FIELD,
|
|
@@ -216,6 +217,76 @@ def project_create(invocation: Invocation) -> HandlerResult:
|
|
|
216
217
|
return data, _meta(invocation, auth.workspace_id, resolved_project(invocation))
|
|
217
218
|
|
|
218
219
|
|
|
220
|
+
#: The projects route caps ``limit`` at 100 (backend 4GENR007 above it) and
|
|
221
|
+
#: the SDK exposes no offset, so this is the largest listing one call can see.
|
|
222
|
+
_ENSURE_PROJECT_LIST_LIMIT = 100
|
|
223
|
+
_ENSURE_CREATE_SYMBOL = "mammoth.api.projects.ProjectsAPI.create"
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def project_ensure(invocation: Invocation) -> HandlerResult:
|
|
227
|
+
"""Return the project with exactly this name, creating it when absent.
|
|
228
|
+
|
|
229
|
+
Idempotent get-or-create for a scratch or working project (the "From
|
|
230
|
+
Claude" convention: pick one project once, land every task's datasets
|
|
231
|
+
there, sweep it with ``project delete``). Matching is exact and
|
|
232
|
+
case-sensitive on the name; when several projects share the name the
|
|
233
|
+
lowest id wins and ``duplicates`` lists the rest, so a re-run never
|
|
234
|
+
creates a second one.
|
|
235
|
+
"""
|
|
236
|
+
document = invocation.load_input() or {}
|
|
237
|
+
name = _string_positional(invocation) or document.get("name")
|
|
238
|
+
if not isinstance(name, str) or not name.strip():
|
|
239
|
+
raise CliError(
|
|
240
|
+
code=CODE_MISSING_ARGUMENT,
|
|
241
|
+
message="A project name is required.",
|
|
242
|
+
exit_status=EXIT_USAGE,
|
|
243
|
+
hint="Pass the name as a positional argument or a 'name' input field.",
|
|
244
|
+
)
|
|
245
|
+
with open_service(invocation) as (service, auth):
|
|
246
|
+
listing = service.list_projects(limit=_ENSURE_PROJECT_LIST_LIMIT)
|
|
247
|
+
projects = list(listing.get("projects", [])) if isinstance(listing, dict) else []
|
|
248
|
+
same_name = sorted(
|
|
249
|
+
(p for p in projects if isinstance(p, dict) and p.get("name") == name),
|
|
250
|
+
key=lambda p: int(p.get("id") or 0),
|
|
251
|
+
)
|
|
252
|
+
if same_name:
|
|
253
|
+
chosen = same_name[0]
|
|
254
|
+
data: dict[str, Any] = {
|
|
255
|
+
"project": chosen,
|
|
256
|
+
"project_id": chosen.get("id"),
|
|
257
|
+
"created": False,
|
|
258
|
+
"duplicates": [p.get("id") for p in same_name[1:]],
|
|
259
|
+
}
|
|
260
|
+
return data, _meta(invocation, auth.workspace_id, chosen.get("id"))
|
|
261
|
+
truncated = bool(listing.get("next")) if isinstance(listing, dict) else False
|
|
262
|
+
if truncated or len(projects) >= _ENSURE_PROJECT_LIST_LIMIT:
|
|
263
|
+
# A name beyond the first page may exist; creating blindly would
|
|
264
|
+
# break the idempotency this command promises.
|
|
265
|
+
raise CliError(
|
|
266
|
+
code=CODE_CONFLICT,
|
|
267
|
+
message=(
|
|
268
|
+
f"Workspace has more than {_ENSURE_PROJECT_LIST_LIMIT} projects; "
|
|
269
|
+
f"cannot prove {name!r} is absent."
|
|
270
|
+
),
|
|
271
|
+
exit_status=EXIT_USAGE,
|
|
272
|
+
hint="Find the project with 'project list' and pass --project, "
|
|
273
|
+
"or create it explicitly with 'project create'.",
|
|
274
|
+
details={"listed": len(projects)},
|
|
275
|
+
)
|
|
276
|
+
created = service.call(_ENSURE_CREATE_SYMBOL, name=name)
|
|
277
|
+
record = created.get("project", created) if isinstance(created, dict) else {}
|
|
278
|
+
project_id = record.get("id") if isinstance(record, dict) else None
|
|
279
|
+
if project_id is None and isinstance(created, dict):
|
|
280
|
+
project_id = created.get("project_id") or created.get("id")
|
|
281
|
+
data = {
|
|
282
|
+
"project": record if isinstance(record, dict) else created,
|
|
283
|
+
"project_id": project_id,
|
|
284
|
+
"created": True,
|
|
285
|
+
"duplicates": [],
|
|
286
|
+
}
|
|
287
|
+
return data, _meta(invocation, auth.workspace_id, project_id)
|
|
288
|
+
|
|
289
|
+
|
|
219
290
|
def project_update(invocation: Invocation) -> HandlerResult:
|
|
220
291
|
"""Update a project's name or color from the ``--input`` document."""
|
|
221
292
|
project_id = _project_id(invocation)
|
|
@@ -187,6 +187,7 @@ HANDLERS: dict[str, Handler] = {
|
|
|
187
187
|
"project.publish-credentials": project_cmd.project_publish_credentials,
|
|
188
188
|
# project family (mutations)
|
|
189
189
|
"project.create": project_cmd.project_create,
|
|
190
|
+
"project.ensure": project_cmd.project_ensure,
|
|
190
191
|
"project.update": project_cmd.project_update,
|
|
191
192
|
"project.delete": project_cmd.project_delete,
|
|
192
193
|
"project.bulk-delete": project_cmd.project_bulk_delete,
|
|
@@ -166,9 +166,12 @@ def build_upgrade_command(manager: str, target_version: str | None) -> list[str]
|
|
|
166
166
|
return [sys.executable, "-m", "pip", "install", "--upgrade", PACKAGE_NAME]
|
|
167
167
|
|
|
168
168
|
|
|
169
|
-
def
|
|
169
|
+
def run_upgrade(command: list[str]) -> subprocess.CompletedProcess[str]:
|
|
170
170
|
"""Run the upgrade command as a subprocess, capturing its output.
|
|
171
171
|
|
|
172
|
+
Public so the opt-in automatic upgrade (:mod:`mammoth_cli.runtime.updates`)
|
|
173
|
+
goes through the same seam tests patch here.
|
|
174
|
+
|
|
172
175
|
Raises:
|
|
173
176
|
CliError: ``upgrade_failed`` when the command cannot be launched.
|
|
174
177
|
"""
|
|
@@ -269,7 +272,7 @@ def perform(invocation: Invocation, *, check: bool, target_version: str | None)
|
|
|
269
272
|
policy=POLICY_PROMPT_OR_YES,
|
|
270
273
|
action=f"upgrade {PACKAGE_NAME} to {action_target} using {manager}",
|
|
271
274
|
)
|
|
272
|
-
result =
|
|
275
|
+
result = run_upgrade(command)
|
|
273
276
|
if result.returncode != 0:
|
|
274
277
|
raise CliError(
|
|
275
278
|
code="upgrade_failed",
|
|
@@ -17,6 +17,9 @@ class Meta:
|
|
|
17
17
|
workspace_id: int | None = None
|
|
18
18
|
project_id: int | None = None
|
|
19
19
|
pagination: dict[str, Any] | None = None
|
|
20
|
+
#: ``{"current", "latest", "command"}`` when a newer CLI is on PyPI
|
|
21
|
+
#: (from the daily cached check), else None.
|
|
22
|
+
update_available: dict[str, Any] | None = None
|
|
20
23
|
|
|
21
24
|
def to_dict(self) -> dict[str, Any]:
|
|
22
25
|
return {
|
|
@@ -25,6 +28,7 @@ class Meta:
|
|
|
25
28
|
"workspace_id": self.workspace_id,
|
|
26
29
|
"project_id": self.project_id,
|
|
27
30
|
"pagination": self.pagination,
|
|
31
|
+
"update_available": self.update_available,
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
|
|
@@ -20,6 +20,7 @@ from mammoth_cli.errors.envelope import EXIT_USAGE, CliError
|
|
|
20
20
|
from mammoth_cli.output.envelope import Meta, Result
|
|
21
21
|
from mammoth_cli.output.policy import MACHINE_OUTPUTS, VALID_OUTPUTS
|
|
22
22
|
from mammoth_cli.output.render import render
|
|
23
|
+
from mammoth_cli.runtime import updates
|
|
23
24
|
from mammoth_cli.runtime.invocation import Invocation
|
|
24
25
|
from mammoth_cli.runtime.runlog import RunLog
|
|
25
26
|
from mammoth_cli.services.mapping import map_sdk_exception
|
|
@@ -73,6 +74,7 @@ def emit_success(
|
|
|
73
74
|
workspace_id: int | None = None,
|
|
74
75
|
project_id: int | None = None,
|
|
75
76
|
pagination: dict[str, Any] | None = None,
|
|
77
|
+
update_available: dict[str, Any] | None = None,
|
|
76
78
|
) -> None:
|
|
77
79
|
"""Render one success envelope to stdout.
|
|
78
80
|
|
|
@@ -85,6 +87,7 @@ def emit_success(
|
|
|
85
87
|
workspace_id: The resolved workspace id, if any.
|
|
86
88
|
project_id: The resolved project id, if any.
|
|
87
89
|
pagination: Pagination metadata, if any.
|
|
90
|
+
update_available: The cached newer-release notice, if any.
|
|
88
91
|
"""
|
|
89
92
|
meta = Meta(
|
|
90
93
|
command=command_id.replace(".", " "),
|
|
@@ -92,6 +95,7 @@ def emit_success(
|
|
|
92
95
|
workspace_id=workspace_id,
|
|
93
96
|
project_id=project_id,
|
|
94
97
|
pagination=pagination,
|
|
98
|
+
update_available=update_available,
|
|
95
99
|
)
|
|
96
100
|
envelope = Result(data=data, meta=meta).to_envelope()
|
|
97
101
|
render(envelope, output=output)
|
|
@@ -171,10 +175,15 @@ def run(
|
|
|
171
175
|
run_log.finish(error.exit_status, error_code=error.code)
|
|
172
176
|
emit_error(error, machine=machine_error, output=output)
|
|
173
177
|
|
|
178
|
+
# The update notice is read from the daily cache (no network); the cache
|
|
179
|
+
# itself is refreshed only after the command has produced its output.
|
|
180
|
+
update = updates.available_update(command_id)
|
|
174
181
|
try:
|
|
175
182
|
_validate_output(output)
|
|
183
|
+
updates.auto_upgrade(command_id, run_log)
|
|
176
184
|
data, meta_extra = producer()
|
|
177
|
-
emit_success(command_id, data, output, **meta_extra)
|
|
185
|
+
emit_success(command_id, data, output, update_available=update, **meta_extra)
|
|
186
|
+
updates.emit_hint(update, output=output)
|
|
178
187
|
except CliError as error:
|
|
179
188
|
fail(error)
|
|
180
189
|
raise typer.Exit(error.exit_status) from None
|
|
@@ -194,6 +203,7 @@ def run(
|
|
|
194
203
|
raise typer.Exit(mapped_error.exit_status) from None
|
|
195
204
|
if run_log is not None:
|
|
196
205
|
run_log.finish(0)
|
|
206
|
+
updates.refresh_if_stale(command_id)
|
|
197
207
|
|
|
198
208
|
|
|
199
209
|
def _open_run_log(command_id: str, invocation: Invocation | None) -> RunLog | None:
|
|
@@ -60,6 +60,7 @@ CODE_INVALID_INPUT_FIELD_TYPE = "invalid_input_field_type"
|
|
|
60
60
|
_TRUE_STRINGS = frozenset({"true", "1", "yes", "y", "on"})
|
|
61
61
|
_FALSE_STRINGS = frozenset({"false", "0", "no", "n", "off"})
|
|
62
62
|
|
|
63
|
+
|
|
63
64
|
def _unknown_option_hint(command_id: str, token: str) -> tuple[str, dict[str, Any]]:
|
|
64
65
|
"""Name the accepted form when an unknown ``--option`` matches a real field.
|
|
65
66
|
|
|
@@ -138,8 +139,7 @@ def _invalid_field_type_error(command_id: str, field: str, value: Any, expected:
|
|
|
138
139
|
return CliError(
|
|
139
140
|
code=CODE_INVALID_INPUT_FIELD_TYPE,
|
|
140
141
|
message=(
|
|
141
|
-
f"Input field '{field}' for '{command_id.replace('.', ' ')}' must be a "
|
|
142
|
-
f"{expected}."
|
|
142
|
+
f"Input field '{field}' for '{command_id.replace('.', ' ')}' must be a " f"{expected}."
|
|
143
143
|
),
|
|
144
144
|
exit_status=EXIT_USAGE,
|
|
145
145
|
hint=f"Pass '{field}' as a {expected} value.",
|
|
@@ -193,6 +193,30 @@ def _coerce_float(value: Any, *, command_id: str, field: str) -> float:
|
|
|
193
193
|
raise _invalid_field_type_error(command_id, field, value, "number")
|
|
194
194
|
|
|
195
195
|
|
|
196
|
+
def _relax_numeric_oneof(schema: Any) -> Any:
|
|
197
|
+
"""Turn ``oneOf: [number, integer, ...]`` into ``anyOf`` throughout ``schema``.
|
|
198
|
+
|
|
199
|
+
The backend's generated schemas declare numeric fields (``threshold`` on a
|
|
200
|
+
data check, for one) as ``oneOf`` over ``number`` and ``integer``. An
|
|
201
|
+
integral value satisfies both branches, so strict ``oneOf`` rejects
|
|
202
|
+
exactly the values the backend accepts (``5`` fails, ``0.5`` passes).
|
|
203
|
+
The intent is clearly "any of these"; validate it that way.
|
|
204
|
+
"""
|
|
205
|
+
if isinstance(schema, list):
|
|
206
|
+
return [_relax_numeric_oneof(item) for item in schema]
|
|
207
|
+
if not isinstance(schema, dict):
|
|
208
|
+
return schema
|
|
209
|
+
relaxed: dict[str, Any] = {}
|
|
210
|
+
for key, value in schema.items():
|
|
211
|
+
if key == "oneOf" and isinstance(value, list):
|
|
212
|
+
types = {b.get("type") for b in value if isinstance(b, dict)}
|
|
213
|
+
if {"number", "integer"} <= types:
|
|
214
|
+
relaxed["anyOf"] = _relax_numeric_oneof(value)
|
|
215
|
+
continue
|
|
216
|
+
relaxed[key] = _relax_numeric_oneof(value)
|
|
217
|
+
return relaxed
|
|
218
|
+
|
|
219
|
+
|
|
196
220
|
def _coerce_document_fields(
|
|
197
221
|
command_id: str,
|
|
198
222
|
document: dict[str, Any],
|
|
@@ -208,15 +232,12 @@ def _coerce_document_fields(
|
|
|
208
232
|
key == "body"
|
|
209
233
|
and is_opaque_mapping(field.annotation)
|
|
210
234
|
and input_schema is not None
|
|
211
|
-
and (
|
|
212
|
-
body_schema := input_schema.get("properties", {}).get("body")
|
|
213
|
-
)
|
|
214
|
-
is not None
|
|
235
|
+
and (body_schema := input_schema.get("properties", {}).get("body")) is not None
|
|
215
236
|
):
|
|
216
237
|
from jsonschema import ValidationError, validate # type: ignore[import-untyped]
|
|
217
238
|
|
|
218
239
|
try:
|
|
219
|
-
validate(document[key], thaw_contract_metadata(body_schema))
|
|
240
|
+
validate(document[key], _relax_numeric_oneof(thaw_contract_metadata(body_schema)))
|
|
220
241
|
except ValidationError as error:
|
|
221
242
|
path = ".".join(str(part) for part in error.absolute_path)
|
|
222
243
|
field_path = f"body.{path}" if path else "body"
|