"""Wiki structure and status models."""
from __future__ import annotations
from pathlib import Path
from typing import Any
from pydantic import BaseModel, Field
from local_deepwiki.models.chunks import FileInfo
class IndexStatus(BaseModel):
"""Status of repository indexing."""
repo_path: str = Field(description="Path to the repository")
indexed_at: float = Field(description="Timestamp of last indexing")
total_files: int = Field(description="Total files processed")
total_chunks: int = Field(description="Total chunks extracted")
languages: dict[str, int] = Field(
default_factory=dict, description="Files per language"
)
files: list[FileInfo] = Field(default_factory=list, description="Indexed file info")
schema_version: int = Field(
default=1, description="Schema version for migration support"
)
def __repr__(self) -> str:
"""Return a concise representation for debugging."""
return (
f"<IndexStatus {self.repo_path} "
f"({self.total_files} files, {self.total_chunks} chunks)>"
)
class WikiPage(BaseModel):
"""A generated wiki page."""
path: str = Field(description="Relative path in wiki directory")
title: str = Field(description="Page title")
content: str = Field(description="Markdown content")
generated_at: float = Field(description="Generation timestamp")
def __repr__(self) -> str:
"""Return a concise representation for debugging."""
return f"<WikiPage {self.path} ({self.title!r})>"
class WikiStructure(BaseModel):
"""Structure of the generated wiki."""
root: str = Field(description="Wiki root directory")
pages: list[WikiPage] = Field(default_factory=list, description="All wiki pages")
def __repr__(self) -> str:
"""Return a concise representation for debugging."""
return f"<WikiStructure {self.root} ({len(self.pages)} pages)>"
def to_toc(self) -> dict[str, Any]:
"""Generate table of contents."""
toc: dict[str, Any] = {"sections": []}
for page in sorted(self.pages, key=lambda p: p.path):
parts = Path(page.path).parts
current = toc
for part in parts[:-1]:
section = next(
(s for s in current.get("sections", []) if s["name"] == part), None
)
if not section:
section = {"name": part, "sections": [], "pages": []}
current.setdefault("sections", []).append(section)
current = section
current.setdefault("pages", []).append(
{"path": page.path, "title": page.title}
)
return toc
class WikiPageStatus(BaseModel):
"""Status of a generated wiki page for incremental generation."""
path: str = Field(description="Wiki page path (e.g., 'files/src/module/file.md')")
source_files: list[str] = Field(
default_factory=list, description="Source files that contributed to this page"
)
source_hashes: dict[str, str] = Field(
default_factory=dict, description="Mapping of source file path to content hash"
)
source_line_info: dict[str, dict[str, int]] = Field(
default_factory=dict,
description="Mapping of source file path to {start_line, end_line}",
)
structural_fingerprint: str = Field(
default="",
description="Structural fingerprint for summary pages (empty for file-level pages)",
)
content_hash: str = Field(description="Hash of the generated page content")
generated_at: float = Field(description="Timestamp when page was generated")
def __repr__(self) -> str:
"""Return a concise representation for debugging."""
return f"<WikiPageStatus {self.path} ({len(self.source_files)} sources)>"
class WikiGenerationStatus(BaseModel):
"""Status of wiki generation for tracking incremental updates."""
repo_path: str = Field(description="Path to the repository")
generated_at: float = Field(description="Timestamp of last generation")
total_pages: int = Field(description="Total pages generated")
index_status_hash: str = Field(
default="", description="Hash of index status for detecting changes"
)
pages: dict[str, WikiPageStatus] = Field(
default_factory=dict, description="Mapping of page path to status"
)
def __repr__(self) -> str:
"""Return a concise representation for debugging."""
return f"<WikiGenerationStatus {self.repo_path} ({self.total_pages} pages)>"