ha-mcp-dev 7.9.0.dev758__tar.gz → 7.9.0.dev760__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 (154) hide show
  1. {ha_mcp_dev-7.9.0.dev758/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.9.0.dev760}/PKG-INFO +9 -2
  2. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/README.md +8 -1
  3. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/pyproject.toml +1 -1
  4. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/client/rest_client.py +28 -8
  5. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/read_only.py +18 -0
  6. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/backup.py +14 -2
  7. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/best_practice_checker.py +73 -2
  8. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_config_automations.py +2 -0
  9. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_traces.py +7 -0
  10. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_updates.py +254 -56
  11. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_utility.py +25 -2
  12. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/update_check.py +2 -2
  13. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/domain_handlers.py +10 -1
  14. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/kill_signal_diagnostics.py +11 -11
  15. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760/src/ha_mcp_dev.egg-info}/PKG-INFO +9 -2
  16. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/LICENSE +0 -0
  17. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/MANIFEST.in +0 -0
  18. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/setup.cfg +0 -0
  19. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/__init__.py +0 -0
  20. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/__main__.py +0 -0
  21. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/_pypi_marker +0 -0
  22. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/_version.py +0 -0
  23. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/auth/__init__.py +0 -0
  24. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/auth/consent_form.py +0 -0
  25. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/auth/provider.py +0 -0
  26. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/backup_manager.py +0 -0
  27. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/client/__init__.py +0 -0
  28. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/client/supervisor_client.py +0 -0
  29. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/client/websocket_client.py +0 -0
  30. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/client/websocket_listener.py +0 -0
  31. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/config.py +0 -0
  32. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  33. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  34. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  35. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/errors.py +0 -0
  36. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/__init__.py +0 -0
  37. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/approval_queue.py +0 -0
  38. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/evaluator.py +0 -0
  39. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/handlers.py +0 -0
  40. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/middleware.py +0 -0
  41. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/model.py +0 -0
  42. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/persistence.py +0 -0
  43. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/policy/value_sources.py +0 -0
  44. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/py.typed +0 -0
  45. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  46. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  47. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  48. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  49. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  50. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  51. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  52. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  53. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  54. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  55. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  56. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  57. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  58. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  59. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  60. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  61. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  62. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  63. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  64. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  65. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  66. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  67. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  68. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  69. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/server.py +0 -0
  70. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/settings_ui/__init__.py +0 -0
  71. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/settings_ui/settings.css +0 -0
  72. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/settings_ui/settings.html +0 -0
  73. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/settings_ui/settings.js +0 -0
  74. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/smoke_test.py +0 -0
  75. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  76. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/__init__.py +0 -0
  77. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/auto_backup.py +0 -0
  78. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  79. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/device_control.py +0 -0
  80. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/enhanced.py +0 -0
  81. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/helpers.py +0 -0
  82. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/radio/__init__.py +0 -0
  83. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/radio/base.py +0 -0
  84. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/radio/matter.py +0 -0
  85. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/radio/thread.py +0 -0
  86. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  87. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/radio/zwave.py +0 -0
  88. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/reference_validator.py +0 -0
  89. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/registry.py +0 -0
  90. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  91. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  92. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  93. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  94. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  95. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  96. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  97. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  98. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  99. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  100. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_addons.py +0 -0
  101. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_areas.py +0 -0
  102. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  103. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  104. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_calendar.py +0 -0
  105. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_camera.py +0 -0
  106. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_categories.py +0 -0
  107. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_code.py +0 -0
  108. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  109. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  110. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  111. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  112. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  113. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_energy.py +0 -0
  114. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_entities.py +0 -0
  115. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  116. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_groups.py +0 -0
  117. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_hacs.py +0 -0
  118. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_history.py +0 -0
  119. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_integrations.py +0 -0
  120. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_labels.py +0 -0
  121. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  122. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_radio.py +0 -0
  123. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_registry.py +0 -0
  124. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_resources.py +0 -0
  125. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_search.py +0 -0
  126. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_service.py +0 -0
  127. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_services.py +0 -0
  128. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_system.py +0 -0
  129. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_themes.py +0 -0
  130. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_todo.py +0 -0
  131. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  132. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  133. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/tools_zones.py +0 -0
  134. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/util_helpers.py +0 -0
  135. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/tools/validation_middleware.py +0 -0
  136. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/transforms/__init__.py +0 -0
  137. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/transforms/categorized_search.py +0 -0
  138. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  139. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/__init__.py +0 -0
  140. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/config_hash.py +0 -0
  141. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/data_paths.py +0 -0
  142. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  143. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/operation_manager.py +0 -0
  144. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/python_sandbox.py +0 -0
  145. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/skill_loader.py +0 -0
  146. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp/utils/usage_logger.py +0 -0
  147. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  148. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  149. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  150. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  151. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  152. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/tests/__init__.py +0 -0
  153. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/tests/test_constants.py +0 -0
  154. {ha_mcp_dev-7.9.0.dev758 → ha_mcp_dev-7.9.0.dev760}/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.9.0.dev758
