rails-ai-context 0.10.1 → 0.10.2
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.
- checksums.yaml +4 -4
- data/README.md +42 -15
- data/demo_script.sh +1 -1
- data/lib/rails_ai_context/introspectors/model_introspector.rb +3 -3
- data/lib/rails_ai_context/tools/get_view.rb +5 -0
- data/lib/rails_ai_context/tools/search_code.rb +5 -1
- data/lib/rails_ai_context/version.rb +1 -1
- data/server.json +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 68c0816e248242dd0b6b6c122f8a5538295823a4da7386746aa3d3ea8c3a8ee0
|
|
4
|
+
data.tar.gz: 178f97d3d8557621dbe0cc163e75e83afed3156ca1ea87d185e29ca380567580
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 953fcec85a05ec05862157ae70a8715f0daad9d1b4f1fba075c8f1ef16a13de90eaf81e3906efd5790fb4ed32106bb5838668ff0d41533a569a7e6443f63b141
|
|
7
|
+
data.tar.gz: eade81b4fa9597317981d8f17a6fccdc6d9872adae3b543dd18cf9449d6746072584f754ded5031c2376b33d30aded7164c03f7253513e1c2f2c7b9c4c35d225
|
data/README.md
CHANGED
|
@@ -21,22 +21,49 @@ The AI doesn't know your schema, your Devise setup, your Sidekiq jobs, or that `
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
## Proof:
|
|
24
|
+
## Proof: 37% Token Savings (Real Benchmark)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Same task — *"Add status and date range filters to the Cooks index page"* — 4 scenarios in parallel, same Rails app:
|
|
27
27
|
|
|
28
|
-
|
|
|
29
|
-
|
|
30
|
-
| **
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
28
|
+
| Setup | Tokens | Saved | What it knows |
|
|
29
|
+
|-------|--------|-------|---------------|
|
|
30
|
+
| **rails-ai-context (full)** | **28,834** | **37%** | 11 MCP tools + generated docs + rules |
|
|
31
|
+
| rails-ai-context CLAUDE.md only | 33,106 | 27% | Generated docs + rules, no MCP tools |
|
|
32
|
+
| Normal Claude `/init` | 40,700 | 11% | Generic CLAUDE.md only |
|
|
33
|
+
| No rails-ai-context at all | 45,477 | baseline | Nothing — discovers everything from scratch |
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
```
|
|
36
|
+
No rails-ai-context 45,477 tk █████████████████████████████████████████████
|
|
37
|
+
Normal Claude /init 40,700 tk █████████████████████████████████████████ -11%
|
|
38
|
+
rails-ai-context CLAUDE.md 33,106 tk █████████████████████████████████ -27%
|
|
39
|
+
rails-ai-context (full) 28,834 tk █████████████████████████████ -37%
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
https://github.com/user-attachments/assets/14476243-1210-4e62-9dc5-9d4aa9caef7e
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
**What each layer gives you:**
|
|
46
|
+
|
|
47
|
+
| | Normal `/init` | rails-ai-context CLAUDE.md | rails-ai-context full |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| Knows it's Rails + Tailwind | Yes | Yes | Yes |
|
|
50
|
+
| Knows model names, columns, associations | No | Yes | Yes |
|
|
51
|
+
| Knows controller actions, filters | No | Yes | Yes |
|
|
52
|
+
| Discovery overhead | ~8 calls | 0 calls | 0 calls |
|
|
53
|
+
| Structured MCP queries | No | No | Yes — 5 MCP calls replace file reads |
|
|
54
|
+
|
|
55
|
+
**~16,600 fewer tokens per task** vs no gem at all.
|
|
56
|
+
|
|
57
|
+
> **This was a simple task on a small 5-model app.** Real-world tasks are 3-10x more complex.
|
|
58
|
+
> A feature touching auth + payments + mailers + tests on a 50-model app? Without the gem, Claude reads `db/schema.rb` (2,000+ lines), every model file, every controller, every view — easily 200K+ tokens per session. With rails-ai-context, MCP tools return only what's needed: `rails_get_schema(table:"users")` returns 25 lines instead of 2,000. **The bigger your app and the harder the task, the more you save.**
|
|
36
59
|
|
|
37
|
-
|
|
60
|
+
| App size | Without gem | With rails-ai-context | Savings |
|
|
61
|
+
|----------|-------------|----------------------|---------|
|
|
62
|
+
| Small (5 models) | 45K tokens | 29K tokens | 37% |
|
|
63
|
+
| Medium (30 models) | ~150K tokens | ~60K tokens | ~60% |
|
|
64
|
+
| Large (100+ models) | ~500K+ tokens | ~100K tokens | ~80% |
|
|
38
65
|
|
|
39
|
-
|
|
66
|
+
*Medium/large estimates based on schema.rb scaling (40 lines/table), model file scaling, and MCP summary-first workflow eliminating full-file reads.*
|
|
40
67
|
|
|
41
68
|
---
|
|
42
69
|
|
|
@@ -60,10 +87,10 @@ The install generator creates `.mcp.json` for auto-discovery — Claude Code and
|
|
|
60
87
|
|
|
61
88
|

|
|
62
89
|
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
90
|
+
- `/init` saves 11% — knows the framework but wastes tokens discovering models and tables
|
|
91
|
+
- **CLAUDE.md saves 27%** — complete Rails-specific map, zero discovery overhead
|
|
92
|
+
- **Full MCP saves 37%** — structured queries replace expensive full-file reads
|
|
93
|
+
- MCP tools return `detail:"summary"` first (~55 tokens), then drill into specifics
|
|
67
94
|
- Split rule files only activate in relevant directories
|
|
68
95
|
|
|
69
96
|
---
|
data/demo_script.sh
CHANGED
|
@@ -169,8 +169,8 @@ module RailsAiContext
|
|
|
169
169
|
macros = {}
|
|
170
170
|
|
|
171
171
|
macros[:has_secure_password] = true if source.match?(/\bhas_secure_password\b/)
|
|
172
|
-
macros[:encrypts] = source.scan(/\bencrypts\s+(
|
|
173
|
-
macros[:normalizes] = source.scan(/\bnormalizes\s+(
|
|
172
|
+
macros[:encrypts] = source.scan(/\bencrypts\s+(.+?)$/).flat_map { |m| m[0].scan(/:(\w+)/).flatten } if source.match?(/\bencrypts\s+:/)
|
|
173
|
+
macros[:normalizes] = source.scan(/\bnormalizes\s+(.+?)$/).flat_map { |m| m[0].scan(/:(\w+)/).flatten } if source.match?(/\bnormalizes\s+:/)
|
|
174
174
|
macros[:has_one_attached] = source.scan(/\bhas_one_attached\s+:(\w+)/).flatten if source.match?(/\bhas_one_attached\s+:/)
|
|
175
175
|
macros[:has_many_attached] = source.scan(/\bhas_many_attached\s+:(\w+)/).flatten if source.match?(/\bhas_many_attached\s+:/)
|
|
176
176
|
macros[:has_rich_text] = source.scan(/\bhas_rich_text\s+:(\w+)/).flatten if source.match?(/\bhas_rich_text\s+:/)
|
|
@@ -180,7 +180,7 @@ module RailsAiContext
|
|
|
180
180
|
macros[:store] = source.scan(/\bstore(?:_accessor)?\s+:(\w+)/).flatten if source.match?(/\bstore(?:_accessor)?\s+:/)
|
|
181
181
|
|
|
182
182
|
# Delegations
|
|
183
|
-
delegations = source.scan(/\bdelegate\s+(.+?),\s*to:\s*:(\w+)/).map do |methods_str, target|
|
|
183
|
+
delegations = source.scan(/\bdelegate\s+(.+?),\s*to:\s*:(\w+)/m).map do |methods_str, target|
|
|
184
184
|
{ methods: methods_str.scan(/:(\w+)/).flatten, to: target }
|
|
185
185
|
end
|
|
186
186
|
macros[:delegations] = delegations if delegations.any?
|
|
@@ -92,6 +92,8 @@ module RailsAiContext
|
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
MAX_FILE_SIZE = 2_000_000 # 2MB safety limit
|
|
96
|
+
|
|
95
97
|
private_class_method def self.read_view_file(path)
|
|
96
98
|
views_dir = Rails.root.join("app", "views")
|
|
97
99
|
full_path = views_dir.join(path)
|
|
@@ -103,6 +105,9 @@ module RailsAiContext
|
|
|
103
105
|
unless File.exist?(full_path)
|
|
104
106
|
return text_response("View not found: #{path}")
|
|
105
107
|
end
|
|
108
|
+
if File.size(full_path) > MAX_FILE_SIZE
|
|
109
|
+
return text_response("File too large: #{path} (#{File.size(full_path)} bytes)")
|
|
110
|
+
end
|
|
106
111
|
|
|
107
112
|
content = File.read(full_path)
|
|
108
113
|
text_response("# #{path}\n\n```erb\n#{content}\n```")
|
|
@@ -106,7 +106,11 @@ module RailsAiContext
|
|
|
106
106
|
|
|
107
107
|
private_class_method def self.search_with_ruby(pattern, search_path, file_type, max_results, root)
|
|
108
108
|
results = []
|
|
109
|
-
|
|
109
|
+
begin
|
|
110
|
+
regex = Regexp.new(pattern, Regexp::IGNORECASE, timeout: 2)
|
|
111
|
+
rescue RegexpError => e
|
|
112
|
+
return [ { file: "error", line_number: 0, content: "Invalid regex: #{e.message}" } ]
|
|
113
|
+
end
|
|
110
114
|
glob = file_type ? "**/*.#{file_type}" : "**/*.{rb,js,erb,yml,yaml,json}"
|
|
111
115
|
excluded = RailsAiContext.configuration.excluded_paths
|
|
112
116
|
|
data/server.json
CHANGED
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
"url": "https://github.com/crisnahine/rails-ai-context",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.10.
|
|
10
|
+
"version": "0.10.2",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "mcpb",
|
|
14
|
-
"identifier": "https://github.com/crisnahine/rails-ai-context/releases/download/v0.10.
|
|
14
|
+
"identifier": "https://github.com/crisnahine/rails-ai-context/releases/download/v0.10.2/rails-ai-context-mcp.mcpb",
|
|
15
15
|
"fileSha256": "dd711a0ad6c4de943ae4da94eaf59a6dc9494b9d57f726e24649ed4e2f156990",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|