ha-mcp-dev 7.14.2.dev2136__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.dev2136/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.14.2.dev2139}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_i18n.py +86 -2
  4. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  5. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/LICENSE +0 -0
  6. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/MANIFEST.in +0 -0
  7. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/README.md +0 -0
  8. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/setup.cfg +0 -0
  9. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/__init__.py +0 -0
  10. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/__main__.py +0 -0
  11. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/_pypi_marker +0 -0
  12. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/_version.py +0 -0
  13. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/auth/__init__.py +0 -0
  14. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/auth/consent_form.py +0 -0
  15. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/auth/provider.py +0 -0
  16. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/backup_manager.py +0 -0
  17. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/browser_landing.py +0 -0
  18. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/__init__.py +0 -0
  19. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/rest_client.py +0 -0
  20. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/supervisor_client.py +0 -0
  21. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/websocket_client.py +0 -0
  22. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/client/websocket_listener.py +0 -0
  23. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/config.py +0 -0
  24. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  25. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  26. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  27. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  28. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  29. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  30. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/errors.py +0 -0
  31. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/llm_exposure.py +0 -0
  32. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/__init__.py +0 -0
  33. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/approval_queue.py +0 -0
  34. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/evaluator.py +0 -0
  35. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/handlers.py +0 -0
  36. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/middleware.py +0 -0
  37. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/model.py +0 -0
  38. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/persistence.py +0 -0
  39. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/policy/value_sources.py +0 -0
  40. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/py.typed +0 -0
  41. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/read_only.py +0 -0
  42. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  43. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  44. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  45. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  46. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  47. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  48. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  49. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  50. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  51. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  52. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  53. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  54. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  55. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  56. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  57. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  58. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  59. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  60. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  61. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  62. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  63. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  64. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  65. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  66. {ha_mcp_dev-7.14.2.dev2136 → 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
  67. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/server.py +0 -0
  68. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/__init__.py +0 -0
  69. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  70. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  71. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  72. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  73. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  74. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  75. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  76. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  77. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_theme.py +0 -0
  78. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  79. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  80. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  81. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  82. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
  83. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  84. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  85. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/settings.css +0 -0
  86. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/settings.html +0 -0
  87. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/settings_ui/settings.js +0 -0
  88. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/smoke_test.py +0 -0
  89. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  90. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/strict_bps.py +0 -0
  91. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/__init__.py +0 -0
  92. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/auto_backup.py +0 -0
  93. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/backup.py +0 -0
  94. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  95. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_api.py +0 -0
  96. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_config_reads.py +0 -0
  97. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_devices.py +0 -0
  98. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_registries.py +0 -0
  99. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  100. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  101. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/device_control.py +0 -0
  102. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/enhanced.py +0 -0
  103. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/helpers.py +0 -0
  104. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/__init__.py +0 -0
  105. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/base.py +0 -0
  106. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/matter.py +0 -0
  107. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/thread.py +0 -0
  108. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  109. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/radio/zwave.py +0 -0
  110. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/reference_validator.py +0 -0
  111. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/registry.py +0 -0
  112. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  113. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  114. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  115. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  116. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  117. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  118. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  119. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  120. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  121. {ha_mcp_dev-7.14.2.dev2136 → 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.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_addons.py +0 -0
  123. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_areas.py +0 -0
  124. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  125. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  126. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_calendar.py +0 -0
  127. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_camera.py +0 -0
  128. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_categories.py +0 -0
  129. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_code.py +0 -0
  130. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  131. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  132. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  133. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  134. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  135. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  136. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_dev.py +0 -0
  137. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_energy.py +0 -0
  138. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_entities.py +0 -0
  139. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  140. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_groups.py +0 -0
  141. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_hacs.py +0 -0
  142. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_history.py +0 -0
  143. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_integrations.py +0 -0
  144. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_labels.py +0 -0
  145. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_radio.py +0 -0
  146. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_registry.py +0 -0
  147. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_resources.py +0 -0
  148. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_search.py +0 -0
  149. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_service.py +0 -0
  150. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_services.py +0 -0
  151. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_system.py +0 -0
  152. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_themes.py +0 -0
  153. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_todo.py +0 -0
  154. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_traces.py +0 -0
  155. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_updates.py +0 -0
  156. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_utility.py +0 -0
  157. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  158. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  159. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  160. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/tools_zones.py +0 -0
  161. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/util_helpers.py +0 -0
  162. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/tools/validation_middleware.py +0 -0
  163. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transforms/__init__.py +0 -0
  164. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transforms/categorized_search.py +0 -0
  165. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  166. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/transport_security.py +0 -0
  167. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/update_check.py +0 -0
  168. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/__init__.py +0 -0
  169. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/config_hash.py +0 -0
  170. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/config_write_lock.py +0 -0
  171. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/data_paths.py +0 -0
  172. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/domain_handlers.py +0 -0
  173. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  174. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  175. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/operation_manager.py +0 -0
  176. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/python_sandbox.py +0 -0
  177. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/skill_loader.py +0 -0
  178. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/utils/usage_logger.py +0 -0
  179. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/__init__.py +0 -0
  180. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/enforcement.py +0 -0
  181. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/model.py +0 -0
  182. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/persistence.py +0 -0
  183. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp/visibility/resolver.py +0 -0
  184. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  185. {ha_mcp_dev-7.14.2.dev2136 → 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.dev2136 → 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.dev2136 → ha_mcp_dev-7.14.2.dev2139}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  188. {ha_mcp_dev-7.14.2.dev2136 → 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.dev2136 → ha_mcp_dev-7.14.2.dev2139}/tests/__init__.py +0 -0
  190. {ha_mcp_dev-7.14.2.dev2136 → ha_mcp_dev-7.14.2.dev2139}/tests/test_constants.py +0 -0
  191. {ha_mcp_dev-7.14.2.dev2136 → 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.dev2136
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.dev2136"
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.14.2.dev2136
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