[project] name = "storepilot" version = "0.1.1" description = "StorePilot — one MCP server to run your entire app portfolio across Google Play and the App Store" readme = "README.md" requires-python = ">=3.11" license = { text = "MIT" } authors = [{ name = "Son Le" }] keywords = ["mcp", "google-play", "app-store-connect", "android", "ios", "automation"] dependencies = [ "mcp[cli]>=2.0.0", "google-api-python-client>=2.140.0", "google-auth>=2.34.0", "google-cloud-storage>=2.18.0", "httpx>=0.27.0", "pyjwt[crypto]>=2.9.0", "pydantic>=2.8.0", "pydantic-settings>=2.4.0", ] [project.optional-dependencies] dev = [ "pytest>=8.0", "pytest-asyncio>=0.23", "ruff>=0.6.0", # Optional: `pytest --cov=storepilot` uses the [tool.coverage] config below. # The default `pytest` run does not require it. "pytest-cov>=5.0", ] [project.scripts] storepilot = "storepilot.server:main" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/storepilot"] [tool.ruff] line-length = 100 target-version = "py311" [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] # `not live` is in the default options, not just documented: a live test must # never run because someone forgot a flag. Run them deliberately with # `pytest -m live`, which needs real credentials and real network access. addopts = "-m 'not live' --strict-markers --strict-config" markers = [ "live: requires real store credentials and network access; excluded by default", ] [tool.coverage.run] source = ["src/storepilot"] branch = true [tool.coverage.report] # Not a target to chase — the useful signal is which money/policy paths are # unexercised, not the percentage. show_missing = true exclude_also = [ "if TYPE_CHECKING:", "raise NotImplementedError", "\\.\\.\\.", ]