@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,206 @@
1
+ #!/bin/bash
2
+ # Tool: measure-context-cost — Estimate AI agent context cost for a package | DEPS: none
3
+ # USAGE: bash tools/measure-context-cost.sh /path/to/package
4
+ # OUTPUT: estimated token costs and efficiency metrics
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/measure-context-cost.sh /path/to/package"
15
+ echo "Usage: bash tools/measure-context-cost.sh /path/to/package [--internal-scope=scope1,scope2]"
16
+ echo ""
17
+ echo "Estimates the context cost (in tokens) for an AI agent to understand"
18
+ echo "a package. Compares cost with and without README/navigation aids."
19
+ echo ""
20
+ echo "Token estimation: 1 token ≈ 4 characters (rough approximation)"
21
+ exit 0
22
+ fi
23
+
24
+ TARGET="."
25
+ INTERNAL_SCOPES=""
26
+
27
+ while [[ $# -gt 0 ]]; do
28
+ case $1 in
29
+ --internal-scope=*)
30
+ INTERNAL_SCOPES="${1#*=}"
31
+ shift
32
+ ;;
33
+ -h|--help)
34
+ exit 0
35
+ ;;
36
+ *)
37
+ TARGET="$1"
38
+ shift
39
+ ;;
40
+ esac
41
+ done
42
+
43
+ if [[ ! -d "$TARGET" ]]; then
44
+ echo "❌ Error: '$TARGET' is not a directory"
45
+ exit 1
46
+ fi
47
+
48
+ PKG_NAME=$(basename "$TARGET")
49
+ CHARS_PER_TOKEN=4
50
+
51
+ echo "📊 Context Cost Analysis: $PKG_NAME"
52
+ if [[ -n "$INTERNAL_SCOPES" ]]; then
53
+ echo "🔍 Treating scopes as local: $INTERNAL_SCOPES"
54
+ fi
55
+ echo "────────────────────────────────────────"
56
+
57
+ # Construct regex for local imports
58
+ if [[ -n "$INTERNAL_SCOPES" ]]; then
59
+ SCOPE_PATTERN=$(echo "$INTERNAL_SCOPES" | tr ',' '|')
60
+ LOCAL_REGEX="^(import |from |use |const .* = require\()).*['\"](\.|/|@/|~/|${SCOPE_PATTERN})"
61
+ else
62
+ LOCAL_REGEX="^(import |from |use |const .* = require\()).*['\"](\.|/|@/|~/)"
63
+ fi
64
+
65
+ # Count source files
66
+ SRC_FILES=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' -o -name '*.py' -o -name '*.rs' \) \
67
+ -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' \
68
+ -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' \
69
+ | wc -l | tr -d ' ')
70
+
71
+ # Total source bytes
72
+ TOTAL_BYTES=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' -o -name '*.py' -o -name '*.rs' \) \
73
+ -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' \
74
+ -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' \
75
+ -exec wc -c {} + 2>/dev/null | grep total | awk '{print $1}')
76
+
77
+ if [[ -z "$TOTAL_BYTES" ]]; then
78
+ TOTAL_BYTES=0
79
+ fi
80
+
81
+ TOTAL_TOKENS=$((TOTAL_BYTES / CHARS_PER_TOKEN))
82
+
83
+ IMPORTS_ALL=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' -o -name '*.py' -o -name '*.rs' \) \
84
+ -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' \
85
+ -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' \
86
+ -exec grep -E "^(import |from |use |const .* = require\()" {} + 2>/dev/null | wc -l | tr -d ' ' || true)
87
+
88
+ IMPORTS_LOCAL=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' -o -name '*.py' -o -name '*.rs' \) \
89
+ -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' \
90
+ -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' \
91
+ -exec grep -E "$LOCAL_REGEX" {} + 2>/dev/null | wc -l | tr -d ' ' || true)
92
+
93
+ TOTAL_LINES=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' \) \
94
+ -not -path '*/node_modules/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' -not -path '*/dist/*' -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' \
95
+ -exec cat {} + 2>/dev/null | wc -l | tr -d ' ' || true)
96
+
97
+ if [[ $SRC_FILES -gt 0 ]]; then
98
+ IMPORTS_GLOBAL=$((IMPORTS_ALL - IMPORTS_LOCAL))
99
+ FANOUT_LOCAL=$(awk "BEGIN {printf \"%.1f\", $IMPORTS_LOCAL/$SRC_FILES}")
100
+ FANOUT_GLOBAL=$(awk "BEGIN {printf \"%.1f\", $IMPORTS_GLOBAL/$SRC_FILES}")
101
+ AVG_LOC=$((TOTAL_LINES / SRC_FILES))
102
+ AVG_WEIGHT=$(awk "BEGIN {print int($AVG_LOC + ($IMPORTS_LOCAL/$SRC_FILES) * 20 + ($IMPORTS_GLOBAL/$SRC_FILES) * 5)}")
103
+ else
104
+ FANOUT_LOCAL=0
105
+ FANOUT_GLOBAL=0
106
+ AVG_LOC=0
107
+ AVG_WEIGHT=0
108
+ fi
109
+
110
+ # Determine Weight Category
111
+ if [[ $AVG_WEIGHT -gt 300 ]]; then
112
+ WEIGHT_CLASS="🔴 Heavy"
113
+ elif [[ $AVG_WEIGHT -gt 150 ]]; then
114
+ WEIGHT_CLASS="⚠️ Moderate"
115
+ else
116
+ WEIGHT_CLASS="✅ Light"
117
+ fi
118
+
119
+ echo "Source files: $SRC_FILES"
120
+ echo "Total source: ~${TOTAL_TOKENS} tokens (${TOTAL_BYTES} bytes, $TOTAL_LINES lines)"
121
+ echo "Fan-out: $FANOUT_LOCAL Local / $FANOUT_GLOBAL Global (Avg dependencies per file)"
122
+ echo "Avg Context Weight (LOC + Loc*20 + Glob*5): $AVG_WEIGHT ($WEIGHT_CLASS)"
123
+ echo ""
124
+
125
+ # Scenario 1: No README (blind navigation)
126
+ echo "📍 WITHOUT README (blind navigation)"
127
+ echo "────────────────────────────────────────"
128
+
129
+ LIST_DIR_CALLS=0
130
+ VIEW_FILE_CALLS=0
131
+
132
+ # Count directories that need list_dir
133
+ SEARCH_DIR="$TARGET/src"
134
+ if [[ ! -d "$SEARCH_DIR" ]]; then
135
+ SEARCH_DIR="$TARGET"
136
+ fi
137
+
138
+ DIR_COUNT=$(find "$SEARCH_DIR" -maxdepth 2 -type d -not -path '*/node_modules/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' -not -path '*/.*' 2>/dev/null | wc -l | tr -d ' ')
139
+ LIST_DIR_CALLS=$((DIR_COUNT))
140
+
141
+ # Agent would need to view ~30% of files to understand the package
142
+ VIEW_FILE_CALLS=$((SRC_FILES * 30 / 100))
143
+ [[ $VIEW_FILE_CALLS -lt 3 ]] && VIEW_FILE_CALLS=3
144
+
145
+ # Estimate tokens per operation
146
+ LIST_DIR_TOKENS=$((LIST_DIR_CALLS * 250)) # ~250 tokens per list_dir
147
+ AVG_FILE_TOKENS=$((TOTAL_TOKENS / SRC_FILES))
148
+ [[ $AVG_FILE_TOKENS -lt 100 ]] && AVG_FILE_TOKENS=100
149
+ VIEW_FILE_TOKENS=$((VIEW_FILE_CALLS * AVG_FILE_TOKENS))
150
+
151
+ BLIND_TOTAL=$((LIST_DIR_TOKENS + VIEW_FILE_TOKENS))
152
+
153
+ echo " list_dir calls: ${LIST_DIR_CALLS} (~${LIST_DIR_TOKENS} tokens)"
154
+ echo " view_file calls: ${VIEW_FILE_CALLS} (~${VIEW_FILE_TOKENS} tokens)"
155
+ echo " TOTAL: ~${BLIND_TOTAL} tokens"
156
+ echo ""
157
+
158
+ # Scenario 2: With README (guided navigation)
159
+ echo "📍 WITH README (guided navigation)"
160
+ echo "────────────────────────────────────────"
161
+
162
+ README_EXISTS="No"
163
+ README_TOKENS=0
164
+ if [[ -f "$TARGET/README.md" ]]; then
165
+ README_EXISTS="Yes"
166
+ README_BYTES=$(wc -c < "$TARGET/README.md" | tr -d ' ')
167
+ README_TOKENS=$((README_BYTES / CHARS_PER_TOKEN))
168
+ fi
169
+
170
+ # With README, agent only needs README + 1-3 target files
171
+ GUIDED_VIEW_CALLS=3
172
+ GUIDED_VIEW_TOKENS=$((GUIDED_VIEW_CALLS * AVG_FILE_TOKENS))
173
+ GUIDED_TOTAL=$((README_TOKENS + GUIDED_VIEW_TOKENS))
174
+
175
+ echo " README exists: ${README_EXISTS}"
176
+ echo " README size: ~${README_TOKENS} tokens"
177
+ echo " view_file calls: ${GUIDED_VIEW_CALLS} (targeted)"
178
+ echo " TOTAL: ~${GUIDED_TOTAL} tokens"
179
+ echo ""
180
+
181
+ # Comparison
182
+ echo "📈 COMPARISON"
183
+ echo "────────────────────────────────────────"
184
+
185
+ if [[ $BLIND_TOTAL -gt 0 ]]; then
186
+ SAVINGS=$(( (BLIND_TOTAL - GUIDED_TOTAL) * 100 / BLIND_TOTAL ))
187
+ else
188
+ SAVINGS=0
189
+ fi
190
+
191
+ echo " Without README: ~${BLIND_TOTAL} tokens"
192
+ echo " With README: ~${GUIDED_TOTAL} tokens"
193
+ echo " Savings: ${SAVINGS}%"
194
+ echo ""
195
+
196
+ if [[ "$README_EXISTS" == "No" ]]; then
197
+ echo "⚠️ README.md is MISSING! Creating one would save ~$((BLIND_TOTAL - GUIDED_TOTAL)) tokens per task."
198
+ else
199
+ # Check if README has Source Structure
200
+ if grep -q "Source Structure\|src/" "$TARGET/README.md" 2>/dev/null; then
201
+ echo "✅ README has Source Structure — agent can navigate efficiently"
202
+ else
203
+ echo "⚠️ README exists but lacks Source Structure section"
204
+ echo " Adding it would improve navigation further."
205
+ fi
206
+ fi
@@ -0,0 +1,174 @@
1
+ #!/bin/bash
2
+ # Tool: scan-fnh — Generate a repository map from FNH headers | DEPS: none
3
+ # USAGE: bash tools/scan-fnh.sh [path] [--internal-scope=...] [--depth=N] [--no-legend]
4
+ # OUTPUT: File map mapping paths to their semantic FNH descriptions and context metrics
5
+ # MODE: read-only analysis
6
+
7
+ set -euo pipefail
8
+
9
+ TARGET="."
10
+ INTERNAL_SCOPES=""
11
+ DEPTH="all"
12
+ SHOW_LEGEND=true
13
+
14
+ show_help() {
15
+ echo "Usage: bash tools/scan-fnh.sh [target] [options]"
16
+ echo ""
17
+ echo "Scans files and extracts their FNH (File Navigation Header)."
18
+ echo "If FNH is missing, computes 'Context Weight' (LOC + Fan-out) on the fly."
19
+ echo "Respects .gitignore natively via git ls-files."
20
+ echo ""
21
+ echo "Arguments:"
22
+ echo " target Directory or specific file to scan (default: .)"
23
+ echo ""
24
+ echo "Options:"
25
+ echo " --depth=N Limit scan depth to N subdirectories (default: all)."
26
+ echo " --internal-scope=@org,pkg Treat these scopes as local imports when calculating penalty weight."
27
+ echo " --no-legend Hide formatting legend and headers, returning pure table data."
28
+ echo " -h, --help Show this help message."
29
+ exit 0
30
+ }
31
+
32
+ while [[ $# -gt 0 ]]; do
33
+ case $1 in
34
+ --internal-scope=*)
35
+ INTERNAL_SCOPES="${1#*=}"
36
+ shift
37
+ ;;
38
+ --depth=*)
39
+ DEPTH="${1#*=}"
40
+ shift
41
+ ;;
42
+ --no-legend)
43
+ SHOW_LEGEND=false
44
+ shift
45
+ ;;
46
+ -h|--help)
47
+ show_help
48
+ ;;
49
+ *)
50
+ TARGET="$1"
51
+ shift
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ if [[ ! -e "$TARGET" ]]; then
57
+ echo "❌ Error: target '$TARGET' does not exist"
58
+ exit 1
59
+ fi
60
+
61
+ IS_SINGLE_FILE=false
62
+ if [[ -f "$TARGET" ]]; then
63
+ IS_SINGLE_FILE=true
64
+ TARGET_DIR="$(dirname "$TARGET")"
65
+ TARGET_FILE="$(basename "$TARGET")"
66
+ cd "$TARGET_DIR"
67
+ else
68
+ cd "$TARGET"
69
+ fi
70
+
71
+ if [[ "$SHOW_LEGEND" == true ]]; then
72
+ echo "🗺️ File Navigation Header (FNH) Semantic Map: $(pwd)"
73
+ if [[ -n "$INTERNAL_SCOPES" ]]; then
74
+ echo "🔍 Treating scopes as local: $INTERNAL_SCOPES"
75
+ fi
76
+ echo "FORMAT: [LOC L] path/to/file | Semantic Description OR 🔴 [NO FNH] ContextWeight W (L_loc: local_deps, I_glb: global_deps)"
77
+ echo "───────────────────────────────────────────────────────────────────────────────"
78
+ fi
79
+
80
+ # Construct regex for local imports (used if we need to calculate context weight)
81
+ if [[ -n "$INTERNAL_SCOPES" ]]; then
82
+ SCOPE_PATTERN=$(echo "$INTERNAL_SCOPES" | tr ',' '|')
83
+ LOCAL_REGEX="^(import |from |use |const .* = require\()).*['\"](\.|/|@/|~/|${SCOPE_PATTERN})"
84
+ else
85
+ LOCAL_REGEX="^(import |from |use |const .* = require\()).*['\"](\.|/|@/|~/)"
86
+ fi
87
+
88
+ # FNH Matching Regex (includes all common AI directives across languages)
89
+ FNH_REGEX="(FNH:|Category:|Tool:|Role:|Guide:|Checklist:|Knowledge:|Architecture:|Report:|Skill:|Service:|Middleware:|Controller:|Repository:|Entity:|Types:|Utility:|Config:|Schema:|Hook:|Component:|Test:|Migration:|Script:|Constants:|Factory:|Adapter:|Event:|Guard:|Package:)"
90
+
91
+ # Extension filter for code/doc files
92
+ EXT_REGEX='\.(ts|tsx|js|jsx|sol|py|rs|md|yml|yaml|sh|json)$|^Dockerfile'
93
+
94
+ # Discover files (Prefer git ls-files to automatically respect all .gitignore files)
95
+ if [[ "$IS_SINGLE_FILE" == true ]]; then
96
+ FILES="$TARGET_FILE"
97
+ else
98
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
99
+ FILES=$(git ls-files | grep -E "$EXT_REGEX" | grep -vE '(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)' || true)
100
+ else
101
+ FILES=$(find . -type f | sed 's|^\./||' | grep -E "$EXT_REGEX" | grep -v 'node_modules/' | grep -v 'dist/' | grep -v '\.git/' | grep -vE '(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)' || true)
102
+ fi
103
+
104
+ if [[ "$DEPTH" != "all" && "$DEPTH" =~ ^[0-9]+$ ]]; then
105
+ FILES=$(echo "$FILES" | awk -F'/' -v d="$DEPTH" '{ if (NF <= d) print $0 }')
106
+ fi
107
+ fi
108
+
109
+ if [[ -z "$FILES" ]]; then
110
+ if [[ "$SHOW_LEGEND" == true ]]; then
111
+ echo "No relevant files found."
112
+ fi
113
+ exit 0
114
+ fi
115
+
116
+ echo "$FILES" | sort | while read -r FILE; do
117
+
118
+ if [[ ! -f "$FILE" ]]; then continue; fi
119
+
120
+ # Count LOC (trimming whitespace)
121
+ LOC=$(wc -l < "$FILE" | tr -d ' ')
122
+
123
+ # Extract FNH string
124
+ DESC=""
125
+ if [[ "$FILE" == *.json ]]; then
126
+ # Light JSON parsing for description
127
+ DESC=$(grep -E '"description"\s*:' "$FILE" 2>/dev/null | head -n 1 | sed -E 's/.*"description"\s*:\s*"([^"]+)".*/\1/' || true)
128
+ if [[ -n "$DESC" ]]; then
129
+ DESC="Description: $DESC"
130
+ fi
131
+ else
132
+ # 5-line lookahead is purely a search window. We output only the matched line.
133
+ HEADER=$(head -n 5 "$FILE" | grep -iE "$FNH_REGEX" | head -n 1 || true)
134
+
135
+ if [[ -n "$HEADER" ]]; then
136
+ # Clean up formatting wrappers (HTML, JSDoc, blockquotes, python docstrings)
137
+ CL_HEADER=$(echo "$HEADER" | sed -E 's/<!--\s*|\s*-->//g' | sed -E 's/\/\*\*\s*|\s*\*\///g' | sed -E 's/^[>#"-]+ //g' | sed -E 's/"""//g')
138
+ # Strip leading/trailing margins
139
+ DESC=$(echo "$CL_HEADER" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
140
+ fi
141
+ fi
142
+
143
+ # Report Output Formatting
144
+ # Minimal formatting to preserve AI context tokens (no excessive space padding)
145
+ if [[ -n "$DESC" ]]; then
146
+ echo "[$LOC L] $FILE | $DESC"
147
+ else
148
+ # If standard markdown, just say NO FNH without calculating code context weight
149
+ if [[ "$FILE" == *.md || "$FILE" == *.json || "$FILE" == *.yml || "$FILE" == *.yaml ]]; then
150
+ if [[ $(basename "$FILE") == "README.md" ]]; then
151
+ echo "[$LOC L] $FILE | ⚠️ [Standard README]"
152
+ else
153
+ echo "[$LOC L] $FILE | 🔴 [NO FNH]"
154
+ fi
155
+ else
156
+ # If code file, calculate Context Weight as a penalty/diagnostic string!
157
+ IMPORTS_ALL=$(grep -E "^(import |from |use |const .* = require\()" "$FILE" 2>/dev/null | wc -l | tr -d ' ' || true)
158
+ IMPORTS_LOCAL=$(grep -E "$LOCAL_REGEX" "$FILE" 2>/dev/null | wc -l | tr -d ' ' || true)
159
+ IMPORTS_GLOBAL=$((IMPORTS_ALL - IMPORTS_LOCAL))
160
+
161
+ WEIGHT=$((LOC + (IMPORTS_LOCAL * 20) + (IMPORTS_GLOBAL * 5)))
162
+
163
+ # Print with rich context penalty warning
164
+ echo "[$LOC L] $FILE | 🔴 [NO FNH] $WEIGHT W (L_loc: $IMPORTS_LOCAL, I_glb: $IMPORTS_GLOBAL)"
165
+ fi
166
+ fi
167
+
168
+ done
169
+
170
+ if [[ "$SHOW_LEGEND" == true ]]; then
171
+ echo "───────────────────────────────────────────────────────────────────────────────"
172
+ echo "AI Context Tip: Use this map to navigate the repository instantly without blind list_dir scans."
173
+ fi
174
+ exit 0
@@ -0,0 +1,53 @@
1
+ #!/bin/bash
2
+ # Tool: shared/config.sh
3
+ # FNH: Global Configuration for ai-context-surgeon Bash Tools | SECTIONS: Exclusions, Environment
4
+ # Description: Provides unified exclusion logic for CI scanners to ensure blind ecosystem adaptability.
5
+
6
+ # -----------------------------------------------------------------------------
7
+ # FIND_EXCLUDES: Used by tools calling `find` directly
8
+ # Usage: find "$DIR" -type f "${FIND_EXCLUDES[@]}"
9
+ # -----------------------------------------------------------------------------
10
+ export FIND_EXCLUDES=(
11
+ "!" "-path" "*/node_modules/*"
12
+ "!" "-path" "*/lib/forge-std/*"
13
+ "!" "-path" "*/lib/openzeppelin-contracts*"
14
+ "!" "-path" "*/lib/erc721a*"
15
+ "!" "-path" "*/venv/*"
16
+ "!" "-path" "*/.venv/*"
17
+ "!" "-path" "*/vendor/*"
18
+ "!" "-path" "*/target/*"
19
+ "!" "-path" "*/dist/*"
20
+ "!" "-path" "*/build/*"
21
+ "!" "-path" "*/out/*"
22
+ "!" "-path" "*/out_forge/*"
23
+ "!" "-path" "*/.next/*"
24
+ "!" "-path" "*/.cache/*"
25
+ "!" "-path" "*/.turbo/*"
26
+ "!" "-path" "*/.git/*"
27
+ )
28
+
29
+ # -----------------------------------------------------------------------------
30
+ # GREP_EXCLUDES_REGEX: Used for fast `grep -vE` filtering
31
+ # -----------------------------------------------------------------------------
32
+ export GREP_EXCLUDES_REGEX="node_modules|lib/(forge-std|openzeppelin|erc721a)|venv|\.venv|vendor|target|dist|build|out|out_forge|\.next|\.cache|\.turbo|\.git"
33
+
34
+ # -----------------------------------------------------------------------------
35
+ # BASH_ARRAY_EXCLUDES: Used when scripting bash loops and `find` match conditions
36
+ # -----------------------------------------------------------------------------
37
+ export BASH_ARRAY_EXCLUDES=(
38
+ "*/node_modules/*"
39
+ "*/lib/forge-std/*"
40
+ "*/lib/openzeppelin-contracts*"
41
+ "*/lib/erc721a*"
42
+ "*/venv/*"
43
+ "*/.venv/*"
44
+ "*/vendor/*"
45
+ "*/target/*"
46
+ "*/dist/*"
47
+ "*/build/*"
48
+ "*/out/*"
49
+ "*/.next/*"
50
+ "*/.cache/*"
51
+ "*/.turbo/*"
52
+ "*/.git/*"
53
+ )
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+ # Tool: validate-context-hygiene — Verify target directories contain compliance files | DEPS: none
3
+ # USAGE: bash tools/validate-context-hygiene.sh [directory_patterns...]
4
+ # OUTPUT: success/fail logs for file presence
5
+ # MODE: ci-compliance
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ RED='\033[0;31m'
12
+ GREEN='\033[0;32m'
13
+ NC='\033[0m'
14
+
15
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
16
+ echo "Usage: bash tools/validate-context-hygiene.sh [directories...]"
17
+ echo "Example: bash tools/validate-context-hygiene.sh apps/* packages/*"
18
+ exit 0
19
+ fi
20
+
21
+ if [ "$#" -eq 0 ]; then
22
+ echo "❌ Error: Please provide directories to check."
23
+ echo "Example: bash tools/validate-context-hygiene.sh apps/* packages/*"
24
+ exit 1
25
+ fi
26
+
27
+ errors=0
28
+ checked=0
29
+
30
+ for dir in "$@"; do
31
+ [ -d "$dir" ] || continue
32
+
33
+ checked=$((checked + 1))
34
+
35
+ for file in README.md .gitignore .antigravityignore; do
36
+ if [ ! -f "$dir/$file" ]; then
37
+ echo -e "${RED}❌ Missing${NC} $dir/$file"
38
+ errors=$((errors + 1))
39
+ fi
40
+ done
41
+ done
42
+
43
+ echo ""
44
+ if [ "$errors" -eq 0 ]; then
45
+ echo -e "${GREEN}✅ All $checked directories have README.md, .gitignore, .antigravityignore${NC}"
46
+ exit 0
47
+ else
48
+ echo -e "${RED}❌ $errors missing files across $checked directories${NC}"
49
+ echo ""
50
+ echo "Fix: Each target package needs self-contained ignore files + README."
51
+ exit 1
52
+ fi
@@ -0,0 +1,100 @@
1
+ #!/bin/bash
2
+ # Tool: validate-context-weight — Identify files with massive context weight | DEPS: none
3
+ # USAGE: bash tools/validate-context-weight.sh /path/to/package
4
+ # OUTPUT: files exceeding context weight threshold
5
+ # MODE: read-only analysis
6
+
7
+ set -euo pipefail
8
+
9
+ TARGET="."
10
+ INTERNAL_SCOPES=""
11
+
12
+ while [[ $# -gt 0 ]]; do
13
+ case $1 in
14
+ --internal-scope=*)
15
+ INTERNAL_SCOPES="${1#*=}"
16
+ shift
17
+ ;;
18
+ -h|--help)
19
+ echo "Usage: bash tools/validate-context-weight.sh [target_dir] [--internal-scope=@myorg,my-package]"
20
+ echo ""
21
+ echo "Finds files that are highly complex based on Context Weight formula:"
22
+ echo "Weight = LOC + (Local Imports * 20) + (Global Imports * 5)"
23
+ exit 0
24
+ ;;
25
+ *)
26
+ TARGET="$1"
27
+ shift
28
+ ;;
29
+ esac
30
+ done
31
+
32
+ if [[ ! -d "$TARGET" ]]; then
33
+ echo "❌ Error: '$TARGET' is not a directory"
34
+ exit 1
35
+ fi
36
+
37
+ echo "⚖️ Context Weight Analysis: $TARGET"
38
+ if [[ -n "$INTERNAL_SCOPES" ]]; then
39
+ echo "🔍 Treating scopes as local: $INTERNAL_SCOPES"
40
+ fi
41
+ echo "────────────────────────────────────────"
42
+
43
+ # Construct regex for local imports
44
+ if [[ -n "$INTERNAL_SCOPES" ]]; then
45
+ SCOPE_PATTERN=$(echo "$INTERNAL_SCOPES" | tr ',' '|')
46
+ LOCAL_REGEX="^(import |from |use |const .* = require\()).*['\"](\.|/|@/|~/|${SCOPE_PATTERN})"
47
+ else
48
+ LOCAL_REGEX="^(import |from |use |const .* = require\()).*['\"](\.|/|@/|~/)"
49
+ fi
50
+
51
+ # Temporary file to store results
52
+ TMP_RESULTS=$(mktemp)
53
+
54
+ # Find all relevant files
55
+ find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' -o -name '*.py' -o -name '*.rs' \) \
56
+ -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' \
57
+ -not -name '*.d.ts' -not -name '*.test.*' -not -name '*.spec.*' | while read -r FILE; do
58
+
59
+ LOC=$(wc -l < "$FILE" | tr -d ' ')
60
+
61
+ IMPORTS_ALL=$(grep -E "^(import |from |use |const .* = require\()" "$FILE" 2>/dev/null | wc -l | tr -d ' ' || true)
62
+ IMPORTS_LOCAL=$(grep -E "$LOCAL_REGEX" "$FILE" 2>/dev/null | wc -l | tr -d ' ' || true)
63
+ IMPORTS_GLOBAL=$((IMPORTS_ALL - IMPORTS_LOCAL))
64
+
65
+ WEIGHT=$((LOC + (IMPORTS_LOCAL * 20) + (IMPORTS_GLOBAL * 5)))
66
+
67
+ # Only report if weight is high enough
68
+ if [[ $WEIGHT -gt 150 ]]; then
69
+ echo "$WEIGHT|$LOC|$IMPORTS_LOCAL|$IMPORTS_GLOBAL|$FILE" >> "$TMP_RESULTS"
70
+ fi
71
+ done
72
+
73
+ # Check if there are results
74
+ if [[ -s "$TMP_RESULTS" ]]; then
75
+ echo "Found files with high Context Weight (Warning > 150, Critical > 300):"
76
+
77
+ # Sort by weight (descending) and format output
78
+ sort -t '|' -k1 -rn "$TMP_RESULTS" | awk -F '|' '{
79
+ weight=$1; loc=$2; i_loc=$3; i_glob=$4; file=$5;
80
+
81
+ if (weight > 300) {
82
+ color="\033[0;31m"; # Red
83
+ icon="🔴";
84
+ } else {
85
+ color="\033[1;33m"; # Yellow
86
+ icon="⚠️ ";
87
+ }
88
+
89
+ printf " %s%s %d W\033[0m (L:%d, I_loc:%d, I_glb:%d) %s\n", color, icon, weight, loc, i_loc, i_glob, file
90
+ }'
91
+
92
+ echo ""
93
+ echo "Context Weight = LOC + (Local Imports * 20) + (Global Imports * 5)"
94
+ echo "To reduce weight, either extract dependencies or split the logic."
95
+ else
96
+ echo "✅ No files exceed context weight threshold (150 W)!"
97
+ fi
98
+
99
+ rm "$TMP_RESULTS"
100
+ exit 0
@@ -0,0 +1,98 @@
1
+ #!/bin/bash
2
+ # Tool: validate-naming — checks naming conventions across monorepo | DEPS: none
3
+ # USAGE: bash tools/validate-naming.sh /path/to/repo
4
+ # OUTPUT: naming violations grouped by type
5
+ # MODE: read-only, no modifications
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ TARGET="${1:-.}"
12
+ VIOLATIONS=0
13
+
14
+ echo "📝 Naming Convention Validator"
15
+ echo " Target: $TARGET"
16
+ echo " ──────────────────────────────────"
17
+ echo ""
18
+
19
+ # Rule 1: Files should be kebab-case (except special files)
20
+ echo " ### Rule 1: Files must be kebab-case.ts"
21
+ echo " Exceptions: index.ts, AGENTS.md, README.md, LICENSE, Dockerfile, .env"
22
+ echo ""
23
+
24
+ SPECIAL_FILES="index\|README\|AGENTS\|LICENSE\|Dockerfile\|CHANGELOG\|CONTRIBUTING\|SECURITY\|\.env\|\.gitignore\|\.npmrc\|\.eslintrc\|\.prettierrc\|node_modules\|\.git"
25
+
26
+ BAD_FILES=$(find "$TARGET" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' \) \
27
+ ! -path '*/node_modules/*' ! -path '*/lib/forge-std/*' ! -path '*/lib/openzeppelin-contracts*' ! -path '*/lib/erc721a*' ! -path '*/.git/*' ! -path '*/dist/*' ! -path '*/.next/*' \
28
+ | xargs -I {} basename {} \
29
+ | grep -v "^index\." \
30
+ | grep -v "^[a-z][a-z0-9]*\(-[a-z0-9]*\)*\.\(ts\|tsx\|js\|jsx\)$" \
31
+ | sort -u 2>/dev/null || true)
32
+
33
+ if [ -n "$BAD_FILES" ]; then
34
+ echo "$BAD_FILES" | while IFS= read -r name; do
35
+ echo " ❌ $name — should be kebab-case"
36
+ done
37
+ echo ""
38
+ else
39
+ echo " ✅ All source files use kebab-case"
40
+ echo ""
41
+ fi
42
+
43
+ # Rule 2: Directories should be kebab-case
44
+ echo " ### Rule 2: Directories must be kebab-case"
45
+ echo " Exceptions: node_modules, .git, .agents, .github, __tests__, __mocks__"
46
+ echo ""
47
+
48
+ BAD_DIRS=$(find "$TARGET" -type d \
49
+ ! -path '*/node_modules/*' ! -path '*/lib/forge-std/*' ! -path '*/lib/openzeppelin-contracts*' ! -path '*/lib/erc721a*' ! -path '*/.git/*' ! -path '*/dist/*' ! -path '*/.next/*' \
50
+ | xargs -I {} basename {} \
51
+ | grep -v '^\.' \
52
+ | grep -v '^__' \
53
+ | grep -v '^node_modules$' \
54
+ | grep -v '^[a-z][a-z0-9]*\(-[a-z0-9]*\)*$' \
55
+ | sort -u 2>/dev/null || true)
56
+
57
+ if [ -n "$BAD_DIRS" ]; then
58
+ echo "$BAD_DIRS" | while IFS= read -r name; do
59
+ echo " ⚠️ $name — should be kebab-case"
60
+ done
61
+ echo ""
62
+ else
63
+ echo " ✅ All directories use kebab-case"
64
+ echo ""
65
+ fi
66
+
67
+ # Rule 3: Check for inconsistent naming in same directory
68
+ echo " ### Rule 3: Consistency within directories"
69
+ echo ""
70
+
71
+ MIXED=0
72
+ OLD_IFS=$IFS
73
+ IFS='
74
+ '
75
+ for dir in $(find "$TARGET" -type d ! -path '*/node_modules/*' ! -path '*/lib/forge-std/*' ! -path '*/lib/openzeppelin-contracts*' ! -path '*/lib/erc721a*' ! -path '*/.git/*' ! -path '*/dist/*' 2>/dev/null); do
76
+ [ -z "$dir" ] && continue
77
+
78
+ FILES=$(find "$dir" -maxdepth 1 -type f \( -name '*.ts' -o -name '*.js' -o -name '*.sol' \) ! -name 'index.*' 2>/dev/null)
79
+ [ -z "$FILES" ] && continue
80
+
81
+ HAS_CAMEL=$(echo "$FILES" | xargs -I {} basename {} | grep -c '[A-Z]' || true)
82
+ HAS_KEBAB=$(echo "$FILES" | xargs -I {} basename {} | grep -c '\-' || true)
83
+
84
+ if [ "$HAS_CAMEL" -gt 0 ] && [ "$HAS_KEBAB" -gt 0 ]; then
85
+ echo " ⚠️ Mixed naming in: $dir"
86
+ echo " camelCase: $HAS_CAMEL files, kebab-case: $HAS_KEBAB files"
87
+ MIXED=$((MIXED + 1))
88
+ fi
89
+ done
90
+ IFS=$OLD_IFS
91
+
92
+ if [ "$MIXED" -eq 0 ]; then
93
+ echo " ✅ No mixed naming conventions within directories"
94
+ fi
95
+
96
+ echo ""
97
+ echo " ──────────────────────────────────"
98
+ echo " Naming check complete"