feat: add config profiles

- Add ConfigProfile and ConfigProfileInclude data models with migrations
- Implement profile resolver service with ordered includes and merge rules
- Add profile CRUD API with validation, compatibility, and cycle detection
- Add instance API plumbing for profile selection on create/start/restart
- Add resolved profile preview and default resolution APIs
- Add frontend config profile API client and management UI
- Add launch/restart profile selection UI
- Add backend integration and unit tests (31 passing)

OpenSpec: add-config-profiles
Quality gates: ruff, TypeScript compile, 31 tests passing
This commit is contained in:
2026-05-24 17:58:39 +00:00
parent 4de312c170
commit 9ad11a021c
23 changed files with 3136 additions and 125 deletions
+5
View File
@@ -9,6 +9,7 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
from src.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
if TYPE_CHECKING:
from src.models.config_profile import ConfigProfile
from src.models.git_repository import GitRepository
from src.models.project import Project
from src.models.tool_type import ToolType
@@ -71,8 +72,12 @@ class ToolInstance(UUIDPrimaryKeyMixin, TimestampMixin, Base):
branch: Mapped[str | None] = mapped_column(
String(255), nullable=True, default="main"
)
selected_config_profile_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(), ForeignKey("config_profiles.id", ondelete="SET NULL"), nullable=True
)
tool_type: Mapped["ToolType"] = relationship()
repository: Mapped["GitRepository"] = relationship()
project: Mapped["Project"] = relationship()
owner: Mapped["User"] = relationship()
selected_config_profile: Mapped["ConfigProfile | None"] = relationship()