3
+ Version: 7.9.0.dev760
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
@@ -462,7 +462,14 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
462
462
  - **[@L1AD](https://github.com/L1AD)** — Filed #966 proposing tool security policies; pointed to PolicyLayer's MCP-security work as prior art that inspired the predicate DSL shape.
463
463
  - **[@nightcityblade](https://github.com/nightcityblade)** — Updated stale Home Assistant Advanced Mode references after HA 2026.6 made formerly advanced options available by default (#1533).
464
464
  - **[@emmelutzer](https://github.com/emmelutzer)** — Financial support via [GitHub Sponsors](https://github.com/sponsors/julienld). Thank you! ☕
465
-
465
+ - **[@pkkr](https://github.com/pkkr)** — `ha_knx_get_project` tool exposing KNX group addresses from an uploaded ETS project file.
466
+ - **[@cbowns](https://github.com/cbowns)** — Fixed inconsistent hyphen in setup.astro Codex CLI docs.
467
+ - **[@Shaan-alpha](https://github.com/Shaan-alpha)** — Extended `ha_restart` known-good error patterns to cover 502/503 responses from reverse proxies.
468
+ - **[@rebelancap](https://github.com/rebelancap)** — Fixed UTC-to-local timezone conversion in `add_timezone_metadata`.
469
+ - **[@saevras](https://github.com/saevras)** — Fixed blueprint import E2E test to use local URL instead of host-to-container networking.
470
+ - **[@jasonjhofmann](https://github.com/jasonjhofmann)** — Recurring calendar events via `rrule` support in `ha_config_set_calendar_event`.
471
+ - **[@vpciii](https://github.com/vpciii)** — Coerce JSON-encoded strings on dict/list tool params.
472
+ - **[@pburtchaell](https://github.com/pburtchaell)** — Financial support via [GitHub Sponsors](https://github.com/sponsors/julienld). Thank you! ☕
466
473
  ---
467
474
 
468
475
  ## 💬 Community
@@ -430,7 +430,14 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
430
430
  - **[@L1AD](https://github.com/L1AD)** — Filed #966 proposing tool security policies; pointed to PolicyLayer's MCP-security work as prior art that inspired the predicate DSL shape.
431
431
  - **[@nightcityblade](https://github.com/nightcityblade)** — Updated stale Home Assistant Advanced Mode references after HA 2026.6 made formerly advanced options available by default (#1533).
432
432
  - **[@emmelutzer](https://github.com/emmelutzer)** — Financial support via [GitHub Sponsors](https://github.com/sponsors/julienld). Thank you! ☕
433
-
433
+ - **[@pkkr](https://github.com/pkkr)** — `ha_knx_get_project` tool exposing KNX group addresses from an uploaded ETS project file.
434
+ - **[@cbowns](https://github.com/cbowns)** — Fixed inconsistent hyphen in setup.astro Codex CLI docs.
435
+ - **[@Shaan-alpha](https://github.com/Shaan-alpha)** — Extended `ha_restart` known-good error patterns to cover 502/503 responses from reverse proxies.
436
+ - **[@rebelancap](https://github.com/rebelancap)** — Fixed UTC-to-local timezone conversion in `add_timezone_metadata`.
437
+ - **[@saevras](https://github.com/saevras)** — Fixed blueprint import E2E test to use local URL instead of host-to-container networking.
438
+ - **[@jasonjhofmann](https://github.com/jasonjhofmann)** — Recurring calendar events via `rrule` support in `ha_config_set_calendar_event`.
439
+ - **[@vpciii](https://github.com/vpciii)** — Coerce JSON-encoded strings on dict/list tool params.
440
+ - **[@pburtchaell](https://github.com/pburtchaell)** — Financial support via [GitHub Sponsors](https://github.com/sponsors/julienld). Thank you! ☕
434
441
  ---
435
442
 
436
443
  ## 💬 Community
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.9.0.dev758"
7
+ version = "7.9.0.dev760"
8
8
  description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13,<3.14"
@@ -606,7 +606,7 @@ class HomeAssistantClient:
606
606
  self._supervised_detected = is_supervised
607
607
  return is_supervised
608
608
 
609
- async def get_addon_logs(self, slug: str) -> str:
609
+ async def get_addon_logs(self, slug: str, lines: int | None = None) -> str:
610
610
  """Fetch an add-on's container logs.
611
611
 
612
612
  Branch on ``is_running_in_addon()`` (which keys off ``SUPERVISOR_TOKEN``
@@ -621,6 +621,15 @@ class HomeAssistantClient:
621
621
  HA URL), falls back to the HA Core proxy path. That path requires an
622
622
  admin LLA but works fine when not invoked from the add-on container.
623
623
 
624
+ ``lines`` sets the journald window Supervisor serves via its
625
+ ``?lines=`` query param (supervisor/api/host.py). Without it,
626
+ Supervisor returns only its default window (``DEFAULT_LINES = 100``
627
+ in supervisor/api/const.py) — which silently capped every larger
628
+ caller-side limit before this param existed. Both branches carry
629
+ it: the direct endpoint parses the query natively, and HA Core's
630
+ hassio proxy forwards ``request.query`` upstream
631
+ (homeassistant/components/hassio/http.py).
632
+
624
633
  Both branches return ``text/plain`` log content.
625
634
 
626
635
  Raises:
@@ -633,17 +642,18 @@ class HomeAssistantClient:
633
642
  HomeAssistantConnectionError: Network, timeout, or transport error.
634
643
  """
635
644
  if is_running_in_addon():
636
- return await self._get_addon_logs_via_supervisor(slug)
645
+ return await self._get_addon_logs_via_supervisor(slug, lines=lines)
637
646
 
638
647
  logger.debug(f"Fetching addon logs for slug={slug} via HA Core proxy")
639
648
  response = await self._raw_request(
640
649
  "GET",
641
650
  f"/hassio/addons/{slug}/logs",
642
651
  headers={"Accept": "text/plain"},
652
+ params={"lines": lines} if lines is not None else None,
643
653
  )
644
654
  return response.text
645
655
 
646
- async def _supervisor_logs_get(self, path: str) -> str:
656
+ async def _supervisor_logs_get(self, path: str, lines: int | None = None) -> str:
647
657
  """Fetch ``text/plain`` logs from a Supervisor REST endpoint.
648
658
 
649
659
  ``path`` is everything between ``http://supervisor/`` and ``/logs``:
@@ -652,6 +662,9 @@ class HomeAssistantClient:
652
662
  - ``"<service>"`` (where service ∈ {supervisor, host, core, dns, audio,
653
663
  cli, multicast, observer}) for system-service logs
654
664
 
665
+ ``lines`` maps to the endpoint's ``?lines=`` journald-window query
666
+ param; omitted → Supervisor's 100-line default window.
667
+
655
668
  Bypasses ``HomeAssistantClient.httpx_client`` because the Supervisor
656
669
  endpoint uses a different base URL (``http://supervisor``) and a
657
670
  different token (``SUPERVISOR_TOKEN``) than HA Core REST. Both
@@ -681,9 +694,10 @@ class HomeAssistantClient:
681
694
 
682
695
  relative_path = f"/{path}/logs"
683
696
  logger.debug(
684
- "Fetching %s%s via Supervisor direct",
697
+ "Fetching %s%s via Supervisor direct (lines=%s)",
685
698
  get_supervisor_base_url(),
686
699
  relative_path,
700
+ lines,
687
701
  )
688
702
 
689
703
  try:
@@ -694,6 +708,7 @@ class HomeAssistantClient:
694
708
  response = await client.get(
695
709
  relative_path,
696
710
  headers={"Accept": "text/plain"},
711
+ params={"lines": lines} if lines is not None else None,
697
712
  )
698
713
  except httpx.TimeoutException as e:
699
714
  raise HomeAssistantConnectionError(
@@ -753,7 +768,9 @@ class HomeAssistantClient:
753
768
  )
754
769
  return response.text
755
770
 
756
- async def _get_addon_logs_via_supervisor(self, slug: str) -> str:
771
+ async def _get_addon_logs_via_supervisor(
772
+ self, slug: str, lines: int | None = None
773
+ ) -> str:
757
774
  """Fetch add-on container logs directly from Supervisor's REST API.
758
775
 
759
776
  Distinct from ``tools_bug_report._fetch_addon_logs``: that helper is
@@ -766,9 +783,11 @@ class HomeAssistantClient:
766
783
  Delegates to ``_supervisor_logs_get`` so error handling stays in
767
784
  lockstep with ``_get_system_service_logs``.
768
785
  """
769
- return await self._supervisor_logs_get(f"addons/{slug}")
786
+ return await self._supervisor_logs_get(f"addons/{slug}", lines=lines)
770
787
 
771
- async def _get_system_service_logs(self, service: str) -> str:
788
+ async def _get_system_service_logs(
789
+ self, service: str, lines: int | None = None
790
+ ) -> str:
772
791
  """Fetch HA system-service logs.
773
792
 
774
793
  ``service`` must be one of the eight Supervisor-managed services:
@@ -796,13 +815,14 @@ class HomeAssistantClient:
796
815
  logs) call kept working through its own Core-proxy fallback.
797
816
  """
798
817
  if is_running_in_addon():
799
- return await self._supervisor_logs_get(service)
818
+ return await self._supervisor_logs_get(service, lines=lines)
800
819
 
801
820
  logger.debug(f"Fetching {service} logs via HA Core proxy")
802
821
  response = await self._raw_request(
803
822
  "GET",
804
823
  f"/hassio/{service}/logs",
805
824
  headers={"Accept": "text/plain"},
825
+ params={"lines": lines} if lines is not None else None,
806
826
  )
807
827
  return response.text
808
828
 
@@ -131,6 +131,16 @@ def _custom_tool_write(args: dict[str, Any]) -> str | None:
131
131
  return "sandbox code execution"
132
132
 
133
133
 
134
+ def _updates_write(args: dict[str, Any]) -> str | None:
135
+ # ``action`` defaults to "list" at the schema layer, so a missing action
136
+ # executes as a read (the middleware sees RAW pre-validation arguments —
137
+ # an absent key here means the tool itself will run the list branch).
138
+ action = args.get("action")
139
+ if action in (None, "list", "get"):
140
+ return None
141
+ return f"action={action!r}"
142
+
143
+
134
144
  def _radio_write(args: dict[str, Any]) -> str | None:
135
145
  action = args.get("action")
136
146
  # Reads (allowed): per-node diagnostics, the integration/network summary,
@@ -200,6 +210,14 @@ READ_ONLY_EXEMPT_TOOLS: dict[str, ReadOnlyExemption] = {
200
210
  "cluster-attribute read ('cluster_read'), and the Thread dataset "
201
211
  "listing ('list_datasets')",
202
212
  ),
213
+ # Update listing/details exist only here — ha_get_updates was merged
214
+ # into this tool (issue #1726), so hiding it would remove the read
215
+ # surface entirely.
216
+ "ha_manage_updates": ReadOnlyExemption(
217
+ _updates_write,
218
+ "listing pending updates (action='list', the default) and reading "
219
+ "update details/release notes (action='get')",
220
+ ),
203
221
  }
204
222
 
205
223
 
@@ -329,11 +329,19 @@ async def _poll_backup_completion(
329
329
  )
330
330
 
331
331
  if event_state == "failed":
332
+ # Surface the failure event verbatim — HA's failed event
333
+ # carries the cause (e.g. another backup already in
334
+ # progress), and dropping it left CI failures reading
335
+ # "Backup creation failed: Backup creation failed" with
336
+ # nothing to diagnose.
332
337
  raise_tool_error(
333
338
  create_error_response(
334
339
  ErrorCode.SERVICE_CALL_FAILED,
335
340
  "Backup creation failed",
336
- context={"backup_job_id": backup_job_id},
341
+ context={
342
+ "backup_job_id": backup_job_id,
343
+ "last_action_event": last_event,
344
+ },
337
345
  )
338
346
  )
339
347
 
@@ -410,7 +418,11 @@ async def _poll_backup_completion(
410
418
  create_error_response(
411
419
  ErrorCode.SERVICE_CALL_FAILED,
412
420
  "Backup creation failed (observed at post-timeout lookup)",
413
- context={"backup_job_id": backup_job_id, "name": name},
421
+ context={
422
+ "backup_job_id": backup_job_id,
423
+ "name": name,
424
+ "last_action_event": last_event,
425
+ },
414
426
  )
415
427
  )
416
428
  if state != "idle":
@@ -162,6 +162,28 @@ _TARGET_FIELDS = ("entity_id", "device_id", "area_id", "floor_id", "label_id")
162
162
  # ``service:`` (legacy) and ``action:`` (modern, 2024+) for the same field.
163
163
  _SERVICE_KEYS = ("service", "action")
164
164
 
165
+ # Purpose-specific trigger/condition keys renamed in HA 2026.7 — the old keys
166
+ # no longer load (home-assistant/core#174463).
167
+ _RENAMED_TRIGGER_KEYS = {
168
+ "battery.low": "battery.became_low",
169
+ "battery.not_low": "battery.no_longer_low",
170
+ "lawn_mower.docked": "lawn_mower.returned_to_dock",
171
+ "schedule.turned_on": "schedule.block_started",
172
+ "schedule.turned_off": "schedule.block_ended",
173
+ "timer.time_remaining": "timer.remaining_time_reached",
174
+ "update.update_became_available": "update.became_available",
175
+ "vacuum.docked": "vacuum.returned_to_dock",
176
+ }
177
+ _RENAMED_CONDITION_KEYS = {
178
+ "climate.target_temperature": "climate.is_target_temperature",
179
+ "climate.target_humidity": "climate.is_target_humidity",
180
+ }
181
+ # Trigger ``options.behavior`` values renamed in HA 2026.7: any→each,
182
+ # last→all (home-assistant/core#173259). The old values still load but raise
183
+ # an HA repair issue and face removal. Condition ``options.behavior`` keeps
184
+ # ``any``/``all`` — conditions are never flagged.
185
+ _DEPRECATED_TRIGGER_BEHAVIOR = {"any": "each", "last": "all"}
186
+
165
187
 
166
188
  # ---------------------------------------------------------------------------
167
189
  # Public API
@@ -318,6 +340,23 @@ def _check_condition_templates(
318
340
  # Shorthand template condition
319
341
  _check_template_string(cond, warnings, skill_prefix, "condition")
320
342
  elif isinstance(cond, dict):
343
+ # 2026.7 renamed purpose-specific condition keys — old keys no
344
+ # longer load.
345
+ condition_key = cond.get("condition")
346
+ renamed_condition = (
347
+ _RENAMED_CONDITION_KEYS.get(condition_key)
348
+ if isinstance(condition_key, str)
349
+ else None
350
+ )
351
+ if renamed_condition:
352
+ _emit(
353
+ warnings,
354
+ f"Condition key `{condition_key}` was renamed to "
355
+ f"`{renamed_condition}` in HA 2026.7 and the old key no "
356
+ f"longer loads — use `condition: {renamed_condition}`.",
357
+ skill_prefix,
358
+ "automation-patterns.md#native-conditions",
359
+ )
321
360
  if cond.get("condition") == "template":
322
361
  vt = cond.get("value_template", "")
323
362
  if isinstance(vt, str):
@@ -655,12 +694,44 @@ def _check_triggers(
655
694
 
656
695
  platform = trigger.get("platform", trigger.get("trigger", ""))
657
696
 
697
+ # 2026.7 renamed purpose-specific trigger keys — old keys no longer load.
698
+ renamed_trigger = (
699
+ _RENAMED_TRIGGER_KEYS.get(platform) if isinstance(platform, str) else None
700
+ )
701
+ if renamed_trigger:
702
+ _emit(
703
+ warnings,
704
+ f"Trigger key `{platform}` was renamed to `{renamed_trigger}` "
705
+ "in HA 2026.7 and the old key no longer loads — use "
706
+ f"`trigger: {renamed_trigger}`.",
707
+ skill_prefix,
708
+ "automation-patterns.md#trigger-types",
709
+ )
710
+
711
+ # 2026.7 renamed trigger `options.behavior` values (any→each, last→all).
712
+ options = trigger.get("options")
713
+ if isinstance(options, dict):
714
+ behavior = options.get("behavior")
715
+ if isinstance(behavior, str) and behavior in _DEPRECATED_TRIGGER_BEHAVIOR:
716
+ _emit(
717
+ warnings,
718
+ f"Trigger `options.behavior: {behavior}` was renamed to "
719
+ f"`{_DEPRECATED_TRIGGER_BEHAVIOR[behavior]}` in HA 2026.7 — "
720
+ "the old value still loads but raises a repair issue and "
721
+ "will be removed. Valid trigger values: `each`, `first`, "
722
+ "`all` (conditions keep `any`/`all`).",
723
+ skill_prefix,
724
+ "automation-patterns.md#trigger-types",
725
+ )
726
+
658
727
  # Device trigger → prefer entity_id-based triggers
659
728
  if platform == "device":
660
729
  _emit(
661
730
  warnings,
662
- "Trigger uses `device` platform with `device_id` — prefer "
663
- "`state` or `event` trigger with `entity_id` when possible "
731
+ "Trigger uses `device` platform with `device_id` — prefer a "
732
+ "purpose-specific trigger (`<domain>.<name>` with a `target:` "
733
+ "of entities/areas/floors/labels, HA 2026.7+) or a `state`/"
734
+ "`event` trigger with `entity_id` when possible "
664
735
  "(device_id breaks on re-add).",
665
736
  skill_prefix,
666
737
  "device-control.md#entity-id-vs-device-id",
@@ -440,6 +440,8 @@ class AutomationConfigTools:
440
440
  Field(
441
441
  description="Complete automation configuration with required fields: 'alias', 'triggers', 'actions'. "
442
442
  "Optional: 'description', 'conditions', 'mode', 'max', 'initial_state', 'variables'. "
443
+ "Purpose-specific triggers/conditions (HA 2026.7+ default: 'trigger': '<domain>.<name>' "
444
+ "with 'target'/'options') are valid config. "
443
445
  "Mutually exclusive with python_transform.",
444
446
  default=None,
445
447
  ),
@@ -712,6 +712,8 @@ def _populate_trigger_info(
712
712
  )
713
713
  if "entity_id" in trigger_vars:
714
714
  result["trigger"]["entity_id"] = trigger_vars["entity_id"]
715
+ if "error" in trigger_step:
716
+ result["trigger"]["error"] = trigger_step["error"]
715
717
 
716
718
  if "trigger" not in result and "trigger" in trace:
717
719
  result["trigger"] = {"description": trace["trigger"]}
@@ -731,6 +733,11 @@ def _populate_condition_results(
731
733
  }
732
734
  if "timestamp" in cond:
733
735
  cond_result["timestamp"] = cond["timestamp"]
736
+ # HA 2026.7+ always records template errors on the failing step
737
+ # (core #172917) — dropping this field would hide the reason a
738
+ # condition evaluated to None.
739
+ if "error" in cond:
740
+ cond_result["error"] = cond["error"]
734
741
  condition_results.append(cond_result)
735
742
  result["condition_results"] = condition_results
736
743