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.
- package/.github/workflows/publish.yml +42 -0
- package/.github/workflows/release.yml +156 -0
- package/CONTRIBUTING.md +56 -0
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/install.sh +129 -0
- package/install.yaml +49 -0
- package/llms.txt +33 -0
- package/package.json +24 -0
- package/plugins/auto-lint-fix.ts +39 -0
- package/plugins/auto-summarize-input.ts +45 -0
- package/plugins/billing-guard.ts +101 -0
- package/plugins/capture-insights.ts +215 -0
- package/plugins/cline/hooks/PostToolUse +73 -0
- package/plugins/cline/hooks/PreToolUse +200 -0
- package/plugins/cline/hooks/TaskComplete +134 -0
- package/plugins/cline/hooks/UserPromptSubmit +29 -0
- package/plugins/cursor/rules/auto-lint-fix.mdc +21 -0
- package/plugins/cursor/rules/auto-summarize-input.mdc +17 -0
- package/plugins/cursor/rules/billing-guard.mdc +26 -0
- package/plugins/cursor/rules/capture-insights.mdc +32 -0
- package/plugins/cursor/rules/code-standards.mdc +77 -0
- package/plugins/cursor/rules/dry-guard.mdc +31 -0
- package/plugins/cursorrules-enforcer.ts +124 -0
- package/plugins/dry-guard.ts +107 -0
- package/plugins/kilo/rules/auto-lint-fix.md +15 -0
- package/plugins/kilo/rules/auto-summarize-input.md +12 -0
- package/plugins/kilo/rules/billing-guard.md +21 -0
- package/plugins/kilo/rules/capture-insights.md +27 -0
- package/plugins/kilo/rules/code-standards.md +71 -0
- package/plugins/kilo/rules/dry-guard.md +25 -0
|
@@ -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.
|