ha-mcp-dev 7.14.2.dev2135__tar.gz → 7.14.2.dev2139__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 (191) hide show
  1. {ha_mcp_dev-7.14.2.dev2135/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.14.2.dev2139}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_i18n.py +86 -2
  4. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/helpers.py +5 -2
  5. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_deep.py +11 -0
  6. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  7. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/LICENSE +0 -0
  8. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/MANIFEST.in +0 -0
  9. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/README.md +0 -0
  10. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/setup.cfg +0 -0
  11. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/__init__.py +0 -0
  12. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/__main__.py +0 -0
  13. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/_pypi_marker +0 -0
  14. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/_version.py +0 -0
  15. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/auth/__init__.py +0 -0
  16. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/auth/consent_form.py +0 -0
  17. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/auth/provider.py +0 -0
  18. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/backup_manager.py +0 -0
  19. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/browser_landing.py +0 -0
  20. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/__init__.py +0 -0
  21. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/rest_client.py +0 -0
  22. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/supervisor_client.py +0 -0
  23. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/websocket_client.py +0 -0
  24. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/websocket_listener.py +0 -0
  25. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/config.py +0 -0
  26. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  27. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  28. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  29. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  30. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  31. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  32. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/errors.py +0 -0
  33. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/llm_exposure.py +0 -0
  34. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/__init__.py +0 -0
  35. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/approval_queue.py +0 -0
  36. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/evaluator.py +0 -0
  37. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/handlers.py +0 -0
  38. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/middleware.py +0 -0
  39. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/model.py +0 -0
  40. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/persistence.py +0 -0
  41. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/value_sources.py +0 -0
  42. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/py.typed +0 -0
  43. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/read_only.py +0 -0
  44. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  45. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  46. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  47. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  48. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  49. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  50. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  51. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  52. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  53. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  54. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  55. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  56. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  57. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  58. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  59. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  60. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  61. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  62. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  63. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  64. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  65. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  66. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  67. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  68. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  69. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/server.py +0 -0
  70. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/__init__.py +0 -0
  71. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  72. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  73. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  74. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  75. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  76. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  77. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  78. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  79. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_theme.py +0 -0
  80. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  81. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  82. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  83. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  84. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
  85. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  86. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  87. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/settings.css +0 -0
  88. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/settings.html +0 -0
  89. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/settings.js +0 -0
  90. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/smoke_test.py +0 -0
  91. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  92. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/strict_bps.py +0 -0
  93. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/__init__.py +0 -0
  94. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/auto_backup.py +0 -0
  95. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/backup.py +0 -0
  96. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  97. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_api.py +0 -0
  98. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_config_reads.py +0 -0
  99. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_devices.py +0 -0
  100. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_registries.py +0 -0
  101. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  102. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  103. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/device_control.py +0 -0
  104. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/enhanced.py +0 -0
  105. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/__init__.py +0 -0
  106. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/base.py +0 -0
  107. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/matter.py +0 -0
  108. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/thread.py +0 -0
  109. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  110. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/zwave.py +0 -0
  111. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/reference_validator.py +0 -0
  112. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/registry.py +0 -0
  113. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  114. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  115. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  116. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  117. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  118. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  119. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  120. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  121. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  122. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_addons.py +0 -0
  123. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_areas.py +0 -0
  124. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  125. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  126. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_calendar.py +0 -0
  127. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_camera.py +0 -0
  128. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_categories.py +0 -0
  129. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_code.py +0 -0
  130. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  131. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  132. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  133. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  134. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  135. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  136. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_dev.py +0 -0
  137. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_energy.py +0 -0
  138. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_entities.py +0 -0
  139. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  140. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_groups.py +0 -0
  141. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_hacs.py +0 -0
  142. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_history.py +0 -0
  143. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_integrations.py +0 -0
  144. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_labels.py +0 -0
  145. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_radio.py +0 -0
  146. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_registry.py +0 -0
  147. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_resources.py +0 -0
  148. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_search.py +0 -0
  149. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_service.py +0 -0
  150. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_services.py +0 -0
  151. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_system.py +0 -0
  152. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_themes.py +0 -0
  153. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_todo.py +0 -0
  154. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_traces.py +0 -0
  155. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_updates.py +0 -0
  156. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_utility.py +0 -0
  157. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  158. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  159. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  160. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_zones.py +0 -0
  161. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/util_helpers.py +0 -0
  162. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/validation_middleware.py +0 -0
  163. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transforms/__init__.py +0 -0
  164. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transforms/categorized_search.py +0 -0
  165. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  166. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transport_security.py +0 -0
  167. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/update_check.py +0 -0
  168. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/__init__.py +0 -0
  169. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/config_hash.py +0 -0
  170. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/config_write_lock.py +0 -0
  171. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/data_paths.py +0 -0
  172. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/domain_handlers.py +0 -0
  173. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  174. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  175. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/operation_manager.py +0 -0
  176. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/python_sandbox.py +0 -0
  177. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/skill_loader.py +0 -0
  178. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/usage_logger.py +0 -0
  179. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/__init__.py +0 -0
  180. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/enforcement.py +0 -0
  181. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/model.py +0 -0
  182. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/persistence.py +0 -0
  183. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/resolver.py +0 -0
  184. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  185. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  186. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  187. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  188. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  189. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/tests/__init__.py +0 -0
  190. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/tests/test_constants.py +0 -0
  191. {ha_mcp_dev-7.14.2.dev2135 → ha_mcp_dev-7.14.2.dev2139}/tests/test_env_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.14.2.dev2135
