Files
strukto-ai--mirage/.pre-commit-config.yaml
bytecii 3293cb5ff4 feat(py): mirage mcp over stdio, and invert the mypy allowlist
Two cleanup-plan items, both Python-side.

Item 29 -- `mirage mcp`. TypeScript shipped a six-tool stdio MCP server;
Python had none, so a pip-install user could not point Cursor or Claude
Desktop at a workspace and `mirage --help` differed by distribution.
Adding the entry point alone would have duplicated the tools, because
this side kept them private inside the Claude Agent SDK integration, so
the shared layer comes first:

  - agents/tool_descriptions.py -- the six strings, one copy.
  - agents/tool_operations.py -- MirageToolOperations, lifted out of the
    SDK server's private _MirageTools.
  - agents/file_version.py -- stale-write protection, which this side
    lacked entirely. TS stamps stored bytes; here the stamp covers the
    rendered bytes, because this read tool has always rendered and an
    edit must search what the agent was actually shown.
  - agents/mcp/server.py + cli/mcp.py -- the server and `mirage mcp`.
  - server/workspace_config.py -- config discovery (candidates, env
    names, walk up from cwd), which Python had nowhere, so every entry
    point had to be handed an explicit path.

The server is the low-level MCP Server rather than FastMCP: FastMCP does
not forward a version, and TS advertises one. Handlers are bound methods,
not decorated closures, so nothing nests.

Item 28 -- the mypy allowlist. 54 modules opted *in* to annotation
checking against 1826, so the default was unchecked and every new file
joined the unchecked side. The default is now strict, with a list of
what is not yet annotated that only shrinks. 166 annotations cleared
along the way; the remainder is named module by module.

Two real defects surfaced by the annotations, neither of them typing:

  - Workspace._original_open / _original_os were invented by assignment
    in lifecycle.patch_process, so unpatch without a patch raised
    AttributeError. Declared, and the restore is guarded.
  - sed_generic declared a non-optional writer while its own docstring
    and its `write_bytes is None` branch said otherwise; the builder
    passes None whenever the backend cannot write.

Tests keep the PathSpec rule instead of full strict: measured, full
strict on python/tests is 2374 errors, of which 634 are `str` where a
pydantic field declares SecretStr -- which pydantic coerces at runtime --
and most of the rest is the monkeypatched-fake pattern CLAUDE.md
sanctions. The rule that is violated for real is PathSpec, 19 times, and
scripts/check_test_pathspec.py now holds that line. One of the 19 was a
latent AttributeError: tests/e2e passes a str to s3 write_bytes, which
reads .mount_path, and the test skips without a live versioned bucket.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 03:33:16 -07:00

171 lines
4.8 KiB
YAML

ci:
# https://pre-commit.ci/#configuration
autofix_prs: true
autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions'
autoupdate_schedule: monthly
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: no-commit-to-branch
name: No commits to master
- id: end-of-file-fixer
name: End-of-file fixer
exclude: |
(?x)^(
typescript/.*|
integ/truth\.txt|
integ/fixtures/.*
)$
- name: mixed-line-ending
id: mixed-line-ending
args: [--fix, lf]
exclude: |
(?x)^(
typescript/.*|
integ/truth\.txt|
integ/fixtures/.*
)$
- id: trailing-whitespace
name: Remove trailing whitespaces
exclude: |
(?x)^(
typescript/.*|
integ/truth\.txt|
integ/fixtures/.*
)$
- id: check-toml
name: Check toml
- id: check-yaml
name: Check yaml
exclude: |
(?x)^(
conda/pytorch-geometric/meta.yaml|
conda/pyg/meta.yaml|
typescript/.*
)$
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.37.1
hooks:
- id: yamllint
name: Lint yaml
args: [-d, '{extends: default, rules: {line-length: disable, document-start: disable, truthy: {level: error}, braces: {max-spaces-inside: 1}}}']
exclude: ^typescript/
- repo: https://github.com/asottile/pyupgrade
rev: v3.21.0
hooks:
- id: pyupgrade
name: Upgrade Python syntax
args: [--py38-plus]
- repo: https://github.com/PyCQA/autoflake
rev: v2.3.1
hooks:
- id: autoflake
name: Remove unused imports and variables
args: [
--remove-all-unused-imports,
--remove-unused-variables,
--remove-duplicate-keys,
--ignore-init-module-imports,
--in-place,
]
- repo: https://github.com/google/yapf
rev: v0.43.0
hooks:
- id: yapf
name: Format code
additional_dependencies: [toml]
# Generated tables are laid out by their generator, which packs
# ranges several to a line so 349 of them stay reviewable.
# Reformatting them here would fight scripts/gen_width_table.py on
# every run, the same way typescript/.prettierignore already exempts
# `**/generated/**`.
exclude: |
(?x)^(
python/mirage/utils/generated/.*
)$
- repo: https://github.com/pycqa/isort
rev: 7.0.0
hooks:
- id: isort
name: Sort imports
exclude: |
(?x)^(
python/mirage/utils/generated/.*
)$
- repo: https://github.com/PyCQA/flake8
rev: 7.3.0
hooks:
- id: flake8
name: Check PEP8
args: [--toml-config=python/pyproject.toml]
additional_dependencies: [Flake8-pyproject]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.3
hooks:
- id: ruff
name: Ruff formatting
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.22
hooks:
- id: mdformat
name: Format Markdown
additional_dependencies:
- mdformat-gfm
- mdformat_frontmatter
- mdformat_footnote
exclude: |
(?x)^(
test/data/cursor\.md|
typescript/.*
)$
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.1
hooks:
- id: sphinx-lint
name: Check Sphinx
- repo: local
hooks:
- id: ts-prettier
name: Prettier (typescript)
entry: typescript/scripts/precommit-run.sh prettier --write
language: system
files: ^typescript/.*\.(ts|tsx|js|mjs|cjs|json|md|yaml|yml)$
pass_filenames: true
- id: ts-eslint
name: ESLint (typescript)
entry: typescript/scripts/precommit-run.sh eslint --fix --no-warn-ignored
language: system
files: ^typescript/.*\.(ts|tsx|js|mjs|cjs)$
pass_filenames: true
- id: ts-knip
name: Knip (typescript dead code)
entry: bash -c 'cd typescript && pnpm exec knip'
language: system
files: ^typescript/.*\.(ts|tsx|js|mjs|cjs|json)$
pass_filenames: false
- id: py-mypy
name: Type check (mypy)
entry: bash -c 'cd python && uv run mypy'
language: system
files: ^python/(mirage/.*\.py|tests/.*\.py|pyproject\.toml)$
pass_filenames: false
- id: py-test-pathspec
name: PathSpec discipline (tests)
entry: python3 scripts/check_test_pathspec.py
language: system
files: ^python/(mirage/.*\.py|tests/.*\.py)$
pass_filenames: false