ha-mcp-dev 8.3.0.dev2438__tar.gz → 8.3.0.dev2442__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 (283) hide show
  1. {ha_mcp_dev-8.3.0.dev2438/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.3.0.dev2442}/PKG-INFO +1 -1
  2. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/pyproject.toml +1 -1
  3. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_i18n.py +247 -37
  4. ha_mcp_dev-8.3.0.dev2442/src/ha_mcp/settings_ui/_locale_policy.py +13 -0
  5. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/README.md +9 -0
  6. ha_mcp_dev-8.3.0.dev2442/src/ha_mcp/settings_ui/locales/tlh.json +832 -0
  7. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_fetch.py +1 -1
  8. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_graph.py +11 -4
  9. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  10. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp_dev.egg-info/SOURCES.txt +2 -0
  11. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/LICENSE +0 -0
  12. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/MANIFEST.in +0 -0
  13. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/README.md +0 -0
  14. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/setup.cfg +0 -0
  15. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/__init__.py +0 -0
  16. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/__main__.py +0 -0
  17. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_pypi_marker +0 -0
  18. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_rich_compat.py +0 -0
  19. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/__init__.py +0 -0
  20. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/requirements.txt +0 -0
  21. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/LICENSE +0 -0
  22. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256 +0 -0
  23. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/VENDORED +0 -0
  24. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/__init__.py +0 -0
  25. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/__main__.py +0 -0
  26. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/asyncio/__init__.py +0 -0
  27. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/asyncio/client.py +0 -0
  28. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/asyncio/connection.py +0 -0
  29. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/asyncio/messages.py +0 -0
  30. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/asyncio/router.py +0 -0
  31. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/asyncio/server.py +0 -0
  32. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/auth.py +0 -0
  33. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/cli.py +0 -0
  34. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/client.py +0 -0
  35. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/connection.py +0 -0
  36. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/datastructures.py +0 -0
  37. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/exceptions.py +0 -0
  38. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/extensions/__init__.py +0 -0
  39. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/extensions/base.py +0 -0
  40. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/extensions/permessage_deflate.py +0 -0
  41. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/frames.py +0 -0
  42. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/headers.py +0 -0
  43. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/http11.py +0 -0
  44. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/imports.py +0 -0
  45. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/__init__.py +0 -0
  46. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/auth.py +0 -0
  47. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/client.py +0 -0
  48. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/exceptions.py +0 -0
  49. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/framing.py +0 -0
  50. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/handshake.py +0 -0
  51. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/http.py +0 -0
  52. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/protocol.py +0 -0
  53. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/legacy/server.py +0 -0
  54. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/protocol.py +0 -0
  55. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/proxy.py +0 -0
  56. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/py.typed +0 -0
  57. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/server.py +0 -0
  58. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/streams.py +0 -0
  59. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/__init__.py +0 -0
  60. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/client.py +0 -0
  61. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/connection.py +0 -0
  62. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/messages.py +0 -0
  63. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/router.py +0 -0
  64. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/server.py +0 -0
  65. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/sync/utils.py +0 -0
  66. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/__init__.py +0 -0
  67. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/client.py +0 -0
  68. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/connection.py +0 -0
  69. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/messages.py +0 -0
  70. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/router.py +0 -0
  71. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/server.py +0 -0
  72. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/trio/utils.py +0 -0
  73. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/typing.py +0 -0
  74. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/uri.py +0 -0
  75. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/utils.py +0 -0
  76. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_vendor/websockets/version.py +0 -0
  77. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/_version.py +0 -0
  78. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/auth/__init__.py +0 -0
  79. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/auth/consent_form.py +0 -0
  80. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/auth/oidc_compat.py +0 -0
  81. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/auth/provider.py +0 -0
  82. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/backup_manager.py +0 -0
  83. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/browser_landing.py +0 -0
  84. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/client/__init__.py +0 -0
  85. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/client/rest_client.py +0 -0
  86. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/client/supervisor_client.py +0 -0
  87. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/client/websocket_client.py +0 -0
  88. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/client/websocket_listener.py +0 -0
  89. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/config.py +0 -0
  90. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  91. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  92. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  93. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  94. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  95. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  96. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/errors.py +0 -0
  97. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/hacs_auto_refresh.py +0 -0
  98. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/llm_exposure.py +0 -0
  99. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/log_filters.py +0 -0
  100. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/__init__.py +0 -0
  101. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/approval_queue.py +0 -0
  102. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/editing.py +0 -0
  103. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/evaluator.py +0 -0
  104. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/handlers.py +0 -0
  105. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/middleware.py +0 -0
  106. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/model.py +0 -0
  107. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/persistence.py +0 -0
  108. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/policy/value_sources.py +0 -0
  109. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/py.typed +0 -0
  110. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/read_only.py +0 -0
  111. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/redaction.py +0 -0
  112. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/renamed_tools.py +0 -0
  113. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  114. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  115. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  116. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  117. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  118. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  119. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  120. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  121. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  122. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  123. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  124. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  125. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  126. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  127. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  128. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  129. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  130. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  131. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  132. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  133. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  134. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  135. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  136. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  137. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  138. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/server.py +0 -0
  139. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/__init__.py +0 -0
  140. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  141. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  142. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  143. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  144. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  145. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  146. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  147. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  148. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_theme.py +0 -0
  149. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  150. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/cs.json +0 -0
  151. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  152. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  153. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/eo.json +0 -0
  154. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/es.json +0 -0
  155. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
  156. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/it.json +0 -0
  157. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/ko.json +0 -0
  158. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/nl.json +0 -0
  159. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/pl.json +0 -0
  160. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  161. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/sv.json +0 -0
  162. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  163. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/settings.css +0 -0
  164. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/settings.html +0 -0
  165. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/settings_ui/settings.js +0 -0
  166. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/smoke_test.py +0 -0
  167. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  168. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/strict_bps.py +0 -0
  169. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/__init__.py +0 -0
  170. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/auto_backup.py +0 -0
  171. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/backup.py +0 -0
  172. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  173. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/best_practice_result.py +0 -0
  174. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/best_practice_variables.py +0 -0
  175. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/bulk_selector.py +0 -0
  176. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/component_api.py +0 -0
  177. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/component_config_entries.py +0 -0
  178. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/component_config_reads.py +0 -0
  179. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/component_devices.py +0 -0
  180. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/component_registries.py +0 -0
  181. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  182. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  183. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_flow_form.py +0 -0
  184. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_flow_menu.py +0 -0
  185. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_flow_walker.py +0 -0
  186. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_identity.py +0 -0
  187. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_reconfigure.py +0 -0
  188. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/config_entry_reload_watch.py +0 -0
  189. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/device_control.py +0 -0
  190. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/error_log_parsing.py +0 -0
  191. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/hacs_registration.py +0 -0
  192. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/helpers.py +0 -0
  193. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/integration_reconfigure.py +0 -0
  194. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/radio/__init__.py +0 -0
  195. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/radio/base.py +0 -0
  196. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/radio/matter.py +0 -0
  197. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/radio/thread.py +0 -0
  198. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  199. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/radio/zwave.py +0 -0
  200. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/reference_validator.py +0 -0
  201. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/registry.py +0 -0
  202. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/renamed_tool_middleware.py +0 -0
  203. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  204. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  205. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  206. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  207. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  208. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  209. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  210. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  211. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  212. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_addons.py +0 -0
  213. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_areas.py +0 -0
  214. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_assist_pipeline.py +0 -0
  215. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  216. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  217. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_calendar.py +0 -0
  218. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_camera.py +0 -0
  219. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_categories.py +0 -0
  220. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_code.py +0 -0
  221. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  222. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  223. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  224. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  225. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  226. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  227. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_dev.py +0 -0
  228. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_energy.py +0 -0
  229. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_entities.py +0 -0
  230. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  231. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_groups.py +0 -0
  232. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_hacs.py +0 -0
  233. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_history.py +0 -0
  234. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_integrations.py +0 -0
  235. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_labels.py +0 -0
  236. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_radio.py +0 -0
  237. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_registry.py +0 -0
  238. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_resources.py +0 -0
  239. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_search.py +0 -0
  240. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_security_policy.py +0 -0
  241. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_service.py +0 -0
  242. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_services.py +0 -0
  243. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_system.py +0 -0
  244. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_themes.py +0 -0
  245. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_todo.py +0 -0
  246. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_traces.py +0 -0
  247. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_updates.py +0 -0
  248. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_utility.py +0 -0
  249. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  250. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  251. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  252. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/tools_zones.py +0 -0
  253. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/util_helpers.py +0 -0
  254. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/tools/validation_middleware.py +0 -0
  255. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/transforms/__init__.py +0 -0
  256. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/transforms/categorized_search.py +0 -0
  257. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  258. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/transport_security.py +0 -0
  259. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/update_check.py +0 -0
  260. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/__init__.py +0 -0
  261. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/config_hash.py +0 -0
  262. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/config_write_lock.py +0 -0
  263. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/data_paths.py +0 -0
  264. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/domain_handlers.py +0 -0
  265. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/entity_membership.py +0 -0
  266. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  267. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  268. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/operation_manager.py +0 -0
  269. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/python_sandbox.py +0 -0
  270. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/skill_loader.py +0 -0
  271. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/utils/usage_logger.py +0 -0
  272. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/visibility/__init__.py +0 -0
  273. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/visibility/enforcement.py +0 -0
  274. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/visibility/model.py +0 -0
  275. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/visibility/persistence.py +0 -0
  276. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp/visibility/resolver.py +0 -0
  277. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  278. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  279. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  280. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  281. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/tests/__init__.py +0 -0
  282. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/tests/test_constants.py +0 -0
  283. {ha_mcp_dev-8.3.0.dev2438 → ha_mcp_dev-8.3.0.dev2442}/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: 8.3.0.dev2438
3
+ Version: 8.3.0.dev2442
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 = "8.3.0.dev2438"
7
+ version = "8.3.0.dev2442"
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
@@ -8,11 +8,16 @@ individual translations may be incomplete and safely inherit missing values.
8
8
  from __future__ import annotations
9
9
 
10
10
  import json
11
+ import logging
11
12
  import re
12
13
  from collections import Counter
13
14
  from pathlib import Path
14
15
  from typing import Any
15
16
 
17
+ from . import _locale_policy
18
+
19
+ _LOGGER = logging.getLogger(__name__)
20
+
16
21
  DEFAULT_LOCALE = "en"
17
22
  LOCALE_COOKIE = "ha_mcp_locale"
18
23
  LOCALES_DIR = Path(__file__).parent / "locales"
@@ -87,6 +92,220 @@ def _validate_tools(value: Any, *, context: str) -> dict[str, dict[str, str]]:
87
92
  return result
88
93
 
89
94
 
95
+ def _warn_best_effort_catalog(locale: str, path: Path, exc: Exception) -> None:
96
+ _LOGGER.warning("Skipping best-effort locale %s from %s: %s", locale, path, exc)
97
+
98
+
99
+ def _warn_best_effort_entry(locale: str, entry: str, exc: Exception) -> None:
100
+ _LOGGER.warning(
101
+ "Ignoring invalid best-effort locale %s %s; using English fallback: %s",
102
+ locale,
103
+ entry,
104
+ exc,
105
+ )
106
+
107
+
108
+ def _validate_best_effort_string_map(
109
+ value: Any,
110
+ *,
111
+ locale: str,
112
+ context: str,
113
+ entry_kind: str,
114
+ ) -> dict[str, str]:
115
+ """Drop invalid best-effort strings while preserving valid siblings."""
116
+ if value is None:
117
+ return {}
118
+ if not isinstance(value, dict):
119
+ raise ValueError(f"{context} must be an object")
120
+
121
+ result: dict[str, str] = {}
122
+ for key, text in value.items():
123
+ try:
124
+ result.update(_validate_string_map({key: text}, context=context))
125
+ except ValueError as exc:
126
+ _warn_best_effort_entry(locale, f"{entry_kind} {key!r}", exc)
127
+ return result
128
+
129
+
130
+ def _validate_best_effort_tools(
131
+ value: Any, *, locale: str, context: str
132
+ ) -> dict[str, dict[str, str]]:
133
+ """Drop invalid best-effort tool fields while preserving valid siblings."""
134
+ if value is None:
135
+ return {}
136
+ if not isinstance(value, dict):
137
+ raise ValueError(f"{context} must be an object")
138
+
139
+ result: dict[str, dict[str, str]] = {}
140
+ for tool_name, tool_values in value.items():
141
+ if not isinstance(tool_name, str) or not isinstance(tool_values, dict):
142
+ exc = ValueError(f"{context} entries must be objects keyed by tool name")
143
+ _warn_best_effort_entry(locale, f"tool {tool_name!r}", exc)
144
+ continue
145
+
146
+ translated: dict[str, str] = {}
147
+ for field, field_value in tool_values.items():
148
+ if field not in ("title", "description"):
149
+ exc = ValueError(
150
+ f"{context}.{tool_name} has unsupported field: {field!r}"
151
+ )
152
+ _warn_best_effort_entry(
153
+ locale, f"tool {tool_name!r} field {field!r}", exc
154
+ )
155
+ continue
156
+ try:
157
+ validated = _validate_tools(
158
+ {tool_name: {field: field_value}}, context=context
159
+ )
160
+ except ValueError as exc:
161
+ _warn_best_effort_entry(
162
+ locale, f"tool {tool_name!r} field {field!r}", exc
163
+ )
164
+ continue
165
+ if field in validated[tool_name]:
166
+ translated[field] = validated[tool_name][field]
167
+ if translated:
168
+ result[tool_name] = translated
169
+ return result
170
+
171
+
172
+ def _load_catalog_file(
173
+ path: Path, *, best_effort_locale: str | None = None
174
+ ) -> dict[str, Any]:
175
+ """Load and validate one catalog without coupling it to its siblings."""
176
+ try:
177
+ raw = json.loads(path.read_text(encoding="utf-8"))
178
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
179
+ raise ImportError(f"Invalid settings UI locale catalog: {path}") from exc
180
+ if not isinstance(raw, dict):
181
+ raise ValueError(f"Locale catalog {path} must contain a JSON object")
182
+
183
+ meta = raw.get("meta")
184
+ if not isinstance(meta, dict):
185
+ raise ValueError(f"Locale catalog {path} must define a meta object")
186
+ native_name = meta.get("native_name")
187
+ direction = meta.get("dir", "ltr")
188
+ if not isinstance(native_name, str) or not native_name.strip():
189
+ raise ValueError(f"Locale catalog {path} needs meta.native_name")
190
+ if direction not in ("ltr", "rtl"):
191
+ raise ValueError(f"Locale catalog {path} meta.dir must be ltr or rtl")
192
+
193
+ unknown_sections = set(raw) - {"meta", "messages", "tool_groups", "tools"}
194
+ if unknown_sections:
195
+ raise ValueError(
196
+ f"Locale catalog {path} has unsupported sections: "
197
+ f"{sorted(unknown_sections)}"
198
+ )
199
+
200
+ if best_effort_locale is None:
201
+ messages = _validate_string_map(
202
+ raw.get("messages"), context=f"{path.name}.messages"
203
+ )
204
+ tool_groups = _validate_string_map(
205
+ raw.get("tool_groups"), context=f"{path.name}.tool_groups"
206
+ )
207
+ tools = _validate_tools(raw.get("tools"), context=f"{path.name}.tools")
208
+ else:
209
+ messages = _validate_best_effort_string_map(
210
+ raw.get("messages"),
211
+ locale=best_effort_locale,
212
+ context=f"{path.name}.messages",
213
+ entry_kind="message",
214
+ )
215
+ tool_groups = _validate_best_effort_string_map(
216
+ raw.get("tool_groups"),
217
+ locale=best_effort_locale,
218
+ context=f"{path.name}.tool_groups",
219
+ entry_kind="tool group",
220
+ )
221
+ tools = _validate_best_effort_tools(
222
+ raw.get("tools"),
223
+ locale=best_effort_locale,
224
+ context=f"{path.name}.tools",
225
+ )
226
+
227
+ return {
228
+ "meta": {"native_name": native_name, "dir": direction},
229
+ "messages": messages,
230
+ "tool_groups": tool_groups,
231
+ "tools": tools,
232
+ }
233
+
234
+
235
+ def _catalog_fragment(
236
+ catalog: dict[str, Any],
237
+ *,
238
+ messages: dict[str, str] | None = None,
239
+ tools: dict[str, dict[str, str]] | None = None,
240
+ ) -> dict[str, Any]:
241
+ """Return a minimal catalog used to validate one translated entry."""
242
+ return {
243
+ "meta": catalog["meta"],
244
+ "messages": messages or {},
245
+ "tool_groups": {},
246
+ "tools": tools or {},
247
+ }
248
+
249
+
250
+ def _sanitize_best_effort_catalog(
251
+ locale: str,
252
+ catalog: dict[str, Any],
253
+ english: dict[str, Any],
254
+ settings_html: Path,
255
+ ) -> dict[str, Any]:
256
+ """Drop only invalid translated entries so the rest of a locale survives."""
257
+ sanitized = {
258
+ "meta": dict(catalog["meta"]),
259
+ "messages": dict(catalog["messages"]),
260
+ "tool_groups": dict(catalog["tool_groups"]),
261
+ "tools": {
262
+ tool_name: dict(fields) for tool_name, fields in catalog["tools"].items()
263
+ },
264
+ }
265
+ known_panels = _known_panels(settings_html)
266
+
267
+ for key, translated in tuple(sanitized["messages"].items()):
268
+ english_messages = (
269
+ {key: english["messages"][key]} if key in english["messages"] else {}
270
+ )
271
+ candidate = {
272
+ DEFAULT_LOCALE: _catalog_fragment(english, messages=english_messages),
273
+ locale: _catalog_fragment(sanitized, messages={key: translated}),
274
+ }
275
+ try:
276
+ _validate_placeholder_parity(candidate)
277
+ _validate_inline_markup(candidate)
278
+ _validate_panel_links(candidate, settings_html, known_panels=known_panels)
279
+ except ValueError as exc:
280
+ del sanitized["messages"][key]
281
+ _warn_best_effort_entry(locale, f"message {key!r}", exc)
282
+
283
+ for tool_name, translated_tool in tuple(sanitized["tools"].items()):
284
+ for field, translated in tuple(translated_tool.items()):
285
+ english_field = english["tools"].get(tool_name, {}).get(field)
286
+ english_tools = (
287
+ {tool_name: {field: english_field}} if english_field is not None else {}
288
+ )
289
+ candidate = {
290
+ DEFAULT_LOCALE: _catalog_fragment(english, tools=english_tools),
291
+ locale: _catalog_fragment(
292
+ sanitized,
293
+ tools={tool_name: {field: translated}},
294
+ ),
295
+ }
296
+ try:
297
+ _validate_placeholder_parity(candidate)
298
+ except ValueError as exc:
299
+ del translated_tool[field]
300
+ _warn_best_effort_entry(
301
+ locale, f"tool {tool_name!r} field {field!r}", exc
302
+ )
303
+ if not translated_tool:
304
+ del sanitized["tools"][tool_name]
305
+
306
+ return sanitized
307
+
308
+
90
309
  def load_catalogs(
91
310
  directory: Path = LOCALES_DIR, settings_html: Path = _SETTINGS_HTML
92
311
  ) -> dict[str, dict[str, Any]]:
@@ -106,47 +325,35 @@ def load_catalogs(
106
325
  for path in paths:
107
326
  locale = path.stem.lower().replace("_", "-")
108
327
  try:
109
- raw = json.loads(path.read_text(encoding="utf-8"))
110
- except (OSError, json.JSONDecodeError) as exc:
111
- raise ImportError(f"Invalid settings UI locale catalog: {path}") from exc
112
- if not isinstance(raw, dict):
113
- raise ValueError(f"Locale catalog {path} must contain a JSON object")
114
-
115
- meta = raw.get("meta")
116
- if not isinstance(meta, dict):
117
- raise ValueError(f"Locale catalog {path} must define a meta object")
118
- native_name = meta.get("native_name")
119
- direction = meta.get("dir", "ltr")
120
- if not isinstance(native_name, str) or not native_name.strip():
121
- raise ValueError(f"Locale catalog {path} needs meta.native_name")
122
- if direction not in ("ltr", "rtl"):
123
- raise ValueError(f"Locale catalog {path} meta.dir must be ltr or rtl")
124
-
125
- unknown_sections = set(raw) - {"meta", "messages", "tool_groups", "tools"}
126
- if unknown_sections:
127
- raise ValueError(
128
- f"Locale catalog {path} has unsupported sections: "
129
- f"{sorted(unknown_sections)}"
328
+ catalogs[locale] = _load_catalog_file(
329
+ path,
330
+ best_effort_locale=(
331
+ locale if _locale_policy.is_best_effort_locale(locale) else None
332
+ ),
130
333
  )
131
-
132
- catalogs[locale] = {
133
- "meta": {"native_name": native_name, "dir": direction},
134
- "messages": _validate_string_map(
135
- raw.get("messages"), context=f"{path.name}.messages"
136
- ),
137
- "tool_groups": _validate_string_map(
138
- raw.get("tool_groups"), context=f"{path.name}.tool_groups"
139
- ),
140
- "tools": _validate_tools(raw.get("tools"), context=f"{path.name}.tools"),
141
- }
334
+ except (ImportError, ValueError) as exc:
335
+ if not _locale_policy.is_best_effort_locale(locale):
336
+ raise
337
+ _warn_best_effort_catalog(locale, path, exc)
142
338
 
143
339
  if DEFAULT_LOCALE not in catalogs:
144
340
  raise ImportError(
145
341
  f"The settings UI requires {DEFAULT_LOCALE}.json in {directory}"
146
342
  )
147
- _validate_placeholder_parity(catalogs)
148
- _validate_inline_markup(catalogs)
149
- _validate_panel_links(catalogs, settings_html)
343
+
344
+ strict_catalogs = {
345
+ locale: catalog
346
+ for locale, catalog in catalogs.items()
347
+ if not _locale_policy.is_best_effort_locale(locale)
348
+ }
349
+ _validate_placeholder_parity(strict_catalogs)
350
+ _validate_inline_markup(strict_catalogs)
351
+ _validate_panel_links(strict_catalogs, settings_html)
352
+
353
+ for locale in sorted(set(catalogs) - set(strict_catalogs)):
354
+ catalogs[locale] = _sanitize_best_effort_catalog(
355
+ locale, catalogs[locale], catalogs[DEFAULT_LOCALE], settings_html
356
+ )
150
357
  return catalogs
151
358
 
152
359
 
@@ -234,7 +441,10 @@ def _known_panels(settings_html: Path = _SETTINGS_HTML) -> set[str]:
234
441
 
235
442
 
236
443
  def _validate_panel_links(
237
- catalogs: dict[str, dict[str, Any]], settings_html: Path = _SETTINGS_HTML
444
+ catalogs: dict[str, dict[str, Any]],
445
+ settings_html: Path = _SETTINGS_HTML,
446
+ *,
447
+ known_panels: set[str] | None = None,
238
448
  ) -> None:
239
449
  """Reject cross-panel links that point at a tab which does not exist.
240
450
 
@@ -247,7 +457,7 @@ def _validate_panel_links(
247
457
  and group labels go through ``escapeHtml``, so a link written there shows
248
458
  as visible garbled markup rather than a dead link — wrong, but not silent.
249
459
  """
250
- panels = _known_panels(settings_html)
460
+ panels = known_panels if known_panels is not None else _known_panels(settings_html)
251
461
  english_messages = catalogs[DEFAULT_LOCALE]["messages"]
252
462
  for locale, catalog in catalogs.items():
253
463
  for key, value in catalog["messages"].items():
@@ -0,0 +1,13 @@
1
+ """Maintenance policy for intentionally best-effort locale catalogs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ # Klingon is a novelty translation maintained by hand. It must never consume
6
+ # machine-translation quota or block delivery for supported localizations.
7
+ BEST_EFFORT_LOCALES = frozenset({"tlh"})
8
+
9
+
10
+ def is_best_effort_locale(locale: str) -> bool:
11
+ """Return whether ``locale`` is isolated from hard localization gates."""
12
+ normalized = locale.lower().replace("_", "-")
13
+ return normalized in BEST_EFFORT_LOCALES
@@ -24,6 +24,15 @@ Home Assistant language code names every file:
24
24
  - `homeassistant-addon/translations/<code>.yaml` (generated)
25
25
  - `homeassistant-addon-dev/translations/<code>.yaml` (generated)
26
26
 
27
+ Klingon (`tlh`) is the one best-effort exception. Its catalogs may be edited
28
+ manually and still ship, but the automatic translation planner never queues
29
+ them. Missing strings use English fallback; invalid or stale Klingon catalogs
30
+ produce warnings instead of failing CI or the daily locale sync. The runtime
31
+ loader skips an invalid Klingon settings catalog, and the generator can project
32
+ English into its add-on catalogs, so Klingon cannot prevent any other locale
33
+ from loading or updating. All other language codes remain subject to every
34
+ hard gate below.
35
+
27
36
  Add the two authored catalogs, then run `python scripts/generate_locales.py`
28
37
  and merge: the post-merge `locale-sync.yml` workflow machine-fills every string
29
38
  over its next daily runs. The component catalog may start as an empty object;