ha-mcp-dev 7.6.0.dev636__tar.gz → 7.6.0.dev638__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/MANIFEST.in +2 -0
  2. {ha_mcp_dev-7.6.0.dev636/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.6.0.dev638}/PKG-INFO +1 -1
  3. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/pyproject.toml +2 -2
  4. ha_mcp_dev-7.6.0.dev638/src/ha_mcp/settings.css +325 -0
  5. ha_mcp_dev-7.6.0.dev638/src/ha_mcp/settings.js +2732 -0
  6. ha_mcp_dev-7.6.0.dev638/src/ha_mcp/settings_ui.py +3119 -0
  7. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  8. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp_dev.egg-info/SOURCES.txt +2 -0
  9. ha_mcp_dev-7.6.0.dev636/src/ha_mcp/settings_ui.py +0 -6051
  10. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/LICENSE +0 -0
  11. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/README.md +0 -0
  12. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/setup.cfg +0 -0
  13. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/__init__.py +0 -0
  14. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/__main__.py +0 -0
  15. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/_pypi_marker +0 -0
  16. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/_version.py +0 -0
  17. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/auth/__init__.py +0 -0
  18. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/auth/consent_form.py +0 -0
  19. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/auth/provider.py +0 -0
  20. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/backup_manager.py +0 -0
  21. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/client/__init__.py +0 -0
  22. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/client/rest_client.py +0 -0
  23. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/client/supervisor_client.py +0 -0
  24. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/client/websocket_client.py +0 -0
  25. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/client/websocket_listener.py +0 -0
  26. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/config.py +0 -0
  27. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/errors.py +0 -0
  28. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/__init__.py +0 -0
  29. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/approval_queue.py +0 -0
  30. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/evaluator.py +0 -0
  31. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/handlers.py +0 -0
  32. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/middleware.py +0 -0
  33. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/model.py +0 -0
  34. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/persistence.py +0 -0
  35. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/policy/value_sources.py +0 -0
  36. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/py.typed +0 -0
  37. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  38. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  39. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  40. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  41. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  42. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  43. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  44. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  45. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  46. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  47. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  48. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  49. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  50. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  51. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  52. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  53. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  54. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  55. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  56. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  57. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  58. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  59. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/server.py +0 -0
  60. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/smoke_test.py +0 -0
  61. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  62. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/__init__.py +0 -0
  63. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/auto_backup.py +0 -0
  64. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/backup.py +0 -0
  65. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  66. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/device_control.py +0 -0
  67. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/enhanced.py +0 -0
  68. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/helpers.py +0 -0
  69. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/reference_validator.py +0 -0
  70. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/registry.py +0 -0
  71. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/smart_search.py +0 -0
  72. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_addons.py +0 -0
  73. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_areas.py +0 -0
  74. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  75. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  76. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_calendar.py +0 -0
  77. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_camera.py +0 -0
  78. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_categories.py +0 -0
  79. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_code.py +0 -0
  80. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  81. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  82. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  83. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  84. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  85. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  86. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_energy.py +0 -0
  87. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_entities.py +0 -0
  88. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  89. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_groups.py +0 -0
  90. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_hacs.py +0 -0
  91. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_history.py +0 -0
  92. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_integrations.py +0 -0
  93. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_labels.py +0 -0
  94. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  95. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_registry.py +0 -0
  96. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_resources.py +0 -0
  97. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_search.py +0 -0
  98. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_service.py +0 -0
  99. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_services.py +0 -0
  100. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_system.py +0 -0
  101. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_todo.py +0 -0
  102. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_traces.py +0 -0
  103. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_updates.py +0 -0
  104. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_utility.py +0 -0
  105. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  106. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  107. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/tools_zones.py +0 -0
  108. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/util_helpers.py +0 -0
  109. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/tools/validation_middleware.py +0 -0
  110. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/transforms/__init__.py +0 -0
  111. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/transforms/categorized_search.py +0 -0
  112. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  113. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/__init__.py +0 -0
  114. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/config_hash.py +0 -0
  115. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/data_paths.py +0 -0
  116. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/domain_handlers.py +0 -0
  117. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  118. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  119. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/operation_manager.py +0 -0
  120. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/python_sandbox.py +0 -0
  121. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/skill_loader.py +0 -0
  122. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp/utils/usage_logger.py +0 -0
  123. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  124. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  125. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  126. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  127. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/tests/__init__.py +0 -0
  128. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/tests/test_constants.py +0 -0
  129. {ha_mcp_dev-7.6.0.dev636 → ha_mcp_dev-7.6.0.dev638}/tests/test_env_manager.py +0 -0
