ha-mcp-dev 7.8.0.dev710__tar.gz → 7.8.0.dev711__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.
- {ha_mcp_dev-7.8.0.dev710/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.8.0.dev711}/PKG-INFO +1 -1
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/pyproject.toml +1 -1
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/backup_manager.py +108 -9
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/auto_backup.py +14 -11
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_entities.py +1 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_registry.py +3 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/LICENSE +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/README.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/setup.cfg +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/settings.css +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/settings.js +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/tests/test_env_manager.py +0 -0
|
@@ -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.
|
|
7
|
+
version = "7.8.0.dev711"
|
|
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"
|
|
@@ -991,19 +991,46 @@ async def _fetch_dashboard(client: Any, entity_id: str) -> Any:
|
|
|
991
991
|
"""
|
|
992
992
|
from fastmcp.exceptions import ToolError
|
|
993
993
|
|
|
994
|
-
from .tools.tools_config_dashboards import
|
|
994
|
+
from .tools.tools_config_dashboards import (
|
|
995
|
+
_get_dashboard_config_internal,
|
|
996
|
+
_resolve_dashboard,
|
|
997
|
+
)
|
|
998
|
+
|
|
999
|
+
# The set/delete tools accept BOTH the canonical hyphenated url_path
|
|
1000
|
+
# AND HA's internal (underscored) dashboard id, eagerly resolving the
|
|
1001
|
+
# latter before writing. ``_get_dashboard_config_internal`` does NOT
|
|
1002
|
+
# lazy-resolve, so an internal-id identifier 404s with "Unknown config
|
|
1003
|
+
# specified" and the pre-write snapshot is silently skipped. Pre-resolve
|
|
1004
|
+
# to the canonical url_path so capture works for whichever form the
|
|
1005
|
+
# caller passed (matching the form the write tool ultimately targets).
|
|
1006
|
+
fetch_path = entity_id
|
|
1007
|
+
try:
|
|
1008
|
+
match, _ = await _resolve_dashboard(client, entity_id)
|
|
1009
|
+
if match and match.get("url_path"):
|
|
1010
|
+
fetch_path = match["url_path"]
|
|
1011
|
+
except (HomeAssistantError, ToolError) as err:
|
|
1012
|
+
# Resolver failure (transport/shape) — fall through with the
|
|
1013
|
+
# original identifier; the canonical form is often already correct.
|
|
1014
|
+
logger.debug(
|
|
1015
|
+
"Auto-backup: dashboard resolve failed for %r: %s — using as-is",
|
|
1016
|
+
entity_id,
|
|
1017
|
+
err,
|
|
1018
|
+
)
|
|
995
1019
|
|
|
996
1020
|
try:
|
|
997
|
-
config, _config_hash = await _get_dashboard_config_internal(client,
|
|
1021
|
+
config, _config_hash = await _get_dashboard_config_internal(client, fetch_path)
|
|
998
1022
|
except ToolError as err:
|
|
999
|
-
# ToolError carries the structured failure payload; treat
|
|
1000
|
-
# missing
|
|
1023
|
+
# ToolError carries the structured failure payload; treat a
|
|
1024
|
+
# missing/unknown dashboard as "nothing to back up" (also covers a
|
|
1025
|
+
# brand-new dashboard on the create path). "Unknown config
|
|
1026
|
+
# specified" is HA's message for an unresolved url_path.
|
|
1001
1027
|
msg = str(err).lower()
|
|
1002
|
-
if "not_found" in msg or "config_not_found" in msg:
|
|
1028
|
+
if "not_found" in msg or "config_not_found" in msg or "unknown config" in msg:
|
|
1003
1029
|
return None
|
|
1004
1030
|
raise
|
|
1005
1031
|
except HomeAssistantError as err:
|
|
1006
|
-
|
|
1032
|
+
msg = str(err).lower()
|
|
1033
|
+
if "not_found" in msg or "config_not_found" in msg or "unknown config" in msg:
|
|
1007
1034
|
return None
|
|
1008
1035
|
raise
|
|
1009
1036
|
return config
|
|
@@ -1305,8 +1332,11 @@ async def _restore_area_or_floor(client: Any, entity_id: str, config: Any) -> An
|
|
|
1305
1332
|
|
|
1306
1333
|
|
|
1307
1334
|
async def _fetch_todo_item(client: Any, entity_id: str) -> Any:
|
|
1308
|
-
|
|
1309
|
-
|
|
1335
|
+
# The second segment is whatever the tool's ``item`` param carried.
|
|
1336
|
+
# ha_set_todo_item / ha_remove_todo_item accept EITHER the item uid OR
|
|
1337
|
+
# its exact summary/name, so this can be either form.
|
|
1338
|
+
cal, _, item_ref = entity_id.partition("::")
|
|
1339
|
+
if not cal or not item_ref:
|
|
1310
1340
|
return None
|
|
1311
1341
|
payload = {
|
|
1312
1342
|
"type": "execute_script",
|
|
@@ -1332,7 +1362,11 @@ async def _fetch_todo_item(client: Any, entity_id: str) -> Any:
|
|
|
1332
1362
|
result = _require_dict(result, "execute_script")
|
|
1333
1363
|
items = result.get("response", {}).get("items", {}).get(cal, {}).get("items", [])
|
|
1334
1364
|
for item in items:
|
|
1335
|
-
|
|
1365
|
+
# Match either form. Matching only on uid silently skipped the
|
|
1366
|
+
# snapshot whenever the caller passed the human-readable summary
|
|
1367
|
+
# (the documented/common case, e.g. ha_remove_todo_item(list, "Buy
|
|
1368
|
+
# milk")) — uid != summary, so the loop found nothing -> None.
|
|
1369
|
+
if item.get("uid") == item_ref or item.get("summary") == item_ref:
|
|
1336
1370
|
return {"todo_entity_id": cal, **item}
|
|
1337
1371
|
return None
|
|
1338
1372
|
|
|
@@ -1366,6 +1400,42 @@ async def _restore_entity_state(client: Any, entity_id: str, config: Any) -> Any
|
|
|
1366
1400
|
return await _rest_post(client, f"states/{entity_id}", payload)
|
|
1367
1401
|
|
|
1368
1402
|
|
|
1403
|
+
# Devices — config/device_registry/{list,update}. ``ha_set_device`` mutates
|
|
1404
|
+
# the user-editable registry fields (name_by_user / area_id / disabled_by /
|
|
1405
|
+
# labels); restore re-applies exactly those. A device deleted by
|
|
1406
|
+
# ``ha_remove_device`` cannot be recreated through the registry, so for that
|
|
1407
|
+
# path the snapshot is an informational pre-delete record and restore is
|
|
1408
|
+
# best-effort.
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
async def _fetch_device(client: Any, entity_id: str) -> Any:
|
|
1412
|
+
items = await _ws_send(client, {"type": "config/device_registry/list"})
|
|
1413
|
+
if not isinstance(items, list):
|
|
1414
|
+
return None
|
|
1415
|
+
for item in items:
|
|
1416
|
+
if item.get("id") == entity_id:
|
|
1417
|
+
return item
|
|
1418
|
+
return None
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
async def _restore_device(client: Any, entity_id: str, config: Any) -> Any:
|
|
1422
|
+
# Re-apply the captured registry state. Uses the same field NAMES as
|
|
1423
|
+
# ``_update_device_internal`` but, unlike that partial-update path, always
|
|
1424
|
+
# sends all four — restore reverts the device to the snapshot, so a
|
|
1425
|
+
# captured ``None`` area/name is intentionally re-applied (cleared).
|
|
1426
|
+
return await _ws_send(
|
|
1427
|
+
client,
|
|
1428
|
+
{
|
|
1429
|
+
"type": "config/device_registry/update",
|
|
1430
|
+
"device_id": entity_id,
|
|
1431
|
+
"name_by_user": config.get("name_by_user"),
|
|
1432
|
+
"area_id": config.get("area_id"),
|
|
1433
|
+
"disabled_by": config.get("disabled_by"),
|
|
1434
|
+
"labels": config.get("labels", []),
|
|
1435
|
+
},
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
|
|
1369
1439
|
# Integration enable/disable — restore re-applies the disabled flag.
|
|
1370
1440
|
|
|
1371
1441
|
|
|
@@ -1435,6 +1505,34 @@ async def _fetch_helper(client: Any, entity_id: str, helper_type: str) -> Any:
|
|
|
1435
1505
|
for item in items:
|
|
1436
1506
|
if item.get("id") == object_id or item.get("id") == entity_id:
|
|
1437
1507
|
return item
|
|
1508
|
+
# Fallback for renamed helpers: after an entity_id rename the object_id
|
|
1509
|
+
# no longer equals the storage collection id (which stays the original
|
|
1510
|
+
# create-time id == the registry unique_id), so the direct match above
|
|
1511
|
+
# misses and the snapshot was silently skipped. Resolve the unique_id
|
|
1512
|
+
# via the entity registry and match on that — the same key the helper
|
|
1513
|
+
# update tool itself resolves to.
|
|
1514
|
+
eid = entity_id if "." in entity_id else f"{helper_type}.{entity_id}"
|
|
1515
|
+
try:
|
|
1516
|
+
entry = await _ws_send(
|
|
1517
|
+
client, {"type": "config/entity_registry/get", "entity_id": eid}
|
|
1518
|
+
)
|
|
1519
|
+
except HomeAssistantError as err:
|
|
1520
|
+
# Only a genuine "entity not found" means there's nothing to back up;
|
|
1521
|
+
# transport/auth/5xx errors must propagate so maybe_snapshot logs a
|
|
1522
|
+
# WARNING rather than silently skipping. Same POLICY as _fetch_automation,
|
|
1523
|
+
# but matched on the message substring because config/entity_registry/get
|
|
1524
|
+
# failures arrive as a WS command error with no status_code to switch on.
|
|
1525
|
+
# Best-effort: if HA's not-found wording ever changes, a real miss
|
|
1526
|
+
# degrades to a WARNING + skip (never a swallowed fatal error).
|
|
1527
|
+
msg = str(err).lower()
|
|
1528
|
+
if "not_found" in msg or "not found" in msg:
|
|
1529
|
+
return None
|
|
1530
|
+
raise
|
|
1531
|
+
unique_id = entry.get("unique_id") if isinstance(entry, dict) else None
|
|
1532
|
+
if unique_id:
|
|
1533
|
+
for item in items:
|
|
1534
|
+
if str(item.get("id")) == str(unique_id):
|
|
1535
|
+
return item
|
|
1438
1536
|
return None
|
|
1439
1537
|
|
|
1440
1538
|
|
|
@@ -1505,6 +1603,7 @@ def register_default_handlers(mgr: BackupManager, _client: Any) -> None:
|
|
|
1505
1603
|
)
|
|
1506
1604
|
mgr.register(DomainHandler("todo_item", _fetch_todo_item, _restore_todo_item))
|
|
1507
1605
|
mgr.register(DomainHandler("entity", _fetch_entity_state, _restore_entity_state))
|
|
1606
|
+
mgr.register(DomainHandler("device", _fetch_device, _restore_device))
|
|
1508
1607
|
mgr.register(DomainHandler("integration", _fetch_integration, _restore_integration))
|
|
1509
1608
|
for helper_type in _KNOWN_HELPER_TYPES:
|
|
1510
1609
|
mgr.register(_make_helper_handler(helper_type))
|
|
@@ -75,17 +75,20 @@ def automation_backup_target(kw: dict[str, Any]) -> str:
|
|
|
75
75
|
config_id = config.get("id")
|
|
76
76
|
if config_id:
|
|
77
77
|
return str(config_id)
|
|
78
|
-
identifier
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
78
|
+
# Return the identifier UNCHANGED — do NOT strip the ``automation.``
|
|
79
|
+
# prefix. Capture and restore resolve the target through
|
|
80
|
+
# ``client.get_automation_config`` -> ``_resolve_automation_id``, which
|
|
81
|
+
# converts an entity_id ("automation.<slug>") to the real numeric
|
|
82
|
+
# ``unique_id`` via a state lookup ONLY when the prefix is present;
|
|
83
|
+
# otherwise it assumes the string already IS a unique_id. Stripping the
|
|
84
|
+
# prefix produced a bare object_id slug that the resolver mis-treats as
|
|
85
|
+
# a unique_id -> GET /config/automation/config/<slug> 404s -> the
|
|
86
|
+
# pre-write snapshot is silently skipped (and, had it resolved, restore
|
|
87
|
+
# would POST to the wrong key and create a stray automation). The
|
|
88
|
+
# doubled domain segment in the snapshot filename
|
|
89
|
+
# ("automation.automation.<slug>.<ts>.yaml") is purely cosmetic and is
|
|
90
|
+
# exactly what the remove path (id_param="identifier") already produces.
|
|
91
|
+
return _resolve_str(kw.get("identifier"))
|
|
89
92
|
|
|
90
93
|
|
|
91
94
|
def with_auto_backup(
|
|
@@ -1316,6 +1316,7 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
1316
1316
|
"title": "Remove Entity",
|
|
1317
1317
|
},
|
|
1318
1318
|
)
|
|
1319
|
+
@with_auto_backup(domain="entity", id_param="entity_id", client=client)
|
|
1319
1320
|
@log_tool_usage
|
|
1320
1321
|
async def ha_remove_entity(
|
|
1321
1322
|
entity_id: Annotated[
|
|
@@ -14,6 +14,7 @@ from pydantic import Field
|
|
|
14
14
|
|
|
15
15
|
from ..client.rest_client import HomeAssistantAPIError, HomeAssistantConnectionError
|
|
16
16
|
from ..errors import ErrorCode, create_error_response
|
|
17
|
+
from .auto_backup import with_auto_backup
|
|
17
18
|
from .helpers import (
|
|
18
19
|
exception_to_structured_error,
|
|
19
20
|
log_tool_usage,
|
|
@@ -599,6 +600,7 @@ def register_registry_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
599
600
|
tags={"Device Registry"},
|
|
600
601
|
annotations={"destructiveHint": True, "title": "Set Device"},
|
|
601
602
|
)
|
|
603
|
+
@with_auto_backup(domain="device", id_param="device_id", client=client)
|
|
602
604
|
@log_tool_usage
|
|
603
605
|
async def ha_set_device(
|
|
604
606
|
device_id: Annotated[
|
|
@@ -700,6 +702,7 @@ def register_registry_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
700
702
|
"title": "Remove Device",
|
|
701
703
|
},
|
|
702
704
|
)
|
|
705
|
+
@with_auto_backup(domain="device", id_param="device_id", client=client)
|
|
703
706
|
@log_tool_usage
|
|
704
707
|
async def ha_remove_device(
|
|
705
708
|
device_id: Annotated[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/dashboard_screenshot/provision.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/resources/skills-vendor/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/best_practice_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_entities.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_overview.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/smart_search/_scoring.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tool_search_hint_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_config_scripts.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_dashboard_screenshot.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/tools/validation_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/transforms/lite_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.8.0.dev710 → ha_mcp_dev-7.8.0.dev711}/src/ha_mcp_dev.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|