What GitHub's generator said for the previous release
This is the body of the v0.5.11 release, made by --generate-notes.
It is one line. It names a pull request. It does not say what changed for a user.
## What's Changed
* Keep the new gate rules from tripping the scanner themselves (v0.5.11) by @gagoar in https://github.com/gagoar/typescript-patterns-enforcer/pull/26
**Full Changelog**: https://github.com/gagoar/typescript-patterns-enforcer/compare/v0.5.10...v0.5.11Source: the v0.5.11 release of gagoar/typescript-patterns-enforcer.
The foghorn draft for v0.6.0
This is the text of the final draft file. We did not change a word of it. The voice is foghorn.
Check TypeScript files written through a shell with an advisory Stop hook (#33)
The mechanical checks ran from a
PostToolUsehook, and that hook only sees files that the Edit and Write tools wrote. A.tsfile written by a shell heredoc or a script never reached the checks.With this release, the plugin also registers a
Stophook. When a session ends, it walks the working directory for.tsand.tsxfiles modified since the session began and runs the same checks on them. It skipsnode_modules,.git,dist,build,out,coverage,.next,.turboand.d.tsfiles. It is advisory: it reports throughsystemMessageand always exits 0, so it cannot trap a session.New output (a
.tsfile written through a shell, then the session stops):ts-patterns: mechanical violations in TypeScript files changed this session (the edit hook does not see files written through a shell): src/list.ts: L1:64 no-zero-comparison `.length` compared with zero: coerce it (`!!x.length`, `!x.length`) (see SKILL.md Core Rule 10).Add six syntactic checks: zero-length comparison, repeated literal, colon-annotated lookup table, fail-open default,
String()of an optional chain and void-returning guard (#35)The hook now flags six more patterns from the audit of the rules. Each check is syntactic only, because the engine has no type information, so each one matches a narrow shape:
no-zero-comparisonflags.lengthcompared with zero (> 0,=== 0,>= 1,< 1and the loose forms). It matches.lengthonly.repeated-literalflags the same string or template, at least 8 characters long, written 3 or more times in one file.colon-annotated-lookupflagsconst x: Record<K, V> = { ... }. Use{ ... } as const satisfies Record<K, V>so thatkeyof typeof xkeeps the literal keys. The check ignores an empty{}.fail-open-defaultflagscall() ?? ""andcall() ?? 0. The check ignores a property default such aserror.status ?? 0, an arithmetic operand and a template placeholder.string-of-optional-chainflagsString(a?.b), becauseString(undefined)is"undefined".void-guardflags a function namedguardorassert*that returnsvoid. Declareasserts conditionso that the narrowing reaches the caller.
Original code:
export function guard(condition: boolean, message: string): void { if (!condition) throw new Error(message); }Old output: none. The hook exited with code 0.
New output:
ts-patterns: 1 mechanical violation(s) in guard.ts: L1:8 void-guard `guard` returns void: declare `asserts condition` so the narrowing reaches the caller (see SKILL.md Core Rule 1). → SKILL.md Core Rule 1 — declare `asserts condition`The other five checks follow the same pattern.
Affects: anyone who runs the plugin on an existing TypeScript codebase. The
PostToolUsehook exits with code 2 when it finds a violation. An edit to a file that already contains one of these patterns now goes back to Claude for a fix.To check: pipe a hook payload to the engine, as in
echo '{"tool_input":{"file_path":"src/a.ts"}}' | node "${CLAUDE_PLUGIN_ROOT}/engine/dist/check.js".Stop the magic-number check from flagging numbers inside a named constant (#35)
Previously the check flagged every number in an arithmetic expression, even when the expression is the initial value of a
constthat names the result. The check also flagged a number inside anas consttable, although the table is the named constant.With this release, the check skips a number in the arithmetic of a
constinitializer and a number inside anas constliteral. This is a deliberate difference from typescript-eslint, which exempts only a bare initializer.Original code:
export const MAX_BYTES = 16 * 1024 * 1024;Old output:
ts-patterns: 3 mechanical violation(s) in magic.ts: L1:26 no-magic-numbers No magic number: 16. → SKILL.md Core Rule 9 — extract to a named const L1:31 no-magic-numbers No magic number: 1024. → SKILL.md Core Rule 9 — extract to a named const L1:38 no-magic-numbers No magic number: 1024. → SKILL.md Core Rule 9 — extract to a named constNew output: none. The hook exits with code 0.
Fold the audit findings into the check skill and the review agent (#32)
The
checkskill and thereviewagent gain the rules that the audit found. No mechanical check covers them. They are: hand-written library shapes, illegal states, fail-open defaults, cast laundering, repeated literals, string boundaries and small items. The review agent has new checklist items 18 to 24.Each finding now carries the label
correctnessorstyle. A change is done when nocorrectnessfinding remains. The skill's review checklist now asks you to print each item markedcheckedorn/a. It also covers files written through a shell.
What foghorn left out
The range held more changes than the draft shows. foghorn dropped these as internal:
- the docs redesign
- the icon
- the badge
- the CI gates
- the version bump
The rule is fixed. A change that only touches the documentation site, the README, badges, artwork, a CI gate, a consistency gate or the version number is internal. foghorn counts the dropped entries and tells you. You can correct a classification before it writes.
What to look for
Each entry names the thing and the change, and links its pull request. Each entry that changed behavior shows what the user sees. The second entry carries an Affects: line and a To check: line, because the change can break someone.
A person still has to read it. The checker looks for an example. It cannot prove that the example is true.