3
+ Version: 7.14.2.dev2139
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.14.2.dev2135"
7
+ version = "7.14.2.dev2139"
8
8
  description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
9
9
  readme = "README.md"
10
10
  # Upper bound widened to <3.15 so the package installs on Home Assistant's
@@ -9,12 +9,15 @@ from __future__ import annotations
9
9
 
10
10
  import json
11
11
  import re
12
+ from collections import Counter
12
13
  from pathlib import Path
13
14
  from typing import Any
14
15
 
15
16
  DEFAULT_LOCALE = "en"
16
17
  LOCALE_COOKIE = "ha_mcp_locale"
17
18
  LOCALES_DIR = Path(__file__).parent / "locales"
19
+ # The page whose tab buttons define the valid cross-panel link targets.
20
+ _SETTINGS_HTML = Path(__file__).parent / "settings.html"
18
21
 
19
22
  _PLACEHOLDER_RE = re.compile(r"\{([a-zA-Z_][a-zA-Z0-9_]*)\}")
20
23
 
@@ -60,8 +63,14 @@ def _validate_tools(value: Any, *, context: str) -> dict[str, dict[str, str]]:
60
63
  return result
61
64
 
62
65
 
63
- def load_catalogs(directory: Path = LOCALES_DIR) -> dict[str, dict[str, Any]]:
64
- """Load and validate every JSON translation catalog in ``directory``."""
66
+ def load_catalogs(
67
+ directory: Path = LOCALES_DIR, settings_html: Path = _SETTINGS_HTML
68
+ ) -> dict[str, dict[str, Any]]:
69
+ """Load and validate every JSON translation catalog in ``directory``.
70
+
71
+ ``settings_html`` is the page whose tab buttons define the valid
72
+ cross-panel link targets; overridable so tests need not depend on the
73
+ shipped page's panel ids."""
65
74
  catalogs: dict[str, dict[str, Any]] = {}
66
75
  try:
67
76
  paths = sorted(directory.glob("*.json"))
@@ -113,6 +122,7 @@ def load_catalogs(directory: Path = LOCALES_DIR) -> dict[str, dict[str, Any]]:
113
122
  )
114
123
  _validate_placeholder_parity(catalogs)
115
124
  _validate_inline_markup(catalogs)
125
+ _validate_panel_links(catalogs, settings_html)
116
126
  return catalogs
117
127
 
118
128
 
@@ -164,6 +174,80 @@ _TAG_LIKE_RE = re.compile(r"</?[a-zA-Z][^>]*>")
164
174
  _ALLOWED_TAGS_RE = re.compile(
165
175
  r'</?code>|</?strong>|</a>|<a href="#" data-panel-link="[a-z][a-z-]*">'
166
176
  )
