ai-guard-plugins 1.1.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.
@@ -0,0 +1,200 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # AI Guard Plugin: PreToolUse Hook for Cline
4
+ # Combines: billing-guard (before), dry-guard, cursorrules-enforcer
5
+ #
6
+ # Requires: jq (https://jqlang.github.io/jq/)
7
+ # Contract: reads JSON from stdin, outputs JSON to stdout
8
+ # =============================================================================
9
+
10
+ set -euo pipefail
11
+
12
+ INPUT=$(cat)
13
+
14
+ TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool // empty' 2>/dev/null || true)
15
+ PARAMS=$(echo "$INPUT" | jq -c '.preToolUse.parameters // {}' 2>/dev/null || echo '{}')
16
+
17
+ # Default: allow
18
+ allow() { echo '{"cancel":false,"contextModification":"","errorMessage":""}'; exit 0; }
19
+ cancel() { echo "{\"cancel\":true,\"contextModification\":\"\",\"errorMessage\":$(echo "$1" | jq -Rs .)}"; exit 0; }
20
+ warn() { echo "{\"cancel\":false,\"contextModification\":$(echo "$1" | jq -Rs .),\"errorMessage\":\"\"}"; exit 0; }
21
+
22
+ [ -z "$TOOL" ] && allow
23
+
24
+ # =============================================================================
25
+ # 1. BILLING GUARD (before) — block commands with billing errors
26
+ # =============================================================================
27
+ if [ "$TOOL" = "execute_command" ]; then
28
+ COMMAND=$(echo "$PARAMS" | jq -r '.command // empty' 2>/dev/null || true)
29
+ if [ -n "$COMMAND" ]; then
30
+ if echo "$COMMAND" | grep -qiE \
31
+ 'payment.method|payment.required|account.is.not.active.*billing|billing.details|quota.exceeded|insufficient.funds|rate.limit.*billing|plan.expired|subscription.inactive'; then
32
+ cancel "BILLING ERROR detected in command. The API provider requires payment. Fix billing before retrying. Do NOT retry this operation."
33
+ fi
34
+ fi
35
+ fi
36
+
37
+ # =============================================================================
38
+ # 2. CURSORRULES ENFORCER — block code violations
39
+ # =============================================================================
40
+ if [ "$TOOL" = "write_to_file" ] || [ "$TOOL" = "insert_code_block" ] || [ "$TOOL" = "search_and_replace" ]; then
41
+ FILE_PATH=$(echo "$PARAMS" | jq -r '.path // empty' 2>/dev/null || true)
42
+ [ -z "$FILE_PATH" ] && allow
43
+
44
+ BASENAME=$(basename "$FILE_PATH")
45
+ LOWER_BASENAME=$(echo "$BASENAME" | tr '[:upper:]' '[:lower:]')
46
+
47
+ # Check: documentation files (before extension filter)
48
+ case "$LOWER_BASENAME" in
49
+ readme|readme.md|changelog.md|contributing.md)
50
+ cancel "CURSORRULES VIOLATIONS in ${BASENAME}:\n- DOCUMENTATION: Creating ${BASENAME}. Do not create documentation files unless explicitly requested.\n\nFix these before proceeding."
51
+ ;;
52
+ esac
53
+
54
+ # Skip non-code extensions
55
+ EXT="${FILE_PATH##*.}"
56
+ case "$EXT" in
57
+ ts|tsx|js|jsx|mts|mjs|cts|cjs) ;;
58
+ *) ;; # Don't exit — DRY guard may still apply for write_to_file
59
+ esac
60
+
61
+ # Skip excluded paths
62
+ for skip in node_modules dist .next build .turbo migrations; do
63
+ [[ "$FILE_PATH" == "$skip/"* || "$FILE_PATH" == *"/$skip/"* ]] && allow
64
+ done
65
+
66
+ # Only run content checks on code files
67
+ IS_CODE=false
68
+ case "$EXT" in
69
+ ts|tsx|js|jsx|mts|mjs|cts|cjs) IS_CODE=true ;;
70
+ esac
71
+
72
+ if [ "$IS_CODE" = true ]; then
73
+ # Extract content
74
+ CONTENT=$(echo "$PARAMS" | jq -r '.content // .new_string // empty' 2>/dev/null || true)
75
+
76
+ if [ -n "$CONTENT" ]; then
77
+ VIOLATIONS=""
78
+
79
+ # Check: as any / as unknown
80
+ if echo "$CONTENT" | grep -qE '\bas\s+(any|unknown)\b'; then
81
+ VIOLATIONS="${VIOLATIONS}\n- TYPE CAST: 'as any' or 'as unknown' found. Use the most specific correct type."
82
+ fi
83
+
84
+ # Check: as Type assertions (exclude import/export aliases like "import { x as Foo }")
85
+ if echo "$CONTENT" | grep -qE '[^{,]\s+as\s+[A-Z][A-Za-z]+' | grep -vqE '(import|export)\s.*\bas\s'; then
86
+ VIOLATIONS="${VIOLATIONS}\n- TYPE ASSERTION: 'as Type' found. Avoid type assertions — use type narrowing or generics."
87
+ fi
88
+
89
+ # Check: require()
90
+ if echo "$CONTENT" | grep -qE '\brequire\s*\('; then
91
+ VIOLATIONS="${VIOLATIONS}\n- REQUIRE: require() found. Use static imports."
92
+ fi
93
+
94
+ # Check: @ts-ignore / @ts-expect-error
95
+ if echo "$CONTENT" | grep -qE '@ts-ignore|@ts-expect-error'; then
96
+ VIOLATIONS="${VIOLATIONS}\n- TS SUPPRESSION: @ts-ignore or @ts-expect-error found. Fix the type error properly."
97
+ fi
98
+
99
+ # Check: TODO / FIXME / HACK / placeholder / later
100
+ if echo "$CONTENT" | grep -qiE '\bTODO\b|\bFIXME\b|\bHACK\b|\bplaceholder\b|//\s*later\b'; then
101
+ VIOLATIONS="${VIOLATIONS}\n- PLACEHOLDER: TODO/FIXME/placeholder found. Production-ready code only."
102
+ fi
103
+
104
+ # Check: underscore-prefixed variables/functions
105
+ if echo "$CONTENT" | grep -qE '(const|let|var|function)\s+_[a-zA-Z]'; then
106
+ VIOLATIONS="${VIOLATIONS}\n- UNDERSCORE NAMING: Variable/function starting with underscore. Do not use underscore prefixes."
107
+ fi
108
+
109
+ # Check: underscore-prefixed filename
110
+ if [ "${BASENAME:0:1}" = "_" ]; then
111
+ VIOLATIONS="${VIOLATIONS}\n- UNDERSCORE FILE: Filename starts with underscore (${BASENAME}). Do not use underscore prefixes."
112
+ fi
113
+
114
+ # Check: index files should only re-export
115
+ if echo "$BASENAME" | grep -qiE '^index\.(ts|tsx|js|jsx|mts|mjs|cts|cjs)$'; then
116
+ NON_EXPORT_LINES=$(echo "$CONTENT" | awk '!/^[[:space:]]*(export[[:space:]]+[{*]|export[[:space:]]+type|export[[:space:]]+default|import[[:space:]]|\/\/|\/\*)/ && $0 !~ /^[[:space:]]*$/ {c++} END {print c+0}')
117
+ if [ "$NON_EXPORT_LINES" -gt 2 ]; then
118
+ VIOLATIONS="${VIOLATIONS}\n- INDEX LOGIC: Logic found in index file. Index files may only re-export modules."
119
+ fi
120
+ else
121
+ # Check: excessive re-exports in non-index files
122
+ REEXPORT_COUNT=$(echo "$CONTENT" | grep -cE 'export\s+\{[^}]*\}\s+from\s+' || echo "0")
123
+ if [ "$REEXPORT_COUNT" -gt 2 ]; then
124
+ VIOLATIONS="${VIOLATIONS}\n- RE-EXPORTS: Multiple re-exports in non-index file."
125
+ fi
126
+ fi
127
+
128
+ if [ -n "$VIOLATIONS" ]; then
129
+ cancel "CURSORRULES VIOLATIONS in ${BASENAME}:$(echo -e "$VIOLATIONS")\n\nFix these before proceeding."
130
+ fi
131
+ fi
132
+ fi
133
+ fi
134
+
135
+ # =============================================================================
136
+ # 3. DRY GUARD — warn before creating duplicate files
137
+ # =============================================================================
138
+ if [ "$TOOL" = "write_to_file" ]; then
139
+ FILE_PATH=$(echo "$PARAMS" | jq -r '.path // empty' 2>/dev/null || true)
140
+ [ -z "$FILE_PATH" ] && allow
141
+
142
+ # Only check code files
143
+ EXT="${FILE_PATH##*.}"
144
+ case "$EXT" in
145
+ ts|tsx|js|jsx) ;;
146
+ *) allow ;;
147
+ esac
148
+
149
+ for skip in node_modules dist .next build .turbo migrations; do
150
+ [[ "$FILE_PATH" == "$skip/"* || "$FILE_PATH" == *"/$skip/"* ]] && allow
151
+ done
152
+
153
+ # Skip if file already exists (editing, not creating)
154
+ [ -f "$FILE_PATH" ] && allow
155
+
156
+ BASENAME=$(basename "$FILE_PATH")
157
+ DIRNAME=$(dirname "$FILE_PATH")
158
+ WARNINGS=""
159
+
160
+ # Tokenize filename and search for similar files
161
+ TOKENS=$(echo "$BASENAME" | sed 's/\.[^.]*$//' | tr '-_.' '\n' | tr '[:upper:]' '[:lower:]' | awk 'length >= 3')
162
+
163
+ for token in $TOKENS; do
164
+ SIMILAR=$(find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) \
165
+ ! -path "*/node_modules/*" ! -path "*/dist/*" ! -path "*/.next/*" ! -path "*/.turbo/*" \
166
+ 2>/dev/null | grep -Fi -- "$token" | grep -Fv -- "$FILE_PATH" | head -8 || true)
167
+ if [ -n "$SIMILAR" ]; then
168
+ COUNT=$(echo "$SIMILAR" | wc -l | tr -d ' ')
169
+ WARNINGS="${WARNINGS}\nSIMILAR FILES (${COUNT} matching '${token}'):\n${SIMILAR}"
170
+ fi
171
+ done
172
+
173
+ # Check target directory for existing files
174
+ if [ -d "$DIRNAME" ]; then
175
+ EXISTING=$(find "$DIRNAME" -maxdepth 1 -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) 2>/dev/null || true)
176
+ if [ -n "$EXISTING" ]; then
177
+ ECOUNT=$(echo "$EXISTING" | wc -l | tr -d ' ')
178
+ WARNINGS="${WARNINGS}\nTARGET DIR already has ${ECOUNT} file(s):\n$(echo "$EXISTING" | head -15)"
179
+ fi
180
+ fi
181
+
182
+ # Check for PascalCase symbol collision
183
+ PASCAL=$(echo "$BASENAME" | sed 's/\.[^.]*$//' | sed -E 's/(^|[-_.])([a-z])/\U\2/g')
184
+ if [ ${#PASCAL} -ge 3 ]; then
185
+ for search_dir in src packages lib app; do
186
+ if [ -d "$search_dir" ]; then
187
+ COLLISIONS=$(grep -rEl -- "export.*${PASCAL}" "$search_dir" 2>/dev/null | grep -Fv -- "$FILE_PATH" | grep -v node_modules | head -5 || true)
188
+ if [ -n "$COLLISIONS" ]; then
189
+ WARNINGS="${WARNINGS}\nSYMBOL COLLISION — '${PASCAL}' already exported from:\n${COLLISIONS}"
190
+ fi
191
+ fi
192
+ done
193
+ fi
194
+
195
+ if [ -n "$WARNINGS" ]; then
196
+ warn "[DRY-GUARD] Before creating ${BASENAME}:$(echo -e "$WARNINGS")\n\nConsider extending an existing file instead of creating a new one."
197
+ fi
198
+ fi
199
+
200
+ allow
@@ -0,0 +1,134 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # AI Guard Plugin: TaskComplete Hook for Cline
4
+ # Simplified: capture-insights (pattern matching + JSONL logging)
5
+ #
6
+ # Requires: jq (https://jqlang.github.io/jq/)
7
+ # Contract: reads JSON from stdin, outputs JSON to stdout
8
+ # =============================================================================
9
+
10
+ set -euo pipefail
11
+
12
+ INPUT=$(cat)
13
+
14
+ TASK_SUMMARY=$(echo "$INPUT" | jq -r '.taskComplete.summary // empty' 2>/dev/null || true)
15
+
16
+ # Default: allow (never cancel on TaskComplete)
17
+ allow() { echo '{"cancel":false,"contextModification":"","errorMessage":""}'; exit 0; }
18
+ inform() { echo "{\"cancel\":false,\"contextModification\":$(echo "$1" | jq -Rs .),\"errorMessage\":\"\"}"; exit 0; }
19
+
20
+ [ -z "$TASK_SUMMARY" ] && allow
21
+
22
+ # =============================================================================
23
+ # Memory file location
24
+ # =============================================================================
25
+ MEMORY_DIR="${HOME}/.cline/memory"
26
+ MEMORY_FILE="${MEMORY_DIR}/insights.jsonl"
27
+
28
+ mkdir -p "$MEMORY_DIR"
29
+
30
+ # =============================================================================
31
+ # Pattern checks (from capture-insights.ts)
32
+ # =============================================================================
33
+ MATCHED_IDS=""
34
+ NOW=$(date -u +"%Y-%m-%dT%H:%M")
35
+ PROJECT_NAME=$(basename "${PWD}")
36
+
37
+ check_pattern() {
38
+ local id="$1"
39
+ local pattern="$2"
40
+ local insight="$3"
41
+
42
+ if echo "$TASK_SUMMARY" | grep -qiE "$pattern"; then
43
+ MATCHED_IDS="${MATCHED_IDS} ${id}"
44
+
45
+ if [ -f "$MEMORY_FILE" ] && grep -q "\"id\":\"${id}\"" "$MEMORY_FILE" 2>/dev/null; then
46
+ # Increment count for existing entry (using jq --arg for safe interpolation)
47
+ TMPFILE=$(mktemp)
48
+ while IFS= read -r line; do
49
+ if echo "$line" | grep -q "\"id\":\"${id}\""; then
50
+ OLD_COUNT=$(echo "$line" | jq -r '.count')
51
+ NEW_COUNT=$((OLD_COUNT + 1))
52
+ OLD_PROJECTS=$(echo "$line" | jq -r '.projects')
53
+ NEW_PROJECTS="$OLD_PROJECTS"
54
+ # Exact token match for project name (not substring)
55
+ if ! printf '%s' "$OLD_PROJECTS" | tr ',' '\n' | grep -Fxq -- "$PROJECT_NAME"; then
56
+ NEW_PROJECTS="${OLD_PROJECTS},${PROJECT_NAME}"
57
+ fi
58
+ echo "$line" | jq -c --argjson count "$NEW_COUNT" --arg last "$NOW" --arg projects "$NEW_PROJECTS" \
59
+ '.count = $count | .last = $last | .projects = $projects'
60
+ else
61
+ echo "$line"
62
+ fi
63
+ done < "$MEMORY_FILE" > "$TMPFILE"
64
+ mv "$TMPFILE" "$MEMORY_FILE"
65
+ else
66
+ # Create new entry
67
+ jq -nc --arg id "$id" --arg insight "$insight" --arg last "$NOW" --arg projects "$PROJECT_NAME" \
68
+ '{id: $id, insight: $insight, count: 1, last: $last, projects: $projects}' >> "$MEMORY_FILE"
69
+ fi
70
+ fi
71
+ }
72
+
73
+ check_pattern "dry-violation" \
74
+ "DRY|don.t repeat|already exists|duplicat" \
75
+ "Check existing files before creating new ones. Extract shared utils when there is clear reuse."
76
+
77
+ check_pattern "unused-code" \
78
+ "unused import|unused variable|dead code" \
79
+ "Biome --fix handles unused imports/variables automatically."
80
+
81
+ check_pattern "type-safety-bypass" \
82
+ "as any|ts-ignore|ts-expect-error" \
83
+ "Never use as any or ts-ignore. Use the most specific correct type."
84
+
85
+ check_pattern "scope-discipline" \
86
+ "refactor.*minimal|minimal change|scope creep" \
87
+ "Make the minimal change needed. Do not refactor while fixing."
88
+
89
+ check_pattern "circular-dep" \
90
+ "circular dependency|circular import" \
91
+ "Restructure module boundaries to break circular dependencies."
92
+
93
+ check_pattern "re-export" \
94
+ "re-export|barrel file|index file.*logic" \
95
+ "Avoid re-exports. Index files may only re-export modules, never logic."
96
+
97
+ check_pattern "path-resolution" \
98
+ "process.cwd|project root.*monorepo" \
99
+ "Never assume process.cwd() equals project root in monorepos."
100
+
101
+ check_pattern "data-migration" \
102
+ "migration|schema change|database migrat" \
103
+ "Verify schema and data integrity after migrations. Make migrations idempotent."
104
+
105
+ check_pattern "workaround" \
106
+ "workaround|hack|bandaid|band-aid" \
107
+ "Document why workaround was needed and plan a proper fix."
108
+
109
+ check_pattern "performance" \
110
+ "performance|slow query|optimize|bottleneck" \
111
+ "Profile before optimizing. Measure, do not guess."
112
+
113
+ check_pattern "security" \
114
+ "security|secret|credential|api.key|token leak" \
115
+ "Review credentials handling. Never commit secrets."
116
+
117
+ check_pattern "test-mock" \
118
+ "test.*mock.*implementation|mock.*detail" \
119
+ "Mock behavior (modules), not implementation details."
120
+
121
+ if [ -n "$MATCHED_IDS" ]; then
122
+ ENTRY_COUNT=0
123
+ [ -f "$MEMORY_FILE" ] && ENTRY_COUNT=$(wc -l < "$MEMORY_FILE" | tr -d ' ')
124
+
125
+ # Squeeze to top 15 if over limit
126
+ if [ "$ENTRY_COUNT" -gt 15 ]; then
127
+ TMPFILE=$(mktemp)
128
+ jq -s 'sort_by(-.count) | .[0:15] | .[]' "$MEMORY_FILE" > "$TMPFILE" 2>/dev/null && mv "$TMPFILE" "$MEMORY_FILE" || true
129
+ fi
130
+
131
+ inform "[capture-insights] Patterns detected in session (${PROJECT_NAME}, ${ENTRY_COUNT} total entries). Learning from this session."
132
+ fi
133
+
134
+ allow
@@ -0,0 +1,29 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # AI Guard Plugin: UserPromptSubmit Hook for Cline
4
+ # Simplified: auto-summarize-input (warns about large inputs)
5
+ #
6
+ # Requires: jq (https://jqlang.github.io/jq/)
7
+ # Contract: reads JSON from stdin, outputs JSON to stdout
8
+ # =============================================================================
9
+
10
+ set -euo pipefail
11
+
12
+ INPUT=$(cat)
13
+
14
+ PROMPT=$(echo "$INPUT" | jq -er '.userPromptSubmit.userPrompt // empty' 2>/dev/null || true)
15
+
16
+ # Default: allow
17
+ allow() { echo '{"cancel":false,"contextModification":"","errorMessage":""}'; exit 0; }
18
+ warn() { echo "{\"cancel\":false,\"contextModification\":$(echo "$1" | jq -Rs .),\"errorMessage\":\"\"}"; exit 0; }
19
+
20
+ [ -z "$PROMPT" ] && allow
21
+
22
+ THRESHOLD=10000
23
+ CHAR_COUNT=${#PROMPT}
24
+
25
+ if [ "$CHAR_COUNT" -gt "$THRESHOLD" ]; then
26
+ warn "[auto-summarize] Input is very large (${CHAR_COUNT} chars). Before processing, summarize this input while preserving ALL code snippets, file paths, error messages, and requirements verbatim. Remove ONLY redundancy, repetition, and filler text."
27
+ fi
28
+
29
+ allow
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: "Auto-format code with Biome after every file write or edit"
3
+ globs: "**/*.ts,**/*.tsx,**/*.js,**/*.jsx,**/*.mts,**/*.mjs,**/*.cts,**/*.cjs"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Auto Lint Fix
8
+
9
+ After EVERY file write or edit to a TypeScript/JavaScript file, run:
10
+
11
+ ```bash
12
+ "${BIOME_PATH:-biome}" check --fix --unsafe <filepath>
13
+ ```
14
+
15
+ ## Rules
16
+
17
+ - Only run on code files: .ts, .tsx, .js, .jsx, .mts, .mjs, .cts, .cjs
18
+ - Skip files in: node_modules, dist, .next, build, .turbo
19
+ - If `BIOME_PATH` environment variable is set, use that path instead of `biome`
20
+ - If Biome is not installed, skip formatting (do not fail)
21
+ - Do not manually fix formatting issues that Biome handles automatically
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: "Summarize large inputs to preserve context window tokens"
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Auto Summarize Input
7
+
8
+ When receiving input that exceeds 10,000 characters, summarize it before processing.
9
+
10
+ ## Summarization rules
11
+
12
+ - Preserve ALL code snippets verbatim
13
+ - Preserve ALL file paths verbatim
14
+ - Preserve ALL error messages verbatim
15
+ - Preserve ALL requirements and specifications verbatim
16
+ - Remove ONLY: redundancy, repetition, and filler text
17
+ - Note the original character count and reduction percentage
@@ -0,0 +1,26 @@
1
+ ---
2
+ description: "Detect and stop on billing/API payment errors to prevent infinite retry loops"
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Billing Guard
7
+
8
+ If ANY API call, tool execution, or command output contains text matching these patterns, IMMEDIATELY stop all operations:
9
+
10
+ - "no payment method" or "add a payment method"
11
+ - "payment required"
12
+ - "account is not active" with "billing"
13
+ - "billing details"
14
+ - "quota exceeded"
15
+ - "insufficient funds"
16
+ - "rate limit" with "billing"
17
+ - "plan expired"
18
+ - "subscription inactive"
19
+
20
+ ## Required behavior
21
+
22
+ 1. STOP all current operations immediately
23
+ 2. Do NOT retry the failed operation
24
+ 3. Do NOT delegate or spawn sub-tasks
25
+ 4. Notify the user that billing needs to be fixed before continuing
26
+ 5. Do NOT attempt workarounds or alternative approaches — the billing issue must be resolved first
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: "Track and learn from recurring coding mistakes across sessions"
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Capture Insights
7
+
8
+ Monitor your own outputs and actions for these recurring anti-patterns. When detected, apply the corresponding lesson immediately.
9
+
10
+ ## Tracked patterns
11
+
12
+ | Pattern | Lesson |
13
+ |---------|--------|
14
+ | DRY violation ("already exists", "duplicate") | Check existing files before creating new ones. Extract shared utils for clear reuse. |
15
+ | Unused code (imports, variables, dead code) | Biome --fix handles unused imports/variables automatically. |
16
+ | Type safety bypass (as any, ts-ignore) | Never use as any or ts-ignore. Use the most specific correct type. |
17
+ | Scope creep (refactoring while fixing) | Make the minimal change needed. Do not refactor while fixing. |
18
+ | Circular dependencies | Restructure module boundaries to break circular dependencies. |
19
+ | Re-export overuse (barrel files with logic) | Index files may only re-export modules, never contain logic. |
20
+ | Path resolution (process.cwd assumptions) | Never assume process.cwd() equals project root in monorepos. |
21
+ | Migration issues | Verify schema and data integrity after migrations. Make migrations idempotent. |
22
+ | Workarounds and hacks | Document why the workaround was needed and plan a proper fix. |
23
+ | Performance guessing | Profile before optimizing. Measure, do not guess. |
24
+ | Security (secrets, credentials, tokens) | Review credentials handling. Never commit secrets. |
25
+ | Test mock overreach | Mock behavior (modules), not implementation details. |
26
+
27
+ ## Required behavior
28
+
29
+ When you detect one of these patterns in your own work:
30
+ 1. Stop and acknowledge the pattern
31
+ 2. Apply the corresponding lesson
32
+ 3. Correct the action before proceeding
@@ -0,0 +1,77 @@
1
+ ---
2
+ description: "Enforce TypeScript/JavaScript coding standards on every file write and edit"
3
+ globs: "**/*.ts,**/*.tsx,**/*.js,**/*.jsx,**/*.mts,**/*.mjs,**/*.cts,**/*.cjs"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Code Standards Enforcer
8
+
9
+ These rules apply to every code file write and edit. Violations must be fixed before proceeding.
10
+
11
+ ## Type safety
12
+
13
+ - Never use `as any` or `as unknown`. Use the most specific correct type.
14
+ - Never use `as Type` assertions. Use type narrowing, generics, or satisfies instead.
15
+ - Never use `@ts-ignore` or `@ts-expect-error`. Fix the underlying type error.
16
+
17
+ ```typescript
18
+ // Bad
19
+ const data = response as any;
20
+ const user = getUser() as UserType;
21
+ // @ts-ignore
22
+ brokenCall();
23
+
24
+ // Good
25
+ const data: ApiResponse = response;
26
+ const user = getUser(); // return type already UserType
27
+ ```
28
+
29
+ ## Import style
30
+
31
+ - Never use `require()`. Use static `import` statements.
32
+
33
+ ```typescript
34
+ // Bad
35
+ const fs = require('fs');
36
+
37
+ // Good
38
+ import fs from 'node:fs';
39
+ ```
40
+
41
+ ## No placeholders
42
+
43
+ - Never leave `TODO`, `FIXME`, `HACK`, `placeholder`, or `// later` comments. All code must be production-ready.
44
+
45
+ ## Naming
46
+
47
+ - Never prefix variables or functions with underscore (`_`).
48
+ - Never prefix filenames with underscore.
49
+
50
+ ```typescript
51
+ // Bad
52
+ const _count = 0;
53
+ function _helper() {}
54
+
55
+ // Good
56
+ const count = 0;
57
+ function helper() {}
58
+ ```
59
+
60
+ ## Index files
61
+
62
+ - Index/barrel files (`index.ts`, `index.js`) may ONLY contain re-exports. No business logic.
63
+ - Non-index files may have at most 2 re-export statements.
64
+
65
+ ```typescript
66
+ // Good index.ts
67
+ export { UserService } from './user-service';
68
+ export { AuthService } from './auth-service';
69
+
70
+ // Bad index.ts
71
+ export { UserService } from './user-service';
72
+ const cache = new Map(); // logic does not belong here
73
+ ```
74
+
75
+ ## Documentation files
76
+
77
+ - Do not create README.md, CHANGELOG.md, or CONTRIBUTING.md unless explicitly requested.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: "Check for duplicate files and symbol collisions before creating new code files"
3
+ globs: "**/*.ts,**/*.tsx,**/*.js,**/*.jsx"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # DRY Guard
8
+
9
+ Before creating ANY new code file (.ts, .tsx, .js, .jsx), perform these checks:
10
+
11
+ ## 1. Similar file search
12
+
13
+ Tokenize the new filename by splitting on `-`, `_`, and `.` (ignore tokens shorter than 3 characters). Search the project for existing files whose names contain any of those tokens.
14
+
15
+ Skip directories: node_modules, dist, .next, build, .turbo, migrations
16
+
17
+ ## 2. Target directory check
18
+
19
+ List existing code files in the target directory. If the directory already contains files, consider whether the new file's logic belongs in one of them.
20
+
21
+ ## 3. Symbol collision check
22
+
23
+ Convert the filename to PascalCase (e.g., `format-date.ts` becomes `FormatDate`). Search `src/`, `packages/`, `lib/`, and `app/` for existing exports matching that name.
24
+
25
+ ## Required behavior
26
+
27
+ - If similar files are found: review them before creating a new file
28
+ - If the symbol already exists: extend the existing file instead
29
+ - If the target directory has related files: consolidate rather than create
30
+
31
+ Do NOT create a new file when extending an existing one would be cleaner.