[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "retio-pagemap" version = "1.1.1" description = "MCP server for AI agent web browsing — converts raw HTML to structured page maps with 97% token reduction" requires-python = ">=3.11" license = {text = "AGPL-3.0-only"} authors = [{name = "Retio AI"}] readme = "README.md" keywords = [ "web-scraping", "ai-agent", "mcp", "html-compression", "playwright", "token-reduction", ] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Affero General Public License v3", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules", "Operating System :: OS Independent", ] dependencies = [ "mcp>=1.26.0,<2.0.0", "playwright>=1.40.0", "pydantic>=2.0.0", "lxml>=6.1.0", "tiktoken>=0.5.0", "beautifulsoup4>=4.9.0", "rapidfuzz>=3.0.0", "pyyaml>=6.0", "protego>=0.3.0", "structlog>=24.1.0", "uvicorn>=0.30.0", "aiosqlite>=0.22.0", "python-multipart>=0.0.27", ] [project.optional-dependencies] cli = [ "tabulate>=0.9.0", "rich>=13.0.0", ] benchmark = [ "anthropic>=0.40.0", "python-dotenv>=1.2.2", "readability-lxml>=0.8.0", "html2text>=2024.2.0", "firecrawl-py>=1.0.0", "httpx>=0.27.0", ] paddle = [ "paddle-python-sdk>=1.13.0", ] creem = [ "httpx>=0.27.0", ] redis = [ "redis>=5.2.0", ] supabase = [ "psycopg[binary]>=3.2.0", "psycopg-pool>=3.2.0", "PyJWT[crypto]>=2.12.0", ] metrics = [ "prometheus-client>=0.21", ] loadtest = [ "locust>=2.29", ] cqp = [ "ruptures>=1.1.10", "optuna>=4.5.0", "cryptography>=46.0.7", "scipy>=1.14", ] [dependency-groups] dev = [ "pytest>=9.0.3", "pytest-asyncio>=1.0", "pytest-cov>=6.0", "pytest-xdist>=3.5", "pytest-timeout>=2.3", "pytest-randomly>=3.15", "hypothesis>=6.100", "ruff>=0.4.0", "pip-audit>=2.10.0", "pip>=26.1", "bandit>=1.9.0", "httpx>=0.27.0", "schemathesis>=3.36.0", "syrupy>=4.0", "time-machine>=2.14", "aioresponses>=0.7", "scipy>=1.14", ] benchmark = [ "anthropic>=0.40.0", "python-dotenv>=1.2.2", "readability-lxml>=0.8.0", "html2text>=2024.2.0", "firecrawl-py>=1.0.0", "httpx>=0.27.0", "pyyaml>=6.0", "tabulate>=0.9.0", ] [project.urls] Homepage = "https://github.com/Retio-ai/pagemap" Repository = "https://github.com/Retio-ai/pagemap" Issues = "https://github.com/Retio-ai/pagemap/issues" [project.scripts] pagemap = "pagemap.cli:main" retio-pagemap = "pagemap.server:main" [tool.hatch.build.targets.wheel] packages = ["src/pagemap"] exclude = [ "src/pagemap/_internal/**", "src/pagemap/browser/**", "src/pagemap/core/config.yaml", ] [tool.hatch.build.targets.sdist] exclude = [ "src/pagemap/_internal/**", "src/pagemap/browser/**", "data/", "mvp/", "baseline/", "packages/", "docs/", "phase0/", "research/", "results/", "scripts/", "todo/", ".github/", ".claude/", ".claude-plugin/", ".cursor-plugin/", "skills/", "rules/", "mcp.json", ".playwright-mcp/", ".mcpregistry_*", ".env", ".env.example", ".mcp.json", ".mcp.json.example", "README.md", "README_DRAFT.md", "ROADMAP.md", "BUSINESS_PLAN_DRAFT.md", "DIRECTION.md", "AGPL_TRANSITION_CHECKLIST.md", "server.json", "smithery.yaml", "glama.json", "*.pdf", "uv.lock", ] [tool.ruff] target-version = "py311" line-length = 120 [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "UP", # pyupgrade "B", # flake8-bugbear "SIM", # flake8-simplify ] ignore = [ "E501", # line too long (handled by formatter) "SIM102", # nested if (often more readable than combined) "SIM108", # ternary operator ] [tool.ruff.lint.isort] known-first-party = ["pagemap"] combine-as-imports = true [tool.bandit] exclude_dirs = ["tests", "src/pagemap/_internal"] skips = [ "B101", # assert — internal invariant checks ] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" timeout = 30 addopts = "--strict-markers -ra" markers = [ "allow_real_get_session: opt out of the _block_real_browser safety net", "snapshot: requires data/snapshots/ test data", "smoke: CLI smoke tests (subprocess-based, no network by default)", "network: requires network access and Playwright Chromium", "fuzz: property-based fuzz tests (hypothesis)", "slow: slow tests (contract testing, SSRF fuzzing)", ] [tool.coverage.run] source = ["pagemap"] omit = ["src/pagemap/_internal/*", "src/pagemap/__main__.py", "src/pagemap/cli.py"] [tool.coverage.report] fail_under = 60 show_missing = true exclude_lines = [ "pragma: no cover", "if TYPE_CHECKING:", "if __name__ == .__main__.", "@overload", "raise NotImplementedError", ]