from __future__ import annotations import hashlib import time from dataclasses import dataclass, field from enum import StrEnum class CheckStatus(StrEnum): PASS = "pass" WARN = "warn" FAIL = "fail" SKIP = "skip" class Severity(StrEnum): INFO = "info" WARNING = "warning" ERROR = "error" class DoctorRepairMode(StrEnum): NONE = "none" YES = "yes" REPAIR = "repair" FORCE = "force" NON_INTERACTIVE = "non_interactive" DEEP = "deep" @dataclass class DoctorOptions: repair_mode: DoctorRepairMode = DoctorRepairMode.NONE deep: bool = False generate_gateway_token: bool = False workspace_suggestions: bool = True @property def should_repair(self) -> bool: return self.repair_mode in (DoctorRepairMode.REPAIR, DoctorRepairMode.FORCE, DoctorRepairMode.YES) @property def should_force(self) -> bool: return self.repair_mode == DoctorRepairMode.FORCE @property def is_non_interactive(self) -> bool: return self.repair_mode in ( DoctorRepairMode.NON_INTERACTIVE, DoctorRepairMode.REPAIR, DoctorRepairMode.YES, ) @dataclass class CredentialCheckResult: status: CheckStatus token_obtained: bool expires_in: int | None = None error: str | None = None detail: dict = field(default_factory=dict) @dataclass class PermissionCheckResult: status: CheckStatus can_send_message: bool = False can_read_message: bool = False can_manage_group: bool = False missing_permissions: list[str] = field(default_factory=list) error: str | None = None @dataclass class ConnectivityCheckResult: status: CheckStatus latency_ms: float | None = None endpoint: str = "" error: str | None = None @dataclass class DiagnosisWarning: severity: Severity code: str message: str suggestion: str @dataclass class LegacyConfigRule: old_key: str new_key: str transform: str | None = None @dataclass class ConfigMutation: description: str = "" old_value: str = "" new_value: str = "" key: str = "" version: int = 0 timestamp: float = field(default_factory=time.time) operator: str = "system" reason: str = "" checksum: str = "" def __post_init__(self): if not self.checksum: self.checksum = self._compute_checksum() def _compute_checksum(self) -> str: payload = f"{self.key}|{self.description}|{self.old_value}|{self.new_value}" return hashlib.sha256(payload.encode("utf-8")).hexdigest() @dataclass class ChannelStatusWarning: channel_type: str account_id: str status: CheckStatus message: str detail: dict = field(default_factory=dict) @dataclass class RepairStep: id: str description: str action: str reversible: bool = True params: dict = field(default_factory=dict) requires_interactive: bool = False is_aggressive: bool = False @dataclass class RepairResult: step_id: str success: bool message: str config_before: dict | None = None config_after: dict | None = None @dataclass class DiagnosisResult: channel_type: str account_id: str overall_status: CheckStatus timestamp: float credential: CredentialCheckResult | None = None permission: PermissionCheckResult | None = None connectivity: ConnectivityCheckResult | None = None config_before: dict | None = None config_after: dict | None = None config_changes: list[ConfigMutation] = field(default_factory=list) warnings: list[DiagnosisWarning] = field(default_factory=list) security_warnings: list[str] = field(default_factory=list) channel_status_warnings: list[ChannelStatusWarning] = field(default_factory=list) repair_plan: list[RepairStep] = field(default_factory=list) repair_results: list[RepairResult] = field(default_factory=list) def to_dict(self) -> dict: result: dict = { "channel_type": self.channel_type, "account_id": self.account_id, "overall_status": self.overall_status.value, "timestamp": self.timestamp, "credential": self._credential_dict(), "permission": self._permission_dict(), "connectivity": self._connectivity_dict(), "config_before": self.config_before, "config_after": self.config_after, "config_changes": [ { "key": c.key, "description": c.description, "old_value": c.old_value, "new_value": c.new_value, "version": c.version, "timestamp": c.timestamp, "operator": c.operator, "reason": c.reason, "checksum": c.checksum, } for c in self.config_changes ], "warnings": [ {"severity": w.severity.value, "code": w.code, "message": w.message, "suggestion": w.suggestion} for w in self.warnings ], "security_warnings": self.security_warnings, "channel_status_warnings": [ { "channel_type": c.channel_type, "account_id": c.account_id, "status": c.status.value, "message": c.message, "detail": c.detail, } for c in self.channel_status_warnings ], "repair_plan": [ { "id": s.id, "description": s.description, "action": s.action, "reversible": s.reversible, "params": s.params, "requires_interactive": s.requires_interactive, "is_aggressive": s.is_aggressive, } for s in self.repair_plan ], "repair_results": [ { "step_id": r.step_id, "success": r.success, "message": r.message, "config_before": r.config_before, "config_after": r.config_after, } for r in self.repair_results ], } return result def _credential_dict(self) -> dict | None: if not self.credential: return None return { "status": self.credential.status.value, "token_obtained": self.credential.token_obtained, "expires_in": self.credential.expires_in, "error": self.credential.error, } def _permission_dict(self) -> dict | None: if not self.permission: return None return { "status": self.permission.status.value, "can_send_message": self.permission.can_send_message, "can_read_message": self.permission.can_read_message, "can_manage_group": self.permission.can_manage_group, "missing_permissions": self.permission.missing_permissions, "error": self.permission.error, } def _connectivity_dict(self) -> dict | None: if not self.connectivity: return None return { "status": self.connectivity.status.value, "latency_ms": self.connectivity.latency_ms, "endpoint": self.connectivity.endpoint, "error": self.connectivity.error, }