feat: implement tool workshop - comprehensive tool system enhancement
- Add Docker Compose and Dockerfile support for tool definitions - Implement readiness probes with configurable command, timeout, interval - Create ConfigFolder model for reusable file collections with project overrides - Add rich tool config fields: port_override, start_command, working_directory, env vars, volumes - Build unified Tool Workshop UI at /tool-workshop replacing /tool-configs and /tool-types - Update instance creation to support dockerfile builds, config folder mounting, readiness probes - Add 3 database migrations for tool_types, tool_configs, and new config_folders table - Create docker_build.py and readiness_probe.py services - Add config_folders API with CRUD and project override endpoints Quality gates: frontend build passes, Python syntax valid, all phases complete Addresses tool-workshop OpenSpec change
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from src.models.base import Base
|
||||
from src.models.config_folder import ConfigFolder
|
||||
from src.models.git_repository import GitRepository
|
||||
from src.models.project import Project
|
||||
from src.models.ssh_key import SSHKey
|
||||
@@ -7,4 +8,4 @@ from src.models.tool_type import ToolType
|
||||
from src.models.user import User
|
||||
from src.models.user_config import UserConfig
|
||||
|
||||
__all__ = ["Base", "GitRepository", "Project", "SSHKey", "ToolInstance", "ToolType", "User", "UserConfig"]
|
||||
__all__ = ["Base", "ConfigFolder", "GitRepository", "Project", "SSHKey", "ToolInstance", "ToolType", "User", "UserConfig"]
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, ForeignKey, JSON, String, Text
|
||||
from sqlalchemy import Uuid as UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from src.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.models.user import User
|
||||
|
||||
|
||||
class ConfigFolder(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
__tablename__ = "config_folders"
|
||||
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
mount_path: Mapped[str] = mapped_column(String(1024), nullable=False)
|
||||
files: Mapped[dict] = mapped_column(
|
||||
JSON, default=dict, nullable=False
|
||||
) # {"relative/path": "content", ...}
|
||||
project_overrides: Mapped[dict | None] = mapped_column(
|
||||
JSON, default=dict, nullable=True
|
||||
) # {"project_id": {"mount_path": "...", "files": {...}}}
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
|
||||
user: Mapped["User"] = relationship()
|
||||
@@ -33,6 +33,15 @@ class ToolConfig(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
file_path: Mapped[str | None] = mapped_column(
|
||||
String(1024), nullable=True
|
||||
) # Only for file type
|
||||
port_override: Mapped[int | None] = mapped_column(nullable=True)
|
||||
start_command: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
working_directory: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
environment_variables: Mapped[dict | None] = mapped_column(
|
||||
JSON, default=dict, nullable=True
|
||||
)
|
||||
volumes: Mapped[list[dict] | None] = mapped_column(
|
||||
JSON, default=list, nullable=True
|
||||
)
|
||||
|
||||
user: Mapped["User"] = relationship()
|
||||
tool_type: Mapped["ToolType"] = relationship()
|
||||
|
||||
@@ -20,7 +20,15 @@ class ToolType(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
category: Mapped[str] = mapped_column(String(50), nullable=False, default="other")
|
||||
interfaces: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
|
||||
default_port: Mapped[int] = mapped_column(nullable=False)
|
||||
compose_template: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
definition_type: Mapped[str] = mapped_column(
|
||||
String(20), nullable=False, default="compose"
|
||||
) # "compose" or "dockerfile"
|
||||
compose_template: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
dockerfile_template: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
build_context: Mapped[dict | None] = mapped_column(
|
||||
JSON, default=dict, nullable=True
|
||||
)
|
||||
readiness_probe: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
required_variables: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
|
||||
is_builtin: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
created_by_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
|
||||
Reference in New Issue
Block a user