rails-ai-context 0.15.5 → 0.15.7
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/CHANGELOG.md +28 -0
- data/README.md +28 -5
- data/docs/GUIDE.md +190 -8
- data/lib/rails_ai_context/configuration.rb +55 -0
- data/lib/rails_ai_context/introspectors/config_introspector.rb +1 -1
- data/lib/rails_ai_context/introspectors/controller_introspector.rb +51 -21
- data/lib/rails_ai_context/introspectors/model_introspector.rb +44 -7
- data/lib/rails_ai_context/introspectors/schema_introspector.rb +24 -4
- data/lib/rails_ai_context/introspectors/test_introspector.rb +1 -1
- data/lib/rails_ai_context/introspectors/view_template_introspector.rb +4 -5
- data/lib/rails_ai_context/tools/get_config.rb +2 -16
- data/lib/rails_ai_context/tools/get_controllers.rb +9 -9
- data/lib/rails_ai_context/tools/get_edit_context.rb +4 -2
- data/lib/rails_ai_context/tools/get_gems.rb +3 -1
- data/lib/rails_ai_context/tools/get_model_details.rb +64 -9
- data/lib/rails_ai_context/tools/get_routes.rb +11 -15
- data/lib/rails_ai_context/tools/get_schema.rb +7 -9
- data/lib/rails_ai_context/tools/get_test_info.rb +14 -4
- data/lib/rails_ai_context/tools/get_view.rb +9 -4
- data/lib/rails_ai_context/tools/search_code.rb +8 -4
- data/lib/rails_ai_context/tools/validate.rb +37 -20
- 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: 39df765c4841adb33e68870093b8f58d02ff28dfe5e245ee81655902a9b0fb78
|
|
4
|
+
data.tar.gz: 58385dad4ad55a627d854a2611ed16f951ac0409d54d80e96966efa8b0e1613b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 49755cc6de2afc6a536b470abea60b5a873a9f73419754f4ad304dd8988b34ebfa65b7d69e9878e2c7bdd3418183e9a71da16007f374161e87f44259c209f5f7
|
|
7
|
+
data.tar.gz: 83441b234d6f429d4a066ec79dece90fd5685d5ee4a3e5df882241b21b2b79cddde40d9c0c4fa3ac79322bf26764cf694a4beaf8dc9c419c82d9bc96e37009e3
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.15.7] - 2026-03-22
|
|
9
|
+
|
|
10
|
+
### Improved
|
|
11
|
+
|
|
12
|
+
- **Hybrid filter extraction** — controller filters now use reflection for complete names (handles inheritance + skips), with source parsing from the inheritance chain for only/except constraints.
|
|
13
|
+
- **Callback source fallback** — when reflection returns nothing (e.g. CI), falls back to parsing callback declarations from model source files.
|
|
14
|
+
- **ERB validation accuracy** — in-process compilation with `<%=` → `<%` pre-processing and yield wrapper eliminates false positives from block-form helpers.
|
|
15
|
+
- **Schema static parser** — now extracts `null: false`, `default:`, `array: true` from schema.rb columns, and parses `add_foreign_key` declarations.
|
|
16
|
+
- **Array column display** — schema tool shows PostgreSQL array types as `string[]`, `integer[]`, etc.
|
|
17
|
+
- **Concern test lookup** — `rails_get_test_info(model:"PlanLimitable")` searches concern test paths.
|
|
18
|
+
- **Controller flexible matching** — underscore-based normalization handles CamelCase, snake_case, and slash notation consistently.
|
|
19
|
+
|
|
20
|
+
## [0.15.6] - 2026-03-22
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **7 new configurable options** — `excluded_controllers`, `excluded_route_prefixes`, `excluded_concerns`, `excluded_filters`, `excluded_middleware`, `search_extensions`, `concern_paths` for stack-specific customization.
|
|
25
|
+
- **Configurable file size limits** — `max_file_size`, `max_test_file_size`, `max_schema_file_size`, `max_view_total_size`, `max_view_file_size`, `max_search_results`, `max_validate_files` all exposed via `Configuration`.
|
|
26
|
+
- **Class methods in model detail** — `rails_get_model_details` now shows class methods section.
|
|
27
|
+
- **Custom validate methods** — `validate :method_name` calls extracted from source and shown in model detail.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **Schema defaults always visible** — Null and Default columns always shown (NOT NULL marked bold). Previous token-saving logic accidentally hid critical migration data.
|
|
32
|
+
- **Optional associations** — `belongs_to` with `optional: true` now shows `[optional]` flag.
|
|
33
|
+
- **Concern methods inline** — shows public methods from concern source files (e.g. `PlanLimitable — can_cook?, increment_cook_count!`).
|
|
34
|
+
- **MCP tool error messages** — all tools now show available values on error/not-found for AI self-correction.
|
|
35
|
+
|
|
8
36
|
## [0.15.5] - 2026-03-22
|
|
9
37
|
|
|
10
38
|
### Fixed
|
data/README.md
CHANGED
|
@@ -295,22 +295,45 @@ end
|
|
|
295
295
|
|
|
296
296
|
| Option | Default | Description |
|
|
297
297
|
|--------|---------|-------------|
|
|
298
|
+
| **Presets & Introspectors** | | |
|
|
298
299
|
| `preset` | `:standard` | Introspector preset (`:standard` or `:full`) |
|
|
299
300
|
| `introspectors` | 13 core | Array of introspector symbols |
|
|
301
|
+
| **Context Generation** | | |
|
|
300
302
|
| `context_mode` | `:compact` | `:compact` (≤150 lines) or `:full` (dump everything) |
|
|
301
303
|
| `claude_max_lines` | `150` | Max lines for CLAUDE.md in compact mode |
|
|
302
|
-
| `
|
|
303
|
-
| `
|
|
304
|
-
|
|
|
305
|
-
| `
|
|
304
|
+
| `generate_root_files` | `true` | Generate root files (CLAUDE.md, etc.) — set `false` for split rules only |
|
|
305
|
+
| `output_dir` | `Rails.root` | Output directory for generated context files |
|
|
306
|
+
| **MCP Server** | | |
|
|
307
|
+
| `server_name` | `"rails-ai-context"` | MCP server name |
|
|
308
|
+
| `server_version` | gem version | MCP server version |
|
|
306
309
|
| `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
|
|
307
310
|
| `http_path` | `"/mcp"` | HTTP endpoint path |
|
|
308
311
|
| `http_port` | `6029` | HTTP server port |
|
|
309
312
|
| `http_bind` | `"127.0.0.1"` | HTTP server bind address |
|
|
310
313
|
| `cache_ttl` | `30` | Cache TTL in seconds |
|
|
314
|
+
| `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
|
|
311
315
|
| `live_reload` | `:auto` | `:auto`, `true`, or `false` — MCP live reload |
|
|
312
316
|
| `live_reload_debounce` | `1.5` | Debounce interval in seconds |
|
|
313
|
-
|
|
|
317
|
+
| **Filtering & Exclusions** | | |
|
|
318
|
+
| `excluded_models` | internal Rails models | Models to skip during introspection |
|
|
319
|
+
| `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
|
|
320
|
+
| `sensitive_patterns` | `.env .env.* config/master.key config/credentials.yml.enc config/credentials/*.yml.enc *.pem *.key` | File patterns blocked from search and read tools |
|
|
321
|
+
| `excluded_controllers` | `DeviseController` etc. | Controller classes hidden from listings |
|
|
322
|
+
| `excluded_route_prefixes` | `action_mailbox/ active_storage/ rails/` etc. | Route controller prefixes hidden with app_only |
|
|
323
|
+
| `excluded_concerns` | Rails/Devise/framework patterns | Regex patterns for concerns to hide |
|
|
324
|
+
| `excluded_filters` | `verify_authenticity_token` etc. | Framework filter names hidden from controller output |
|
|
325
|
+
| `excluded_middleware` | standard Rack/Rails middleware | Default middleware hidden from config output |
|
|
326
|
+
| **File Size Limits** | | |
|
|
327
|
+
| `max_file_size` | `2_000_000` | Per-file read limit for tools (bytes) |
|
|
328
|
+
| `max_test_file_size` | `500_000` | Test file read limit (bytes) |
|
|
329
|
+
| `max_schema_file_size` | `10_000_000` | schema.rb / structure.sql parse limit (bytes) |
|
|
330
|
+
| `max_view_total_size` | `5_000_000` | Total aggregated view content for UI patterns (bytes) |
|
|
331
|
+
| `max_view_file_size` | `500_000` | Per-view file during aggregation (bytes) |
|
|
332
|
+
| `max_search_results` | `100` | Max search results per call |
|
|
333
|
+
| `max_validate_files` | `20` | Max files per validate call |
|
|
334
|
+
| **Search & Discovery** | | |
|
|
335
|
+
| `search_extensions` | `rb js erb yml yaml json ts tsx vue svelte haml slim` | File extensions for Ruby fallback search |
|
|
336
|
+
| `concern_paths` | `app/models/concerns app/controllers/concerns` | Where to look for concern source files |
|
|
314
337
|
</details>
|
|
315
338
|
|
|
316
339
|
---
|
data/docs/GUIDE.md
CHANGED
|
@@ -297,6 +297,8 @@ Returns model details: associations, validations, scopes, enums, callbacks, conc
|
|
|
297
297
|
|-------|------|-------------|
|
|
298
298
|
| `model` | string | Model class name (e.g. `User`). Case-insensitive. Omit for listing. |
|
|
299
299
|
| `detail` | string | `summary` / `standard` (default) / `full`. Ignored when model is specified. |
|
|
300
|
+
| `limit` | integer | Max models to return when listing. Default: 50. |
|
|
301
|
+
| `offset` | integer | Skip models for pagination. Default: 0. |
|
|
300
302
|
|
|
301
303
|
**Examples:**
|
|
302
304
|
|
|
@@ -329,6 +331,7 @@ Returns all routes: HTTP verbs, paths, controller actions, route names.
|
|
|
329
331
|
| `detail` | string | `summary` / `standard` (default) / `full` |
|
|
330
332
|
| `limit` | integer | Max routes to return. Default: 100 (standard), 200 (full). |
|
|
331
333
|
| `offset` | integer | Skip routes for pagination. Default: 0. |
|
|
334
|
+
| `app_only` | boolean | Filter out internal Rails routes (Active Storage, Action Mailbox, Conductor, etc.). Default: true. |
|
|
332
335
|
|
|
333
336
|
**Examples:**
|
|
334
337
|
|
|
@@ -386,7 +389,7 @@ rails_get_controllers(detail: "full")
|
|
|
386
389
|
|
|
387
390
|
Returns application configuration. No parameters.
|
|
388
391
|
|
|
389
|
-
**Returns:** cache store, session store, timezone, queue adapter, mailer settings, custom middleware, initializers,
|
|
392
|
+
**Returns:** cache store, session store, timezone, queue adapter, mailer settings, custom middleware (framework defaults are filtered out), notable initializers, CurrentAttributes classes.
|
|
390
393
|
|
|
391
394
|
```
|
|
392
395
|
rails_get_config()
|
|
@@ -401,7 +404,7 @@ Returns test infrastructure details. Optionally filter by model or controller to
|
|
|
401
404
|
|
|
402
405
|
| Param | Type | Description |
|
|
403
406
|
|-------|------|-------------|
|
|
404
|
-
| `model` | string | Show tests for a specific model (e.g. `User`). |
|
|
407
|
+
| `model` | string | Show tests for a specific model (e.g. `User`). Also searches concern test paths (`spec/models/concerns/`, `test/models/concerns/`). |
|
|
405
408
|
| `controller` | string | Show tests for a specific controller (e.g. `Cooks`). |
|
|
406
409
|
| `detail` | string | `summary` / `standard` (default) / `full`. |
|
|
407
410
|
|
|
@@ -441,6 +444,108 @@ rails_get_conventions()
|
|
|
441
444
|
→ Architecture: [MVC, Service objects, Concerns], Patterns: [STI, Polymorphism], ...
|
|
442
445
|
```
|
|
443
446
|
|
|
447
|
+
### rails_get_stimulus
|
|
448
|
+
|
|
449
|
+
Returns Stimulus controller details: targets, values, actions, outlets, classes.
|
|
450
|
+
|
|
451
|
+
**Parameters:**
|
|
452
|
+
|
|
453
|
+
| Param | Type | Description |
|
|
454
|
+
|-------|------|-------------|
|
|
455
|
+
| `controller` | string | Specific Stimulus controller name (e.g. `hello`, `filter-form`). Case-insensitive. |
|
|
456
|
+
| `detail` | string | `summary` / `standard` (default) / `full` |
|
|
457
|
+
| `limit` | integer | Max controllers to return when listing. Default: 50. |
|
|
458
|
+
| `offset` | integer | Skip controllers for pagination. Default: 0. |
|
|
459
|
+
|
|
460
|
+
**Examples:**
|
|
461
|
+
|
|
462
|
+
```
|
|
463
|
+
rails_get_stimulus()
|
|
464
|
+
→ Standard: controller names with targets and actions
|
|
465
|
+
|
|
466
|
+
rails_get_stimulus(detail: "summary")
|
|
467
|
+
→ Names with target/action counts
|
|
468
|
+
|
|
469
|
+
rails_get_stimulus(controller: "filter-form")
|
|
470
|
+
→ Full detail: targets, actions, values, outlets, classes, file path
|
|
471
|
+
|
|
472
|
+
rails_get_stimulus(detail: "full")
|
|
473
|
+
→ All controllers with all details
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### rails_get_view
|
|
477
|
+
|
|
478
|
+
Returns view template contents, partials, and Stimulus controller references.
|
|
479
|
+
|
|
480
|
+
**Parameters:**
|
|
481
|
+
|
|
482
|
+
| Param | Type | Description |
|
|
483
|
+
|-------|------|-------------|
|
|
484
|
+
| `controller` | string | Filter views by controller name (e.g. `cooks`, `brand_profiles`). Use `layouts` for layout files. |
|
|
485
|
+
| `path` | string | Specific view path relative to `app/views` (e.g. `cooks/index.html.erb`). Returns full content. |
|
|
486
|
+
| `detail` | string | `summary` / `standard` (default) / `full` |
|
|
487
|
+
|
|
488
|
+
**Examples:**
|
|
489
|
+
|
|
490
|
+
```
|
|
491
|
+
rails_get_view()
|
|
492
|
+
→ Standard: all view files with partial/stimulus refs
|
|
493
|
+
|
|
494
|
+
rails_get_view(controller: "cooks")
|
|
495
|
+
→ All templates and partials for CooksController
|
|
496
|
+
|
|
497
|
+
rails_get_view(path: "cooks/index.html.erb")
|
|
498
|
+
→ Full template content
|
|
499
|
+
|
|
500
|
+
rails_get_view(controller: "layouts")
|
|
501
|
+
→ Layout files
|
|
502
|
+
|
|
503
|
+
rails_get_view(controller: "cooks", detail: "full")
|
|
504
|
+
→ Full template content for all cooks views
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### rails_get_edit_context
|
|
508
|
+
|
|
509
|
+
Returns just enough context to make a surgical Edit to a file. Returns the target area with line numbers and surrounding code.
|
|
510
|
+
|
|
511
|
+
**Parameters:**
|
|
512
|
+
|
|
513
|
+
| Param | Type | Description |
|
|
514
|
+
|-------|------|-------------|
|
|
515
|
+
| `file` | string | **Required.** File path relative to Rails root (e.g. `app/models/cook.rb`). |
|
|
516
|
+
| `near` | string | **Required.** What to find — a method name, keyword, or string to locate (e.g. `scope`, `def index`). |
|
|
517
|
+
| `context_lines` | integer | Lines of context above and below the match. Default: 5. |
|
|
518
|
+
|
|
519
|
+
**Examples:**
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
rails_get_edit_context(file: "app/models/cook.rb", near: "scope")
|
|
523
|
+
→ Code around the first scope with line numbers, expanded to full method
|
|
524
|
+
|
|
525
|
+
rails_get_edit_context(file: "app/controllers/cooks_controller.rb", near: "def index")
|
|
526
|
+
→ The index action source with surrounding context
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### rails_validate
|
|
530
|
+
|
|
531
|
+
Validates syntax of multiple files at once (Ruby, ERB, JavaScript).
|
|
532
|
+
|
|
533
|
+
**Parameters:**
|
|
534
|
+
|
|
535
|
+
| Param | Type | Description |
|
|
536
|
+
|-------|------|-------------|
|
|
537
|
+
| `files` | array | **Required.** File paths relative to Rails root (e.g. `["app/models/cook.rb", "app/views/cooks/index.html.erb"]`). |
|
|
538
|
+
|
|
539
|
+
**Examples:**
|
|
540
|
+
|
|
541
|
+
```
|
|
542
|
+
rails_validate(files: ["app/models/cook.rb"])
|
|
543
|
+
→ ✓ app/models/cook.rb — syntax OK
|
|
544
|
+
|
|
545
|
+
rails_validate(files: ["app/models/cook.rb", "app/controllers/cooks_controller.rb", "app/views/cooks/index.html.erb"])
|
|
546
|
+
→ Checks all three files, reports pass/fail for each
|
|
547
|
+
```
|
|
548
|
+
|
|
444
549
|
### rails_search_code
|
|
445
550
|
|
|
446
551
|
Ripgrep-powered regex search across the codebase.
|
|
@@ -450,8 +555,10 @@ Ripgrep-powered regex search across the codebase.
|
|
|
450
555
|
| Param | Type | Description |
|
|
451
556
|
|-------|------|-------------|
|
|
452
557
|
| `pattern` | string | **Required.** Regex pattern to search for. |
|
|
558
|
+
| `path` | string | Subdirectory to search in (e.g. `app/models`, `config`). Default: entire app. |
|
|
453
559
|
| `file_type` | string | Filter by file type (e.g. `rb`, `erb`, `js`). Alphanumeric only. |
|
|
454
|
-
| `max_results` | integer | Max results to return. Default:
|
|
560
|
+
| `max_results` | integer | Max results to return. Default: 30, max: 100. |
|
|
561
|
+
| `context_lines` | integer | Lines of context before and after each match (like grep -C). Default: 0, max: 5. |
|
|
455
562
|
|
|
456
563
|
**Examples:**
|
|
457
564
|
|
|
@@ -464,18 +571,28 @@ rails_search_code(pattern: "class.*Controller", file_type: "rb")
|
|
|
464
571
|
|
|
465
572
|
rails_search_code(pattern: "def create", file_type: "rb", max_results: 50)
|
|
466
573
|
→ First 50 create methods across the codebase
|
|
574
|
+
|
|
575
|
+
rails_search_code(pattern: "current_user", path: "app/controllers")
|
|
576
|
+
→ Search only in app/controllers/
|
|
577
|
+
|
|
578
|
+
rails_search_code(pattern: "validates", context_lines: 2)
|
|
579
|
+
→ Matches with 2 lines of context before and after
|
|
467
580
|
```
|
|
468
581
|
|
|
469
|
-
**Security:** Uses `Open3.capture2` with array arguments (no shell injection). Validates file_type. Blocks path traversal. Respects `excluded_paths` config.
|
|
582
|
+
**Security:** Uses `Open3.capture2` with array arguments (no shell injection). Validates file_type. Blocks path traversal. Respects `excluded_paths` and `sensitive_patterns` config.
|
|
470
583
|
|
|
471
584
|
### Detail Level Summary
|
|
472
585
|
|
|
473
|
-
|
|
474
|
-
|
|
586
|
+
All tools that support `detail` use these three levels. Default limits vary by tool — schema defaults shown below:
|
|
587
|
+
|
|
588
|
+
| Level | What it returns | Schema default limit | Best for |
|
|
589
|
+
|-------|----------------|---------------------|----------|
|
|
475
590
|
| `summary` | Names + counts | 50 | Getting the landscape, understanding what exists |
|
|
476
591
|
| `standard` | Names + key details | 15 | Working context, column types, action names |
|
|
477
592
|
| `full` | Everything | 5 | Deep inspection, indexes, FKs, constraints |
|
|
478
593
|
|
|
594
|
+
Other tools default to higher limits (e.g. models/controllers/stimulus: 50 for all levels, routes: 100/200).
|
|
595
|
+
|
|
479
596
|
### Recommended Workflow
|
|
480
597
|
|
|
481
598
|
1. **Start with `detail:"summary"`** to see what exists
|
|
@@ -636,6 +753,55 @@ RailsAiContext.configure do |config|
|
|
|
636
753
|
# Paths to exclude from code search
|
|
637
754
|
config.excluded_paths += %w[vendor/bundle]
|
|
638
755
|
|
|
756
|
+
# Sensitive file patterns blocked from search and read tools
|
|
757
|
+
# config.sensitive_patterns += %w[config/my_secret.yml]
|
|
758
|
+
|
|
759
|
+
# Controllers hidden from listings (e.g. Devise internals)
|
|
760
|
+
# config.excluded_controllers += %w[MyInternalController]
|
|
761
|
+
|
|
762
|
+
# Route prefixes hidden with app_only (e.g. admin frameworks)
|
|
763
|
+
# config.excluded_route_prefixes += %w[admin/]
|
|
764
|
+
|
|
765
|
+
# Regex patterns for concerns to hide from model output
|
|
766
|
+
# config.excluded_concerns += [/MyInternal::/]
|
|
767
|
+
|
|
768
|
+
# Framework filter names hidden from controller output
|
|
769
|
+
# config.excluded_filters += %w[my_internal_filter]
|
|
770
|
+
|
|
771
|
+
# Default middleware hidden from config output
|
|
772
|
+
# config.excluded_middleware += %w[MyMiddleware]
|
|
773
|
+
|
|
774
|
+
# --- File size limits ---
|
|
775
|
+
|
|
776
|
+
# Per-file read limit for tools (default: 2MB)
|
|
777
|
+
# config.max_file_size = 2_000_000
|
|
778
|
+
|
|
779
|
+
# Test file read limit (default: 500KB)
|
|
780
|
+
# config.max_test_file_size = 500_000
|
|
781
|
+
|
|
782
|
+
# schema.rb / structure.sql parse limit (default: 10MB)
|
|
783
|
+
# config.max_schema_file_size = 10_000_000
|
|
784
|
+
|
|
785
|
+
# Total aggregated view content for UI patterns (default: 5MB)
|
|
786
|
+
# config.max_view_total_size = 5_000_000
|
|
787
|
+
|
|
788
|
+
# Per-view file during aggregation (default: 500KB)
|
|
789
|
+
# config.max_view_file_size = 500_000
|
|
790
|
+
|
|
791
|
+
# Max search results per call (default: 100)
|
|
792
|
+
# config.max_search_results = 100
|
|
793
|
+
|
|
794
|
+
# Max files per validate call (default: 20)
|
|
795
|
+
# config.max_validate_files = 20
|
|
796
|
+
|
|
797
|
+
# --- Search and file discovery ---
|
|
798
|
+
|
|
799
|
+
# File extensions for Ruby fallback search
|
|
800
|
+
# config.search_extensions = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
|
|
801
|
+
|
|
802
|
+
# Where to look for concern source files
|
|
803
|
+
# config.concern_paths = %w[app/models/concerns app/controllers/concerns]
|
|
804
|
+
|
|
639
805
|
# --- Live reload ---
|
|
640
806
|
|
|
641
807
|
# Auto-invalidate MCP tool caches on file changes
|
|
@@ -667,6 +833,7 @@ end
|
|
|
667
833
|
| `cache_ttl` | Integer | `30` | Cache TTL in seconds for introspection results |
|
|
668
834
|
| `excluded_models` | Array | internal Rails models | Models to skip |
|
|
669
835
|
| `excluded_paths` | Array | `node_modules tmp log vendor .git` | Paths excluded from code search |
|
|
836
|
+
| `sensitive_patterns` | Array | `.env`, `.key`, `.pem`, credentials | File patterns blocked from search and read tools |
|
|
670
837
|
| `output_dir` | String | `nil` (Rails.root) | Where to write context files |
|
|
671
838
|
| `auto_mount` | Boolean | `false` | Auto-mount HTTP MCP endpoint |
|
|
672
839
|
| `http_path` | String | `"/mcp"` | HTTP endpoint path |
|
|
@@ -675,7 +842,22 @@ end
|
|
|
675
842
|
| `live_reload` | Symbol/Boolean | `:auto` | `:auto`, `true`, or `false` — enable MCP live reload |
|
|
676
843
|
| `live_reload_debounce` | Float | `1.5` | Debounce interval in seconds for live reload |
|
|
677
844
|
| `server_name` | String | `"rails-ai-context"` | MCP server name |
|
|
845
|
+
| `server_version` | String | gem version | MCP server version |
|
|
678
846
|
| `generate_root_files` | Boolean | `true` | Generate root files (CLAUDE.md, .windsurfrules, etc.) — set `false` for split rules only |
|
|
847
|
+
| `max_file_size` | Integer | `2_000_000` | Per-file read limit for tools (2MB) |
|
|
848
|
+
| `max_test_file_size` | Integer | `500_000` | Test file read limit (500KB) |
|
|
849
|
+
| `max_schema_file_size` | Integer | `10_000_000` | schema.rb / structure.sql parse limit (10MB) |
|
|
850
|
+
| `max_view_total_size` | Integer | `5_000_000` | Total aggregated view content for UI patterns (5MB) |
|
|
851
|
+
| `max_view_file_size` | Integer | `500_000` | Per-view file during aggregation (500KB) |
|
|
852
|
+
| `max_search_results` | Integer | `100` | Max search results per call |
|
|
853
|
+
| `max_validate_files` | Integer | `20` | Max files per validate call |
|
|
854
|
+
| `excluded_controllers` | Array | `DeviseController`, etc. | Controller classes hidden from listings |
|
|
855
|
+
| `excluded_route_prefixes` | Array | `action_mailbox/`, `active_storage/`, etc. | Route controller prefixes hidden with `app_only` |
|
|
856
|
+
| `excluded_concerns` | Array | framework regex patterns | Regex patterns for concerns to hide from model output |
|
|
857
|
+
| `excluded_filters` | Array | `verify_authenticity_token`, etc. | Framework filter names hidden from controller output |
|
|
858
|
+
| `excluded_middleware` | Array | standard Rails middleware | Default middleware hidden from config output |
|
|
859
|
+
| `search_extensions` | Array | `rb js erb yml yaml json ts tsx vue svelte haml slim` | File extensions for Ruby fallback search |
|
|
860
|
+
| `concern_paths` | Array | `app/models/concerns app/controllers/concerns` | Where to look for concern source files |
|
|
679
861
|
|
|
680
862
|
### Root file generation
|
|
681
863
|
|
|
@@ -712,7 +894,7 @@ These run by default. Fast and cover core Rails structure.
|
|
|
712
894
|
| `controllers` | Actions, filters (before/after/around with only/except), strong params methods, parent class, API controller detection, concerns. |
|
|
713
895
|
| `tests` | Test framework (rspec/minitest), factories/fixtures with locations and counts, system tests, CI config files, coverage tool, test helpers, VCR cassettes. |
|
|
714
896
|
| `migrations` | Total count, schema version, pending migrations, recent migration history with detected actions (create_table, add_column, etc.), migration statistics. |
|
|
715
|
-
| `config` | Cache store, session store, timezone, middleware stack, initializers, credentials
|
|
897
|
+
| `config` | Cache store, session store, timezone, queue adapter, mailer settings, middleware stack, initializers, credentials status, CurrentAttributes classes. |
|
|
716
898
|
| `stimulus` | Stimulus controllers with targets, values (with types), actions, outlets, classes. Extracted from JS/TS files. |
|
|
717
899
|
| `view_templates` | View file contents, partial references, Stimulus data attributes, UI pattern extraction, model field usage in partials. |
|
|
718
900
|
| `design_tokens` | Auto-detects CSS framework (Tailwind v3/v4, Bootstrap, Sass, plain CSS) and extracts design tokens from config files and built CSS. |
|
|
@@ -750,7 +932,7 @@ config.preset = :full
|
|
|
750
932
|
|
|
751
933
|
```ruby
|
|
752
934
|
# Start with standard, add specific ones
|
|
753
|
-
config.introspectors += %i[views turbo auth api
|
|
935
|
+
config.introspectors += %i[views turbo auth api]
|
|
754
936
|
|
|
755
937
|
# Or build from scratch
|
|
756
938
|
config.introspectors = %i[schema models routes gems auth api]
|
|
@@ -60,6 +60,26 @@ module RailsAiContext
|
|
|
60
60
|
# When false, only generates split rule files (.claude/rules/, .cursor/rules/, etc.)
|
|
61
61
|
attr_accessor :generate_root_files
|
|
62
62
|
|
|
63
|
+
# File size limits (bytes) — increase for larger projects
|
|
64
|
+
attr_accessor :max_file_size # Per-file read limit for tools (default: 2MB)
|
|
65
|
+
attr_accessor :max_test_file_size # Test file read limit (default: 500KB)
|
|
66
|
+
attr_accessor :max_schema_file_size # schema.rb / structure.sql parse limit (default: 10MB)
|
|
67
|
+
attr_accessor :max_view_total_size # Total aggregated view content for UI patterns (default: 5MB)
|
|
68
|
+
attr_accessor :max_view_file_size # Per-view file during aggregation (default: 500KB)
|
|
69
|
+
attr_accessor :max_search_results # Max search results per call (default: 100)
|
|
70
|
+
attr_accessor :max_validate_files # Max files per validate call (default: 20)
|
|
71
|
+
|
|
72
|
+
# Filtering — customize what's hidden from AI output
|
|
73
|
+
attr_accessor :excluded_controllers # Controller classes hidden from listings (e.g. DeviseController)
|
|
74
|
+
attr_accessor :excluded_route_prefixes # Route controller prefixes hidden with app_only (e.g. action_mailbox/)
|
|
75
|
+
attr_accessor :excluded_concerns # Regex patterns for concerns to hide (e.g. /Devise::Models/)
|
|
76
|
+
attr_accessor :excluded_filters # Framework filter names hidden from controller output
|
|
77
|
+
attr_accessor :excluded_middleware # Default middleware hidden from config output
|
|
78
|
+
|
|
79
|
+
# Search and file discovery
|
|
80
|
+
attr_accessor :search_extensions # File extensions for Ruby fallback search (default: rb,js,erb,yml,yaml,json)
|
|
81
|
+
attr_accessor :concern_paths # Where to look for concern source files (default: app/models/concerns)
|
|
82
|
+
|
|
63
83
|
def initialize
|
|
64
84
|
@server_name = "rails-ai-context"
|
|
65
85
|
@server_version = RailsAiContext::VERSION
|
|
@@ -87,6 +107,41 @@ module RailsAiContext
|
|
|
87
107
|
@live_reload = :auto
|
|
88
108
|
@live_reload_debounce = 1.5
|
|
89
109
|
@generate_root_files = true
|
|
110
|
+
@max_file_size = 2_000_000
|
|
111
|
+
@max_test_file_size = 500_000
|
|
112
|
+
@max_schema_file_size = 10_000_000
|
|
113
|
+
@max_view_total_size = 5_000_000
|
|
114
|
+
@max_view_file_size = 500_000
|
|
115
|
+
@max_search_results = 100
|
|
116
|
+
@max_validate_files = 20
|
|
117
|
+
@excluded_controllers = %w[DeviseController Devise::OmniauthCallbacksController]
|
|
118
|
+
@excluded_route_prefixes = %w[action_mailbox/ active_storage/ rails/ conductor/ devise/ turbo/]
|
|
119
|
+
@excluded_concerns = [
|
|
120
|
+
/::Generated/,
|
|
121
|
+
/\A(ActiveRecord|ActiveModel|ActiveSupport|ActionText|ActionMailbox|ActiveStorage)/,
|
|
122
|
+
/\A(ActionDispatch|ActionController|ActionView|AbstractController)/,
|
|
123
|
+
/\A(Devise::Models|Devise::Orm|Bullet::|Turbo::|GlobalID::|Rolify::)/
|
|
124
|
+
]
|
|
125
|
+
@excluded_filters = %w[
|
|
126
|
+
verify_authenticity_token verify_same_origin_request
|
|
127
|
+
turbo_tracking_request_id handle_unverified_request
|
|
128
|
+
mark_for_same_origin_verification
|
|
129
|
+
]
|
|
130
|
+
@excluded_middleware = %w[
|
|
131
|
+
Rack::Sendfile ActionDispatch::Static ActionDispatch::Executor
|
|
132
|
+
ActionDispatch::ServerTiming Rack::Runtime
|
|
133
|
+
ActionDispatch::RequestId ActionDispatch::RemoteIp
|
|
134
|
+
Rails::Rack::Logger ActionDispatch::ShowExceptions
|
|
135
|
+
ActionDispatch::DebugExceptions ActionDispatch::Callbacks
|
|
136
|
+
ActionDispatch::Cookies ActionDispatch::Session::CookieStore
|
|
137
|
+
ActionDispatch::Flash ActionDispatch::ContentSecurityPolicy::Middleware
|
|
138
|
+
ActionDispatch::PermissionsPolicy::Middleware ActionDispatch::ActionableExceptions
|
|
139
|
+
Rack::Head Rack::ConditionalGet Rack::ETag Rack::TempfileReaper
|
|
140
|
+
ActiveRecord::Migration::CheckPending ActionDispatch::HostAuthorization
|
|
141
|
+
Rack::MethodOverride ActionDispatch::Session::AbstractSecureStore
|
|
142
|
+
]
|
|
143
|
+
@search_extensions = %w[rb js erb yml yaml json ts tsx vue svelte haml slim]
|
|
144
|
+
@concern_paths = %w[app/models/concerns app/controllers/concerns]
|
|
90
145
|
end
|
|
91
146
|
|
|
92
147
|
def preset=(name)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module RailsAiContext
|
|
4
4
|
module Introspectors
|
|
5
5
|
# Extracts application configuration: cache store, session store,
|
|
6
|
-
# timezone, middleware stack, initializers, credentials
|
|
6
|
+
# timezone, middleware stack, initializers, credentials status.
|
|
7
7
|
class ConfigIntrospector
|
|
8
8
|
attr_reader :app
|
|
9
9
|
|
|
@@ -9,12 +9,9 @@ module RailsAiContext
|
|
|
9
9
|
class ControllerIntrospector
|
|
10
10
|
attr_reader :app
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
turbo_tracking_request_id handle_unverified_request
|
|
16
|
-
mark_for_same_origin_verification
|
|
17
|
-
].freeze
|
|
12
|
+
def excluded_filters
|
|
13
|
+
RailsAiContext.configuration.excluded_filters
|
|
14
|
+
end
|
|
18
15
|
|
|
19
16
|
def initialize(app)
|
|
20
17
|
@app = app
|
|
@@ -153,30 +150,63 @@ module RailsAiContext
|
|
|
153
150
|
actions.sort
|
|
154
151
|
end
|
|
155
152
|
|
|
156
|
-
#
|
|
157
|
-
#
|
|
153
|
+
# Hybrid approach: reflection for complete filter names (handles inheritance + skips),
|
|
154
|
+
# source parsing from inheritance chain for only/except constraints.
|
|
158
155
|
def extract_filters(ctrl, source = nil)
|
|
156
|
+
if ctrl.respond_to?(:_process_action_callbacks)
|
|
157
|
+
reflection_filters = ctrl._process_action_callbacks.filter_map do |cb|
|
|
158
|
+
next if cb.filter.is_a?(Proc) || cb.filter.to_s.start_with?("_")
|
|
159
|
+
next if excluded_filters.include?(cb.filter.to_s)
|
|
160
|
+
{ name: cb.filter.to_s, kind: cb.kind.to_s }
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if reflection_filters.any?
|
|
164
|
+
# Collect only/except constraints from source files in the inheritance chain
|
|
165
|
+
source_constraints = collect_source_constraints(ctrl, source)
|
|
166
|
+
reflection_filters.each do |f|
|
|
167
|
+
if (sc = source_constraints[f[:name]])
|
|
168
|
+
f[:only] = sc[:only] if sc[:only]&.any?
|
|
169
|
+
f[:except] = sc[:except] if sc[:except]&.any?
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
return reflection_filters
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Fallback to source parsing when reflection is unavailable
|
|
159
177
|
if source
|
|
160
178
|
filters = extract_filters_from_source(source)
|
|
161
179
|
return filters if filters.any?
|
|
162
180
|
end
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
ctrl._process_action_callbacks.filter_map do |cb|
|
|
166
|
-
next if cb.filter.is_a?(Proc) || cb.filter.to_s.start_with?("_")
|
|
167
|
-
next if FRAMEWORK_FILTERS.include?(cb.filter.to_s)
|
|
168
|
-
|
|
169
|
-
filter = { name: cb.filter.to_s, kind: cb.kind.to_s }
|
|
170
|
-
filter[:only] = cb.instance_variable_get(:@if)&.filter_map { |c| extract_action_condition(c) }&.flatten
|
|
171
|
-
filter[:except] = cb.instance_variable_get(:@unless)&.filter_map { |c| extract_action_condition(c) }&.flatten
|
|
172
|
-
filter.delete(:only) if filter[:only]&.empty?
|
|
173
|
-
filter.delete(:except) if filter[:except]&.empty?
|
|
174
|
-
filter
|
|
175
|
-
end
|
|
181
|
+
|
|
182
|
+
[]
|
|
176
183
|
rescue
|
|
177
184
|
[]
|
|
178
185
|
end
|
|
179
186
|
|
|
187
|
+
# Walk up the controller inheritance chain and collect filter constraints from source files
|
|
188
|
+
def collect_source_constraints(ctrl, current_source = nil)
|
|
189
|
+
constraints = {}
|
|
190
|
+
klass = ctrl
|
|
191
|
+
while klass && klass.name
|
|
192
|
+
break if klass.name.start_with?("ActionController::", "AbstractController::")
|
|
193
|
+
break if klass == ActionController::Base
|
|
194
|
+
break if defined?(ActionController::API) && klass == ActionController::API
|
|
195
|
+
|
|
196
|
+
src = (klass == ctrl) ? (current_source || read_source(klass)) : read_source(klass)
|
|
197
|
+
if src
|
|
198
|
+
extract_filters_from_source(src).each do |sf|
|
|
199
|
+
# First definition wins (most specific controller in chain)
|
|
200
|
+
constraints[sf[:name]] ||= sf
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
klass = klass.superclass
|
|
204
|
+
end
|
|
205
|
+
constraints
|
|
206
|
+
rescue
|
|
207
|
+
{}
|
|
208
|
+
end
|
|
209
|
+
|
|
180
210
|
def extract_filters_from_source(source)
|
|
181
211
|
filters = []
|
|
182
212
|
source.each_line do |line|
|
|
@@ -59,6 +59,7 @@ module RailsAiContext
|
|
|
59
59
|
table_name: model.table_name,
|
|
60
60
|
associations: extract_associations(model),
|
|
61
61
|
validations: extract_validations(model),
|
|
62
|
+
custom_validates: extract_custom_validates(model),
|
|
62
63
|
scopes: extract_scopes(model),
|
|
63
64
|
enums: extract_enums(model),
|
|
64
65
|
callbacks: extract_callbacks(model),
|
|
@@ -109,6 +110,17 @@ module RailsAiContext
|
|
|
109
110
|
[]
|
|
110
111
|
end
|
|
111
112
|
|
|
113
|
+
# Extract custom validate :method_name calls from source
|
|
114
|
+
# These are business-rule validators that model.validators doesn't include
|
|
115
|
+
def extract_custom_validates(model)
|
|
116
|
+
source_path = model_source_path(model)
|
|
117
|
+
return [] unless source_path && File.exist?(source_path)
|
|
118
|
+
|
|
119
|
+
File.read(source_path).scan(/^\s*validate\s+:(\w+)/).flatten
|
|
120
|
+
rescue
|
|
121
|
+
[]
|
|
122
|
+
end
|
|
123
|
+
|
|
112
124
|
def model_source_path(model)
|
|
113
125
|
root = app.root.to_s
|
|
114
126
|
underscored = model.name.underscore
|
|
@@ -133,7 +145,7 @@ module RailsAiContext
|
|
|
133
145
|
after_commit after_rollback
|
|
134
146
|
]
|
|
135
147
|
|
|
136
|
-
callback_types.each_with_object({}) do |type, hash|
|
|
148
|
+
result = callback_types.each_with_object({}) do |type, hash|
|
|
137
149
|
callbacks = model.send(:"_#{type}_callbacks").reject do |cb|
|
|
138
150
|
cb.filter.to_s.start_with?(*EXCLUDED_CALLBACKS) || cb.filter.is_a?(Proc)
|
|
139
151
|
end
|
|
@@ -142,6 +154,29 @@ module RailsAiContext
|
|
|
142
154
|
|
|
143
155
|
hash[type.to_s] = callbacks.map { |cb| cb.filter.to_s }
|
|
144
156
|
end
|
|
157
|
+
|
|
158
|
+
# If reflection returned nothing, fall back to source parsing
|
|
159
|
+
return result if result.any?
|
|
160
|
+
extract_callbacks_from_source(model)
|
|
161
|
+
rescue
|
|
162
|
+
extract_callbacks_from_source(model)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Parse callback declarations from model source file
|
|
166
|
+
def extract_callbacks_from_source(model)
|
|
167
|
+
source_path = model_source_path(model)
|
|
168
|
+
return {} unless source_path && File.exist?(source_path)
|
|
169
|
+
|
|
170
|
+
source = File.read(source_path)
|
|
171
|
+
callbacks = {}
|
|
172
|
+
source.each_line do |line|
|
|
173
|
+
if (match = line.match(/\A\s*(before_validation|after_validation|before_save|after_save|before_create|after_create|before_update|after_update|before_destroy|after_destroy|after_commit|after_rollback)\s+:(\w+)/))
|
|
174
|
+
type = match[1]
|
|
175
|
+
method_name = match[2]
|
|
176
|
+
(callbacks[type] ||= []) << method_name
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
callbacks
|
|
145
180
|
rescue
|
|
146
181
|
{}
|
|
147
182
|
end
|
|
@@ -156,16 +191,18 @@ module RailsAiContext
|
|
|
156
191
|
|
|
157
192
|
def framework_concern?(name)
|
|
158
193
|
return true if name.nil?
|
|
159
|
-
return true if name.
|
|
160
|
-
return true if name.
|
|
161
|
-
|
|
162
|
-
return true if %w[Kernel JSON PP Marshal MessagePack].include?(name)
|
|
163
|
-
false
|
|
194
|
+
return true if %w[Kernel JSON PP Marshal MessagePack].any? { |prefix| name == prefix || name.start_with?("#{prefix}::") }
|
|
195
|
+
return true if name.start_with?("ActiveModel::", "ActiveRecord::", "ActiveSupport::")
|
|
196
|
+
RailsAiContext.configuration.excluded_concerns.any? { |pattern| name.match?(pattern) }
|
|
164
197
|
end
|
|
165
198
|
|
|
166
199
|
def extract_public_class_methods(model)
|
|
200
|
+
scope_names = extract_scopes(model).map(&:to_s)
|
|
167
201
|
(model.methods - ActiveRecord::Base.methods - Object.methods)
|
|
168
|
-
.reject { |m|
|
|
202
|
+
.reject { |m|
|
|
203
|
+
ms = m.to_s
|
|
204
|
+
ms.start_with?("_", "autosave") || scope_names.include?(ms)
|
|
205
|
+
}
|
|
169
206
|
.sort
|
|
170
207
|
.first(30) # Cap to avoid noise
|
|
171
208
|
.map(&:to_s)
|