ha-mcp-dev 7.5.0.dev516__tar.gz → 7.5.0.dev518__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.5.0.dev516/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.5.0.dev518}/PKG-INFO +1 -1
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/pyproject.toml +1 -1
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_helpers.py +287 -94
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/LICENSE +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/README.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/setup.cfg +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/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.5.0.
|
|
7
|
+
version = "7.5.0.dev518"
|
|
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"
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
@@ -867,6 +867,69 @@ def _validate_numeric_range(
|
|
|
867
867
|
)
|
|
868
868
|
|
|
869
869
|
|
|
870
|
+
def _validate_initial_in_options(
|
|
871
|
+
options: Any, initial: Any, helper_type: str = "input_select"
|
|
872
|
+
) -> None:
|
|
873
|
+
"""Reject ``initial`` values not in ``options``.
|
|
874
|
+
|
|
875
|
+
Called from both create and update branches with the resolved values —
|
|
876
|
+
caller-supplied on create, merged with the existing config on update.
|
|
877
|
+
``initial=None`` is the unset case and passes through. The
|
|
878
|
+
``isinstance(options, list)`` early-return mirrors the defensive shape
|
|
879
|
+
check in ``_validate_input_select_options`` below — both validators are
|
|
880
|
+
invariant gates, not type contracts; a future non-list caller is
|
|
881
|
+
silently skipped rather than raising a confusing ``TypeError`` on
|
|
882
|
+
``initial not in options``.
|
|
883
|
+
"""
|
|
884
|
+
if not isinstance(options, list) or initial is None:
|
|
885
|
+
return
|
|
886
|
+
if initial not in options:
|
|
887
|
+
raise_tool_error(
|
|
888
|
+
create_error_response(
|
|
889
|
+
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
890
|
+
f"initial={initial!r} must be one of options "
|
|
891
|
+
f"{options!r} for {helper_type}.",
|
|
892
|
+
context=_simple_helper_error_context(
|
|
893
|
+
helper_type,
|
|
894
|
+
initial=initial,
|
|
895
|
+
options=options,
|
|
896
|
+
),
|
|
897
|
+
suggestions=[
|
|
898
|
+
"Pick an `initial` value that's in `options`.",
|
|
899
|
+
"Or omit `initial` to use the default or existing value.",
|
|
900
|
+
],
|
|
901
|
+
)
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def _validate_datetime_has_date_or_time(
|
|
906
|
+
has_date: bool | None, has_time: bool | None
|
|
907
|
+
) -> None:
|
|
908
|
+
"""Reject ``input_datetime`` payloads where both components are False.
|
|
909
|
+
|
|
910
|
+
Treats ``None`` as "not constrained" — only the explicit (False, False)
|
|
911
|
+
case is flagged, since that's what reaches HA as the broken-entity
|
|
912
|
+
payload. Both the create and update branches call this with the
|
|
913
|
+
resolved-after-merge ``has_date`` / ``has_time`` pair.
|
|
914
|
+
"""
|
|
915
|
+
if has_date is False and has_time is False:
|
|
916
|
+
raise_tool_error(
|
|
917
|
+
create_error_response(
|
|
918
|
+
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
919
|
+
"At least one of has_date or has_time must be True for input_datetime",
|
|
920
|
+
context=_simple_helper_error_context(
|
|
921
|
+
"input_datetime",
|
|
922
|
+
has_date=has_date,
|
|
923
|
+
has_time=has_time,
|
|
924
|
+
),
|
|
925
|
+
suggestions=[
|
|
926
|
+
"Set has_date=True to keep the date component.",
|
|
927
|
+
"Set has_time=True to keep the time component.",
|
|
928
|
+
],
|
|
929
|
+
)
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
|
|
870
933
|
def _validate_input_select_options(options: Any) -> None:
|
|
871
934
|
"""Reject input_select option lists containing duplicates (Bug 17, issue #1150).
|
|
872
935
|
|
|
@@ -1409,6 +1472,69 @@ async def _apply_registry_updates_to_entity(
|
|
|
1409
1472
|
return applied
|
|
1410
1473
|
|
|
1411
1474
|
|
|
1475
|
+
class HelperResponse(TypedDict, total=False):
|
|
1476
|
+
"""Uniform response contract for ``ha_config_set_helper`` (issue #1293).
|
|
1477
|
+
|
|
1478
|
+
Documents the legal key set across all three branches (create, update,
|
|
1479
|
+
flow). ``total=False`` because per-branch fields (entity_id, flow extras,
|
|
1480
|
+
warnings) are conditional. Consumed by ``_helper_response`` below — all
|
|
1481
|
+
return literals in this module funnel through that builder so the shape
|
|
1482
|
+
has a single point of construction.
|
|
1483
|
+
"""
|
|
1484
|
+
|
|
1485
|
+
success: bool
|
|
1486
|
+
action: str # "create" | "update"
|
|
1487
|
+
helper_type: str
|
|
1488
|
+
data: dict[str, Any]
|
|
1489
|
+
entity_id: str # absent on flow branch (use entity_ids[] for multi-entity)
|
|
1490
|
+
message: str | None
|
|
1491
|
+
warnings: list[str] # omitted when empty
|
|
1492
|
+
# Flow-helper convenience accessors (only set on the flow branch).
|
|
1493
|
+
method: str
|
|
1494
|
+
entry_id: str | None
|
|
1495
|
+
title: str | None
|
|
1496
|
+
updated: bool
|
|
1497
|
+
entity_ids: list[str]
|
|
1498
|
+
area_id: str | None
|
|
1499
|
+
labels: list[str]
|
|
1500
|
+
category: str
|
|
1501
|
+
applied: list[dict[str, Any]]
|
|
1502
|
+
|
|
1503
|
+
|
|
1504
|
+
def _helper_response(
|
|
1505
|
+
action: str,
|
|
1506
|
+
helper_type: str,
|
|
1507
|
+
*,
|
|
1508
|
+
data: dict[str, Any],
|
|
1509
|
+
entity_id: str | None = None,
|
|
1510
|
+
message: str | None = None,
|
|
1511
|
+
warnings: list[str] | None = None,
|
|
1512
|
+
**extras: Any,
|
|
1513
|
+
) -> dict[str, Any]:
|
|
1514
|
+
"""Single construction point for the ``ha_config_set_helper`` response.
|
|
1515
|
+
|
|
1516
|
+
Enforces the uniform shape from issue #1293: ``success`` → ``action`` →
|
|
1517
|
+
``helper_type`` → ``data`` → ``entity_id`` (when present) → ``message`` →
|
|
1518
|
+
flow-helper extras → ``warnings`` (only when non-empty). Returning
|
|
1519
|
+
``dict[str, Any]`` rather than ``HelperResponse`` keeps the call sites
|
|
1520
|
+
free of mypy gymnastics around the dynamic ``**extras`` keys; the
|
|
1521
|
+
TypedDict serves as the readable contract anchor instead.
|
|
1522
|
+
"""
|
|
1523
|
+
resp: dict[str, Any] = {
|
|
1524
|
+
"success": True,
|
|
1525
|
+
"action": action,
|
|
1526
|
+
"helper_type": helper_type,
|
|
1527
|
+
"data": data,
|
|
1528
|
+
}
|
|
1529
|
+
if entity_id is not None:
|
|
1530
|
+
resp["entity_id"] = entity_id
|
|
1531
|
+
resp["message"] = message
|
|
1532
|
+
resp.update(extras)
|
|
1533
|
+
if warnings:
|
|
1534
|
+
resp["warnings"] = warnings
|
|
1535
|
+
return resp
|
|
1536
|
+
|
|
1537
|
+
|
|
1412
1538
|
async def _handle_flow_helper(
|
|
1413
1539
|
client: Any,
|
|
1414
1540
|
helper_type: str,
|
|
@@ -1562,18 +1688,15 @@ async def _handle_flow_helper(
|
|
|
1562
1688
|
helper_id, # type: ignore[arg-type]
|
|
1563
1689
|
)
|
|
1564
1690
|
|
|
1691
|
+
# Cache the flow_result keys read multiple times below (issue #1293
|
|
1692
|
+
# follow-up: reduces three .get() lookups for entry_id and two for title
|
|
1693
|
+
# to one each, and makes the post-flow logic readable as a sequence of
|
|
1694
|
+
# named values rather than repeated dict access). ``.get()`` is kept —
|
|
1695
|
+
# ``create_flow_helper`` propagates HA's optional entry_id via ``.get()``
|
|
1696
|
+
# too (tools_config_entry_flow.py:L700), so a missing key must surface as
|
|
1697
|
+
# None for the ``if entry_id:`` guard below, not raise KeyError.
|
|
1565
1698
|
entry_id = flow_result.get("entry_id")
|
|
1566
|
-
|
|
1567
|
-
"success": True,
|
|
1568
|
-
"action": action,
|
|
1569
|
-
"helper_type": helper_type,
|
|
1570
|
-
"method": "config_flow",
|
|
1571
|
-
"entry_id": entry_id,
|
|
1572
|
-
"title": flow_result.get("title"),
|
|
1573
|
-
"message": flow_result.get("message"),
|
|
1574
|
-
}
|
|
1575
|
-
if action == "update":
|
|
1576
|
-
result["updated"] = True
|
|
1699
|
+
title = flow_result.get("title")
|
|
1577
1700
|
|
|
1578
1701
|
# Resolve all entities for this config entry (multi-entity helpers handled naturally).
|
|
1579
1702
|
# For create with wait=True, poll briefly for at least one entity to appear —
|
|
@@ -1617,7 +1740,22 @@ async def _handle_flow_helper(
|
|
|
1617
1740
|
else:
|
|
1618
1741
|
entities = await _get_entities_for_config_entry(client, entry_id, warnings)
|
|
1619
1742
|
entity_ids = [e["entity_id"] for e in entities if e.get("entity_id")]
|
|
1620
|
-
|
|
1743
|
+
|
|
1744
|
+
# ``data`` mirrors the HA flow_result payload for cross-action uniformity
|
|
1745
|
+
# with the create/update branches (issue #1293). ``entry_id`` and ``title``
|
|
1746
|
+
# also stay flat as convenience accessors — they are the primary identifiers
|
|
1747
|
+
# callers reach for, and remain heavily used by per-action metadata
|
|
1748
|
+
# consumers throughout the codebase. Per-entity registry-write outcomes
|
|
1749
|
+
# live in the ``applied`` flat array, not nested in ``data``, because one
|
|
1750
|
+
# flow can yield N entities with different per-entity results.
|
|
1751
|
+
extras: dict[str, Any] = {
|
|
1752
|
+
"method": "config_flow",
|
|
1753
|
+
"entry_id": entry_id,
|
|
1754
|
+
"title": title,
|
|
1755
|
+
"entity_ids": entity_ids,
|
|
1756
|
+
}
|
|
1757
|
+
if action == "update":
|
|
1758
|
+
extras["updated"] = True
|
|
1621
1759
|
|
|
1622
1760
|
# Apply registry updates (area_id / labels / category) to every entity.
|
|
1623
1761
|
# Use `is not None` so an explicit empty value (area_id="" or labels=[])
|
|
@@ -1640,17 +1778,21 @@ async def _handle_flow_helper(
|
|
|
1640
1778
|
)
|
|
1641
1779
|
)
|
|
1642
1780
|
if area_id is not None:
|
|
1643
|
-
|
|
1781
|
+
extras["area_id"] = area_id if area_id else None
|
|
1644
1782
|
if labels_list is not None:
|
|
1645
|
-
|
|
1783
|
+
extras["labels"] = labels_list
|
|
1646
1784
|
if category:
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1785
|
+
extras["category"] = category
|
|
1786
|
+
extras["applied"] = applied_per_entity
|
|
1787
|
+
|
|
1788
|
+
return _helper_response(
|
|
1789
|
+
action,
|
|
1790
|
+
helper_type,
|
|
1791
|
+
data={"entry_id": entry_id, "title": title},
|
|
1792
|
+
message=flow_result.get("message"),
|
|
1793
|
+
warnings=warnings,
|
|
1794
|
+
**extras,
|
|
1795
|
+
)
|
|
1654
1796
|
|
|
1655
1797
|
|
|
1656
1798
|
def _format_schedule_days(
|
|
@@ -2398,28 +2540,12 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2398
2540
|
)
|
|
2399
2541
|
)
|
|
2400
2542
|
message["options"] = options
|
|
2401
|
-
#
|
|
2402
|
-
#
|
|
2403
|
-
#
|
|
2404
|
-
#
|
|
2543
|
+
# If `initial` was passed but isn't one of the options,
|
|
2544
|
+
# reject explicitly instead of silently dropping. Shared
|
|
2545
|
+
# with the update branch via the helper so the same
|
|
2546
|
+
# invariant fires on both code paths.
|
|
2547
|
+
_validate_initial_in_options(options, initial)
|
|
2405
2548
|
if initial is not None:
|
|
2406
|
-
if initial not in options:
|
|
2407
|
-
raise_tool_error(
|
|
2408
|
-
create_error_response(
|
|
2409
|
-
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
2410
|
-
f"initial={initial!r} must be one of options "
|
|
2411
|
-
f"{options!r} for input_select.",
|
|
2412
|
-
context=_simple_helper_error_context(
|
|
2413
|
-
helper_type,
|
|
2414
|
-
initial=initial,
|
|
2415
|
-
options=options,
|
|
2416
|
-
),
|
|
2417
|
-
suggestions=[
|
|
2418
|
-
"Pick an `initial` value that's in `options`.",
|
|
2419
|
-
"Or omit `initial` so the entity starts unset.",
|
|
2420
|
-
],
|
|
2421
|
-
)
|
|
2422
|
-
)
|
|
2423
2549
|
message["initial"] = initial
|
|
2424
2550
|
|
|
2425
2551
|
elif helper_type == "input_number":
|
|
@@ -2477,15 +2603,12 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2477
2603
|
message["has_date"] = has_date
|
|
2478
2604
|
message["has_time"] = has_time
|
|
2479
2605
|
|
|
2480
|
-
# Validate that at least one is True
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
context=_simple_helper_error_context(helper_type),
|
|
2487
|
-
)
|
|
2488
|
-
)
|
|
2606
|
+
# Validate that at least one is True — shared with the
|
|
2607
|
+
# update branch via the helper so the same invariant
|
|
2608
|
+
# fires on both code paths.
|
|
2609
|
+
_validate_datetime_has_date_or_time(
|
|
2610
|
+
message["has_date"], message["has_time"]
|
|
2611
|
+
)
|
|
2489
2612
|
|
|
2490
2613
|
if initial is not None:
|
|
2491
2614
|
message["initial"] = initial
|
|
@@ -2616,6 +2739,12 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2616
2739
|
if not entity_id and helper_data.get("id"):
|
|
2617
2740
|
entity_id = f"{helper_type}.{helper_data['id']}"
|
|
2618
2741
|
|
|
2742
|
+
# Issue #1293: collect warnings in a top-level list rather
|
|
2743
|
+
# than nest them in the payload dict. Aligns this branch
|
|
2744
|
+
# with the flow-helper path and lets callers do
|
|
2745
|
+
# ``result.get("warnings", [])`` uniformly.
|
|
2746
|
+
warnings: list[str] = []
|
|
2747
|
+
|
|
2619
2748
|
# Wait for entity to be properly registered before proceeding
|
|
2620
2749
|
wait_bool = coerce_bool_param(wait, "wait", default=True)
|
|
2621
2750
|
if wait_bool and entity_id:
|
|
@@ -2624,11 +2753,11 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2624
2753
|
client, entity_id
|
|
2625
2754
|
)
|
|
2626
2755
|
if not registered:
|
|
2627
|
-
|
|
2756
|
+
warnings.append(
|
|
2628
2757
|
f"Helper created but {entity_id} not yet queryable. It may take a moment to become available."
|
|
2629
2758
|
)
|
|
2630
2759
|
except Exception as e:
|
|
2631
|
-
|
|
2760
|
+
warnings.append(
|
|
2632
2761
|
f"Helper created but verification failed: {e}"
|
|
2633
2762
|
)
|
|
2634
2763
|
|
|
@@ -2647,6 +2776,11 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2647
2776
|
update_message
|
|
2648
2777
|
)
|
|
2649
2778
|
if update_result.get("success"):
|
|
2779
|
+
# Mirror the update branch's icon propagation
|
|
2780
|
+
# (line ~3343) so the create response's ``data``
|
|
2781
|
+
# carries the same registry-write echo set.
|
|
2782
|
+
if icon is not None:
|
|
2783
|
+
helper_data["icon"] = icon if icon else None
|
|
2650
2784
|
if area_id is not None:
|
|
2651
2785
|
helper_data["area_id"] = area_id if area_id else None
|
|
2652
2786
|
if labels is not None:
|
|
@@ -2658,29 +2792,39 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2658
2792
|
if isinstance(error_detail, dict)
|
|
2659
2793
|
else str(error_detail)
|
|
2660
2794
|
)
|
|
2661
|
-
|
|
2795
|
+
warnings.append(
|
|
2662
2796
|
f"Helper created but entity registry update failed: {error_msg}"
|
|
2663
2797
|
)
|
|
2664
2798
|
|
|
2665
|
-
# Apply category via shared helper (consistent with automations/scripts)
|
|
2799
|
+
# Apply category via shared helper (consistent with automations/scripts).
|
|
2800
|
+
# Issue #1293: route the success/failure through ``cat_result`` so any
|
|
2801
|
+
# ``category_warning`` lands in the top-level ``warnings`` list instead
|
|
2802
|
+
# of leaking nested into ``helper_data``. Mirrors the precedent in
|
|
2803
|
+
# ``_handle_flow_helper`` (the ``cat_result`` block near the end of
|
|
2804
|
+
# ``_apply_registry_updates_to_entity``).
|
|
2666
2805
|
if category and entity_id:
|
|
2806
|
+
cat_result: dict[str, Any] = {}
|
|
2667
2807
|
await apply_entity_category(
|
|
2668
2808
|
client,
|
|
2669
2809
|
entity_id,
|
|
2670
2810
|
category,
|
|
2671
2811
|
"helpers",
|
|
2672
|
-
|
|
2812
|
+
cat_result,
|
|
2673
2813
|
"helper",
|
|
2674
2814
|
)
|
|
2815
|
+
if "category" in cat_result:
|
|
2816
|
+
helper_data["category"] = cat_result["category"]
|
|
2817
|
+
elif "category_warning" in cat_result:
|
|
2818
|
+
warnings.append(cat_result["category_warning"])
|
|
2675
2819
|
|
|
2676
|
-
return
|
|
2677
|
-
"
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
"
|
|
2682
|
-
|
|
2683
|
-
|
|
2820
|
+
return _helper_response(
|
|
2821
|
+
"create",
|
|
2822
|
+
helper_type,
|
|
2823
|
+
data=helper_data,
|
|
2824
|
+
entity_id=entity_id,
|
|
2825
|
+
message=f"Successfully created {helper_type}: {name}",
|
|
2826
|
+
warnings=warnings,
|
|
2827
|
+
)
|
|
2684
2828
|
else:
|
|
2685
2829
|
raise_tool_error(
|
|
2686
2830
|
create_error_response(
|
|
@@ -2728,6 +2872,11 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2728
2872
|
}
|
|
2729
2873
|
|
|
2730
2874
|
updated_data: dict[str, Any] = {}
|
|
2875
|
+
# Issue #1293: collect warnings in a top-level list for the
|
|
2876
|
+
# update path too, mirroring create + flow-helper branches.
|
|
2877
|
+
# (No re-annotation — the create branch above already defined
|
|
2878
|
+
# ``warnings: list[str]``; mypy treats this as the same binding.)
|
|
2879
|
+
warnings = []
|
|
2731
2880
|
|
|
2732
2881
|
if helper_type == "tag":
|
|
2733
2882
|
# Tags use their own registry — no entity registry entries.
|
|
@@ -2762,14 +2911,19 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
2762
2911
|
|
|
2763
2912
|
# Tags don't have entity registry entries, so return directly
|
|
2764
2913
|
# without wait_for_entity_registered (they're not entities).
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
"
|
|
2772
|
-
|
|
2914
|
+
# Issue #1293: same uniform builder as the sibling create/update
|
|
2915
|
+
# branches. No producer appends to ``warnings`` on the tag path
|
|
2916
|
+
# today, but ``_helper_response`` already omits the key when the
|
|
2917
|
+
# list is empty — future warnings flow through the same contract
|
|
2918
|
+
# without further plumbing.
|
|
2919
|
+
return _helper_response(
|
|
2920
|
+
"update",
|
|
2921
|
+
helper_type,
|
|
2922
|
+
data=updated_data,
|
|
2923
|
+
entity_id=entity_id,
|
|
2924
|
+
message=f"Successfully updated {helper_type}: {entity_id}",
|
|
2925
|
+
warnings=warnings,
|
|
2926
|
+
)
|
|
2773
2927
|
|
|
2774
2928
|
elif helper_type in config_store_types:
|
|
2775
2929
|
# Person and zone: look up unique_id from entity registry
|
|
@@ -3048,6 +3202,14 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
3048
3202
|
if initial is not None
|
|
3049
3203
|
else existing.get("initial")
|
|
3050
3204
|
)
|
|
3205
|
+
# Parity with the create-branch guard. Resolves to
|
|
3206
|
+
# (new options, new initial) / (new options, old
|
|
3207
|
+
# initial) / (old options, new initial) — any
|
|
3208
|
+
# combination that excludes initial from the final
|
|
3209
|
+
# options list is caught.
|
|
3210
|
+
_validate_initial_in_options(
|
|
3211
|
+
update_msg["options"], initial_val
|
|
3212
|
+
)
|
|
3051
3213
|
if initial_val is not None:
|
|
3052
3214
|
update_msg["initial"] = initial_val
|
|
3053
3215
|
|
|
@@ -3140,6 +3302,14 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
3140
3302
|
if has_time is not None
|
|
3141
3303
|
else existing.get("has_time", False)
|
|
3142
3304
|
)
|
|
3305
|
+
# Parity with the create-branch guard. A merge
|
|
3306
|
+
# that resolves to (False, False) — caller
|
|
3307
|
+
# disabling the one component the existing entity
|
|
3308
|
+
# had — would otherwise write a broken-entity
|
|
3309
|
+
# payload and surface HA's cryptic generic error.
|
|
3310
|
+
_validate_datetime_has_date_or_time(
|
|
3311
|
+
update_msg["has_date"], update_msg["has_time"]
|
|
3312
|
+
)
|
|
3143
3313
|
initial_val = (
|
|
3144
3314
|
initial
|
|
3145
3315
|
if initial is not None
|
|
@@ -3230,30 +3400,49 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
3230
3400
|
reg_result = await client.send_websocket_message(
|
|
3231
3401
|
registry_update
|
|
3232
3402
|
)
|
|
3233
|
-
if
|
|
3403
|
+
if reg_result.get("success"):
|
|
3404
|
+
# Issue #1293: mirror the create branch by propagating the
|
|
3405
|
+
# registry writes into ``updated_data`` so the response's
|
|
3406
|
+
# ``data`` reflects the post-update state.
|
|
3407
|
+
if icon is not None:
|
|
3408
|
+
updated_data["icon"] = icon if icon else None
|
|
3409
|
+
if area_id is not None:
|
|
3410
|
+
updated_data["area_id"] = area_id if area_id else None
|
|
3411
|
+
if labels is not None:
|
|
3412
|
+
updated_data["labels"] = labels
|
|
3413
|
+
else:
|
|
3234
3414
|
error_detail = reg_result.get("error", {})
|
|
3235
3415
|
error_msg = (
|
|
3236
3416
|
error_detail.get("message", "Unknown error")
|
|
3237
3417
|
if isinstance(error_detail, dict)
|
|
3238
3418
|
else str(error_detail)
|
|
3239
3419
|
)
|
|
3240
|
-
logger.warning
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3420
|
+
# No ``logger.warning`` here — the create-branch and
|
|
3421
|
+
# flow-helper registry-update failure paths surface this
|
|
3422
|
+
# via ``warnings.append`` only, and the response carries
|
|
3423
|
+
# the message to the caller in the top-level ``warnings``
|
|
3424
|
+
# list. Logging again would double-report.
|
|
3425
|
+
warnings.append(
|
|
3244
3426
|
f"Config updated but entity registry update failed: {error_msg}"
|
|
3245
3427
|
)
|
|
3246
3428
|
|
|
3247
|
-
# Apply category via shared helper
|
|
3429
|
+
# Apply category via shared helper. Issue #1293: route through
|
|
3430
|
+
# ``cat_result`` so any ``category_warning`` lands in the top-level
|
|
3431
|
+
# ``warnings`` list instead of nested in ``updated_data``.
|
|
3248
3432
|
if category:
|
|
3433
|
+
cat_result = {}
|
|
3249
3434
|
await apply_entity_category(
|
|
3250
3435
|
client,
|
|
3251
3436
|
entity_id,
|
|
3252
3437
|
category,
|
|
3253
3438
|
"helpers",
|
|
3254
|
-
|
|
3439
|
+
cat_result,
|
|
3255
3440
|
"helper",
|
|
3256
3441
|
)
|
|
3442
|
+
if "category" in cat_result:
|
|
3443
|
+
updated_data["category"] = cat_result["category"]
|
|
3444
|
+
elif "category_warning" in cat_result:
|
|
3445
|
+
warnings.append(cat_result["category_warning"])
|
|
3257
3446
|
|
|
3258
3447
|
else:
|
|
3259
3448
|
# Fallback for unknown/future helper types: entity registry update only
|
|
@@ -3287,39 +3476,43 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
3287
3476
|
)
|
|
3288
3477
|
)
|
|
3289
3478
|
|
|
3290
|
-
# Apply category via shared helper
|
|
3479
|
+
# Apply category via shared helper. Issue #1293: same temp-dict
|
|
3480
|
+
# routing as the simple-helper branch above.
|
|
3291
3481
|
if category:
|
|
3482
|
+
cat_result = {}
|
|
3292
3483
|
await apply_entity_category(
|
|
3293
3484
|
client,
|
|
3294
3485
|
entity_id,
|
|
3295
3486
|
category,
|
|
3296
3487
|
"helpers",
|
|
3297
|
-
|
|
3488
|
+
cat_result,
|
|
3298
3489
|
"helper",
|
|
3299
3490
|
)
|
|
3491
|
+
if "category" in cat_result:
|
|
3492
|
+
updated_data["category"] = cat_result["category"]
|
|
3493
|
+
elif "category_warning" in cat_result:
|
|
3494
|
+
warnings.append(cat_result["category_warning"])
|
|
3300
3495
|
|
|
3301
3496
|
# Wait for entity to reflect the update
|
|
3302
3497
|
wait_bool = coerce_bool_param(wait, "wait", default=True)
|
|
3303
|
-
response: dict[str, Any] = {
|
|
3304
|
-
"success": True,
|
|
3305
|
-
"action": "update",
|
|
3306
|
-
"helper_type": helper_type,
|
|
3307
|
-
"entity_id": entity_id,
|
|
3308
|
-
"updated_data": updated_data,
|
|
3309
|
-
"message": f"Successfully updated {helper_type}: {entity_id}",
|
|
3310
|
-
}
|
|
3311
3498
|
if wait_bool:
|
|
3312
3499
|
try:
|
|
3313
3500
|
registered = await wait_for_entity_registered(client, entity_id)
|
|
3314
3501
|
if not registered:
|
|
3315
|
-
|
|
3502
|
+
warnings.append(
|
|
3316
3503
|
f"Update applied but {entity_id} not yet queryable."
|
|
3317
3504
|
)
|
|
3318
3505
|
except Exception as e:
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3506
|
+
warnings.append(f"Update applied but verification failed: {e}")
|
|
3507
|
+
|
|
3508
|
+
return _helper_response(
|
|
3509
|
+
"update",
|
|
3510
|
+
helper_type,
|
|
3511
|
+
data=updated_data,
|
|
3512
|
+
entity_id=entity_id,
|
|
3513
|
+
message=f"Successfully updated {helper_type}: {entity_id}",
|
|
3514
|
+
warnings=warnings,
|
|
3515
|
+
)
|
|
3323
3516
|
|
|
3324
3517
|
# This should never be reached since action is either "create" or "update"
|
|
3325
3518
|
raise_tool_error(
|
|
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.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/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
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/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
|
|
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.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/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
|
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/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.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.5.0.dev516 → ha_mcp_dev-7.5.0.dev518}/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
|