@@ -1,3 +1,5 @@
1
1
  include README.md
2
2
  include LICENSE
3
+ include src/ha_mcp/settings.js
4
+ include src/ha_mcp/settings.css
3
5
  recursive-include src/ha_mcp/resources *.md *.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.6.0.dev636
3
+ Version: 7.6.0.dev638
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT
@@ -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.dev636"
7
+ version = "7.6.0.dev638"
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"
@@ -53,7 +53,7 @@ package-dir = {"" = "src", "tests" = "tests"}
53
53
  packages = { find = { where = ["src", "."], include = ["ha_mcp*", "tests"] } }
54
54
 
55
55
  [tool.setuptools.package-data]
56
- ha_mcp = ["py.typed", "_pypi_marker", "resources/skills-vendor/**/*"]
56
+ ha_mcp = ["py.typed", "_pypi_marker", "settings.js", "settings.css", "resources/skills-vendor/**/*"]
57
57
 
58
58
  [tool.mypy]
59
59
  python_version = "3.13"
@@ -0,0 +1,325 @@
1
+
2
+ :root {
3
+ --bg: #1c1c1e; --surface: #2c2c2e; --surface-hover: #3a3a3c;
4
+ --text: #f5f5f7; --text-secondary: #98989d; --accent: #0a84ff;
5
+ --accent-hover: #409cff; --danger: #ff453a; --success: #30d158;
6
+ --warning: #ffd60a; --border: #38383a; --disabled-bg: #1a1a1c;
7
+ }
8
+ * { box-sizing: border-box; margin: 0; padding: 0; }
9
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
10
+ background: var(--bg); color: var(--text); line-height: 1.5; padding: 16px; }
11
+ /* Small unobtrusive version label at the bottom of every settings
12
+ page so an operator can see the running build without leaving
13
+ the UI. Empty until the /api/settings/info GET populates it. */
14
+ .version-footer { margin-top: 32px; padding: 12px 0; font-size: 0.75rem;
15
+ color: var(--text-secondary); text-align: center;
16
+ border-top: 1px solid var(--border); opacity: 0.7; }
17
+ .header { display: flex; align-items: center; justify-content: space-between;
18
+ padding: 16px 0; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
19
+ .header h1 { font-size: 1.5rem; font-weight: 600; }
20
+ .status { font-size: 0.85rem; padding: 4px 12px; border-radius: 12px;
21
+ background: var(--surface); color: var(--text-secondary); }
22
+ .status.saved { background: #0d3b1e; color: var(--success); }
23
+ .search { width: 100%; padding: 10px 16px; border-radius: 10px; border: 1px solid var(--border);
24
+ background: var(--surface); color: var(--text); font-size: 0.95rem; margin-bottom: 16px;
25
+ outline: none; }
26
+ .search:focus { border-color: var(--accent); }
27
+ .readonly-notice { background: #1a2a3a; border: 1px solid #1a4a7a; border-radius: 10px;
28
+ padding: 12px 16px; margin-bottom: 16px; font-size: 0.85rem; color: #6cb4ff; }
29
+ .group { background: var(--surface); border-radius: 12px; margin-bottom: 8px;
30
+ overflow: hidden; border: 1px solid var(--border); }
31
+ .group-header { display: flex; align-items: center; justify-content: space-between;
32
+ padding: 12px 16px; cursor: pointer; user-select: none; gap: 12px; }
33
+ .group-header:hover { background: var(--surface-hover); }
34
+ .group-header-left { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
35
+ .group-name { font-weight: 600; font-size: 0.95rem; }
36
+ .group-count { font-size: 0.8rem; color: var(--text-secondary); }
37
+ .group-chevron { transition: transform 0.2s; color: var(--text-secondary);
38
+ display: inline-block; width: 12px; }
39
+ .group-chevron.open { transform: rotate(90deg); }
40
+ .group-master { flex-shrink: 0; }
41
+ .group-tools { display: none; border-top: 1px solid var(--border); }
42
+ .group-tools.open { display: block; }
43
+ .tool { display: flex; align-items: center; justify-content: space-between;
44
+ padding: 10px 16px; border-bottom: 1px solid var(--border); }
45
+ .tool:last-child { border-bottom: none; }
46
+ .tool.hidden { display: none; }
47
+ .tool.env-pinned .tool-name { color: var(--text-secondary); }
48
+ .tool-info { flex: 1; min-width: 0; }
49
+ .tool-name { font-size: 0.9rem; font-weight: 500; }
50
+ .tool-meta { font-size: 0.75rem; color: var(--text-secondary); margin-top: 2px; }
51
+ .tool-desc { font-size: 0.8rem; color: var(--text-secondary); margin-top: 2px;
52
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
53
+ .badge { display: inline-block; font-size: 0.7rem; padding: 1px 6px;
54
+ border-radius: 4px; margin-left: 6px; font-weight: 500; }
55
+ .badge.readonly { background: #1a2a3a; color: #6cb4ff; }
56
+ .badge.destructive { background: #3a1a1a; color: #ff6b6b; }
57
+ .badge.mandatory { background: #1a3a1a; color: #6bff6b; }
58
+ .tool-toggles { display: flex; gap: 16px; align-items: center; }
59
+ .toggle-group { display: flex; flex-direction: column; align-items: center; gap: 2px;
60
+ font-size: 0.7rem; color: var(--text-secondary); }
61
+ .toggle-group.disabled-toggle { opacity: 0.35; }
62
+ .switch { position: relative; display: inline-block; width: 36px; height: 20px; }
63
+ .switch input { opacity: 0; width: 0; height: 0; }
64
+ .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0;
65
+ background: #555; border-radius: 10px; transition: background 0.2s; }
66
+ .slider::before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px;
67
+ top: 3px; background: var(--text); border-radius: 50%; transition: transform 0.2s; }
68
+ input:checked + .slider { background: var(--accent); }
69
+ input:checked + .slider::before { transform: translateX(16px); }
70
+ input:disabled + .slider { cursor: not-allowed; opacity: 0.4; }
71
+ .disabled-by-note { font-size: 0.7rem; color: var(--warning); margin-top: 2px;
72
+ font-style: italic; }
73
+ .summary { display: flex; gap: 16px; padding: 8px 0; margin-bottom: 16px;
74
+ font-size: 0.85rem; color: var(--text-secondary); flex-wrap: wrap; }
75
+ .summary span { background: var(--surface); padding: 4px 12px; border-radius: 8px; }
76
+ .pin-notice { background: #3a2e1a; border: 1px solid #7a5a1a; border-radius: 10px;
77
+ padding: 10px 16px; margin-bottom: 12px; font-size: 0.85rem; color: #ffd680; display: none; }
78
+ .pin-notice.show { display: block; }
79
+ .restart-notice { background: #3a1a1a; border: 1px solid #7a1a1a; border-radius: 10px;
80
+ padding: 12px 16px; margin-bottom: 12px; font-size: 0.9rem; color: #ff9090;
81
+ font-weight: 500; display: none; align-items: center; justify-content: space-between; gap: 12px; }
82
+ .restart-notice.show { display: flex; }
83
+ .restart-notice-text { flex: 1; }
84
+ .restart-btn { padding: 8px 16px; border-radius: 8px; border: none;
85
+ background: var(--accent); color: white; font-weight: 600; cursor: pointer;
86
+ font-size: 0.85rem; flex-shrink: 0; }
87
+ .restart-btn:hover { background: var(--accent-hover); }
88
+ .restart-btn:disabled { opacity: 0.5; cursor: not-allowed; }
89
+ /* Destructive variant — visually distinct from the primary accent
90
+ so a glance at the page makes "Disable settings server"
91
+ obviously not a routine click. Matches the restart-notice red
92
+ family so the danger semantic reads even without label text. */
93
+ .danger-btn { padding: 7px 14px; border-radius: 8px;
94
+ border: 1px solid #7a1a1a; background: transparent; color: #ff9090;
95
+ font-weight: 600; cursor: pointer; font-size: 0.8rem; flex-shrink: 0; }
96
+ .danger-btn:hover { background: #2a0e0e; }
97
+ .danger-btn:disabled { opacity: 0.5; cursor: not-allowed; }
98
+ /* Tabs — generic structure other tabs can stack onto without
99
+ touching existing markup. New tabs add a button to .tabs and
100
+ a sibling .panel below; the JS switcher dispatches via the
101
+ data-panel attribute. */
102
+ .tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
103
+ .tab { padding: 10px 16px; border: none; background: transparent; color: var(--text-secondary);
104
+ font-size: 0.95rem; cursor: pointer; border-bottom: 2px solid transparent; font-weight: 500; }
105
+ .tab.active { color: var(--text); border-bottom-color: var(--accent); }
106
+ .panel { display: none; }
107
+ .panel.active { display: block; }
108
+ /* Backups */
109
+ .backup-filters { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
110
+ .backup-filters input { padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border);
111
+ background: var(--surface); color: var(--text); font-size: 0.85rem; }
112
+ .backup-filters input:focus { border-color: var(--accent); outline: none; }
113
+ .backup-filters button { padding: 8px 12px; border-radius: 8px; border: none;
114
+ background: var(--surface); color: var(--text); font-size: 0.85rem; cursor: pointer; }
115
+ .backup-filters button:hover { background: var(--surface-hover); }
116
+ .backup-filters button.danger { background: #3a1a1a; color: #ff6b6b; }
117
+ .backup-state { background: var(--surface); border-radius: 10px; padding: 10px 16px; margin-bottom: 12px;
118
+ font-size: 0.85rem; color: var(--text-secondary); display: flex; gap: 16px; flex-wrap: wrap; }
119
+ .backup-state span { display: inline-block; }
120
+ .backup-state strong { color: var(--text); }
121
+ .backup-row { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
122
+ padding: 10px 14px; margin-bottom: 6px; display: flex; align-items: center; gap: 12px; }
123
+ .backup-row-info { flex: 1; min-width: 0; }
124
+ .backup-row-name { font-size: 0.9rem; font-weight: 500; word-break: break-all; }
125
+ .backup-row-meta { font-size: 0.75rem; color: var(--text-secondary); margin-top: 2px; }
126
+ .backup-row-actions { display: flex; gap: 6px; flex-shrink: 0; }
127
+ .backup-row-actions button { padding: 6px 10px; border-radius: 6px; border: none;
128
+ background: var(--accent); color: white; font-size: 0.8rem; cursor: pointer; }
129
+ .backup-row-actions button:hover { background: var(--accent-hover); }
130
+ .backup-row-actions button.danger { background: var(--danger); }
131
+ .backup-row-actions button.secondary { background: var(--surface-hover); color: var(--text); }
132
+ .backup-empty { padding: 24px; text-align: center; color: var(--text-secondary); font-size: 0.9rem;
133
+ background: var(--surface); border: 1px dashed var(--border); border-radius: 10px; }
134
+ .backup-config { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
135
+ padding: 14px 16px; margin-bottom: 12px; }
136
+ .backup-config-form { display: grid; grid-template-columns: 1fr; gap: 10px; }
137
+ .backup-field { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
138
+ .backup-field-label { min-width: 200px; font-size: 0.9rem; font-weight: 500; }
139
+ .backup-field-control input[type="number"] { width: 120px; padding: 6px 10px;
140
+ border-radius: 6px; border: 1px solid var(--border); background: var(--bg); color: var(--text); }
141
+ .backup-field-control input[type="number"]:disabled { opacity: 0.55; cursor: not-allowed; }
142
+ .backup-field-locked { background: #2a2520; color: #f4b860; font-size: 0.78rem;
143
+ padding: 2px 8px; border-radius: 999px; }
144
+ .backup-field-help { font-size: 0.75rem; color: var(--text-secondary); flex-basis: 100%; margin-left: 200px; }
145
+ .backup-config-actions { display: flex; align-items: center; gap: 12px; margin-top: 10px;
146
+ padding-top: 10px; border-top: 1px solid var(--border); }
147
+ .backup-config-actions button { padding: 8px 16px; border-radius: 6px; border: none;
148
+ background: var(--accent); color: white; font-size: 0.9rem; cursor: pointer; font-weight: 500; }
149
+ .backup-config-actions button:hover { background: var(--accent-hover); }
150
+ .backup-config-actions button:disabled { opacity: 0.5; cursor: not-allowed; }
151
+ /* Modal */
152
+ .modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.7);
153
+ display: none; align-items: center; justify-content: center; z-index: 10; padding: 16px; }
154
+ .modal-backdrop.show { display: flex; }
155
+ .modal { background: var(--bg); border: 1px solid var(--border); border-radius: 12px;
156
+ max-width: 900px; width: 100%; max-height: 90vh; display: flex; flex-direction: column; }
157
+ .modal-header { padding: 14px 16px; border-bottom: 1px solid var(--border);
158
+ display: flex; align-items: center; justify-content: space-between; gap: 12px; }
159
+ .modal-title { font-size: 1.05rem; font-weight: 600; word-break: break-all; }
160
+ .modal-close { background: transparent; border: none; color: var(--text-secondary);
161
+ font-size: 1.4rem; cursor: pointer; padding: 0 8px; }
162
+ .modal-body { flex: 1; overflow: auto; padding: 16px; }
163
+ .modal-body pre { background: var(--surface); padding: 12px; border-radius: 8px;
164
+ font-size: 0.8rem; overflow: auto; line-height: 1.4; }
165
+ .diff-add { color: #6bff6b; }
166
+ .diff-rem { color: #ff6b6b; }
167
+ .diff-hdr { color: #6cb4ff; }
168
+ /* Server-settings rows (#863). One row per FEATURE_FLAG_FIELDS
169
+ entry. Locked rows (env / addon origin) get the dim treatment +
170
+ a small inline note pointing at the env var to adjust. */
171
+ .features-sub { font-size: 0.75rem; color: var(--text-secondary);
172
+ margin-bottom: 8px; }
173
+ .feature-row { display: flex; align-items: flex-start; justify-content: space-between;
174
+ gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
175
+ .feature-row:first-child { border-top: none; }
176
+ .feature-info { flex: 1; min-width: 0; }
177
+ .feature-name { font-size: 0.9rem; font-weight: 500; }
178
+ .feature-help { font-size: 0.75rem; color: var(--text-secondary); margin-top: 2px;
179
+ line-height: 1.4; }
180
+ .feature-help code { background: #111; padding: 1px 5px; border-radius: 4px;
181
+ font-size: 0.72rem; }
182
+ .feature-locked-note { font-size: 0.72rem; color: var(--warning); margin-top: 4px;
183
+ font-style: italic; }
184
+ .feature-control { flex-shrink: 0; display: flex; align-items: center; }
185
+ .feature-control input[type="number"] { width: 64px; padding: 4px 8px;
186
+ background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
187
+ color: var(--text); font-size: 0.85rem; }
188
+ .feature-control input[type="number"]:disabled { opacity: 0.4; cursor: not-allowed; }
189
+ .feature-row.locked .feature-name { color: var(--text-secondary); }
190
+ /* Beta master toggle + nested sub-rows. The master row
191
+ ``.beta-master-row`` is visually distinguished as a section
192
+ header. The 5 sub-rows ``.beta-sub`` are indented with a vertical
193
+ connector line on the left; when master is off they get
194
+ ``.dimmed`` (reduced opacity + disabled inputs) to make the
195
+ gated state visible without removing rows from the DOM. */
196
+ .feature-row.beta-master-row { font-weight: 600; padding-top: 16px;
197
+ border-top: 2px solid var(--border); margin-top: 8px; }
198
+ .feature-row.beta-master-row .feature-help { font-weight: 400; }
199
+ .feature-row.beta-sub { padding-left: 32px; position: relative; }
200
+ .feature-row.beta-sub::before { content: ""; position: absolute;
201
+ left: 12px; top: 0; bottom: 0; width: 2px; background: var(--border); }
202
+ .feature-row.beta-sub.dimmed { opacity: 0.55; }
203
+ .feature-row.beta-sub.dimmed input { cursor: not-allowed; }
204
+ /* Code-mode sub-numerics — second-level nesting under the
205
+ enable_code_mode beta sub-row. Same dimming
206
+ logic as beta-sub but deeper-indented and gated by
207
+ enable_code_mode rather than the master. */
208
+ .feature-row.codemode-sub { padding-left: 56px; position: relative; }
209
+ .feature-row.codemode-sub::before { content: ""; position: absolute;
210
+ left: 36px; top: 0; bottom: 0; width: 2px; background: var(--border); }
211
+ .feature-row.codemode-sub.dimmed { opacity: 0.55; }
212
+ .feature-row.codemode-sub.dimmed input { cursor: not-allowed; }
213
+ /* YAML packages per-key sub-rows — second-level nested under
214
+ enable_yaml_config_editing. Same dimming logic as codemode-sub
215
+ but gated by enable_yaml_config_editing (the parent flag) rather
216
+ than enable_code_mode. */
217
+ .feature-row.yaml-packages-sub { padding-left: 56px; position: relative; }
218
+ .feature-row.yaml-packages-sub::before { content: ""; position: absolute;
219
+ left: 36px; top: 0; bottom: 0; width: 2px; background: var(--border); }
220
+ .feature-row.yaml-packages-sub.dimmed { opacity: 0.55; }
221
+ .feature-row.yaml-packages-sub.dimmed input { cursor: not-allowed; }
222
+ /* Advanced settings sections — one row per
223
+ ADVANCED_SETTINGS_FIELDS entry, grouped by section. Visually
224
+ matches the .feature-row treatment so the Server Settings tab
225
+ reads as one coherent surface. */
226
+ .adv-section-title { font-size: 0.85rem; font-weight: 600;
227
+ color: var(--text-secondary); margin: 20px 0 4px; text-transform: uppercase;
228
+ letter-spacing: 0.05em; }
229
+ /* Beta section header is visually distinct (warning color, slightly
230
+ larger) so the dangerous-features block at the bottom is impossible
231
+ to miss as a category boundary. */
232
+ .adv-section-title.beta-section-title { color: var(--warning);
233
+ font-size: 0.95rem; margin-top: 32px;
234
+ border-top: 1px solid var(--warning); padding-top: 16px; }
235
+ /* Two-step save note + primary-CTA save button.
236
+ The default <button> in this UI is intentionally small/neutral
237
+ because most surfaces have many of them; the Save row gets a
238
+ dedicated, larger primary style so users don't miss the action.
239
+ Duplicated at top and bottom so scrolling either way reaches it. */
240
+ .adv-save-note { background: rgba(255, 152, 0, 0.08);
241
+ border-left: 3px solid var(--warning); padding: 10px 14px;
242
+ border-radius: 6px; margin: 12px 0; color: var(--text);
243
+ font-size: 0.85rem; line-height: 1.4; }
244
+ .adv-save-note strong { color: var(--warning); }
245
+ .adv-save-row { display: flex; align-items: center; gap: 12px;
246
+ margin: 16px 0; padding: 8px 0; }
247
+ .adv-save-btn { padding: 10px 22px; font-size: 1rem; font-weight: 600;
248
+ border: none; border-radius: 8px; background: var(--accent);
249
+ color: white; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.15);
250
+ transition: background 0.15s ease, transform 0.05s ease; }
251
+ .adv-save-btn:hover { background: var(--accent-hover); }
252
+ .adv-save-btn:active { transform: translateY(1px); }
253
+ .adv-save-btn:disabled { opacity: 0.55; cursor: not-allowed;
254
+ box-shadow: none; }
255
+ .adv-section { border-top: 1px solid var(--border); }
256
+ .adv-row { display: flex; align-items: flex-start; justify-content: space-between;
257
+ gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
258
+ .adv-row:first-child { border-top: none; }
259
+ .adv-row.locked .adv-name { color: var(--text-secondary); }
260
+ .adv-info { flex: 1; min-width: 0; }
261
+ .adv-name { font-size: 0.9rem; font-weight: 500; }
262
+ .adv-help { font-size: 0.75rem; color: var(--text-secondary); margin-top: 2px;
263
+ line-height: 1.4; }
264
+ .adv-help code { background: #111; padding: 1px 5px; border-radius: 4px;
265
+ font-size: 0.72rem; }
266
+ .adv-locked-note { font-size: 0.72rem; color: var(--warning); margin-top: 4px;
267
+ font-style: italic; }
268
+ .adv-control { flex-shrink: 0; display: flex; align-items: center; }
269
+ .adv-control input[type="text"],
270
+ .adv-control input[type="number"],
271
+ .adv-control select { padding: 4px 8px; background: var(--bg);
272
+ border: 1px solid var(--border); border-radius: 6px; color: var(--text);
273
+ font-size: 0.85rem; min-width: 120px; }
274
+ .adv-control input:disabled,
275
+ .adv-control select:disabled { opacity: 0.4; cursor: not-allowed; }
276
+ .adv-control input[type="checkbox"]:disabled { opacity: 0.4; cursor: not-allowed; }
277
+ /* Tool Security Policies — per-tool card layout.
278
+ Cards reuse the surface/border variables already in use elsewhere
279
+ so they read consistently with backup-row / group blocks. */
280
+ .policy-rule-card { background: var(--surface); border: 1px solid var(--border);
281
+ border-radius: 10px; padding: 12px 14px; margin: 8px 0; }
282
+ .policy-rule-header { display: flex; justify-content: space-between;
283
+ align-items: center; margin-bottom: 8px; }
284
+ .policy-rule-header strong { font-size: 0.95rem; }
285
+ .policy-rule-remove { background: transparent; border: none;
286
+ color: var(--text-secondary); cursor: pointer; font-size: 1.1rem;
287
+ padding: 0 6px; }
288
+ .policy-rule-remove:hover { color: var(--danger); }
289
+ .policy-predicate-list { list-style: none; padding: 0; margin: 6px 0; }
290
+ .policy-predicate-row { padding: 4px 0; display: flex; align-items: center;
291
+ gap: 8px; flex-wrap: wrap; }
292
+ .policy-predicate-row code { background: var(--bg); padding: 3px 8px;
293
+ border-radius: 4px; font-size: 0.8rem; color: var(--text); }
294
+ .policy-predicate-row button { background: transparent; border: none;
295
+ color: var(--accent); cursor: pointer; font-size: 0.8rem; padding: 2px 4px; }
296
+ .policy-predicate-row button:hover { text-decoration: underline; }
297
+ .policy-add-predicate { background: transparent; border: 1px dashed var(--border);
298
+ color: var(--accent); padding: 6px 12px; border-radius: 6px;
299
+ cursor: pointer; font-size: 0.85rem; margin-top: 4px; }
300
+ .policy-add-predicate:hover { background: var(--surface-hover); }
301
+ .policy-predicate-form { background: var(--bg); padding: 10px;
302
+ margin: 6px 0; border: 1px dashed var(--border); border-radius: 6px;
303
+ display: flex; flex-direction: column; gap: 8px; }
304
+ .policy-predicate-form .policy-form-row { display: flex; flex-wrap: wrap;
305
+ gap: 6px; align-items: center; }
306
+ .policy-predicate-form .policy-form-label { min-width: 90px;
307
+ color: var(--text-secondary); font-size: 0.82rem; }
308
+ .policy-predicate-form select,
309
+ .policy-predicate-form input { padding: 5px 8px; border-radius: 4px;
310
+ border: 1px solid var(--border); background: var(--surface);
311
+ color: var(--text); font-size: 0.85rem; }
312
+ .policy-predicate-form input.policy-predicate-path-custom { min-width: 200px; }
313
+ .policy-predicate-form input.policy-predicate-value { min-width: 220px;
314
+ font-family: monospace; }
315
+ .policy-predicate-form .policy-form-hint { font-size: 0.75rem;
316
+ color: var(--text-secondary); padding-left: 96px; margin-top: -4px; }
317
+ .policy-predicate-form-error { color: var(--danger); font-size: 0.78rem;
318
+ width: 100%; margin-top: 4px; }
319
+ .policy-rule-lifetime { margin: 10px 0; font-size: 0.85rem;
320
+ color: var(--text-secondary); }
321
+ .policy-rule-lifetime input { width: 64px; padding: 4px 8px;
322
+ background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
323
+ color: var(--text); font-size: 0.85rem; margin: 0 6px; }
324
+ .policy-save-status { margin-left: 10px; font-size: 0.8rem;
325
+ color: var(--text-secondary); }