from sqlalchemy import ForeignKey, Integer, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from scribe.models import Base from scribe.models.base import TimestampMixin class RepoBinding(Base, TimestampMixin): """Maps a git repository to the Scribe project it represents. The SessionStart hook sends the working repo's normalized remote (`repo_key`, e.g. ``git.fabledsword.com/bvandeusen/fabledscribe``) and the server resolves it to a project — so the operator can work across many repos/projects without pinning a project id in plugin config. The key is a *stable identifier* (the git remote), not a dir-name heuristic. """ __tablename__ = "repo_bindings" __table_args__ = ( UniqueConstraint("user_id", "repo_key", name="uq_repo_bindings_user_repo"), ) id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) project_id: Mapped[int] = mapped_column( Integer, ForeignKey("projects.id", ondelete="CASCADE"), nullable=False ) repo_key: Mapped[str] = mapped_column(Text, nullable=False) def to_dict(self) -> dict: return { "id": self.id, "user_id": self.user_id, "project_id": self.project_id, "repo_key": self.repo_key, "created_at": self.created_at.isoformat(), "updated_at": self.updated_at.isoformat(), }