@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,64 @@
1
+ # Config: antigravityignore — files to exclude from AI agent context
2
+ # Syntax: same as .gitignore | Each level is self-contained
3
+ # THREE SYSTEMS: .gitignore (git), .antigravityignore (agent context), .npmignore (npm publish)
4
+
5
+ # ─ Lock files (massive, zero context value)
6
+ pnpm-lock.yaml
7
+ package-lock.json
8
+ yarn.lock
9
+ bun.lockb
10
+
11
+ # ─ Build artifacts
12
+ dist/
13
+ build/
14
+ .next/
15
+ .nuxt/
16
+ out/
17
+
18
+ # ─ Cache
19
+ .turbo/
20
+ .cache/
21
+ .parcel-cache/
22
+ *.tsbuildinfo
23
+
24
+ # ─ Coverage & reports
25
+ coverage/
26
+ .nyc_output/
27
+
28
+ # ─ Generated files
29
+ *.generated.ts
30
+ *.generated.js
31
+ *.d.ts.map
32
+
33
+ # ─ Minified files
34
+ *.min.js
35
+ *.min.css
36
+
37
+ # ─ Source maps
38
+ *.map
39
+
40
+ # ─ IDE / OS
41
+ .DS_Store
42
+ .idea/
43
+ .vscode/settings.json
44
+
45
+ # ─ Changelog (history, not context)
46
+ CHANGELOG.md
47
+
48
+ # ─ Web3 / Solidity Generated Files
49
+ artifacts/
50
+ cache/
51
+ cache_forge/
52
+ out/
53
+ out_forge/
54
+ typechain/
55
+ typechain-types/
56
+ broadcast/
57
+ broadcast_forge/
58
+ flatten/
59
+ flattened/
60
+ build/contracts/
61
+ # Common Foundry dependencies that kill context limits:
62
+ lib/forge-std/
63
+ lib/openzeppelin-contracts*/
64
+ lib/erc721a*/
@@ -0,0 +1,7 @@
1
+ # ai-context-surgeon Rules Trigger
2
+
3
+ Follow the architectural instructions located in:
4
+ .agents/AGENTS.md
5
+
6
+ If requested to refactor, adopt roles from:
7
+ .agents/surgeon/roles/
@@ -0,0 +1,44 @@
1
+ <!-- FNH: Template — Knowledge Item (metadata.json) | SECTIONS: Metadata, Artifacts | DEPS: none -->
2
+ <!-- Knowledge Item Template -->
3
+ <!-- Directory: .agents/knowledge/{{KI_NAME}}/ -->
4
+
5
+ <!-- FILE: metadata.json -->
6
+ {
7
+ "title": "{{KI_TITLE}}",
8
+ "summary": "{{KI_SUMMARY_1_2_SENTENCES}}",
9
+ "references": [
10
+ {
11
+ "type": "file",
12
+ "path": "artifacts/{{ARTIFACT_NAME}}.md"
13
+ }
14
+ ]
15
+ }
16
+
17
+ <!-- FILE: artifacts/{{ARTIFACT_NAME}}.md -->
18
+
19
+ # {{KI_TITLE}}
20
+
21
+ > {{KI_SUMMARY_1_2_SENTENCES}}
22
+
23
+ ## {{SECTION_1}}
24
+
25
+ {{CONCRETE_SPECIFIC_INFORMATION}}
26
+
27
+ ## {{SECTION_2}}
28
+
29
+ {{MORE_CONCRETE_INFORMATION}}
30
+
31
+ <!--
32
+ RULES FOR WRITING KNOWLEDGE ITEMS:
33
+ 1. ATOMIC — One topic per KI. Not "everything about the project".
34
+ 2. CONCRETE — Specific values, rules, patterns. Not "our API is modern".
35
+ 3. ACTIONABLE — Agent should know WHAT TO DO after reading.
36
+ 4. STRUCTURED — Headers, tables, code blocks. Easy to scan.
37
+ 5. SMALL — Keep under 200 lines. Agent loads full KI into context.
38
+
39
+ GOOD EXAMPLE:
40
+ "API responses use: { data: T, error: null } | { data: null, error: { code, message } }"
41
+
42
+ BAD EXAMPLE:
43
+ "Our API supports many flexible response formats"
44
+ -->
@@ -0,0 +1,26 @@
1
+ <!-- FNH: Template — ideal package.json | SECTIONS: Fields Tier, Sort Order | DEPS: strategy/package-json-guide.md -->
2
+ {
3
+ "name": "@{{SCOPE}}/{{PACKAGE_NAME}}",
4
+ "version": "1.0.0",
5
+ "description": "{{ONE_LINE_DESCRIPTION}}",
6
+ "private": true,
7
+ "type": "module",
8
+
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+
12
+ "scripts": {
13
+ "dev": "{{DEV_COMMAND}}",
14
+ "build": "tsc",
15
+ "test": "vitest run",
16
+ "lint": "eslint src/"
17
+ },
18
+
19
+ "dependencies": {
20
+ {{RUNTIME_DEPENDENCIES}}
21
+ },
22
+
23
+ "devDependencies": {
24
+ {{MINIMAL_DEV_DEPENDENCIES}}
25
+ }
26
+ }
@@ -0,0 +1,45 @@
1
+ <!-- FNH: Template — package README for new packages | EXPORTS: domain logic, API | DEPS: none -->
2
+ # packages/{{PACKAGE_NAME}}
3
+
4
+ > Package: {{PACKAGE_DESCRIPTION}} | SECTIONS: Source Structure, Scripts, Meta | DEPS: none
5
+
6
+ ## Source Structure
7
+
8
+ ```
9
+ src/
10
+ index.ts ← Public API exports
11
+ types.ts ← Type contracts (interfaces, DTOs)
12
+ {{FILE_TREE}}
13
+ ```
14
+
15
+ ## Dependencies
16
+
17
+ | Package | Purpose |
18
+ |----|----|
19
+ | `@{{SCOPE}}/{{DEP_NAME}}` | {{DEP_PURPOSE}} |
20
+
21
+ ## Public API
22
+
23
+ ```typescript
24
+ // Key exports from src/index.ts
25
+ export { {{EXPORTS}} } from './...';
26
+ ```
27
+
28
+ ## Environment Variables
29
+
30
+ | Variable | Required | Description |
31
+ |----|----|----|
32
+ | `{{ENV_VAR}}` | {{REQUIRED}} | {{ENV_DESC}} |
33
+
34
+ ## Scripts
35
+
36
+ ```bash
37
+ # Build
38
+ {{BUILD_CMD}}
39
+
40
+ # Test
41
+ {{TEST_CMD}}
42
+
43
+ # Lint
44
+ {{LINT_CMD}}
45
+ ```
@@ -0,0 +1,34 @@
1
+ <!-- FNH: Template — publish-meta.json for bulk metadata injection | SECTIONS: Shared Meta, Overrides | DEPS: tools/enrich-package-json.js -->
2
+ {
3
+ "_comment": "Publish metadata — injected into package.json before npm publish, stripped after",
4
+
5
+ "shared": {
6
+ "author": "{{AUTHOR_NAME}} <{{AUTHOR_EMAIL}}>",
7
+ "license": "MIT",
8
+ "engines": {
9
+ "node": ">=18.0.0"
10
+ }
11
+ },
12
+
13
+ "repositoryPattern": "git+https://github.com/{{ORG}}/{{REPO}}.git",
14
+ "homepagePattern": "https://github.com/{{ORG}}/{{REPO}}/tree/main/packages/{{package}}",
15
+ "bugsUrl": "https://github.com/{{ORG}}/{{REPO}}/issues",
16
+
17
+ "defaultFiles": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+
23
+ "packages": {
24
+ "@{{SCOPE}}/core": {
25
+ "keywords": ["core", "domain", "entities"]
26
+ },
27
+ "@{{SCOPE}}/api": {
28
+ "keywords": ["api", "rest", "express"]
29
+ },
30
+ "@{{SCOPE}}/shared": {
31
+ "keywords": ["shared", "types", "utils"]
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,50 @@
1
+ <!-- FNH: Template — skill definition (SKILL.md) | SECTIONS: Use, Prerequisites, Steps | DEPS: none -->
2
+ ---
3
+ name: {{SKILL_NAME}}
4
+ description: >-
5
+ {{SKILL_DESCRIPTION_ONE_LINE}}
6
+ Use when {{TRIGGER_CONDITION}}.
7
+ ---
8
+
9
+ # {{SKILL_TITLE}}
10
+
11
+ ## When to Use
12
+ - {{TRIGGER_1}}
13
+ - {{TRIGGER_2}}
14
+
15
+ ## When NOT to Use
16
+ - {{ANTI_TRIGGER_1}}
17
+ - {{ANTI_TRIGGER_2}}
18
+
19
+ ## Prerequisites
20
+ - {{PREREQ_1}}
21
+
22
+ ## Steps
23
+
24
+ 1. {{STEP_1}}
25
+ 2. {{STEP_2}}
26
+ 3. {{STEP_3}}
27
+ 4. Verify: `{{VERIFY_COMMAND}}`
28
+
29
+ ## Template Code
30
+
31
+ ### {{TEMPLATE_FILE_1}}
32
+
33
+ ```{{LANGUAGE}}
34
+ {{TEMPLATE_CODE}}
35
+ ```
36
+
37
+ ## Gotchas
38
+
39
+ - ⚠️ {{GOTCHA_1}}
40
+ - ⚠️ {{GOTCHA_2}}
41
+
42
+ <!--
43
+ RULES FOR WRITING SKILLS:
44
+ 1. SELF-CONTAINED — Everything needed is in this file + assets/
45
+ 2. SPECIFIC TRIGGERS — Clear "when to use" / "when NOT to use"
46
+ 3. STEP-BY-STEP — Numbered steps, not prose
47
+ 4. TEMPLATES — Copy-paste ready code
48
+ 5. VERIFY — Always include a verification step
49
+ 6. CONCISE — Agent context is limited. Don't waste it.
50
+ -->
@@ -0,0 +1,33 @@
1
+ <!-- FNH: Template — executable workflow | SECTIONS: Steps, Annotations | DEPS: none -->
2
+ ---
3
+ description: {{WORKFLOW_DESCRIPTION}}
4
+ ---
5
+
6
+ {{TURBO_ANNOTATION}}
7
+ <!-- Use '// turbo-all' above to auto-approve ALL commands -->
8
+ <!-- Use '// turbo' above individual steps to auto-approve that step only -->
9
+ <!-- Omit both for manual approval of every command -->
10
+
11
+ 1. {{STEP_1_DESCRIPTION}}
12
+ ```bash
13
+ {{COMMAND_1}}
14
+ ```
15
+
16
+ 2. {{STEP_2_DESCRIPTION}}
17
+ ```bash
18
+ {{COMMAND_2}}
19
+ ```
20
+
21
+ 3. Verify result:
22
+ ```bash
23
+ {{VERIFY_COMMAND}}
24
+ ```
25
+
26
+ <!--
27
+ RULES FOR WRITING WORKFLOWS:
28
+ 1. IDEMPOTENT — Running twice should not break anything
29
+ 2. EXPLICIT — Every command fully specified (no "run the usual build")
30
+ 3. VERIFIABLE — Last step always verifies success
31
+ 4. SAFE — Use '// turbo' only for read-only/safe commands
32
+ 5. PARAMETERIZED — Use {{PLACEHOLDERS}} for variable parts
33
+ -->
@@ -0,0 +1,213 @@
1
+ #!/bin/bash
2
+ # Tool: analyze-package-json — Analyze package.json files for AI-readiness | DEPS: none
3
+ # USAGE: bash tools/analyze-package-json.sh /path/to/monorepo
4
+ # OUTPUT: analysis report in scout-report.md
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/analyze-package-json.sh /path/to/monorepo"
15
+ echo ""
16
+ echo "Analyzes all package.json files in a monorepo for AI-agent readiness."
17
+ echo "Checks for:"
18
+ echo " - Inline configs (jest, eslint, prettier, babel) — should be separate files"
19
+ echo " - Missing critical fields (name, description, scripts)"
20
+ echo " - Excessive dependencies"
21
+ echo " - Field ordering"
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 "📦 Analyzing package.json files in: $TARGET"
32
+ echo "════════════════════════════════════════════════════════"
33
+
34
+ TOTAL_ISSUES=0
35
+ TOTAL_FILES=0
36
+
37
+ # Find all package.json files (excluding node_modules)
38
+ find "$TARGET" -name "package.json" \
39
+ -not -path "*/node_modules/*" -not -path "*/lib/forge-std/*" -not -path "*/lib/openzeppelin-contracts*" -not -path "*/lib/erc721a*" \
40
+ -not -path "*/dist/*" \
41
+ -not -path "*/.git/*" \
42
+ | sort \
43
+ | while read -r pkg_file; do
44
+
45
+ TOTAL_FILES=$((TOTAL_FILES + 1))
46
+ ISSUES=0
47
+
48
+ rel_path="${pkg_file#$TARGET/}"
49
+ line_count=$(wc -l < "$pkg_file" | tr -d ' ')
50
+ byte_count=$(wc -c < "$pkg_file" | tr -d ' ')
51
+ token_estimate=$((byte_count / 4))
52
+
53
+ echo ""
54
+ echo "────────────────────────────────────────"
55
+ echo "📄 $rel_path"
56
+ echo " Lines: $line_count | Tokens: ~$token_estimate"
57
+ echo ""
58
+
59
+ # ── Tier 1: Critical fields check ──
60
+
61
+ pkg_name=$(python3 -c "import json; d=json.load(open('$pkg_file')); print(d.get('name',''))" 2>/dev/null || echo "")
62
+ pkg_desc=$(python3 -c "import json; d=json.load(open('$pkg_file')); print(d.get('description',''))" 2>/dev/null || echo "")
63
+ has_scripts=$(python3 -c "import json; d=json.load(open('$pkg_file')); print('yes' if d.get('scripts') else 'no')" 2>/dev/null || echo "no")
64
+ has_main=$(python3 -c "import json; d=json.load(open('$pkg_file')); print('yes' if d.get('main') or d.get('exports') else 'no')" 2>/dev/null || echo "no")
65
+ has_type=$(python3 -c "import json; d=json.load(open('$pkg_file')); print('yes' if d.get('type') else 'no')" 2>/dev/null || echo "no")
66
+
67
+ if [[ -z "$pkg_name" ]]; then
68
+ echo " 🔴 MISSING: name"
69
+ ISSUES=$((ISSUES + 1))
70
+ fi
71
+
72
+ if [[ -z "$pkg_desc" ]]; then
73
+ echo " 🟡 MISSING: description — agent won't understand purpose"
74
+ ISSUES=$((ISSUES + 1))
75
+ fi
76
+
77
+ if [[ "$has_scripts" == "no" ]]; then
78
+ echo " 🟡 MISSING: scripts — agent won't know how to build/test"
79
+ ISSUES=$((ISSUES + 1))
80
+ fi
81
+
82
+ if [[ "$has_main" == "no" ]]; then
83
+ echo " 🟢 MISSING: main/exports — no entry point defined"
84
+ fi
85
+
86
+ if [[ "$has_type" == "no" ]]; then
87
+ echo " 🟢 MISSING: type — module system unclear (CJS assumed)"
88
+ fi
89
+
90
+ # ── Tier 4: Inline configs check ──
91
+
92
+ python3 -c "
93
+ import json, sys
94
+
95
+ d = json.load(open('$pkg_file'))
96
+ issues = 0
97
+
98
+ # Inline config detection
99
+ inline_configs = {
100
+ 'jest': 'jest.config.ts',
101
+ 'eslintConfig': '.eslintrc.js or eslint.config.js',
102
+ 'prettier': '.prettierrc',
103
+ 'babel': 'babel.config.js',
104
+ 'browserslist': '.browserslistrc',
105
+ 'lint-staged': '.lintstagedrc',
106
+ 'husky': '.husky/',
107
+ 'commitlint': 'commitlint.config.js',
108
+ 'stylelint': '.stylelintrc',
109
+ 'postcss': 'postcss.config.js',
110
+ 'ava': 'ava.config.js',
111
+ 'mocha': '.mocharc.yml',
112
+ 'nyc': '.nycrc',
113
+ 'c8': 'c8 CLI flags',
114
+ 'release-it': '.release-it.json',
115
+ 'standard-version': '.versionrc',
116
+ }
117
+
118
+ for field, target in inline_configs.items():
119
+ if field in d:
120
+ val = d[field]
121
+ lines = len(json.dumps(val, indent=2).split('\n'))
122
+ tokens = len(json.dumps(val)) // 4
123
+ print(f' 🔴 INLINE CONFIG: \"{field}\" ({lines} lines, ~{tokens} tokens) → move to {target}')
124
+ issues += 1
125
+
126
+ # Dependency counts
127
+ deps = d.get('dependencies', {})
128
+ dev_deps = d.get('devDependencies', {})
129
+ peer_deps = d.get('peerDependencies', {})
130
+
131
+ dep_count = len(deps)
132
+ dev_dep_count = len(dev_deps)
133
+
134
+ if dep_count > 25:
135
+ print(f' 🟡 MANY dependencies: {dep_count} — consider splitting package')
136
+ issues += 1
137
+ elif dep_count > 50:
138
+ print(f' 🔴 TOO MANY dependencies: {dep_count} — package does too much')
139
+ issues += 1
140
+
141
+ if dev_dep_count > 20:
142
+ print(f' 🟡 MANY devDependencies: {dev_dep_count} — consider hoisting to root')
143
+ issues += 1
144
+
145
+ # Resolutions/overrides
146
+ if 'resolutions' in d:
147
+ res_count = len(d['resolutions'])
148
+ res_tokens = len(json.dumps(d['resolutions'])) // 4
149
+ if res_count > 5:
150
+ print(f' 🟡 resolutions: {res_count} entries (~{res_tokens} tokens) — keep only in root')
151
+ issues += 1
152
+
153
+ if 'overrides' in d:
154
+ ovr_count = len(d['overrides']) if isinstance(d['overrides'], dict) else 0
155
+ ovr_tokens = len(json.dumps(d['overrides'])) // 4
156
+ if ovr_count > 5:
157
+ print(f' 🟡 overrides: {ovr_count} entries (~{ovr_tokens} tokens) — keep only in root')
158
+ issues += 1
159
+
160
+ # Scripts count
161
+ scripts = d.get('scripts', {})
162
+ script_count = len(scripts)
163
+ if script_count > 12:
164
+ print(f' 🟡 TOO MANY scripts: {script_count} — simplify to 4-8 key scripts')
165
+ issues += 1
166
+
167
+ # Long script values
168
+ for name, cmd in scripts.items():
169
+ if len(cmd) > 150:
170
+ print(f' 🟡 LONG script \"{name}\": {len(cmd)} chars — move to scripts/*.sh')
171
+ issues += 1
172
+
173
+ # Size check
174
+ if lines_count := len(json.dumps(d, indent=2).split('\n')):
175
+ if lines_count > 60:
176
+ print(f' 🔴 FILE TOO LARGE: {lines_count} lines — target ≤30 lines')
177
+ issues += 1
178
+ elif lines_count > 30:
179
+ print(f' 🟡 FILE LARGE: {lines_count} lines — target ≤30 lines')
180
+ issues += 1
181
+
182
+ # Token budget assessment
183
+ total_tokens = len(json.dumps(d)) // 4
184
+ if total_tokens > 2000:
185
+ emoji = '🔴'
186
+ label = 'HARMFUL'
187
+ elif total_tokens > 800:
188
+ emoji = '🟡'
189
+ label = 'HIGH'
190
+ elif total_tokens > 300:
191
+ emoji = '🟢'
192
+ label = 'OK'
193
+ else:
194
+ emoji = '⭐'
195
+ label = 'EXCELLENT'
196
+
197
+ print(f'')
198
+ print(f' {emoji} Context cost: ~{total_tokens} tokens ({label})')
199
+ print(f' deps: {dep_count} | devDeps: {dev_dep_count} | scripts: {script_count}')
200
+
201
+ if issues == 0:
202
+ print(f' ✅ No issues found')
203
+
204
+ sys.exit(issues)
205
+ " 2>/dev/null || true
206
+
207
+ done
208
+
209
+ echo ""
210
+ echo "════════════════════════════════════════════════════════"
211
+ echo "✅ Analysis complete"
212
+ echo ""
213
+ echo "📖 See strategy/package-json-guide.md for full optimization guide"
@@ -0,0 +1,101 @@
1
+ #!/bin/bash
2
+ # Tool: analyze-structure — Analyze monorepo structure and generate metrics | DEPS: none
3
+ # USAGE: bash tools/analyze-structure.sh /path/to/monorepo
4
+ # OUTPUT: structural metrics and directory map
5
+ # MODE: read-only analysis
6
+
7
+ set -euo pipefail
8
+
9
+ source "$(dirname "$0")/shared/config.sh"
10
+
11
+ TARGET="${1:-.}"
12
+ DIVIDER="────────────────────────────────────────"
13
+
14
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
15
+ echo "Usage: bash tools/analyze-structure.sh /path/to/monorepo"
16
+ echo ""
17
+ echo "Analyzes monorepo structure and outputs key metrics:"
18
+ echo " - Total files and directories"
19
+ echo " - Files per directory (top 10 densest)"
20
+ echo " - Deepest nesting level"
21
+ echo " - Package inventory with README/index.ts/types.ts presence"
22
+ echo " - Overall health indicators"
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 "🔍 Analyzing: $TARGET"
32
+ echo "$DIVIDER"
33
+
34
+ # Exclude common non-source directories
35
+ EXCLUDE="-not -path '*/node_modules/*' -not -path '*/lib/forge-std/*' -not -path '*/lib/openzeppelin-contracts*' -not -path '*/lib/erc721a*' -not -path '*/.git/*' -not -path '*/dist/*' -not -path '*/build/*' -not -path '*/.next/*' -not -path '*/.turbo/*'"
36
+
37
+ # 1. Total file counts
38
+ echo ""
39
+ echo "📊 FILE METRICS"
40
+ echo "$DIVIDER"
41
+
42
+ TOTAL_FILES=$(eval "find '$TARGET' -type f $EXCLUDE" | wc -l | tr -d ' ')
43
+ TOTAL_DIRS=$(eval "find '$TARGET' -type d $EXCLUDE" | wc -l | tr -d ' ')
44
+ SRC_FILES=$(eval "find '$TARGET' -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.sol' \) $EXCLUDE" | wc -l | tr -d ' ')
45
+
46
+ echo "Total files: $TOTAL_FILES"
47
+ echo "Total directories: $TOTAL_DIRS"
48
+ echo "Source files: $SRC_FILES (ts/tsx/js/jsx)"
49
+
50
+ # 2. Deepest nesting
51
+ MAX_DEPTH=$(eval "find '$TARGET' -type f $EXCLUDE" | awk -F/ '{print NF}' | sort -n | tail -1)
52
+ echo "Max nesting depth: $MAX_DEPTH levels"
53
+
54
+ # 3. Densest directories (most files in one dir)
55
+ echo ""
56
+ echo "📁 DENSEST DIRECTORIES (top 10)"
57
+ echo "$DIVIDER"
58
+
59
+ eval "find '$TARGET' -type d $EXCLUDE" | while read -r dir; do
60
+ count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')
61
+ if [[ $count -gt 0 ]]; then
62
+ echo "$count $dir"
63
+ fi
64
+ done | sort -rn | head -10
65
+
66
+ # 4. Package inventory
67
+ echo ""
68
+ echo "📦 PACKAGE INVENTORY"
69
+ echo "$DIVIDER"
70
+
71
+ for pkg_dir in "$TARGET"/packages/* "$TARGET"/apps/*; do
72
+ if [[ -d "$pkg_dir" ]]; then
73
+ pkg_name=$(basename "$pkg_dir")
74
+ has_readme="❌"
75
+ has_index="❌"
76
+ has_types="❌"
77
+ has_tests="❌"
78
+
79
+ [[ -f "$pkg_dir/README.md" ]] && has_readme="✅"
80
+ [[ -f "$pkg_dir/src/index.ts" || -f "$pkg_dir/src/index.js" ]] && has_index="✅"
81
+ [[ -f "$pkg_dir/src/types.ts" || -d "$pkg_dir/src/types" ]] && has_types="✅"
82
+ [[ -d "$pkg_dir/tests" || -d "$pkg_dir/__tests__" || -d "$pkg_dir/test" ]] && has_tests="✅"
83
+
84
+ file_count=$(eval "find '$pkg_dir' -type f $EXCLUDE" | wc -l | tr -d ' ')
85
+
86
+ echo "$pkg_name: ${file_count} files | README:${has_readme} index:${has_index} types:${has_types} tests:${has_tests}"
87
+ fi
88
+ done
89
+
90
+ # 5. AGENTS.md check
91
+ echo ""
92
+ echo "🧠 AI-READINESS"
93
+ echo "$DIVIDER"
94
+
95
+ [[ -f "$TARGET/.agents/AGENTS.md" ]] && echo "AGENTS.md: ✅" || echo "AGENTS.md: ❌ MISSING"
96
+ [[ -d "$TARGET/.agents/knowledge" ]] && echo "Knowledge Items: ✅ ($(ls "$TARGET/.agents/knowledge" 2>/dev/null | wc -l | tr -d ' ') items)" || echo "Knowledge Items: ❌ MISSING"
97
+ [[ -d "$TARGET/.agents/skills" ]] && echo "Skills: ✅ ($(ls "$TARGET/.agents/skills" 2>/dev/null | wc -l | tr -d ' ') skills)" || echo "Skills: ❌ MISSING"
98
+ [[ -d "$TARGET/.agents/workflows" ]] && echo "Workflows: ✅ ($(ls "$TARGET/.agents/workflows" 2>/dev/null | wc -l | tr -d ' ') workflows)" || echo "Workflows: ❌ MISSING"
99
+
100
+ echo ""
101
+ echo "✅ Analysis complete"