netbox-super-cli 1.3.0__tar.gz → 1.4.0__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.
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/bench.yml +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/claude.yml +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/docs.yml +2 -2
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/e2e.yml +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/lint.yml +3 -3
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/release.yml +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/test.yml +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/CHANGELOG.md +44 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/PKG-INFO +57 -4
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/README.md +56 -3
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/reference/config.md +3 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/_version.py +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/app.py +16 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/globals.py +13 -2
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/handlers.py +3 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/registration.py +51 -6
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/runtime.py +19 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/tui_commands.py +51 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/config/models.py +14 -0
- netbox_super_cli-1.4.0/nsc/config/saved_searches.py +54 -0
- netbox_super_cli-1.4.0/nsc/output/colors.py +36 -0
- netbox_super_cli-1.4.0/nsc/output/flatten.py +72 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/render.py +2 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/table.py +30 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/__init__.py +11 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/app.py +34 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/columns.py +23 -9
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/keymap.py +5 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/filter.py +74 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/list.py +13 -3
- netbox_super_cli-1.4.0/nsc/tui/screens/saved_search_picker.py +92 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/styles.tcss +24 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/view.py +27 -4
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/help.py +1 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/pyproject.toml +1 -1
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/skills/netbox-super-cli/SKILL.md +5 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_registration.py +74 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_runtime_color.py +26 -2
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_tui_command.py +71 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/test_models.py +36 -1
- netbox_super_cli-1.4.0/tests/config/test_saved_searches.py +86 -0
- netbox_super_cli-1.4.0/tests/output/test_colors.py +28 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_flatten.py +97 -0
- netbox_super_cli-1.4.0/tests/output/test_table_color.py +277 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_app.py +47 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_columns.py +49 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_filter_screen.py +118 -2
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_keymap.py +6 -4
- netbox_super_cli-1.4.0/tests/tui/test_view.py +87 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/uv.lock +1 -1
- netbox_super_cli-1.3.0/nsc/output/flatten.py +0 -53
- netbox_super_cli-1.3.0/tests/output/test_table_color.py +0 -138
- netbox_super_cli-1.3.0/tests/tui/test_view.py +0 -27
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/dependabot.yml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.github/workflows/skill-convention-review.yml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.gitignore +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.pre-commit-config.yaml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/.python-version +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/AGENTS.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/CLAUDE.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/LICENSE +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/architecture/caching.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/architecture/command-generation.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/architecture/http-client.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/architecture/overview.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/architecture/schema-loading.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/assets/tui/detail.svg +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/assets/tui/filter.svg +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/assets/tui/list.svg +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/assets/tui/picker.svg +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/assets/tui/search.svg +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/contributing/adding-bundled-schemas.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/contributing/branching.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/contributing/development.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/contributing/release-process.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/getting-started/concepts.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/getting-started/first-run.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/getting-started/install.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/audit-log.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/ci-and-automation.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/interactive-tui.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/managing-profiles.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/output-formats.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/using-with-ai-agents.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/working-with-plugins.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/guides/writes-and-safety.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/index.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/reference/cli.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/reference/exit-codes.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/docs/reference/schemas.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/justfile +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/mkdocs.yml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/__main__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/aliases/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/aliases/resolver.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/auth/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/auth/verify.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/builder/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/builder/build.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cache/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cache/store.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/aliases_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/cache_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/commands_dump.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/config_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/init_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/login_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/profiles_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/skill_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/apply.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/bulk.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/coercion.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/confirmation.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/input.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/cli/writes/preflight.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/completion/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/completion/cache_probe.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/completion/callbacks.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/completion/providers.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/config/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/config/loader.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/config/settings.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/config/writer.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/http/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/http/audit.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/http/client.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/http/errors.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/http/retry.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/model/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/model/command_model.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/_console.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/csv_.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/errors.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/explain.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/headers.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/json_.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/jsonl.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/output/yaml_.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schema/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schema/hashing.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schema/loader.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schema/models.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schema/source.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schemas/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schemas/bundled/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schemas/bundled/manifest.yaml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schemas/bundled/netbox-4.5.10.json.gz +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/schemas/bundled/netbox-4.6.0.json.gz +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/skill/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/_bindings.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/bulk.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/catalog.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/errors.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/filters.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/fk.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/forms.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/nav.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/relations.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/bulk_edit_form.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/columns.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/detail.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/edit_form.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/global_search.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/picker.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/screens/record_picker.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/search.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/selection.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/_modal.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/bulk_diff.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/bulk_summary.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/confirm.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/diff.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/nsc/tui/widgets/nav_tree.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/scripts/gen_docs.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/scripts/sync_agents_md.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/aliases/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/aliases/test_resolver.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/audit/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/audit/test_redaction_full.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/auth/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/auth/test_verify.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/benchmarks/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/benchmarks/test_startup.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/builder/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/builder/test_build.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/builder/test_default_columns.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/builder/test_redaction_marking.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/builder/test_request_body_shape.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cache/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cache/test_prune.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cache/test_store.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_aliases_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_app_smoke.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_cache_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_commands_dump.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_completion_protocol_smoke.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_completion_smoke.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_config_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_dynamic_completion.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_explain.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_globals_color.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_handlers.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_init_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_lazy_textual_import.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_login_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_meta_subcommands_under_broken_config.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_ndjson_input.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_profiles_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_respx_integration.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_runtime.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_skill_commands.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_stdin_sniffer.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/test_writes_respx.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_apply.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_bulk.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_confirmation.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_handler_helpers.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_handlers_audit.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_input.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/cli/writes/test_preflight.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/test_loader.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/test_settings_private_dir.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/test_writer_atomicity.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/test_writer_dotted_paths.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/config/test_writer_roundtrip.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/conftest.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/README.md +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/conftest.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/docker-compose.yml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_audit_redaction.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_auth_error_envelope.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_bulk_create_with_loop_fallback.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_full_cycle.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_login.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_ndjson.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_preflight_blocks_apply.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/test_validation_error_envelope_from_netbox.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/e2e/wait_for_netbox.sh +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/fixtures/profiles/single_profile.yaml +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/fixtures/responses/auth_401.json +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/fixtures/responses/circuits_providers_list.json +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/fixtures/responses/dcim_devices_get.json +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/fixtures/responses/dcim_devices_list_p1.json +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/fixtures/responses/dcim_devices_list_p2.json +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_audit.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_audit_permissions.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_audit_redaction.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_client.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_client_redaction_threading.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_errors.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/http/test_retry.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/model/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/model/test_command_model.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/model/test_request_body_shape.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_console.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_csv.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_errors.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_errors_aliases.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_errors_color.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_explain.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_explain_color.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_input_error_envelope.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_json.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_jsonl.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_render_dispatch.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_table.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/output/test_yaml.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/schema/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/schema/test_hashing.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/schema/test_loader.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/schema/test_models.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/schema/test_source.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/schema/test_source_ttl.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/scripts/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/scripts/test_gen_docs.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/scripts/test_sync_agents_md.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/skill/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/skill/test_bundle.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/test_packaging.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/__init__.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bindings.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bulk_apply.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bulk_diff.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bulk_diff_modal.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bulk_edit_form.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bulk_import_isolation.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_bulk_summary.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_catalog.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_column_chooser.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_detail_screen.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_diff.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_diff_modal.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_edit_form.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_errors.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_filters.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_fk_resolve.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_forms.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_global_search.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_help_overlay.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_list_screen.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_picker.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_record_picker.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_relations.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_search.py +0 -0
- {netbox_super_cli-1.3.0 → netbox_super_cli-1.4.0}/tests/tui/test_selection.py +0 -0
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
build:
|
|
27
27
|
runs-on: ubuntu-latest
|
|
28
28
|
steps:
|
|
29
|
-
- uses: actions/checkout@
|
|
29
|
+
- uses: actions/checkout@v7
|
|
30
30
|
- name: Install uv
|
|
31
31
|
uses: astral-sh/setup-uv@v7
|
|
32
32
|
with:
|
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
run: uv run mkdocs build --strict
|
|
40
40
|
- name: Upload Pages artifact
|
|
41
41
|
if: github.ref_type == 'tag'
|
|
42
|
-
uses: actions/upload-pages-artifact@
|
|
42
|
+
uses: actions/upload-pages-artifact@v5
|
|
43
43
|
with:
|
|
44
44
|
path: site
|
|
45
45
|
|
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
lint:
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
16
|
- name: Install uv
|
|
17
17
|
uses: astral-sh/setup-uv@v7
|
|
18
18
|
with:
|
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
docs-reference-fresh:
|
|
32
32
|
runs-on: ubuntu-latest
|
|
33
33
|
steps:
|
|
34
|
-
- uses: actions/checkout@
|
|
34
|
+
- uses: actions/checkout@v7
|
|
35
35
|
- name: Install uv
|
|
36
36
|
uses: astral-sh/setup-uv@v7
|
|
37
37
|
with:
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
agents-md-fresh:
|
|
47
47
|
runs-on: ubuntu-latest
|
|
48
48
|
steps:
|
|
49
|
-
- uses: actions/checkout@
|
|
49
|
+
- uses: actions/checkout@v7
|
|
50
50
|
- name: Install uv
|
|
51
51
|
uses: astral-sh/setup-uv@v7
|
|
52
52
|
with:
|
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
# prerequisites).
|
|
40
40
|
steps:
|
|
41
41
|
- name: Checkout (full history for changelog notes)
|
|
42
|
-
uses: actions/checkout@
|
|
42
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
43
43
|
with:
|
|
44
44
|
fetch-depth: 0
|
|
45
45
|
|
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to netbox-super-cli are tracked here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely. From v1.0.0 onward, releases follow [Semantic Versioning](https://semver.org/) and the version in `pyproject.toml` matches the git tag. Pre-1.0 milestones (Phase 1-5) were pinned by tag while `pyproject.toml` stayed at `0.0.1`.
|
|
4
4
|
|
|
5
|
+
## v1.4.0 — 2026-06-26
|
|
6
|
+
|
|
7
|
+
Minor release. Three user-facing features for the interactive TUI and table
|
|
8
|
+
output: individually selectable custom-field columns, local saved searches, and
|
|
9
|
+
NetBox-native object colors.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Individually selectable custom fields** ([#121], closes [#118]). The TUI
|
|
14
|
+
column chooser (`f` — Fields) now expands `custom_fields` into one toggleable
|
|
15
|
+
column per custom field (`custom_fields.<name>`) instead of a single opaque
|
|
16
|
+
object. On the CLI, `--columns custom_fields.<name>` selects an individual
|
|
17
|
+
custom field (now documented).
|
|
18
|
+
- **Saved searches** ([#123], closes [#119]). Named filter sets persist per
|
|
19
|
+
resource. In the TUI filter builder, `Ctrl+W` saves the current filters under
|
|
20
|
+
a name and `Ctrl+O` opens a picker to apply one (`d` deletes an entry). On the
|
|
21
|
+
CLI, `--saved <name>` re-applies a saved filter set on `list`; explicit
|
|
22
|
+
`--filter` and typed options take precedence over saved values. Names
|
|
23
|
+
containing `.` (or whitespace) are rejected to keep the config file well-formed.
|
|
24
|
+
- **NetBox object colors** ([#122], closes [#120]). Role, tag, and other
|
|
25
|
+
color-bearing fields render in their NetBox-defined colors in table output. A
|
|
26
|
+
new `object_colors` setting (`auto`/`on`/`off`) and the
|
|
27
|
+
`--object-colors/--no-object-colors` flag toggle this independently of
|
|
28
|
+
`--color`; `off`, `NO_COLOR`, and non-TTY output are always respected.
|
|
29
|
+
|
|
30
|
+
[#118]: https://github.com/thomaschristory/netbox-super-cli/issues/118
|
|
31
|
+
[#119]: https://github.com/thomaschristory/netbox-super-cli/issues/119
|
|
32
|
+
[#120]: https://github.com/thomaschristory/netbox-super-cli/issues/120
|
|
33
|
+
[#121]: https://github.com/thomaschristory/netbox-super-cli/pull/121
|
|
34
|
+
[#122]: https://github.com/thomaschristory/netbox-super-cli/pull/122
|
|
35
|
+
[#123]: https://github.com/thomaschristory/netbox-super-cli/pull/123
|
|
36
|
+
|
|
37
|
+
## v1.3.1 — 2026-06-25
|
|
38
|
+
|
|
39
|
+
Patch release. CI maintenance only — no runtime or user-facing changes.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- **CI**: bump `actions/checkout` from 5 to 7 ([#110]) and
|
|
44
|
+
`actions/upload-pages-artifact` from 3 to 5 ([#109]).
|
|
45
|
+
|
|
46
|
+
[#109]: https://github.com/thomaschristory/netbox-super-cli/pull/109
|
|
47
|
+
[#110]: https://github.com/thomaschristory/netbox-super-cli/pull/110
|
|
48
|
+
|
|
5
49
|
## v1.3.0 — 2026-06-25
|
|
6
50
|
|
|
7
51
|
Minor release. A batch of user-facing features — singular alias forms, parallel
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-super-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Dynamic NetBox CLI generated from the live OpenAPI schema.
|
|
5
5
|
Project-URL: Homepage, https://github.com/thomaschristory/netbox-super-cli
|
|
6
6
|
Project-URL: Issues, https://github.com/thomaschristory/netbox-super-cli/issues
|
|
@@ -27,9 +27,29 @@ Requires-Dist: textual>=0.50
|
|
|
27
27
|
Requires-Dist: typer<0.27,>=0.26
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
<div align="center">
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# netbox-super-cli · `nsc`
|
|
33
|
+
|
|
34
|
+
**A Python CLI for [NetBox](https://netbox.dev/) that builds its entire command tree from your install's live OpenAPI schema.**
|
|
35
|
+
|
|
36
|
+
One binary, any NetBox version, every plugin endpoint — the schema, not hand-written code, defines the surface.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/netbox-super-cli/)
|
|
41
|
+
[](https://pypi.org/project/netbox-super-cli/)
|
|
42
|
+
[](https://pypi.org/project/netbox-super-cli/)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
[](https://github.com/thomaschristory/netbox-super-cli/actions/workflows/test.yml)
|
|
45
|
+
[](https://thomaschristory.github.io/netbox-super-cli/)
|
|
46
|
+
[](https://github.com/thomaschristory/netbox-super-cli/stargazers)
|
|
47
|
+
|
|
48
|
+
[**📚 Documentation**](https://thomaschristory.github.io/netbox-super-cli/) · [**🚀 Install**](#install) · [**🖥️ Interactive TUI**](#interactive-tui) · [**🤖 AI Skill**](#bundled-skill-for-ai-agents)
|
|
49
|
+
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
---
|
|
33
53
|
|
|
34
54
|
> **Docs:** [thomaschristory.github.io/netbox-super-cli](https://thomaschristory.github.io/netbox-super-cli/) — the full guide, including install, first-run, guides, and the auto-generated CLI/config/exit-code reference.
|
|
35
55
|
|
|
@@ -74,7 +94,9 @@ nsc tui devices # jump straight into the devices list
|
|
|
74
94
|
Highlights: a collapsible resource picker, a web-UI-style filter builder (`/`),
|
|
75
95
|
inline record editing with a confirm-diff save, schema-derived relationship
|
|
76
96
|
drill-down, bulk edit with a per-record preview, a persisted column chooser
|
|
77
|
-
(`f`), and global search (`Ctrl`+`F`).
|
|
97
|
+
(`f`) that lists each custom field individually, and global search (`Ctrl`+`F`).
|
|
98
|
+
The same dotted paths work on the CLI: `nsc ls devices --columns id,name,custom_fields.rack_role`.
|
|
99
|
+
Full walkthrough in the
|
|
78
100
|
[Interactive TUI guide](https://thomaschristory.github.io/netbox-super-cli/guides/interactive-tui/).
|
|
79
101
|
|
|
80
102
|
## Reading
|
|
@@ -90,6 +112,37 @@ uv run nsc circuits providers list --output csv
|
|
|
90
112
|
uv run nsc ipam prefixes list --filter created__gte=2026-01-01 --output yaml
|
|
91
113
|
```
|
|
92
114
|
|
|
115
|
+
### Saved searches
|
|
116
|
+
|
|
117
|
+
Filter sets you save from the TUI (Ctrl+W in the filter builder) are stored
|
|
118
|
+
locally under `saved_searches` in `~/.nsc/config.yaml`, keyed by tag/resource.
|
|
119
|
+
Re-apply one on the CLI with `--saved`:
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
uv run nsc dcim devices list --saved active-switches
|
|
123
|
+
# explicit --filter / typed options override the saved values:
|
|
124
|
+
uv run nsc dcim devices list --saved active-switches --status offline
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This is a local, per-config convenience and is unrelated to NetBox's
|
|
128
|
+
server-side saved filters (`extras saved-filters`), which store web-UI query
|
|
129
|
+
strings.
|
|
130
|
+
|
|
131
|
+
### Object colors
|
|
132
|
+
|
|
133
|
+
NetBox assigns colors to roles, tags, and similar fields. In table output `nsc`
|
|
134
|
+
renders those values in their NetBox-defined colors:
|
|
135
|
+
|
|
136
|
+
```sh
|
|
137
|
+
uv run nsc dcim devices list # colored when stdout is a TTY
|
|
138
|
+
uv run nsc dcim devices list --no-object-colors # plain text
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Toggle it independently of `--color` with the `object_colors` setting
|
|
142
|
+
(`auto`/`on`/`off`) or the `--object-colors/--no-object-colors` flag. `off`,
|
|
143
|
+
`NO_COLOR`, and non-TTY output are always respected, so piped or redirected
|
|
144
|
+
output stays uncolored.
|
|
145
|
+
|
|
93
146
|
## Writing
|
|
94
147
|
|
|
95
148
|
```sh
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# netbox-super-cli · `nsc`
|
|
4
|
+
|
|
5
|
+
**A Python CLI for [NetBox](https://netbox.dev/) that builds its entire command tree from your install's live OpenAPI schema.**
|
|
6
|
+
|
|
7
|
+
One binary, any NetBox version, every plugin endpoint — the schema, not hand-written code, defines the surface.
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
[](https://pypi.org/project/netbox-super-cli/)
|
|
12
|
+
[](https://pypi.org/project/netbox-super-cli/)
|
|
13
|
+
[](https://pypi.org/project/netbox-super-cli/)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
[](https://github.com/thomaschristory/netbox-super-cli/actions/workflows/test.yml)
|
|
16
|
+
[](https://thomaschristory.github.io/netbox-super-cli/)
|
|
17
|
+
[](https://github.com/thomaschristory/netbox-super-cli/stargazers)
|
|
18
|
+
|
|
19
|
+
[**📚 Documentation**](https://thomaschristory.github.io/netbox-super-cli/) · [**🚀 Install**](#install) · [**🖥️ Interactive TUI**](#interactive-tui) · [**🤖 AI Skill**](#bundled-skill-for-ai-agents)
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
---
|
|
4
24
|
|
|
5
25
|
> **Docs:** [thomaschristory.github.io/netbox-super-cli](https://thomaschristory.github.io/netbox-super-cli/) — the full guide, including install, first-run, guides, and the auto-generated CLI/config/exit-code reference.
|
|
6
26
|
|
|
@@ -45,7 +65,9 @@ nsc tui devices # jump straight into the devices list
|
|
|
45
65
|
Highlights: a collapsible resource picker, a web-UI-style filter builder (`/`),
|
|
46
66
|
inline record editing with a confirm-diff save, schema-derived relationship
|
|
47
67
|
drill-down, bulk edit with a per-record preview, a persisted column chooser
|
|
48
|
-
(`f`), and global search (`Ctrl`+`F`).
|
|
68
|
+
(`f`) that lists each custom field individually, and global search (`Ctrl`+`F`).
|
|
69
|
+
The same dotted paths work on the CLI: `nsc ls devices --columns id,name,custom_fields.rack_role`.
|
|
70
|
+
Full walkthrough in the
|
|
49
71
|
[Interactive TUI guide](https://thomaschristory.github.io/netbox-super-cli/guides/interactive-tui/).
|
|
50
72
|
|
|
51
73
|
## Reading
|
|
@@ -61,6 +83,37 @@ uv run nsc circuits providers list --output csv
|
|
|
61
83
|
uv run nsc ipam prefixes list --filter created__gte=2026-01-01 --output yaml
|
|
62
84
|
```
|
|
63
85
|
|
|
86
|
+
### Saved searches
|
|
87
|
+
|
|
88
|
+
Filter sets you save from the TUI (Ctrl+W in the filter builder) are stored
|
|
89
|
+
locally under `saved_searches` in `~/.nsc/config.yaml`, keyed by tag/resource.
|
|
90
|
+
Re-apply one on the CLI with `--saved`:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
uv run nsc dcim devices list --saved active-switches
|
|
94
|
+
# explicit --filter / typed options override the saved values:
|
|
95
|
+
uv run nsc dcim devices list --saved active-switches --status offline
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This is a local, per-config convenience and is unrelated to NetBox's
|
|
99
|
+
server-side saved filters (`extras saved-filters`), which store web-UI query
|
|
100
|
+
strings.
|
|
101
|
+
|
|
102
|
+
### Object colors
|
|
103
|
+
|
|
104
|
+
NetBox assigns colors to roles, tags, and similar fields. In table output `nsc`
|
|
105
|
+
renders those values in their NetBox-defined colors:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
uv run nsc dcim devices list # colored when stdout is a TTY
|
|
109
|
+
uv run nsc dcim devices list --no-object-colors # plain text
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Toggle it independently of `--color` with the `object_colors` setting
|
|
113
|
+
(`auto`/`on`/`off`) or the `--object-colors/--no-object-colors` flag. `off`,
|
|
114
|
+
`NO_COLOR`, and non-TTY output are always respected, so piped or redirected
|
|
115
|
+
output stays uncolored.
|
|
116
|
+
|
|
64
117
|
## Writing
|
|
65
118
|
|
|
66
119
|
```sh
|
|
@@ -11,8 +11,9 @@ All fields below describe `~/.nsc/config.yaml`.
|
|
|
11
11
|
|---|---|---|
|
|
12
12
|
| `default_profile` | `str | None` | `None` |
|
|
13
13
|
| `profiles` | `dict[str, Profile]` | `{}` |
|
|
14
|
-
| `defaults` | `<class 'Defaults'>` | `Defaults(output=<OutputFormat.TABLE: 'table'>, page_size=50, timeout=30.0, schema_refresh=<SchemaRefresh.DAILY: 'daily'>, color_mode=<ColorMode.AUTO: 'auto'>, audit_redaction=<AuditRedaction.SAFE: 'safe'>)` |
|
|
14
|
+
| `defaults` | `<class 'Defaults'>` | `Defaults(output=<OutputFormat.TABLE: 'table'>, page_size=50, timeout=30.0, schema_refresh=<SchemaRefresh.DAILY: 'daily'>, color_mode=<ColorMode.AUTO: 'auto'>, object_colors=<ObjectColorMode.AUTO: 'auto'>, audit_redaction=<AuditRedaction.SAFE: 'safe'>)` |
|
|
15
15
|
| `columns` | `dict[str, dict[str, list[str]]]` | `{}` |
|
|
16
|
+
| `saved_searches` | `dict[str, dict[str, dict[str, dict[str, str]]]]` | `{}` |
|
|
16
17
|
|
|
17
18
|
## `Profile`
|
|
18
19
|
|
|
@@ -34,4 +35,5 @@ All fields below describe `~/.nsc/config.yaml`.
|
|
|
34
35
|
| `timeout` | `<class 'float'>` | `30.0` |
|
|
35
36
|
| `schema_refresh` | `<enum 'SchemaRefresh'>` | `<SchemaRefresh.DAILY: 'daily'>` |
|
|
36
37
|
| `color_mode` | `<enum 'ColorMode'>` | `<ColorMode.AUTO: 'auto'>` |
|
|
38
|
+
| `object_colors` | `<enum 'ObjectColorMode'>` | `<ObjectColorMode.AUTO: 'auto'>` |
|
|
37
39
|
| `audit_redaction` | `<enum 'AuditRedaction'>` | `<AuditRedaction.SAFE: 'safe'>` |
|
|
@@ -94,6 +94,14 @@ def _extract_global_overrides(args: list[str]) -> CLIOverrides:
|
|
|
94
94
|
kwargs["refresh_schema"] = True
|
|
95
95
|
i += 1
|
|
96
96
|
continue
|
|
97
|
+
if a == "--object-colors":
|
|
98
|
+
kwargs["object_colors"] = True
|
|
99
|
+
i += 1
|
|
100
|
+
continue
|
|
101
|
+
if a == "--no-object-colors":
|
|
102
|
+
kwargs["object_colors"] = False
|
|
103
|
+
i += 1
|
|
104
|
+
continue
|
|
97
105
|
i += 1
|
|
98
106
|
return CLIOverrides(**kwargs) # type: ignore[arg-type]
|
|
99
107
|
|
|
@@ -310,6 +318,13 @@ def _root(
|
|
|
310
318
|
),
|
|
311
319
|
] = False,
|
|
312
320
|
output: Annotated[str | None, typer.Option("--output", "-o")] = None,
|
|
321
|
+
object_colors: Annotated[
|
|
322
|
+
bool | None,
|
|
323
|
+
typer.Option(
|
|
324
|
+
"--object-colors/--no-object-colors",
|
|
325
|
+
help="Render NetBox-native object colors (role/tag/…) in table output.",
|
|
326
|
+
),
|
|
327
|
+
] = None,
|
|
313
328
|
debug: Annotated[bool, typer.Option("--debug")] = False,
|
|
314
329
|
) -> None:
|
|
315
330
|
"""Root callback — global options live here."""
|
|
@@ -321,6 +336,7 @@ def _root(
|
|
|
321
336
|
schema_override=schema,
|
|
322
337
|
refresh_schema=refresh_schema,
|
|
323
338
|
output=output,
|
|
339
|
+
object_colors=object_colors,
|
|
324
340
|
)
|
|
325
341
|
try:
|
|
326
342
|
config = load_config(default_paths().config_file)
|
|
@@ -10,10 +10,11 @@ from nsc.cli.runtime import (
|
|
|
10
10
|
CLIOverrides,
|
|
11
11
|
RuntimeContext,
|
|
12
12
|
resolve_color,
|
|
13
|
+
resolve_object_colors,
|
|
13
14
|
resolve_profile,
|
|
14
15
|
)
|
|
15
16
|
from nsc.config import default_paths
|
|
16
|
-
from nsc.config.models import Config
|
|
17
|
+
from nsc.config.models import Config, ObjectColorMode
|
|
17
18
|
from nsc.http.client import NetBoxClient
|
|
18
19
|
from nsc.output.render import select_format
|
|
19
20
|
from nsc.schema.source import resolve_command_model
|
|
@@ -48,6 +49,8 @@ def build_runtime_context(state: GlobalState) -> RuntimeContext:
|
|
|
48
49
|
redaction=state.config.defaults.audit_redaction,
|
|
49
50
|
profile_name=profile.name,
|
|
50
51
|
)
|
|
52
|
+
color = resolve_color(state.config.defaults.color_mode, is_tty=sys.stdout.isatty())
|
|
53
|
+
object_color_mode = _resolve_object_color_mode(state)
|
|
51
54
|
return RuntimeContext(
|
|
52
55
|
resolved_profile=profile,
|
|
53
56
|
config=state.config,
|
|
@@ -56,11 +59,19 @@ def build_runtime_context(state: GlobalState) -> RuntimeContext:
|
|
|
56
59
|
output_format=output,
|
|
57
60
|
debug=state.debug,
|
|
58
61
|
page_size=state.config.defaults.page_size,
|
|
59
|
-
color=
|
|
62
|
+
color=color,
|
|
60
63
|
color_stderr=resolve_color(state.config.defaults.color_mode, is_tty=sys.stderr.isatty()),
|
|
64
|
+
object_colors=resolve_object_colors(object_color_mode, color=color),
|
|
61
65
|
)
|
|
62
66
|
|
|
63
67
|
|
|
68
|
+
def _resolve_object_color_mode(state: GlobalState) -> ObjectColorMode:
|
|
69
|
+
override = state.overrides.object_colors
|
|
70
|
+
if override is None:
|
|
71
|
+
return state.config.defaults.object_colors
|
|
72
|
+
return ObjectColorMode.ON if override else ObjectColorMode.OFF
|
|
73
|
+
|
|
74
|
+
|
|
64
75
|
__all__ = [
|
|
65
76
|
"GlobalState",
|
|
66
77
|
"build_runtime_context",
|
|
@@ -104,6 +104,7 @@ def handle_list(
|
|
|
104
104
|
stream=_out(stream),
|
|
105
105
|
compact=ctx.compact,
|
|
106
106
|
color=ctx.color,
|
|
107
|
+
object_colors=ctx.object_colors,
|
|
107
108
|
)
|
|
108
109
|
except (NetBoxAPIError, NetBoxClientError) as exc:
|
|
109
110
|
env = map_error(exc, operation_id=operation.operation_id)
|
|
@@ -130,6 +131,7 @@ def handle_get(
|
|
|
130
131
|
stream=_out(stream),
|
|
131
132
|
compact=ctx.compact,
|
|
132
133
|
color=ctx.color,
|
|
134
|
+
object_colors=ctx.object_colors,
|
|
133
135
|
)
|
|
134
136
|
except (NetBoxAPIError, NetBoxClientError) as exc:
|
|
135
137
|
env = map_error(exc, operation_id=operation.operation_id)
|
|
@@ -616,6 +618,7 @@ def _render_response(
|
|
|
616
618
|
stream=stream,
|
|
617
619
|
compact=ctx.compact,
|
|
618
620
|
color=ctx.color,
|
|
621
|
+
object_colors=ctx.object_colors,
|
|
619
622
|
)
|
|
620
623
|
|
|
621
624
|
|
|
@@ -120,10 +120,39 @@ def _register_write(
|
|
|
120
120
|
|
|
121
121
|
|
|
122
122
|
_GLOBAL_FLAG_NAMES: frozenset[str] = frozenset(
|
|
123
|
-
{"output", "compact", "columns", "limit", "all_", "filter_"}
|
|
123
|
+
{"output", "compact", "columns", "limit", "all_", "filter_", "saved"}
|
|
124
124
|
)
|
|
125
125
|
|
|
126
126
|
|
|
127
|
+
def _resolve_saved_filters(
|
|
128
|
+
ctx: RuntimeContext,
|
|
129
|
+
tag_name: str,
|
|
130
|
+
resource_name: str,
|
|
131
|
+
saved_name: str | None,
|
|
132
|
+
explicit_filters: list[tuple[str, str]],
|
|
133
|
+
typed_kwargs: dict[str, Any],
|
|
134
|
+
) -> list[tuple[str, str]]:
|
|
135
|
+
"""Layer a `--saved` filter set under explicit `--filter` and typed options.
|
|
136
|
+
|
|
137
|
+
Saved params are the base; explicit `--filter` pairs and any non-None typed
|
|
138
|
+
query option (already in ``typed_kwargs``) win. Order matters: ``handle_list``
|
|
139
|
+
overlays ``ctx.filters`` onto the typed-option params, so saved keys that the
|
|
140
|
+
user also set via a typed flag must be dropped here to let the flag win.
|
|
141
|
+
"""
|
|
142
|
+
if saved_name is None:
|
|
143
|
+
return explicit_filters
|
|
144
|
+
from nsc.config.saved_searches import get_saved_search # noqa: PLC0415
|
|
145
|
+
|
|
146
|
+
saved = get_saved_search(ctx.config, tag_name, resource_name, saved_name)
|
|
147
|
+
if saved is None:
|
|
148
|
+
raise typer.BadParameter(
|
|
149
|
+
f"no saved search named {saved_name!r} for {tag_name}/{resource_name}"
|
|
150
|
+
)
|
|
151
|
+
typed_keys = {k for k, v in typed_kwargs.items() if v is not None}
|
|
152
|
+
base = [(k, v) for k, v in saved.items() if k not in typed_keys]
|
|
153
|
+
return base + explicit_filters
|
|
154
|
+
|
|
155
|
+
|
|
127
156
|
def _build_read_closure(
|
|
128
157
|
operation: Operation,
|
|
129
158
|
tag_name: str,
|
|
@@ -151,17 +180,19 @@ def _build_read_closure(
|
|
|
151
180
|
limit = kwargs.pop("limit", None)
|
|
152
181
|
fetch_all = kwargs.pop("all_", False)
|
|
153
182
|
filters_raw: list[str] = kwargs.pop("filter_", None) or []
|
|
183
|
+
saved_name: str | None = kwargs.pop("saved", None)
|
|
154
184
|
ctx = get_ctx()
|
|
185
|
+
explicit_filters = [
|
|
186
|
+
(item.split("=", 1)[0], item.split("=", 1)[1]) for item in filters_raw if "=" in item
|
|
187
|
+
]
|
|
155
188
|
update: dict[str, Any] = {
|
|
156
189
|
"compact": compact,
|
|
157
190
|
"columns_override": columns_csv.split(",") if columns_csv else None,
|
|
158
191
|
"limit": limit,
|
|
159
192
|
"fetch_all": fetch_all,
|
|
160
|
-
"filters":
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if "=" in item
|
|
164
|
-
],
|
|
193
|
+
"filters": _resolve_saved_filters(
|
|
194
|
+
ctx, tag_name, resource_name, saved_name, explicit_filters, kwargs
|
|
195
|
+
),
|
|
165
196
|
}
|
|
166
197
|
if output:
|
|
167
198
|
update["output_format"] = OutputFormat(output)
|
|
@@ -311,6 +342,20 @@ def _build_global_flag_params() -> tuple[inspect.Parameter, ...]:
|
|
|
311
342
|
annotation=list[str] | None,
|
|
312
343
|
default=typer.Option(None, "--filter"),
|
|
313
344
|
),
|
|
345
|
+
inspect.Parameter(
|
|
346
|
+
name="saved",
|
|
347
|
+
kind=inspect.Parameter.KEYWORD_ONLY,
|
|
348
|
+
annotation=str | None,
|
|
349
|
+
default=typer.Option(
|
|
350
|
+
None,
|
|
351
|
+
"--saved",
|
|
352
|
+
help=(
|
|
353
|
+
"Apply a LOCAL named filter set saved from the TUI (config "
|
|
354
|
+
"`saved_searches`). Explicit --filter/typed options override it. "
|
|
355
|
+
"Unrelated to NetBox server-side saved filters."
|
|
356
|
+
),
|
|
357
|
+
),
|
|
358
|
+
),
|
|
314
359
|
)
|
|
315
360
|
|
|
316
361
|
|
|
@@ -15,7 +15,7 @@ from typing import Any, Literal
|
|
|
15
15
|
from pydantic import BaseModel, ConfigDict, HttpUrl, SkipValidation
|
|
16
16
|
|
|
17
17
|
from nsc.cache.store import ADHOC_PROFILE
|
|
18
|
-
from nsc.config.models import ColorMode, Config, OutputFormat, Profile
|
|
18
|
+
from nsc.config.models import ColorMode, Config, ObjectColorMode, OutputFormat, Profile
|
|
19
19
|
from nsc.config.settings import default_paths
|
|
20
20
|
from nsc.http.client import NetBoxClient
|
|
21
21
|
from nsc.http.errors import NetBoxAPIError, NetBoxClientError
|
|
@@ -52,6 +52,7 @@ class CLIOverrides(_Frozen):
|
|
|
52
52
|
schema_override: str | None = None
|
|
53
53
|
refresh_schema: bool = False
|
|
54
54
|
output: str | None = None
|
|
55
|
+
object_colors: bool | None = None
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
class ResolvedProfile(_Frozen):
|
|
@@ -186,6 +187,22 @@ def resolve_color(mode: ColorMode, *, is_tty: bool) -> bool:
|
|
|
186
187
|
return is_tty
|
|
187
188
|
|
|
188
189
|
|
|
190
|
+
def resolve_object_colors(mode: ObjectColorMode, *, color: bool) -> bool:
|
|
191
|
+
"""Resolve whether NetBox-native object colors render.
|
|
192
|
+
|
|
193
|
+
Always gated by the global `color` resolution (no ANSI when color is off),
|
|
194
|
+
but can be disabled independently: OFF turns object colors off while status
|
|
195
|
+
coloring stays on; ON/AUTO follow `color`.
|
|
196
|
+
|
|
197
|
+
Contract: ON is deliberately *not* a force — it stays identical to AUTO so
|
|
198
|
+
that `--object-colors` (and `NSC_OBJECT_COLORS=on`) can never override the
|
|
199
|
+
no-color decision (`--no-color`, `NO_COLOR`, non-tty). Only OFF diverges.
|
|
200
|
+
"""
|
|
201
|
+
if mode is ObjectColorMode.OFF:
|
|
202
|
+
return False
|
|
203
|
+
return color
|
|
204
|
+
|
|
205
|
+
|
|
189
206
|
class RuntimeContext(BaseModel):
|
|
190
207
|
"""Per-invocation runtime state.
|
|
191
208
|
|
|
@@ -208,6 +225,7 @@ class RuntimeContext(BaseModel):
|
|
|
208
225
|
compact: bool = False
|
|
209
226
|
color: bool = False
|
|
210
227
|
color_stderr: bool = False
|
|
228
|
+
object_colors: bool = False
|
|
211
229
|
apply: bool = False
|
|
212
230
|
explain: bool = False
|
|
213
231
|
strict: bool = False
|
|
@@ -41,6 +41,46 @@ def _save_columns(tag: str, resource: str, columns: list[str]) -> None:
|
|
|
41
41
|
atomic_write(path, dump_round_trip(doc))
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
def _save_search(tag: str, resource: str, name: str, params: dict[str, str]) -> None:
|
|
45
|
+
"""Persist a filter set to ``saved_searches.<tag>.<resource>.<name>``."""
|
|
46
|
+
from nsc.config.saved_searches import validate_saved_search_name # noqa: PLC0415
|
|
47
|
+
from nsc.config.settings import default_paths # noqa: PLC0415
|
|
48
|
+
from nsc.config.writer import ( # noqa: PLC0415
|
|
49
|
+
acquire_lock,
|
|
50
|
+
atomic_write,
|
|
51
|
+
dump_round_trip,
|
|
52
|
+
load_round_trip,
|
|
53
|
+
set_path,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Defensive: a dotted name would split into a nested map under set_path and
|
|
57
|
+
# corrupt the file. Validate before touching disk so the file is untouched.
|
|
58
|
+
validate_saved_search_name(name)
|
|
59
|
+
path = default_paths().config_file
|
|
60
|
+
with acquire_lock(path):
|
|
61
|
+
doc = load_round_trip(path)
|
|
62
|
+
set_path(doc, f"saved_searches.{tag}.{resource}.{name}", dict(params))
|
|
63
|
+
atomic_write(path, dump_round_trip(doc))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _delete_search(tag: str, resource: str, name: str) -> None:
|
|
67
|
+
"""Remove ``saved_searches.<tag>.<resource>.<name>`` and prune empty parents."""
|
|
68
|
+
from nsc.config.settings import default_paths # noqa: PLC0415
|
|
69
|
+
from nsc.config.writer import ( # noqa: PLC0415
|
|
70
|
+
acquire_lock,
|
|
71
|
+
atomic_write,
|
|
72
|
+
dump_round_trip,
|
|
73
|
+
load_round_trip,
|
|
74
|
+
unset_path,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
path = default_paths().config_file
|
|
78
|
+
with acquire_lock(path):
|
|
79
|
+
doc = load_round_trip(path)
|
|
80
|
+
unset_path(doc, f"saved_searches.{tag}.{resource}.{name}")
|
|
81
|
+
atomic_write(path, dump_round_trip(doc))
|
|
82
|
+
|
|
83
|
+
|
|
44
84
|
def register(app: typer.Typer) -> None:
|
|
45
85
|
def tui(
|
|
46
86
|
ctx: typer.Context,
|
|
@@ -54,12 +94,23 @@ def register(app: typer.Typer) -> None:
|
|
|
54
94
|
from nsc.tui import run_tui # noqa: PLC0415 # deferred: keeps Textual lazy.
|
|
55
95
|
|
|
56
96
|
column_prefs = {tag: dict(resources) for tag, resources in runtime.config.columns.items()}
|
|
97
|
+
saved_searches = {
|
|
98
|
+
tag: {
|
|
99
|
+
res: {name: dict(params) for name, params in sets.items()}
|
|
100
|
+
for res, sets in resources.items()
|
|
101
|
+
}
|
|
102
|
+
for tag, resources in runtime.config.saved_searches.items()
|
|
103
|
+
}
|
|
57
104
|
run_tui(
|
|
58
105
|
runtime.command_model,
|
|
59
106
|
runtime.client,
|
|
60
107
|
initial_resource=resource,
|
|
61
108
|
save_columns=_save_columns,
|
|
62
109
|
column_prefs=column_prefs,
|
|
110
|
+
object_colors=runtime.object_colors,
|
|
111
|
+
saved_searches=saved_searches,
|
|
112
|
+
save_search=_save_search,
|
|
113
|
+
delete_search=_delete_search,
|
|
63
114
|
)
|
|
64
115
|
|
|
65
116
|
# `tui` is canonical; `interactive` and `i` are hidden aliases for the same
|