@ivannikov-pro/ai-context-surgeon 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.
Files changed (87) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +372 -0
  3. package/bin/catalog.js +153 -0
  4. package/bin/cli.js +380 -0
  5. package/bin/installer.js +135 -0
  6. package/bin/prompts.js +371 -0
  7. package/checklists/phase-1-analysis.md +58 -0
  8. package/checklists/phase-2-planning.md +67 -0
  9. package/checklists/phase-3-restructuring.md +77 -0
  10. package/checklists/phase-4-documentation.md +111 -0
  11. package/checklists/phase-5-validation.md +91 -0
  12. package/examples/before-after/README.md +139 -0
  13. package/examples/ideal-monorepo/README.md +127 -0
  14. package/knowledge/agent-context-system/artifacts/guide.md +183 -0
  15. package/knowledge/agent-context-system/artifacts/knowledge.md +177 -0
  16. package/knowledge/agent-context-system/artifacts/skills.md +101 -0
  17. package/knowledge/agent-context-system/artifacts/workflows.md +143 -0
  18. package/knowledge/agent-context-system/metadata.json +26 -0
  19. package/knowledge/agent-context-system/timestamps.json +5 -0
  20. package/knowledge/agent-vulnerabilities/LICENSE +21 -0
  21. package/knowledge/agent-vulnerabilities/artifacts/stealth_injection.md +110 -0
  22. package/knowledge/agent-vulnerabilities/artifacts/vulnerabilities.md +232 -0
  23. package/knowledge/agent-vulnerabilities/metadata.json +14 -0
  24. package/knowledge/agent-vulnerabilities/timestamps.json +5 -0
  25. package/knowledge/power-words-dictionary/LICENSE +21 -0
  26. package/knowledge/power-words-dictionary/artifacts/dictionary.md +231 -0
  27. package/knowledge/power-words-dictionary/artifacts/prompt_amplifier.py +381 -0
  28. package/knowledge/power-words-dictionary/metadata.json +14 -0
  29. package/knowledge/power-words-dictionary/timestamps.json +5 -0
  30. package/package.json +77 -0
  31. package/roles/README.md +81 -0
  32. package/roles/architect.md +203 -0
  33. package/roles/inspector.md +232 -0
  34. package/roles/librarian.md +176 -0
  35. package/roles/scout.md +169 -0
  36. package/roles/surgeon.md +172 -0
  37. package/roles/tuner.md +204 -0
  38. package/skills/annotate-jsdoc/SKILL.md +262 -0
  39. package/skills/prompt-engineering/LICENSE +21 -0
  40. package/skills/prompt-engineering/SKILL.md +235 -0
  41. package/skills/prompt-engineering/scripts/extract_instructions.py +416 -0
  42. package/skills/prompt-engineering/scripts/prompt_amplifier.py +381 -0
  43. package/skills/prompt-engineering/scripts/prompt_diff_tracker.py +281 -0
  44. package/skills/prompt-engineering/scripts/prompt_dna_analyzer.py +692 -0
  45. package/skills/prompt-engineering/scripts/templates/code_review.md +47 -0
  46. package/skills/prompt-engineering/scripts/templates/dump_extraction.md +59 -0
  47. package/skills/prompt-engineering/scripts/templates/multi_agent_orchestration.md +100 -0
  48. package/skills/prompt-engineering/scripts/templates/prompt_audit.md +106 -0
  49. package/skills/prompt-engineering/scripts/templates/stealth_injection.md +110 -0
  50. package/skills/prompt-engineering/scripts/templates/task_automation.md +87 -0
  51. package/skills/prompt-engineering/workflows/amplify.md +36 -0
  52. package/skills/prompt-engineering/workflows/audit.md +55 -0
  53. package/skills/prompt-engineering/workflows/context-dump.md +90 -0
  54. package/skills/prompt-engineering/workflows/diff.md +44 -0
  55. package/strategy/bash-guide.md +134 -0
  56. package/strategy/context-exclusion.md +220 -0
  57. package/strategy/context-weight-theory.md +49 -0
  58. package/strategy/file-navigation-header.md +562 -0
  59. package/strategy/jsdoc-guide.md +596 -0
  60. package/strategy/monorepo_strategy.md +726 -0
  61. package/strategy/package-json-guide.md +541 -0
  62. package/templates/AGENTS.md.template +148 -0
  63. package/templates/antigravityignore.template +64 -0
  64. package/templates/cursorrules.template +7 -0
  65. package/templates/knowledge-item.template +44 -0
  66. package/templates/package-json-ideal.template +26 -0
  67. package/templates/package-readme.template +45 -0
  68. package/templates/publish-meta.template +34 -0
  69. package/templates/skill.template +50 -0
  70. package/templates/workflow.template +33 -0
  71. package/tools/analyze-package-json.sh +213 -0
  72. package/tools/analyze-structure.sh +101 -0
  73. package/tools/audit-jsdoc.sh +176 -0
  74. package/tools/check-fnh-freshness.sh +74 -0
  75. package/tools/detect-circular-deps.sh +147 -0
  76. package/tools/detect-god-files.sh +71 -0
  77. package/tools/enforce-god-files.sh +112 -0
  78. package/tools/enrich-package-json.js +311 -0
  79. package/tools/generate-jsdoc-headers.sh +109 -0
  80. package/tools/generate-source-map.sh +71 -0
  81. package/tools/lint-imports.sh +123 -0
  82. package/tools/measure-context-cost.sh +206 -0
  83. package/tools/scan-fnh.sh +174 -0
  84. package/tools/shared/config.sh +53 -0
  85. package/tools/validate-context-hygiene.sh +52 -0
  86. package/tools/validate-context-weight.sh +100 -0
  87. package/tools/validate-naming.sh +98 -0
@@ -0,0 +1,176 @@
1
+ #!/bin/bash
2
+ # Tool: audit-jsdoc — Analyze JSDoc quality for AI-agent readiness | DEPS: none
3
+ # USAGE: bash tools/audit-jsdoc.sh /path/to/directory
4
+ # OUTPUT: JSDoc quality audit report
5
+ # MODE: read-only analysis
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ TARGET="${1:-.}"
12
+
13
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
14
+ echo "Usage: bash tools/audit-jsdoc.sh /path/to/directory"
15
+ echo ""
16
+ echo "Analyzes JSDoc comments in TypeScript/JavaScript files for AI-readiness."
17
+ echo "Detects:"
18
+ echo " - Missing file headers"
19
+ echo " - Wasteful tags (@author, @since, @copyright, @param {type} in TS)"
20
+ echo " - Missing critical tags (@throws, side effects)"
21
+ echo " - Multi-line blocks that could be one-liners"
22
+ echo " - Token cost estimation"
23
+ exit 0
24
+ fi
25
+
26
+ if [[ ! -d "$TARGET" ]]; then
27
+ echo "❌ Error: '$TARGET' is not a directory"
28
+ exit 1
29
+ fi
30
+
31
+ echo "📝 JSDoc AI-Readiness Audit: $TARGET"
32
+ echo "════════════════════════════════════════════════════════"
33
+
34
+ # Find source files
35
+ SRC_FILES=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' \) \
36
+ -not -path '*/node_modules/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' -not -path '*/dist/*' -not -path '*/.git/*' \
37
+ -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' -not -name '*.min.*')
38
+
39
+ TOTAL_FILES=$(echo "$SRC_FILES" | wc -l | tr -d ' ')
40
+ echo "Scanning $TOTAL_FILES source files..."
41
+ echo ""
42
+
43
+ # Metrics
44
+ FILES_NO_HEADER=0
45
+ FILES_WITH_HEADER=0
46
+ WASTEFUL_TAGS=0
47
+ MULTILINE_BLOCKS=0
48
+ TOTAL_JSDOC_LINES=0
49
+ USEFUL_ANNOTATIONS=0
50
+
51
+ echo "$SRC_FILES" | while read -r file; do
52
+ [[ -z "$file" ]] && continue
53
+
54
+ rel_path="${file#$TARGET/}"
55
+ first_line=$(head -1 "$file" 2>/dev/null || echo "")
56
+ issues=""
57
+
58
+ # Check file header
59
+ if ! echo "$first_line" | grep -q '/\*\*'; then
60
+ FILES_NO_HEADER=$((FILES_NO_HEADER + 1))
61
+ else
62
+ FILES_WITH_HEADER=$((FILES_WITH_HEADER + 1))
63
+ fi
64
+
65
+ # Count JSDoc lines
66
+ file_jsdoc_lines=$(grep -c '^\s*\*\|^\s*/\*\*' "$file" || true)
67
+ TOTAL_JSDOC_LINES=$((TOTAL_JSDOC_LINES + file_jsdoc_lines))
68
+
69
+ # Detect wasteful tags (Tier 4 — should be removed)
70
+ wasteful=""
71
+ for tag in "@author" "@since" "@version" "@copyright" "@license" "@date" "@fileoverview" "@module" "@namespace" "@memberof" "@classdesc" "@constructs"; do
72
+ if grep -q "$tag" "$file" 2>/dev/null; then
73
+ count=$(grep -c "$tag" "$file" || true)
74
+ wasteful="$wasteful $tag(${count})"
75
+ WASTEFUL_TAGS=$((WASTEFUL_TAGS + count))
76
+ fi
77
+ done
78
+
79
+ # Detect @param {type} in TypeScript files (redundant)
80
+ if [[ "$file" == *.ts || "$file" == *.tsx ]]; then
81
+ param_type_count=$(grep -cE '@param\s+\{' "$file" || true)
82
+ if [[ $param_type_count -gt 0 ]]; then
83
+ wasteful="$wasteful @param{type}(${param_type_count})"
84
+ WASTEFUL_TAGS=$((WASTEFUL_TAGS + param_type_count))
85
+ fi
86
+
87
+ returns_type_count=$(grep -cE '@returns?\s+\{' "$file" || true)
88
+ if [[ $returns_type_count -gt 0 ]]; then
89
+ wasteful="$wasteful @returns{type}(${returns_type_count})"
90
+ WASTEFUL_TAGS=$((WASTEFUL_TAGS + returns_type_count))
91
+ fi
92
+ fi
93
+
94
+ # Detect useful tags
95
+ useful=""
96
+ for tag in "@throws" "@deprecated" "@mutates" "@sideeffect"; do
97
+ if grep -q "$tag" "$file" 2>/dev/null; then
98
+ count=$(grep -c "$tag" "$file" || true)
99
+ useful="$useful $tag(${count})"
100
+ USEFUL_ANNOTATIONS=$((USEFUL_ANNOTATIONS + count))
101
+ fi
102
+ done
103
+
104
+ # Detect multi-line JSDoc blocks (>3 lines)
105
+ multiline=$(python3 -c "
106
+ import re
107
+ with open('$file') as f:
108
+ content = f.read()
109
+ blocks = re.findall(r'/\*\*[\s\S]*?\*/', content)
110
+ big_blocks = [b for b in blocks if b.count('\n') > 3]
111
+ print(len(big_blocks))
112
+ " 2>/dev/null || echo "0")
113
+
114
+ if [[ $multiline -gt 0 ]]; then
115
+ MULTILINE_BLOCKS=$((MULTILINE_BLOCKS + multiline))
116
+ fi
117
+
118
+ # Report per-file issues
119
+ if [[ -n "$wasteful" || $multiline -gt 0 ]] || ! echo "$first_line" | grep -q '/\*\*'; then
120
+ echo " 📄 $rel_path"
121
+
122
+ if ! echo "$first_line" | grep -q '/\*\*'; then
123
+ echo " 🟡 No file header"
124
+ fi
125
+
126
+ if [[ -n "$wasteful" ]]; then
127
+ echo " 🔴 Wasteful:$wasteful"
128
+ fi
129
+
130
+ if [[ $multiline -gt 0 ]]; then
131
+ echo " 🟡 $multiline multi-line block(s) — consider one-liners"
132
+ fi
133
+
134
+ if [[ -n "$useful" ]]; then
135
+ echo " ✅ Useful:$useful"
136
+ fi
137
+ fi
138
+
139
+ done
140
+
141
+ echo ""
142
+ echo "════════════════════════════════════════════════════════"
143
+ echo ""
144
+ echo "📊 SUMMARY"
145
+ echo "────────────────────────────────────────"
146
+ echo "Total source files: $TOTAL_FILES"
147
+ echo "Files with header: $FILES_WITH_HEADER"
148
+ echo "Files without header: $FILES_NO_HEADER"
149
+ echo "Total JSDoc lines: $TOTAL_JSDOC_LINES"
150
+ echo "Wasteful tag instances: $WASTEFUL_TAGS"
151
+ echo "Multi-line blocks: $MULTILINE_BLOCKS"
152
+ echo "Useful annotations: $USEFUL_ANNOTATIONS"
153
+ echo ""
154
+
155
+ # Token estimate
156
+ EST_WASTEFUL_TOKENS=$((WASTEFUL_TAGS * 8))
157
+ EST_MULTILINE_TOKENS=$((MULTILINE_BLOCKS * 30))
158
+ EST_TOTAL_WASTE=$((EST_WASTEFUL_TOKENS + EST_MULTILINE_TOKENS))
159
+
160
+ echo "💰 ESTIMATED WASTE"
161
+ echo "────────────────────────────────────────"
162
+ echo "Wasteful tags: ~${EST_WASTEFUL_TOKENS} tokens"
163
+ echo "Multi-line blocks: ~${EST_MULTILINE_TOKENS} tokens (could be one-liners)"
164
+ echo "Total waste: ~${EST_TOTAL_WASTE} tokens"
165
+ echo ""
166
+
167
+ if [[ $EST_TOTAL_WASTE -gt 1000 ]]; then
168
+ echo "🔴 HIGH WASTE — significant context budget being burned on noise"
169
+ elif [[ $EST_TOTAL_WASTE -gt 300 ]]; then
170
+ echo "🟡 MODERATE WASTE — some cleanup recommended"
171
+ else
172
+ echo "✅ LOW WASTE — JSDoc is fairly optimized"
173
+ fi
174
+
175
+ echo ""
176
+ echo "📖 See strategy/jsdoc-guide.md for full optimization guide"
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ # Tool: check-fnh-freshness — warns if source files changed but their FNH headers didn't | DEPS: none
3
+ # USAGE: bash tools/check-fnh-freshness.sh [base-ref]
4
+ # OUTPUT: list of files with potentially stale FNH headers
5
+ # MODE: read-only, git-based analysis
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ BASE_REF="${1:-HEAD~1}"
12
+ WARN_COUNT=0
13
+ CHECKED=0
14
+
15
+ echo "🧭 FNH Freshness Check"
16
+ echo " Comparing against: $BASE_REF"
17
+ echo " ──────────────────────────────────"
18
+
19
+ # Check TypeScript/JavaScript files
20
+ for file in $(git diff --name-only "$BASE_REF" -- '*.ts' '*.js' '*.tsx' '*.jsx' '*.sol' 2>/dev/null || true); do
21
+ [ -f "$file" ] || continue
22
+ CHECKED=$((CHECKED + 1))
23
+
24
+ # Count how many lines changed in the FNH region (first 8 lines)
25
+ fnh_diff=$(git diff "$BASE_REF" -- "$file" | awk '/^@@/{found=1} found{print}' | head -30 | grep -cE '^\+.*(/\*\*|\* )' || true)
26
+
27
+ # Count total changed lines (excluding FNH)
28
+ total_changes=$(git diff "$BASE_REF" -- "$file" | grep -cE '^[+-]' || true)
29
+
30
+ if [ "$total_changes" -gt 5 ] && [ "$fnh_diff" -eq 0 ]; then
31
+ echo " ⚠️ $file"
32
+ echo " $total_changes lines changed, FNH header unchanged"
33
+ WARN_COUNT=$((WARN_COUNT + 1))
34
+ fi
35
+ done
36
+
37
+ # Check Markdown files — look for > blockquote after H1
38
+ for file in $(git diff --name-only "$BASE_REF" -- '*.md' 2>/dev/null || true); do
39
+ [ -f "$file" ] || continue
40
+ CHECKED=$((CHECKED + 1))
41
+
42
+ # Check if file has a > context line in first 5 lines
43
+ has_fnh=$(head -5 "$file" | grep -c '^>' || true)
44
+ if [ "$has_fnh" -eq 0 ]; then
45
+ echo " ❌ $file — missing FNH (no > blockquote after H1)"
46
+ WARN_COUNT=$((WARN_COUNT + 1))
47
+ fi
48
+ done
49
+
50
+ # Check shell scripts
51
+ for file in $(git diff --name-only "$BASE_REF" -- '*.sh' 2>/dev/null || true); do
52
+ [ -f "$file" ] || continue
53
+ CHECKED=$((CHECKED + 1))
54
+
55
+ has_fnh=$(head -3 "$file" | grep -c '^# Tool:\|^# Script:\|^# Config:' || true)
56
+ if [ "$has_fnh" -eq 0 ]; then
57
+ echo " ❌ $file — missing FNH (no # Tool/Script/Config header)"
58
+ WARN_COUNT=$((WARN_COUNT + 1))
59
+ fi
60
+ done
61
+
62
+ echo ""
63
+ echo " ──────────────────────────────────"
64
+ echo " Files checked: $CHECKED"
65
+ echo " Warnings: $WARN_COUNT"
66
+
67
+ if [ "$WARN_COUNT" -gt 0 ]; then
68
+ echo ""
69
+ echo " 💡 Run the annotate-jsdoc skill to fix missing/stale FNH headers"
70
+ exit 1
71
+ else
72
+ echo " ✅ All FNH headers look fresh"
73
+ exit 0
74
+ fi
@@ -0,0 +1,147 @@
1
+ #!/bin/bash
2
+ # Tool: detect-circular-deps — Detect circular dependencies between packages | DEPS: none
3
+ # USAGE: bash tools/detect-circular-deps.sh /path/to/monorepo
4
+ # OUTPUT: list of circular dependency chains
5
+ # MODE: read-only analysis
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ TARGET="${1:-.}"
12
+
13
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
14
+ echo "Usage: bash tools/detect-circular-deps.sh /path/to/monorepo"
15
+ echo ""
16
+ echo "Detects circular dependencies between packages in a monorepo."
17
+ echo "Scans package.json files for internal dependencies and builds a graph."
18
+ echo "Reports any cycles found."
19
+ exit 0
20
+ fi
21
+
22
+ if [[ ! -d "$TARGET" ]]; then
23
+ echo "❌ Error: '$TARGET' is not a directory"
24
+ exit 1
25
+ fi
26
+
27
+ echo "🔍 Checking circular dependencies in: $TARGET"
28
+ echo "────────────────────────────────────────"
29
+
30
+ # Build dependency graph from package.json files
31
+ TEMP_FILE=$(mktemp)
32
+ PACKAGES_DIR="$TARGET/packages"
33
+ APPS_DIR="$TARGET/apps"
34
+
35
+ # Collect all internal package names
36
+ declare -a INTERNAL_PACKAGES=()
37
+
38
+ for pkg_json in "$PACKAGES_DIR"/*/package.json "$APPS_DIR"/*/package.json; do
39
+ if [[ -f "$pkg_json" ]]; then
40
+ pkg_name=$(python3 -c "import json; print(json.load(open('$pkg_json'))['name'])" 2>/dev/null || echo "unknown")
41
+ if [[ "$pkg_name" != "unknown" ]]; then
42
+ INTERNAL_PACKAGES+=("$pkg_name")
43
+ fi
44
+ fi
45
+ done
46
+
47
+ if [[ ${#INTERNAL_PACKAGES[@]} -eq 0 ]]; then
48
+ echo "⚠️ No packages found in packages/ or apps/"
49
+ echo " This tool expects a monorepo with packages/*/package.json"
50
+ rm -f "$TEMP_FILE"
51
+ exit 0
52
+ fi
53
+
54
+ echo "Found ${#INTERNAL_PACKAGES[@]} internal packages"
55
+ echo ""
56
+
57
+ # Check for cycles using import scanning
58
+ CYCLES_FOUND=0
59
+
60
+ for pkg_dir in "$PACKAGES_DIR"/* "$APPS_DIR"/*; do
61
+ if [[ -d "$pkg_dir" && -f "$pkg_dir/package.json" ]]; then
62
+ pkg_name=$(python3 -c "import json; print(json.load(open('$pkg_dir/package.json'))['name'])" 2>/dev/null || continue)
63
+
64
+ # Get dependencies
65
+ deps=$(python3 -c "
66
+ import json
67
+ data = json.load(open('$pkg_dir/package.json'))
68
+ all_deps = {}
69
+ all_deps.update(data.get('dependencies', {}))
70
+ all_deps.update(data.get('devDependencies', {}))
71
+ internals = [d for d in all_deps if any(d == p for p in '''${INTERNAL_PACKAGES[*]}'''.split())]
72
+ print(' '.join(internals))
73
+ " 2>/dev/null || echo "")
74
+
75
+ if [[ -n "$deps" ]]; then
76
+ for dep in $deps; do
77
+ echo "$pkg_name -> $dep" >> "$TEMP_FILE"
78
+ done
79
+ fi
80
+ fi
81
+ done
82
+
83
+ echo "📊 DEPENDENCY GRAPH"
84
+ echo "────────────────────────────────────────"
85
+
86
+ if [[ -s "$TEMP_FILE" ]]; then
87
+ cat "$TEMP_FILE"
88
+ else
89
+ echo "No internal dependencies found."
90
+ fi
91
+
92
+ echo ""
93
+ echo "────────────────────────────────────────"
94
+
95
+ # Simple cycle detection using Python
96
+ python3 -c "
97
+ import sys
98
+
99
+ edges = []
100
+ with open('$TEMP_FILE') as f:
101
+ for line in f:
102
+ parts = line.strip().split(' -> ')
103
+ if len(parts) == 2:
104
+ edges.append((parts[0], parts[1]))
105
+
106
+ # Build adjacency list
107
+ graph = {}
108
+ for src, dst in edges:
109
+ graph.setdefault(src, []).append(dst)
110
+
111
+ # DFS cycle detection
112
+ WHITE, GRAY, BLACK = 0, 1, 2
113
+ color = {node: WHITE for node in graph}
114
+ for node in set(dst for _, dst in edges):
115
+ color.setdefault(node, WHITE)
116
+
117
+ cycles = []
118
+
119
+ def dfs(node, path):
120
+ color[node] = GRAY
121
+ path.append(node)
122
+ for neighbor in graph.get(node, []):
123
+ if color.get(neighbor) == GRAY:
124
+ cycle_start = path.index(neighbor)
125
+ cycles.append(path[cycle_start:] + [neighbor])
126
+ elif color.get(neighbor) == WHITE:
127
+ dfs(neighbor, path)
128
+ path.pop()
129
+ color[node] = BLACK
130
+
131
+ for node in list(color.keys()):
132
+ if color[node] == WHITE:
133
+ dfs(node, [])
134
+
135
+ if cycles:
136
+ print(f'🔴 CIRCULAR DEPENDENCIES FOUND: {len(cycles)} cycle(s)')
137
+ print()
138
+ for i, cycle in enumerate(cycles, 1):
139
+ print(f' Cycle {i}: {\" → \".join(cycle)}')
140
+ print()
141
+ print('These MUST be resolved before restructuring.')
142
+ sys.exit(1)
143
+ else:
144
+ print('✅ No circular dependencies detected!')
145
+ " 2>/dev/null || echo "⚠️ Python3 required for cycle detection"
146
+
147
+ rm -f "$TEMP_FILE"
@@ -0,0 +1,71 @@
1
+ #!/bin/bash
2
+ # Tool: detect-god-files — Find files exceeding a line threshold | DEPS: none
3
+ # USAGE: bash tools/detect-god-files.sh /path/to/monorepo [threshold]
4
+ # OUTPUT: list of files with line counts exceeding threshold
5
+ # MODE: read-only analysis
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ TARGET="${1:-.}"
12
+ THRESHOLD="${2:-500}"
13
+
14
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
15
+ echo "Usage: bash tools/detect-god-files.sh /path/to/monorepo [threshold]"
16
+ echo ""
17
+ echo "Finds source files exceeding [threshold] lines (default: 500)."
18
+ echo "These 'god-files' are candidates for decomposition."
19
+ echo ""
20
+ echo "Arguments:"
21
+ echo " path Path to monorepo (default: current directory)"
22
+ echo " threshold Line count threshold (default: 500)"
23
+ exit 0
24
+ fi
25
+
26
+ if [[ ! -d "$TARGET" ]]; then
27
+ echo "❌ Error: '$TARGET' is not a directory"
28
+ exit 1
29
+ fi
30
+
31
+ echo "🔍 Searching for files > ${THRESHOLD} lines in: $TARGET"
32
+ echo "────────────────────────────────────────"
33
+
34
+ GOD_FILES=$(find "$TARGET" \
35
+ -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.py' -o -name '*.go' -o -name '*.rs' -o -name '*.sol' \) \
36
+ -not -path '*/node_modules/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' \
37
+ -not -path '*/.git/*' \
38
+ -not -path '*/dist/*' \
39
+ -not -path '*/build/*' \
40
+ -not -path '*/.next/*' \
41
+ -not -path '*/generated/*' \
42
+ -not -path '*.min.*' \
43
+ -not -path '*.d.ts' \
44
+ -exec wc -l {} + 2>/dev/null \
45
+ | grep -v ' total$' \
46
+ | awk -v t="$THRESHOLD" '$1 > t' \
47
+ | sort -rn)
48
+
49
+ if [[ -z "$GOD_FILES" ]]; then
50
+ echo "✅ No god-files found! All files are within ${THRESHOLD} lines."
51
+ exit 0
52
+ fi
53
+
54
+ COUNT=$(echo "$GOD_FILES" | wc -l | tr -d ' ')
55
+ echo "🔴 Found ${COUNT} god-file(s):"
56
+ echo ""
57
+
58
+ echo "$GOD_FILES" | while read -r line; do
59
+ lines=$(echo "$line" | awk '{print $1}')
60
+ file=$(echo "$line" | awk '{print $2}')
61
+ severity="🟡"
62
+ [[ $lines -gt 1000 ]] && severity="🔴"
63
+ [[ $lines -gt 2000 ]] && severity="💀"
64
+ echo "${severity} ${lines} lines — ${file}"
65
+ done
66
+
67
+ echo ""
68
+ echo "────────────────────────────────────────"
69
+ echo "Severity: 🟡 ${THRESHOLD}-1000 | 🔴 1000-2000 | 💀 2000+"
70
+ echo ""
71
+ echo "Next: Use the Architect role to plan decomposition of these files."
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+ # Tool: enforce-god-files — Enforce file size limits across the codebase (CI blocker) | DEPS: none
3
+ # USAGE: bash tools/enforce-god-files.sh /path/to/scan [--strict]
4
+ # OUTPUT: File size compliance report
5
+ # MODE: ci-compliance
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ RED='\033[0;31m'
12
+ YELLOW='\033[1;33m'
13
+ CYAN='\033[0;36m'
14
+ GREEN='\033[0;32m'
15
+ DIM='\033[2m'
16
+ NC='\033[0m'
17
+
18
+ CRITICAL_LIMIT=300
19
+ WARN_LIMIT=150
20
+ NOTICE_LIMIT=100
21
+ STRICT=false
22
+
23
+ TARGET="${1:-.}"
24
+
25
+ if [[ "$TARGET" == "--help" || "$TARGET" == "-h" ]]; then
26
+ echo "Usage: bash tools/enforce-god-files.sh /path/to/scan [--strict]"
27
+ echo "Enforces file size limits and exits with 1 if limit is exceeded."
28
+ echo ""
29
+ echo "Tiers:"
30
+ echo " CRITICAL (>300 lines) — hard blocker, exit 1"
31
+ echo " WARNING (151-300) — soft warning, logged but not blocking"
32
+ echo " NOTICE (101-150) — consider refactoring on next edit"
33
+ echo " OK (≤100) — fully compliant"
34
+ echo ""
35
+ echo "Arguments:"
36
+ echo " --strict Fail on WARNING tier (>150 lines) as well"
37
+ exit 0
38
+ fi
39
+
40
+ if [[ "${2:-}" == "--strict" || "${1:-}" == "--strict" ]]; then
41
+ STRICT=true
42
+ [[ "${1:-}" == "--strict" ]] && TARGET="."
43
+ fi
44
+
45
+ if [[ ! -d "$TARGET" ]]; then
46
+ echo "❌ Error: '$TARGET' is not a directory"
47
+ exit 1
48
+ fi
49
+
50
+
51
+ critical_count=0
52
+ warn_count=0
53
+ notice_count=0
54
+ ok_count=0
55
+ critical_files=""
56
+ warn_files=""
57
+ notice_files=""
58
+
59
+ echo "━━━ File Size Compliance Check ━━━"
60
+
61
+ while IFS= read -r file; do
62
+ lines=$(wc -l < "$file" | tr -d ' ')
63
+
64
+ if [ "$lines" -gt "$CRITICAL_LIMIT" ]; then
65
+ critical_count=$((critical_count + 1))
66
+ critical_files="${critical_files}\n ${RED}🚫 ${lines} lines${NC} $file"
67
+ elif [ "$lines" -gt "$WARN_LIMIT" ]; then
68
+ warn_count=$((warn_count + 1))
69
+ warn_files="${warn_files}\n ${YELLOW}⚠️ ${lines} lines${NC} $file"
70
+ elif [ "$lines" -gt "$NOTICE_LIMIT" ]; then
71
+ notice_count=$((notice_count + 1))
72
+ notice_files="${notice_files}\n ${CYAN}🔍 ${lines} lines${NC} $file"
73
+ else
74
+ ok_count=$((ok_count + 1))
75
+ fi
76
+ done < <(find "$TARGET" -type f \( -name '*.ts' -o -name '*.js' -o -name '*.tsx' -o -name '*.jsx' -o -name '*.py' -o -name '*.go' -o -name '*.rs' -o -name '*.sol' \) "${FIND_EXCLUDES[@]}" 2>/dev/null)
77
+
78
+ echo ""
79
+ if [ "$critical_count" -gt 0 ]; then
80
+ echo -e "${RED}🚫 CRITICAL ($critical_count files > $CRITICAL_LIMIT lines) — MUST split before merge:${NC}"
81
+ echo -e "$critical_files"
82
+ echo ""
83
+ fi
84
+
85
+ if [ "$warn_count" -gt 0 ]; then
86
+ echo -e "${YELLOW}⚠️ WARNING ($warn_count files > $WARN_LIMIT lines) — split when editing:${NC}"
87
+ echo -e "$warn_files"
88
+ echo ""
89
+ fi
90
+
91
+ if [ "$notice_count" -gt 0 ]; then
92
+ echo -e "${CYAN}🔍 NOTICE ($notice_count files > $NOTICE_LIMIT lines) — consider refactoring:${NC}"
93
+ echo -e "$notice_files"
94
+ echo ""
95
+ fi
96
+
97
+ echo -e "${GREEN}✅ $ok_count files fully compliant (≤$NOTICE_LIMIT lines)${NC}"
98
+ echo -e "${DIM} $notice_count notice, $warn_count warnings, $critical_count critical${NC}"
99
+ echo ""
100
+
101
+ if [ "$critical_count" -gt 0 ]; then
102
+ echo -e "${RED}FAILED: $critical_count files exceed $CRITICAL_LIMIT lines. Split them first.${NC}"
103
+ exit 1
104
+ fi
105
+
106
+ if [ "$STRICT" = true ] && [ "$warn_count" -gt 0 ]; then
107
+ echo -e "${YELLOW}FAILED (strict mode): $warn_count files exceed $WARN_LIMIT lines.${NC}"
108
+ exit 1
109
+ fi
110
+
111
+ echo -e "${GREEN}PASSED${NC}"
112
+ exit 0