[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "timmy-time"
version = "1.0.0"
description = "Mission Control for sovereign AI agents"
readme = "README.md"
license = "MIT"
authors = ["Alexander Whitestone"]
homepage = "http://localhost:3000/rockachopa/Timmy-time-dashboard"
repository = "http://localhost:3000/rockachopa/Timmy-time-dashboard"
packages = [
    { include = "config.py", from = "src" },

    { include = "dashboard", from = "src" },
    { include = "infrastructure", from = "src" },
    { include = "integrations", from = "src" },
    { include = "spark", from = "src" },
    { include = "timmy", from = "src" },
    { include = "timmy_serve", from = "src" },
    { include = "timmyctl", from = "src" },
]

[tool.poetry.dependencies]
python = ">=3.11,<4"
agno = { version = ">=2.0.0,<3.0", extras = ["sqlite"] }
ollama = ">=0.3.0,<1.0"
openai = ">=1.0.0"
fastapi = ">=0.115.0,<1.0"
uvicorn = { version = ">=0.32.0,<1.0", extras = ["standard"] }
jinja2 = ">=3.1.0"
httpx = ">=0.27.0"
python-multipart = ">=0.0.12"
typer = ">=0.12.0"
rich = ">=13.0.0"
pydantic-settings = ">=2.0.0,<3.0"
mcp = ">=1.0.0"
# Optional extras
redis = { version = ">=5.0.0", optional = true }
celery = { version = ">=5.3.0", extras = ["redis"], optional = true }
python-telegram-bot = { version = ">=21.0", optional = true }
"discord.py" = { version = ">=2.3.0", optional = true }
airllm = { version = ">=2.9.0", optional = true }
pyttsx3 = { version = ">=2.90", optional = true }
openai-whisper = { version = ">=20231117", optional = true }
piper-tts = { version = ">=1.2.0", optional = true }
sounddevice = { version = ">=0.4.6", optional = true }
sentence-transformers = { version = ">=2.0.0", optional = true }
numpy = { version = ">=1.24.0", optional = true }
requests = { version = ">=2.31.0", optional = true }
GitPython = { version = ">=3.1.40", optional = true }
pytest = { version = ">=8.0.0", optional = true }
pytest-asyncio = { version = ">=0.24.0", optional = true }
pytest-cov = { version = ">=5.0.0", optional = true }
pytest-timeout = { version = ">=2.3.0", optional = true }
selenium = { version = ">=4.20.0", optional = true }
pytest-randomly = { version = ">=3.16.0", optional = true }
pytest-xdist = { version = ">=3.5.0", optional = true }

[tool.poetry.extras]
telegram = ["python-telegram-bot"]
discord = ["discord.py"]
bigbrain = ["airllm"]
voice = ["pyttsx3", "openai-whisper", "piper-tts", "sounddevice"]
celery = ["celery"]
embeddings = ["sentence-transformers", "numpy"]
git = ["GitPython"]
dev = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-timeout", "pytest-randomly", "pytest-xdist", "selenium"]

[tool.poetry.group.dev.dependencies]
pytest = ">=8.0.0"
pytest-asyncio = ">=0.24.0"
pytest-cov = ">=5.0.0"
pytest-timeout = ">=2.3.0"
selenium = ">=4.20.0"
pytest-randomly = "^4.0.1"
pytest-xdist = "^3.8.0"
ruff = ">=0.8.0"
mypy = ">=1.0.0"

[tool.poetry.scripts]
timmy = "timmy.cli:main"
timmy-serve = "timmy_serve.cli:main"
timmyctl = "timmyctl.cli:main"

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src", "tests"]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
timeout = 30
timeout_method = "signal"
timeout_func_only = false
addopts = "-v --tb=short --strict-markers --disable-warnings --durations=10"
markers = [
    "unit: Unit tests (fast, no I/O)",
    "integration: Integration tests (may use SQLite)",
    "functional: Functional tests (real HTTP requests, no mocking)",
    "e2e: End-to-end tests (full system, may be slow)",
    "dashboard: Dashboard route tests",
    "slow: Tests that take >1 second",
    "selenium: Requires Selenium and Chrome (browser automation)",
    "docker: Requires Docker and docker-compose",
    "ollama: Requires Ollama service running",
    "external_api: Requires external API access",
    "skip_ci: Skip in CI environment (local development only)",
]

[tool.ruff]
line-length = 100
target-version = "py311"
src = ["src", "tests"]

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "S"]
ignore = [
    # Mapped from existing bandit skips: B101→S101, B104→S104, etc.
    "S101", "S104", "S307", "S310", "S324", "S601", "S608",
    # Project patterns: graceful degradation (try/except pass), FastAPI Depends()
    "S110", "S112", "B008",
    # Subprocess usage in scripts/infrastructure
    "S603", "S607",
    # Non-cryptographic random is fine for non-security contexts
    "S311",
    # Line length handled by formatter; long strings/URLs can't always be broken
    "E501",
]

[tool.ruff.lint.isort]
known-first-party = ["config", "dashboard", "infrastructure", "integrations", "spark", "timmy", "timmy_serve"]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S"]

[tool.coverage.run]
source = ["src"]
omit = [
    "*/tests/*",
]

[tool.coverage.report]
show_missing = true
skip_empty = true
precision = 1
exclude_lines = [
    "pragma: no cover",
    "if __name__ == .__main__.",
    "if TYPE_CHECKING:",
    "raise NotImplementedError",
    "@abstractmethod",
]
# Fail CI if coverage drops below this threshold
fail_under = 73

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"
