from datetime import datetime from typing import Optional, Any from uuid import UUID from pydantic import BaseModel, Field # ── Parameter schema types ────────────────────────────────────────────────── class ScriptParameterValidation(BaseModel): pattern: Optional[str] = None min_length: Optional[int] = None max_length: Optional[int] = None min_value: Optional[float] = None max_value: Optional[float] = None class ScriptParameter(BaseModel): key: str label: str type: str # text | password | select | boolean | multi_text | number | textarea required: bool = True placeholder: Optional[str] = None group: Optional[str] = None order: int = 0 help_text: Optional[str] = None options: Optional[list[dict]] = None # for select type: [{value, label}] default: Optional[Any] = None validation: Optional[ScriptParameterValidation] = None sensitive: bool = False # password fields → redacted in generation record class ScriptParametersSchema(BaseModel): parameters: list[ScriptParameter] # ── Category ──────────────────────────────────────────────────────────────── class ScriptCategoryResponse(BaseModel): id: UUID name: str slug: str description: Optional[str] = None icon: Optional[str] = None sort_order: int template_count: int = 0 class Config: from_attributes = True # ── Template ──────────────────────────────────────────────────────────────── class ScriptTemplateCreate(BaseModel): category_id: UUID name: str = Field(..., min_length=1, max_length=200) description: Optional[str] = None use_case: Optional[str] = None script_body: str = Field(..., min_length=1) parameters_schema: dict = Field(default_factory=dict) default_values: dict = Field(default_factory=dict) validation_rules: dict = Field(default_factory=dict) tags: list[str] = Field(default_factory=list) complexity: str = Field(default="beginner", pattern="^(beginner|intermediate|advanced)$") estimated_runtime: Optional[str] = None requires_elevation: bool = False requires_modules: list[str] = Field(default_factory=list) language: str | None = None class ScriptTemplateUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=200) description: Optional[str] = None use_case: Optional[str] = None script_body: Optional[str] = None parameters_schema: Optional[dict] = None default_values: Optional[dict] = None validation_rules: Optional[dict] = None tags: Optional[list[str]] = None complexity: Optional[str] = Field(None, pattern="^(beginner|intermediate|advanced)$") estimated_runtime: Optional[str] = None requires_elevation: Optional[bool] = None requires_modules: Optional[list[str]] = None is_active: Optional[bool] = None class ScriptTemplateListItem(BaseModel): id: UUID category_id: UUID team_id: Optional[UUID] = None created_by: Optional[UUID] = None name: str slug: str description: Optional[str] = None tags: list[str] complexity: str estimated_runtime: Optional[str] = None requires_elevation: bool requires_modules: list[str] is_verified: bool usage_count: int language: str | None = None class Config: from_attributes = True class ScriptTemplateDetail(ScriptTemplateListItem): use_case: Optional[str] = None script_body: str parameters_schema: dict default_values: dict validation_rules: dict version: int created_at: datetime updated_at: datetime class Config: from_attributes = True # ── Generation ─────────────────────────────────────────────────────────────── class ScriptGenerateRequest(BaseModel): template_id: UUID parameters: dict[str, Any] session_id: Optional[UUID] = None # Legacy tree-based session ai_session_id: Optional[UUID] = None # FlowPilot AI session class ScriptGenerateResponse(BaseModel): id: UUID script: str warnings: list[str] = Field(default_factory=list) metadata: dict class Config: from_attributes = True class ScriptGenerationRecord(BaseModel): id: UUID template_id: UUID template_name: str parameters_used: dict # passwords already redacted created_at: datetime class Config: from_attributes = True