ha-mcp-dev 7.8.0.dev702__tar.gz → 7.8.0.dev703__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 (143) hide show
  1. {ha_mcp_dev-7.8.0.dev702/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.8.0.dev703}/PKG-INFO +3 -3
  2. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/README.md +2 -2
  3. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/pyproject.toml +3 -1
  4. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/read_only.py +6 -1
  5. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/settings.js +2 -2
  6. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/backup.py +121 -1
  7. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_filesystem.py +36 -15
  8. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703/src/ha_mcp_dev.egg-info}/PKG-INFO +3 -3
  9. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/LICENSE +0 -0
  10. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/MANIFEST.in +0 -0
  11. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/setup.cfg +0 -0
  12. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/__init__.py +0 -0
  13. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/__main__.py +0 -0
  14. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/_pypi_marker +0 -0
  15. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/_version.py +0 -0
  16. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/auth/__init__.py +0 -0
  17. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/auth/consent_form.py +0 -0
  18. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/auth/provider.py +0 -0
  19. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/backup_manager.py +0 -0
  20. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/client/__init__.py +0 -0
  21. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/client/rest_client.py +0 -0
  22. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/client/supervisor_client.py +0 -0
  23. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/client/websocket_client.py +0 -0
  24. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/client/websocket_listener.py +0 -0
  25. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/config.py +0 -0
  26. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  27. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  28. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  29. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/errors.py +0 -0
  30. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/__init__.py +0 -0
  31. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/approval_queue.py +0 -0
  32. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/evaluator.py +0 -0
  33. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/handlers.py +0 -0
  34. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/middleware.py +0 -0
  35. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/model.py +0 -0
  36. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/persistence.py +0 -0
  37. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/policy/value_sources.py +0 -0
  38. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/py.typed +0 -0
  39. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  40. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  41. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  42. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  43. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  44. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  45. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  46. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  47. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  48. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  49. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  50. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  51. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  52. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  53. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  54. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  55. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  56. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  57. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  58. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  59. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  60. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  61. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/server.py +0 -0
  62. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/settings.css +0 -0
  63. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/settings_ui.py +0 -0
  64. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/smoke_test.py +0 -0
  65. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  66. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/__init__.py +0 -0
  67. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/auto_backup.py +0 -0
  68. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  69. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  70. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/device_control.py +0 -0
  71. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/enhanced.py +0 -0
  72. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/helpers.py +0 -0
  73. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/reference_validator.py +0 -0
  74. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/registry.py +0 -0
  75. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  76. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  77. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  78. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  79. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  80. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  81. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  82. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  83. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  84. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  85. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_addons.py +0 -0
  86. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_areas.py +0 -0
  87. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  88. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  89. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_calendar.py +0 -0
  90. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_camera.py +0 -0
  91. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_categories.py +0 -0
  92. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_code.py +0 -0
  93. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  94. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  95. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  96. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  97. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  98. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  99. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_energy.py +0 -0
  100. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_entities.py +0 -0
  101. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_groups.py +0 -0
  102. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_hacs.py +0 -0
  103. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_history.py +0 -0
  104. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_integrations.py +0 -0
  105. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_labels.py +0 -0
  106. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  107. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_registry.py +0 -0
  108. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_resources.py +0 -0
  109. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_search.py +0 -0
  110. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_service.py +0 -0
  111. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_services.py +0 -0
  112. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_system.py +0 -0
  113. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_themes.py +0 -0
  114. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_todo.py +0 -0
  115. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_traces.py +0 -0
  116. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_updates.py +0 -0
  117. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_utility.py +0 -0
  118. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  119. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  120. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/tools_zones.py +0 -0
  121. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/util_helpers.py +0 -0
  122. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/tools/validation_middleware.py +0 -0
  123. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/transforms/__init__.py +0 -0
  124. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/transforms/categorized_search.py +0 -0
  125. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  126. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/__init__.py +0 -0
  127. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/config_hash.py +0 -0
  128. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/data_paths.py +0 -0
  129. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/domain_handlers.py +0 -0
  130. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  131. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  132. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/operation_manager.py +0 -0
  133. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/python_sandbox.py +0 -0
  134. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/skill_loader.py +0 -0
  135. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp/utils/usage_logger.py +0 -0
  136. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  137. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  138. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  139. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  140. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  141. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/tests/__init__.py +0 -0
  142. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/tests/test_constants.py +0 -0
  143. {ha_mcp_dev-7.8.0.dev702 → ha_mcp_dev-7.8.0.dev703}/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.8.0.dev702
