ha-mcp-dev 8.4.3.dev2576__tar.gz → 8.4.3.dev2579__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 (310) hide show
  1. {ha_mcp_dev-8.4.3.dev2576/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.4.3.dev2579}/PKG-INFO +1 -1
  2. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/pyproject.toml +1 -1
  3. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/approval_queue.py +30 -1
  4. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/middleware.py +139 -31
  5. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  6. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/LICENSE +0 -0
  7. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/MANIFEST.in +0 -0
  8. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/README.md +0 -0
  9. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/setup.cfg +0 -0
  10. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_rich_compat.py +0 -0
  14. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/__init__.py +0 -0
  15. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/requirements.txt +0 -0
  16. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/LICENSE +0 -0
  17. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256 +0 -0
  18. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/VENDORED +0 -0
  19. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/__init__.py +0 -0
  20. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/__main__.py +0 -0
  21. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/asyncio/__init__.py +0 -0
  22. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/asyncio/client.py +0 -0
  23. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/asyncio/connection.py +0 -0
  24. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/asyncio/messages.py +0 -0
  25. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/asyncio/router.py +0 -0
  26. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/asyncio/server.py +0 -0
  27. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/auth.py +0 -0
  28. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/cli.py +0 -0
  29. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/client.py +0 -0
  30. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/connection.py +0 -0
  31. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/datastructures.py +0 -0
  32. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/exceptions.py +0 -0
  33. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/extensions/__init__.py +0 -0
  34. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/extensions/base.py +0 -0
  35. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/extensions/permessage_deflate.py +0 -0
  36. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/frames.py +0 -0
  37. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/headers.py +0 -0
  38. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/http11.py +0 -0
  39. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/imports.py +0 -0
  40. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/__init__.py +0 -0
  41. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/auth.py +0 -0
  42. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/client.py +0 -0
  43. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/exceptions.py +0 -0
  44. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/framing.py +0 -0
  45. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/handshake.py +0 -0
  46. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/http.py +0 -0
  47. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/protocol.py +0 -0
  48. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/legacy/server.py +0 -0
  49. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/protocol.py +0 -0
  50. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/proxy.py +0 -0
  51. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/py.typed +0 -0
  52. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/server.py +0 -0
  53. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/streams.py +0 -0
  54. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/__init__.py +0 -0
  55. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/client.py +0 -0
  56. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/connection.py +0 -0
  57. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/messages.py +0 -0
  58. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/router.py +0 -0
  59. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/server.py +0 -0
  60. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/sync/utils.py +0 -0
  61. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/__init__.py +0 -0
  62. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/client.py +0 -0
  63. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/connection.py +0 -0
  64. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/messages.py +0 -0
  65. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/router.py +0 -0
  66. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/server.py +0 -0
  67. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/trio/utils.py +0 -0
  68. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/typing.py +0 -0
  69. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/uri.py +0 -0
  70. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/utils.py +0 -0
  71. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_vendor/websockets/version.py +0 -0
  72. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/_version.py +0 -0
  73. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/auth/__init__.py +0 -0
  74. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/auth/consent_form.py +0 -0
  75. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/auth/oidc_compat.py +0 -0
  76. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/auth/provider.py +0 -0
  77. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/backup_manager.py +0 -0
  78. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/browser_landing.py +0 -0
  79. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/client/__init__.py +0 -0
  80. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/client/rest_client.py +0 -0
  81. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/client/supervisor_client.py +0 -0
  82. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/client/websocket_client.py +0 -0
  83. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/client/websocket_listener.py +0 -0
  84. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/config.py +0 -0
  85. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  86. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  87. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  88. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  89. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  90. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  91. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/errors.py +0 -0
  92. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/ha_request_queue.py +0 -0
  93. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/hacs_auto_refresh.py +0 -0
  94. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/llm_exposure.py +0 -0
  95. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/log_filters.py +0 -0
  96. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/__init__.py +0 -0
  97. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/editing.py +0 -0
  98. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/evaluator.py +0 -0
  99. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/handlers.py +0 -0
  100. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/model.py +0 -0
  101. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/persistence.py +0 -0
  102. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/policy/value_sources.py +0 -0
  103. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/py.typed +0 -0
  104. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/read_only.py +0 -0
  105. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/redaction.py +0 -0
  106. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/renamed_tools.py +0 -0
  107. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  108. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  109. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  110. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  111. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  112. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  113. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  114. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  115. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  116. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  117. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/area-target-over-entity-list/case.yaml +0 -0
  118. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/arrive-home-automation/case.yaml +0 -0
  119. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/assist-shortcut-card/case.yaml +0 -0
  120. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/avg-temperature/case.yaml +0 -0
  121. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/backup-deletion-confirmation/case.yaml +0 -0
  122. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/blueprint-authoring/case.yaml +0 -0
  123. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/button-event-entity/case.yaml +0 -0
  124. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/device-id-trigger-migration/case.yaml +0 -0
  125. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/helper-flow-fields-not-platform-yaml/case.yaml +0 -0
  126. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/media-player-song/case.yaml +0 -0
  127. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/motion-light-automation-mode/case.yaml +0 -0
  128. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/rename-entity-impact-analysis/case.yaml +0 -0
  129. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/template-attributes-yaml-exception/case.yaml +0 -0
  130. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/timer-finished-automation/case.yaml +0 -0
  131. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/evals/vacuum-last-clean/case.yaml +0 -0
  132. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/scripts/check_eval_cases.py +0 -0
  133. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  134. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  135. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  136. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/backups.md +0 -0
  137. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  138. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  139. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  140. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  141. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  142. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  143. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  144. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  145. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  146. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  147. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  148. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/server.py +0 -0
  149. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/__init__.py +0 -0
  150. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  151. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  152. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  153. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  154. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  155. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  156. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_i18n.py +0 -0
  157. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_locale_policy.py +0 -0
  158. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  159. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  160. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_theme.py +0 -0
  161. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  162. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  163. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/cs.json +0 -0
  164. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  165. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  166. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/eo.json +0 -0
  167. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/es.json +0 -0
  168. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
  169. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/it.json +0 -0
  170. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/ko.json +0 -0
  171. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/nl.json +0 -0
  172. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/pl.json +0 -0
  173. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  174. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/sv.json +0 -0
  175. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/tlh.json +0 -0
  176. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  177. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/settings.css +0 -0
  178. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/settings.html +0 -0
  179. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/settings_ui/settings.js +0 -0
  180. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/smoke_test.py +0 -0
  181. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  182. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/strict_bps.py +0 -0
  183. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tool_dispatch.py +0 -0
  184. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/__init__.py +0 -0
  185. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/auto_backup.py +0 -0
  186. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/backup.py +0 -0
  187. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  188. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/best_practice_result.py +0 -0
  189. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/best_practice_variables.py +0 -0
  190. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/blueprint_sources.py +0 -0
  191. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/blueprint_substitute.py +0 -0
  192. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/blueprint_write.py +0 -0
  193. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/bulk_selector.py +0 -0
  194. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/component_api.py +0 -0
  195. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/component_config_entries.py +0 -0
  196. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/component_config_reads.py +0 -0
  197. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/component_devices.py +0 -0
  198. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/component_registries.py +0 -0
  199. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  200. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  201. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_flow_form.py +0 -0
  202. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_flow_menu.py +0 -0
  203. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_flow_walker.py +0 -0
  204. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_identity.py +0 -0
  205. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_reconfigure.py +0 -0
  206. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/config_entry_reload_watch.py +0 -0
  207. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/device_control.py +0 -0
  208. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/error_log_parsing.py +0 -0
  209. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/hacs_registration.py +0 -0
  210. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/helpers.py +0 -0
  211. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/integration_reconfigure.py +0 -0
  212. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/log_common.py +0 -0
  213. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/log_sources.py +0 -0
  214. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/log_sources_fault.py +0 -0
  215. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/log_sources_supervisor.py +0 -0
  216. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/radio/__init__.py +0 -0
  217. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/radio/base.py +0 -0
  218. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/radio/matter.py +0 -0
  219. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/radio/thread.py +0 -0
  220. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  221. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/radio/zwave.py +0 -0
  222. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/reference_validator.py +0 -0
  223. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/registry.py +0 -0
  224. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/renamed_tool_middleware.py +0 -0
  225. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  226. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  227. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  228. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  229. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  230. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  231. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_graph.py +0 -0
  232. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  233. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  234. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  235. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  236. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_addons.py +0 -0
  237. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_areas.py +0 -0
  238. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_assist_pipeline.py +0 -0
  239. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  240. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  241. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_calendar.py +0 -0
  242. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_camera.py +0 -0
  243. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_categories.py +0 -0
  244. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_code.py +0 -0
  245. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  246. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  247. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  248. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  249. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  250. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  251. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_dev.py +0 -0
  252. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_energy.py +0 -0
  253. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_entities.py +0 -0
  254. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  255. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_groups.py +0 -0
  256. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_hacs.py +0 -0
  257. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_history.py +0 -0
  258. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_integrations.py +0 -0
  259. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_labels.py +0 -0
  260. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_logs.py +0 -0
  261. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_radio.py +0 -0
  262. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_registry.py +0 -0
  263. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_resources.py +0 -0
  264. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_search.py +0 -0
  265. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_security_policy.py +0 -0
  266. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_service.py +0 -0
  267. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_services.py +0 -0
  268. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_system.py +0 -0
  269. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_themes.py +0 -0
  270. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_todo.py +0 -0
  271. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_traces.py +0 -0
  272. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_updates.py +0 -0
  273. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_utility.py +0 -0
  274. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  275. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  276. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  277. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/tools_zones.py +0 -0
  278. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/util_helpers.py +0 -0
  279. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/tools/validation_middleware.py +0 -0
  280. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/transforms/__init__.py +0 -0
  281. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/transforms/categorized_search.py +0 -0
  282. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  283. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/transport_security.py +0 -0
  284. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/update_check.py +0 -0
  285. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/__init__.py +0 -0
  286. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/config_hash.py +0 -0
  287. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/config_write_lock.py +0 -0
  288. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/data_paths.py +0 -0
  289. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/device_registry_semantics.py +0 -0
  290. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/domain_handlers.py +0 -0
  291. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/entity_membership.py +0 -0
  292. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  293. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  294. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/operation_manager.py +0 -0
  295. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/python_sandbox.py +0 -0
  296. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/skill_loader.py +0 -0
  297. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/utils/usage_logger.py +0 -0
  298. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/visibility/__init__.py +0 -0
  299. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/visibility/enforcement.py +0 -0
  300. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/visibility/model.py +0 -0
  301. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/visibility/persistence.py +0 -0
  302. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp/visibility/resolver.py +0 -0
  303. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  304. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  305. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  306. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  307. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  308. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/tests/__init__.py +0 -0
  309. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/tests/test_constants.py +0 -0
  310. {ha_mcp_dev-8.4.3.dev2576 → ha_mcp_dev-8.4.3.dev2579}/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.4.3.dev2576
