katalyst-taxonomy-cli 2.0.1a7__tar.gz → 2.0.1a8__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.
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/PKG-INFO +1 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/pyproject.toml +35 -1
- katalyst_taxonomy_cli-2.0.1a8/src/Justfile +2 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/app.py +19 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/bundle.py +7 -5
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config_sources.py +45 -2
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/create.py +19 -0
- katalyst_taxonomy_cli-2.0.1a8/src/katalyst_taxonomy_cli/commands/drafts.py +103 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/lifecycle.py +44 -5
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/lint.py +2 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/plugin.py +3 -4
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/query.py +29 -4
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/rescaffold.py +2 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/show.py +10 -2
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/update.py +25 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/context.py +6 -1
- katalyst_taxonomy_cli-2.0.1a8/src/katalyst_taxonomy_cli/options.py +61 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/releases.py +1 -1
- katalyst_taxonomy_cli-2.0.1a8/src/layer.yaml +23 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/conftest.py +1 -7
- katalyst_taxonomy_cli-2.0.1a8/tests/test_agents_home_mcp.py +126 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_cli_version.py +1 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_command.py +1 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_explain.py +1 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_plugins_command.py +1 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_profiles.py +1 -1
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_sources.py +88 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_core_schema.py +1 -1
- katalyst_taxonomy_cli-2.0.1a8/tests/test_create_variant_field.py +158 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_help_names_no_product.py +51 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_k1_runtime_additions.py +283 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_kind_selector_shared_path.py +160 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_lifecycle_moves.py +125 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_mcp_config_tool_parity.py +684 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_nested_collection_and_scope.py +142 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_node_under_parent_directory.py +129 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_plugin_gating.py +1 -1
- katalyst_taxonomy_cli-2.0.1a8/tests/test_qualified_filenames.py +144 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_relate_properties.py +148 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_relocation.py +330 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_rest_shipped_plugins.py +41 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_scaffold_holdings.py +232 -0
- katalyst_taxonomy_cli-2.0.1a8/tests/test_schema_gate.py +141 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/.gitignore +7 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/Justfile +2 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/01_kata_init.feature +222 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/02_kata_clone.feature +103 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/04_kata_deps.feature +219 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/06_kata_status.feature +35 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/11_kata_create_expanded.feature +179 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/13_kata_portfolio_org.feature +174 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/14_kata_resolve.feature +94 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/17_kata_show.feature +37 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/19_kata_backend_ops.feature +19 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/20_kata_promotion.feature +27 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/21_kata_roundtrip.feature +86 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/22_kata_error_ux.feature +97 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/23_kata_show_deep.feature +103 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/24_kata_resolve_deep.feature +85 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/26_kata_fresh_repo.feature +19 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/31_kata_config_discovery.feature +212 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/32_kata_config_profiles.feature +189 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/43_kata_relate_update.feature +59 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/44_kata_create_typed_fields.feature +66 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/51_kata_labels_annotations.feature +76 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/57_kata_self_channels.feature +39 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/58_kata_import_change_set.feature +71 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/59_kata_update_in_place.feature +58 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/63_kata_library_layers.feature +115 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/features/cli/64_kata_xspec_layers.feature +150 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/layer.yaml +23 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/package.json +19 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/playwright.config.ts +5 -0
- katalyst_taxonomy_cli-2.0.1a8/xspec/tsconfig.json +4 -0
- katalyst_taxonomy_cli-2.0.1a7/src/katalyst_taxonomy_cli/commands/drafts.py +0 -63
- katalyst_taxonomy_cli-2.0.1a7/src/katalyst_taxonomy_cli/options.py +0 -20
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/.gitignore +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/__init__.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/__main__.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/_wiring.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/__init__.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/api.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/backend.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/clone.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config_filters.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config_home.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config_plugins.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config_profile.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/config_schemas.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/core.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/deps.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/diff.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/export.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/init.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/kinds.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/migrate.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/promote.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/relate.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/relocate.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/remove.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/resolve.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/rollback.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/self_update.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/status.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/sync.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/commands/versions.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/discovery.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/fields.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/install.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/installer.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/output.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/py.typed +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_add.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_add_bundle.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_api_command.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_backend_option.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_clone.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_command_signatures.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_home.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_config_schemas_command.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_create.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_create_owners.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_create_typed_and_variants.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_deps.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_git_backend_cli.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_github_backend_cli.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_import_change_set.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_import_inside_repo.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_install.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_installer.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_kinds.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_kinds_plugin_settings.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_labels_annotations.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_lifecycle_kind_selector.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_lint_output.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_lint_profile_graph.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_lint_strict.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_migrate.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_optional_extras.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_output.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_plugin_command.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_relate_update.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_releases.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_relocate.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_remove.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_repository_targets.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_self_channels.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_self_update.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_template_merge.py +0 -0
- {katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/tests/test_update_in_place.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "katalyst-taxonomy-cli"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.1a8"
|
|
4
4
|
description = "CLI for katalyst-taxonomy — the kata command"
|
|
5
5
|
license = { text = "Proprietary" }
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -41,3 +41,37 @@ packages = ["src/katalyst_taxonomy_cli"]
|
|
|
41
41
|
|
|
42
42
|
[tool.hatch.build.targets.wheel.sources]
|
|
43
43
|
"src" = ""
|
|
44
|
+
|
|
45
|
+
[dependency-groups]
|
|
46
|
+
dev = [
|
|
47
|
+
"katalyst-test-bundle",
|
|
48
|
+
"pytest>=8.2",
|
|
49
|
+
"pytest-cov>=5.0",
|
|
50
|
+
"ruff>=0.5",
|
|
51
|
+
"pyright>=1.1",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
addopts = ["-ra"]
|
|
56
|
+
testpaths = ["tests"]
|
|
57
|
+
pythonpath = ["src"]
|
|
58
|
+
|
|
59
|
+
[tool.ruff]
|
|
60
|
+
target-version = "py312"
|
|
61
|
+
line-length = 100
|
|
62
|
+
# As at the repository root, no first-party sources: every import sorts as a third-party one.
|
|
63
|
+
src = []
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = ["E4", "E7", "E9", "F", "B", "I"]
|
|
67
|
+
|
|
68
|
+
[tool.ruff.format]
|
|
69
|
+
quote-style = "double"
|
|
70
|
+
|
|
71
|
+
[tool.pyright]
|
|
72
|
+
include = ["src", "tests"]
|
|
73
|
+
exclude = ["**/node_modules", "**/__pycache__", "**/.*"]
|
|
74
|
+
venvPath = "."
|
|
75
|
+
venv = ".venv"
|
|
76
|
+
pythonVersion = "3.12"
|
|
77
|
+
typeCheckingMode = "strict"
|
{katalyst_taxonomy_cli-2.0.1a7 → katalyst_taxonomy_cli-2.0.1a8}/src/katalyst_taxonomy_cli/app.py
RENAMED
|
@@ -413,6 +413,7 @@ def tax(
|
|
|
413
413
|
profile=profile,
|
|
414
414
|
)
|
|
415
415
|
_register_source_providers(profile)
|
|
416
|
+
_report_pending_sources()
|
|
416
417
|
if ctx.invoked_subcommand == "plugin":
|
|
417
418
|
# `kata tax plugin remove` is how a broken source plugin is taken out; a plugin
|
|
418
419
|
# that will not activate must not stop the command that removes it.
|
|
@@ -469,6 +470,24 @@ def _register_source_providers(profile: str | None) -> None:
|
|
|
469
470
|
ensure_source_providers(True, profile=profile)
|
|
470
471
|
|
|
471
472
|
|
|
473
|
+
def _report_pending_sources() -> None:
|
|
474
|
+
"""Say which plugins and schema bundles a sourced profile declares that are not loaded.
|
|
475
|
+
|
|
476
|
+
Loading one runs its code, so it waits for the user to accept it
|
|
477
|
+
(:mod:`katalyst_taxonomy.services.source_consent`). This only reports, on stderr and
|
|
478
|
+
never failing the command; ``kata config sync`` is where it is accepted.
|
|
479
|
+
"""
|
|
480
|
+
from katalyst_taxonomy.adapters.orchestration import pending_source_declarations
|
|
481
|
+
|
|
482
|
+
for declaration in pending_source_declarations():
|
|
483
|
+
click.echo(
|
|
484
|
+
f"{declaration.describe()}; it is not loaded, because it runs code. Run "
|
|
485
|
+
f"'kata config sync {declaration.profile}' to review and accept it, or "
|
|
486
|
+
f"'{declaration.install_command} {declaration.shown_source}' to install it yourself.",
|
|
487
|
+
err=True,
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
|
|
472
491
|
# ---------------------------------------------------------------------------
|
|
473
492
|
# Plugin activation (#219)
|
|
474
493
|
# ---------------------------------------------------------------------------
|
|
@@ -45,13 +45,11 @@ def add_bundle(ctx: CliContext, source_uri: str, yes: bool) -> None:
|
|
|
45
45
|
that depend solely on katalyst-engine are accepted.
|
|
46
46
|
"""
|
|
47
47
|
from katalyst_taxonomy.services.bundle_service import install_bundle
|
|
48
|
+
from katalyst_taxonomy.services.source_consent import CONFIRM_PROMPT, consent_notice
|
|
48
49
|
|
|
49
50
|
if not yes:
|
|
50
|
-
click.echo(
|
|
51
|
-
|
|
52
|
-
f"Source: {source_uri}"
|
|
53
|
-
)
|
|
54
|
-
if not click.confirm("Proceed?", default=False):
|
|
51
|
+
click.echo(consent_notice("schemas", source_uri))
|
|
52
|
+
if not click.confirm(CONFIRM_PROMPT, default=False):
|
|
55
53
|
ctx.output.echo("Aborted.")
|
|
56
54
|
raise SystemExit(1)
|
|
57
55
|
|
|
@@ -90,6 +88,10 @@ def list_bundles(ctx: CliContext) -> None:
|
|
|
90
88
|
f" {b.name or b.fqn or '(unnamed)'}{version} [{shown_source(b.source)}] "
|
|
91
89
|
f"{pin}, {b.state} kinds: {kinds}"
|
|
92
90
|
)
|
|
91
|
+
if b.error:
|
|
92
|
+
ctx.output.echo(f" error: {b.error}")
|
|
93
|
+
if any(b.state == "failed" for b in bundles):
|
|
94
|
+
ctx.output.echo("A failed bundle is skipped. `kata tax bundle remove <name>` drops it.")
|
|
93
95
|
|
|
94
96
|
|
|
95
97
|
@bundle.command("remove")
|
|
@@ -15,6 +15,7 @@ other command reads the pinned copy.
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
from collections.abc import Callable
|
|
18
19
|
from typing import TYPE_CHECKING, Any
|
|
19
20
|
|
|
20
21
|
import click
|
|
@@ -22,6 +23,7 @@ import click
|
|
|
22
23
|
from ..output import ConsoleOutput, OutputPort
|
|
23
24
|
|
|
24
25
|
if TYPE_CHECKING: # pragma: no cover - typing only
|
|
26
|
+
from katalyst_taxonomy.config.profile_sources import SourceDeclaration
|
|
25
27
|
from katalyst_taxonomy.services.config_sources import SourceStatus, SourceSync
|
|
26
28
|
|
|
27
29
|
__all__ = ["attach"]
|
|
@@ -42,22 +44,55 @@ def _short(pin: str | None) -> str:
|
|
|
42
44
|
return pin[:12] if len(pin) in (40, 64) else pin
|
|
43
45
|
|
|
44
46
|
|
|
47
|
+
def _asker(out: OutputPort, *, yes: bool, interactive: bool) -> Callable[[SourceDeclaration], bool]:
|
|
48
|
+
"""What decides, per declaration, whether the user accepts code from a source."""
|
|
49
|
+
from katalyst_taxonomy.services.source_consent import CONFIRM_PROMPT, consent_notice
|
|
50
|
+
|
|
51
|
+
def ask(declaration: SourceDeclaration) -> bool:
|
|
52
|
+
if yes:
|
|
53
|
+
return True
|
|
54
|
+
if not interactive:
|
|
55
|
+
return False
|
|
56
|
+
out.info(declaration.describe() + ".")
|
|
57
|
+
click.echo(consent_notice(declaration.section, declaration.source))
|
|
58
|
+
try:
|
|
59
|
+
return click.confirm(CONFIRM_PROMPT, default=False)
|
|
60
|
+
except click.Abort:
|
|
61
|
+
click.echo()
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
return ask
|
|
65
|
+
|
|
66
|
+
|
|
45
67
|
@click.command("sync")
|
|
46
68
|
@click.argument("names", nargs=-1, metavar="[PROFILE]...")
|
|
47
69
|
@click.option("--format", "fmt", type=_FORMAT_CHOICE, default="text")
|
|
48
|
-
|
|
70
|
+
@click.option(
|
|
71
|
+
"-y",
|
|
72
|
+
"--yes",
|
|
73
|
+
is_flag=True,
|
|
74
|
+
help="Accept every plugin and schema bundle a profile declares, without asking.",
|
|
75
|
+
)
|
|
76
|
+
def config_sync(names: tuple[str, ...], fmt: str, yes: bool) -> None:
|
|
49
77
|
"""Fetch every sourced profile (or each PROFILE) and pin it.
|
|
50
78
|
|
|
51
79
|
A git source is pinned to its commit, a kata API to its ETag or content hash. Each
|
|
52
80
|
repository a sourced profile's filesystem backends name is found under
|
|
53
81
|
spec.workspace by its remote URL, or cloned there. Exits 1 if any fetch failed; a
|
|
54
82
|
failed one keeps its previous pin.
|
|
83
|
+
|
|
84
|
+
A plugin or schema bundle with a source that a profile declares runs code when it is
|
|
85
|
+
loaded, so it is not loaded until you accept it: this asks about each one that is new
|
|
86
|
+
(or whose pin changed), as 'kata tax plugin add' does. A declined one stays unloaded
|
|
87
|
+
and is asked about again at the next sync. With --format json nothing is asked; only
|
|
88
|
+
--yes accepts.
|
|
55
89
|
"""
|
|
56
90
|
from katalyst_taxonomy.adapters.orchestration import sync_config_sources
|
|
57
91
|
|
|
58
92
|
out = _output()
|
|
93
|
+
accept = _asker(out, yes=yes, interactive=fmt == "text")
|
|
59
94
|
try:
|
|
60
|
-
results: list[SourceSync] = sync_config_sources(names)
|
|
95
|
+
results: list[SourceSync] = sync_config_sources(names, accept=accept)
|
|
61
96
|
except ValueError as exc:
|
|
62
97
|
raise click.ClickException(str(exc)) from exc
|
|
63
98
|
if fmt == "json":
|
|
@@ -79,6 +114,14 @@ def config_sync(names: tuple[str, ...], fmt: str) -> None:
|
|
|
79
114
|
for clone in result.clones:
|
|
80
115
|
how = "cloned to" if clone.cloned else "using"
|
|
81
116
|
out.info(f" {clone.repository}: {how} {clone.path}")
|
|
117
|
+
for declaration in result.accepted:
|
|
118
|
+
out.info(f" Accepted {declaration.kind} {declaration.name!r}.")
|
|
119
|
+
for declaration in result.pending:
|
|
120
|
+
out.warning(
|
|
121
|
+
f"Not accepted: {declaration.kind} {declaration.name!r} from "
|
|
122
|
+
f"{declaration.shown_source}. It is not loaded; 'kata config sync "
|
|
123
|
+
f"{result.profile}' asks again."
|
|
124
|
+
)
|
|
82
125
|
if any(not r.ok for r in results):
|
|
83
126
|
raise SystemExit(1)
|
|
84
127
|
|
|
@@ -71,6 +71,16 @@ from katalyst_taxonomy_cli.context import CliContext
|
|
|
71
71
|
"it must be named."
|
|
72
72
|
),
|
|
73
73
|
)
|
|
74
|
+
@click.option(
|
|
75
|
+
"--force",
|
|
76
|
+
is_flag=True,
|
|
77
|
+
default=False,
|
|
78
|
+
help=(
|
|
79
|
+
"Create it in a state the lifecycle does not start a node in, or without the "
|
|
80
|
+
"fields and links the state's gate needs. Needs --reason; recorded in the node."
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
@click.option("--reason", default="", help="With --force: why the lifecycle is overridden.")
|
|
74
84
|
@click.option(
|
|
75
85
|
"--dry-run",
|
|
76
86
|
is_flag=True,
|
|
@@ -96,6 +106,8 @@ def create(
|
|
|
96
106
|
annotation_pairs: tuple[str, ...],
|
|
97
107
|
target_dir: str | None,
|
|
98
108
|
backend_target: str | None,
|
|
109
|
+
force: bool,
|
|
110
|
+
reason: str,
|
|
99
111
|
dry_run: bool,
|
|
100
112
|
) -> None:
|
|
101
113
|
"""Create a NODE_TYPE node called NAME, in the backend --backend names.
|
|
@@ -115,6 +127,9 @@ def create(
|
|
|
115
127
|
a value of its type (boolean, integer, list, map) and allowed values, a reference
|
|
116
128
|
naming a node of the referenced kind.
|
|
117
129
|
|
|
130
|
+
A node starts active, or as a draft (--set lifecycle_state=draft); the lifecycle and
|
|
131
|
+
the gates of its kind are held on create as on update.
|
|
132
|
+
|
|
118
133
|
--label KEY=VALUE and --annotation KEY=VALUE go in the node's metadata, on any kind.
|
|
119
134
|
A key is a name of letters, digits, '-', '_' and '.' (at most 63), optionally after a
|
|
120
135
|
DNS prefix and '/' (example.org/team); a label's value is such a name (or empty), an
|
|
@@ -139,6 +154,8 @@ def create(
|
|
|
139
154
|
|
|
140
155
|
from .._wiring import resolve_backend
|
|
141
156
|
|
|
157
|
+
if force and not reason.strip():
|
|
158
|
+
raise click.UsageError("--force needs --reason: a forced move is recorded with why.")
|
|
142
159
|
resolved_parent = parent or parent_alt
|
|
143
160
|
node_file = read_node_file(from_file)
|
|
144
161
|
labels = {**node_file.labels, **parse_pairs(label_pairs, option="--label")}
|
|
@@ -171,6 +188,8 @@ def create(
|
|
|
171
188
|
target_dir=target_dir,
|
|
172
189
|
profile=ctx.profile,
|
|
173
190
|
dry_run=dry_run,
|
|
191
|
+
force=force,
|
|
192
|
+
reason=reason,
|
|
174
193
|
)
|
|
175
194
|
if exit_code != 0:
|
|
176
195
|
raise SystemExit(exit_code)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""kata tax drafts — List the drafts: nodes in a draft state, and a promotable backend's draft rows."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from katalyst_taxonomy_cli.context import CliContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command("drafts")
|
|
11
|
+
@click.option(
|
|
12
|
+
"--schema", "show_schema", is_flag=True, help="Show draft schema definitions instead of nodes."
|
|
13
|
+
)
|
|
14
|
+
@click.option(
|
|
15
|
+
"--backend",
|
|
16
|
+
"backend_target",
|
|
17
|
+
default=None,
|
|
18
|
+
help="Backend to operate on.",
|
|
19
|
+
)
|
|
20
|
+
@click.pass_obj
|
|
21
|
+
def drafts(
|
|
22
|
+
ctx: CliContext,
|
|
23
|
+
show_schema: bool,
|
|
24
|
+
backend_target: str | None,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""List the drafts.
|
|
27
|
+
|
|
28
|
+
On any backend, a draft is a node in a draft state of its lifecycle
|
|
29
|
+
(``lifecycle_state: draft``): written, not accepted, and left out of normal reads.
|
|
30
|
+
Move it on with ``kata tax update --set lifecycle_state=…``. Without --backend, the
|
|
31
|
+
drafts of every backend the profile reads.
|
|
32
|
+
|
|
33
|
+
On a promotable backend (Databricks) the rows synced or created but not yet promoted
|
|
34
|
+
to active are listed too, and --schema lists draft schema definitions. Those rows are
|
|
35
|
+
a backend revision, not a lifecycle state; ``kata tax promote`` moves them.
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
|
|
39
|
+
kata tax drafts
|
|
40
|
+
|
|
41
|
+
kata tax drafts --backend local
|
|
42
|
+
|
|
43
|
+
kata tax drafts --schema
|
|
44
|
+
"""
|
|
45
|
+
from katalyst_taxonomy.ports.backend import PromotableBackend
|
|
46
|
+
|
|
47
|
+
from .._wiring import resolve_backend, resolve_promotable_backend
|
|
48
|
+
|
|
49
|
+
if not show_schema and (
|
|
50
|
+
backend_target is None
|
|
51
|
+
or not isinstance(resolve_backend(ctx, backend_target).backend, PromotableBackend)
|
|
52
|
+
):
|
|
53
|
+
_list_draft_nodes(ctx, backend_target)
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
_, backend, _ = resolve_promotable_backend(ctx, backend_target)
|
|
57
|
+
|
|
58
|
+
if show_schema:
|
|
59
|
+
items = backend.list_draft_schema()
|
|
60
|
+
label = "Draft schema definitions"
|
|
61
|
+
else:
|
|
62
|
+
items = backend.list_drafts()
|
|
63
|
+
label = "Draft nodes"
|
|
64
|
+
|
|
65
|
+
if not items:
|
|
66
|
+
ctx.output.echo(f"No {label.lower()} found.")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
ctx.output.echo(f"{label} ({len(items)}):")
|
|
70
|
+
ctx.output.echo("")
|
|
71
|
+
for item in items:
|
|
72
|
+
if show_schema:
|
|
73
|
+
kind = item.get("kind", "?")
|
|
74
|
+
wing = item.get("wing", "?")
|
|
75
|
+
ctx.output.echo(f" [{kind:15s}] wing={wing}")
|
|
76
|
+
else:
|
|
77
|
+
fqtn = item.get("fqtn", "?")
|
|
78
|
+
kind = item.get("kind", "?")
|
|
79
|
+
name = item.get("name", "?")
|
|
80
|
+
ctx.output.echo(f" [{kind:15s}] {name:30s} ({fqtn})")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _list_draft_nodes(ctx: CliContext, backend_target: str | None) -> None:
|
|
84
|
+
"""The nodes of the backend that are in a state the lifecycle hides."""
|
|
85
|
+
from katalyst_taxonomy.engine.accessors import get_identity_fqtn
|
|
86
|
+
from katalyst_taxonomy.engine.bridge import get_default_registry
|
|
87
|
+
from katalyst_taxonomy.services.filters import StateView, narrow_to_states
|
|
88
|
+
|
|
89
|
+
from .._wiring import resolve_read
|
|
90
|
+
|
|
91
|
+
lifecycle = get_default_registry().lifecycle
|
|
92
|
+
resolved = resolve_read(ctx, backend_target)
|
|
93
|
+
nodes = narrow_to_states(
|
|
94
|
+
tuple(node for _, backend in resolved.sources for node in backend.list_nodes()),
|
|
95
|
+
StateView(states=lifecycle.hidden),
|
|
96
|
+
)
|
|
97
|
+
if not nodes:
|
|
98
|
+
ctx.output.echo("No draft nodes found.")
|
|
99
|
+
return
|
|
100
|
+
ctx.output.echo(f"Draft nodes ({len(nodes)}):")
|
|
101
|
+
ctx.output.echo("")
|
|
102
|
+
for node in nodes:
|
|
103
|
+
ctx.output.echo(f" [{node.kind:15s}] {node.name:30s} ({get_identity_fqtn(node)})")
|
|
@@ -24,6 +24,24 @@ from katalyst_taxonomy_cli.context import CliContext
|
|
|
24
24
|
__all__ = ["delete", "import_", "restore"]
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
_FORCE = click.option(
|
|
28
|
+
"--force",
|
|
29
|
+
is_flag=True,
|
|
30
|
+
help=(
|
|
31
|
+
"Move the node against the lifecycle (or past a gate of its kind). Needs --reason; "
|
|
32
|
+
"recorded in the node's provenance."
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
_REASON = click.option(
|
|
36
|
+
"--reason", default="", help="With --force: why the lifecycle is overridden."
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _check_force(force: bool, reason: str) -> None:
|
|
41
|
+
if force and not reason.strip():
|
|
42
|
+
raise click.UsageError("--force needs --reason: a forced move is recorded with why.")
|
|
43
|
+
|
|
44
|
+
|
|
27
45
|
def _service(ctx: CliContext, backend_target: str | None, address: str) -> tuple[Any, Any]:
|
|
28
46
|
from katalyst_taxonomy.engine.bridge import get_default_registry
|
|
29
47
|
from katalyst_taxonomy.services.node_lifecycle import NodeLifecycleService
|
|
@@ -45,21 +63,33 @@ def _service(ctx: CliContext, backend_target: str | None, address: str) -> tuple
|
|
|
45
63
|
help="Take the node out of the backend instead of retiring it.",
|
|
46
64
|
)
|
|
47
65
|
@click.option("--dry-run", is_flag=True, help="With --remove: show the impact; change nothing.")
|
|
66
|
+
@_FORCE
|
|
67
|
+
@_REASON
|
|
48
68
|
@click.pass_obj
|
|
49
69
|
def delete(
|
|
50
|
-
ctx: CliContext,
|
|
70
|
+
ctx: CliContext,
|
|
71
|
+
address: str,
|
|
72
|
+
backend_target: str | None,
|
|
73
|
+
remove: bool,
|
|
74
|
+
dry_run: bool,
|
|
75
|
+
force: bool,
|
|
76
|
+
reason: str,
|
|
51
77
|
) -> None:
|
|
52
78
|
"""Delete the node ADDRESS (``backend:fqtn``) names: retire it, or with --remove, remove it.
|
|
53
79
|
|
|
54
80
|
A removal follows each referring relationship's delete policy: block (refused),
|
|
55
81
|
cascade (removed too), detach (dropped from the referrer) or redirect (moved to the
|
|
56
82
|
node's replacement). It is shown first with --dry-run, and is all or nothing.
|
|
83
|
+
|
|
84
|
+
A retire is a move to the lifecycle's retired state, held to the lifecycle as an
|
|
85
|
+
update is (--force --reason overrides).
|
|
57
86
|
"""
|
|
87
|
+
_check_force(force, reason)
|
|
58
88
|
service, resolved = _service(ctx, backend_target, address)
|
|
59
89
|
if not remove:
|
|
60
90
|
if dry_run:
|
|
61
91
|
raise click.UsageError("--dry-run goes with --remove; a retire changes one field.")
|
|
62
|
-
outcome = service.retire(resolved.address)
|
|
92
|
+
outcome = service.retire(resolved.address, force=force, reason=reason)
|
|
63
93
|
if not outcome.success:
|
|
64
94
|
ctx.output.echo(f"Error: {outcome.error}")
|
|
65
95
|
raise SystemExit(1)
|
|
@@ -81,11 +111,20 @@ def delete(
|
|
|
81
111
|
@click.option(
|
|
82
112
|
"--backend", "backend_target", default=None, help="The backend, when ADDRESS has no prefix."
|
|
83
113
|
)
|
|
114
|
+
@_FORCE
|
|
115
|
+
@_REASON
|
|
84
116
|
@click.pass_obj
|
|
85
|
-
def restore(
|
|
86
|
-
|
|
117
|
+
def restore(
|
|
118
|
+
ctx: CliContext, address: str, backend_target: str | None, force: bool, reason: str
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Return the retired node ADDRESS to service, after the local shapes pass on it.
|
|
121
|
+
|
|
122
|
+
Only a retired node is restored; any other state moves with ``kata tax update --set
|
|
123
|
+
lifecycle_state=STATE``.
|
|
124
|
+
"""
|
|
125
|
+
_check_force(force, reason)
|
|
87
126
|
service, resolved = _service(ctx, backend_target, address)
|
|
88
|
-
outcome = service.restore(resolved.address)
|
|
127
|
+
outcome = service.restore(resolved.address, force=force, reason=reason)
|
|
89
128
|
if not outcome.success:
|
|
90
129
|
ctx.output.echo(f"Error: {outcome.error}")
|
|
91
130
|
raise SystemExit(1)
|
|
@@ -126,6 +126,7 @@ def lint(ctx: CliContext, verbose: bool, strict: bool, backend: str | None) -> N
|
|
|
126
126
|
for title, found in (
|
|
127
127
|
("Undeclared spec keys", result.undeclared_fields),
|
|
128
128
|
("Misplaced documents", result.misplaced_documents),
|
|
129
|
+
("Forced lifecycle moves", result.forced_moves),
|
|
129
130
|
("Relationships no kind carries", result.uncarried_relationships),
|
|
130
131
|
("Shape findings", result.shape_findings),
|
|
131
132
|
("Shape warnings", result.shape_warnings),
|
|
@@ -151,6 +152,7 @@ def lint(ctx: CliContext, verbose: bool, strict: bool, backend: str | None) -> N
|
|
|
151
152
|
+ len(result.duplicate_names)
|
|
152
153
|
+ len(result.undeclared_fields)
|
|
153
154
|
+ len(result.misplaced_documents)
|
|
155
|
+
+ len(result.forced_moves)
|
|
154
156
|
+ len(result.uncarried_relationships)
|
|
155
157
|
+ len(result.shape_findings)
|
|
156
158
|
+ len(result.shape_warnings)
|
|
@@ -50,13 +50,12 @@ def add_plugin(ctx: CliContext, source_uri: str, yes: bool) -> None:
|
|
|
50
50
|
katalyst_taxonomy.plugins entry point and depends only on katalyst-engine and
|
|
51
51
|
katalyst-taxonomy. Installing executes the plugin's Python code.
|
|
52
52
|
"""
|
|
53
|
+
from katalyst_taxonomy.services.source_consent import CONFIRM_PROMPT, consent_notice
|
|
53
54
|
from katalyst_taxonomy.sources.schemes import BUNDLE_SOURCE_SCHEMES, reject_unknown_scheme
|
|
54
55
|
|
|
55
56
|
if not yes:
|
|
56
|
-
click.echo(
|
|
57
|
-
|
|
58
|
-
)
|
|
59
|
-
if not click.confirm("Proceed?", default=False):
|
|
57
|
+
click.echo(consent_notice("plugins", source_uri))
|
|
58
|
+
if not click.confirm(CONFIRM_PROMPT, default=False):
|
|
60
59
|
ctx.output.echo("Aborted.")
|
|
61
60
|
raise SystemExit(1)
|
|
62
61
|
try:
|
|
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from katalyst_taxonomy_cli.context import CliContext
|
|
10
|
+
from katalyst_taxonomy_cli.options import state_options, state_view
|
|
10
11
|
|
|
11
12
|
if TYPE_CHECKING: # pragma: no cover - typing only
|
|
12
13
|
from katalyst_engine.model.node import Node
|
|
@@ -55,6 +56,7 @@ if TYPE_CHECKING: # pragma: no cover - typing only
|
|
|
55
56
|
"(its declaration's holds); each is shown with that directory."
|
|
56
57
|
),
|
|
57
58
|
)
|
|
59
|
+
@state_options
|
|
58
60
|
@click.pass_obj
|
|
59
61
|
def query(
|
|
60
62
|
ctx: CliContext,
|
|
@@ -64,12 +66,18 @@ def query(
|
|
|
64
66
|
fqtn: str | None,
|
|
65
67
|
name: str | None,
|
|
66
68
|
holds: str | None,
|
|
69
|
+
include_drafts: bool,
|
|
70
|
+
state_names: tuple[str, ...],
|
|
67
71
|
) -> None:
|
|
68
72
|
"""Query nodes and relationships from a backend.
|
|
69
73
|
|
|
70
74
|
Uses the unified TaxonomyBackend.list_nodes() and list_relationships()
|
|
71
75
|
interface — works against any backend implementation.
|
|
72
76
|
|
|
77
|
+
A node in a state other than active is marked with it, `(draft)`, `(retired)`. Drafts
|
|
78
|
+
are left out unless --include-drafts or --state draft asks for them. Asked about one
|
|
79
|
+
node (--fqtn naming exactly one), the output also says where it may move next.
|
|
80
|
+
|
|
73
81
|
Examples:
|
|
74
82
|
|
|
75
83
|
kata tax query --kind tool
|
|
@@ -85,6 +93,10 @@ def query(
|
|
|
85
93
|
kata tax query --fqtn prod-graph:payments
|
|
86
94
|
|
|
87
95
|
kata tax query --fqtn repo:shop.web --holds ROLE
|
|
96
|
+
|
|
97
|
+
kata tax query --state draft
|
|
98
|
+
|
|
99
|
+
kata tax query --include-drafts --kind capability
|
|
88
100
|
"""
|
|
89
101
|
from .._wiring import resolve_read
|
|
90
102
|
|
|
@@ -131,7 +143,9 @@ def query(
|
|
|
131
143
|
from katalyst_taxonomy.services.filters import visible_nodes
|
|
132
144
|
|
|
133
145
|
try:
|
|
134
|
-
nodes = visible_nodes(
|
|
146
|
+
nodes = visible_nodes(
|
|
147
|
+
ctx.cwd, nodes, profile=ctx.profile, states=state_view(include_drafts, state_names)
|
|
148
|
+
)
|
|
135
149
|
except ValueError as exc:
|
|
136
150
|
raise click.ClickException(str(exc)) from exc
|
|
137
151
|
held: dict[int, str] = {}
|
|
@@ -148,6 +162,12 @@ def query(
|
|
|
148
162
|
ctx.output.echo(f"Nodes ({len(nodes)}):")
|
|
149
163
|
ctx.output.echo("")
|
|
150
164
|
from katalyst_taxonomy.engine.accessors import get_identity_fqtn
|
|
165
|
+
from katalyst_taxonomy.engine.bridge import get_default_registry
|
|
166
|
+
from katalyst_taxonomy.services.lifecycle_rule import LifecycleRule
|
|
167
|
+
|
|
168
|
+
registry = get_default_registry()
|
|
169
|
+
rule = LifecycleRule(registry)
|
|
170
|
+
lifecycle = registry.lifecycle
|
|
151
171
|
|
|
152
172
|
for node in nodes:
|
|
153
173
|
# Qualified, because the same name in two backends is two nodes.
|
|
@@ -157,9 +177,14 @@ def query(
|
|
|
157
177
|
)
|
|
158
178
|
continue
|
|
159
179
|
desc = (node.description or "")[:55]
|
|
160
|
-
# A
|
|
161
|
-
|
|
162
|
-
|
|
180
|
+
# A node out of the default state says so (katalyst-core's lifecycle): `(draft)`,
|
|
181
|
+
# `(retired)`. Retired nodes are still in the graph; drafts only when asked for.
|
|
182
|
+
marked = f" ({state})" if (state := rule.state_of(node)) != lifecycle.default else ""
|
|
183
|
+
ctx.output.echo(f" [{node.kind:15s}] {get_identity_fqtn(node):40s} {desc}{marked}")
|
|
184
|
+
if len(nodes) == 1:
|
|
185
|
+
moves = ", ".join(rule.next_moves(nodes[0])) or "none"
|
|
186
|
+
ctx.output.echo("")
|
|
187
|
+
ctx.output.echo(f"State: {rule.state_of(nodes[0])}; may move to: {moves}")
|
|
163
188
|
|
|
164
189
|
|
|
165
190
|
def _narrow_to_selected_subtree(
|
|
@@ -80,6 +80,7 @@ def rescaffold(
|
|
|
80
80
|
from katalyst_taxonomy.engine.accessors import get_source_path
|
|
81
81
|
from katalyst_taxonomy.engine.qualification import match_fqtn_in
|
|
82
82
|
from katalyst_taxonomy.ports.backend import repository_root_of
|
|
83
|
+
from katalyst_taxonomy.services.filters import SHOW_ALL_STATES
|
|
83
84
|
from katalyst_taxonomy.services.rescaffold import rescaffold_node
|
|
84
85
|
from katalyst_taxonomy.services.template_install import template_base_resolver
|
|
85
86
|
|
|
@@ -118,7 +119,7 @@ def rescaffold(
|
|
|
118
119
|
mode=mode,
|
|
119
120
|
dry_run=dry_run,
|
|
120
121
|
create_hooks=create_hooks(),
|
|
121
|
-
load_taxonomy=lambda: load_taxonomy(root, profile=ctx.profile),
|
|
122
|
+
load_taxonomy=lambda: load_taxonomy(root, profile=ctx.profile, states=SHOW_ALL_STATES),
|
|
122
123
|
)
|
|
123
124
|
if not outcome.success:
|
|
124
125
|
ctx.output.echo(f"Error: {outcome.error}")
|
|
@@ -5,18 +5,26 @@ from __future__ import annotations
|
|
|
5
5
|
import click
|
|
6
6
|
|
|
7
7
|
from katalyst_taxonomy_cli.context import CliContext
|
|
8
|
+
from katalyst_taxonomy_cli.options import state_options, state_view
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@click.command("show")
|
|
11
12
|
@click.option("--format", "fmt", type=click.Choice(["tree", "list", "json"]), default=None)
|
|
13
|
+
@state_options
|
|
12
14
|
@click.pass_obj
|
|
13
|
-
def show(
|
|
14
|
-
|
|
15
|
+
def show(
|
|
16
|
+
ctx: CliContext, fmt: str | None, include_drafts: bool, state_names: tuple[str, ...]
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Show the taxonomy structure.
|
|
19
|
+
|
|
20
|
+
Drafts are left out unless --include-drafts or --state asks for them.
|
|
21
|
+
"""
|
|
15
22
|
import json as json_module
|
|
16
23
|
|
|
17
24
|
from katalyst_taxonomy.services.serialization import build_tree_lines, serialize_taxonomy
|
|
18
25
|
|
|
19
26
|
fmt = fmt or ctx.output_format or "tree"
|
|
27
|
+
ctx.states = state_view(include_drafts, state_names)
|
|
20
28
|
service = ctx.taxonomy_service
|
|
21
29
|
|
|
22
30
|
if fmt == "json":
|