177
+ # The tab a cross-panel link switches to. The allowlist above only accepts the
178
+ # tag *shape*, so "outils" or "backup" passes it and then silently does
179
+ # nothing: settings.js hands the value to activateTab, which no-ops on an
180
+ # unknown panel. Read the real ids out of the page rather than restating them.
181
+ # Matches the whole anchor, not a bare attribute: a message may legitimately
182
+ # show `<code>data-panel-link="example"</code>` as literal help text, and that
183
+ # is documentation, not navigation.
184
+ _PANEL_LINK_RE = re.compile(r'<a href="#" data-panel-link="([a-z][a-z-]*)">')
185
+ _PANEL_ID_RE = re.compile(r'data-panel="([a-z][a-z-]*)"')
186
+ # Only a real tab button declares a panel. Scanning the whole page for the
187
+ # attribute would let a future code sample or doc comment mentioning
188
+ # `data-panel="example"` register a tab that does not exist — the same gap
189
+ # between "textually present" and "functionally real" this module closes on
190
+ # the link side.
191
+ _TAB_BUTTON_RE = re.compile(r"<button\b[^>]*>")
192
+
193
+
194
+ def _known_panels(settings_html: Path = _SETTINGS_HTML) -> set[str]:
195
+ """Panel ids declared by the settings page's own tab buttons."""
196
+ try:
197
+ markup = settings_html.read_text(encoding="utf-8")
198
+ except OSError as exc: # pragma: no cover - packaging guard
199
+ raise ImportError(
200
+ f"settings.html missing at {settings_html}. It must ship in "
201
+ "package-data (wheel), MANIFEST.in (sdist), and the PyInstaller "
202
+ "datas (binary) -- this is a packaging bug, not a usage error."
203
+ ) from exc
204
+ return {
205
+ panel
206
+ for tag in _TAB_BUTTON_RE.findall(markup)
207
+ if 'role="tab"' in tag
208
+ for panel in _PANEL_ID_RE.findall(tag)
209
+ }
210
+
211
+
212
+ def _validate_panel_links(
213
+ catalogs: dict[str, dict[str, Any]], settings_html: Path = _SETTINGS_HTML
214
+ ) -> None:
215
+ """Reject cross-panel links that point at a tab which does not exist.
216
+
217
+ A mistyped target is invisible to every other check: the tag shape is
218
+ allowlisted, the string carries no placeholders, and the visible link text
219
+ still reads correctly. The link just stops working, in that one language.
220
+
221
+ Scoped to ``messages`` for the same reason ``_validate_inline_markup`` is:
222
+ only those render through ``tHtml``, which restores the anchor. Tool names
223
+ and group labels go through ``escapeHtml``, so a link written there shows
224
+ as visible garbled markup rather than a dead link — wrong, but not silent.
225
+ """
226
+ panels = _known_panels(settings_html)
227
+ english_messages = catalogs[DEFAULT_LOCALE]["messages"]
228
+ for locale, catalog in catalogs.items():
229
+ for key, value in catalog["messages"].items():
230
+ targets = _PANEL_LINK_RE.findall(value)
231
+ unknown = sorted(set(targets) - panels)
232
+ if unknown:
233
+ raise ValueError(
234
+ f"Locale {locale} message {key!r} links to panel(s) "
235
+ f"{unknown}, which settings.html does not declare; "
236
+ f"known panels: {sorted(panels)}"
237
+ )
238
+ source = english_messages.get(key)
239
+ if source is None or locale == DEFAULT_LOCALE:
240
+ continue
241
+ source_targets = _PANEL_LINK_RE.findall(source)
242
+ # Order-independent: a translation may reorder two links to suit
243
+ # its grammar and still point at the same tabs. Counter keeps the
244
+ # multiplicity check, so dropping one of a repeated pair fails.
245
+ if Counter(targets) != Counter(source_targets):
246
+ raise ValueError(
247
+ f"Locale {locale} message {key!r} links to "
248
+ f"{sorted(targets)}, but English links to "
249
+ f"{sorted(source_targets)}"
250
+ )
167
251
 
168
252
 
169
253
  def _validate_inline_markup(catalogs: dict[str, dict[str, Any]]) -> None:
@@ -526,9 +526,12 @@ def log_tool_usage(func: Any) -> Any:
526
526
  elif hasattr(result, "__len__"):
527
527
  response_size = len(str(result).encode("utf-8"))
528
528
  return result
529
- except Exception as e:
529
+ except BaseException as e:
530
+ # BaseException, not Exception: a cancelled tool call must not be
531
+ # recorded as a success. str() is empty on a bare CancelledError,
532
+ # so the class name stands in.
530
533
  success = False
531
- error_message = str(e)
534
+ error_message = str(e) or type(e).__name__
532
535
  raise
533
536
  finally:
534
537
  execution_time_ms = (time.time() - start_time) * 1000
@@ -913,6 +913,9 @@ class DeepSearchMixin(SceneSearchMixin):
913
913
  return_exceptions=True,
914
914
  )
915
915
  for result in type_results:
916
+ if isinstance(result, BaseException) and not isinstance(result, Exception):
917
+ # Never swallow cancellation/shutdown into a failed-type count.
918
+ raise result
916
919
  if isinstance(result, tuple):
917
920
  type_matches, type_failed = result
918
921
  results.extend(type_matches)
@@ -1166,6 +1169,11 @@ class DeepSearchMixin(SceneSearchMixin):
1166
1169
  results: list[dict[str, Any]] = []
1167
1170
  failed_count = 1 if list_failed else 0
1168
1171
  for dash_result in dash_results:
1172
+ if isinstance(dash_result, BaseException) and not isinstance(
1173
+ dash_result, Exception
1174
+ ):
1175
+ # Never swallow cancellation/shutdown into a failure count.
1176
+ raise dash_result
1169
1177
  if isinstance(dash_result, tuple):
1170
1178
  dash_matches, dash_failed = dash_result
1171
1179
  results.extend(dash_matches)
@@ -1491,6 +1499,9 @@ class DeepSearchMixin(SceneSearchMixin):
1491
1499
  out: list[dict[str, Any]] = []
1492
1500
  probe_failures = 0
1493
1501
  for item in scored:
1502
+ if isinstance(item, BaseException) and not isinstance(item, Exception):
1503
+ # Never swallow cancellation/shutdown into a probe-failure log.
1504
+ raise item
1494
1505
  if isinstance(item, tuple):
1495
1506
  result, probe_failed = item
1496
1507
  if result is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.14.2.dev2135
3
+ Version: 7.14.2.dev2139
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT