get-shit-done's CLI core carries the highest activity risk — 5 functions to address first

All five top hotspots in gsd-build/get-shit-done are 'fire'-quadrant god functions in the CLI layer, combining CC values up to 181 with nesting depths up to 15 and active recent commit churn.

Stephen Collins ·
oss javascript refactoring code-health

Antipatterns Detected

complex_branching5deeply_nested5exit_heavy5god_function5long_function5

Key Points

What is a god function and why does it matter in get-shit-done?

A god function is a single function that has grown to handle too many responsibilities at once, accumulating branching logic, deeply nested conditions, and calls to a large number of other functions. In get-shit-done, all five top hotspots are flagged as god functions — `runCommand` alone calls 108 distinct functions — meaning a bug or change in any one of them can ripple unpredictably across a wide portion of the codebase. The practical risk is that the more a god function does, the harder it is to reason about, test exhaustively, or change safely.

How do I reduce cyclomatic complexity in JavaScript?

The most direct technique is the extract-method refactoring: identify cohesive groups of conditional logic inside a large function and pull them into named, single-purpose helper functions, each of which can be tested in isolation. For functions like `runCommand` with a cyclomatic complexity of 181, decomposing by command type or execution phase can reduce each sub-function's complexity to a manageable range while making the top-level dispatcher read as a straightforward routing table.

Is get-shit-done actively maintained?

The structural data strongly suggests it is: all five top hotspots are classified in the 'fire' quadrant, meaning they combine high structural complexity with high recent commit activity. `runCommand` carries a risk score of 21.7 and `install` scores 21.5 — the highest in the dataset — indicating the CLI core is being actively developed at the same time it carries its highest structural risk.

How do I reproduce this analysis?

Run the Hotspots CLI against the gsd-build/get-shit-done repository at commit 2205a85 to reproduce these results.

What does activity-weighted risk mean?

Complexity × recent commit frequency — functions that are hard to understand AND actively changing are the highest priority for refactoring.

In gsd-build/get-shit-done, the five highest-priority hotspots all sit in the CLI execution layer — and every one of them is in the ‘fire’ quadrant, meaning structural complexity and active development are colliding right now. The top function, runCommand in get-shit-done/bin/gsd-tools.cjs, carries a cyclomatic complexity of 181, a max nesting depth of 15, fan-out of 108, and a risk score of 21.7 — making it a live regression risk, not a cleanup backlog item. Across 2,544 total functions in the repo, 118 are rated critical; five of those critical functions share the same cluster of god-function, deeply-nested, and exit-heavy patterns concentrated in the tool’s core orchestration and setup paths.

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

FunctionFileRiskCCNDFO
runCommandget-shit-done/bin/gsd-tools.cjs21.718115108
installbin/install.js21.5112981
cmdInitManagerget-shit-done/bin/lib/init.cjs21.267857
uninstallbin/install.js20.8112834
cmdValidateHealthget-shit-done/bin/lib/verify.cjs20.2102748

Hotspot Analysis

runCommand — get-shit-done/bin/gsd-tools.cjs

As the name and path suggest, runCommand is the central command dispatcher for the gsd CLI — the function that receives a user’s command and routes execution across the tool’s subsystems. Its cyclomatic complexity of 181 means there are 181 independent execution paths to reason about and test, its max nesting depth of 15 is well into extreme territory (four levels is already a refactoring signal), and its fan-out of 108 means it directly invokes 108 distinct functions — giving it one of the broadest coupling footprints in the codebase. With a recent commit activity of 20.2 and a ‘fire’ quadrant classification, this function is both structurally the most dangerous in the repo and under active development right now, making every commit a live regression risk across a wide blast radius.

Recommendation: Before the next feature lands here, write characterization tests that exercise the highest-risk branches, then extract cohesive command-handling sub-functions to bring the CC below 30 and the nesting depth below 5. Audit the 108 fan-out callees to identify which can be grouped behind a narrower interface.

install — bin/install.js

The install function in bin/install.js almost certainly orchestrates the full toolchain installation sequence — detecting environments, writing configuration, and invoking downstream setup routines. Its cyclomatic complexity of 112 and max nesting depth of 9 indicate a function that has grown to absorb many conditional installation scenarios inline rather than delegating them, and its fan-out of 81 means changes here can ripple across a large portion of the setup subsystem. With a recent commit activity of 20.2 and a ‘fire’ quadrant classification, it is being actively changed at the same time it carries extreme structural risk, and its exit-heavy pattern means test coverage across all exit paths is a significant burden.

Recommendation: Extract each major installation phase (environment detection, dependency resolution, config writing) into dedicated functions, then add targeted tests for each exit path before the next round of changes — the exit-heavy pattern makes untested paths a silent regression risk.

cmdInitManager — get-shit-done/bin/lib/init.cjs

Living in lib/init.cjs, cmdInitManager appears to handle the initialization command path — likely managing the setup state machine that runs when a user first configures gsd in a project. Its cyclomatic complexity of 67 and max nesting depth of 8 reveal a function encoding many branching initialization scenarios in a single body, and its fan-out of 57 makes it a hub that couples the init subsystem to a wide slice of the library. Its recent commit activity of 20.11 and ‘fire’ quadrant status confirm this is actively changing, meaning each iteration on initialization behavior compounds the existing structural risk.

Recommendation: Decompose cmdInitManager by responsibility — separate environment-detection logic, configuration-writing steps, and user-prompt handling into individually testable units — to drive the cyclomatic complexity down and reduce the blast radius of future init-path changes.

uninstall — bin/install.js

uninstall shares its file with install, and the pairing is telling: both carry a cyclomatic complexity of 112, and both are in the ‘fire’ quadrant. The uninstall path presumably mirrors installation in reverse — detecting what was written, walking through dependent removals, and handling partial or failed states — which produces an almost identical branching surface. With a nesting depth of 8 and a risk score of 20.8, the function is slightly less coupled (fan-out of 34 versus install’s 81) but no less complex internally. Because both functions live in the same file and share structural patterns, they are natural candidates for a paired refactoring: shared phase-detection or environment-inspection logic can be extracted once and called by both.

Recommendation: Identify the conditional logic that appears in both install and uninstall and extract it into shared helpers — this reduces duplication and complexity in both functions simultaneously. Add exit-path tests before refactoring, as the exit-heavy pattern means the uninstall path has many silent failure modes.

cmdValidateHealth — get-shit-done/bin/lib/verify.cjs

cmdValidateHealth sits in the verify.cjs module and almost certainly runs the health-check command that confirms a gsd environment is correctly configured — validating installed tools, checking paths, and reporting on any setup issues. Its cyclomatic complexity of 102 and nesting depth of 7 suggest it encodes a wide range of environment states and validation conditions inline, and its fan-out of 48 means it touches a broad slice of the codebase to gather health signals. With a risk score of 20.2 and a ‘fire’ quadrant classification, it is actively changing at a time when its structural complexity already makes safe edits difficult.

Recommendation: Decompose validation into one function per concern — tool presence, path validity, config integrity — each returning a structured result. A top-level cmdValidateHealth that aggregates those results becomes a simple loop over validators, collapsing the current CC of 102 to near 5 and making each validation rule independently testable.

Codebase Risk Distribution

All five top hotspots share the same structural patterns (complex_branching, deeply_nested, exit_heavy, god_function, long_function), which is typical of the highest-risk functions in any large codebase — they accumulate every structural signal on the way to the top. More useful context is how the risk is distributed across all 2,544 analyzed functions:

BandFunctions
Critical118
High128
Moderate1,396
Low902

Hotspot patterns 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

  • runCommand in get-shit-done/bin/gsd-tools.cjs has a cyclomatic complexity of 181 and fan-out of 108 — write characterization tests covering its highest-risk branches before any further feature work lands in this function.
  • Both install and uninstall in bin/install.js share a cyclomatic complexity of 112 and are both in the ‘fire’ quadrant; treating them as a paired refactoring target (extracting shared phase logic) would reduce duplication and structural risk simultaneously.
  • All five top hotspots carry the god-function and exit-heavy patterns — every new exit path added during active development increases the test-coverage gap; enforce a policy of adding branch-level tests with each PR touching these files.

Reproduce This Analysis

git clone https://github.com/gsd-build/get-shit-done
cd get-shit-done
git checkout 2205a855ef8b49761c1a12ed60206e5202f95093
hotspots analyze . --mode snapshot --explain-patterns --force

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 →

Run this on your own codebase

Hotspots runs locally in under a minute — no account, no data leaves your machine.

macOS
$ brew install Stephen-Collins-tech/tap/hotspots
Linux / cargo
$ cargo install hotspots-cli
Run in any repo
$ hotspots analyze .
★ Star on GitHub

Related Analyses