ha-mcp-dev 8.0.0.dev2224__tar.gz → 8.0.0.dev2228__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-8.0.0.dev2224/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.0.0.dev2228}/PKG-INFO +1 -1
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/pyproject.toml +1 -1
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/__main__.py +36 -33
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/config.py +9 -8
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/__init__.py +3 -1
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_persistence.py +10 -3
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_theme.py +9 -6
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/en.json +2 -2
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/settings.html +12 -10
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/settings.js +5 -3
- ha_mcp_dev-8.0.0.dev2228/src/ha_mcp/stdio_settings_sidecar.py +1390 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- ha_mcp_dev-8.0.0.dev2224/src/ha_mcp/stdio_settings_sidecar.py +0 -880
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/LICENSE +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/MANIFEST.in +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/README.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/setup.cfg +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_i18n.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/README.md +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/de.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/es.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/it.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/strict_bps.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/best_practice_result.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/best_practice_variables.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/component_api.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/component_config_reads.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/component_devices.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/component_registries.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/radio/matter.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/radio/zigbee.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/radio/zwave.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_dev.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/config_write_lock.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/visibility/enforcement.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/visibility/resolver.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/tests/__init__.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/tests/test_constants.py +0 -0
- {ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/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 = "8.0.0.
|
|
7
|
+
version = "8.0.0.dev2228"
|
|
8
8
|
description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# Upper bound widened to <3.15 so the package installs on Home Assistant's
|
|
@@ -901,27 +901,27 @@ def _maybe_spawn_settings_sidecar() -> None:
|
|
|
901
901
|
is async; this happens before the main stdio loop so there's no
|
|
902
902
|
nested-loop conflict with ``_run_entrypoint``'s own ``asyncio.run``.
|
|
903
903
|
|
|
904
|
-
Performance: the dump constructs the full FastMCP server
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
904
|
+
Performance: the dump constructs the full FastMCP server via the
|
|
905
|
+
cached ``_get_server()`` singleton the stdio session builds anyway,
|
|
906
|
+
so this only front-loads that cost. The dump runs as maybe_spawn's
|
|
907
|
+
``prepare`` hook — winner-only, inside the spawn lock — because the
|
|
908
|
+
replacement sidecar must read a cache dumped by the SAME parent that
|
|
909
|
+
spawned it: a spawn-lock loser with a different environment could
|
|
910
|
+
otherwise overwrite the winner's cache (issue #2131 review), and the
|
|
911
|
+
sidecar reloads that shared file per request.
|
|
908
912
|
"""
|
|
909
913
|
from ha_mcp.settings_ui import (
|
|
910
914
|
_get_tool_metadata,
|
|
911
915
|
dump_tool_metadata_cache,
|
|
912
916
|
)
|
|
913
917
|
from ha_mcp.stdio_settings_sidecar import (
|
|
914
|
-
_existing_sidecar_alive,
|
|
915
918
|
_is_disabled,
|
|
916
919
|
maybe_spawn,
|
|
917
920
|
)
|
|
918
921
|
|
|
919
|
-
#
|
|
920
|
-
#
|
|
921
|
-
|
|
922
|
-
# already has a cache from a prior parent startup; a disabled
|
|
923
|
-
# sidecar never reads one).
|
|
924
|
-
if _is_disabled() or _existing_sidecar_alive():
|
|
922
|
+
# Disabled is the only dump-skipping gate; maybe_spawn() logs the
|
|
923
|
+
# skip reason (a disabled sidecar never reads the cache).
|
|
924
|
+
if _is_disabled():
|
|
925
925
|
try:
|
|
926
926
|
maybe_spawn()
|
|
927
927
|
except Exception as e:
|
|
@@ -932,32 +932,35 @@ def _maybe_spawn_settings_sidecar() -> None:
|
|
|
932
932
|
)
|
|
933
933
|
return
|
|
934
934
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
#
|
|
939
|
-
#
|
|
940
|
-
#
|
|
941
|
-
# surfaces in its MCP server log panel).
|
|
942
|
-
logger.info(
|
|
943
|
-
"Tool metadata cache: %d tools dumped, write %s",
|
|
944
|
-
len(metadata),
|
|
945
|
-
"succeeded" if dumped else "FAILED",
|
|
946
|
-
)
|
|
947
|
-
except Exception as e:
|
|
948
|
-
# Cache dump is best-effort — the sidecar falls back to an empty
|
|
949
|
-
# tools list rather than blocking stdio startup. Include the
|
|
950
|
-
# exception class in the warning so ops can distinguish
|
|
935
|
+
def _dump_metadata_cache() -> None:
|
|
936
|
+
# One-off asyncio.run is safe here: this runs before the main
|
|
937
|
+
# stdio loop, so there's no nested-loop conflict with
|
|
938
|
+
# _run_entrypoint's own asyncio.run. Best-effort — the sidecar
|
|
939
|
+
# falls back to an empty tools list rather than blocking stdio
|
|
940
|
+
# startup. The exception class in the warning distinguishes
|
|
951
941
|
# server-init failures (Pydantic ValidationError) from cache I/O
|
|
952
942
|
# (OSError) from event-loop issues (RuntimeError).
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
943
|
+
try:
|
|
944
|
+
metadata = asyncio.run(_get_tool_metadata(_get_server()))
|
|
945
|
+
dumped = dump_tool_metadata_cache(metadata)
|
|
946
|
+
# Deliberate one-liner so users debugging an empty settings
|
|
947
|
+
# page can see whether the parent's dump succeeded by
|
|
948
|
+
# grepping the stdio process output (which Claude Desktop
|
|
949
|
+
# surfaces in its MCP server log panel).
|
|
950
|
+
logger.info(
|
|
951
|
+
"Tool metadata cache: %d tools dumped, write %s",
|
|
952
|
+
len(metadata),
|
|
953
|
+
"succeeded" if dumped else "FAILED",
|
|
954
|
+
)
|
|
955
|
+
except Exception as e:
|
|
956
|
+
logger.warning(
|
|
957
|
+
"Failed to dump tool metadata cache (%s)",
|
|
958
|
+
type(e).__name__,
|
|
959
|
+
exc_info=True,
|
|
960
|
+
)
|
|
958
961
|
|
|
959
962
|
try:
|
|
960
|
-
maybe_spawn()
|
|
963
|
+
maybe_spawn(prepare=_dump_metadata_cache)
|
|
961
964
|
except Exception as e:
|
|
962
965
|
# Spawn failures already log inside maybe_spawn(); the bare
|
|
963
966
|
# except here is a defense-in-depth guard for any unexpected
|
|
@@ -102,11 +102,12 @@ class Settings(BaseSettings):
|
|
|
102
102
|
# WebSocket configuration (essential for async operations)
|
|
103
103
|
enable_websocket: bool = Field(True, alias="ENABLE_WEBSOCKET")
|
|
104
104
|
|
|
105
|
-
# Settings UI sidecar (stdio mode only, #1587). 0 = pick a
|
|
106
|
-
# ephemeral port
|
|
107
|
-
#
|
|
108
|
-
# restarts
|
|
109
|
-
#
|
|
105
|
+
# Settings UI sidecar (stdio mode only, #1587). 0 (default) = pick a
|
|
106
|
+
# free ephemeral port on the first spawn and reuse it afterwards
|
|
107
|
+
# (persisted in ui.state, #2131) so the settings URL/origin stays
|
|
108
|
+
# stable across restarts; 1024-65535 pins a preferred fixed port
|
|
109
|
+
# instead (best-effort: falls back to an ephemeral one if taken).
|
|
110
|
+
# Read by run_main() in stdio_settings_sidecar.py.
|
|
110
111
|
sidecar_pin_port: int = Field(0, alias="HA_MCP_SIDECAR_PORT")
|
|
111
112
|
|
|
112
113
|
# Development/Debug configuration
|
|
@@ -859,9 +860,9 @@ ADVANCED_SETTINGS_FIELDS: tuple[AdvancedField, ...] = (
|
|
|
859
860
|
AdvancedField("environment", "ENVIRONMENT", str, "diagnostics", True),
|
|
860
861
|
AdvancedField("log_level", "LOG_LEVEL", str, "diagnostics", True),
|
|
861
862
|
AdvancedField("debug", "DEBUG", bool, "diagnostics", True),
|
|
862
|
-
# Settings UI sidecar (stdio-only).
|
|
863
|
-
#
|
|
864
|
-
# (
|
|
863
|
+
# Settings UI sidecar (stdio-only). 0 (default) = first spawn picks a
|
|
864
|
+
# free port and later spawns reuse it via ui.state (#2131); a value
|
|
865
|
+
# pins a preferred fixed port instead (best-effort, #1587).
|
|
865
866
|
AdvancedField("sidecar_pin_port", "HA_MCP_SIDECAR_PORT", int, "sidecar", True),
|
|
866
867
|
# NOTE: ``auto_backup_dir`` and ``auto_backup_calendar_lookahead_days``
|
|
867
868
|
# are NOT in this tuple. They are in ``BACKUP_OVERRIDE_FIELDS`` (defined
|
|
@@ -626,7 +626,9 @@ def register_settings_routes(
|
|
|
626
626
|
("/api/settings/features", ["GET"], "get_feature_flags"),
|
|
627
627
|
("/api/settings/features", ["POST"], "save_feature_flags"),
|
|
628
628
|
# Theme / accessibility prefs (#1574 review) — server-side copy so
|
|
629
|
-
# they survive
|
|
629
|
+
# they survive a stdio sidecar origin change (stable by default
|
|
630
|
+
# since #2131, but fresh on first spawn / lost ui.state / pin
|
|
631
|
+
# change / taken remembered port)
|
|
630
632
|
("/api/settings/theme", ["GET"], "get_theme_prefs"),
|
|
631
633
|
("/api/settings/theme", ["POST"], "save_theme_prefs"),
|
|
632
634
|
# Advanced settings endpoints
|
{ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/_persistence.py
RENAMED
|
@@ -67,7 +67,11 @@ def dump_tool_metadata_cache(metadata: list[dict[str, Any]]) -> bool:
|
|
|
67
67
|
"""
|
|
68
68
|
path = _get_tool_metadata_cache_path()
|
|
69
69
|
try:
|
|
70
|
-
|
|
70
|
+
# Atomic (tmp-then-rename): since the dump moved ahead of the
|
|
71
|
+
# sidecar retire it overlaps the OLD still-serving sidecar on
|
|
72
|
+
# every startup, and a truncate-write would hand a concurrent
|
|
73
|
+
# /api/tools request an empty tool list from the torn file.
|
|
74
|
+
_atomic_write_json(path, metadata)
|
|
71
75
|
except OSError:
|
|
72
76
|
logger.warning("Failed to dump tool metadata cache to %s", path, exc_info=True)
|
|
73
77
|
return False
|
|
@@ -203,10 +207,13 @@ def effective_tool_config(settings: Settings | None = None) -> dict[str, Any]:
|
|
|
203
207
|
return {**cfg, "tools": tools}
|
|
204
208
|
|
|
205
209
|
|
|
206
|
-
def _atomic_write_json(
|
|
210
|
+
def _atomic_write_json(
|
|
211
|
+
path: Path, payload: dict[str, Any] | list[dict[str, Any]]
|
|
212
|
+
) -> None:
|
|
207
213
|
"""Write ``payload`` to ``path`` atomically.
|
|
208
214
|
|
|
209
|
-
Writes to
|
|
215
|
+
Writes to a unique same-directory temp file (``mkstemp``, since
|
|
216
|
+
#1993) first and ``os.replace``s into place so a
|
|
210
217
|
crash or out-of-space mid-write cannot leave a partial/empty file —
|
|
211
218
|
callers that read the file back (``load_tool_config`` /
|
|
212
219
|
``_load_backup_settings_override``) would otherwise treat a
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"""Theme / accessibility preference persistence for the settings UI.
|
|
2
2
|
|
|
3
3
|
The browser keeps these in localStorage for synchronous pre-paint reads,
|
|
4
|
-
but localStorage is origin-scoped and the stdio settings sidecar
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
but localStorage is origin-scoped and the stdio settings sidecar's port
|
|
5
|
+
can change — historically on every spawn, now (#2131) only on the first
|
|
6
|
+
spawn, a lost ``ui.state``, a pin change, or a remembered port another
|
|
7
|
+
process took — and each port change is a fresh origin that starts
|
|
8
|
+
empty. The
|
|
9
|
+
server-side copy here survives that: POSTs land in ``theme_prefs.json``
|
|
10
|
+
next to the other settings files, and the page handler seeds them back
|
|
11
|
+
into the served HTML (``server-prefs`` head script) so a fresh origin
|
|
12
|
+
paints with the user's saved choices.
|
|
10
13
|
|
|
11
14
|
Kept as a leaf module (no imports from the settings_ui package) so the
|
|
12
15
|
handler families and ``__init__`` can depend on it without cycles.
|
{ha_mcp_dev-8.0.0.dev2224 → ha_mcp_dev-8.0.0.dev2228}/src/ha_mcp/settings_ui/locales/en.json
RENAMED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"policies.pending.empty": "No pending approvals.",
|
|
64
64
|
"policies.rules.title": "Gated tools",
|
|
65
65
|
"policies.rules.empty": "No tools currently security-gated. Enable per-tool gating from the <a href=\"#\" data-panel-link=\"tools\">Tools</a> tab.",
|
|
66
|
-
"accessibility.intro": "These settings apply immediately and are saved in this browser and on the server, so they survive restarts in every mode (including stdio, where the settings page
|
|
66
|
+
"accessibility.intro": "These settings apply immediately and are saved in this browser and on the server, so they survive restarts in every mode (including stdio, where the settings page can occasionally move to a new port). The docs site offers the same controls in its navigation bar; it has no server and saves per browser.",
|
|
67
67
|
"accessibility.storage_blocked": "Your browser is blocking site storage; choices apply for this session only.",
|
|
68
68
|
"accessibility.theme.title": "Theme",
|
|
69
69
|
"accessibility.theme.help": "One-click color schemes. Auto, the default, follows your OS preference and flips live when it changes.",
|
|
@@ -420,7 +420,7 @@
|
|
|
420
420
|
"advanced.extra_yaml_write_keys.label": "Extra YAML write keys",
|
|
421
421
|
"advanced.extra_yaml_write_keys.help": "Comma-separated top-level keys ha_config_set_yaml may write in addition to the built-in ones, for YAML-first integrations on this install (e.g. alert2). Keys that redefine Home Assistant's own trust boundary can never be added and are ignored. Requires custom component 1.2.4 or newer.",
|
|
422
422
|
"advanced.sidecar_pin_port.label": "Settings UI sidecar port",
|
|
423
|
-
"advanced.sidecar_pin_port.help": "0
|
|
423
|
+
"advanced.sidecar_pin_port.help": "0 picks a free port on first start and keeps it for later restarts; 1024–65535 pins a preferred port (falls back to a free one if taken). Restart required.",
|
|
424
424
|
"advanced.enable_dev_mode.label": "Developer mode",
|
|
425
425
|
"advanced.enable_dev_mode.help": "⚠ Registers hidden tools that can change settings and replace the running server. Development and testing only. Restart required.",
|
|
426
426
|
"addon.backup_hint.name": "Full-HA snapshot suggestion level (LLM-facing)",
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
system sans-serif. -->
|
|
16
16
|
<script data-purpose="server-prefs" data-prefs="__HA_MCP_THEME_PREFS__">
|
|
17
17
|
// #1574 review: theme/accessibility prefs also persist server-side
|
|
18
|
-
// (theme_prefs.json) because stdio
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
18
|
+
// (theme_prefs.json) because the stdio sidecar's port — stable by
|
|
19
|
+
// default since #2131, but fresh on first spawn, a lost ui.state, a
|
|
20
|
+
// pin change, or a taken remembered port — is the browser origin, and
|
|
21
|
+
// a new origin's localStorage starts empty. The page handler
|
|
22
|
+
// substitutes the data-prefs attribute at request time; this seeds
|
|
23
|
+
// only MISSING localStorage keys (the browser's own latest choice
|
|
24
|
+
// wins) before the anti-FOUC resolver below reads them. The docs site
|
|
25
|
+
// is a static build and stays localStorage-only.
|
|
24
26
|
(function () {
|
|
25
27
|
var el = document.currentScript;
|
|
26
28
|
var raw = el ? el.getAttribute("data-prefs") : "";
|
|
@@ -366,10 +368,10 @@
|
|
|
366
368
|
<div class="panel" id="panel-accessibility" role="tabpanel" aria-labelledby="tab-accessibility" tabindex="0">
|
|
367
369
|
<p class="tool-desc" style="margin-bottom:16px" data-i18n="accessibility.intro">
|
|
368
370
|
These settings apply immediately and are saved in this browser and on the
|
|
369
|
-
server, so they survive restarts in every mode (including stdio, where
|
|
370
|
-
settings page
|
|
371
|
-
the same controls in its navigation bar; it has no server and
|
|
372
|
-
browser.
|
|
371
|
+
server, so they survive restarts in every mode (including stdio, where
|
|
372
|
+
the settings page can occasionally move to a new port). The docs site
|
|
373
|
+
offers the same controls in its navigation bar; it has no server and
|
|
374
|
+
saves per browser.
|
|
373
375
|
</p>
|
|
374
376
|
<p class="a11y-contrast-warning" id="a11y-storage-note" hidden data-i18n="accessibility.storage_blocked">
|
|
375
377
|
Your browser is blocking site storage; choices apply for this session
|
|
@@ -3534,7 +3534,7 @@ const ADVANCED_FIELD_META = {
|
|
|
3534
3534
|
code_mode_max_invocations: { label: "Code-mode max invocations", help: "API/tool-call cap per sandbox run. Restart required." },
|
|
3535
3535
|
code_mode_saved_tools_path:{ label: "Saved-tools path", help: "JSON file where ha_manage_custom_tool persists saved tools across restarts. Restart required." },
|
|
3536
3536
|
extra_yaml_write_keys: { label: "Extra YAML write keys", help: "Comma-separated top-level keys ha_config_set_yaml may write in addition to the built-in ones, for YAML-first integrations on this install (e.g. alert2). Keys that redefine Home Assistant's own trust boundary can never be added and are ignored. Requires custom component 1.2.4 or newer." },
|
|
3537
|
-
sidecar_pin_port: { label: "Settings UI sidecar port", help: "0
|
|
3537
|
+
sidecar_pin_port: { label: "Settings UI sidecar port", help: "0 picks a free port on first start and keeps it for later restarts; 1024–65535 pins a preferred port (falls back to a free one if taken). Restart required." },
|
|
3538
3538
|
enable_dev_mode: { label: "Developer mode", help: "⚠ DANGER: registers hidden developer tools (ha_dev_manage_server, ha_dev_manage_settings) that let AI agents change server settings and replace the running server version (e.g. install a PR build). For development and testing only. Restart required." },
|
|
3539
3539
|
};
|
|
3540
3540
|
|
|
@@ -4020,8 +4020,10 @@ loadFsCustomPaths();
|
|
|
4020
4020
|
|
|
4021
4021
|
// #1574 review: localStorage is the synchronous store the anti-FOUC
|
|
4022
4022
|
// script reads at paint time, but it is origin-scoped and the stdio
|
|
4023
|
-
// sidecar
|
|
4024
|
-
//
|
|
4023
|
+
// sidecar's port (= the origin) can still change: stable by default
|
|
4024
|
+
// since #2131, yet fresh on first spawn, a lost ui.state, a pin
|
|
4025
|
+
// change, or a taken remembered port. This hook therefore (a) mirrors
|
|
4026
|
+
// every change to the server
|
|
4025
4027
|
// (./api/settings/theme -> theme_prefs.json), which seeds the next
|
|
4026
4028
|
// fresh origin via the server-prefs head script, and (b) surfaces a
|
|
4027
4029
|
// blocked localStorage (private mode) once instead of silently losing
|