Development¶
make build # rebuild the C++ extensions (_core, _opt)
make test # unit tests
make test-tty # PTY-driven curses integration tests (slow, requires xterm-256color)
make lint # ruff check
make typecheck # mypy
make qa # lint + typecheck + test + format (Python and TypeScript)
Desktop frontend¶
make web-build # compile the desktop app's React client into web/static/
make web-run # launch the desktop app (needs web-build first)
make web-dev # Vite dev server with HMR, against a mock bridge
make web-jstest # vitest suite for the client
make test-web # Playwright tests driving the built bundle in headless Chromium
Documentation¶
make docs # build the site into site/ (strict: broken links fail)
make docs-serve # live-reloading preview on http://127.0.0.1:8000
make docs-deploy # publish to the gh-pages branch via mkdocs gh-deploy
make docs-clean # remove the built site
The site is MkDocs with the Material theme, configured in mkdocs.yml, and its dependencies live in the docs dependency group rather than in dev -- uv run --group docs pulls them only when the site is built. The API reference is generated by mkdocstrings, which reads the sources statically, so building the docs does not require the compiled extensions.
make docs-deploy commits to and pushes the gh-pages branch. It is a deliberate manual step; nothing in CI publishes the site.
Packaging¶
make wheel # cpXX-cpXX wheel for current Python
make wheel-abi3 # single cp312-abi3 wheel (Python>=3.12)
make sdist # source distribution
make publish # upload to PyPI (after make check)
The abi3 build is gated on GRIDCALC_STABLE_ABI=ON (CMake) plus wheel.py-api=cp312 (scikit-build-core). Per-version wheels and the abi3 wheel have separate CI workflows under .github/workflows/.
Tests¶
Tests are pytest, in tests/, roughly mirroring the source layout, and run with GRIDCALC_SANDBOX=1 so sandbox validation is always active. tests/integration/test_tui_pty.py drives the real curses app over a pty.
The web frontend's automated layers run against substitutes -- vitest in happy-dom, and a Chromium suite against a mocked bridge -- so scripts/drive_web.py (make web-drive) exists to drive the shipped bundle against the shipped engine in the real webview, with screenshots. It needs a display and is excluded from make qa.