py-wlcli 0.8.0__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.0 → py_wlcli-0.8.2}/PKG-INFO +1 -1
  2. py_wlcli-0.8.2/VERSION +1 -0
  3. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/capabilities.py +3 -1
  4. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/cc/checks.py +263 -17
  5. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/cc/cli.py +1 -1
  6. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/cc/mutate.py +46 -32
  7. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/env/cli.py +17 -4
  8. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/env_status.py +93 -13
  9. py_wlcli-0.8.0/VERSION +0 -1
  10. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/.gitignore +0 -0
  11. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/LICENSE +0 -0
  12. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/README.md +0 -0
  13. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/pyproject.toml +0 -0
  14. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/__init__.py +0 -0
  15. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/__init__.py +0 -0
  16. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/__main__.py +0 -0
  17. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/cc/__init__.py +0 -0
  18. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/cli_click.py +0 -0
  19. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/__init__.py +0 -0
  20. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/base.py +0 -0
  21. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/__init__.py +0 -0
  22. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/build.py +0 -0
  23. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/build_utils.py +0 -0
  24. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/__init__.py +0 -0
  25. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/cleanup.py +0 -0
  26. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/coordinator.py +0 -0
  27. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/environment.py +0 -0
  28. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/rust_builder.py +0 -0
  29. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/builders/stubs.py +0 -0
  30. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/dist.py +0 -0
  31. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/buildcommands/test.py +0 -0
  32. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/__init__.py +0 -0
  33. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/build.py +0 -0
  34. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/clean.py +0 -0
  35. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/clean_utils.py +0 -0
  36. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/core.py +0 -0
  37. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/__init__.py +0 -0
  38. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/dead_code_command.py +0 -0
  39. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/detector.py +0 -0
  40. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/fixer.py +0 -0
  41. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/reporter.py +0 -0
  42. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/dead_code/utils.py +0 -0
  43. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/lfs.py +0 -0
  44. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/python.py +0 -0
  45. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/rust.py +0 -0
  46. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/utils/__init__.py +0 -0
  47. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/clean/venv.py +0 -0
  48. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/cleanup.py +0 -0
  49. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/click_base.py +0 -0
  50. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/config/__init__.py +0 -0
  51. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/config/config.py +0 -0
  52. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/__init__.py +0 -0
  53. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/debug.py +0 -0
  54. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/debug_cache.py +0 -0
  55. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/debug_subagent.py +0 -0
  56. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/output_formatter.py +0 -0
  57. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/debug/source_hasher.py +0 -0
  58. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/__init__.py +0 -0
  59. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_cache_adapter.py +0 -0
  60. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_command.py +0 -0
  61. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_coordinator.py +0 -0
  62. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_executor.py +0 -0
  63. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_outcome.py +0 -0
  64. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_path_handler.py +0 -0
  65. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_progress.py +0 -0
  66. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/format_reporter.py +0 -0
  67. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/python_formatter.py +0 -0
  68. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/format/rust_formatter.py +0 -0
  69. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/gate/__init__.py +0 -0
  70. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/gate/gate_command.py +0 -0
  71. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/gate/preflight.py +0 -0
  72. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/__init__.py +0 -0
  73. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/config.py +0 -0
  74. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/git_facts.py +0 -0
  75. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/git_flow.py +0 -0
  76. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/hook.py +0 -0
  77. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/policy.py +0 -0
  78. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/git/push_update.py +0 -0
  79. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/__init__.py +0 -0
  80. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/__init__.py +0 -0
  81. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/check_git_bash.py +0 -0
  82. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/error_handler.py +0 -0
  83. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/common/exceptions.py +0 -0
  84. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/__init__.py +0 -0
  85. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/cargo_sync.py +0 -0
  86. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/config_manager.py +0 -0
  87. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/directory_utils.py +0 -0
  88. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/__init__.py +0 -0
  89. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/branch_creator.py +0 -0
  90. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_flow_interface.py +0 -0
  91. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_flow_manager.py +0 -0
  92. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_lfs_manager.py +0 -0
  93. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/git_utility.py +0 -0
  94. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git/gitignore_manager.py +0 -0
  95. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/git_initializer.py +0 -0
  96. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/i18n_manager.py +0 -0
  97. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/log_manager.py +0 -0
  98. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/__init__.py +0 -0
  99. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/config_generator.py +0 -0
  100. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/directory_creator.py +0 -0
  101. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/hook_source.py +0 -0
  102. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/hooks_manager.py +0 -0
  103. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/readme_handler.py +0 -0
  104. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +0 -0
  105. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/setup_handler.py +0 -0
  106. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/sop_generator.py +0 -0
  107. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/template_copier.py +0 -0
  108. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/project_structure/template_manager.py +0 -0
  109. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/pyproject_generator.py +0 -0
  110. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/rust_initializer.py +0 -0
  111. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/symlink_cleaner.py +0 -0
  112. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/symlink_manager.py +0 -0
  113. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/components/venv_manager.py +0 -0
  114. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/initenv.py +0 -0
  115. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/__init__.py +0 -0
  116. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/environment_initializer.py +0 -0
  117. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/git_lfs_initializer.py +0 -0
  118. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/initenv/services/project_structure_initializer.py +0 -0
  119. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/README.md +0 -0
  120. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/__init__.py +0 -0
  121. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/cli.py +0 -0
  122. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/config.py +0 -0
  123. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/hook.py +0 -0
  124. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/initializer.py +0 -0
  125. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/manager.py +0 -0
  126. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/policy.py +0 -0
  127. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lfs/watcher.py +0 -0
  128. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/__init__.py +0 -0
  129. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_command.py +0 -0
  130. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_executor.py +0 -0
  131. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_reporter.py +0 -0
  132. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/lint_run.py +0 -0
  133. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/lint/mypy_config.py +0 -0
  134. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/registry.py +0 -0
  135. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/__init__.py +0 -0
  136. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/__init__.py +0 -0
  137. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/capabilities.py +0 -0
  138. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/config.py +0 -0
  139. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/common/version_cache.py +0 -0
  140. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/__init__.py +0 -0
  141. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/base_handler.py +0 -0
  142. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/install_handler.py +0 -0
  143. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/status_handler.py +0 -0
  144. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/uninstall_handler.py +0 -0
  145. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/update_handler.py +0 -0
  146. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/handlers/version_handler.py +0 -0
  147. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/self_command.py +0 -0
  148. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/__init__.py +0 -0
  149. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/installation_manager.py +0 -0
  150. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/local_installer.py +0 -0
  151. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/pypi_updater.py +0 -0
  152. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/self/services/windows_update.py +0 -0
  153. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/__init__.py +0 -0
  154. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/base_dependency_analyzer.py +0 -0
  155. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/batch_processor.py +0 -0
  156. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/cache_manager.py +0 -0
  157. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/coverage_analyzer.py +0 -0
  158. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/coverage_cache_manager.py +0 -0
  159. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/progress_manager.py +0 -0
  160. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/python_env_detector.py +0 -0
  161. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/report_generator.py +0 -0
  162. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/single_test_executor.py +0 -0
  163. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/speed_checker.py +0 -0
  164. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_command_builder.py +0 -0
  165. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_commands.py +0 -0
  166. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_reporter.py +0 -0
  167. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_result_handler.py +0 -0
  168. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_runner.py +0 -0
  169. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/test_utils.py +0 -0
  170. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/__init__.py +0 -0
  171. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/coverage_parser.py +0 -0
  172. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/env_info.py +0 -0
  173. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/junit_parser.py +0 -0
  174. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/markdown_utils.py +0 -0
  175. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/testcommands/utils/project_root.py +0 -0
  176. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/__init__.py +0 -0
  177. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/__init__.py +0 -0
  178. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/backup_manager.py +0 -0
  179. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/component_manager.py +0 -0
  180. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/conflict_resolver.py +0 -0
  181. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/vendors_updater.py +0 -0
  182. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/services/version_tracker.py +0 -0
  183. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/update_command.py +0 -0
  184. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/update/utils/__init__.py +0 -0
  185. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/version/__init__.py +0 -0
  186. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/version/version_command.py +0 -0
  187. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/commands/workflow.py +0 -0
  188. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/env/__init__.py +0 -0
  189. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/envelope.py +0 -0
  190. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/exceptions.py +0 -0
  191. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/lib/__init__.py +0 -0
  192. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/lib/rust_utils.py +0 -0
  193. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/mcp/__init__.py +0 -0
  194. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/mcp/capabilities.py +0 -0
  195. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/mcp/cli.py +0 -0
  196. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/mcp/gitlab.py +0 -0
  197. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/mcp/k8s.py +0 -0
  198. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/mcp/protocol.py +0 -0
  199. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/platform.py +0 -0
  200. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/quality/__init__.py +0 -0
  201. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/__init__.py +0 -0
  202. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/cache.py +0 -0
  203. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/cache_ledger.py +0 -0
  204. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/cache_store.py +0 -0
  205. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/__init__.py +0 -0
  206. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/config_loader.py +0 -0
  207. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/core.py +0 -0
  208. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/defaults.py +0 -0
  209. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/env_exporter.py +0 -0
  210. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/env_parser.py +0 -0
  211. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/config/validation.py +0 -0
  212. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/error_handler.py +0 -0
  213. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/file_copier.py +0 -0
  214. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/file_operations.py +0 -0
  215. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/language_utils.py +0 -0
  216. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/lazy_import.py +0 -0
  217. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/log_levels.py +0 -0
  218. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/log_rotators.py +0 -0
  219. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/logging.py +0 -0
  220. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/output_context.py +0 -0
  221. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/__init__.py +0 -0
  222. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/decorators.py +0 -0
  223. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/exporter.py +0 -0
  224. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/models.py +0 -0
  225. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/performance/monitor.py +0 -0
  226. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/performance_monitor.py +0 -0
  227. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/platform_adapter.py +0 -0
  228. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/pre_commit.py +0 -0
  229. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/pre_commit_config.py +0 -0
  230. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/root.py +0 -0
  231. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/root_fallback.py +0 -0
  232. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/run_evidence.py +0 -0
  233. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logger.py +0 -0
  234. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/__init__.py +0 -0
  235. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/config.py +0 -0
  236. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/core.py +0 -0
  237. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/env.py +0 -0
  238. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/filtering.py +0 -0
  239. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/filters.py +0 -0
  240. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/formatters.py +0 -0
  241. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/handlers.py +0 -0
  242. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/structured_logging/logger.py +0 -0
  243. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/subprocess.py +0 -0
  244. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/subprocess_utils.py +0 -0
  245. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/test_utils/__init__.py +0 -0
  246. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/test_utils/test_filter.py +0 -0
  247. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_run.py +0 -0
  248. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_tool.py +0 -0
  249. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_tree.py +0 -0
  250. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/uv_workspace.py +0 -0
  251. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/version/__init__.py +0 -0
  252. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/version/pypi_version_checker.py +0 -0
  253. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_comparator.py +0 -0
  254. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_detectors.py +0 -0
  255. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_service.py +0 -0
  256. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/version/version_updater.py +0 -0
  257. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/wl_dir_updater.py +0 -0
  258. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/__init__.py +0 -0
  259. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/core.py +0 -0
  260. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/detection_strategies.py +0 -0
  261. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/exceptions.py +0 -0
  262. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/types.py +0 -0
  263. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/utils/workspace_detector/venv_resolver.py +0 -0
  264. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/.codespellrc +0 -0
  265. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/dependencies.toml +0 -0
  266. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/mypy.ini +0 -0
  267. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/pyproject_defaults.toml +0 -0
  268. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/template_config.toml +0 -0
  269. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/config/tool_configs.toml +0 -0
  270. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/git/.gitignore +0 -0
  271. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/git/.pre-commit-config.yaml +0 -0
  272. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/applypatch-msg.sample +0 -0
  273. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/commit-msg.sample +0 -0
  274. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/fsmonitor-watchman.sample +0 -0
  275. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/post-update.sample +0 -0
  276. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-applypatch.sample +0 -0
  277. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-commit +0 -0
  278. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-commit.legacy +0 -0
  279. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-commit.sample +0 -0
  280. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-merge-commit.sample +0 -0
  281. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-push.sample +0 -0
  282. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-rebase.sample +0 -0
  283. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/pre-receive.sample +0 -0
  284. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/prepare-commit-msg.sample +0 -0
  285. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/push-to-checkout.sample +0 -0
  286. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/sendemail-validate.sample +0 -0
  287. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/applypatch-msg.sample +0 -0
  288. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/check_lockfile.py +0 -0
  289. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/check_lockfile.sh +0 -0
  290. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/commit-msg.sample +0 -0
  291. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +0 -0
  292. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/post-update.sample +0 -0
  293. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-applypatch.sample +0 -0
  294. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit +0 -0
  295. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit.legacy +0 -0
  296. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit.py +0 -0
  297. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-commit.sample +0 -0
  298. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-merge-commit.sample +0 -0
  299. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-push +0 -0
  300. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-push.sample +0 -0
  301. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-rebase.sample +0 -0
  302. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/pre-receive.sample +0 -0
  303. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +0 -0
  304. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/update.sample +0 -0
  305. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/hooks/win/work.bat +0 -0
  306. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/.gitignore +0 -0
  307. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/.python-version +0 -0
  308. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/LICENSE +0 -0
  309. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/README.md +0 -0
  310. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/pyproject.toml +0 -0
  311. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/pyproject_no_workspace.toml +0 -0
  312. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/project/pyproject_workspace.toml +0 -0
  313. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/readme/README.md +0 -0
  314. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/Cargo.toml +0 -0
  315. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/lib/__init__.py +0 -0
  316. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/lib/rust_utils.py +0 -0
  317. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/src/lib.rs +0 -0
  318. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/src/main.rs +0 -0
  319. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/rust/tests/test_rust_fallback.py +0 -0
  320. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/git-dev-sop.md +0 -0
  321. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/industrial-standard-sop.md +0 -0
  322. {py_wlcli-0.8.0 → py_wlcli-0.8.2}/src/wl_cli/vendors/sop_doc/python-sop.md +0 -0
  323. {py_wlcli-0.8.0 → 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.0
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,9 +43,11 @@ 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",
50
+ "mcp.serve": "0.8.1",
49
51
  "test.clean_cache": "0.7.0",
50
52
  }
