""" Machine model for technician's machines used for MSP work. Tracks laptops, desktops, and workstations with their capabilities, installed tools, MCP servers, and skills. """ from datetime import datetime from typing import TYPE_CHECKING, Optional from sqlalchemy import Boolean, Index, Integer, String, Text, TIMESTAMP from sqlalchemy.orm import Mapped, mapped_column, relationship from .base import Base, TimestampMixin, UUIDMixin if TYPE_CHECKING: from .session import Session class Machine(Base, UUIDMixin, TimestampMixin): """ Machine model representing technician's machines used for MSP work. Tracks machine identification, capabilities, installed tools, MCP servers, skills, and network context. Machines are auto-detected on session start using hostname, username, platform, and home directory. Attributes: hostname: Machine hostname from `hostname` command machine_fingerprint: SHA256 hash of hostname + username + platform + home_directory friendly_name: Human-readable name like "Main Laptop" or "Home Desktop" machine_type: Type of machine (laptop, desktop, workstation, vm) platform: Operating system platform (win32, darwin, linux) os_version: Operating system version username: Username from `whoami` command home_directory: User home directory path has_vpn_access: Whether machine can connect to client networks vpn_profiles: JSON array of available VPN profiles has_docker: Whether Docker is installed has_powershell: Whether PowerShell is installed powershell_version: PowerShell version if installed has_ssh: Whether SSH is available has_git: Whether Git is installed typical_network_location: Typical network location (home, office, mobile) static_ip: Static IP address if applicable claude_working_directory: Primary working directory for Claude Code additional_working_dirs: JSON array of additional working directories installed_tools: JSON object with tool versions available_mcps: JSON array of available MCP servers mcp_capabilities: JSON object with MCP capabilities available_skills: JSON array of available skills skill_paths: JSON object mapping skill names to paths preferred_shell: Preferred shell (powershell, bash, zsh, cmd) package_manager_commands: JSON object with package manager commands is_primary: Whether this is the primary machine is_active: Whether machine is active last_seen: Last time machine was seen last_session_id: UUID of last session from this machine notes: Additional notes about the machine """ __tablename__ = "machines" # Machine identification (auto-detected) hostname: Mapped[str] = mapped_column( String(255), nullable=False, unique=True, doc="Machine hostname from `hostname` command" ) machine_fingerprint: Mapped[Optional[str]] = mapped_column( String(500), unique=True, doc="SHA256 hash: hostname + username + platform + home_directory" ) # Environment details friendly_name: Mapped[Optional[str]] = mapped_column( String(255), doc="Human-readable name like 'Main Laptop' or 'Home Desktop'" ) machine_type: Mapped[Optional[str]] = mapped_column( String(50), doc="Type of machine: laptop, desktop, workstation, vm" ) platform: Mapped[Optional[str]] = mapped_column( String(50), doc="Operating system platform: win32, darwin, linux" ) os_version: Mapped[Optional[str]] = mapped_column( String(100), doc="Operating system version" ) username: Mapped[Optional[str]] = mapped_column( String(255), doc="Username from `whoami` command" ) home_directory: Mapped[Optional[str]] = mapped_column( String(500), doc="User home directory path" ) # Capabilities has_vpn_access: Mapped[bool] = mapped_column( Boolean, default=False, server_default="0", doc="Whether machine can connect to client networks" ) vpn_profiles: Mapped[Optional[str]] = mapped_column( Text, doc="JSON array of available VPN profiles" ) has_docker: Mapped[bool] = mapped_column( Boolean, default=False, server_default="0", doc="Whether Docker is installed" ) has_powershell: Mapped[bool] = mapped_column( Boolean, default=False, server_default="0", doc="Whether PowerShell is installed" ) powershell_version: Mapped[Optional[str]] = mapped_column( String(20), doc="PowerShell version if installed" ) has_ssh: Mapped[bool] = mapped_column( Boolean, default=True, server_default="1", doc="Whether SSH is available" ) has_git: Mapped[bool] = mapped_column( Boolean, default=True, server_default="1", doc="Whether Git is installed" ) # Network context typical_network_location: Mapped[Optional[str]] = mapped_column( String(100), doc="Typical network location: home, office, mobile" ) static_ip: Mapped[Optional[str]] = mapped_column( String(45), doc="Static IP address if applicable (supports IPv4/IPv6)" ) # Claude Code context claude_working_directory: Mapped[Optional[str]] = mapped_column( String(500), doc="Primary working directory for Claude Code" ) additional_working_dirs: Mapped[Optional[str]] = mapped_column( Text, doc="JSON array of additional working directories" ) # Tool versions installed_tools: Mapped[Optional[str]] = mapped_column( Text, doc="JSON object with tool versions like {\"git\": \"2.40\", \"docker\": \"24.0\"}" ) # MCP Servers & Skills available_mcps: Mapped[Optional[str]] = mapped_column( Text, doc="JSON array of available MCP servers" ) mcp_capabilities: Mapped[Optional[str]] = mapped_column( Text, doc="JSON object with MCP capabilities" ) available_skills: Mapped[Optional[str]] = mapped_column( Text, doc="JSON array of available skills" ) skill_paths: Mapped[Optional[str]] = mapped_column( Text, doc="JSON object mapping skill names to paths" ) # OS-Specific Commands preferred_shell: Mapped[Optional[str]] = mapped_column( String(50), doc="Preferred shell: powershell, bash, zsh, cmd" ) package_manager_commands: Mapped[Optional[str]] = mapped_column( Text, doc="JSON object with package manager commands" ) # Status is_primary: Mapped[bool] = mapped_column( Boolean, default=False, server_default="0", doc="Whether this is the primary machine" ) is_active: Mapped[bool] = mapped_column( Boolean, default=True, server_default="1", doc="Whether machine is currently active" ) last_seen: Mapped[Optional[datetime]] = mapped_column( TIMESTAMP, doc="Last time machine was seen" ) last_session_id: Mapped[Optional[str]] = mapped_column( String(36), doc="UUID of last session from this machine" ) # Notes notes: Mapped[Optional[str]] = mapped_column( Text, doc="Additional notes about the machine" ) # Relationships sessions: Mapped[list["Session"]] = relationship( "Session", back_populates="machine", doc="Sessions associated with this machine" ) # Indexes __table_args__ = ( Index("idx_machines_hostname", "hostname"), Index("idx_machines_fingerprint", "machine_fingerprint"), Index("idx_machines_is_active", "is_active"), Index("idx_machines_platform", "platform"), ) def __repr__(self) -> str: """String representation of the machine.""" return f""