#
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 MindTenet LLC. All rights reserved.
# SPDX-License-Identifier: AGPL-3.0-or-later
#

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "undef-terminal"
dynamic = ["version"]
description = "Shared terminal I/O primitives for the undef ecosystem"
readme = "README.md"
requires-python = ">=3.11"
license = "AGPL-3.0-or-later"
authors = [
  {name = "MindTenet LLC"},
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: System :: Networking",
    "Topic :: Terminals",
    "Framework :: FastAPI",
]
dependencies = ["undef-telemetry>=0.3"]

[project.urls]
Homepage = "https://github.com/undef-games/undef-terminal"
Repository = "https://github.com/undef-games/undef-terminal"

[project.optional-dependencies]
websocket = ["fastapi>=0.110", "websockets>=12.0"]
ssh       = ["asyncssh>=2.14"]
emulator  = ["pyte>=0.8"]
server    = ["fastapi>=0.110", "uvicorn>=0.24", "pyjwt>=2.9"]
cli       = ["fastapi>=0.110", "uvicorn>=0.24", "websockets>=12.0"]
client    = ["httpx>=0.27"]
all       = ["fastapi>=0.110", "asyncssh>=2.14", "pyte>=0.8", "uvicorn>=0.24", "websockets>=12.0", "pyjwt>=2.9", "httpx>=0.27", "fastmcp>=2.0"]
mcp = [
    "fastmcp>=2.0",
]

[project.scripts]
uterm = "undef.terminal.cli:main"
uterm-server = "undef.terminal.server.cli:main"
uterm-mcp = "undef.terminal.mcp.cli:main"

[tool.setuptools.dynamic]
version = {file = "VERSION"}

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.package-data]
"undef.terminal" = [
    "py.typed",
    "frontend/*",
    "frontend/app/*.js",
    "frontend/app/views/*.js",
    "frontend/app/widgets/*.js",
    "frontend/.vite/*",
    "frontend/assets/*",
]

[dependency-groups]
dev = [
    "asyncssh>=2.22.0",
    "bandit>=1.9",
    "codespell>=2.4.1",
    "detect-secrets>=1.5.0",
    "fastapi>=0.110",
    "httpx>=0.27",
    "hypothesis>=6.151.9",
    "mutmut>=3.3.1",
    "mypy>=1.19",
    "pip-audit>=2.7.0",
    "pip-licenses>=5.5.0",
    "pre-commit>=4.0",
    "pydantic>=2.0",
    "pyjwt>=2.9",
    "pyte>=0.8.2",
    "pytest>=9.0",
    "pytest-asyncio>=1.3",
    "pytest-cov>=7.0",
    "pytest-playwright>=0.7.2",
    "pytest-randomly>=3.15.0",
    "pytest-timeout>=2.4.0",
    "pytest-xdist>=3.8",
    "reuse>=6.2.0",
    "ruff>=0.15",
    "ty>=0.0.17",
    "uv>=0.10.7",
    "uvicorn>=0.24",
    "vulture>=2.14",
    "websockets>=16.0",
    "xenon>=0.9.3",
    "fastmcp>=2.0",
]

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
testpaths = ["tests"]
filterwarnings = [
    "ignore:websockets\\.legacy is deprecated; see .*:DeprecationWarning:websockets\\.legacy",
    "ignore:websockets\\.server\\.WebSocketServerProtocol is deprecated:DeprecationWarning:uvicorn\\.protocols\\.websockets\\.websockets_impl",
    "ignore:remove second argument of ws_handler:DeprecationWarning:websockets\\.legacy\\.server",
]
addopts = [
    "--import-mode=importlib",
    "-v",
    "--strict-markers",
    "--strict-config",
    "--tb=short",
    "-ra",
    "--ignore=tests/playwright/test_hijack.py",
    "--ignore=tests/playwright/test_server.py",
    "--cov=undef.terminal",
    "--cov-branch",
    "--cov-report=term-missing",
    "--cov-fail-under=100",
]

[tool.ruff]
line-length = 120
target-version = "py311"
exclude = [
    ".git",
    ".venv",
    "__pycache__",
    "packages/undef-terminal-cloudflare/python_modules",
]

[tool.ruff.lint]
select = [
    "E",
    "W",
    "F",
    "I",
    "N",
    "UP",
    "B",
    "C4",
    "SIM",
    "TCH",
    "PTH",
    "DTZ",
    "ICN",
    "ISC",
    "PERF",
    "PIE",
    "RET",
    "RSE",
    "TID",
    "S",
    "ARG",
    "RUF",
]
ignore = ["E501", "S104", "S112", "S311"]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401", "RUF022"]
"tests/**/*.py" = ["E402", "B905", "S101", "S105", "S106", "S110", "ARG", "TCH", "RUF003", "RUF012", "RUF015", "RUF043", "RUF059"]
"packages/**/tests/**/*.py" = ["E402", "B905", "S101", "S105", "S106", "S110", "ARG", "TCH", "RUF003", "RUF012", "RUF015", "RUF043", "RUF059"]

[tool.coverage.run]
source = ["undef.terminal"]
omit = ["tests/*"]
branch = true

[tool.coverage.report]
fail_under = 100
show_missing = true
skip_covered = false

[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_any_generics = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
follow_imports = "normal"
ignore_missing_imports = false
namespace_packages = true
explicit_package_bases = true
mypy_path = ["src"]

[[tool.mypy.overrides]]
module = [
    "undef.telemetry",
    "undef.telemetry.*",
    "structlog",
    "structlog.*",
]
ignore_missing_imports = true

[tool.ty.environment]
python-version = "3.11"

[tool.ty.rules]
# FastAPI/Starlette add_middleware(CORSMiddleware, ...) is the documented
# pattern; ty incorrectly rejects it due to incomplete starlette stubs.
invalid-argument-type = "ignore"
# asyncio.create_task(Awaitable[T]) requires a type: ignore[arg-type] for mypy;
# ty does not see the same error and reports the suppression as unused.
unused-type-ignore-comment = "ignore"

[tool.codespell]
skip = ".git,*.pyc,__pycache__,.venv,node_modules,uv.lock,*.mmd,src/undef/terminal/frontend/assets/*.js"
ignore-words-list = "ore,opps,wont,strat,nd,rade,ans"

[tool.bandit]
exclude_dirs = [
    "tests",
    "packages/undef-terminal-cloudflare/python_modules",
    "packages/undef-terminal-cloudflare/node_modules",
]

[tool.vulture]
min_confidence = 80
paths = ["src", "tests"]

[tool.xenon]
max_absolute = "C"
max_modules = "B"
max_average = "A"

[tool.mutmut]
paths_to_mutate = ["src/undef/terminal/"]
tests_dir = ["tests/"]
also_copy = ["scripts/"]
do_not_mutate = [
    "src/undef/terminal/frontend/",
    "src/undef/terminal/transports/",
    "src/undef/terminal/gateway.py",
    "src/undef/terminal/server/connectors/",
]
pytest_add_cli_args = ["--no-cov"]
pytest_add_cli_args_test_selection = [
    "-m",
    "not playwright",
    "--ignore=tests/playwright/test_hijack.py",
    "--ignore=tests/playwright/test_example.py",
    "--ignore=tests/playwright/test_frontend_coverage.py",
    "--ignore=tests/playwright/test_terminal_proxy.py",
    "--ignore=tests/example/test_server_e2e.py",
    "--ignore=tests/hijack/test_hypothesis.py",
    "--ignore=tests/e2e",
    "--ignore=tests/hijack/test_hypothesis_ordering.py",
]

[tool.uv.workspace]
members = [
    ".",
    "packages/undef-terminal-cloudflare",
]

[tool.uv.sources]
undef-terminal = { workspace = true }
undef-terminal-cloudflare = { workspace = true }
undef-telemetry = { path = "../undef-telemetry", editable = true }
