From asynkron-devtools
Detects code duplication and clones using QuickDup CLI scanner. Identifies DRY violations and copy-pasted code by file extension to reduce codebase size and clean up redundancy.
npx claudepluginhub asynkron/asynkron-skills --plugin asynkron-devtoolsThis skill uses the workspace's default tool permissions.
Before running quickdup, check if it is installed:
Detects code duplicates using jscpd token-level analysis across files, classifies exact/near/structural clones, ranks by impact score (lines x instances), prepares prioritized refactoring plans.
Detects and refactors code duplication using PMD CPD for exact duplicates and Semgrep for patterns. Useful for code clones, DRY violations, and copy-paste code.
Audits JS/TS codebases for semantic function duplicates via extraction scripts and LLM intent clustering. Useful for LLM-generated code with reimplemented utilities.
Share bugs, ideas, or general feedback.
Before running quickdup, check if it is installed:
which quickdup
If not found, install it:
curl -sSL https://raw.githubusercontent.com/asynkron/Asynkron.QuickDup/main/install.sh | bashiwr -useb https://raw.githubusercontent.com/asynkron/Asynkron.QuickDup/main/install.ps1 | iexgo install github.com/asynkron/Asynkron.QuickDup/cmd/quickdup@latestQuickDup is a fast structural code clone detector (~100k lines in 500ms). It uses indent-delta fingerprinting to find duplicate code patterns. It is designed as a candidate generator — it optimizes for speed and recall, surfacing candidates fast for AI-assisted review.
Results are written to .quickdup/results.json and cached in .quickdup/cache.gob for fast incremental re-runs.
-select to inspect specific patternsBefore running, determine the primary language/extension of the project. Look at the files in the target path and use the appropriate -ext flag (e.g. .go, .ts, .cs, .py, .java, .rs).
Scan current project:
quickdup -path . -ext .go
Scan with specific extension (adapt to project language):
quickdup -path $ARGUMENTS -ext .ts
Show top 20 patterns:
quickdup -path . -ext .go -top 20
Inspect specific patterns in detail:
quickdup -path . -ext .go -select 0..5
Strict similarity (fewer false positives):
quickdup -path . -ext .go -min-similarity 0.9
Require more occurrences:
quickdup -path . -ext .go -min 5
Exclude generated files:
quickdup -path . -ext .go -exclude "*.pb.go,*_gen.go,*_test.go"
Compare duplication between branches:
quickdup -path . -ext .go -compare origin/main..HEAD
| Flag | Default | Purpose |
|---|---|---|
-path | . | Directory to scan |
-ext | .go | File extension to match |
-min | 2 | Minimum occurrences to report |
-min-size | 3 | Minimum pattern size (lines) |
-max-size | 0 | Max pattern size (0 = unlimited) |
-min-score | 5 | Minimum score threshold |
-min-similarity | 0.75 | Token similarity threshold (0.0-1.0) |
-top | 10 | Show top N patterns |
-select | — | Detailed view (e.g. 0..5) |
-exclude | — | Exclude file globs (comma-separated) |
-no-cache | false | Force full re-parse |
-strategy | normalized-indent | Detection strategy |
-compare | — | Compare between commits (base..head) |
If a pattern is intentional duplication, suppress it by adding its hash to .quickdup/ignore.json:
{
"description": "Patterns to ignore",
"ignored": ["56c2f5f9b27ed5a0"]
}
QuickDup finds duplication candidates. The next step is knowing how to fix them. Not all duplication is the same — each type has a different refactoring strategy.
Two blocks share the same control flow and structure, but differ in injected behavior (which function is called, which parameters are passed, whether some context like an index exists).
How to recognize it:
How to refactor:
if (variant) { ... } else { ... }. Instead, extract the shared structure and pass behavior in.Good:
IterateAndResolve(array, i => CreateResolve(i), ...)
Bad:
IterateAndResolve(array, withIndex: true)
Rule of thumb: If two methods differ only in what they do inside a shared structure, extract the structure. If they differ in structure, keep them separate.
Repeated switch/pattern match blocks on the same domain structures. Common in AST walkers, serializers, interpreters, and compilers.
How to recognize it:
switch or pattern matching blocksWhen to leave it alone:
When to refactor:
How to refactor:
Good: Statement? TryUnwrapBody(Statement s)
Bad: HandleStatement(s, mode)
Rule of thumb: If the switch describes structure, duplication is documentation. If the switch implements behavior, consider extraction.
The same set of context values passed together in multiple places — same parameters, same order, same meaning.
How to recognize it:
How to refactor:
Extract a value object:
new ExecutionContext(thisValue, realmState, isStrict, homeObject, privateScope)
Then pass the single object instead of 5+ individual arguments.
When to leave it: Appears only once, is highly localized, or has extremely short lifetime.
Rule of thumb: If the same parameter list appears 2-3+ times, it wants to become a named type.
Duplicated defensive parsing of callback arguments — same local variables, same guards, same positional decoding.
How to recognize it:
args.Count >= 1, args[0])How to refactor:
Extract a small helper whose only job is to unpack the arguments:
UnwrapResolveReject(args, out var resolve, out var reject);
This is purely mechanical code — the intent is obscured by boilerplate, and any bug fix would need to be applied to every copy.
Rule of thumb: If you copy the same argument decoding logic twice, extract it. If the extraction reads like English, you picked the right abstraction.
-ext for the project before running-min-similarity if too many false positives-select 0..5 to inspect the top candidates before refactoring