3
+ Version: 7.8.0.dev703
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
@@ -275,8 +275,8 @@ Some tools require a companion custom component installed in Home Assistant. Sta
275
275
  | Tool | Description |
276
276
  |------|-------------|
277
277
  | `ha_config_set_yaml` *(beta)* | Safely add, replace, or remove top-level YAML keys in `configuration.yaml` and package files (automatic backup, validation, and config check) |
278
- | `ha_list_files` *(beta)* | List files in allowed directories (www/, themes/, custom_templates/) |
279
- | `ha_read_file` *(beta)* | Read files from allowed paths (config YAML, logs, www/, themes/, custom_templates/, custom_components/) |
278
+ | `ha_list_files` *(beta)* | List files in allowed directories |
279
+ | `ha_read_file` *(beta)* | Read files from allowed paths (config YAML, logs, and allowed directories) |
280
280
  | `ha_write_file` *(beta)* | Write files to allowed directories |
281
281
  | `ha_delete_file` *(beta)* | Delete files from allowed directories |
282
282
 
@@ -245,8 +245,8 @@ Some tools require a companion custom component installed in Home Assistant. Sta
245
245
  | Tool | Description |
246
246
  |------|-------------|
247
247
  | `ha_config_set_yaml` *(beta)* | Safely add, replace, or remove top-level YAML keys in `configuration.yaml` and package files (automatic backup, validation, and config check) |
248
- | `ha_list_files` *(beta)* | List files in allowed directories (www/, themes/, custom_templates/) |
249
- | `ha_read_file` *(beta)* | Read files from allowed paths (config YAML, logs, www/, themes/, custom_templates/, custom_components/) |
248
+ | `ha_list_files` *(beta)* | List files in allowed directories |
249
+ | `ha_read_file` *(beta)* | Read files from allowed paths (config YAML, logs, and allowed directories) |
250
250
  | `ha_write_file` *(beta)* | Write files to allowed directories |
251
251
  | `ha_delete_file` *(beta)* | Delete files from allowed directories |
252
252
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.8.0.dev702"
7
+ version = "7.8.0.dev703"
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"
@@ -85,6 +85,8 @@ ignore_missing_imports = true
85
85
  [[tool.mypy.overrides]]
