py-wlcli 0.8.1__tar.gz → 0.8.2__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.
Files changed (323) hide show
  1. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/PKG-INFO +1 -1
  2. py_wlcli-0.8.2/VERSION +1 -0
  3. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/capabilities.py +2 -1
  4. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/cc/checks.py +160 -0
  5. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/cc/mutate.py +31 -8
  6. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/env/cli.py +17 -4
  7. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/env_status.py +93 -13
  8. py_wlcli-0.8.1/VERSION +0 -1
  9. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/.gitignore +0 -0
  10. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/LICENSE +0 -0
  11. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/README.md +0 -0
  12. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/pyproject.toml +0 -0
  13. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/__init__.py +0 -0
  14. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/__init__.py +0 -0
  15. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/__main__.py +0 -0
  16. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/cc/__init__.py +0 -0
  17. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/cc/cli.py +0 -0
  18. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/cli_click.py +0 -0
  19. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/__init__.py +0 -0
  20. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/base.py +0 -0
  21. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/__init__.py +0 -0
  22. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/build.py +0 -0
  23. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/build_utils.py +0 -0
  24. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/__init__.py +0 -0
  25. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/cleanup.py +0 -0
  26. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/coordinator.py +0 -0
  27. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/environment.py +0 -0
  28. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/rust_builder.py +0 -0
  29. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/stubs.py +0 -0
  30. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/dist.py +0 -0
  31. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/test.py +0 -0
  32. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/__init__.py +0 -0
  33. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/build.py +0 -0
  34. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/clean.py +0 -0
  35. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/clean_utils.py +0 -0
  36. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/core.py +0 -0
  37. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/__init__.py +0 -0
  38. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/dead_code_command.py +0 -0
  39. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/detector.py +0 -0
  40. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/fixer.py +0 -0
  41. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/reporter.py +0 -0
  42. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/utils.py +0 -0
  43. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/lfs.py +0 -0
  44. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/python.py +0 -0
  45. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/rust.py +0 -0
  46. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/utils/__init__.py +0 -0
  47. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/venv.py +0 -0
  48. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/cleanup.py +0 -0
  49. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/click_base.py +0 -0
  50. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/config/__init__.py +0 -0
  51. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/config/config.py +0 -0
  52. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/__init__.py +0 -0
  53. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/debug.py +0 -0
  54. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/debug_cache.py +0 -0
  55. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/debug_subagent.py +0 -0
  56. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/output_formatter.py +0 -0
  57. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/source_hasher.py +0 -0
  58. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/__init__.py +0 -0
  59. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_cache_adapter.py +0 -0
  60. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_command.py +0 -0
  61. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_coordinator.py +0 -0
  62. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_executor.py +0 -0
  63. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_outcome.py +0 -0
  64. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_path_handler.py +0 -0
  65. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_progress.py +0 -0
  66. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_reporter.py +0 -0
  67. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/python_formatter.py +0 -0
  68. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/format/rust_formatter.py +0 -0
  69. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/gate/__init__.py +0 -0
  70. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/gate/gate_command.py +0 -0
  71. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/gate/preflight.py +0 -0
  72. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/__init__.py +0 -0
  73. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/config.py +0 -0
  74. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/git_facts.py +0 -0
  75. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/git_flow.py +0 -0
  76. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/hook.py +0 -0
  77. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/policy.py +0 -0
  78. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/git/push_update.py +0 -0
  79. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/__init__.py +0 -0
  80. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/__init__.py +0 -0
  81. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/check_git_bash.py +0 -0
  82. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/error_handler.py +0 -0
  83. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/exceptions.py +0 -0
  84. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/__init__.py +0 -0
  85. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/cargo_sync.py +0 -0
  86. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/config_manager.py +0 -0
  87. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/directory_utils.py +0 -0
  88. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/__init__.py +0 -0
  89. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/branch_creator.py +0 -0
  90. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_flow_interface.py +0 -0
  91. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_flow_manager.py +0 -0
  92. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_lfs_manager.py +0 -0
  93. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_utility.py +0 -0
  94. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/gitignore_manager.py +0 -0
  95. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git_initializer.py +0 -0
  96. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/i18n_manager.py +0 -0
  97. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/log_manager.py +0 -0
  98. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/__init__.py +0 -0
  99. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/config_generator.py +0 -0
  100. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/directory_creator.py +0 -0
  101. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/hook_source.py +0 -0
  102. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/hooks_manager.py +0 -0
  103. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/readme_handler.py +0 -0
  104. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +0 -0
  105. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/setup_handler.py +0 -0
  106. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/sop_generator.py +0 -0
  107. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/template_copier.py +0 -0
  108. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/template_manager.py +0 -0
  109. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/pyproject_generator.py +0 -0
  110. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/rust_initializer.py +0 -0
  111. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/symlink_cleaner.py +0 -0
  112. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/symlink_manager.py +0 -0
  113. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/venv_manager.py +0 -0
  114. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/initenv.py +0 -0
  115. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/__init__.py +0 -0
  116. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/environment_initializer.py +0 -0
  117. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/git_lfs_initializer.py +0 -0
  118. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/project_structure_initializer.py +0 -0
  119. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/README.md +0 -0
  120. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/__init__.py +0 -0
  121. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/cli.py +0 -0
  122. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/config.py +0 -0
  123. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/hook.py +0 -0
  124. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/initializer.py +0 -0
  125. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/manager.py +0 -0
  126. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/policy.py +0 -0
  127. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/watcher.py +0 -0
  128. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/__init__.py +0 -0
  129. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_command.py +0 -0
  130. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_executor.py +0 -0
  131. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_reporter.py +0 -0
  132. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_run.py +0 -0
  133. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/mypy_config.py +0 -0
  134. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/registry.py +0 -0
  135. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/__init__.py +0 -0
  136. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/__init__.py +0 -0
  137. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/capabilities.py +0 -0
  138. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/config.py +0 -0
  139. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/version_cache.py +0 -0
  140. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/__init__.py +0 -0
  141. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/base_handler.py +0 -0
  142. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/install_handler.py +0 -0
  143. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/status_handler.py +0 -0
  144. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/uninstall_handler.py +0 -0
  145. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/update_handler.py +0 -0
  146. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/version_handler.py +0 -0
  147. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/self_command.py +0 -0
  148. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/__init__.py +0 -0
  149. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/installation_manager.py +0 -0
  150. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/local_installer.py +0 -0
  151. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/pypi_updater.py +0 -0
  152. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/windows_update.py +0 -0
  153. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/__init__.py +0 -0
  154. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/base_dependency_analyzer.py +0 -0
  155. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/batch_processor.py +0 -0
  156. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/cache_manager.py +0 -0
  157. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/coverage_analyzer.py +0 -0
  158. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/coverage_cache_manager.py +0 -0
  159. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/progress_manager.py +0 -0
  160. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/python_env_detector.py +0 -0
  161. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/report_generator.py +0 -0
  162. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/single_test_executor.py +0 -0
  163. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/speed_checker.py +0 -0
  164. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_command_builder.py +0 -0
  165. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_commands.py +0 -0
  166. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_reporter.py +0 -0
  167. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_result_handler.py +0 -0
  168. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_runner.py +0 -0
  169. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_utils.py +0 -0
  170. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/__init__.py +0 -0
  171. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/coverage_parser.py +0 -0
  172. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/env_info.py +0 -0
  173. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/junit_parser.py +0 -0
  174. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/markdown_utils.py +0 -0
  175. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/project_root.py +0 -0
  176. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/__init__.py +0 -0
  177. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/__init__.py +0 -0
  178. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/backup_manager.py +0 -0
  179. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/component_manager.py +0 -0
  180. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/conflict_resolver.py +0 -0
  181. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/vendors_updater.py +0 -0
  182. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/version_tracker.py +0 -0
  183. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/update_command.py +0 -0
  184. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/update/utils/__init__.py +0 -0
  185. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/version/__init__.py +0 -0
  186. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/version/version_command.py +0 -0
  187. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/commands/workflow.py +0 -0
  188. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/env/__init__.py +0 -0
  189. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/envelope.py +0 -0
  190. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/exceptions.py +0 -0
  191. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/lib/__init__.py +0 -0
  192. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/lib/rust_utils.py +0 -0
  193. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/mcp/__init__.py +0 -0
  194. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/mcp/capabilities.py +0 -0
  195. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/mcp/cli.py +0 -0
  196. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/mcp/gitlab.py +0 -0
  197. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/mcp/k8s.py +0 -0
  198. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/mcp/protocol.py +0 -0
  199. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/platform.py +0 -0
  200. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/quality/__init__.py +0 -0
  201. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/__init__.py +0 -0
  202. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/cache.py +0 -0
  203. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/cache_ledger.py +0 -0
  204. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/cache_store.py +0 -0
  205. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/__init__.py +0 -0
  206. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/config_loader.py +0 -0
  207. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/core.py +0 -0
  208. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/defaults.py +0 -0
  209. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/env_exporter.py +0 -0
  210. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/env_parser.py +0 -0
  211. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/config/validation.py +0 -0
  212. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/error_handler.py +0 -0
  213. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/file_copier.py +0 -0
  214. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/file_operations.py +0 -0
  215. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/language_utils.py +0 -0
  216. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/lazy_import.py +0 -0
  217. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/log_levels.py +0 -0
  218. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/log_rotators.py +0 -0
  219. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/logging.py +0 -0
  220. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/output_context.py +0 -0
  221. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/__init__.py +0 -0
  222. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/decorators.py +0 -0
  223. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/exporter.py +0 -0
  224. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/models.py +0 -0
  225. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/monitor.py +0 -0
  226. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/performance_monitor.py +0 -0
  227. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/platform_adapter.py +0 -0
  228. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/pre_commit.py +0 -0
  229. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/pre_commit_config.py +0 -0
  230. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/root.py +0 -0
  231. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/root_fallback.py +0 -0
  232. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/run_evidence.py +0 -0
  233. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logger.py +0 -0
  234. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/__init__.py +0 -0
  235. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/config.py +0 -0
  236. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/core.py +0 -0
  237. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/env.py +0 -0
  238. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/filtering.py +0 -0
  239. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/filters.py +0 -0
  240. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/formatters.py +0 -0
  241. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/handlers.py +0 -0
  242. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/logger.py +0 -0
  243. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/subprocess.py +0 -0
  244. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/subprocess_utils.py +0 -0
  245. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/test_utils/__init__.py +0 -0
  246. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/test_utils/test_filter.py +0 -0
  247. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_run.py +0 -0
  248. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_tool.py +0 -0
  249. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_tree.py +0 -0
  250. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_workspace.py +0 -0
  251. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/version/__init__.py +0 -0
  252. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/version/pypi_version_checker.py +0 -0
  253. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_comparator.py +0 -0
  254. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_detectors.py +0 -0
  255. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_service.py +0 -0
  256. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_updater.py +0 -0
  257. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/wl_dir_updater.py +0 -0
  258. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/__init__.py +0 -0
  259. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/core.py +0 -0
  260. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/detection_strategies.py +0 -0
  261. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/exceptions.py +0 -0
  262. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/types.py +0 -0
  263. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/venv_resolver.py +0 -0
  264. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/.codespellrc +0 -0
  265. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/dependencies.toml +0 -0
  266. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/mypy.ini +0 -0
  267. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/pyproject_defaults.toml +0 -0
  268. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/template_config.toml +0 -0
  269. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/tool_configs.toml +0 -0
  270. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/git/.gitignore +0 -0
  271. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/git/.pre-commit-config.yaml +0 -0
  272. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/applypatch-msg.sample +0 -0
  273. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/commit-msg.sample +0 -0
  274. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/fsmonitor-watchman.sample +0 -0
  275. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/post-update.sample +0 -0
  276. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-applypatch.sample +0 -0
  277. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-commit +0 -0
  278. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-commit.legacy +0 -0
  279. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-commit.sample +0 -0
  280. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-merge-commit.sample +0 -0
  281. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-push.sample +0 -0
  282. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-rebase.sample +0 -0
  283. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-receive.sample +0 -0
  284. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/prepare-commit-msg.sample +0 -0
  285. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/push-to-checkout.sample +0 -0
  286. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/sendemail-validate.sample +0 -0
  287. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/applypatch-msg.sample +0 -0
  288. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/check_lockfile.py +0 -0
  289. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/check_lockfile.sh +0 -0
  290. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/commit-msg.sample +0 -0
  291. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +0 -0
  292. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/post-update.sample +0 -0
  293. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-applypatch.sample +0 -0
  294. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit +0 -0
  295. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit.legacy +0 -0
  296. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit.py +0 -0
  297. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit.sample +0 -0
  298. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-merge-commit.sample +0 -0
  299. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-push +0 -0
  300. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-push.sample +0 -0
  301. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-rebase.sample +0 -0
  302. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-receive.sample +0 -0
  303. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +0 -0
  304. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/update.sample +0 -0
  305. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/win/work.bat +0 -0
  306. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/.gitignore +0 -0
  307. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/.python-version +0 -0
  308. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/LICENSE +0 -0
  309. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/README.md +0 -0
  310. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/pyproject.toml +0 -0
  311. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/pyproject_no_workspace.toml +0 -0
  312. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/pyproject_workspace.toml +0 -0
  313. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/readme/README.md +0 -0
  314. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/Cargo.toml +0 -0
  315. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/lib/__init__.py +0 -0
  316. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/lib/rust_utils.py +0 -0
  317. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/src/lib.rs +0 -0
  318. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/src/main.rs +0 -0
  319. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/tests/test_rust_fallback.py +0 -0
  320. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/git-dev-sop.md +0 -0
  321. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/industrial-standard-sop.md +0 -0
  322. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/python-sop.md +0 -0
  323. {py_wlcli-0.8.1 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/rust-readme.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: py_wlcli
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: wl_cli - Python项目
5
5
  Project-URL: Homepage, https://gitlab.gewinnrobo.com/Humuyuan/wl-cli
6
6
  Project-URL: Issues, https://gitlab.gewinnrobo.com/Humuyuan/wl-cli/-/issues
py_wlcli-0.8.2/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.8.2
@@ -1,4 +1,4 @@
1
- """The shared capability registry for the ``wl`` CLI (issues #270, #221).
1
+ """The shared capability registry for the ``wl`` CLI (issues #270, #221, #231).
2
2
 
3
3
  Capabilities are the stable, dotted names a consumer (wlcc) probes instead of
4
4
  grepping ``--help`` for an implementation flag (wlcc ADR-0010, decision 6):
@@ -43,6 +43,7 @@ CAPABILITY_SINCE: dict[str, str] = {
43
43
  "cc.statusline": "0.8.0",
44
44
  "cc.upgrade": "0.8.0",
45
45
  "env.check": "0.8.0",
46
+ "env.check.require": "0.8.2",
46
47
  "env.repair": "0.8.0",
47
48
  "mcp.gitlab": "0.8.0",
48
49
  "mcp.k8s": "0.8.0",
@@ -107,6 +107,15 @@ MCP_SERVE_ARGS: dict[str, str] = {
107
107
  "k8s-diagnose": "k8s",
108
108
  }
109
109
 
110
+ #: Environment the registered argv needs, per server (#229). ``gitlab`` owns
111
+ #: its default host inside ``server.py``; ``k8s-diagnose`` cannot discover the
112
+ #: SSH target, so the registration must carry it. This is the single source
113
+ #: for both the ``claude mcp add -e`` argv and the registration check.
114
+ MCP_SERVE_ENV: dict[str, tuple[tuple[str, str], ...]] = {
115
+ "gitlab": (),
116
+ "k8s-diagnose": (("K8S_SSH_HOST", "ubuntu-server"),),
117
+ }
118
+
110
119
  #: Capability the ``wl`` on ``PATH`` must advertise before a registration argv
111
120
  #: counts as verifiable (#228). Consumers (wlcc) use the same bit to decide
112
121
  #: that registration goes through ``wl mcp serve``.
@@ -608,6 +617,124 @@ def _wl_reason(fields: dict[str, Any]) -> str:
608
617
  return f"the wl CLI on PATH is not usable ({state or 'unknown state'})"
609
618
 
610
619
 
620
+ def mcp_config_path() -> Path:
621
+ """Return Claude Code's user-scope config file (``claude mcp add -s user``).
622
+
623
+ ``CLAUDE_CONFIG_DIR`` moves the file *inside* that directory, while the
624
+ default location is ``~/.claude.json`` -- a sibling of ``~/.claude``, not
625
+ ``~/.claude/.claude.json``. ``HostContext.config_root`` therefore cannot
626
+ supply this path on its own. Verified against the CLI on 2026-11-05.
627
+ """
628
+ raw = os.environ.get("CLAUDE_CONFIG_DIR")
629
+ if raw:
630
+ # The real CLI resolves this relative to the cwd and does **not**
631
+ # expand ``~`` (measured 2026-11-05), so neither may we.
632
+ return Path(os.path.abspath(raw)) / ".claude.json"
633
+ return Path(os.path.expanduser("~/.claude.json"))
634
+
635
+
636
+ def _registration_status(name: str, entry: Any, wl: str) -> str:
637
+ """Classify one stored registration as ``ok``, ``missing`` or ``stale``.
638
+
639
+ The stamp alone is not evidence: a payload swap that keeps the version
640
+ leaves the old argv pointing at a deleted plugin file (#229), so the
641
+ stored command, args and required environment are compared verbatim.
642
+ """
643
+ if not isinstance(entry, dict):
644
+ return "missing"
645
+ if entry.get("type", "stdio") != "stdio":
646
+ return "stale"
647
+ if entry.get("command") != wl:
648
+ return "stale"
649
+ if entry.get("args") != ["mcp", "serve", MCP_SERVE_ARGS[name]]:
650
+ return "stale"
651
+ env = entry.get("env")
652
+ if env is None:
653
+ env = {}
654
+ if not isinstance(env, dict):
655
+ return "stale"
656
+ for key, _default in MCP_SERVE_ENV[name]:
657
+ # Only presence matters: a user's custom host (e.g. a real K8S_SSH_HOST)
658
+ # is a working registration and must not be rewritten to the default.
659
+ if not env.get(key):
660
+ return "stale"
661
+ return "ok"
662
+
663
+
664
+ def _cwd() -> str:
665
+ """The working directory Claude Code keys the local scope by."""
666
+ return os.path.abspath(os.getcwd())
667
+
668
+
669
+ def _shadowing_servers(config: dict[str, Any]) -> dict[str, str]:
670
+ """Return server name -> scope for entries that shadow the user scope.
671
+
672
+ Claude Code resolves ``mcpServers`` for the working directory: the local
673
+ scope in ``projects[<cwd>].mcpServers`` and the project ``<cwd>/.mcp.json``
674
+ both take precedence over the user-scope map (#229 review). A shadowing
675
+ entry is reported, never rewritten -- it belongs to the project, not wlcc.
676
+ """
677
+ shadowed: dict[str, str] = {}
678
+ cwd = _cwd()
679
+ projects = config.get("projects")
680
+ if isinstance(projects, dict):
681
+ local = projects.get(cwd)
682
+ if isinstance(local, dict):
683
+ servers = local.get("mcpServers")
684
+ if isinstance(servers, dict):
685
+ for name in MCP_SERVERS:
686
+ if name in servers:
687
+ shadowed[name] = "local"
688
+ project_data, _ = _read_json_object(Path(cwd) / ".mcp.json")
689
+ if project_data is not None:
690
+ servers = project_data.get("mcpServers")
691
+ if isinstance(servers, dict):
692
+ for name in MCP_SERVERS:
693
+ shadowed.setdefault(name, "project")
694
+ return shadowed
695
+
696
+
697
+ def probe_mcp_registrations(wl: str) -> dict[str, Any]:
698
+ """Report the user-scope registrations for the servers wlcc owns.
699
+
700
+ A missing config file reads as "no registrations" rather than an error --
701
+ ``claude mcp add`` creates it, so the first repair must be allowed to
702
+ write. An unreadable file is reported through ``error`` and never
703
+ rewritten. ``stale`` lists the server names whose stored argv does not
704
+ match ``<wl> mcp serve <sub>``; ``shadowed`` names the same-name entries
705
+ in the local/project scopes that override the user registration.
706
+ """
707
+ path = mcp_config_path()
708
+ data, error = _read_json_object(path)
709
+ report: dict[str, Any] = {
710
+ "config": str(path),
711
+ "servers": {},
712
+ "stale": [],
713
+ "shadowed": {},
714
+ "error": error,
715
+ }
716
+ if data is None:
717
+ return report
718
+ servers = data.get("mcpServers")
719
+ if servers is None:
720
+ servers = {}
721
+ elif not isinstance(servers, dict):
722
+ report["error"] = f"{path}: 'mcpServers' is not an object"
723
+ return report
724
+ for name in MCP_SERVERS:
725
+ entry = servers.get(name)
726
+ status = _registration_status(name, entry, wl)
727
+ report["servers"][name] = {
728
+ "status": status,
729
+ "command": entry.get("command") if isinstance(entry, dict) else None,
730
+ "args": entry.get("args") if isinstance(entry, dict) else None,
731
+ }
732
+ if status != "ok":
733
+ report["stale"].append(name)
734
+ report["shadowed"] = _shadowing_servers(data)
735
+ return report
736
+
737
+
611
738
  def probe_mcp(host: HostContext) -> dict[str, Any]:
612
739
  """§3: the registration target, version stamp and interpreter visibility.
613
740
 
@@ -616,6 +743,11 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
616
743
  instead of looking for a plugin-root ``mcp-tools/server.py``. The
617
744
  interpreter probe stays a report field but can no longer gate the section
618
745
  -- ``python`` is not part of the registered command any more.
746
+
747
+ Since #229 the version stamp is not the only evidence: the stored
748
+ user-scope registration is read back and compared verbatim, because a
749
+ payload swap that keeps the version number used to leave a dead
750
+ ``mcp-tools/server.py`` argv behind while this section still said ``ok``.
619
751
  """
620
752
  cache = _wlcc_cache(host)
621
753
  fields: dict[str, Any] = {
@@ -625,6 +757,8 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
625
757
  "plugin_root": None,
626
758
  "rejected": False,
627
759
  "servers": list(MCP_SERVERS),
760
+ "mcp_config": str(mcp_config_path()),
761
+ "registrations": {},
628
762
  "wl": _probe_wl_serve(),
629
763
  "python": _probe_python(),
630
764
  }
@@ -655,6 +789,13 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
655
789
  if not wl_state.startswith("ok:"):
656
790
  return _result("unverifiable", _wl_reason(fields["wl"]), **fields)
657
791
 
792
+ registration = probe_mcp_registrations(str(fields["wl"].get("path") or ""))
793
+ fields["mcp_config"] = registration["config"]
794
+ fields["registrations"] = registration["servers"]
795
+ fields["shadowed"] = registration["shadowed"]
796
+ if registration["error"]:
797
+ return _result("unverifiable", registration["error"], **fields)
798
+
658
799
  if registered != version:
659
800
  return _result(
660
801
  "dangling",
@@ -662,6 +803,25 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
662
803
  "wl cc repair will re-register",
663
804
  **fields,
664
805
  )
806
+
807
+ if registration["shadowed"]:
808
+ scopes = ", ".join(
809
+ f"{name} ({scope})" for name, scope in registration["shadowed"].items()
810
+ )
811
+ return _result(
812
+ "dangling",
813
+ f"MCP registration shadowed by a higher scope: {scopes}; "
814
+ "remove the shadowing project entry manually",
815
+ **fields,
816
+ )
817
+ if registration["stale"]:
818
+ return _result(
819
+ "dangling",
820
+ "stale MCP registration for "
821
+ + ", ".join(registration["stale"])
822
+ + "; wl cc repair will re-register",
823
+ **fields,
824
+ )
665
825
  return _result("ok", None, **fields)
666
826
 
667
827
 
@@ -87,11 +87,17 @@ GSTACK_REPO = "https://github.com/garrytan/gstack.git"
87
87
  #: wlcc marketplace source when it is not registered yet (``/wl-upgrade`` §2).
88
88
  WLCC_MARKETPLACE_REPO = "https://gitlab.gewinnrobo.com/Humuyuan/wlcc.git"
89
89
 
90
- #: Per-server extra argv for ``claude mcp add`` (check.sh §3). The GitLab host
91
- #: is deliberately *not* passed: ``server.py`` owns that default (#242).
90
+ #: Per-server extra argv for ``claude mcp add`` (check.sh §3), derived from
91
+ #: the same ``checks.MCP_SERVE_ENV`` table the registration check reads, so
92
+ #: the written argv and the verified argv cannot drift (#229). The GitLab
93
+ #: host is deliberately *not* passed: ``server.py`` owns that default (#242).
92
94
  MCP_SERVER_EXTRA: dict[str, tuple[str, ...]] = {
93
- "gitlab": (),
94
- "k8s-diagnose": ("-e", "K8S_SSH_HOST=ubuntu-server"),
95
+ name: tuple(
96
+ part
97
+ for key, value in checks.MCP_SERVE_ENV[name]
98
+ for part in ("-e", f"{key}={value}")
99
+ )
100
+ for name in checks.MCP_SERVERS
95
101
  }
96
102
 
97
103
  #: How many timestamped ``settings.json`` backups are kept (hooks-drift).
@@ -494,9 +500,12 @@ def ensure_mcp() -> dict[str, Any]:
494
500
  Since #228 the registered argv is ``<wl> mcp serve <sub>`` -- the plugin
495
501
  tree's ``mcp-tools/server.py`` is neither required nor kept as a fallback.
496
502
  A rejected plugin root or a missing/unusable ``wl`` is reported as
497
- ``unverifiable`` and never registered. The stamp is the idempotency latch,
498
- so it is written only after *both* ``claude mcp add`` calls returned 0; one
499
- failure leaves the old stamp in place and the next run retries.
503
+ ``unverifiable`` and never registered. Since #229 the idempotency latch is
504
+ the *pair* of the version stamp and the stored registration: a matching
505
+ stamp with a stale argv (same version, swapped payload) is repaired rather
506
+ than reported ``ok``. The stamp is written only after *both* ``claude mcp
507
+ add`` calls returned 0; one failure leaves the old stamp in place and the
508
+ next run retries.
500
509
  """
501
510
  before = checks.probe_mcp(checks.load_host_context())
502
511
  fields = _section_fields(before)
@@ -506,6 +515,17 @@ def ensure_mcp() -> dict[str, Any]:
506
515
  if before["status"] == "ok":
507
516
  return _result("ok", None, changed, **fields)
508
517
 
518
+ shadowed = before.get("shadowed")
519
+ if isinstance(shadowed, dict) and shadowed:
520
+ scopes = ", ".join(f"{name} ({scope})" for name, scope in shadowed.items())
521
+ return _result(
522
+ "dangling",
523
+ f"MCP registration shadowed by a higher scope: {scopes}; "
524
+ "remove the shadowing project entry manually",
525
+ changed,
526
+ **fields,
527
+ )
528
+
509
529
  plugin_root = before.get("plugin_root")
510
530
  if not isinstance(plugin_root, str) or not plugin_root:
511
531
  return _result(
@@ -534,7 +554,10 @@ def ensure_mcp() -> dict[str, Any]:
534
554
  for name in checks.MCP_SERVERS:
535
555
  subcommand = checks.MCP_SERVE_ARGS[name]
536
556
  try:
537
- _run([claude, "mcp", "remove", name])
557
+ # ``-s user`` is required: without it the CLI refuses to remove
558
+ # when the same name also exists in the local/project scope, and
559
+ # the following ``add -s user`` then fails as a duplicate.
560
+ _run([claude, "mcp", "remove", name, "-s", "user"])
538
561
  proc = _run(
539
562
  [
540
563
  claude,
@@ -74,18 +74,31 @@ def _summary_lines(
74
74
  is_flag=True,
75
75
  help="Emit one five-state JSON envelope on stdout.",
76
76
  )
77
- def check(as_json: bool) -> None:
77
+ @click.option(
78
+ "--require",
79
+ "require",
80
+ multiple=True,
81
+ metavar="CAPABILITY",
82
+ help=(
83
+ "Assert a capability is available (repeatable). The consumer contract "
84
+ "is the capability name, not a version string; a missing or unknown "
85
+ "name exits 1 with status 'error'."
86
+ ),
87
+ )
88
+ def check(as_json: bool, require: tuple[str, ...]) -> None:
78
89
  """Report the running wl: version, executable, platform and capabilities.
79
90
 
80
91
  Read-only. In ``--json`` mode stdout is exactly one envelope line and
81
92
  diagnostics go to stderr; the probe itself runs in a temporary CWD and the
82
93
  dispatcher skips the startup ``.wl`` self-sync (#220), so the caller's
83
- directory is never written to.
94
+ directory is never written to. ``--require`` turns the report into an
95
+ assertion: consumers gate on capability names, never on a version string
96
+ (#231).
84
97
  """
85
98
  if as_json:
86
- raise SystemExit(emit_check())
99
+ raise SystemExit(emit_check(require))
87
100
 
88
- status, reason, fields = build_payload()
101
+ status, reason, fields = build_payload(require=require)
89
102
  for line in _summary_lines(status, reason, fields):
90
103
  click.echo(line)
91
104
  raise SystemExit(exit_code(status))
@@ -15,10 +15,11 @@ commands (#220).
15
15
 
16
16
  Envelope contract: ``status`` is ``ok`` for a supported interpreter,
17
17
  ``unverifiable`` when the platform matrix rejects it (unreachable for an
18
- installed wl -- the wheel requires Python 3.11+), and ``error`` only when the
19
- payload itself cannot be built. The envelope's ``reason`` is the platform
20
- reason when unsupported; the matrix's own ``reason`` is always carried as
21
- ``platform_reason``, so the two keys never collide.
18
+ installed wl -- the wheel requires Python 3.11+), and ``error`` when the
19
+ payload itself cannot be built or a ``--require`` assertion fails (#231). The
20
+ envelope's ``reason`` is the platform reason when unsupported; the matrix's
21
+ own ``reason`` is always carried as ``platform_reason``, so the two keys never
22
+ collide.
22
23
  """
23
24
 
24
25
  from __future__ import annotations
@@ -36,7 +37,7 @@ from .envelope import OK_STATUSES, dump, exit_code
36
37
  from .platform import platform_payload
37
38
 
38
39
  if TYPE_CHECKING:
39
- from collections.abc import Generator
40
+ from collections.abc import Generator, Sequence
40
41
 
41
42
  #: Stable tool name in the envelope's ``tool`` key (the alias reuses it: both
42
43
  #: commands answer the same question, so consumers key off one name).
@@ -101,15 +102,71 @@ def install_fields() -> dict[str, str]:
101
102
  return {"command": INSTALL_COMMAND, "floor": INSTALL_FLOOR}
102
103
 
103
104
 
104
- def build_payload() -> tuple[str, str | None, dict[str, Any]]:
105
+ #: Reason prefixes for the ``--require`` contract (#231). A known capability
106
+ #: that this build does not advertise is ``no_capability:``; a name that is
107
+ #: not in the registry at all is ``unknown_capability:`` -- reporting a typo as
108
+ #: satisfied would turn one misspelling into a gate that never fails.
109
+ NO_CAPABILITY = "no_capability:"
110
+ UNKNOWN_CAPABILITY = "unknown_capability:"
111
+
112
+
113
+ def evaluate_requirements(
114
+ required: Sequence[str],
115
+ capabilities: Sequence[str],
116
+ ) -> tuple[str | None, list[str]]:
117
+ """Evaluate ``--require`` names against the advertised capabilities (#231).
118
+
119
+ The registry (:data:`wl_cli.capabilities.CAPABILITY_SINCE`) answers "is
120
+ this a capability name at all"; the envelope's ``capabilities`` list
121
+ answers "does this build have it". A registered name that is not
122
+ advertised is missing (``no_capability:<names>``); an unregistered name is
123
+ a typo (``unknown_capability:<names>``), never a satisfied requirement.
124
+
125
+ Names are de-duplicated in request order. When both classes are present
126
+ the unknown names win the ``reason`` (the request itself is invalid while
127
+ ``missing`` still carries every known-but-unavailable name), so a caller
128
+ fixing the payload sees the typo first.
129
+
130
+ Args:
131
+ required: Capability names from ``--require``, in request order.
132
+ capabilities: The names this build advertises (the envelope payload).
133
+
134
+ Returns:
135
+ ``(reason, missing)``. ``reason`` is ``None`` when every requested
136
+ capability is advertised; ``missing`` is always the known-but-
137
+ unavailable names in request order.
138
+ """
139
+ known = set(CAPABILITY_SINCE)
140
+ advertised = set(capabilities)
141
+ ordered = list(dict.fromkeys(required))
142
+ unknown = [name for name in ordered if name not in known]
143
+ missing = [name for name in ordered if name in known and name not in advertised]
144
+ if unknown:
145
+ return UNKNOWN_CAPABILITY + ",".join(unknown), missing
146
+ if missing:
147
+ return NO_CAPABILITY + ",".join(missing), missing
148
+ return None, missing
149
+
150
+
151
+ def build_payload(
152
+ *, require: Sequence[str] = ()
153
+ ) -> tuple[str, str | None, dict[str, Any]]:
105
154
  """Build the ``wl env check`` fields.
106
155
 
156
+ Args:
157
+ require: Capability names asserted with ``--require`` (#231). They are
158
+ checked against the advertised ``capabilities`` only when the
159
+ probe itself holds; a platform failure keeps its own status and
160
+ reason, as before.
161
+
107
162
  Returns:
108
163
  ``(status, reason, fields)``. ``status`` is ``ok`` when the running
109
164
  interpreter is supported, ``unverifiable`` when the shared platform
110
- matrix says otherwise, and ``error`` only when the payload cannot be
111
- built at all. ``reason`` carries the readable platform reason when the
112
- status is not ``ok``; ``fields`` is the envelope payload.
165
+ matrix says otherwise, and ``error`` when the payload cannot be built
166
+ at all or a requested capability is missing/unknown. ``reason``
167
+ carries the readable explanation when the status is not ``ok``;
168
+ ``fields`` is the envelope payload, with a ``missing`` list only when
169
+ a requested capability is known but not advertised.
113
170
  """
114
171
  executable = executable_path()
115
172
  try:
@@ -142,16 +199,39 @@ def build_payload() -> tuple[str, str | None, dict[str, Any]]:
142
199
  )
143
200
 
144
201
  if fields["supported"] is True:
145
- return "ok", None, fields
146
- return "unverifiable", platform_reason or "unsupported platform", fields
202
+ status, reason = "ok", None
203
+ else:
204
+ status, reason = "unverifiable", platform_reason or "unsupported platform"
205
+
206
+ # Capability requirements are an assertion about a healthy probe: when the
207
+ # platform itself is unsupported, the platform reason is the actionable
208
+ # answer and stays untouched.
209
+ if status in OK_STATUSES and require:
210
+ requirement_reason, missing = evaluate_requirements(
211
+ require, fields["capabilities"]
212
+ )
213
+ if requirement_reason is not None:
214
+ status, reason = "error", requirement_reason
215
+ if missing:
216
+ fields["missing"] = missing
217
+ return status, reason, fields
147
218
 
148
219
 
149
- def emit_check() -> int:
220
+ def emit_check(required: Sequence[str] = ()) -> int:
150
221
  """Write the ``env check`` envelope to stdout and return its exit code.
151
222
 
152
223
  Both ``wl env check --json`` and the deprecated ``wl self capabilities
153
224
  --json`` alias call this, so the two commands cannot answer differently.
225
+ ``required`` carries the repeatable ``--require`` names (empty for the
226
+ alias, which reports rather than asserts).
227
+
228
+ Args:
229
+ required: Capability names the caller asserts, in request order.
230
+
231
+ Returns:
232
+ The envelope exit code: ``0`` when the probe holds and every required
233
+ capability is present, ``1`` otherwise.
154
234
  """
155
- status, reason, fields = build_payload()
235
+ status, reason, fields = build_payload(require=required)
156
236
  dump(status, status in OK_STATUSES, tool=TOOL, reason=reason, **fields)
157
237
  return exit_code(status)
py_wlcli-0.8.1/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.8.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes