Find and extract duplicated code into shared abstractions. Use when seeing repeated utilities, copy-pasted components, duplicated hooks, or boilerplate repeated across files.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Find and extract duplicated code into shared abstractions. Use when seeing repeated utilities, copy-pasted components, duplicated hooks, or boilerplate repeated across files.
Enumerate duplicate ranges with a deterministic clone detector, then read only the reported ranges — not whole candidate files. This keeps discovery reproducible and cheap. Token-based detection (jscpd) finds copy-paste independent of whitespace/formatting and of the enclosing symbol name — clone pairs a name-based Grep misses when the wrapping function is renamed. ast-grep (1b) then adds tolerance for variables renamed inside the block.
1a. Token-based near-duplicates with jscpd
jscpd is a token-based copy/paste detector that supports 150+ languages despite the "js" in the name; npx runs it with no global install. Run it over the target path:
It writes /tmp/jscpd-dry/jscpd-report.json. Read that report and parse its duplicates array — each entry gives the exact file/line ranges of a clone pair plus its size in tokens/lines:
For each reported clone, Read only the line ranges (Read with offset/limit around start/end) to confirm the duplication and classify it — do not Read whole candidate files. jscpd similarity is high by construction for a reported clone (a --min-tokens match); note the tokens/lines for the Extraction Plan.
1b. Structural confirmation with ast-grep
Once jscpd surfaces a cluster, confirm it is the same shape — same call-shape / same block modulo captured variables — with ast-grep metavariables. $VAR / $INIT match any identifier/expression, so a block differing only in renamed captures still matches:
Use this to separate a genuine extractable duplicate from a coincidental token overlap before planning the extraction. (For a standalone structural search without extraction, use the ast-grep-search skill.)
1c. Graceful fallback (Grep) when the detector is unavailable
When npx/jscpd is unavailable, or the ecosystem has no npx on PATH, fall back to agent-driven text search:
Use Grep to find repeated function names, variable patterns, and import clusters
Use Glob to identify files with similar structure (e.g., all *List.tsx, all *Detail.tsx)
Read candidate files to confirm duplication and measure scope
This fallback has lower recall for near-duplicates (renamed variables, reordered params) — prefer the jscpd path when available, and reserve Grep for when it is not.
Duplication signals to classify (both the jscpd and the Grep path feed the same categories in Step 2):
Utility functions defined identically in multiple files (string truncation, date formatting, validation)
Identical error handling blocks (try/catch patterns, error state JSX)
Duplicated import blocks that signal repeated inline implementations
Step 2: Classify duplications
Group discovered duplications into extraction categories:
Category
Extract Into
Location Convention
Utilities
Pure functions
src/lib/utils/ or src/utils/
Components
Shared UI components
src/components/ui/ or src/components/shared/
Hooks
Custom React/Vue hooks
src/hooks/ or src/composables/
Types
Shared type definitions
src/types/ or alongside the abstraction
Follow the project's existing conventions for shared code location. If no convention exists, propose one based on the framework.
Step 3: Plan extractions
For each duplication cluster, plan the extraction:
Name the abstraction — Use a clear, descriptive name that reflects the shared behavior
Define the interface — Determine parameters needed to cover all usage variations
Choose the location — Follow project conventions for shared code placement
List all consumers — Identify every file that will be updated
Assess risk — Note any subtle differences between duplicated instances that need parameterization
Present the plan to the user before proceeding (unless --dry-run was not specified and the scope is clear).
Plan format:
## Extraction Plan
### 1. [Abstraction Name] → [target file path]
- Type: utility | component | hook
- Replaces: [N] identical blocks across [M] files
- Consumers: [list of files]
- Parameters: [any variations that need to be parameterized]
- Duplicated: [N] tokens / [N] lines (from jscpd; blank when the Grep fallback was used)
- Similarity: [N]% (from jscpd; "exact" when ast-grep-confirmed as the same shape)
- Estimated lines saved: [N]
The Duplicated and Similarity fields come from jscpd's report (tokens/lines per clone, and the cluster's percentage) — a quantified --dry-run report instead of a best-effort narrative. When the Grep fallback (1c) supplied the cluster, leave them blank or note "grep-estimated".
Step 4: Extract shared abstractions
Execute each planned extraction:
Create the shared abstraction with proper typing and documentation
Replace each instance in consumer files with an import + usage of the new abstraction
Handle variations — parameterize differences between instances rather than creating multiple abstractions
Update imports — add the new import, remove imports that were only needed for the inline version
Extraction order: Start with utilities (no dependencies), then components, then hooks (may depend on utilities/components).
Mark each extraction as completed in the todo list before moving to the next.
Step 5: Write tests
Write tests for each extracted abstraction:
Abstraction Type
Test Approach
Utility function
Unit tests covering all input variations, edge cases
UI component
Render tests, prop variations, accessibility
Custom hook
Hook testing with mock dependencies, state transitions
Type definitions
Type-level tests if applicable (tsd, expect-type)
Place test files adjacent to the abstraction or in the project's test directory, following existing conventions.
Step 6: Clean up dead code
After all extractions are complete:
Remove unused imports from all updated consumer files
Remove dead code — inline helper functions that are now replaced
Verify no orphaned references — search for any remaining references to removed code
Step 7: Verify all checks pass
Run the full verification suite:
TypeScript/JavaScript projects:
npx tsc --noEmit # Type checking
npm run lint # Linting (or biome/eslint directly)
npm run test# Full test suite
Python projects:
ty check . # Type checking
ruff check . # Linting
pytest # Test suite
Rust projects:
cargo check # Type checking
cargo clippy # Linting
cargo test# Test suite
All three must pass. If any fail, fix the issues before reporting completion.
Output Summary
After all phases complete, report:
## DRY Consolidation Summary
### Extractions
- [Abstraction Name] (type) — replaced N blocks in M files
- ...
### New Files Created
- path/to/new/file.ts — [description]
- ...
### Tests Added
- N tests across M test files
### Net Effect
- ~N lines of duplicated code consolidated
- N reusable abstractions created
- All verified: typecheck + lint + N passing tests
Agentic Optimizations
Context
Approach
Deterministic clone scan
npx jscpd --reporters json --min-tokens 50 --output /tmp/jscpd-dry --silent <path> then parse duplicates[] for exact ranges
Structural shape confirm
ast-grep -p '<pattern with $METAVARS>' --lang <lang> <path>
Quick scan
Use --dry-run to see duplication report without changes
Focused extraction
Use --scope utilities to extract only utility functions
Large codebase
Scope to specific directory: /code:dry-consolidation src/components/
Post-extraction verify
`npx tsc --noEmit 2>&1
Test run (fast)
npm test -- --bail=1 --reporter=dot for quick pass/fail
See Also
/code:refactor — Functional refactoring of a file or directory (pure functions, immutability, composition)
/code:antipatterns — Detection-only analysis for code smells
ast-grep-search — Structural code search for finding patterns
Related Skills
If dead code detected during consolidation → /code:dead-code
If complexity is high after consolidation → /code:complexity