3
+ Version: 8.4.3.dev2579
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.4.3.dev2576"
7
+ version = "8.4.3.dev2579"
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
@@ -33,6 +33,7 @@ class PendingApproval:
33
33
  expires_at: datetime
34
34
  _decision: Decision = "pending"
35
35
  _event: anyio.Event = field(default_factory=anyio.Event)
36
+ _claimed: bool = False
36
37
 
37
38
  @property
38
39
  def decision(self) -> Decision:
@@ -51,6 +52,26 @@ class PendingApproval:
51
52
  await self._event.wait()
52
53
  return self._decision
53
54
 
55
+ def claim(self) -> bool:
56
+ """Take exclusive ownership of this approval. False if already taken.
57
+
58
+ ``decide()`` wakes every waiter sharing this entry, and each one
59
+ would otherwise consume it and dispatch — one click authorizing N
60
+ executions (issue #2387). This is the same one-shot transition
61
+ ``decide()`` uses, and for the same reason: exactly one caller may
62
+ act on a given decision.
63
+
64
+ The flag lives on the entry rather than on queue membership
65
+ because ``_sweep_expired`` can drop an approved row (it ignores
66
+ ``decision``) while a waiter still holds this reference and is
67
+ legitimately entitled to consume it. There is no ``await`` here,
68
+ so the check-and-set cannot interleave with another task.
69
+ """
70
+ if self._claimed:
71
+ return False
72
+ self._claimed = True
73
+ return True
74
+
54
75
  def __post_init__(self) -> None:
55
76
  if self.expires_at <= self.created_at:
56
77
  raise ValueError("expires_at must be after created_at")
@@ -221,10 +242,18 @@ class ApprovalQueue:
221
242
 
222
243
  def consume_and_maybe_remember(
223
244
  self, entry: PendingApproval, *, remember_minutes: int
224
- ) -> None:
245
+ ) -> bool:
246
+ """Consume one approval. False when another waiter already did.
247
+
248
+ A losing caller must not dispatch on this entry, and must not
249
+ arm the remember-cache from a decision it did not consume.
250
+ """
251
+ if not entry.claim():
252
+ return False
225
253
  self.remove(entry.token)
226
254
  if remember_minutes > 0:
227
255
  self.remember(entry.tool_name, entry.args_hash, minutes=remember_minutes)
256
+ return True
228
257
 
229
258
  def _sweep_expired(self) -> None:
230
259
  now = datetime.now(UTC)
@@ -56,7 +56,12 @@ class PolicyMiddleware(Middleware):
56
56
 
57
57
  Loads the policy, evaluates the call, and -- when approval is
58
58
  required -- finds or creates a pending queue entry and waits up to
59
- the configured window for a decision. A dynamic selector call
59
+ the configured window for a decision. Identical static calls share
60
+ one queue entry so the user sees a single approval row, but the
61
+ approval itself is consumed exactly once
62
+ (``PendingApproval.claim``): a second waiter woken by the same
63
+ decision gets its own pending row instead of riding the first
64
+ call's click. A dynamic selector call
60
65
  (``has_dynamic_selector_targets``) never shares or reuses another
