Skip to content

Releases: smixs/code-quality

1.3.3 — advice, never a block

Choose a tag to compare

@smixs smixs released this 28 Sep 07:46

The plugin now advises and never blocks. It trusts the agent the way a good reviewer trusts a colleague: it measures, shows its work and says loudly when something is dangerous; the agent decides and says why.

What's new in 1.3.3

  • No hook stops the agent. pre-commit, commit-msg and pre-push print their report and let git go on; only an interrupt (Ctrl-C) stops it. The shell guard no longer denies --no-verify, commit -n or core.hooksPath: the command runs and a red flag sits next to its output.
  • Red flags first. Dangerous moves open every output as one line: RED FLAG: <what you are doing> -- <why it is dangerous>; check: <what to verify>. They cover a secret in the change or the pushed history, a deleted, skipped or weakened test, a baseline refreshed with the code, red touched tests on push, and a git command that skips the hooks. Secret checks stay.
  • The Stop hook never holds the turn. The user sees the red flags at once; the agent gets the full report once, with its next message (agent-notes on UserPromptSubmit in Claude Code and Codex, the next-turn channel in pi and omp, a message without a reply in OpenCode). Grok drops UserPromptSubmit context, so there the report reaches the user only.
  • Findings are advice. CRAP, complexity, diff coverage, cycles, dead code, clones, glossary, AI attribution and Jev appear under FINDINGS (n), advice, nothing blocked: or as notes. check, the full run and mutant still exit 1 on findings, so a script or CI can decide for itself.
  • [hooks] flag_bypass replaces block_bypass (still read); false silences the shell guard's flag.

Verified: 407 tests; live git hooks in a scratch repository (a commit with a secret, a deleted test, a push with red tests all go through with the flags first); a live Claude Code session where the turn ended after one answer and the next message carried the red flag verbatim.

Upgrade: claude plugin update code-quality@code-quality, or your agent's plugin update. Running install-hooks again is not needed: the hooks pick up the new copy the next time an agent runs. No config change is needed.

1.3.2

Choose a tag to compare

@smixs smixs released this 27 Sep 10:45

Touched-test acceptance now finds every test that can break: check --tests and mutant follow the project's imports to the end, resolve modules the way the project does, and keep the coverage that tests write from child processes.

What's new in 1.3.2

  • Every test that reaches the change. check --tests and mutant select the whole chain of importers (imports, re-exports, dynamic imports, require, and path strings in tests), not two steps. On a real bun monorepo a change to a shared utility now selects 109 of the 109 tests that depend on it (1.3.1: 23). pre-push is unchanged.
  • Modules resolve like the project resolves them. The nearest tsconfig.json paths (through extends, TypeScript key precedence), package.json#imports (#lib/*), and workspace packages by name (exports, including the string form, module, main).
  • Coverage from child processes counts. The built-in node, bun, vitest and pytest commands write their report under $QG_DIR and append it to $QG_LCOV instead of replacing the file; the exit code stays the tests'.
  • Broken lcov is refused everywhere. The full gate, a plain check and --skip-tests check the lcov structure before any CRAP number; an orphan or repeated end_of_record is invalid coverage.
  • mutant_timeout_s defaults to 900 s, as touched_timeout_s: a mutant on a shared module now runs every dependent test.

Verified: 404 tests; live runs on two real consumer repositories (a TypeScript agent and a bun monorepo), including a shared module with 576 dependent test files (check --tests GATE PASS, mutant KILLED).

Upgrade: claude plugin update code-quality@code-quality, or your agent's plugin update. No config change is needed.

1.3.1 — accept a change by its own tests

Choose a tag to compare

@smixs smixs released this 27 Sep 07:38

A lead can now accept an agent's change by the tests that change touches, prove that a test catches a real bug, and trust that the pushed commit, not the local checkout, is what the gate judged.

What's new

1.3.0

  • check --since <base> --tests runs the tests the change touches (by name, by import, and one more hop through a test harness) with coverage in a private run folder, then judges only the changed functions. Old debt does not block.
  • mutant --file <path> --find <text> --replace <text> [--test <path>] makes one exact mutation, runs the tests, and prints KILLED, SURVIVED or ERROR. The file is restored byte for byte after every outcome, Ctrl-C included; a mutant left by a killed run is restored on the next start.
  • One test executor for the full gate, check --tests, pre-push and mutant: it waits while the machine is busy (1-minute load above 2 × CPU, up to 10 minutes, then runs) and kills the whole test process group on a timeout or Ctrl-C.
  • pre-push judges the pushed commit: when the push has touched tests to run, pushing a commit other than the checked-out one, or with uncommitted changes in the files the touched tests read, is refused with the reason.
  • New [tests] keys (touched_cmd, mutant_cmd, max_load, load_wait_s, touched_timeout_s, mutant_timeout_s) are protected like the rest of .quality.toml.
  • New acceptance skill: the runbook for accepting a change — a spec with a failure table, one parallel pass on a frozen candidate, one batched repair, two rounds.

1.3.1

  • Touched tests include X.<anything>.test.ts for X.tsx and test files that name a repository file by a path string, so render tests that load a harness by path are selected.
  • A bun.lock or bun.lockb at the root makes a package.json project a bun project for touched runs and mutant.
  • Only the agent entry points (agent-stop, guard-bash) move the machine's git hook pointers; a copy run by hand never takes them.
  • mutant reports a malformed state file as MUTANT ERROR with the state paths; lcov DA lines count only inside their SF record.

Verified: 381 tests; live runs on two real consumer repositories (a TypeScript agent and a bun monorepo).

Upgrade: claude plugin update code-quality@code-quality, or your agent's plugin update. No config change is needed.

1.0.0 — one gate, every agent

Choose a tag to compare

@smixs smixs released this 23 Sep 03:52

code-quality is now a plugin, not only a skill. One repository installs into Claude Code, Codex, Grok, pi, omp and opencode; the agent hooks run without the model having to remember the skill.

What's new

  • Plugin packaging: .claude-plugin/ (Claude Code, Grok, omp), .codex-plugin/ + marketplace (Codex), pi/omp package, opencode plugin (V1 and V2). The skill lives in skills/code-quality/.
  • Stop hook in every harness: the agent is sent back once with the gate's reasons.
  • Bypass guard: git commit --no-verify / -n (also FOO=1 git …, bundled -nm), -c core.hooksPath=… and git config core.hooksPath are refused in repositories with .quality.toml. Switch: [hooks] block_bypass = false.
  • Inline suppressions no longer hide gate rules: eslint-disable complexity, # noqa: C901, //nolint:gocyclo and friends are ignored by the analyzers, and a new suppression in the diff is itself a tamper finding.
  • Git hooks install into a stable shim (~/.local/share/code-quality, override with CODE_QUALITY_HOME), so plugin updates don't break them.
  • Grok 1.0.40 does not run plugin hooks yet: bun scripts/quality.ts install-grok-hooks wires them globally.

Verified live: Claude Code, Codex and Grok (stop, bypass refusal, switch). pi fully, omp partly, opencode via adapter handlers. 218 tests.

Breaking: SKILL.md moved to skills/code-quality/, git hooks moved from hooks/ to git-hooks/; rerun install-hooks in your repositories.