86
86
  module = [
87
87
  "homeassistant.*",
88
+ "aiohasupervisor",
89
+ "aiohasupervisor.*",
88
90
  "aiohttp",
89
91
  "voluptuous",
90
92
  "jsonschema",
@@ -66,8 +66,12 @@ class ReadOnlyExemption(NamedTuple):
66
66
  def _backup_write(args: dict[str, Any]) -> str | None:
67
67
  scope = args.get("scope")
68
68
  action = args.get("action")
69
+ # Read-only-safe: per-edit backup listing/viewing, and snapshot listing
70
+ # (issue #1586 — pure ``backup/info`` read, no tarball mutation).
69
71
  if scope == "edits" and action in ("list", "view"):
70
72
  return None
73
+ if scope == "snapshot" and action == "list":
74
+ return None
71
75
  return f"scope={scope!r}, action={action!r}"
72
76
 
73
77
 
@@ -144,7 +148,8 @@ def _custom_tool_write(args: dict[str, Any]) -> str | None:
144
148
  READ_ONLY_EXEMPT_TOOLS: dict[str, ReadOnlyExemption] = {
145
149
  "ha_manage_backup": ReadOnlyExemption(
146
150
  _backup_write,
147
- "listing and viewing per-edit backups (scope='edits', action='list' or 'view')",
151
+ "listing and viewing per-edit backups (scope='edits', action='list' or "
152
+ "'view') and listing snapshots (scope='snapshot', action='list')",
148
153
  ),
149
154
  "ha_manage_addon": ReadOnlyExemption(
150
155
  _addon_write,
@@ -1030,8 +1030,8 @@ function renderFsCustomPathsSubForm(parentEl, masterOn, fsOn) {
1030
1030
  : '.storage, secrets.yaml';
1031
1031
  info.innerHTML =
1032
1032
  `<div class="feature-name">Custom filesystem directories (advanced)</div>` +
1033
- `<div class="feature-help">Extra directories (one per line, relative to your config dir) that the file tools may READ and WRITE — e.g. <code>pyscript</code>, <code>python_scripts</code>. Each entry grants both read and write. Applies immediately; no restart needed.</div>` +
1034
- `<div class="feature-help">Always blocked (cannot be added): <code>${escapeHtml(denyList)}</code>, path traversal (<code>..</code>), and absolute paths.</div>`;
1033
+ `<div class="feature-help">Extra directories (one per line) that the file tools may READ and WRITE — either relative to your config dir (e.g. <code>pyscript</code>, <code>python_scripts</code>) or an absolute HAOS sibling volume <code>/share</code>, <code>/media</code>, <code>/ssl</code>, <code>/backup</code> (or a subdirectory of one). Each entry grants both read and write. Applies immediately; no restart needed.</div>` +
1034
+ `<div class="feature-help">Always blocked (cannot be added): <code>${escapeHtml(denyList)}</code>, path traversal (<code>..</code>), and any absolute path outside the HAOS sibling volumes.</div>`;
1035
1035
 
1036
1036
  const control = document.createElement('div');
1037
1037
  control.className = 'feature-control';
@@ -731,10 +731,126 @@ async def restore_backup(
731
731
  return None # py/mixed-returns: explicit terminal; error handlers above always raise (NoReturn), unreachable
732
732
 
733
733
 
734
+ def _summarize_backup(entry: dict[str, Any]) -> dict[str, Any]:
735
+ """Project one HA ``backup/info`` entry to the fields a caller needs to
736
+ identify and choose a snapshot (issue #1586).
737
+
738
+ Size is reported per backup agent; we surface the largest reported size
739
+ across agents. Every field is ``.get`` so a schema the running HA version
740
+ doesn't populate yields ``None`` rather than raising.
741
+ """
742
+ agents = entry.get("agents") or {}
743
+ size_bytes: int | None = None
744
+ if isinstance(agents, dict):
745
+ sizes: list[int] = []
746
+ for a in agents.values():
747
+ if isinstance(a, dict):
748
+ size = a.get("size")
749
+ # Accept int or float (some agents report byte counts as float);
750
+ # bool is an int subclass but never a real size, so exclude it.
751
+ if isinstance(size, (int, float)) and not isinstance(size, bool):
752
+ sizes.append(int(size))
753
+ if sizes:
754
+ size_bytes = max(sizes)
755
+ return {
756
+ "backup_id": entry.get("backup_id"),
757
+ "name": entry.get("name"),
758
+ "date": entry.get("date"),
759
+ "size_bytes": size_bytes,
760
+ "protected": entry.get("protected"),
761
+ "database_included": entry.get("database_included"),
762
+ "homeassistant_included": entry.get("homeassistant_included"),
763
+ "homeassistant_version": entry.get("homeassistant_version"),
764
+ "with_automatic_settings": entry.get("with_automatic_settings"),
765
+ "agent_ids": list(agents.keys()) if isinstance(agents, dict) else [],
766
+ }
767
+
768
+
769
+ async def list_backups(client: HomeAssistantClient, limit: int = 200) -> dict[str, Any]:
770
+ """List the full HA snapshot tarballs known to Home Assistant (issue #1586).
771
+
772
+ Surfaces the inventory HA already returns from its WebSocket ``backup/info``
773
+ command — the same data ``restore_backup`` uses internally to verify a
774
+ ``backup_id`` exists. Before this, the snapshot scope exposed only
775
+ ``create`` and ``restore``, so a caller had no way to discover backup IDs or
776
+ confirm a specific backup landed; they had to already know the ID. Newest
777
+ first. Read-only: no safety backup, no restart.
778
+ """
779
+ ws_client = None
780
+ try:
781
+ ws_client, error = await get_connected_ws_client(
782
+ client.base_url, client.token, verify_ssl=client.verify_ssl
783
+ )
784
+ if error:
785
+ raise_tool_error(
786
+ error
787
+ or create_error_response(
788
+ ErrorCode.CONNECTION_FAILED,
789
+ "Failed to connect to Home Assistant WebSocket to list backups",
790
+ )
791
+ )
792
+ ws_client = cast(HomeAssistantWebSocketClient, ws_client)
793
+
794
+ info = await ws_client.send_command("backup/info")
795
+ if not info.get("success"):
796
+ raise_tool_error(
797
+ create_error_response(
798
+ ErrorCode.SERVICE_CALL_FAILED,
799
+ info.get("error", "Failed to retrieve backup information"),
800
+ )
801
+ )
802
+
803
+ result_block = info.get("result") or {}
804
+ raw_backups = result_block.get("backups") or []
805
+ summarized = [_summarize_backup(b) for b in raw_backups]
806
+ # Newest first so "did my backup land?" is answered by the top entry.
807
+ # Parse via _parse_backup_date (handles `Z`/naive) rather than sorting
808
+ # the raw strings lexicographically — `'Z'` > `'+'` would misorder a mix
809
+ # of `...Z` and `...+00:00`. Undated entries sink to the bottom.
810
+ _date_floor = datetime.min.replace(tzinfo=UTC)
811
+ summarized.sort(
812
+ key=lambda b: _parse_backup_date(b.get("date")) or _date_floor,
813
+ reverse=True,
814
+ )
815
+ total = len(summarized)
816
+ if limit and total > limit:
817
+ summarized = summarized[:limit]
818
+ return {
819
+ "success": True,
820
+ "count": len(summarized),
821
+ "total": total,
822
+ "backups": summarized,
823
+ }
824
+
825
+ except ToolError:
826
+ raise
827
+ except Exception as e:
828
+ logger.error(f"Error listing backups: {e}")
829
+ exception_to_structured_error(
830
+ e,
831
+ context={"tool": "list_backups"},
832
+ suggestions=["Check Home Assistant connection and the backup integration"],
833
+ )
834
+ return None # unreachable: exception_to_structured_error always raises
835
+ finally:
836
+ # Always disconnect WebSocket — narrow to transport errors; a
837
+ # programming error during cleanup should still surface.
838
+ if ws_client:
839
+ try:
840
+ await ws_client.disconnect()
841
+ except (TimeoutError, OSError, ConnectionError) as err:
842
+ logger.debug(
843
+ "ws disconnect (cleanup) transport error: %s: %s",
844
+ type(err).__name__,
845
+ err,
846
+ )
847
+
848
+
734
849
  # Valid (scope, action) combinations. Anything outside this set is
735
850
  # rejected with a structured VALIDATION_INVALID_PARAMETER error.
736
851
  _VALID_COMBOS: set[tuple[str, str]] = {
737
852
  ("snapshot", "create"),
853
+ ("snapshot", "list"),
738
854
  ("snapshot", "restore"),
739
855
  ("edits", "create"),
740
856
  ("edits", "list"),
@@ -799,6 +915,7 @@ def register_backup_tools(
799
915
  | scope | action | What it does |
800
916
  |---|---|---|
801
917
  | `snapshot` | `create` | Create a full HA tarball (config + addons, no DB by default). Heavy, seconds-long. |
918
+ | `snapshot` | `list` | List full HA tarball snapshots (id, name, date, size). Read-only — use to discover a `backup_id` or confirm a backup landed. |
802
919
  | `snapshot` | `restore` | Restore a full HA tarball. **Restarts HA.** Last-resort recovery. |
803
920
  | `edits` | `create` | On-demand snapshot of one entity (`domain` + `entity_id` required). Use before the user manually edits in the HA UI. Same handler path the decorator takes on writes; bypasses the `enable_auto_backup` toggle. |
804
921
  | `edits` | `list` | List per-entity auto-backups (lightweight). Filter by `domain` and/or `entity_id`. |
@@ -817,6 +934,7 @@ def register_backup_tools(
817
934
 
818
935
  **Examples:**
819
936
  - Snapshot before risky op: `ha_manage_backup(scope="snapshot", action="create", name="Before_Big_Change")`
937
+ - List snapshots (to discover a backup_id or confirm one landed): `ha_manage_backup(scope="snapshot", action="list")`
820
938
  - Restore full snapshot: `ha_manage_backup(scope="snapshot", action="restore", backup_id="dd7550ed")`
821
939
  - On-demand entity snapshot before a manual UI edit: `ha_manage_backup(scope="edits", action="create", domain="helper_input_boolean", entity_id="kitchen_lights_active")`
822
940
  - List recent auto-backups for one automation: `ha_manage_backup(scope="edits", action="list", domain="automation", entity_id="kitchen_lights")`
@@ -906,7 +1024,7 @@ def register_backup_tools(
906
1024
  default=200,
907
1025
  ge=1,
908
1026
  le=10_000,
909
- description="(edits.list) Maximum number of entries to return.",
1027
+ description="(edits.list / snapshot.list) Maximum number of entries to return.",
910
1028
  ),
911
1029
  ] = 200,
912
1030
  ) -> dict[str, Any]:
@@ -916,6 +1034,8 @@ def register_backup_tools(
916
1034
  if scope == "snapshot":
917
1035
  if action == "create":
918
1036
  return await create_backup(client, name)
1037
+ if action == "list":
1038
+ return await list_backups(client, limit)
919
1039
  # action == "restore"
920
1040
  bid = _require("backup_id", backup_id, scope, action)
921
1041
  return await restore_backup(client, bid, restore_database)
@@ -57,7 +57,11 @@ CALLER_TOKEN_BOOTSTRAP_SERVICE = "get_caller_token"
57
57
  # ``themes/*.yaml`` yaml_path scope; a <0.8.0 component reaches the old
58
58
  # handler and rejects ``themes/<name>.yaml`` with a misleading "not
59
59
  # allowed" message instead of this actionable update prompt.
60
- MIN_COMPONENT_VERSION = "0.8.0"
60
+ # 0.9.0: the file tools accept absolute HAOS sibling-volume paths (/share,
61
+ # /media, /ssl, /backup — issue #1586). A <0.9.0 component's allowlist
62
+ # normalizer rejects every absolute path, so adding a volume would silently
63
+ # do nothing; the version gate surfaces an actionable "update" prompt instead.
64
+ MIN_COMPONENT_VERSION = "0.9.0"
61
65
 
62
66
 
63
67
  def _version_tuple(version: str) -> tuple[int, ...]:
@@ -333,9 +337,12 @@ class FilesystemTools:
333
337
  str,
334
338
  Field(
335
339
  description=(
336
- "Relative directory path from config directory. "
337
- "Allowed paths: www/, themes/, custom_templates/, dashboards/. "
338
- "Example: 'www/' or 'themes/my_theme'"
340
+ "Directory path. Relative to the config dir for the built-in "
341
+ "allowlist (www/, themes/, custom_templates/, dashboards/). "
342
+ "Custom directories and HAOS sibling volumes "
343
+ "(/share, /media, /ssl, /backup) configured in the ha-mcp "
344
+ "settings UI are also allowed (pass the absolute path). "
345
+ "Example: 'www/' or '/share/llm'"
339
346
  ),
340
347
  ),
341
348
  ],
@@ -360,7 +367,9 @@ class FilesystemTools:
360
367
  - `themes/` - Theme files
361
368
  - `custom_templates/` - Jinja2 template files
362
369
  - `dashboards/` - YAML-mode dashboard files
363
- - Plus any custom directories configured in the ha-mcp settings UI
370
+ - Plus any custom directories OR HAOS sibling volumes (`/share`,
371
+ `/media`, `/ssl`, `/backup`) configured in the ha-mcp settings UI
372
+ (pass the absolute path for volumes)
364
373
 
365
374
  **Security:** Only directories in the allowed list can be accessed.
366
375
  Path traversal attempts (../) are blocked.
@@ -435,8 +444,10 @@ class FilesystemTools:
435
444
  str,
436
445
  Field(
437
446
  description=(
438
- "Relative path from config directory. "
439
- "Examples: 'configuration.yaml', 'www/custom.css', 'home-assistant.log'"
447
+ "File path. Relative to the config dir for the built-in "
448
+ "allowlist; absolute for a configured HAOS sibling volume "
449
+ "(/share, /media, /ssl, /backup). Examples: "
450
+ "'configuration.yaml', 'www/custom.css', '/share/llm/notes.md'"
440
451
  ),
441
452
  ),
442
453
  ],
@@ -468,7 +479,9 @@ class FilesystemTools:
468
479
  - `home-assistant.log` (tail only)
469
480
  - `www/**`, `themes/**`, `custom_templates/**`, `dashboards/**`
470
481
  - `custom_components/**/*.py` (read-only)
471
- - Plus any custom directories configured in the ha-mcp settings UI
482
+ - Plus any custom directories OR HAOS sibling volumes (`/share`,
483
+ `/media`, `/ssl`, `/backup`) configured in the ha-mcp settings UI
484
+ (pass the absolute path for volumes)
472
485
 
473
486
  **Security:**
474
487
  - Path traversal (../) is blocked
@@ -546,9 +559,11 @@ class FilesystemTools:
546
559
  str,
547
560
  Field(
548
561
  description=(
549
- "Relative path from config directory. "
550
- "Must be in www/, themes/, custom_templates/, or dashboards/. "
551
- "Example: 'www/custom.css', 'themes/my_theme.yaml'"
562
+ "File path. Must be in a writable built-in dir (www/, "
563
+ "themes/, custom_templates/, dashboards/), a configured "
564
+ "custom directory, or a configured HAOS sibling volume "
565
+ "(/share, /media, /ssl, /backup — pass the absolute path). "
566
+ "Example: 'www/custom.css', '/share/llm/out.txt'"
552
567
  ),
553
568
  ),
554
569
  ],
@@ -590,7 +605,9 @@ class FilesystemTools:
590
605
  - `themes/` - Theme YAML files
591
606
  - `custom_templates/` - Jinja2 template files
592
607
  - `dashboards/` - YAML-mode dashboard files
593
- - Plus any custom directories configured in the ha-mcp settings UI
608
+ - Plus any custom directories OR HAOS sibling volumes (`/share`,
609
+ `/media`, `/ssl`, `/backup`) configured in the ha-mcp settings UI
610
+ (pass the absolute path for volumes)
594
611
 
595
612
  **Security:**
596
613
  - Only the directories above allow writes
@@ -678,8 +695,10 @@ class FilesystemTools:
678
695
  str,
679
696
  Field(
680
697
  description=(
681
- "Relative path from config directory. "
682
- "Must be in www/, themes/, custom_templates/, or dashboards/. "
698
+ "File path. Must be in a writable built-in dir (www/, "
699
+ "themes/, custom_templates/, dashboards/), a configured "
700
+ "custom directory, or a configured HAOS sibling volume "
701
+ "(/share, /media, /ssl, /backup — pass the absolute path). "
683
702
  "Example: 'www/old-file.css'"
684
703
  ),
685
704
  ),
@@ -705,7 +724,9 @@ class FilesystemTools:
705
724
  - `themes/` - Theme files
706
725
  - `custom_templates/` - Template files
707
726
  - `dashboards/` - YAML-mode dashboard files
708
- - Plus any custom directories configured in the ha-mcp settings UI
727
+ - Plus any custom directories OR HAOS sibling volumes (`/share`,
728
+ `/media`, `/ssl`, `/backup`) configured in the ha-mcp settings UI
729
+ (pass the absolute path for volumes)
709
730
 
710
731
  **Security:**
711
732
  - Only the directories above allow deletions
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.8.0.dev702
3
+ Version: 7.8.0.dev703
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
@@ -275,8 +275,8 @@ Some tools require a companion custom component installed in Home Assistant. Sta
275
275
  | Tool | Description |
276
276
  |------|-------------|
277
277
  | `ha_config_set_yaml` *(beta)* | Safely add, replace, or remove top-level YAML keys in `configuration.yaml` and package files (automatic backup, validation, and config check) |
278
- | `ha_list_files` *(beta)* | List files in allowed directories (www/, themes/, custom_templates/) |
279
- | `ha_read_file` *(beta)* | Read files from allowed paths (config YAML, logs, www/, themes/, custom_templates/, custom_components/) |
278
+ | `ha_list_files` *(beta)* | List files in allowed directories |
279
+ | `ha_read_file` *(beta)* | Read files from allowed paths (config YAML, logs, and allowed directories) |
280
280
  | `ha_write_file` *(beta)* | Write files to allowed directories |
281
281
  | `ha_delete_file` *(beta)* | Delete files from allowed directories |
282
282