61
66
  call's pending entry, and is never reissued on TTL eviction: see
62
67
  the inline comments above the ``existing =``, ``pending =``, and
@@ -167,36 +172,16 @@ class PolicyMiddleware(Middleware):
167
172
  # The accepted cost is that a retry never silently rides an earlier
168
173
  # approval: each blocked call gets its own approval row, and only
169
174
  # approving the row for the CURRENTLY-blocked call has any effect.
170
- existing = None if dynamic_targets else self._queue.find(name, args_hash)
171
- if existing and existing.decision == "approved":
172
- self._queue.consume_and_maybe_remember(
173
- existing,
174
- remember_minutes=remember_minutes,
175
- )
175
+ if self._resolve_already_decided(
176
+ name,
177
+ args_hash,
178
+ dynamic_targets=dynamic_targets,
179
+ remember_minutes=remember_minutes,
180
+ ):
176
181
  return await call_next(context)
177
- if existing and existing.decision == "denied":
178
- self._queue.remove(existing.token)
179
- self._raise_denied_error()
180
182
 
181
- # find_or_create serialises the create — two concurrent calls with
182
- # the same args_hash share one pending entry, so the user only sees
183
- # one approval row and approving it releases every waiter. Dynamic
184
- # selector calls must NOT share a pending entry: two concurrent
185
- # identical calls can still resolve to different (or overlapping)
186
- # target sets by the time each one dispatches, so folding them onto
187
- # one approval would let a single click authorize more executions
188
- # than the user saw. Skip the sharing and always mint a fresh entry.
189
- pending = (
190
- self._queue.create(
191
- name, args_hash, args, ttl_minutes=policy.approval_ttl_minutes
192
- )
193
- if dynamic_targets
194
- else await self._queue.find_or_create(
195
- name,
196
- args_hash,
197
- args,
198
- ttl_minutes=policy.approval_ttl_minutes,
199
- )
183
+ pending = await self._new_pending(
184
+ name, args_hash, args, policy=policy, dynamic_targets=dynamic_targets
200
185
  )
201
186
 
202
187
  wait = (
@@ -207,11 +192,24 @@ class PolicyMiddleware(Middleware):
207
192
  await self._wait_for_decision(context, pending, wait)
208
193
 
209
194
  if pending.decision == "approved":
210
- self._queue.consume_and_maybe_remember(
195
+ if self._claim_approval(
211
196
  pending,
197
+ name,
198
+ args_hash,
199
+ dynamic_targets=dynamic_targets,
212
200
  remember_minutes=remember_minutes,
201
+ ):
202
+ return await call_next(context)
203
+ # Another waiter on this shared entry consumed the approval
204
+ # first. This call has none of its own, so it must not ride
205
+ # that click: mint a fresh row and tell the caller to get it
206
+ # approved. Its wait budget is already spent, so it does not
207
+ # wait again here -- re-waiting would also let a steady
208
+ # stream of identical calls starve one another.
209
+ pending = await self._new_pending(
210
+ name, args_hash, args, policy=policy, dynamic_targets=dynamic_targets
213
211
  )
214
- return await call_next(context)
212
+ self._raise_pending_error(pending, rule, dynamic_targets=dynamic_targets)
215
213
  if pending.decision == "denied":
216
214
  self._queue.remove(pending.token)
217
215
  self._raise_denied_error()
@@ -222,6 +220,116 @@ class PolicyMiddleware(Middleware):
222
220
  self._raise_pending_error(pending, rule, dynamic_targets=dynamic_targets)
223
221
  return None # py/mixed-returns: explicit terminal; error handlers above always raise (NoReturn), unreachable
224
222
 
223
+ def _resolve_already_decided(
224
+ self,
225
+ name: str,
226
+ args_hash: str,
227
+ *,
228
+ dynamic_targets: bool,
229
+ remember_minutes: int,
230
+ ) -> bool:
231
+ """Act on an entry this call did not create. True means dispatch now.
232
+
233
+ A dynamic selector call must never consume an entry it did not
234
+ itself create and is not itself still waiting on, so it skips this
235
+ lookup entirely -- see the creator-only binding rationale above the
236
+ call site in ``on_call_tool``.
237
+
238
+ The claim cannot currently fail on this path: consuming an entry
239
+ also removes it, and there is no ``await`` between the ``find()``
240
+ and the claim, so no other task can interleave. It is checked
241
+ anyway so that adding an await to this stretch degrades into an
242
+ extra approval prompt rather than silently restoring the double
243
+ dispatch the claim exists to stop.
244
+ """
245
+ if dynamic_targets:
246
+ return False
247
+ existing = self._queue.find(name, args_hash)
248
+ if existing is None:
249
+ return False
250
+ if existing.decision == "approved":
251
+ return self._claim_approval(
252
+ existing,
253
+ name,
254
+ args_hash,
255
+ dynamic_targets=dynamic_targets,
256
+ remember_minutes=remember_minutes,
257
+ )
258
+ if existing.decision == "denied":
259
+ self._queue.remove(existing.token)
260
+ self._raise_denied_error()
261
+ return False
262
+
263
+ def _claim_approval(
264
+ self,
265
+ entry: PendingApproval,
266
+ name: str,
267
+ args_hash: str,
268
+ *,
269
+ dynamic_targets: bool,
270
+ remember_minutes: int,
271
+ ) -> bool:
272
+ """Consume an approved entry for this invocation.
273
+
274
+ Exactly one caller may act on a given approval (see
275
+ ``PendingApproval.claim``). A caller that loses the claim still
276
+ proceeds when the winner's ``remember_minutes`` armed a
277
+ remember-cache entry covering this exact call: that window is the
278
+ user saying "stop asking for this", so re-prompting would
279
+ contradict the rule they configured. The ``is_remembered`` gate
280
+ earlier in ``on_call_tool`` ran before the approval existed, which
281
+ is why it has to be re-checked here rather than relied upon.
282
+
283
+ A dynamic selector call never reads the remember-cache -- that
284
+ same gate skips the lookup for it, and ``remember_minutes`` is
285
+ forced to 0 -- so it must not consult one here either. No
286
+ reachable case arms such a key today (``has_dynamic_selector_targets``
287
+ is a pure function of the name and args that also produce
288
+ ``args_hash``, so static and dynamic calls cannot collide on one
289
+ key), but the guard keeps this branch degrading the same
290
+ direction as the defensive claim check in
291
+ ``_resolve_already_decided``: toward an extra prompt, never
292
+ toward a dispatch the caller was not entitled to.
293
+ """
294
+ if self._queue.consume_and_maybe_remember(
295
+ entry, remember_minutes=remember_minutes
296
+ ):
297
+ return True
298
+ if dynamic_targets:
299
+ return False
300
+ return self._queue.is_remembered(name, args_hash)
301
+
302
+ async def _new_pending(
303
+ self,
304
+ name: str,
305
+ args_hash: str,
306
+ args: dict[str, Any],
307
+ *,
308
+ policy: Policy,
309
+ dynamic_targets: bool,
310
+ ) -> PendingApproval:
311
+ """Mint the pending entry this invocation will wait on.
312
+
313
+ ``find_or_create`` serialises the create -- two concurrent calls
314
+ with the same args_hash share one pending entry, so the user only
315
+ sees one approval row. Sharing the row is safe; sharing the
316
+ *decision* is not, which is what ``_claim_approval`` enforces.
317
+
318
+ Dynamic selector calls must NOT share a pending entry at all: two
319
+ concurrent identical calls can still resolve to different (or
320
+ overlapping) target sets by the time each one dispatches, so
321
+ folding them onto one approval would let a single click authorize
322
+ a broader effect than the user saw. Skip the sharing and always
323
+ mint a fresh entry.
324
+ """
325
+ if dynamic_targets:
326
+ return self._queue.create(
327
+ name, args_hash, args, ttl_minutes=policy.approval_ttl_minutes
328
+ )
329
+ return await self._queue.find_or_create(
330
+ name, args_hash, args, ttl_minutes=policy.approval_ttl_minutes
331
+ )
332
+
225
333
  def _finalize_timed_out_pending(
226
334
  self,
227
335
  pending: PendingApproval,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 8.4.3.dev2576
3
+ Version: 8.4.3.dev2579
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