Releases: W-Mai/Cha
1.20.0 - 2026-06-05
Release Notes
🎉 First minor since v1.0 — and the first release with a proper home on the web. https://cha.to01.icu is now a real product page, not just a README dump. Star the repo, share the link, and tell your linter Cha said hi.
The analyzer itself didn't move — every --version-visible behavior is identical to v1.19.0. What landed is the documentation, presentation, and integration story: somewhere we can actually point new users.
Added
- Bilingual documentation site at https://cha.to01.icu — landing page (oranda) plus a full mdbook tree at
/book/(English) and/book/zh-CN/(中文). 60+ pages covering install, quick-start, every CLI subcommand, every output format, LSP integration for VS Code / Helix / Neovim / Zed, configuration reference, JSON Schema, plugin development, six worked recipes (migrate from clippy, monorepo CI, suppress in legacy code, custom plugin in 50 lines, calibrate to your codebase, baseline workflow), three contributor guides (architecture, writing a smell, releasing), and an academic-references page tracing every smell back to its source. - Cookbook recipes — six task-oriented walkthroughs:
migrate-from-clippy,monorepo-ci,suppress-legacy,custom-plugin-50loc,calibrate,baseline. Each starts with a problem statement and ends with copy-pasteable commands. Authored in English and Chinese (the Chinese versions are written natively, not translated, so the prose style matches the rest of zh-CN). - Contributor guides —
contributing/architecture.mddocuments the seven-crate workspace and data flow with mermaid diagrams;writing-a-smell.mdwalks throughMiddleManAnalyzeras the worked example;releasing.mdis the runbook forcargo xtask bump→release. - Configuration reference — every
.cha.tomlkey, grouped by plugin, with thresholds and defaults sourced fromcha-core/src/plugins/. JSON Schema reference page documentingcha schemaoutput and how to wire it into IDEs. - Bilingual landing page (
LANDING.md) — hero with logo + tagline + three CTAs, six feature cards (detectors, WASM SDK, LSP, git-aware analysis, output formats, two-level cache), 30-second get-started block, smell-category table, and editor integration links. Replaces the previous "README dumped into the homepage" experience. - CJK-aware search via Pagefind 1.4 — replaces mdbook's bundled elasticlunr (which silently dropped non-ASCII tokens, leaving the zh-CN tree un-searchable). Press
sor/on any docs page to open a modal that indexes both language trees. - Per-page social meta + branded OG card — every page emits
og:title/og:image/twitter:cardso Slack / iMessage / 微信 link previews show a real card instead of a 32×32 favicon. The 1200×628 card embeds the Cha logo and is regenerable viapython3 static/gen_og_card.py. - Custom 404 page — site-wide warm-themed 404 with the Cha logo and shortcuts back into the live parts of the site, replacing GitHub Pages' generic gray 404.
- Language switcher in mdbook header — the toolbar globe icon switches between EN and zh-CN trees and remembers per-page equivalents.
xtask docs-check— verifies every page referenced inbook/src(-zh-CN)/SUMMARY.mdactually exists; runs as part ofcargo xtask ciso a broken SUMMARY can't ship.xtask i18n-check— flags zh-CN pages whose git ctime trails their English counterpart, surfacing translation drift.xtask docgen-cli— generatesbook/src/reference/cli-manual.mdfromcha help-markdownso the CLI manual page in docs always matches the binary's actual--help. Hiddencha help-markdownsubcommand added for this.- VS Code extension page — full inventory of what each LSP capability looks like inside VS Code (wavy underlines, lightbulbs, code-lens overlays, inlay hints, hover cards, semantic-token modifier, status-bar workspace scan progress) plus the
cha.disabledPluginssetting documentation.
Fixed
- tree-sitter S-expression query link — the link in
docs/plugin-development.mdand the zh-CN translation pointed at/syntax-highlighting/queries, which 404s on the current tree-sitter docs site. Updated to/using-parsers/queries/. docs/plugin-development.mdFunctionInfo/ClassInfofield tables — were bare struct dumps; now per-field semantic tables (type + what each field actually drives) for both languages.- README plugin table — every entry now has an anchor link into
docs/plugins.md's detailed description, in bothREADME.mdandREADME.zh-CN.md. The previousUnstableDependencyrow (which never matched a real detector) was removed andasync_callback_leakadded.
Changed
- Project homepage —
https://cha.to01.icuis the canonical entry point. README still works on github.com but now points at the docs site for anything beyond the quick-start. - CI — the
Webworkflow builds the EN tree via oranda, re-builds the zh-CN tree via mdbook withMDBOOK_BOOK__SRC=src-zh-CN, indexes both with Pagefind, and restorespublic/CNAME+ dropspublic/404.htmlafter oranda's clean. Deploys viaJamesIves/github-pages-deploy-action@v4.6.4.
Notes for upgraders
Nothing to do. cha analyze produces the same output, .cha.toml accepts the same keys, every CLI flag still works. This is a documentation release: the binary moves from "had a single README" to "had a 60-page bilingual docs site" without changing anything you'd notice from the terminal.
If you want to celebrate by reading something other than --help: https://cha.to01.icu.
Install cha-cli 1.20.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.20.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.20.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.20.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.19.0 - 2026-05-22
Release Notes
Hardcoded thresholds and keyword lists become plugin config; cha fix stops hardcoding smell names; the last two text-scanning detectors switch to AST queries.
Added
Plugin::try_fix(finding, ctx) -> Option<Patch>— every plugin can now contribute auto-fixes.cha fixwalks all enabled plugins and asks each one. Adding fix support for a new smell is one trait override, not a host-sideif smell_name == ...patch.cha_core::Patch/cha_core::TextEdit— public byte-range edit types for plugin authors. Edits within a single finding are applied in reverse byte-offset order.DesignPatternAdvisorconfig — 8 magic-number thresholds (strategy_min_arms,state_min_arms,builder_min_params,builder_alt_min_params,builder_alt_min_optional,null_object_min_count,template_min_self_calls,template_min_methods) and 2 keyword lists (type_field_keywords,state_field_keywords) are now overridable via[plugins.design_pattern].GodClassAnalyzer::min_tcc— Tight Class Cohesion threshold (Lanza-Marinescu's 1/3) is configurable.cache.rswalker skip-dirs — extended from{target, node_modules, dist}to also skipbuild,out,__pycache__,venv,.venv,vendor. Reduces unnecessary.cha.tomldiscovery work in polyglot repos.
Fixed
switch_statement/message_chain: replaced bespoke text scanners (find_switch_keyword,walk_chainand ~140 lines of hand-rolled tokenization) with tree-sitter queries againstswitch_statement/match_expression/field_expression/member_expression/selector_expression. Smell counts unchanged, but keyword positions are now sourced from the AST. No more false positives on keywords inside strings.inappropriate_intimacyimport resolution: extension probe expanded from{.ts, .tsx, .rs}to also include.py,.go,.cpp,.cc,.cxx,.c,.h,.hpp,.hxx,.js,.jsx,.mts,.cts. Sibling-file lookups in non-JS/Rust projects no longer silently fail.calibrate.rstable rendering: 3 metric labels were hardcoded across 3 separateprintlnblocks. Adding a calibration metric now means one entry in a(label, samples)array.
Changed
cha fixdelegates toPlugin::try_fixfor every finding — no morefilter(|f| f.smell_name == "naming_convention")on the host. Existing behavior preserved (NamingAnalyzer fixesnaming_conventionPascalCase violations); other plugins returnNoneuntil they opt in.
Install cha-cli 1.19.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.19.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.19.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.19.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.18.0 - 2026-05-22
Release Notes
Built-in detectors now use AST queries instead of text scanning. Several core plugins previously did substring matches that misfired on strings, comments, and unrelated identifiers.
Added
cha_core::query— host-side tree-sitter query helper (run_query/run_queries/node_to_match). Both built-in plugins and the WASMtree_queryhost import now go through this single API.DeadCodeAnalyzer::entry_points— entry-point names are now configurable via[plugins.dead_code] entry_points = [...]. Default list expanded from Rust-only (5 names) to multi-language (Rust + Python__init__etc + Goinit+ C_start+ tokio).LengthAnalyzer::complexity_factor_threshold— was hardcoded10.0, now configurable via[plugins.length].
Fixed
unsafe_api: rewritten from line-basedline.contains+ odd-quote-count heuristic to per-language tree-sitter queries. Picks up realsprintf/strcpy/strcat/systemcall sites that the line-based heuristic missed. Comments and string literals containing keywords likeunsafeno longer false-positive.dead_code: substringis_in_file_referencedreplaced with AST identifier scan. Token-concat macro detection rewritten — instead of nuking the entire file when any#define ... ##exists, parse define bodies forprefix##X##suffixslots, scan call sites for invocation arguments, synthesize plausible expansion names, and add them to the reference set. X-macro dispatch tables (e.g.STYLE_DEF) no longer hide every dispatch function.IdentifierPositionslookup is now O(1) per symbol viaHashMap<name, Vec<line>>.error_handling:unwrap_abuseuses tree-sitter ((call_expression field_expression unwrap|expect)); empty-catch detection is per-language (Rust skipped, TScatch_clause, Pythonexcept_clause). String literals and comments containing the substringunwraporcatchno longer trigger.hardcoded_secret: regex matches now run againststring_literalnode text only, not full source lines. Comments and identifier names with secret-like substrings no longer false-positive.cha fix:String::replacewhole-content substitution replaced with tree-sitter identifier-node range collection + byte-offset reverse substitution. The previous implementation could rewrite identifier names inside string literals and comments, corrupting source files.git_metrics::check_test_ratio:f.contains("test") || f.contains("spec")replaced withcha_core::is_test_path. The substring check wrongly countedrequest.rs/spectrum.rsetc. as test files, polluting the test-to-production ratio that driveslow_test_ratio.wasm.rs::infer_file_role: replaced duplicate test-path heuristics withcha_core::is_test_path. WASM plugins'FileRole::Testclassification now matches the canonical convention used elsewhere (__tests__/,__mocks__/,.test.ts,.spec.ts).find_macro_invocation_args: word-boundary check added —STYLE_DEFno longer matchesSTYLE_DEFINEinvocations.
Removed
unsafe_apiis_in_stringheuristic — superseded by tree-sitter queries that distinguish string literals at the AST level.error_handlingline-baseddetect_empty_catch— replaced with grammar-aware queries.HostState::query_cache— query compilation now lives incha_core::query(compile-on-demand; LRU caching to be added if measurement warrants).
Install cha-cli 1.18.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.18.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.18.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.18.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.17.0 - 2026-05-21
Release Notes
Added
project_query::function_at(path, line, col)— new host import returning theFunctionInfowhose body contains the given position. Useful for tree-query–driven detectors that need to disambiguate which declared function a queried position belongs to.WasmPluginTest::option_list / option_bool / option_int / option_float— list and typed option setters in the test harness, replacing the previous string-onlyoption().
Changed (breaking for WASM plugins)
tree_query::QueryMatch.start_line/end_lineare now 1-based (was 0-based). Aligns withFunctionInfo/ClassInfo/CommentInfoline numbering — no more per-plugin off-by-one conversion. Inputs tonode_at(line, col)andnodes_in_range(start, end)are likewise 1-based now.- Existing plugins compiled against the pre-1.17 WIT will need to be rebuilt against the new SDK; instantiation will fail loudly otherwise.
Fixed
react-hooksexample plugin — false positives onhook_after_early_return(in sibling components and inside return expressions likereturn useState()) eliminated by switching toproject_query::function_atfor host-function disambiguation. Now reports 5 true positives / 0 false positives on the 6-component .tsx fixture (was 5 / 2).
Documentation
docs/plugin-development.md: added Line/Column convention note, Project Query API section, WASM Compatibility Cheatsheet (regex panics, no clock, no FS),cha plugin buildvscargo builddistinction, and new option helpers in Testing.
Install cha-cli 1.17.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.17.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.17.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.17.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.16.0 - 2026-05-21
Release Notes
Added
TsxParserincha-parser—.tsxfiles now route to a parser usingtree_sitter_typescript::LANGUAGE_TSX, so JSX nodes (jsx_element,jsx_attribute,jsx_self_closing_element) are first-class AST citizens. WASM plugins can now match them viatree_query::run_query.examples/wasm-plugin-react-hooks— example WASM plugin demonstratingtree_queryintegration. Detects 5 React Rules of Hooks violations: hooks called from non-component functions, hooks in conditionals, hooks in loops, hooks after early return, and hooks in nested callbacks.examples/wasm-plugin-todo-tracker— example WASM plugin demonstrating extended TODO comment tracking beyond the builtintodo_tracker. Adds 5 new smells: extended tag set (BUG/WIP/OPTIMIZE/PERF/DEPRECATED + user-configurable extras),(by:YYYY-MM-DD)expiration, priority escalation (!/!!/!!!), per-file TODO hotspot detection, and required-attribution policy.
Notes
- WIT unchanged at
cha:plugin@0.3.0(no breaking change). - Routing for
.ts/.mts/.ctscontinues to useLANGUAGE_TYPESCRIPT. Only.tsxswitched.
Install cha-cli 1.16.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.16.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.16.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.16.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.15.0 - 2026-05-14
Release Notes
Added
ProjectQuerytrait incha-core— plugins now access cross-file data through a typed interface onAnalysisContext.projectinstead of host-side post-hoc string-matched filtering. 12 methods cover the project-level queries existing post-analysis passes need:is_called_externally,callers_of,function_home/function_by_name/class_home,is_third_party,workspace_crate_names,is_test_path, etc. WASM plugins also gain access via theproject-queryhost import.ProjectQueryBulktrait extendsProjectQueryfor in-process iteration (iter_models); not exposed to WASM.cha_core::is_test_path— public utility consolidating two duplicated implementations.- example-wasm
unused_helpersmell — demonstratesproject_query::callers_ofcallback.
Changed
- WIT bumped to
cha:plugin@0.3.0(breaking) — addsproject-queryhost import. External plugins compiled against0.2.0must rebuild. large_api_surfaceC/C++ heuristics —.h/.hppheaders are now skipped (their 100% public surface is by design);.c/.cppimplementation files use a higher count threshold (30, configurable asc_max_exported_count) and the ratio gate is effectively off (configurable asc_max_exported_ratio). lvgl baseline: 393 → 34 findings (-91%).dead_codeis now project-aware — usesProjectQuery::is_called_externallyto confirm cross-file usage; the per-file text search is just an early shortcut. The token-concat macro heuristic (#define ... ##) remains because parsers don't macro-expand. lvgl baseline: 67 → 6 findings (-91%).
Removed
Plugin::cross_file_aware_smellstrait method — replaced by typed query throughAnalysisContext.project.cha-cli::cross_file_filtermodule — the post-hoc string-matched filter is gone; plugins produce final findings using the typed trait.- 3 duplicated
workspace_crate_namesimpls + 3 duplicatedis_third_party/is_external_leakimpls + 2 duplicatedis_test_pathimpls — all consolidated.
Added
- New
.cha.tomlconfig keys forapi_surface:max_exported_ratio,c_max_exported_count,c_max_exported_ratio,skip_c_headers. All language-aware defaults preserved.
Install cha-cli 1.15.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.15.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.15.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.15.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.14.0 - 2026-05-14
Release Notes
Added
- Plugin AST Query API — WASM plugins can now execute tree-sitter queries against the current file's AST via the
tree-queryhost import interface (run-query,run-queries,node-at,nodes-in-range). Enables plugins to do custom structural pattern matching without reimplementing parsing. file-roleenum inanalysis-input— host infers whether a file issource,test,doc,config, orgeneratedfrom its path, allowing plugins to apply differential detection strategies.- SourceModel enrichment —
analysis-inputnow includescomments,type-aliases,parameter-names,switch-arm-values, andis-module-declfields previously only available to internal plugins. parse_file_full()incha-parser— returnsParseResultcarrying model + tree-sitterTree+Languagefor downstream use by WASM host callbacks.
Changed
- WIT bumped to
cha:plugin@0.2.0— breaking change: plugins compiled against0.1.0must be recompiled. No behavioral change for existing internal plugins.
Install cha-cli 1.14.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.14.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.14.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.14.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.13.1 - 2026-04-30
Release Notes
Added
abstraction_leak_surgerydetector — files that co-change in git history and share a third-party type in their function signatures. Upgrade of the classicshotgun_surgery: instead of "these files always change together" (agnostic of why), this pinpoints "these files always change together because they all depend on the same external type" — the shared external type is the concrete abstraction leak driving the co-change cascade. SeverityHint.- Inputs: git co-change counts (
git log --name-only -N, threshold ≥ 5 commits in last 100) × per-fileTypeOrigin::Externalsets derived from parameter / return types. Workspace-sibling crates auto-whitelisted (same mechanismcross_boundary_chain/leaky_public_signatureuse), socha_core-internal dependencies betweencha-parser/cha-clidon't fire. - Cha self-baseline: 10 genuine findings, all pointing at the 5 language parsers sharing
tree_sitter::Node— exactly the abstraction leak the detector is designed to find (tree-sitter upgrades ripple across every parser file). lvglsrc/: 0 (C project, no External origins).
- Inputs: git co-change counts (
Install cha-cli 1.13.1
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.13.1/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.13.1/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.13.1
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.13.0 - 2026-04-30
Release Notes
Added
primitive_representationdetector (roadmap S8.2). Flags function parameters whose name carries a domain concept (user_id,email,status_code,api_url,password,language, …) but whose type is a raw scalar primitive (String,i32,bool,char, …). Signals an opportunity to introduce a newtype / value object to preserve the invariant. Per-parameter detection groups all offending params of one function into a single hint. Complements the existingprimitive_obsession(which looks at per-function ratio): this fires on even a single param when it's clearly a business concept.- Business-token and noise-token vocabularies are deliberately narrow to keep signal-to-noise high. Substring matches are ruled out (tokens must be standalone words —
widget_identifierdoes not trigger onid). - Parameters already typed with project-local newtypes (e.g.
id: UserIdwhereUserIdisTypeOrigin::Local) are skipped — the author already did the right thing. - Container types (
Path,PathBuf,Vec,Arc,Box,HashMap, …) are treated as domain-carrying and excluded; wrappingpath: &Pathin a newtype would destroy the abstraction. - Only runs on
is_exportedfunctions — private helpers are noise for a design signal aimed at public API hygiene. - Cha self-analyze: 14 findings (all genuine —
rel_path/env_hash/language/key/hashas raw types). lvglsrc/baseline: 53 findings (TTFplatformID/encodingID/languageID/nameID: int, file-explorerpath/dir: charpointers, …).
- Business-token and noise-token vocabularies are deliberately narrow to keep signal-to-noise high. Substring matches are ruled out (tokens must be standalone words —
stringly_typed_dispatchdetector (roadmap S8.8). Flags functions whoseswitch/matchbody dispatches on ≥ 3 string or ≥ 3 integer literal arms — classic "the arm values should have been an enum" smell. Char-literal arms (C tokenisers) skipped. Enum-variant / structural-pattern arms classify asOtherand never contribute to the threshold, somatch event { Event::Click => …, Event::Scroll => …, _ => … }stays quiet whilematch s { "click" => …, "scroll" => …, "submit" => … }fires. SeverityHint. Complements S8.2primitive_representation(signature side) with the body-side dispatch signal.- New
cha_core::ArmValueenum (Str / Int / Char / Other) +FunctionInfo.switch_arm_values+FunctionSymbol.switch_arm_values. Populated by every parser via a new sharedcha-parser/src/switch_arms.rshelper — language-specific arm-node kinds funnel through one classifier. - Cha self-baseline: 20 findings (all node-kind dispatchers in the 6 language parsers — valid detections, users can add
// cha:ignore stringly_typed_dispatchif the dispatch shape is forced by tree-sitter). lvglsrc/baseline: 23 findings (PNG/JPEG/QR error-code dispatchers, color-format size tables, TTF bytecode interpreter).
- New
cross_boundary_chaindetector (roadmap S8.U4). Flags functions wherechain_depth ≥ 3and the chain's root parameter is externally-typed (TypeOrigin::External(crate)) — the function is reaching into a third-party library's internal field layout, not just over-chaining local data. Companion to the existingmessage_chain(which fires on depth regardless of source):cross_boundary_chainis narrower but a stronger abstraction-leak signal. SeverityHint.- Workspace crates are auto-whitelisted (same mechanism
leaky_public_signatureuses), so siblingcha_core::Findingtraversals inside this repo don't fire. Cha self-baseline: 4 findings, all genuinetree_sitter::Nodetraversals incha-parser. lvglsrc/baseline: 0 (C project, fewExternalorigins by design). - Zero parser changes — reuses
chain_depth,parameter_types(with origin),parameter_names,external_refs. Pure post-pass onProjectIndex.
- Workspace crates are auto-whitelisted (same mechanism
FunctionInfo.parameter_names+FunctionSymbol.parameter_names(cha-core). Parallel toparameter_types: identifier names in declaration order. All six parsers (Rust / TS / Python / Go / C / C++) extract these;self/ C++thispositions skipped to stay length-aligned withparameter_types. Enables name-semantic analyses likeprimitive_representation, future LSP hover with full signatures, futurecha summary.- New helpers
cha_parser::rust_imports::rust_param_namesandcha_parser::cpp::c_param_nameextract identifier names from their language's declarator chains; reused across all C/C++ function-definition sites.
Install cha-cli 1.13.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.13.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.13.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.13.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
1.12.0 - 2026-04-28
Release Notes
Added
SymbolIndex— structural view of a file, cached separately fromSourceModel. New type incha-core::modelcarrying the fields consumers likecha deps, LSP workspace-symbols, and futurecha summaryall share — class/function names + signatures + positions +type_aliases— without per-function-body data (complexity, body hash, TypeRef origin, cognitive, chain depth etc. stay inSourceModel).ProjectCache::{get,put}_symbolsstore tosymbols/{chash}.bin, mirrored independently ofparse/{chash}.bin. Sameenv_hashmechanism invalidates both on parser code changes.cached_symbols(path)is a new warm fast path that skipsSourceModeldeserialisation entirely —symbols/{chash}.binis roughly 10% the size ofparse/{chash}.bin.cached_parsenow populates both caches on every fresh parse, so the two views are always in lockstep.lvgl src/warm benchmarks (379 files):deps --type imports1.28s → 38ms (34×),--type classes1.30s → 56ms (23×),--type calls1.30s → 48ms (27×). Edge counts unchanged vs. pre-migration (1351/142/8109).cha-cli/src/c_oop_enrichgrows aenrich_c_oop_symbols/attribute_methods_by_name_from_symbolspair alongside the existingSourceModelfunctions. Sharedattribute_one_rawkeeps attribution rules single-sourced; build-index / write-back are deliberate parallel code paths because the two storage types have to stay independent.cha-cli/src/parse_cache.rs(new module) hosts bothcached_parseandcached_symbols.
- C++ parser now handles
ClassName::method()out-of-class definitions, namespaces, and templates. Three gaps in the previous CppParser have been closed:void Foo::bar() {...}(and::global(),A::B::c(), destructorsFoo::~Foo(), operatorsFoo::operator+()) was silently dropped —find_func_name_nodeonly accepted bareidentifierdeclarators. It now also unwrapsqualified_identifier,destructor_name, andoperator_name.- Out-of-class method definitions now attribute to their owning same-file class:
void Foo::bar()bumpsClassInfo::method_countonFooand flipshas_behavior. Cross-file attribution still runs throughcha-cli::c_oop_enrich. namespace_definition,linkage_specification(extern "C" { ... }), andtemplate_declarationare now explicitly matched in the top-level dispatch (previously fell through to the generic recursion arm) — same observable behaviour, but the nesting constructs are now a stable hook rather than an accidental default-case artefact.- C++-specific declarator helpers moved to a new
cha-parser/src/cpp.rssoc_lang.rsstays below thelarge_filegate.
SourceModel.type_aliasesnow populated for Rust, TypeScript, Python, and Go (previously all four returned emptyvec![]with parser-side TODOs). Each parser recognises its language's alias form and records(alias, rhs)pairs: Rusttype X = Y;/pub type X<T> = Y;, TypeScripttype X = Y;/export type X<T> = Y;, Python 3.12+type X = Yand pre-3.12X: TypeAlias = Y, Gotype X = Y(only the true alias form —type X Ydefined types are excluded). Plain PythonX = Yassignments remain unclassified (too ambiguous). Shared extraction lives in a newcha-parser/src/type_aliases.rsmodule so per-language files stay below thelarge_filegate.
Changed
boundary_leakdetector migrated toProjectIndex. The three smells it emits (abstraction_boundary_leak,return_type_leak,test_only_type_in_production) previously parsed the whole project a second time — the codebase noted a "cached model occasionally drops typedef aliases" concern with root cause TBD. v1.11.0's binary-mtime cache keying removed the suspected root cause, and a newcache::tests::cache_roundtrip_preserves_type_aliasesunit test makes the invariant a testable one.boundary_leak::detectnow takes&ProjectIndexand shares the same parse pass asanemic_domain_model,typed_intimacy,module_envy, and friends. Verified against lvgl'ssrc/tree: 155 findings before = 155 findings after (abstraction_boundary_leak: 154, return_type_leak: 1). Completes roadmap S8.infra.4.
Fixed
- C++: template specialisation methods attribute to the right class.
template<> void Foo<int>::bar()used to drop on the floor because the qualifierFoo<int>(atemplate_typenode) didn't match the stored class nameFoo.attach_to_classnow strips trailing<...>template arguments before matching, so out-of-class specialisations attribute correctly. Same stripping applies to any declaration whose declarator surfacesFoo<...>as the owning scope. - C++: real inheritance (
class Derived : public Base) now recognised.extract_classconsults thebase_class_clausechild and pulls the firsttype_identifier(ortemplate_type's underlying name) asparent_name. Falls back to the first-field heuristic only when no base clause is present, so legacy C struct-embedding cases still work. Also fixes the class-name extraction for templated classes sotemplate<typename T> class Foo {...}stores"Foo"instead of"Foo<T>". - C++: reference-return methods no longer vanish.
const int& Foo::get()and similarreference_declarator-wrapped definitions used to be silently dropped because tree-sitter-cpp'sreference_declaratorhas nodeclaratorfield — the declarator walker returnedNone. Bothfind_func_name_node(c_lang) anddescend_to_qualified_identifier(cpp) now fall back to the first named child when the field is absent. Same fix path covers reference-return + qualified (const T& Foo::bar()) so class attribution still works. 6 additional regression tests (reference/pointer return types, multi-method attribution, constructor,extern "C", const member) added incha-parser/tests/cpp_enhancements.rs(14 total).
Install cha-cli 1.12.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/W-Mai/Cha/releases/download/v1.12.0/cha-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/W-Mai/Cha/releases/download/v1.12.0/cha-cli-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install W-Mai/cellar/cha-cliDownload cha-cli 1.12.0
| File | Platform | Checksum |
|---|---|---|
| cha-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| cha-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| cha-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cha-cli-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cha-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| cha-cli-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |