@intentsolutionsio/code-cleanup 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +25 -0
- package/README.md +93 -0
- package/agents/async-pattern-fixer.md +224 -0
- package/agents/circular-dep-untangler.md +149 -0
- package/agents/dead-code-hunter.md +148 -0
- package/agents/defensive-code-cleaner.md +123 -0
- package/agents/dry-deduplicator.md +175 -0
- package/agents/legacy-code-remover.md +149 -0
- package/agents/performance-optimizer.md +222 -0
- package/agents/security-scanner.md +169 -0
- package/agents/slop-remover.md +194 -0
- package/agents/type-consolidator.md +136 -0
- package/agents/weak-type-eliminator.md +134 -0
- package/package.json +45 -0
- package/skills/cleanup-code/SKILL.md +183 -0
- package/skills/cleanup-code/references/dimensions.md +241 -0
- package/skills/cleanup-code/references/patterns.md +195 -0
- package/skills/cleanup-code/references/safety.md +105 -0
- package/skills/cleanup-code/references/tools.md +185 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cleanup-code
|
|
3
|
+
description: |
|
|
4
|
+
Comprehensive codebase cleanup across 11 quality dimensions: dead code, duplication,
|
|
5
|
+
weak types, circular deps, defensive cruft, legacy code, AI slop, type consolidation,
|
|
6
|
+
security, performance, and async patterns. Analyzes code with confidence scoring and
|
|
7
|
+
verifies changes with build/test gates. Use when codebase has accumulated tech debt,
|
|
8
|
+
after major feature work, before releases, or when code quality metrics are declining.
|
|
9
|
+
Trigger with "/cleanup-code-code", "clean up the codebase", "remove dead code", "fix code quality".
|
|
10
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash(git:*), Bash(npm:*), Bash(npx:*), Bash(pnpm:*), Bash(python3:*), Bash(tsc:*), Bash(wc:*), Bash(ls:*), AskUserQuestion
|
|
11
|
+
version: 1.0.0
|
|
12
|
+
author: Jeremy Longshore <jeremy@intentsolutions.io>
|
|
13
|
+
license: MIT
|
|
14
|
+
compatible-with: claude-code, codex, openclaw
|
|
15
|
+
tags: [code-quality, cleanup, refactoring, dead-code, deduplication, type-safety, security]
|
|
16
|
+
argument-hint: "[scope] [--dimensions d1,d2,...] [--changed]"
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Codebase Cleanup
|
|
20
|
+
|
|
21
|
+
Systematic code cleanup across 11 quality dimensions, ordered by risk. Each finding includes
|
|
22
|
+
confidence scoring (HIGH/MEDIUM/LOW) and all changes are verified through build/test gates.
|
|
23
|
+
|
|
24
|
+
## Environment Detection
|
|
25
|
+
|
|
26
|
+
!`git rev-parse --show-toplevel 2>/dev/null && echo "---" && git diff --stat HEAD~5 2>/dev/null | tail -5`
|
|
27
|
+
!`ls package.json pyproject.toml Cargo.toml go.mod Makefile 2>/dev/null | head -5`
|
|
28
|
+
!`cat package.json 2>/dev/null | head -3; echo "---"; ls tsconfig.json .eslintrc* 2>/dev/null`
|
|
29
|
+
|
|
30
|
+
## Prerequisites
|
|
31
|
+
|
|
32
|
+
- Git repository with clean working tree (no uncommitted changes)
|
|
33
|
+
- Language toolchain installed (Node.js/Python/Go/Rust as applicable)
|
|
34
|
+
- Optional: `knip`, `madge`, `jscpd`, `ruff`, `bandit` for tool-verified scanning
|
|
35
|
+
|
|
36
|
+
## Overview
|
|
37
|
+
|
|
38
|
+
This skill orchestrates cleanup across **11 dimensions**, each with a dedicated agent.
|
|
39
|
+
Dimensions are ordered LOW → HIGH risk. See [dimensions reference](references/dimensions.md)
|
|
40
|
+
for full detection criteria, verification steps, and risk profiles.
|
|
41
|
+
|
|
42
|
+
**The 11 Dimensions** (by risk level):
|
|
43
|
+
|
|
44
|
+
| # | Dimension | Key | Risk | Auto-apply? |
|
|
45
|
+
|---|-----------|-----|------|-------------|
|
|
46
|
+
| 1 | Dead code removal | `dead` | LOW | Yes (after build) |
|
|
47
|
+
| 2 | AI slop removal | `slop` | LOW | Comments only |
|
|
48
|
+
| 3 | Weak type elimination | `types` | MED | Yes (after typecheck) |
|
|
49
|
+
| 4 | Security cleanup | `security` | MED | Flag only |
|
|
50
|
+
| 5 | Legacy code removal | `legacy` | MED | With confirmation |
|
|
51
|
+
| 6 | Type consolidation | `typecons` | MED | Yes (after typecheck) |
|
|
52
|
+
| 7 | Defensive code cleanup | `defensive` | MED | Flag only |
|
|
53
|
+
| 8 | Performance optimization | `perf` | MED | Flag only |
|
|
54
|
+
| 9 | DRY deduplication | `dry` | HIGH | Flag only (>=10 lines) |
|
|
55
|
+
| 10 | Async pattern fixes | `async` | HIGH | Flag only |
|
|
56
|
+
| 11 | Circular dep untangling | `circular` | HIGH | Flag only |
|
|
57
|
+
|
|
58
|
+
## Instructions
|
|
59
|
+
|
|
60
|
+
### Step 1: Safety Checkpoint
|
|
61
|
+
|
|
62
|
+
Before any changes:
|
|
63
|
+
|
|
64
|
+
1. Verify clean git state: `git status --porcelain` must be empty (or stash changes)
|
|
65
|
+
2. Record baseline: `git rev-parse HEAD` as rollback point
|
|
66
|
+
3. Run existing tests to confirm green baseline
|
|
67
|
+
4. See [safety protocol](references/safety.md) for revert procedures
|
|
68
|
+
|
|
69
|
+
### Step 2: Determine Scope
|
|
70
|
+
|
|
71
|
+
Parse user arguments to set scope:
|
|
72
|
+
|
|
73
|
+
- **Full codebase** (default): scan all source files
|
|
74
|
+
- **Specific path**: `cleanup src/api/` — limit to directory
|
|
75
|
+
- **Changed files only**: `--changed` flag — `git diff --name-only HEAD~10`
|
|
76
|
+
- **Specific dimensions**: `--dimensions dead,types,security`
|
|
77
|
+
- **Single dimension**: `cleanup --dimensions dry`
|
|
78
|
+
|
|
79
|
+
Exclude from all scans: `node_modules/`, `dist/`, `build/`, `.git/`, vendor dirs, generated files.
|
|
80
|
+
|
|
81
|
+
### Step 3: Execute Dimensions
|
|
82
|
+
|
|
83
|
+
For each selected dimension (in risk order):
|
|
84
|
+
|
|
85
|
+
1. **Scan** using patterns from [patterns reference](references/patterns.md)
|
|
86
|
+
2. **Score confidence** — HIGH (certain, safe to fix), MEDIUM (likely, needs review), LOW (possible, flag only)
|
|
87
|
+
3. **Apply or flag** based on the dimension's auto-apply policy (see table above)
|
|
88
|
+
4. **Verify** — run build/typecheck/tests after each dimension with auto-apply
|
|
89
|
+
|
|
90
|
+
Use [tools reference](references/tools.md) for language-specific tool commands (knip, madge, ruff, jscpd, etc.).
|
|
91
|
+
|
|
92
|
+
### Step 4: Build Verification Gate
|
|
93
|
+
|
|
94
|
+
After each auto-applied dimension:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# TypeScript/JavaScript
|
|
98
|
+
npx tsc --noEmit 2>&1 | tail -20
|
|
99
|
+
npm test 2>&1 | tail -30
|
|
100
|
+
|
|
101
|
+
# Python
|
|
102
|
+
python3 -m py_compile <changed_files>
|
|
103
|
+
python3 -m pytest --tb=short 2>&1 | tail -30
|
|
104
|
+
|
|
105
|
+
# General
|
|
106
|
+
git diff --stat # Show what changed
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If verification fails, revert that dimension: `git checkout -- .`
|
|
110
|
+
|
|
111
|
+
### Step 5: Generate Report
|
|
112
|
+
|
|
113
|
+
Produce a cleanup report in this format:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
## Cleanup Report
|
|
117
|
+
|
|
118
|
+
**Scope:** [path or "full codebase"]
|
|
119
|
+
**Baseline:** [commit hash]
|
|
120
|
+
**Dimensions:** [list of dimensions run]
|
|
121
|
+
|
|
122
|
+
### Summary
|
|
123
|
+
| Dimension | Findings | Applied | Flagged | Confidence |
|
|
124
|
+
|-----------|----------|---------|---------|------------|
|
|
125
|
+
| dead | 12 | 10 | 2 | HIGH |
|
|
126
|
+
| types | 8 | 8 | 0 | HIGH |
|
|
127
|
+
| security | 3 | 0 | 3 | MEDIUM |
|
|
128
|
+
|
|
129
|
+
### Changes Applied
|
|
130
|
+
- [file:line] description of change
|
|
131
|
+
|
|
132
|
+
### Flagged for Review
|
|
133
|
+
- [file:line] description + reasoning + suggested fix
|
|
134
|
+
|
|
135
|
+
### Lines Removed: N | Lines Modified: N | Files Touched: N
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Output
|
|
139
|
+
|
|
140
|
+
A structured cleanup report containing:
|
|
141
|
+
- Summary table with findings per dimension (count, applied, flagged, confidence)
|
|
142
|
+
- List of changes applied with file:line references
|
|
143
|
+
- List of flagged items with reasoning and suggested fixes
|
|
144
|
+
- Stats: lines removed, lines modified, files touched
|
|
145
|
+
|
|
146
|
+
## Error Handling
|
|
147
|
+
|
|
148
|
+
| Error | Recovery |
|
|
149
|
+
|-------|----------|
|
|
150
|
+
| Dirty git state | Ask user to commit or stash first |
|
|
151
|
+
| Build fails after cleanup | `git checkout -- .` to revert dimension |
|
|
152
|
+
| No test command found | Skip verification, flag all as "unverified" |
|
|
153
|
+
| Tool not installed | Fall back to grep patterns (see references/patterns.md) |
|
|
154
|
+
| Confidence unclear | Default to flag-only, never auto-apply |
|
|
155
|
+
|
|
156
|
+
## Examples
|
|
157
|
+
|
|
158
|
+
**Full cleanup:**
|
|
159
|
+
```
|
|
160
|
+
/cleanup-code
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Security-focused:**
|
|
164
|
+
```
|
|
165
|
+
/cleanup-code --dimensions security,async
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Changed files only:**
|
|
169
|
+
```
|
|
170
|
+
/cleanup-code src/api/ --changed
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Single dimension deep-dive:**
|
|
174
|
+
```
|
|
175
|
+
/cleanup-code --dimensions dead
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Resources
|
|
179
|
+
|
|
180
|
+
- [All 11 Dimensions](references/dimensions.md) — detection criteria, verification, risk profiles
|
|
181
|
+
- [Tool Reference](references/tools.md) — language-specific cleanup tools
|
|
182
|
+
- [Grep Patterns](references/patterns.md) — detection patterns by dimension
|
|
183
|
+
- [Safety Protocol](references/safety.md) — revert procedures, confidence scoring
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Cleanup Dimensions Reference
|
|
2
|
+
|
|
3
|
+
Complete reference for all 11 cleanup dimensions, ordered by risk level.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Dead Code (Key: `dead` | Risk: LOW)
|
|
8
|
+
|
|
9
|
+
**What:** Unreachable code, unused exports, unused variables, unused imports, unused functions, dead branches.
|
|
10
|
+
|
|
11
|
+
**Detection:**
|
|
12
|
+
- Unused exports: `knip` (JS/TS), `vulture` (Python), `deadcode` (Go)
|
|
13
|
+
- Unused variables: compiler warnings, linter output
|
|
14
|
+
- Unreachable code: code after `return`/`throw`/`break`/`continue`
|
|
15
|
+
- Dead feature flags: flags that are always true/false
|
|
16
|
+
|
|
17
|
+
**Verification:**
|
|
18
|
+
1. Remove candidate
|
|
19
|
+
2. Run `tsc --noEmit` (TS) or equivalent type check
|
|
20
|
+
3. Run test suite
|
|
21
|
+
4. If both pass → confirmed dead code
|
|
22
|
+
|
|
23
|
+
**Auto-apply:** Yes, after build verification passes.
|
|
24
|
+
|
|
25
|
+
**False positive signals:** Dynamic imports, reflection, test fixtures, plugin entry points, CLI entry points.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. AI Slop (Key: `slop` | Risk: LOW)
|
|
30
|
+
|
|
31
|
+
**What:** Low-value comments generated by AI assistants — restating obvious code, adding filler.
|
|
32
|
+
|
|
33
|
+
**Detection patterns:**
|
|
34
|
+
- Comments that restate the next line: `// Set the name` above `name = value`
|
|
35
|
+
- Obvious JSDoc: `@param name - The name` or `@returns The result`
|
|
36
|
+
- Section markers with no value: `// --- Helper Functions ---`
|
|
37
|
+
- Filler phrases: "This function", "This method", "This class", "As mentioned above"
|
|
38
|
+
- Over-documentation of trivial code
|
|
39
|
+
|
|
40
|
+
**Verification:** Read the comment and the code it describes. If removing the comment loses zero information, it's slop.
|
|
41
|
+
|
|
42
|
+
**Auto-apply:** Comments only — remove slop comments. Never modify actual code in this dimension.
|
|
43
|
+
|
|
44
|
+
**False positive signals:** Comments explaining *why* (business logic, workarounds, TODOs with context), JSDoc on public APIs.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 3. Weak Types (Key: `types` | Risk: MEDIUM)
|
|
49
|
+
|
|
50
|
+
**What:** `any`, `unknown` used unnecessarily, missing return types, implicit any, overly broad generics.
|
|
51
|
+
|
|
52
|
+
**Detection:**
|
|
53
|
+
- TypeScript: `any` type annotations, missing return types on exported functions
|
|
54
|
+
- Python: missing type hints on public functions, `Any` imports from typing
|
|
55
|
+
- Untyped function parameters in public APIs
|
|
56
|
+
|
|
57
|
+
**Verification:**
|
|
58
|
+
1. Replace `any` with specific type
|
|
59
|
+
2. Run `tsc --noEmit` — must compile without new errors
|
|
60
|
+
3. Run tests
|
|
61
|
+
|
|
62
|
+
**Auto-apply:** Yes, when the correct type is unambiguous (inferred from usage). Flag when ambiguous.
|
|
63
|
+
|
|
64
|
+
**False positive signals:** Intentional `any` for serialization boundaries, third-party type gaps, `unknown` in catch blocks (correct usage).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 4. Security (Key: `security` | Risk: MEDIUM)
|
|
69
|
+
|
|
70
|
+
**What:** Hardcoded secrets, weak crypto, SQL injection vectors, command injection, path traversal, insecure defaults.
|
|
71
|
+
|
|
72
|
+
**Detection categories:**
|
|
73
|
+
|
|
74
|
+
| Category | Patterns |
|
|
75
|
+
|----------|----------|
|
|
76
|
+
| Hardcoded secrets | API keys, tokens, passwords in source code |
|
|
77
|
+
| Weak crypto | MD5, SHA1 for security purposes, `Math.random()` for tokens |
|
|
78
|
+
| SQL injection | String concatenation in SQL queries |
|
|
79
|
+
| Command injection | Unsanitized input in `exec()`, `spawn()`, shell commands |
|
|
80
|
+
| Path traversal | Unsanitized `../` in file paths |
|
|
81
|
+
| Insecure defaults | HTTP instead of HTTPS, disabled TLS verification |
|
|
82
|
+
|
|
83
|
+
**Verification:** Manual review required — security findings are NEVER auto-applied.
|
|
84
|
+
|
|
85
|
+
**Auto-apply:** NEVER. Flag all findings with severity (CRITICAL/HIGH/MEDIUM/LOW) and suggested fix.
|
|
86
|
+
|
|
87
|
+
**False positive signals:** Test fixtures, example code in docs, intentionally disabled security in dev mode.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 5. Legacy Code (Key: `legacy` | Risk: MEDIUM)
|
|
92
|
+
|
|
93
|
+
**What:** Deprecated API usage, old syntax patterns, compatibility shims for dropped platforms, polyfills for supported targets.
|
|
94
|
+
|
|
95
|
+
**Detection:**
|
|
96
|
+
- Deprecated Node.js APIs (`fs.exists`, `url.parse`, `new Buffer()`)
|
|
97
|
+
- Old JS patterns (`var`, `arguments` object, `prototype` instead of class)
|
|
98
|
+
- Unnecessary polyfills based on browserslist/engines config
|
|
99
|
+
- Compatibility code for unsupported environments
|
|
100
|
+
|
|
101
|
+
**Verification:**
|
|
102
|
+
1. Replace with modern equivalent
|
|
103
|
+
2. Check minimum platform target (engines, browserslist)
|
|
104
|
+
3. Run tests
|
|
105
|
+
|
|
106
|
+
**Auto-apply:** Yes, with confirmation prompt for each batch.
|
|
107
|
+
|
|
108
|
+
**False positive signals:** Intentional backward compatibility, library code that must support older runtimes.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 6. Type Consolidation (Key: `typecons` | Risk: MEDIUM)
|
|
113
|
+
|
|
114
|
+
**What:** Duplicate type definitions, inconsistent interfaces, types that should be derived/shared.
|
|
115
|
+
|
|
116
|
+
**Detection:**
|
|
117
|
+
- Multiple interfaces with >80% field overlap
|
|
118
|
+
- Same type defined in multiple files
|
|
119
|
+
- Types that could use `Pick<>`, `Omit<>`, `Partial<>` instead of duplication
|
|
120
|
+
- Enum values duplicated as string literals elsewhere
|
|
121
|
+
|
|
122
|
+
**Verification:**
|
|
123
|
+
1. Consolidate to single source
|
|
124
|
+
2. Update all imports
|
|
125
|
+
3. Run `tsc --noEmit` + tests
|
|
126
|
+
|
|
127
|
+
**Auto-apply:** Yes, after typecheck passes.
|
|
128
|
+
|
|
129
|
+
**False positive signals:** Types that are intentionally separate (different domains), API boundary types that mirror but shouldn't depend on internal types.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 7. Defensive Code (Key: `defensive` | Risk: MEDIUM)
|
|
134
|
+
|
|
135
|
+
**What:** Unnecessary null checks, impossible error handling, redundant validation, dead catch blocks.
|
|
136
|
+
|
|
137
|
+
**Detection:**
|
|
138
|
+
- Null checks on values that are never null (check upstream guarantees)
|
|
139
|
+
- Try/catch around code that cannot throw
|
|
140
|
+
- Validation of internal function parameters (not at system boundary)
|
|
141
|
+
- Default values for required parameters
|
|
142
|
+
- `typeof x !== 'undefined'` checks in module scope
|
|
143
|
+
|
|
144
|
+
**Verification:** Trace data flow to confirm the defensive check is unnecessary. Read callers and type definitions.
|
|
145
|
+
|
|
146
|
+
**Auto-apply:** Flag only. Show reasoning for why the check is unnecessary.
|
|
147
|
+
|
|
148
|
+
**False positive signals:** Legitimate boundary validation, checks that guard against runtime data (API responses, user input), platform-specific guards.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 8. Performance (Key: `perf` | Risk: MEDIUM)
|
|
153
|
+
|
|
154
|
+
**What:** N+1 queries, blocking I/O in async contexts, bundle bloat, unnecessary re-renders, inefficient algorithms.
|
|
155
|
+
|
|
156
|
+
**Detection categories:**
|
|
157
|
+
|
|
158
|
+
| Category | Patterns |
|
|
159
|
+
|----------|----------|
|
|
160
|
+
| N+1 queries | Loop containing DB/API call |
|
|
161
|
+
| Blocking I/O | `fs.readFileSync` in request handlers, synchronous HTTP |
|
|
162
|
+
| Bundle bloat | Full library import when tree-shakeable (`import lodash` vs `import map from 'lodash/map'`) |
|
|
163
|
+
| Re-renders | Missing `useMemo`/`useCallback` on expensive ops, object literals in JSX props |
|
|
164
|
+
| Inefficient algorithms | Nested loops on large datasets, repeated array scans |
|
|
165
|
+
|
|
166
|
+
**Verification:** Performance changes require benchmarking or profile evidence.
|
|
167
|
+
|
|
168
|
+
**Auto-apply:** Flag only. Provide suggested fix and estimated impact.
|
|
169
|
+
|
|
170
|
+
**False positive signals:** One-time startup code, build scripts, code paths that handle small datasets, intentional eager loading.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 9. DRY Deduplication (Key: `dry` | Risk: HIGH)
|
|
175
|
+
|
|
176
|
+
**What:** Copy-pasted code blocks, duplicated logic across files, repeated patterns that should be abstracted.
|
|
177
|
+
|
|
178
|
+
**Detection:**
|
|
179
|
+
- `jscpd` tool for exact/near-duplicate detection
|
|
180
|
+
- Manual scan for functions with identical structure but different names
|
|
181
|
+
- Threshold: **>=10 identical lines** before flagging
|
|
182
|
+
|
|
183
|
+
**Verification:** Ensure the duplicated code truly serves the same purpose. Sometimes identical code has different *reasons* to change.
|
|
184
|
+
|
|
185
|
+
**Auto-apply:** NEVER for code. Flag only, with suggested extraction.
|
|
186
|
+
|
|
187
|
+
**Important:** Three similar lines is NOT duplication. Only flag when extraction genuinely reduces maintenance burden. Premature abstraction is worse than duplication.
|
|
188
|
+
|
|
189
|
+
**False positive signals:** Test setup code (intentionally duplicated for isolation), similar but semantically different operations, code that will diverge.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 10. Async Patterns (Key: `async` | Risk: HIGH)
|
|
194
|
+
|
|
195
|
+
**What:** Floating promises, `async` in `forEach`, missing `await`, unhandled rejections, race conditions.
|
|
196
|
+
|
|
197
|
+
**Detection:**
|
|
198
|
+
|
|
199
|
+
| Pattern | Problem |
|
|
200
|
+
|---------|---------|
|
|
201
|
+
| `array.forEach(async ...)` | Promises float, no error handling |
|
|
202
|
+
| Missing `await` | Promise returned but not awaited |
|
|
203
|
+
| `async` function with no `await` | Unnecessary async wrapper |
|
|
204
|
+
| `.then()` mixed with `await` | Inconsistent patterns, harder to debug |
|
|
205
|
+
| Missing `.catch()` on fire-and-forget | Unhandled rejection |
|
|
206
|
+
| `Promise.all` without error strategy | One failure kills all |
|
|
207
|
+
|
|
208
|
+
**Verification:**
|
|
209
|
+
1. Confirm the async pattern is actually incorrect (not intentional fire-and-forget)
|
|
210
|
+
2. Apply fix
|
|
211
|
+
3. Run tests — async bugs often only surface under load
|
|
212
|
+
|
|
213
|
+
**Auto-apply:** NEVER. Flag with explanation of the specific risk.
|
|
214
|
+
|
|
215
|
+
**False positive signals:** Intentional fire-and-forget with error logging, event emitters, streaming patterns where floating is expected.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 11. Circular Dependencies (Key: `circular` | Risk: HIGH)
|
|
220
|
+
|
|
221
|
+
**What:** Module A imports B which imports A, creating initialization order issues, bundle bloat, and test difficulty.
|
|
222
|
+
|
|
223
|
+
**Detection:**
|
|
224
|
+
- `madge --circular` (JS/TS)
|
|
225
|
+
- `dependency-cruiser` (JS/TS, configurable)
|
|
226
|
+
- Import graph analysis
|
|
227
|
+
|
|
228
|
+
**Resolution strategies:**
|
|
229
|
+
1. **Extract shared types** to a separate module
|
|
230
|
+
2. **Dependency inversion** — depend on interfaces, not implementations
|
|
231
|
+
3. **Lazy imports** — dynamic `import()` to break cycles
|
|
232
|
+
4. **Barrel file restructuring** — split index.ts re-exports
|
|
233
|
+
|
|
234
|
+
**Verification:**
|
|
235
|
+
1. Run `madge --circular` — should show fewer cycles
|
|
236
|
+
2. Run full test suite
|
|
237
|
+
3. Check bundle size hasn't increased
|
|
238
|
+
|
|
239
|
+
**Auto-apply:** NEVER. Flag with dependency graph and suggested resolution strategy.
|
|
240
|
+
|
|
241
|
+
**False positive signals:** Circular type-only imports (no runtime impact in TS), monorepo cross-references that are resolved by bundler.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Grep Patterns by Dimension
|
|
2
|
+
|
|
3
|
+
Fallback detection patterns when dedicated tools aren't installed. Use with `Grep` tool or `rg`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Dead Code
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Unused imports (JS/TS) — imported but never referenced
|
|
11
|
+
rg "^import .+ from " --type ts -l # Get all files with imports, then cross-reference
|
|
12
|
+
|
|
13
|
+
# Unreachable code after return/throw
|
|
14
|
+
rg "^\s*(return|throw)\b" -A 2 --type ts # Look for code after return/throw
|
|
15
|
+
|
|
16
|
+
# Commented-out code blocks (>3 lines)
|
|
17
|
+
rg "^\s*//" --type ts -c | sort -t: -k2 -rn | head -20 # Files with most comments
|
|
18
|
+
|
|
19
|
+
# TODO/FIXME/HACK markers (potential dead code indicators)
|
|
20
|
+
rg "(TODO|FIXME|HACK|XXX|DEPRECATED)" --type-add 'src:*.{ts,js,py,go,rs}' --type src
|
|
21
|
+
|
|
22
|
+
# Empty catch blocks
|
|
23
|
+
rg "catch\s*\([^)]*\)\s*\{\s*\}" --type ts
|
|
24
|
+
|
|
25
|
+
# Unused function parameters (starts with _)
|
|
26
|
+
rg "function\s+\w+\([^)]*_\w+" --type ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## AI Slop
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Restating comments: "// Set X" or "// Get X" or "// Return X"
|
|
33
|
+
rg "//\s*(Set|Get|Return|Create|Initialize|Define|Check|Update|Delete|Remove)\s+(the\s+)?\w+" --type ts
|
|
34
|
+
|
|
35
|
+
# Obvious JSDoc
|
|
36
|
+
rg "@param\s+\w+\s*-?\s*(The|A|An)\s+\w+$" --type ts
|
|
37
|
+
rg "@returns?\s*(The|A|An)\s+\w+$" --type ts
|
|
38
|
+
|
|
39
|
+
# Filler section markers
|
|
40
|
+
rg "//\s*-{3,}.*-{3,}" --type ts
|
|
41
|
+
rg "//\s*(Helper|Utility|Private|Public)\s+(Functions|Methods|Variables)" --type ts
|
|
42
|
+
|
|
43
|
+
# "This function/method/class" comments
|
|
44
|
+
rg "//.*\b(This (function|method|class|variable|constant|module))" --type ts
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Weak Types
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Explicit any (TypeScript)
|
|
51
|
+
rg ": any\b" --type ts
|
|
52
|
+
rg "as any\b" --type ts
|
|
53
|
+
rg "<any>" --type ts
|
|
54
|
+
|
|
55
|
+
# Implicit any — missing return types on exported functions
|
|
56
|
+
rg "export (async )?function \w+\([^)]*\)\s*\{" --type ts # No return type annotation
|
|
57
|
+
|
|
58
|
+
# Python Any import
|
|
59
|
+
rg "from typing import.*\bAny\b" --type py
|
|
60
|
+
rg ":\s*Any\b" --type py
|
|
61
|
+
|
|
62
|
+
# Object type (too broad)
|
|
63
|
+
rg ": object\b" --type ts
|
|
64
|
+
rg ": Object\b" --type ts
|
|
65
|
+
rg ": \{\}" --type ts # Empty object type
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Security
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Hardcoded secrets
|
|
72
|
+
rg "(api[_-]?key|secret|password|token|auth)\s*[:=]\s*['\"][^'\"]{8,}" -i
|
|
73
|
+
rg "(AKIA[A-Z0-9]{16})" # AWS access keys
|
|
74
|
+
rg "-----BEGIN (RSA |EC |DSA )?PRIVATE.KEY-----"
|
|
75
|
+
rg "(ghp_|gho_|ghu_|ghs_|ghr_)[A-Za-z0-9_]{36,}" # GitHub tokens
|
|
76
|
+
|
|
77
|
+
# Weak crypto
|
|
78
|
+
rg "(md5|sha1)\s*\(" -i --type-add 'src:*.{ts,js,py,go,rs}' --type src
|
|
79
|
+
rg "Math\.random\(\)" --type ts # Insecure random for tokens
|
|
80
|
+
rg "crypto\.createHash\(['\"]md5" --type ts
|
|
81
|
+
|
|
82
|
+
# SQL injection vectors
|
|
83
|
+
rg "(query|exec|execute)\s*\(\s*[`'\"].*\$\{" --type ts # Template literal in SQL
|
|
84
|
+
rg "f['\"].*SELECT.*\{" --type py # Python f-string SQL
|
|
85
|
+
|
|
86
|
+
# Command injection
|
|
87
|
+
rg "(exec|execSync|spawn|spawnSync)\s*\(" --type ts
|
|
88
|
+
rg "(subprocess\.call|os\.system|os\.popen)\s*\(" --type py
|
|
89
|
+
|
|
90
|
+
# eval usage
|
|
91
|
+
rg "\beval\s*\(" --type-add 'src:*.{ts,js,py}' --type src
|
|
92
|
+
|
|
93
|
+
# Insecure defaults
|
|
94
|
+
rg "rejectUnauthorized:\s*false" --type ts
|
|
95
|
+
rg "verify\s*=\s*False" --type py # Disabled SSL verify
|
|
96
|
+
rg "http://" --type-add 'src:*.{ts,js,py,go}' --type src # Plain HTTP
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Legacy Code
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Old Node.js APIs
|
|
103
|
+
rg "\bnew Buffer\b" --type ts
|
|
104
|
+
rg "\bfs\.exists\b" --type ts # Use fs.access instead
|
|
105
|
+
rg "\burl\.parse\b" --type ts # Use new URL() instead
|
|
106
|
+
rg "\bpath\.resolve\(__dirname" --type ts # Use import.meta in ESM
|
|
107
|
+
|
|
108
|
+
# Old JS patterns
|
|
109
|
+
rg "\bvar\s+" --type ts # Use let/const
|
|
110
|
+
rg "\.prototype\." --type ts # Use class syntax
|
|
111
|
+
rg "\barguments\b" --type ts # Use rest params
|
|
112
|
+
rg "require\(" --type ts # CJS in TS files
|
|
113
|
+
|
|
114
|
+
# Unnecessary polyfills
|
|
115
|
+
rg "core-js|regenerator-runtime|@babel/polyfill" --type json
|
|
116
|
+
rg "Object\.assign" --type ts # Spread is available everywhere now
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Type Consolidation
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Duplicate interface names across files
|
|
123
|
+
rg "^(export )?(interface|type) (\w+)" --type ts -o | sort | uniq -d
|
|
124
|
+
|
|
125
|
+
# Pick/Omit opportunities — interfaces with many shared fields
|
|
126
|
+
rg "^\s+(id|name|email|createdAt|updatedAt|status):" --type ts -c | sort -t: -k2 -rn
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Defensive Code
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Unnecessary null checks (look for patterns after non-null assertions)
|
|
133
|
+
rg "\?\.\w+\?\." --type ts # Excessive optional chaining
|
|
134
|
+
rg "!= null|!== null|!= undefined|!== undefined" --type ts
|
|
135
|
+
rg "typeof \w+ !== ['\"]undefined['\"]" --type ts
|
|
136
|
+
|
|
137
|
+
# Empty catch blocks (swallowed errors)
|
|
138
|
+
rg "catch\s*\(\w*\)\s*\{\s*\}" --type ts
|
|
139
|
+
|
|
140
|
+
# Redundant boolean comparisons
|
|
141
|
+
rg "=== true|=== false|!== true|!== false" --type ts
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Performance
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# N+1 query indicators (loop + await)
|
|
148
|
+
rg "for.*\{" -A 5 --type ts | rg "await.*(find|query|fetch|get)"
|
|
149
|
+
|
|
150
|
+
# Sync I/O in potentially async contexts
|
|
151
|
+
rg "readFileSync|writeFileSync|execSync" --type ts
|
|
152
|
+
rg "JSON\.parse\(fs\.readFileSync" --type ts
|
|
153
|
+
|
|
154
|
+
# Bundle bloat — full library imports
|
|
155
|
+
rg "import \w+ from ['\"]lodash['\"]" --type ts # Should use lodash/map
|
|
156
|
+
rg "import \* as" --type ts # Namespace imports prevent tree shaking
|
|
157
|
+
rg "require\(['\"]moment['\"]" --type ts # moment.js is heavy, use date-fns/dayjs
|
|
158
|
+
|
|
159
|
+
# React re-render triggers
|
|
160
|
+
rg "\{\{" --type tsx # Inline objects in JSX (new ref every render)
|
|
161
|
+
rg "useEffect\(\s*\(\)\s*=>" -A 3 --type tsx # Missing deps array
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Async Patterns
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# forEach with async (floating promises)
|
|
168
|
+
rg "\.forEach\(async" --type ts
|
|
169
|
+
|
|
170
|
+
# Missing await
|
|
171
|
+
rg "async.*=>" -A 3 --type ts | rg "return [^a]" # Async arrow without await
|
|
172
|
+
|
|
173
|
+
# Async function with no await
|
|
174
|
+
rg "async function" --type ts # Then check function body for await
|
|
175
|
+
|
|
176
|
+
# Mixed .then() and await
|
|
177
|
+
rg "await.*\.then\(" --type ts
|
|
178
|
+
rg "\.then\(" --type ts -c | sort -t: -k2 -rn # Files with most .then()
|
|
179
|
+
|
|
180
|
+
# Unhandled promise rejection
|
|
181
|
+
rg "\.catch\(\s*\)" --type ts # Empty catch on promise
|
|
182
|
+
rg "Promise\.(all|race|allSettled)\(" --type ts # Check for error handling
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Circular Dependencies
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Barrel file re-exports (common source of circles)
|
|
189
|
+
rg "export \* from" --type ts
|
|
190
|
+
rg "export \{.*\} from ['\"]\.\./" --type ts # Re-exporting from parent
|
|
191
|
+
|
|
192
|
+
# Mutual imports — quick heuristic
|
|
193
|
+
# Find files that import each other (requires cross-referencing)
|
|
194
|
+
rg "from ['\"]\.\.?/" --type ts -l # Files with relative imports
|
|
195
|
+
```
|