51
53
 
@@ -15,7 +15,7 @@ the ticket cannot drift from the implementation:
15
15
  section wlcc source
16
16
  =========== ============================================================
17
17
  plugins §1 required plugins + §7 context-mode (optional plugin)
18
- mcp §3 plugin root, version stamp and interpreter visibility
18
+ mcp §3 registered wl command, version stamp, interpreter visibility
19
19
  settings §5 gstack + §6 claude-mem (host-side configuration)
20
20
  stamps §8 stamp registry (report only -- never delete)
21
21
  hooks §9 dangling hook commands (read-only plan)
@@ -98,6 +98,29 @@ RETIRED_STAMPS = frozenset({"gemini-key.enc", "mcp-visionary-pending"})
98
98
  #: MCP servers check.sh §3 registers.
99
99
  MCP_SERVERS: tuple[str, ...] = ("gitlab", "k8s-diagnose")
100
100
 
101
+ #: Registered server name -> ``wl mcp serve`` subcommand (#228). The server
102
+ #: names are the stable interface (tool schema and existing user config); only
103
+ #: the execution path moved from the plugin's ``mcp-tools/server.py`` to the
104
+ #: wl CLI. ``k8s-diagnose`` keeps its name but serves ``wl mcp serve k8s``.
105
+ MCP_SERVE_ARGS: dict[str, str] = {
106
+ "gitlab": "gitlab",
107
+ "k8s-diagnose": "k8s",
108
+ }
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
+
119
+ #: Capability the ``wl`` on ``PATH`` must advertise before a registration argv
120
+ #: counts as verifiable (#228). Consumers (wlcc) use the same bit to decide
121
+ #: that registration goes through ``wl mcp serve``.
122
+ MCP_SERVE_CAPABILITY = "mcp.serve"
123
+
101
124
  #: Literal absolute path anchor from wlcc ``hooks-drift.py``: the dangling rule
102
125
  #: is exactly ``*/.claude/*``. Kept with the trailing slash on purpose.
103
126
  CLAUDE_SEG = "/.claude/"
@@ -475,7 +498,10 @@ def _interpreter_state(path: str, version: str, returncode: int) -> dict[str, An
475
498
 
476
499
 
477
500
  def _probe_python() -> dict[str, Any]:
478
- """Resolve the interpreter MCP servers will run under (check.sh §3).
501
+ """Report the interpreter check.sh §3 used to run the MCP servers under.
502
+
503
+ Since #228 the servers run under ``wl mcp serve`` and no interpreter is
504
+ part of the registered argv, so the result is informational only.
479
505
 
480
506
  ``uv --no-cache python find 3.12`` resolves a local installation without
481
507
  downloading and keeps its cache in a temporary directory for the duration
@@ -518,8 +544,211 @@ def _probe_python() -> dict[str, Any]:
518
544
  return _interpreter_state(path, probe.stdout.strip(), probe.returncode)
519
545
 
520
546
 
547
+ def _probe_wl_serve() -> dict[str, Any]:
548
+ """Probe the ``wl`` on ``PATH`` for the ``mcp.serve`` capability (#228).
549
+
550
+ The registration argv is ``<wl> mcp serve <sub>``, so the executable that
551
+ will be registered has to exist *and* advertise the capability. Asking it
552
+ for ``wl env check --json`` reads the same capability registry wlcc keys
553
+ off, instead of trusting the wl that happens to be running ``cc check``.
554
+ Every failure is a state value, never an exception.
555
+
556
+ Returns:
557
+ Fields ``path`` / ``state`` / ``version`` / ``capability``. ``state``
558
+ is ``ok:<version>`` when the capability is advertised, ``fail:absent``
559
+ when no ``wl`` is on ``PATH``, and ``fail:unusable`` /
560
+ ``fail:missing_capability`` (with a readable ``reason``) otherwise.
561
+ """
562
+ fields: dict[str, Any] = {
563
+ "path": None,
564
+ "state": "fail:absent",
565
+ "version": None,
566
+ "capability": MCP_SERVE_CAPABILITY,
567
+ }
568
+ wl = shutil.which("wl")
569
+ if wl is None:
570
+ return fields
571
+ fields["path"] = wl
572
+ try:
573
+ probe = subprocess.run(
574
+ [wl, "env", "check", "--json"],
575
+ capture_output=True,
576
+ text=True,
577
+ check=False,
578
+ timeout=30,
579
+ )
580
+ except (OSError, subprocess.SubprocessError) as exc:
581
+ fields.update(state="fail:unusable", reason=str(exc))
582
+ return fields
583
+ # ``env check`` exits 1 when the platform matrix says ``unverifiable`` but
584
+ # still emits the payload; parse first so a supported capability is not
585
+ # rejected because of an unrelated platform warning.
586
+ try:
587
+ payload = json.loads(probe.stdout)
588
+ except ValueError:
589
+ payload = None
590
+ if not isinstance(payload, dict):
591
+ fields.update(
592
+ state="fail:unusable",
593
+ reason=f"wl env check exited {probe.returncode} without a JSON payload",
594
+ )
595
+ return fields
596
+ version = payload.get("version")
597
+ fields["version"] = version if isinstance(version, str) else None
598
+ capabilities = payload.get("capabilities")
599
+ if isinstance(capabilities, list) and MCP_SERVE_CAPABILITY in capabilities:
600
+ fields["state"] = f"ok:{fields['version'] or 'unknown'}"
601
+ return fields
602
+ fields.update(
603
+ state="fail:missing_capability",
604
+ reason=f"{wl} does not advertise {MCP_SERVE_CAPABILITY}",
605
+ )
606
+ return fields
607
+
608
+
609
+ def _wl_reason(fields: dict[str, Any]) -> str:
610
+ """Return a readable reason for a ``wl`` probe that is not ``ok``."""
611
+ state = str(fields.get("state", ""))
612
+ if state == "fail:absent":
613
+ return "the wl CLI is not on PATH"
614
+ reason = fields.get("reason")
615
+ if isinstance(reason, str) and reason:
616
+ return reason
617
+ return f"the wl CLI on PATH is not usable ({state or 'unknown state'})"
618
+
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
+
521
738
  def probe_mcp(host: HostContext) -> dict[str, Any]:
522
- """§3: plugin-root trust, version stamp and interpreter visibility."""
739
+ """§3: the registration target, version stamp and interpreter visibility.
740
+
741
+ Since #228 the registered argv is ``<wl> mcp serve <sub>``: the probe
742
+ verifies that the ``wl`` on ``PATH`` exists and advertises ``mcp.serve``
743
+ instead of looking for a plugin-root ``mcp-tools/server.py``. The
744
+ interpreter probe stays a report field but can no longer gate the section
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``.
751
+ """
523
752
  cache = _wlcc_cache(host)
524
753
  fields: dict[str, Any] = {
525
754
  "cache_root": str(cache),
@@ -528,6 +757,9 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
528
757
  "plugin_root": None,
529
758
  "rejected": False,
530
759
  "servers": list(MCP_SERVERS),
760
+ "mcp_config": str(mcp_config_path()),
761
+ "registrations": {},
762
+ "wl": _probe_wl_serve(),
531
763
  "python": _probe_python(),
532
764
  }
533
765
  try:
@@ -552,17 +784,17 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
552
784
  fields["rejected"] = True
553
785
  return _result("unverifiable", root_error, **fields)
554
786
  fields["plugin_root"] = str(root)
555
- server = root / ".claude" / "mcp-tools" / "server.py"
556
- if server.is_symlink():
557
- fields["rejected"] = True
558
- return _result(
559
- "unverifiable", f"MCP server script is a symlink: {server}", **fields
560
- )
561
- if not server.is_file():
562
- fields["rejected"] = True
563
- return _result(
564
- "unverifiable", f"MCP server script is missing: {server}", **fields
565
- )
787
+
788
+ wl_state = str(fields["wl"].get("state", ""))
789
+ if not wl_state.startswith("ok:"):
790
+ return _result("unverifiable", _wl_reason(fields["wl"]), **fields)
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)
566
798
 
567
799
  if registered != version:
568
800
  return _result(
@@ -571,10 +803,24 @@ def probe_mcp(host: HostContext) -> dict[str, Any]:
571
803
  "wl cc repair will re-register",
572
804
  **fields,
573
805
  )
574
- python_state = str(fields["python"].get("state", ""))
575
- if not python_state.startswith(("supplied:", "ok:")):
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"]:
576
818
  return _result(
577
- "dangling", f"MCP interpreter is not usable: {python_state}", **fields
819
+ "dangling",
820
+ "stale MCP registration for "
821
+ + ", ".join(registration["stale"])
822
+ + "; wl cc repair will re-register",
823
+ **fields,
578
824
  )
579
825
  return _result("ok", None, **fields)
580
826
 
@@ -278,7 +278,7 @@ def mcp_ensure(as_json: bool) -> None:
278
278
  @mcp_group.command(name="list")
279
279
  @click.option("--json", "as_json", is_flag=True, help=_JSON_HELP)
280
280
  def mcp_list(as_json: bool) -> None:
281
- """Report the plugin root, interpreter, stamp and servers without writing."""
281
+ """Report the wl target, plugin root, interpreter, stamp and servers."""
282
282
  _run_single("cc mcp list", lambda: mutate.probe_section("mcp"), as_json)
