mammoth-cli 2.1.4__tar.gz → 2.1.5__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.1.4 → mammoth_cli-2.1.5}/PKG-INFO +2 -2
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/__init__.py +1 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +5 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/activity.py +85 -2
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/dashboard.py +41 -2
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/dataset.py +41 -13
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/folder.py +64 -8
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/project.py +174 -53
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/view.py +69 -12
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/view_ops.py +5 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/view_profile.py +3 -2
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/listing.py +53 -9
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/read_queries.py +82 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/sdk_service.py +5 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/write_impact.py +85 -7
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/pyproject.toml +2 -2
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/dashboard.yaml +3 -3
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/dataset.yaml +1 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/file.yaml +4 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/folder.yaml +2 -2
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/project.yaml +1 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/sdk-methods.yaml +1 -1
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/.gitignore +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/LICENSE +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/README.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/__main__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/app.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-style.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/addon.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/agent.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/ai.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/annotation.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/auth.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/automation.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/batch.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/billing.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/browse.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/calc.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/capability.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/client_app.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/completion.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/config.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/connector.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/context.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/data_app.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/doctor.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/external_key.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/file.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/job.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/notification.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/parameter.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/registry.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/report.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/schedule.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/schema.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/skill.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/snippet.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/support.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/template.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/trash.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/upgrade.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/user.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/webhook.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/workflow.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/commands/workspace.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/context/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/context/credentials.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/context/endpoint.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/context/profiles.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/context/resolver.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/contracts/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/contracts/auth.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/embed.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/errors/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/errors/envelope.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/manifest/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/manifest/loader.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/messages/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/output/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/output/envelope.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/output/normalize.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/output/policy.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/output/progress.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/output/render.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/py.typed +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/confirm.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/dataset_health.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/dryrun.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/dryrun_targets.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/embedded.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/executor.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/input_loader.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/intent_only.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/invocation.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/new_data.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/options.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/parents.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/runlog.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/session.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/state.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/strict.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/updates.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/validate.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/runtime/verify.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/argspec.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/board_values.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/coerce.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/command_contract.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/conditions.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/dashboard_filters.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/dashboard_pages.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/dashboard_review.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/data_profile.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/data_quality.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/dispatch.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/factory.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/input_fields.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/mapping.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/openapi_types.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/positionals.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/protocol.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/stored_stats.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/testing.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/text_dates.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/services/type_system.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/skills/__init__.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/skills/installer.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/skills/steering.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/mammoth_cli/testing.py +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/activity.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/addon.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/agent.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/ai.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/annotation.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/auth.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/automation.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/batch.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/billing.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/browse.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/calc.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/capability.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/client-app.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/completion.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/config.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/connector.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/context.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/data-app.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/doctor.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/external-key.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/job.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/log.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/notification.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/parameter.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/report.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/schedule.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/schema.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/skill.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/snippet.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/support.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/template.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/trash.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/upgrade.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/user.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/version.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/view.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/webhook.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/workflow.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/commands/workspace.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/edits-target.source.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/openapi-operations.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/schema-v1.json +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/manifests/sdk-catalog.source.yaml +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/openapi/metadata.json +0 -0
- {mammoth_cli-2.1.4 → mammoth_cli-2.1.5}/spec/openapi/openapi.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mammoth-cli
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.5
|
|
4
4
|
Summary: Command-line interface for the Mammoth Analytics platform
|
|
5
5
|
Project-URL: homepage, https://mammoth.io
|
|
6
6
|
Project-URL: repository, https://github.com/EdgeMetric/mammothsdk
|
|
@@ -17,7 +17,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
17
17
|
Requires-Python: <3.15,>=3.12
|
|
18
18
|
Requires-Dist: jsonschema>=4.20
|
|
19
19
|
Requires-Dist: keyring<26,>=25.7
|
|
20
|
-
Requires-Dist: mammoth-io<0.9,>=0.8.
|
|
20
|
+
Requires-Dist: mammoth-io<0.9,>=0.8.2
|
|
21
21
|
Requires-Dist: platformdirs<5,>=4.10
|
|
22
22
|
Requires-Dist: pydantic<3,>=2.12.5
|
|
23
23
|
Requires-Dist: pyyaml<7,>=6
|
|
@@ -23,6 +23,11 @@ request:
|
|
|
23
23
|
an id you already have (for example from a dataset's own automation/task
|
|
24
24
|
metadata) instead.
|
|
25
25
|
|
|
26
|
+
PDF or image intake (`append_data` + `new_data_addition_in_folder`) needs one
|
|
27
|
+
destination dataset that already has a saved extraction recipe and a name
|
|
28
|
+
pattern the file name matches; a password-protected or unreadable file holds
|
|
29
|
+
for input. Read `automation capabilities` before you promise it.
|
|
30
|
+
|
|
26
31
|
`schema find "recurring work"` phrasing (e.g. "schedule a daily refresh",
|
|
27
32
|
"run every week automatically") resolves to `automation create`.
|
|
28
33
|
|
|
@@ -12,6 +12,7 @@ public SDK method named by the command's reviewed manifest ``sdk_symbol``.
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
|
+
from datetime import UTC, datetime
|
|
15
16
|
from typing import Any
|
|
16
17
|
|
|
17
18
|
from mammoth_cli.errors.envelope import (
|
|
@@ -157,14 +158,96 @@ def _meta(invocation: Invocation, workspace_id: int, project_id: int | None) ->
|
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
|
|
161
|
+
_WORKSPACE_USERS_SYMBOL = "mammoth.api.workspace.WorkspaceAPI.list_users"
|
|
162
|
+
_TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
|
|
163
|
+
_EPOCH = "1970-01-01 00:00:00"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _close_time_window(kwargs: dict[str, Any]) -> str | None:
|
|
167
|
+
"""Give a lone ``start_time`` or ``end_time`` its missing bound; say so.
|
|
168
|
+
|
|
169
|
+
The backend applies the time filter only when BOTH bounds are present
|
|
170
|
+
(activity_logs/manager.py ``_get_time_filters``) and otherwise lists the
|
|
171
|
+
latest entries of all time -- so "what changed today" with only a
|
|
172
|
+
``start_time`` answered from the wrong window.
|
|
173
|
+
"""
|
|
174
|
+
start, end = kwargs.get("start_time"), kwargs.get("end_time")
|
|
175
|
+
if bool(start) == bool(end):
|
|
176
|
+
return None
|
|
177
|
+
if start:
|
|
178
|
+
kwargs["end_time"] = datetime.now(UTC).strftime(_TIME_FORMAT)
|
|
179
|
+
return f"end_time was not given; the window runs to now ({kwargs['end_time']} UTC)."
|
|
180
|
+
kwargs["start_time"] = _EPOCH
|
|
181
|
+
return f"start_time was not given; the window starts at {_EPOCH} UTC."
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _local_time(stamp: Any) -> str | None:
|
|
185
|
+
"""A ``created_at`` (UTC if it has no offset) as ISO in this machine's timezone."""
|
|
186
|
+
if not isinstance(stamp, str):
|
|
187
|
+
return None
|
|
188
|
+
try:
|
|
189
|
+
moment = datetime.fromisoformat(stamp)
|
|
190
|
+
except ValueError:
|
|
191
|
+
return stamp
|
|
192
|
+
if moment.tzinfo is None:
|
|
193
|
+
moment = moment.replace(tzinfo=UTC)
|
|
194
|
+
return moment.astimezone().isoformat(timespec="seconds")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _user_emails(service: Any) -> dict[Any, str]:
|
|
198
|
+
"""Workspace users by id; empty when the caller may not list them."""
|
|
199
|
+
try:
|
|
200
|
+
users = service.call(_WORKSPACE_USERS_SYMBOL)
|
|
201
|
+
except Exception: # noqa: BLE001 -- a name is a convenience; the id is always shown
|
|
202
|
+
return {}
|
|
203
|
+
return {u["id"]: u["email"] for u in users if isinstance(u, dict) and u.get("email")}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _change(entry: dict[str, Any], emails: dict[Any, str]) -> dict[str, Any]:
|
|
207
|
+
"""One log entry as a line of a change list: when, who, what, on which object."""
|
|
208
|
+
details = entry.get("details") if isinstance(entry.get("details"), dict) else {}
|
|
209
|
+
primary = entry.get("primary_object") if isinstance(entry.get("primary_object"), dict) else {}
|
|
210
|
+
user_id = entry.get("user_id")
|
|
211
|
+
change = {
|
|
212
|
+
"when": _local_time(entry.get("created_at")),
|
|
213
|
+
"user_id": user_id,
|
|
214
|
+
"user": emails.get(user_id),
|
|
215
|
+
"action": entry.get("name_key"),
|
|
216
|
+
"category": entry.get("category"),
|
|
217
|
+
"object": {"name": primary.get("name"), "resource_id": primary.get("resource_id")},
|
|
218
|
+
"result": entry.get("result"),
|
|
219
|
+
}
|
|
220
|
+
if details.get("task_name"):
|
|
221
|
+
change["task"] = details["task_name"]
|
|
222
|
+
return change
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _with_changes(service: Any, data: Any, note: str | None) -> Any:
|
|
226
|
+
"""Add ``changes``: each entry with its time, user and action (no entry dropped)."""
|
|
227
|
+
logs = data.get("activity_logs") if isinstance(data, dict) else None
|
|
228
|
+
if not isinstance(logs, list):
|
|
229
|
+
return data
|
|
230
|
+
emails = _user_emails(service)
|
|
231
|
+
changes = [_change(entry, emails) for entry in logs if isinstance(entry, dict)]
|
|
232
|
+
extra = {"time_window_note": note} if note else {}
|
|
233
|
+
return {**data, "changes": changes, **extra}
|
|
234
|
+
|
|
235
|
+
|
|
160
236
|
def activity_list(invocation: Invocation) -> HandlerResult:
|
|
161
|
-
"""List activity logs in the active workspace, with optional filters.
|
|
237
|
+
"""List activity logs in the active workspace, with optional filters.
|
|
238
|
+
|
|
239
|
+
``changes`` lists each entry with its ``when`` (ISO, this machine's UTC
|
|
240
|
+
offset), ``user_id`` and ``user``, ``action``, ``object`` and ``result``,
|
|
241
|
+
so "who changed this view today" is answered from the list, not from its
|
|
242
|
+
absence.
|
|
243
|
+
"""
|
|
162
244
|
document = _bound_document(invocation)
|
|
163
245
|
_refuse_bare_resource_id(document)
|
|
164
246
|
kwargs: dict[str, Any] = {}
|
|
165
247
|
_forward_optional(document, kwargs, _LIST_OPTIONAL)
|
|
248
|
+
note = _close_time_window(kwargs)
|
|
166
249
|
with open_service(invocation) as (service, auth):
|
|
167
|
-
data = service.call(_symbol(invocation), **kwargs)
|
|
250
|
+
data = _with_changes(service, service.call(_symbol(invocation), **kwargs), note)
|
|
168
251
|
return data, _meta(invocation, auth.workspace_id, resolved_project(invocation))
|
|
169
252
|
|
|
170
253
|
|
|
@@ -17,7 +17,7 @@ from typing import Any, Literal, cast
|
|
|
17
17
|
from mammoth.models.dashboards import AddPagesSpec
|
|
18
18
|
from pydantic import ValidationError
|
|
19
19
|
|
|
20
|
-
from mammoth_cli.commands.view import view_profiles
|
|
20
|
+
from mammoth_cli.commands.view import _FIND_DATASET_SYMBOL, view_profiles
|
|
21
21
|
from mammoth_cli.context import profiles
|
|
22
22
|
from mammoth_cli.errors.envelope import (
|
|
23
23
|
CODE_INVALID_ARGUMENT,
|
|
@@ -392,9 +392,48 @@ def dashboard_get(invocation: Invocation) -> HandlerResult:
|
|
|
392
392
|
if not invocation.readback:
|
|
393
393
|
data = _with_board_values(service, auth, {"dashboard_id": dashboard_id}, data)
|
|
394
394
|
data = _with_board_project(data)
|
|
395
|
+
data = _with_source_datasets(service, invocation, auth.workspace_id, data)
|
|
395
396
|
return data, _meta(invocation, auth.workspace_id)
|
|
396
397
|
|
|
397
398
|
|
|
399
|
+
def _source_dataset(service: Any, invocation: Invocation, workspace_id: Any, view_id: int) -> Any:
|
|
400
|
+
"""The dataset that owns ``view_id``: remembered, else looked up; never raises."""
|
|
401
|
+
profile_name = invocation.profile or profiles.get_selected()
|
|
402
|
+
remembered = parents.lookup(profile_name, workspace_id, view_id)
|
|
403
|
+
if remembered is not None:
|
|
404
|
+
return {"view_id": view_id, "dataset_id": remembered}
|
|
405
|
+
try:
|
|
406
|
+
dataset_id = int(service.call(_FIND_DATASET_SYMBOL, dataview_id=view_id))
|
|
407
|
+
except Exception as exc: # noqa: BLE001 -- one unreadable source must not hide the others
|
|
408
|
+
return {"view_id": view_id, "dataset_id": None, "error": f"{type(exc).__name__}: {exc}"}
|
|
409
|
+
parents.remember(profile_name, workspace_id, {view_id: dataset_id})
|
|
410
|
+
return {"view_id": view_id, "dataset_id": dataset_id}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _with_source_datasets(
|
|
414
|
+
service: Any, invocation: Invocation, workspace_id: Any, data: Any
|
|
415
|
+
) -> Any:
|
|
416
|
+
"""Label each source: a board's ``sources`` are VIEW ids, never dataset ids.
|
|
417
|
+
|
|
418
|
+
An agent read 3882 from ``sources`` as a dataset id and got a 403
|
|
419
|
+
(RT21-01). ``source_views`` gives each source's ``view_id`` and the
|
|
420
|
+
``dataset_id`` that owns it.
|
|
421
|
+
"""
|
|
422
|
+
sources = data.get("sources") if isinstance(data, dict) else None
|
|
423
|
+
if not isinstance(sources, list) or not sources:
|
|
424
|
+
return data
|
|
425
|
+
views = [
|
|
426
|
+
_source_dataset(service, invocation, workspace_id, view_id)
|
|
427
|
+
for view_id in sources
|
|
428
|
+
if isinstance(view_id, int)
|
|
429
|
+
]
|
|
430
|
+
return {
|
|
431
|
+
**data,
|
|
432
|
+
"source_views": views,
|
|
433
|
+
"sources_note": "sources are view ids; use a source's dataset_id for dataset commands.",
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
|
|
398
437
|
def _with_board_project(data: Any) -> Any:
|
|
399
438
|
"""Name the project the board lives in; ``None`` when the backend does not say."""
|
|
400
439
|
data = _dump_model(data)
|
|
@@ -714,7 +753,7 @@ def _with_board_values(service: Any, auth: Any, positionals: dict[str, Any], dat
|
|
|
714
753
|
data = _dump_model(data)
|
|
715
754
|
if not isinstance(data, dict):
|
|
716
755
|
return data
|
|
717
|
-
dashboard_id = positionals.get("dashboard_id") or data.get("id")
|
|
756
|
+
dashboard_id = positionals.get("dashboard_id") or data.get("id")
|
|
718
757
|
if not isinstance(dashboard_id, int):
|
|
719
758
|
return {**data, "values": {"unavailable": "the result names no dashboard id"}}
|
|
720
759
|
return {
|
|
@@ -32,8 +32,10 @@ from mammoth_cli.runtime.new_data import with_file_upload_path
|
|
|
32
32
|
from mammoth_cli.runtime.session import open_service, require_project
|
|
33
33
|
from mammoth_cli.services.listing import (
|
|
34
34
|
DATASET_LIST_FIELDS,
|
|
35
|
+
ambiguity_note,
|
|
35
36
|
dataset_summary,
|
|
36
37
|
fit_budget,
|
|
38
|
+
name_hit,
|
|
37
39
|
search_page,
|
|
38
40
|
)
|
|
39
41
|
|
|
@@ -170,16 +172,31 @@ def _find_in_projects(
|
|
|
170
172
|
{
|
|
171
173
|
"project_id": project_id,
|
|
172
174
|
"project_name": project.get("name"),
|
|
173
|
-
|
|
174
|
-
"name": name,
|
|
175
|
+
**name_hit(dataset),
|
|
175
176
|
}
|
|
176
177
|
)
|
|
177
178
|
return matches
|
|
178
179
|
|
|
179
180
|
|
|
180
|
-
def _other_projects(
|
|
181
|
+
def _other_projects(visible: list[dict[str, Any]], project_id: int) -> list[dict[str, Any]]:
|
|
181
182
|
"""Every visible project except ``project_id``."""
|
|
182
|
-
return [p for p in
|
|
183
|
+
return [p for p in visible if p.get("id") != project_id]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def named_project(service: Any, project_id: int, visible: list[dict[str, Any]]) -> dict[str, Any]:
|
|
187
|
+
"""``{"id", "name"}`` of ``project_id``, so a match can say where it was found.
|
|
188
|
+
|
|
189
|
+
A search scoped by ``--project`` knew only the id, and its matches came back
|
|
190
|
+
with ``project_name: None``: the agent could not tell the user which project
|
|
191
|
+
held the dataset.
|
|
192
|
+
"""
|
|
193
|
+
for project in visible:
|
|
194
|
+
if project.get("id") == project_id:
|
|
195
|
+
return project
|
|
196
|
+
record = service.call("mammoth.api.projects.ProjectsAPI.get", project_id=project_id)
|
|
197
|
+
record = record.model_dump(mode="json") if hasattr(record, "model_dump") else record
|
|
198
|
+
record = record.get("project", record) if isinstance(record, dict) else {}
|
|
199
|
+
return {"id": project_id, "name": record.get("name")}
|
|
183
200
|
|
|
184
201
|
|
|
185
202
|
def dataset_find(invocation: Invocation) -> HandlerResult:
|
|
@@ -195,26 +212,30 @@ def dataset_find(invocation: Invocation) -> HandlerResult:
|
|
|
195
212
|
name_substring = _require_string_positional(invocation, "name substring")
|
|
196
213
|
needle = name_substring.lower()
|
|
197
214
|
with open_service(invocation) as (service, auth):
|
|
215
|
+
visible = _visible_projects(service)
|
|
198
216
|
if invocation.project is not None:
|
|
199
|
-
projects: list[dict[str, Any]] = [
|
|
217
|
+
projects: list[dict[str, Any]] = [named_project(service, invocation.project, visible)]
|
|
200
218
|
matches = _find_in_projects(service, needle, projects)
|
|
201
219
|
if not matches:
|
|
202
|
-
others = _other_projects(
|
|
220
|
+
others = _other_projects(visible, invocation.project)
|
|
203
221
|
matches = _find_in_projects(service, needle, others)
|
|
204
222
|
projects += others
|
|
205
223
|
else:
|
|
206
|
-
projects =
|
|
224
|
+
projects = visible
|
|
207
225
|
matches = _find_in_projects(service, needle, projects)
|
|
208
226
|
meta = {
|
|
209
227
|
"profile": invocation.profile,
|
|
210
228
|
"workspace_id": auth.workspace_id,
|
|
211
229
|
"project_id": invocation.project,
|
|
212
230
|
}
|
|
213
|
-
|
|
231
|
+
result: dict[str, Any] = {
|
|
214
232
|
"matches": matches,
|
|
215
233
|
"projects_searched": len(projects),
|
|
216
234
|
"projects_truncated": len(projects) >= _MAX_PROJECTS_SEARCHED,
|
|
217
|
-
}
|
|
235
|
+
}
|
|
236
|
+
if note := ambiguity_note(len(matches), name_substring):
|
|
237
|
+
result["note"] = note
|
|
238
|
+
return result, meta
|
|
218
239
|
|
|
219
240
|
|
|
220
241
|
def dataset_list(invocation: Invocation) -> HandlerResult:
|
|
@@ -264,7 +285,7 @@ def _dataset_name_search(
|
|
|
264
285
|
page = search_page(records, name, int(document.get("offset", 0)), document.get("limit"))
|
|
265
286
|
if page["matched"] == 0:
|
|
266
287
|
elsewhere = _find_in_projects(
|
|
267
|
-
service, name.lower(), _other_projects(service, project_id)
|
|
288
|
+
service, name.lower(), _other_projects(_visible_projects(service), project_id)
|
|
268
289
|
)
|
|
269
290
|
if elsewhere:
|
|
270
291
|
page["in_other_projects"] = elsewhere
|
|
@@ -504,14 +525,21 @@ def dataset_interpretation(invocation: Invocation) -> HandlerResult:
|
|
|
504
525
|
|
|
505
526
|
``--input`` carries ``user_instruction`` (plain English, e.g. one of the
|
|
506
527
|
suggestions ``dataset get`` shows), a ``structure_map`` from an earlier
|
|
507
|
-
preview, or a ``destination_dataset_id``; at least one is required.
|
|
528
|
+
preview, or a ``destination_dataset_id``; at least one is required. ``confirm``
|
|
529
|
+
alone also takes ``mode``: ``"original"`` keeps the file in its uploaded layout
|
|
530
|
+
(no other field then), ``"interpreted"`` is the default.
|
|
508
531
|
"""
|
|
509
532
|
project_id = require_project(invocation)
|
|
510
533
|
dataset_id = _require_int_positional(invocation, "dataset id")
|
|
511
534
|
document = invocation.load_input() or {}
|
|
512
535
|
kwargs: dict[str, Any] = {"dataset_id": dataset_id, "project_id": project_id}
|
|
513
|
-
|
|
514
|
-
|
|
536
|
+
confirming = invocation.command_id == "dataset.interpretation.confirm"
|
|
537
|
+
_forward_optional(
|
|
538
|
+
document,
|
|
539
|
+
kwargs,
|
|
540
|
+
(*_INTERPRETATION_FIELDS, "mode") if confirming else _INTERPRETATION_FIELDS,
|
|
541
|
+
)
|
|
542
|
+
if not any(field in kwargs for field in (*_INTERPRETATION_FIELDS, "mode")):
|
|
515
543
|
raise CliError(
|
|
516
544
|
code=CODE_MISSING_ARGUMENT,
|
|
517
545
|
message="Say how to read the file: pass one of " + ", ".join(_INTERPRETATION_FIELDS),
|
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
|
+
from mammoth_cli.commands.dataset import named_project
|
|
14
15
|
from mammoth_cli.errors.envelope import (
|
|
15
16
|
CODE_INVALID_ARGUMENT,
|
|
16
17
|
CODE_MISSING_ARGUMENT,
|
|
@@ -121,11 +122,12 @@ def folder_find(invocation: Invocation) -> HandlerResult:
|
|
|
121
122
|
needle = name_substring.lower()
|
|
122
123
|
matches: list[dict[str, Any]] = []
|
|
123
124
|
with open_service(invocation) as (service, auth):
|
|
125
|
+
listing = service.list_projects(limit=_MAX_PROJECTS_SEARCHED)
|
|
126
|
+
visible = list(listing.get("projects", [])) if isinstance(listing, dict) else []
|
|
124
127
|
if invocation.project is not None:
|
|
125
|
-
projects: list[dict[str, Any]] = [
|
|
128
|
+
projects: list[dict[str, Any]] = [named_project(service, invocation.project, visible)]
|
|
126
129
|
else:
|
|
127
|
-
|
|
128
|
-
projects = list(listing.get("projects", [])) if isinstance(listing, dict) else []
|
|
130
|
+
projects = visible
|
|
129
131
|
for project in projects:
|
|
130
132
|
project_id = project.get("id")
|
|
131
133
|
if project_id is None:
|
|
@@ -136,8 +138,7 @@ def folder_find(invocation: Invocation) -> HandlerResult:
|
|
|
136
138
|
response = service.call(
|
|
137
139
|
"mammoth.api.folders.FoldersAPI.list", project_id=project_id, limit=100
|
|
138
140
|
)
|
|
139
|
-
|
|
140
|
-
for folder in folders:
|
|
141
|
+
for folder in _folders_of(response):
|
|
141
142
|
name = folder.get("name") if isinstance(folder, dict) else None
|
|
142
143
|
if isinstance(name, str) and needle in name.lower():
|
|
143
144
|
matches.append(
|
|
@@ -265,9 +266,7 @@ def folder_move(invocation: Invocation) -> HandlerResult:
|
|
|
265
266
|
if not any(field in kwargs for field in ("resource_ids", "dataset_ids", "view_ids")):
|
|
266
267
|
raise CliError(
|
|
267
268
|
code=CODE_MISSING_FIELD,
|
|
268
|
-
message=(
|
|
269
|
-
"This command requires one of 'resource_ids', 'dataset_ids', " "or 'view_ids'."
|
|
270
|
-
),
|
|
269
|
+
message=("This command requires one of 'resource_ids', 'dataset_ids', or 'view_ids'."),
|
|
271
270
|
exit_status=EXIT_USAGE,
|
|
272
271
|
hint=(
|
|
273
272
|
"Pass it via --input, e.g. "
|
|
@@ -275,10 +274,67 @@ def folder_move(invocation: Invocation) -> HandlerResult:
|
|
|
275
274
|
),
|
|
276
275
|
)
|
|
277
276
|
with open_service(invocation) as (service, auth):
|
|
277
|
+
_resolve_folder_fields(service, project_id, kwargs)
|
|
278
278
|
data = service.call(_symbol(invocation), **kwargs)
|
|
279
279
|
return data, _meta(invocation, auth.workspace_id, project_id)
|
|
280
280
|
|
|
281
281
|
|
|
282
|
+
_FOLDER_LIST_SYMBOL = "mammoth.api.folders.FoldersAPI.list"
|
|
283
|
+
_FOLDER_PAGE = 100
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _folders_of(page: Any) -> list[dict[str, Any]]:
|
|
287
|
+
"""The folder records of a ``FoldersAPI.list`` page (a model or a dict)."""
|
|
288
|
+
page = page.model_dump(mode="json") if hasattr(page, "model_dump") else page
|
|
289
|
+
folders = page.get("folders", []) if isinstance(page, dict) else []
|
|
290
|
+
return [f for f in folders if isinstance(f, dict)]
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _project_folders(service: Any, project_id: int) -> list[dict[str, Any]]:
|
|
294
|
+
"""Every folder of the project (``id`` and ``resource_id`` each), page by page."""
|
|
295
|
+
folders: list[dict[str, Any]] = []
|
|
296
|
+
while True:
|
|
297
|
+
page = service.call(
|
|
298
|
+
_FOLDER_LIST_SYMBOL, project_id=project_id, limit=_FOLDER_PAGE, offset=len(folders)
|
|
299
|
+
)
|
|
300
|
+
batch = _folders_of(page)
|
|
301
|
+
folders += batch
|
|
302
|
+
if len(batch) < _FOLDER_PAGE:
|
|
303
|
+
return folders
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _resolve_folder_fields(service: Any, project_id: int, kwargs: dict[str, Any]) -> None:
|
|
307
|
+
"""Turn a folder's ``resource_id`` into the ``id`` the backend wants, in place.
|
|
308
|
+
|
|
309
|
+
``target_folder_resource_id`` is named for a resource id but the backend
|
|
310
|
+
wants the folder's own ``id``. A value that is a folder's ``id`` is sent
|
|
311
|
+
as it is; one that is only some folder's ``resource_id`` is replaced by
|
|
312
|
+
that folder's ``id``; one that is both (two different folders) is refused.
|
|
313
|
+
"""
|
|
314
|
+
for field in ("target_folder_resource_id", "source_folder_resource_id"):
|
|
315
|
+
value = kwargs.get(field)
|
|
316
|
+
if value in (None, "", "root"):
|
|
317
|
+
continue
|
|
318
|
+
folders = _project_folders(service, project_id)
|
|
319
|
+
by_id = [f for f in folders if str(f.get("id")) == str(value)]
|
|
320
|
+
by_resource = [f for f in folders if str(f.get("resource_id")) == str(value)]
|
|
321
|
+
if by_id and by_resource and by_id != by_resource:
|
|
322
|
+
raise CliError(
|
|
323
|
+
code=CODE_INVALID_ARGUMENT,
|
|
324
|
+
message=(
|
|
325
|
+
f"'{field}' {value} is the id of folder '{by_id[0].get('name')}' and the "
|
|
326
|
+
f"resource_id of folder '{by_resource[0].get('name')}'."
|
|
327
|
+
),
|
|
328
|
+
exit_status=EXIT_USAGE,
|
|
329
|
+
hint=(
|
|
330
|
+
f"Pass the folder's id ({by_id[0].get('id')} or {by_resource[0].get('id')}) "
|
|
331
|
+
"as it appears in 'folder list'."
|
|
332
|
+
),
|
|
333
|
+
)
|
|
334
|
+
if not by_id and by_resource:
|
|
335
|
+
kwargs[field] = by_resource[0].get("id")
|
|
336
|
+
|
|
337
|
+
|
|
282
338
|
def folder_trash(invocation: Invocation) -> HandlerResult:
|
|
283
339
|
"""Move one folder to the project trash (reversible)."""
|
|
284
340
|
project_id = require_project(invocation)
|