ha-mcp-dev 7.6.0.dev644__tar.gz → 7.6.0.dev645__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.6.0.dev644/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.6.0.dev645}/PKG-INFO +1 -1
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/pyproject.toml +1 -1
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_system.py +125 -57
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/LICENSE +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/README.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/setup.cfg +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/settings.css +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/settings.js +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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.6.0.
|
|
7
|
+
version = "7.6.0.dev645"
|
|
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"
|
|
@@ -60,51 +60,6 @@ class SystemTools:
|
|
|
60
60
|
def __init__(self, client: Any) -> None:
|
|
61
61
|
self._client = client
|
|
62
62
|
|
|
63
|
-
@tool(
|
|
64
|
-
name="ha_check_config",
|
|
65
|
-
tags={"System"},
|
|
66
|
-
annotations={
|
|
67
|
-
"idempotentHint": True,
|
|
68
|
-
"readOnlyHint": True,
|
|
69
|
-
"title": "Check Configuration",
|
|
70
|
-
},
|
|
71
|
-
)
|
|
72
|
-
@log_tool_usage
|
|
73
|
-
async def ha_check_config(self) -> dict[str, Any]:
|
|
74
|
-
"""
|
|
75
|
-
Check Home Assistant configuration for errors.
|
|
76
|
-
|
|
77
|
-
Validates configuration files without applying changes.
|
|
78
|
-
Always run this before ha_restart() to ensure configuration is valid.
|
|
79
|
-
"""
|
|
80
|
-
try:
|
|
81
|
-
config_result = await self._client.check_config()
|
|
82
|
-
|
|
83
|
-
# The API returns {"result": "valid"} or {"result": "invalid", "errors": [...]}
|
|
84
|
-
is_valid = config_result.get("result") == "valid"
|
|
85
|
-
errors = config_result.get("errors") or [] # Handle None case
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
"success": True,
|
|
89
|
-
"result": "valid" if is_valid else "invalid",
|
|
90
|
-
"is_valid": is_valid,
|
|
91
|
-
"errors": errors,
|
|
92
|
-
"message": (
|
|
93
|
-
"Configuration is valid"
|
|
94
|
-
if is_valid
|
|
95
|
-
else f"Configuration has {len(errors)} error(s)"
|
|
96
|
-
),
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
except Exception as e:
|
|
100
|
-
exception_to_structured_error(
|
|
101
|
-
e,
|
|
102
|
-
suggestions=[
|
|
103
|
-
"Ensure Home Assistant is running and accessible",
|
|
104
|
-
"Check your connection settings",
|
|
105
|
-
],
|
|
106
|
-
)
|
|
107
|
-
|
|
108
63
|
@tool(
|
|
109
64
|
name="ha_restart",
|
|
110
65
|
tags={"System"},
|
|
@@ -127,15 +82,16 @@ class SystemTools:
|
|
|
127
82
|
measure to prevent accidental restarts.
|
|
128
83
|
|
|
129
84
|
**Best Practices:**
|
|
130
|
-
1.
|
|
85
|
+
1. Config is validated automatically before the restart proceeds; to
|
|
86
|
+
pre-check, call ha_get_system_health(include="config_check")
|
|
131
87
|
2. Notify users before restarting (if applicable)
|
|
132
88
|
3. Schedule restarts during low-activity periods
|
|
133
89
|
|
|
134
90
|
**Example Usage:**
|
|
135
91
|
```python
|
|
136
|
-
#
|
|
137
|
-
|
|
138
|
-
if
|
|
92
|
+
# Optional pre-check (ha_restart also validates config automatically)
|
|
93
|
+
health = ha_get_system_health(include="config_check")
|
|
94
|
+
if health["config_check"]["is_valid"]:
|
|
139
95
|
# Restart with confirmation
|
|
140
96
|
result = ha_restart(confirm=True)
|
|
141
97
|
```
|
|
@@ -153,7 +109,7 @@ class SystemTools:
|
|
|
153
109
|
"This is a safety measure to prevent accidental restarts."
|
|
154
110
|
),
|
|
155
111
|
suggestions=[
|
|
156
|
-
|
|
112
|
+
'Pre-check config via ha_get_system_health(include="config_check")',
|
|
157
113
|
"Call ha_restart(confirm=True) to proceed with restart",
|
|
158
114
|
"Consider using ha_reload_core() for config-only changes",
|
|
159
115
|
],
|
|
@@ -391,7 +347,10 @@ class SystemTools:
|
|
|
391
347
|
be large (Hue ~290 KB, ZHA/MQTT/ESPHome several MB) — pair with
|
|
392
348
|
``diagnostics_fields`` or ``diagnostics_truncate_at_bytes`` to fit the LLM
|
|
393
349
|
context budget.
|
|
394
|
-
-
|
|
350
|
+
- "config_check": Validate HA configuration via POST /config/core/check_config
|
|
351
|
+
(the pre-restart safety check; ha_restart runs it automatically). Returns
|
|
352
|
+
{result: valid|invalid, is_valid, errors}; read-only/idempotent, takes no args.
|
|
353
|
+
- Example: include="repairs,zha_network,zwave_network,config_check"
|
|
395
354
|
- Example: include="diagnostics", config_entry_id="abc123..."
|
|
396
355
|
- include_dismissed_repairs: Include user-dismissed/ignored repairs (default: False). Only meaningful when "repairs" is in `include`.
|
|
397
356
|
- config_entry_id: Required when ``include`` contains ``diagnostics``. The config
|
|
@@ -430,10 +389,47 @@ class SystemTools:
|
|
|
430
389
|
includes = self._parse_includes(include)
|
|
431
390
|
include_dismissed_repairs_bool = bool(include_dismissed_repairs)
|
|
432
391
|
|
|
392
|
+
# Sections that require the system_health WebSocket connection; the
|
|
393
|
+
# REST-based sections (config_check, diagnostics) do not.
|
|
394
|
+
ws_backed = {"repairs", "zha_network", "zha_network_full", "zwave_network"}
|
|
395
|
+
|
|
433
396
|
ws_client = None
|
|
434
397
|
|
|
435
398
|
try:
|
|
436
|
-
|
|
399
|
+
try:
|
|
400
|
+
ws_client, result = await self._fetch_health_info()
|
|
401
|
+
except ToolError as health_err:
|
|
402
|
+
# The system_health/info baseline (WebSocket) is unavailable.
|
|
403
|
+
# Only ``await self._fetch_health_info()`` runs in this inner
|
|
404
|
+
# try, and it raises ToolError solely for baseline-unavailable
|
|
405
|
+
# conditions (connect failure / timeout / WS error), so this
|
|
406
|
+
# catch cannot swallow an unrelated ToolError.
|
|
407
|
+
#
|
|
408
|
+
# Degrade gracefully ONLY when the caller asked for a REST-based
|
|
409
|
+
# section (config_check / diagnostics) that can still be served
|
|
410
|
+
# without the WebSocket. config_check is the pure-REST
|
|
411
|
+
# replacement for the removed ha_check_config tool, so it must
|
|
412
|
+
# not depend on the health WebSocket (the system_health/info
|
|
413
|
+
# command carries its own 10s timeout and can hang/be absent on
|
|
414
|
+
# some installs). If the caller asked for nothing (the health
|
|
415
|
+
# baseline itself) or only WS-backed sections, the baseline WAS
|
|
416
|
+
# the deliverable: re-raise so the failure surfaces as
|
|
417
|
+
# isError=true, exactly as before this change.
|
|
418
|
+
if not (includes & {"config_check", "diagnostics"}):
|
|
419
|
+
raise
|
|
420
|
+
logger.warning("system_health baseline unavailable: %s", health_err)
|
|
421
|
+
ws_client = None
|
|
422
|
+
result = {
|
|
423
|
+
"success": True,
|
|
424
|
+
"baseline_available": False,
|
|
425
|
+
"health_info": {},
|
|
426
|
+
"component_count": 0,
|
|
427
|
+
"message": "System health baseline unavailable.",
|
|
428
|
+
"warnings": [
|
|
429
|
+
"system_health baseline unavailable; "
|
|
430
|
+
"returning REST-based sections only."
|
|
431
|
+
],
|
|
432
|
+
}
|
|
437
433
|
|
|
438
434
|
# Warn about unrecognized include values
|
|
439
435
|
VALID_INCLUDES = {
|
|
@@ -442,6 +438,7 @@ class SystemTools:
|
|
|
442
438
|
"zha_network_full",
|
|
443
439
|
"zwave_network",
|
|
444
440
|
"diagnostics",
|
|
441
|
+
"config_check",
|
|
445
442
|
}
|
|
446
443
|
unknown = includes - VALID_INCLUDES
|
|
447
444
|
if unknown:
|
|
@@ -464,6 +461,27 @@ class SystemTools:
|
|
|
464
461
|
want_zha = zha_full or zha_summary
|
|
465
462
|
want_zwave = "zwave_network" in includes
|
|
466
463
|
|
|
464
|
+
if ws_client is None:
|
|
465
|
+
# Health WebSocket unavailable: WS-backed sections can't run.
|
|
466
|
+
# Give each requested WS-backed section a machine-readable error
|
|
467
|
+
# sub-dict under its own key (same shape the section carries when
|
|
468
|
+
# the baseline is up but the fetch fails), plus a summary
|
|
469
|
+
# warning, then skip them so the REST sections below still run.
|
|
470
|
+
ws_error = "requires the system_health WebSocket, which is unavailable"
|
|
471
|
+
if want_repairs:
|
|
472
|
+
result["repairs"] = {"error": ws_error}
|
|
473
|
+
if want_zha:
|
|
474
|
+
result["zha_network"] = {"error": ws_error}
|
|
475
|
+
if want_zwave:
|
|
476
|
+
result["zwave_network"] = {"error": ws_error}
|
|
477
|
+
unavailable = sorted(includes & ws_backed)
|
|
478
|
+
if unavailable:
|
|
479
|
+
result.setdefault("warnings", []).append(
|
|
480
|
+
"These sections require the system_health WebSocket, "
|
|
481
|
+
f"which is unavailable: {', '.join(unavailable)}"
|
|
482
|
+
)
|
|
483
|
+
want_repairs = want_zha = want_zwave = False
|
|
484
|
+
|
|
467
485
|
sections: list[tuple[str, Coroutine[Any, Any, dict[str, Any]]]] = []
|
|
468
486
|
if want_repairs:
|
|
469
487
|
sections.append(
|
|
@@ -593,6 +611,14 @@ class SystemTools:
|
|
|
593
611
|
"in include"
|
|
594
612
|
)
|
|
595
613
|
|
|
614
|
+
if "config_check" in includes:
|
|
615
|
+
# REST call on self._client (POST /config/core/check_config),
|
|
616
|
+
# not a ws_client command — so it runs inline like diagnostics
|
|
617
|
+
# rather than in the ws ``sections`` gather above. Standalone
|
|
618
|
+
# ``if`` (not chained to diagnostics) so both can be requested
|
|
619
|
+
# in one call.
|
|
620
|
+
result["config_check"] = await self._fetch_config_check()
|
|
621
|
+
|
|
596
622
|
return result
|
|
597
623
|
|
|
598
624
|
except ToolError:
|
|
@@ -606,11 +632,7 @@ class SystemTools:
|
|
|
606
632
|
],
|
|
607
633
|
)
|
|
608
634
|
finally:
|
|
609
|
-
|
|
610
|
-
try:
|
|
611
|
-
await ws_client.disconnect()
|
|
612
|
-
except Exception:
|
|
613
|
-
pass
|
|
635
|
+
await self._safe_disconnect(ws_client)
|
|
614
636
|
|
|
615
637
|
@staticmethod
|
|
616
638
|
def _parse_includes(include: str | None) -> set[str]:
|
|
@@ -619,6 +641,16 @@ class SystemTools:
|
|
|
619
641
|
return set()
|
|
620
642
|
return {s.strip().lower() for s in include.split(",") if s.strip()}
|
|
621
643
|
|
|
644
|
+
@staticmethod
|
|
645
|
+
async def _safe_disconnect(ws_client: Any) -> None:
|
|
646
|
+
"""Best-effort WebSocket disconnect; never raises."""
|
|
647
|
+
if ws_client is None:
|
|
648
|
+
return
|
|
649
|
+
try:
|
|
650
|
+
await ws_client.disconnect()
|
|
651
|
+
except Exception:
|
|
652
|
+
pass
|
|
653
|
+
|
|
622
654
|
async def _fetch_health_info(self) -> tuple[Any, dict[str, Any]]:
|
|
623
655
|
"""Connect to WebSocket and retrieve system health info.
|
|
624
656
|
|
|
@@ -645,6 +677,9 @@ class SystemTools:
|
|
|
645
677
|
"system_health/info", wait_timeout=10.0
|
|
646
678
|
)
|
|
647
679
|
except TimeoutError:
|
|
680
|
+
# The connection opened but the command stalled — disconnect it
|
|
681
|
+
# before raising so we don't leak the socket.
|
|
682
|
+
await self._safe_disconnect(ws_client)
|
|
648
683
|
raise_tool_error(
|
|
649
684
|
create_error_response(
|
|
650
685
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
@@ -652,6 +687,7 @@ class SystemTools:
|
|
|
652
687
|
)
|
|
653
688
|
)
|
|
654
689
|
except Exception as e:
|
|
690
|
+
await self._safe_disconnect(ws_client)
|
|
655
691
|
raise_tool_error(
|
|
656
692
|
create_error_response(
|
|
657
693
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
@@ -818,6 +854,38 @@ class SystemTools:
|
|
|
818
854
|
)
|
|
819
855
|
return zwave_network
|
|
820
856
|
|
|
857
|
+
async def _fetch_config_check(self) -> dict[str, Any]:
|
|
858
|
+
"""Validate HA configuration via POST /config/core/check_config.
|
|
859
|
+
|
|
860
|
+
Returns an embeddable sub-dict (matching the ``_fetch_repairs`` /
|
|
861
|
+
``_fetch_zha_network`` convention): baseline keys always present, with
|
|
862
|
+
an ``error`` field on backend failure. Never raises, so a config-check
|
|
863
|
+
failure surfaces as ``result["config_check"]["error"]`` without sinking
|
|
864
|
+
the rest of ha_get_system_health. Instance method (not @staticmethod)
|
|
865
|
+
because it calls the REST client (``self._client``), like the
|
|
866
|
+
diagnostics path.
|
|
867
|
+
"""
|
|
868
|
+
config_check: dict[str, Any] = {
|
|
869
|
+
"result": "unknown",
|
|
870
|
+
"is_valid": False,
|
|
871
|
+
"errors": [],
|
|
872
|
+
}
|
|
873
|
+
try:
|
|
874
|
+
config_result = await self._client.check_config()
|
|
875
|
+
# The API returns {"result": "valid"} or
|
|
876
|
+
# {"result": "invalid", "errors": [...]}.
|
|
877
|
+
is_valid = config_result.get("result") == "valid"
|
|
878
|
+
errors = config_result.get("errors") or [] # Handle None case
|
|
879
|
+
config_check = {
|
|
880
|
+
"result": "valid" if is_valid else "invalid",
|
|
881
|
+
"is_valid": is_valid,
|
|
882
|
+
"errors": errors,
|
|
883
|
+
}
|
|
884
|
+
except Exception as e:
|
|
885
|
+
logger.warning("Failed to check config: %s", e)
|
|
886
|
+
config_check["error"] = f"Config check not available: {e}"
|
|
887
|
+
return config_check
|
|
888
|
+
|
|
821
889
|
|
|
822
890
|
def register_system_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
823
891
|
"""Register Home Assistant system management tools."""
|
|
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
|
|
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.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_entities.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_overview.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/smart_search/_scoring.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.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/tools_config_scripts.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.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/tools/validation_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.6.0.dev644 → ha_mcp_dev-7.6.0.dev645}/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
|