Skip to content

feat(typos-format): per-file typos autofix hook plugin#880

Closed
kyle-sexton wants to merge 1 commit into
mainfrom
feat/831-typos-format-hook-plugin
Closed

feat(typos-format): per-file typos autofix hook plugin#880
kyle-sexton wants to merge 1 commit into
mainfrom
feat/831-typos-format-hook-plugin

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Summary

New plugin — plugins/typos-format/ — a PostToolUse hook that runs typos -w on every
edited file, auto-fixing unambiguous spelling mistakes and surfacing residual (ambiguous)
findings via additionalContext. Zero-config: uses typos' built-in dictionary and the
consuming repo's own optional _typos.toml allowlist.

Fix

  • PostToolUse hook on Write|Edit, no extension filter (typos is a cross-language spell
    checker, not a single-ecosystem formatter) — typos --force-exclude -w --format json <file> runs against every edited file.
  • --force-exclude is load-bearing, not cosmetic: verified empirically (typos-cli 1.44.0)
    that without it, an explicitly-named file bypasses BOTH the consumer's [files] extend-exclude globs AND typos' own binary-file detection — an unflagged hook would
    scan every binary edit for garbage "typos". With it, both are honored.
  • Config/allowlist discovery is anchored on the edited file itself, not the hook's cwd
    (verified: an absolute file path checked from an unrelated working directory still
    resolves a _typos.toml several directories above it) — so, unlike markdownlint-cli2,
    this hook never needs to cd to the repo root.
  • typos -w --format json in one pass already yields exactly the residual findings —
    fixed typos never appear in that output (verified), so no separate fix-then-verify pass
    is needed (simpler than the markdown-format/ruff-format two-pass shape).
  • Exit codes (verified against typos-cli 1.44.0, undocumented beyond the CLI's own
    --format json note): 0 = clean, 2 = residual findings remain, anything else = the
    tool itself broke (bad config, internal error) rather than rendering a spelling judgment.
  • Advisory only: hook always exits 0. Kill switch: typos_format_enabled userConfig
    boolean (default true).
  • /typos-format:setup skill on the uniform check-centric contract (check read-only,
    apply guidance-only — every prerequisite is a PATH binary or the native toggle, so
    there is no write path).
  • Initial version 0.1.0 — confirmed via git log on bash-lint's (now bash-format)
    founding commit that a brand-new plugin's first plugin.json uses 0.1.0 with no
    CHANGELOG.md entry at creation; the changelog only starts recording at the first
    subsequent change. No clearer format-hook precedent exists for a from-scratch plugin.

Verification

  • bash plugins/typos-format/hooks/typos-format.test.sh — 63/64 assertions pass. The one
    failure (telemetry/slow-sink C1 fd1-leak timing, expects <2000ms) is a pre-existing
    platform-specific flake on this Windows/Git Bash machine, not introduced by this
    change: plugins/markdown-format/hooks/markdown-format.test.sh (untouched, already on
    main) fails the identical assertion on the same machine (5182ms vs. the 2000ms bound).
  • scripts/sync-hook-utils.sh --check — pass (11/11 plugin copies match lib/hook-utils.sh).
  • scripts/check-silent-skips.sh — pass (missing-typos/missing-jq paths use
    hook::notice_once + hook::emit_skip_notice).
  • scripts/check-changelog-parity.sh --check and --check-bump origin/main — pass.
  • node scripts/validate-plugin-contracts.mjs — pass (1913 plugin files checked).
  • node scripts/generate-catalog.mjs --check — pass (catalog in sync with marketplace.json).
  • claude plugin validate plugins/typos-format/ — pass.
  • Every empirical claim above (config-discovery anchor, --force-exclude behavior, exit
    codes, ambiguous-correction handling) was independently re-derived by hand against a real
    typos-cli 1.44.0 binary before this PR touched any file — see prior turns in the
    authoring session for the raw transcript.

Known gap, left as-is on purpose: CI's plugin-gate job does not install typos (unlike
shellcheck/biome/ruff, which it does install), so typos-format.test.sh will SKIP
there rather than execute its behavioral assertions — this mirrors the existing, documented
shfmt-optional precedent in scripts/run-plugin-tests.sh ("an individual test SKIPs when
an optional tool it needs is absent"). Provisioning typos onto the CI runner is a
separate, shared-ci.yml change outside this PR's scope.

Closes #831

Related

  • Epic: Epic: lint/static-analysis gap closure #830
  • Brief item 1, docs/topics/lint-static-analysis-gaps/PLAN.md
  • Templated from plugins/markdown-format/ (issue-named primary template) and
    plugins/ruff-format/ (closer analog for the config-driven exclude/discovery shape,
    e.g. --force-exclude rationale)

Provenance note

This worktree was briefed as "completely clean, no prior work" but already contained a
complete, uncommitted implementation (hook script, tests, README, CHANGELOG, setup skill,
plus marketplace.json/README.md edits) from an untracked prior session. Before building
on it, every non-trivial behavioral claim in the code/tests/docs was independently
re-verified by hand against a real typos binary (see Verification above) rather than
trusted as-is; nothing was taken on faith. It matched my own independent findings closely,
so it was kept rather than rewritten.

New plugin, mirroring the markdown-format/ruff-format hook shape: a
PostToolUse hook runs `typos --force-exclude -w --format json` against
every edited file (no extension filter — typos is a cross-language spell
checker), auto-fixing every unambiguous typo and surfacing residual
(ambiguous) findings via additionalContext, always advisory. Discovers the
consuming repo's own optional _typos.toml the way typos itself does
(anchored on the edited file, not the hook's cwd). Closes #831.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Superseded by #872, which independently implemented and merged the same plugins/typos-format/ plugin first (resolving issue #831). No cross-reconciliation needed — comparison against #872 found the trees equivalent except one material behavioral gap, filed as standalone follow-up #884 (and flagged directly on #872's own comment thread) since it's a real defect in already-merged code, not a paper-cut.

Closing this PR without merging.

@kyle-sexton
kyle-sexton deleted the feat/831-typos-format-hook-plugin branch July 22, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated Opened by automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(typos-format): per-file typos autofix hook plugin

1 participant