cherry-studio’s highest activity-risk function, initClient in MCPService.ts, carries an activity risk score of 19.66 with a recent commit activity of 18.63 — it was modified just 1 day ago and has been touched twice in the last 30 days, making its cyclomatic complexity of 25, max nesting depth of 9, and fan-out of 46 a live regression risk rather than a cleanup backlog item. The project spans 5,073 analyzed functions, 479 of which are rated critical, and every one of the top-ranked hotspots lands in the ‘fire’ quadrant — meaning high structural complexity and active recent change are occurring simultaneously across the codebase’s most sensitive layers. Cherry-studio appears to be an AI desktop client integrating multiple model providers and tooling protocols, and the data shows that both its MCP service layer and its AI reasoning utilities are under active development at precisely the points of highest structural complexity.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
initClient | src/main/services/MCPService.ts | 19.7 | 25 | 9 | 46 |
getReasoningEffort | src/renderer/src/aiCore/utils/reasoning.ts | 19.1 | 132 | 6 | 37 |
run | src/main/services/CodeToolsService.ts | 18.7 | 66 | 5 | 52 |
load_run_results | resources/skills/skill-creator/scripts/aggregate_benchmark.py | 18.6 | 51 | 6 | 28 |
backupToS3 | src/renderer/src/services/BackupService.ts | 18.0 | 32 | 7 | 24 |
Large Repo Analysis
cherry-studio is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 5 or more commits in the last 30 days; other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.
Codemod / Tooling Files in Results
The function _0x18b2 in src/main/integration/nutstore/sso/lib/index.mjs is a vendored or bundled third-party SSO library — the obfuscated name and .mjs path under a lib/ subdirectory are strong indicators of a bundled dependency rather than project-authored code. Its metrics (CC 5, ND 2, FO 4) are low-risk and its activity score reflects commits to the integration wrapper, not the library itself. Exclude it from future analyses with: { "exclude": ["src/main/integration/nutstore/sso/lib/"] } in your .hotspotsrc.json.
Hotspot Analysis
initClient — src/main/services/MCPService.ts
Based on its name and location in MCPService.ts, initClient almost certainly bootstraps a Model Context Protocol client — establishing connections, configuring transports, and wiring up the service layer that downstream AI tool calls depend on. Its cyclomatic complexity of 25 means there are at least 25 independent execution paths through initialization logic, its max nesting depth of 9 is a strong refactoring signal on its own, and its fan-out of 46 means it directly calls 46 distinct functions — making it a true god function whose blast radius touches nearly every service the MCP layer exposes. This is a fire-quadrant function: it was last changed just 1 day ago and has 2 commits touching it in the last 30 days, so that CC-25/ND-9/FO-46 structure is being actively navigated by contributors right now, which is where live regressions are born.
Recommendation: Before any refactoring, add characterization tests that exercise each of the major initialization branches — the exit-heavy pattern flagged in the data means multiple early-return paths exist and are easy to miss. Then extract sub-functions by responsibility (transport setup, capability negotiation, error handling) to bring fan-out and nesting depth down to reviewable levels; targeting ND ≤ 4 and FO ≤ 15 per extracted unit would cut the blast radius substantially.
getReasoningEffort — src/renderer/src/aiCore/utils/reasoning.ts
Sitting in the renderer-side AI core utilities, getReasoningEffort almost certainly maps model configurations or user settings to a reasoning effort level — likely a classification or dispatch function that branches across many supported providers or effort tiers. Its cyclomatic complexity of 132 is extreme by any standard: CC 100+ represents a function with over a hundred independent execution paths, each one a required test case and a potential bug surface. A fan-out of 37 reinforces the god-function characterization — it reaches into 37 other functions — and while its max nesting depth of 6 is lower than initClient’s, the sheer scale of branching (CC 132) means the cognitive load of understanding any single change through it is enormous. It is a fire-quadrant function touched once in the last 30 days and last changed 6 days ago, meaning active iteration is happening through a function of extraordinary complexity.
Recommendation: A CC of 132 warrants immediate decomposition: the most effective first step is to identify the top-level dispatch axis — likely provider type or effort tier — and extract each branch into its own named function, reducing the root function to a pure routing shell. Pair this with a table-driven or strategy-pattern approach so that adding a new provider or effort level does not require adding yet another conditional branch to an already unmaintainable function.
run — src/main/services/CodeToolsService.ts
run in CodeToolsService.ts is almost certainly the main execution dispatcher for cherry-studio’s code tooling layer — responsible for invoking terminal commands, scripts, or sandboxed code execution on behalf of the AI. Its cyclomatic complexity of 66 with a max nesting depth of only 5 is a signature of broad sequential branching rather than deep nesting: many tool types, runtime environments, or execution modes each handled by their own branch. The fan-out of 52 is the highest in the top 5, meaning this single function reaches into 52 distinct downstream callees — a fan-out that makes it a true god function whose internal changes ripple across half the tools service layer. An activity risk of 18.7 confirms it is under active development at this level of complexity.
Recommendation: The fan-out of 52 is the primary risk signal here: changes to run can disturb 52 downstream callees, and testing it in isolation requires stubbing most of the tools layer. Extract each tool type or execution mode into a dedicated handler and route through a dispatch table; this reduces fan-out at the root, eliminates the per-tool branching, and makes each handler independently testable.
load_run_results — resources/skills/skill-creator/scripts/aggregate_benchmark.py
load_run_results lives in a Python benchmark aggregation script under resources/skills/skill-creator/ — a path that suggests it is part of the tooling used to evaluate or calibrate skill-creator capabilities, likely loading and merging results from multiple benchmark runs. A CC of 51 with ND 6 and FO 28 indicates a function that handles many result formats or edge cases (CC 51) through moderately deep nesting (ND 6) while calling into 28 distinct downstream helpers. Data-loading functions in benchmark scripts commonly accumulate this shape when they need to handle partial results, missing files, version mismatches, and format variations — each case adding a branch.
Recommendation: Separate the concerns of loading raw results from the concerns of validating and normalizing them. A loader that simply reads files and a normalizer that handles format variations and missing data are independently testable and much easier to extend. Targeting CC ≤ 15 per function and ND ≤ 4 would bring this into a maintainable range.
backupToS3 — src/renderer/src/services/BackupService.ts
backupToS3 handles cloud backup of user data to S3 — a function that must coordinate authentication, serialization, chunked upload, error handling, and retry logic, all of which contribute branches. Its CC of 32 with ND 7 is notable: the nesting depth is relatively high for the complexity level, which suggests the branching is driven by nested error-handling or retry logic rather than a flat dispatch across many cases. A fan-out of 24 means it reaches into 24 downstream callees, touching auth, serialization, and upload utilities. An activity risk of 18.0 indicates this is not dormant infrastructure — it is being actively changed.
Recommendation: The ND 7 signal points to nested try/catch or retry structures as the primary refactoring target. Extract the retry/error-handling wrapper into its own reusable function, and separate the serialization and upload phases so each can be tested without the others. This directly reduces nesting depth and isolates the most fragile logic — error handling and retries — from the core upload path.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
god_function | 6 |
long_function | 6 |
complex_branching | 5 |
deeply_nested | 5 |
exit_heavy | 5 |
hub_function | 1 |
middle_man | 1 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
Key Takeaways
- initClient in MCPService.ts has a fan-out of 46 and was last modified 1 day ago — add characterization tests covering its exit-heavy paths before the next change lands, or risk a regression that propagates across nearly every function it calls.
- getReasoningEffort carries a cyclomatic complexity of 132, which means over 100 execution paths are effectively untestable as a unit — decompose it along its primary dispatch axis (likely provider or effort tier) using a strategy pattern to make each path independently verifiable.
- Every top-ranked function in cherry-studio falls in the fire quadrant — there are no debt-quadrant functions in the dataset, meaning the team is actively iterating at the points of highest structural complexity; prioritize test coverage on initClient and getReasoningEffort before adding new branching logic to either.
Reproduce This Analysis
git clone https://github.com/CherryHQ/cherry-studio
cd cherry-studio
git checkout a574aa5e3fc92919cbbeb04f3e4a6a439a30c0aa
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →