# pyproject.toml [build-system] build-backend = "maturin" requires = [ "maturin>=1.10,<1.16" ] [project] name = "diffctx" version = "1.16.0" description = "Selects the minimum code an LLM needs to review a git diff" readme = "README.md" keywords = [ "ai", "chatgpt", "claude", "code-analysis", "code-context", "code-review", "code-to-prompt", "codebase", "context", "context-selection", "diff-context", "directory-tree", "export", "git-diff", "json", "llm", "llm-context", "mcp", "model-context-protocol", "tree", "yaml", ] license = "Apache-2.0" authors = [ { name = "Nikolay Eremeev", email = "nikolay.eremeev@outlook.com" }, ] requires-python = ">=3.10" classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Version Control :: Git", "Topic :: Utilities", "Typing :: Typed", ] dependencies = [ "pathspec>=0.11,<2.0", ] optional-dependencies.dev = [ "black>=23.0.0,<27.0", "charset-normalizer>=3.0,<4.0", "coverage>=7.0,<8.0", "hypothesis>=6.0,<7.0", "import-linter>=2.0,<3.0", "mypy>=1.0,<3.0", "pre-commit>=3.0,<5.0", "pygit2>=1.12,<2.0", "pytest>=7.0,<10.0", "pytest-asyncio>=0.23,<2.0", "pytest-cov>=3.0,<8.0", "pytest-timeout>=2.1,<3.0", "pytest-xdist>=3.0,<4.0", "pyyaml>=6.0.2,<8.0", "radon>=6.0,<7.0", "ruff>=0.4,<1.0", "tiktoken>=0.9,<1.0", "types-pyyaml>=6.0,<7.0", ] optional-dependencies.full = [ "charset-normalizer>=3.0,<4.0", ] optional-dependencies.mcp = [ "anyio>=4.5,<5.0", # <2.0 is deliberate, not staleness. MCP Python SDK v2 renamed `FastMCP` to # `MCPServer` and moved it from `mcp.server.fastmcp` to `mcp.server.mcpserver`, # so 2.x fails at import here. Widening the bound also drops every client on # 1.x, which is a compatibility decision rather than a version bump — tracked # separately. Migration guide: https://py.sdk.modelcontextprotocol.io/migration/ "mcp>=1.27,<2.0", ] urls.Author = "https://nikolay-eremeev.com" urls.Changelog = "https://github.com/nikolay-e/diffctx/blob/main/CHANGELOG.md" urls.Documentation = "https://nikolay-e.github.io/diffctx/" urls.Homepage = "https://nikolay-e.github.io/diffctx/" urls.Issues = "https://github.com/nikolay-e/diffctx/issues" urls.Paper = "https://doi.org/10.5281/zenodo.18824579" urls.Repository = "https://github.com/nikolay-e/diffctx" scripts.diffctx = "diffctx.cli:main" scripts.diffctx-mcp = "diffctx.mcp.server:main" [dependency-groups] # The research harness. One resolver, one lock (uv.lock): this used to be a # second pip stack (requirements-eval.txt + .lock) with its own bot. eval = [ "charset-normalizer>=3.0,<4.0", "datasets>=5.0.1,<6.0", "huggingface-hub>=1.27.0,<2.0", "numpy>=2.2.6,<3.0", "pathspec>=0.11,<2.0", "pebble>=5.2.1,<6.0", "pyyaml>=6.0,<7.0", "rank-bm25>=0.2.2,<1.0", "scipy>=1.15.3,<2.0", "tiktoken>=0.8,<1.0", ] [tool.maturin] python-source = "src" module-name = "diffctx._diffctx" manifest-path = "crates/diffctx-native/Cargo.toml" features = [ "pyo3/extension-module", "python" ] # The version is patched in every surface by the cd.yml release bump; that # step is the single list of where it lives. include = [ { path = "LICENSE", format = "sdist" }, { path = "README.md", format = "sdist" }, { path = "CHANGELOG.md", format = "sdist" }, { path = "Cargo.toml", format = "sdist" }, { path = "Cargo.lock", format = "sdist" }, { path = "crates/diffctx-native/Cargo.toml", format = "sdist" }, { path = "crates/diffctx-native/src/**/*", format = "sdist" }, { path = "rust-toolchain.toml", format = "sdist" }, ] [tool.black] line-length = 130 target-version = [ "py310" ] [tool.ruff] target-version = "py310" line-length = 130 lint.select = [ "C901", "E", "F", "I", "N", "RUF", "UP", "W" ] lint.ignore = [ "E501" ] # Line length handled by black lint.mccabe.max-complexity = 15 [tool.pyproject-fmt] column_width = 130 keep_full_version = true [tool.pytest] ini_options.testpaths = [ "tests" ] ini_options.pythonpath = [ "src" ] ini_options.norecursedirs = [ ".git", ".mypy_cache", ".pytest_cache", "__pycache__", ".hypothesis" ] ini_options.addopts = "-n auto --dist worksteal" ini_options.truncation_limit_lines = 100 ini_options.timeout = 30 ini_options.asyncio_mode = "auto" [tool.coverage] run.branch = true run.omit = [ "*/__pycache__/*" ] run.source = [ "diffctx" ] report.exclude_lines = [ "@(abc\\.)?abstractmethod", "if __name__ == .__main__.:", "if TYPE_CHECKING:", "pragma: no cover", ] report.fail_under = 40 report.show_missing = true report.skip_empty = true [tool.mypy] python_version = "3.10" strict = true warn_return_any = true warn_unused_configs = true disallow_untyped_calls = true disallow_untyped_defs = true disallow_incomplete_defs = true check_untyped_defs = true no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = true warn_no_return = true warn_unreachable = true files = [ "src" ] [[tool.mypy.overrides]] module = [ "mcp", "mcp.server", "mcp.server.fastmcp", "mcp.types", "anyio", "anyio.*", "diffctx._diffctx", "pathspec", "charset_normalizer", ] ignore_missing_imports = true [[tool.mypy.overrides]] module = [ "diffctx.ignore", "diffctx.tree", ] disable_error_code = [ "type-arg" ] [[tool.mypy.overrides]] module = [ "diffctx.mcp.*" ] disallow_untyped_decorators = false [tool.commitizen] name = "cz_conventional_commits" tag_format = "v$version" version_files = [ "src/diffctx/version.py:__version__", "CITATION.cff:^version" ] [tool.importlinter] root_package = "diffctx" [[tool.importlinter.contracts]] id = "no-cli-writer" name = "CLI should not import writer directly" type = "forbidden" source_modules = [ "diffctx.cli" ] forbidden_modules = [ "diffctx.writer" ] allow_indirect_imports = true [[tool.importlinter.contracts]] id = "no-tree-cli" name = "Tree building should not import CLI" type = "forbidden" source_modules = [ "diffctx.tree" ] forbidden_modules = [ "diffctx.cli" ] [[tool.importlinter.contracts]] id = "no-diffctx-writer" name = "Native adapters should not import writer" type = "forbidden" source_modules = [ "diffctx._native" ] forbidden_modules = [ "diffctx.writer" ] [[tool.importlinter.contracts]] id = "no-mcp-cli" name = "MCP server must not import CLI" type = "forbidden" source_modules = [ "diffctx.mcp" ] forbidden_modules = [ "diffctx.cli", "diffctx._app" ] [[tool.importlinter.contracts]] id = "no-writer-cli" name = "Writer should not import CLI" type = "forbidden" source_modules = [ "diffctx.writer" ] forbidden_modules = [ "diffctx.cli" ] [[tool.importlinter.contracts]] id = "no-tree-writer" name = "Tree building should not import writer" type = "forbidden" source_modules = [ "diffctx.tree" ] forbidden_modules = [ "diffctx.writer" ]