283
283
 
284
284
 
@@ -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).
@@ -488,22 +494,18 @@ def ensure_plugins() -> dict[str, Any]:
488
494
  # --------------------------------------------------------------------------- #
489
495
 
490
496
 
491
- def _mcp_script(plugin_root: Path, name: str) -> Path:
492
- """Return the registered server script for *name* under the plugin root."""
493
- tools = plugin_root / ".claude" / "mcp-tools"
494
- if name == "gitlab":
495
- return tools / "server.py"
496
- return tools / name / "server.py"
497
-
498
-
499
497
  def ensure_mcp() -> dict[str, Any]:
500
- """Re-register both MCP servers and write the version stamp only on success.
501
-
502
- A rejected plugin root or an unusable interpreter is reported as
503
- ``unverifiable`` and never registered -- the same closed set of states
504
- ``check.sh`` §3 uses. The stamp is the idempotency latch, so it is written
505
- only after *both* ``claude mcp add`` calls returned 0; one failure leaves
506
- the old stamp in place and the next run retries.
498
+ """Re-register both MCP servers as ``wl mcp serve`` and stamp on success.
499
+
500
+ Since #228 the registered argv is ``<wl> mcp serve <sub>`` -- the plugin
501
+ tree's ``mcp-tools/server.py`` is neither required nor kept as a fallback.
502
+ A rejected plugin root or a missing/unusable ``wl`` is reported as
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.
507
509
  """
508
510
  before = checks.probe_mcp(checks.load_host_context())
509
511
  fields = _section_fields(before)
@@ -513,6 +515,17 @@ def ensure_mcp() -> dict[str, Any]:
513
515
  if before["status"] == "ok":
514
516
  return _result("ok", None, changed, **fields)
515
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
+
516
529
  plugin_root = before.get("plugin_root")
517
530
  if not isinstance(plugin_root, str) or not plugin_root:
518
531
  return _result(
@@ -521,15 +534,12 @@ def ensure_mcp() -> dict[str, Any]:
521
534
  changed,
522
535
  **fields,
523
536
  )
524
- python = before.get("python")
525
- python_path = python.get("path") if isinstance(python, dict) else None
526
- python_state = python.get("state") if isinstance(python, dict) else None
527
- if not isinstance(python_path, str) or not str(python_state).startswith(
528
- ("supplied:", "ok:")
529
- ):
537
+ wl_probe = before.get("wl")
538
+ wl = wl_probe.get("path") if isinstance(wl_probe, dict) else None
539
+ if not isinstance(wl, str) or not wl:
530
540
  return _result(
531
541
  "unverifiable",
532
- f"MCP interpreter is not usable: {python_state}",
542
+ before.get("reason") or "the wl CLI is not on PATH",
533
543
  changed,
534
544
  **fields,
535
545
  )
@@ -541,11 +551,13 @@ def ensure_mcp() -> dict[str, Any]:
541
551
  )
542
552
 
543
553
  failures: list[str] = []
544
- root = Path(plugin_root)
545
554
  for name in checks.MCP_SERVERS:
546
- script = str(_mcp_script(root, name))
555
+ subcommand = checks.MCP_SERVE_ARGS[name]
547
556
  try:
548
- _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"])
549
561
  proc = _run(
550
562
  [
551
563
  claude,
@@ -556,15 +568,17 @@ def ensure_mcp() -> dict[str, Any]:
556
568
  "-s",
557
569
  "user",
558
570
  "--",
559
- python_path,
560
- script,
571
+ wl,
572
+ "mcp",
573
+ "serve",
574
+ subcommand,
561
575
  ]
562
576
  )
563
577
  except (OSError, subprocess.SubprocessError) as exc:
564
578
  failures.append(f"{name}: {exc}")
565
579
  continue
566
580
  if proc.returncode == 0:
567
- changed.append(f"mcp: registered {name} -> {script}")
581
+ changed.append(f"mcp: registered {name} -> {wl} mcp serve {subcommand}")
568
582
  else:
569
583
  failures.append(f"{name}: {_failure(proc)}")
570
584
 
@@ -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))