rails-ai-context 0.15.2 → 0.15.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36149e337f1a334d91a8a59cce1df6b090e621cafbb08886114f775d93cbd643
4
- data.tar.gz: 45bc13bd494a4b4de5742f29b0919a9c77515f4c301c3f347f9235caec08d8a2
3
+ metadata.gz: 688db0da1f692aa30e3e0129f13819bb00959f64306c4bb2efabf3ced84dd7f0
4
+ data.tar.gz: 3338568f68df0f0a74f312e234138580d7b20f607adc6404709c0910580d90c5
5
5
  SHA512:
6
- metadata.gz: 05aa1e4216100cc18572615abf83ea1e22cb1faf77b594a9cb9fea4a4bfab2919a18189a5648455598b051aa6e8b89db00c39ae7ad3018f82aa95bb4bc760064
7
- data.tar.gz: eb59ad0f7fa0c3df2147bb31f1f9b85a69a1a461fd248ade6f97928ed775d727537ddab744aea83284ed6931a0ab997e6c5c46f6e0f716cc5a5f4724b6f4890f
6
+ metadata.gz: 10302870e79b4ef00cdbe55d48e38f03e602b5bed0ccd5d2cf3b5176fa4daa171e0a9d77f044ec32c95e9bbbbc19a3c8cac3de951900e17edd05f8647ea2ebaa
7
+ data.tar.gz: bc923eca00f2a7bcdd6fff58aeb7738e1b47b176cf9db1eba7c3f83d7e864aba433d582614f6e63896d0cd9e9042c7b50203473c0915f9f6ea549b49c89d3264
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ 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.3] - 2026-03-22
9
+
10
+ ### Fixed
11
+
12
+ - **Schema `add_index` column parsing** — option keys (e.g. `unique`, `name`) were being picked up as column names (PR #12).
13
+ - **Windsurf test command** — extracted `TestCommandDetection` shared module; Windsurf now shows specific test command instead of generic "Run tests after changes".
14
+
15
+ ### Changed
16
+
17
+ - **Documentation** — updated all docs (README, CLAUDE.md, GUIDE.md, SECURITY.md, CHANGELOG, server.json, install generator) to match v0.15.x codebase. Fixed spec counts, file counts, preset counts, config options, and supported versions.
18
+
8
19
  ## [0.15.2] - 2026-03-22
9
20
 
10
21
  ### Fixed
@@ -77,6 +88,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
88
  - **Stimulus dash/underscore normalization** — Both `weekly-chart` and `weekly_chart` work for controller lookup. Output shows HTML `data-controller` attribute.
78
89
  - **Model public method signatures** — `rails_get_model_details(model: "Cook")` shows method names with params from source, stopping at private boundary.
79
90
 
91
+ ## [0.13.1] - 2026-03-20
92
+
93
+ ### Changed
94
+
95
+ - **View summary** — now shows partials used by each view.
96
+ - **Model details** — shows method signatures (name + parameters) instead of just method names.
97
+ - Removed unused demo files; fixed GUIDE.md preset tables.
98
+
80
99
  ## [0.13.0] - 2026-03-20
81
100
 
82
101
  ### Added
@@ -139,6 +158,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
139
158
  - **View partial structure** — `rails_get_view(detail: "standard")` shows model fields and helper methods used by each partial.
140
159
  - **Schema column names** — `.claude/rules/rails-schema.md` shows key column names with types, foreign keys, indexes, and enum values. Keeps polymorphic `_type`, STI `type`, and soft-delete `deleted_at` columns.
141
160
 
161
+ ## [0.10.2] - 2026-03-20
162
+
163
+ ### Security
164
+
165
+ - **ReDoS protection** — added regex timeout and converted greedy quantifiers to non-greedy across all pattern matching.
166
+ - **File size limits** — added size caps on parsed files to prevent memory exhaustion from oversized inputs.
167
+
168
+ ## [0.10.1] - 2026-03-19
169
+
170
+ ### Changed
171
+
172
+ - Patch release for RubyGems republish (no code changes).
173
+
142
174
  ## [0.10.0] - 2026-03-19
143
175
 
144
176
  ### Added
@@ -278,6 +310,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
278
310
  - **Zeitwerk dependency** — Changed from open-ended `>= 2.6` to pessimistic `~> 2.6` per RubyGems best practices
279
311
  - **Documentation** — Updated CONTRIBUTING.md, CHANGELOG.md, and CLAUDE.md to reflect Zeitwerk autoloading, introspector presets, and `.mcp.json` auto-discovery changes
280
312
 
313
+ ## [0.5.1] - 2026-03-18
314
+
315
+ ### Fixed
316
+
317
+ - Documentation updates and animated demo GIF added to README.
318
+ - Zeitwerk autoloading fixes for edge cases.
319
+
281
320
  ## [0.5.0] - 2026-03-18
282
321
 
283
322
  ### Added
data/CLAUDE.md CHANGED
@@ -10,7 +10,7 @@ structure to AI assistants via the Model Context Protocol (MCP).
10
10
  - `lib/rails_ai_context/introspector.rb` — Orchestrates sub-introspectors
11
11
  - `lib/rails_ai_context/introspectors/` — 29 introspectors (schema, models, routes, jobs, gems, conventions, stimulus, database_stats, controllers, views, view_templates, design_tokens, turbo, i18n, config, active_storage, action_text, auth, api, tests, rake_tasks, assets, devops, action_mailbox, migrations, seeds, middleware, engines, multi_database)
12
12
  - `lib/rails_ai_context/tools/` — 13 MCP tools using the official mcp SDK
13
- - `lib/rails_ai_context/serializers/` — Output formatters (claude, claude_rules, opencode, cursor_rules, windsurf, windsurf_rules, copilot, copilot_instructions, rules, markdown, JSON)
13
+ - `lib/rails_ai_context/serializers/` — Output formatters (claude, claude_rules, opencode, opencode_rules, cursor_rules, windsurf, windsurf_rules, copilot, copilot_instructions, rules, markdown, JSON, context_file_serializer, test_command_detection)
14
14
  - `lib/rails_ai_context/resources.rb` — MCP resources (static data AI clients read directly)
15
15
  - `lib/rails_ai_context/server.rb` — MCP server configuration (stdio + HTTP transports)
16
16
  - `lib/rails_ai_context/middleware.rb` — Rack middleware for auto-mounting MCP HTTP endpoint
@@ -28,21 +28,22 @@ structure to AI assistants via the Model Context Protocol (MCP).
28
28
  2. **Zero-config** — Railtie auto-registers at boot, introspects without setup
29
29
  3. **Graceful degradation** — works without DB by parsing schema.rb as text
30
30
  4. **Read-only tools only** — all MCP tools are annotated as non-destructive
31
- 5. **Dual output** — static files (CLAUDE.md) + live MCP server (stdio/HTTP)
32
- 6. **Diff-aware** — context regeneration skips unchanged files
33
- 7. **Per-assistant serializers** — each AI tool gets tailored output format
34
- 8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
35
- 9. **Introspector presets** — `:standard` (13 core) default, `:full` (28) for power users
36
- 10. **MCP auto-discovery** — `.mcp.json` generated by install generator
37
- 11. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
38
- 12. **Per-tool split rules** — `.claude/rules/`, `.cursor/rules/`, `.windsurf/rules/`, `.github/instructions/`
39
- 13. **Section markers** — root file content wrapped in `<!-- BEGIN/END rails-ai-context -->` to preserve user content
40
- 14. **generate_root_files toggle** — when false, skip root files (CLAUDE.md, etc.), only generate split rules
31
+ 5. **Sensitive pattern blocking** — search/read tools reject `.env`, `*.key`, `*.pem` and other secret files via `sensitive_patterns`
32
+ 6. **Dual output** — static files (CLAUDE.md) + live MCP server (stdio/HTTP)
33
+ 7. **Diff-aware** — context regeneration skips unchanged files
34
+ 8. **Per-assistant serializers** — each AI tool gets tailored output format
35
+ 9. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
36
+ 10. **Introspector presets** — `:standard` (13 core) default, `:full` (28) for power users
37
+ 11. **MCP auto-discovery** — `.mcp.json` generated by install generator
38
+ 12. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
39
+ 13. **Per-tool split rules** — `.claude/rules/`, `.cursor/rules/`, `.windsurf/rules/`, `.github/instructions/`
40
+ 14. **Section markers** — root file content wrapped in `<!-- BEGIN/END rails-ai-context -->` to preserve user content
41
+ 15. **generate_root_files toggle** — when false, skip root files (CLAUDE.md, etc.), only generate split rules
41
42
 
42
43
  ## Testing
43
44
 
44
45
  ```bash
45
- bundle exec rspec # Run specs (491 examples)
46
+ bundle exec rspec # Run specs (507 examples)
46
47
  bundle exec rubocop # Lint
47
48
  ```
48
49
 
data/README.md CHANGED
@@ -302,9 +302,11 @@ end
302
302
  | `max_tool_response_chars` | `120_000` | Safety cap for MCP tool responses |
303
303
  | `excluded_models` | internal Rails models | Models to skip during introspection |
304
304
  | `excluded_paths` | `node_modules tmp log vendor .git` | Paths excluded from code search |
305
+ | `sensitive_patterns` | `.env .env.* *.key *.pem config/master.key config/credentials.yml.enc` | File patterns blocked from search and read tools |
305
306
  | `auto_mount` | `false` | Auto-mount HTTP MCP endpoint |
306
307
  | `http_path` | `"/mcp"` | HTTP endpoint path |
307
308
  | `http_port` | `6029` | HTTP server port |
309
+ | `http_bind` | `"127.0.0.1"` | HTTP server bind address |
308
310
  | `cache_ttl` | `30` | Cache TTL in seconds |
309
311
  | `live_reload` | `:auto` | `:auto`, `true`, or `false` — MCP live reload |
310
312
  | `live_reload_debounce` | `1.5` | Debounce interval in seconds |
@@ -326,6 +328,7 @@ end
326
328
  | `rails ai:context:cursor` | Generate Cursor files only |
327
329
  | `rails ai:context:windsurf` | Generate Windsurf files only |
328
330
  | `rails ai:context:copilot` | Generate Copilot files only |
331
+ | `rails ai:context:json` | Generate JSON context file only |
329
332
  | `rails ai:serve` | Start MCP server (stdio) |
330
333
  | `rails ai:serve_http` | Start MCP server (HTTP) |
331
334
  | `rails ai:doctor` | Run diagnostics and AI readiness score (0-100) |
@@ -396,7 +399,7 @@ The gem parses `db/schema.rb` as text when no database is connected. Works in CI
396
399
  ```bash
397
400
  git clone https://github.com/crisnahine/rails-ai-context.git
398
401
  cd rails-ai-context && bundle install
399
- bundle exec rspec # 491 examples
402
+ bundle exec rspec # 507 examples
400
403
  bundle exec rubocop # Lint
401
404
  ```
402
405
 
data/SECURITY.md CHANGED
@@ -4,9 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  |---------|--------------------|
7
- | 0.8.x | :white_check_mark: |
8
- | 0.7.x | :white_check_mark: |
9
- | < 0.7 | :x: |
7
+ | 0.15.x | :white_check_mark: |
8
+ | < 0.14 | :x: |
10
9
 
11
10
  ## Reporting a Vulnerability
12
11
 
@@ -25,5 +24,5 @@ If you discover a security vulnerability in rails-ai-context, please report it r
25
24
  - All MCP tools are **read-only** and never modify your application or database.
26
25
  - Code search (`rails_search_code`) uses `Open3.capture2` with array arguments to prevent shell injection.
27
26
  - File paths are validated against path traversal attacks.
28
- - Credentials and secret values are **never** exposed — only key names are introspected.
27
+ - Credentials and secret values are **never** exposed — only a `credentials_configured` boolean is reported (key names and values are never introspected).
29
28
  - The gem does not make any outbound network requests.
data/docs/GUIDE.md CHANGED
@@ -39,7 +39,7 @@ rails ai:context
39
39
  This creates:
40
40
  1. `config/initializers/rails_ai_context.rb` — configuration file
41
41
  2. `.mcp.json` — MCP auto-discovery for Claude Code and Cursor
42
- 3. 20 context files — tailored for each AI assistant
42
+ 3. 25 context files — tailored for each AI assistant
43
43
 
44
44
  ### Existing project
45
45
 
@@ -125,15 +125,17 @@ end
125
125
 
126
126
  ## Generated Files
127
127
 
128
- `rails ai:context` generates **20 files** across all AI assistants:
128
+ `rails ai:context` generates **25 files** across all AI assistants:
129
129
 
130
- ### Claude Code (4 files)
130
+ ### Claude Code (6 files)
131
131
 
132
132
  | File | Purpose | Notes |
133
133
  |------|---------|-------|
134
134
  | `CLAUDE.md` | Main context file | ≤150 lines in compact mode. Claude Code reads this automatically. |
135
135
  | `.claude/rules/rails-schema.md` | Database table listing | Auto-loaded by Claude Code alongside CLAUDE.md. |
136
136
  | `.claude/rules/rails-models.md` | Model listing with associations | Auto-loaded by Claude Code alongside CLAUDE.md. |
137
+ | `.claude/rules/rails-context.md` | Project context and conventions | Auto-loaded by Claude Code alongside CLAUDE.md. |
138
+ | `.claude/rules/rails-ui-patterns.md` | UI patterns and design tokens | Auto-loaded by Claude Code alongside CLAUDE.md. |
137
139
  | `.claude/rules/rails-mcp-tools.md` | Full MCP tool reference | Parameters, detail levels, pagination, workflow guide. |
138
140
 
139
141
  ### OpenCode (3 files)
@@ -144,13 +146,14 @@ end
144
146
  | `app/models/AGENTS.md` | Model reference | Auto-loaded by OpenCode when reading files in `app/models/`. |
145
147
  | `app/controllers/AGENTS.md` | Controller reference | Auto-loaded by OpenCode when reading files in `app/controllers/`. |
146
148
 
147
- ### Cursor (5 files)
149
+ ### Cursor (6 files)
148
150
 
149
151
  | File | Purpose | Notes |
150
152
  |------|---------|-------|
151
153
  | `.cursor/rules/rails-project.mdc` | Project overview | `alwaysApply: true` — loaded in every conversation. |
152
154
  | `.cursor/rules/rails-models.mdc` | Model reference | `globs: app/models/**/*.rb` — auto-attaches when editing models. |
153
155
  | `.cursor/rules/rails-controllers.mdc` | Controller reference | `globs: app/controllers/**/*.rb` — auto-attaches when editing controllers. |
156
+ | `.cursor/rules/rails-ui-patterns.mdc` | UI patterns and design tokens | `alwaysApply: true` — loaded in every conversation. |
154
157
  | `.cursor/rules/rails-mcp-tools.mdc` | MCP tool reference | `alwaysApply: true` — always available. |
155
158
 
156
159
  ### Windsurf (3 files)
@@ -161,13 +164,15 @@ end
161
164
  | `.windsurf/rules/rails-context.md` | Project overview | New Windsurf rules format. |
162
165
  | `.windsurf/rules/rails-mcp-tools.md` | MCP tool reference | Compact — respects 6K per-file limit. |
163
166
 
164
- ### GitHub Copilot (4 files)
167
+ ### GitHub Copilot (6 files)
165
168
 
166
169
  | File | Purpose | Notes |
167
170
  |------|---------|-------|
168
171
  | `.github/copilot-instructions.md` | Repo-wide instructions | ≤500 lines in compact mode. |
169
172
  | `.github/instructions/rails-models.instructions.md` | Model context | `applyTo: app/models/**/*.rb` — loaded when editing models. |
170
173
  | `.github/instructions/rails-controllers.instructions.md` | Controller context | `applyTo: app/controllers/**/*.rb` — loaded when editing controllers. |
174
+ | `.github/instructions/rails-context.instructions.md` | Project context and conventions | `applyTo: **/*` — loaded everywhere. |
175
+ | `.github/instructions/rails-ui-patterns.instructions.md` | UI patterns and design tokens | `applyTo: **/*` — loaded everywhere. |
171
176
  | `.github/instructions/rails-mcp-tools.instructions.md` | MCP tool reference | `applyTo: **/*` — loaded everywhere. |
172
177
 
173
178
  ### Generic (1 file)
@@ -188,7 +193,7 @@ Commit **all files except `.ai-context.json`** (which is gitignored). This gives
188
193
 
189
194
  | Command | Mode | Format | Description |
190
195
  |---------|------|--------|-------------|
191
- | `rails ai:context` | compact | all | Generate all 20 context files |
196
+ | `rails ai:context` | compact | all | Generate all 25 context files |
192
197
  | `rails ai:context:full` | full | all | Generate all files in full mode |
193
198
  | `rails ai:context:claude` | compact | Claude | CLAUDE.md + .claude/rules/ |
194
199
  | `rails ai:context:opencode` | compact | OpenCode | AGENTS.md + per-directory AGENTS.md |
@@ -688,6 +693,7 @@ These run by default. Fast and cover core Rails structure.
688
693
  | `controllers` | Actions, filters (before/after/around with only/except), strong params methods, parent class, API controller detection, concerns. |
689
694
  | `tests` | Test framework (rspec/minitest), factories/fixtures with locations and counts, system tests, CI config files, coverage tool, test helpers, VCR cassettes. |
690
695
  | `migrations` | Total count, schema version, pending migrations, recent migration history with detected actions (create_table, add_column, etc.), migration statistics. |
696
+ | `config` | Cache store, session store, timezone, middleware stack, initializers, credentials keys, CurrentAttributes classes. |
691
697
  | `stimulus` | Stimulus controllers with targets, values (with types), actions, outlets, classes. Extracted from JS/TS files. |
692
698
  | `view_templates` | View file contents, partial references, Stimulus data attributes, UI pattern extraction, model field usage in partials. |
693
699
  | `design_tokens` | Auto-detects CSS framework (Tailwind v3/v4, Bootstrap, Sass, plain CSS) and extracts design tokens from config files and built CSS. |
@@ -701,7 +707,6 @@ Includes all standard introspectors plus:
701
707
  | `views` | Layouts, templates grouped by controller, partials (per-controller and shared), helpers with methods, template engines (erb, haml, slim), view components. |
702
708
  | `turbo` | Turbo Frames (IDs and files), Turbo Stream templates, model broadcasts (`broadcasts_to`, `broadcasts`). |
703
709
  | `i18n` | Default locale, available locales, locale files with key counts, backend class, parse errors. |
704
- | `config` | Cache store, session store, timezone, middleware stack, initializers, credentials keys, CurrentAttributes classes. |
705
710
  | `active_storage` | Attachments (has_one_attached, has_many_attached per model), storage services, direct upload config. |
706
711
  | `action_text` | Rich text fields (has_rich_text per model), Action Text installation status. |
707
712
  | `auth` | Devise models with modules, Rails 8 built-in auth, has_secure_password, Pundit policies, CanCanCan, CORS config, CSP config. |
@@ -41,8 +41,8 @@ module RailsAiContext
41
41
 
42
42
  RailsAiContext.configure do |config|
43
43
  # Introspector preset:
44
- # :standard — 8 core introspectors (schema, models, routes, jobs, gems, conventions, controllers, tests)
45
- # :full — all 21 introspectors (adds views, turbo, auth, API, config, assets, devops, etc.)
44
+ # :standard — 13 core introspectors (schema, models, routes, jobs, gems, conventions, controllers, tests, migrations, stimulus, view_templates, design_tokens, config)
45
+ # :full — all 28 introspectors (adds views, turbo, auth, API, assets, devops, etc.)
46
46
  # config.preset = :standard
47
47
 
48
48
  # Or cherry-pick individual introspectors:
@@ -186,7 +186,14 @@ module RailsAiContext
186
186
  elsif (match = line.match(/add_index\s+"(\w+)",\s+(.+)/))
187
187
  table_name = match[1]
188
188
  rest = match[2]
189
- cols = rest.scan(/(?::|\")(\w+)/).flatten
189
+ # Extract columns only from the [...] array portion, not option keys
190
+ array_match = rest.match(/\[([^\]]+)\]/)
191
+ cols = if array_match
192
+ inside = array_match[1]
193
+ inside.include?('"') ? inside.scan(/"(\w+)"/).flatten : inside.scan(/\b(\w+)\b/).flatten
194
+ else
195
+ rest.match(/(?::|")(\w+)/)&.[](1)&.then { |c| [ c ] } || []
196
+ end
190
197
  unique = rest.include?("unique: true")
191
198
  idx_name = rest.match(/name:\s*"(\w+)"/)&.send(:[], 1)
192
199
  tables[table_name]&.dig(:indexes)&.push({ name: idx_name, columns: cols, unique: unique }.compact) if cols.any?
@@ -6,6 +6,8 @@ module RailsAiContext
6
6
  # In :compact mode (default), produces ≤150 lines with MCP tool references.
7
7
  # In :full mode, delegates to MarkdownSerializer with behavioral rules.
8
8
  class ClaudeSerializer
9
+ include TestCommandDetection
10
+
9
11
  attr_reader :context
10
12
 
11
13
  def initialize(context)
@@ -272,16 +274,6 @@ module RailsAiContext
272
274
  ]
273
275
  end
274
276
 
275
- def detect_test_command
276
- tests = context[:tests]
277
- framework = tests.is_a?(Hash) ? tests[:framework] : nil
278
- case framework
279
- when "rspec" then "bundle exec rspec"
280
- when "minitest" then "rails test"
281
- else "rails test"
282
- end
283
- end
284
-
285
277
  def render_footer
286
278
  [
287
279
  "## Rules",
@@ -299,17 +291,9 @@ module RailsAiContext
299
291
 
300
292
  # Internal: full-mode Claude serializer (wraps MarkdownSerializer with behavioral rules)
301
293
  class FullClaudeSerializer < MarkdownSerializer
302
- private
294
+ include TestCommandDetection
303
295
 
304
- def detect_test_command
305
- tests = context[:tests]
306
- framework = tests.is_a?(Hash) ? tests[:framework] : nil
307
- case framework
308
- when "rspec" then "bundle exec rspec"
309
- when "minitest" then "rails test"
310
- else "rails test"
311
- end
312
- end
296
+ private
313
297
 
314
298
  def header
315
299
  <<~MD
@@ -6,6 +6,8 @@ module RailsAiContext
6
6
  # In :compact mode (default), produces ≤500 lines with MCP tool references.
7
7
  # In :full mode, delegates to MarkdownSerializer with Copilot header.
8
8
  class CopilotSerializer
9
+ include TestCommandDetection
10
+
9
11
  attr_reader :context
10
12
 
11
13
  def initialize(context)
@@ -142,16 +144,6 @@ module RailsAiContext
142
144
 
143
145
  lines.join("\n")
144
146
  end
145
-
146
- def detect_test_command
147
- tests = context[:tests]
148
- framework = tests.is_a?(Hash) ? tests[:framework] : nil
149
- case framework
150
- when "rspec" then "bundle exec rspec"
151
- when "minitest" then "rails test"
152
- else "rails test"
153
- end
154
- end
155
147
  end
156
148
 
157
149
  # Internal: full-mode Copilot serializer (wraps MarkdownSerializer)
@@ -5,6 +5,8 @@ module RailsAiContext
5
5
  # Generates AI-friendly markdown context files from introspection data.
6
6
  # Outputs: CLAUDE.md (for Claude Code), .windsurfrules, etc.
7
7
  class MarkdownSerializer # rubocop:disable Metrics/ClassLength
8
+ include TestCommandDetection
9
+
8
10
  attr_reader :context
9
11
 
10
12
  def initialize(context)
@@ -503,16 +505,6 @@ module RailsAiContext
503
505
  _This context file is auto-generated. Run `rails ai:context` to regenerate._
504
506
  MD
505
507
  end
506
-
507
- def detect_test_command
508
- tests = context[:tests]
509
- framework = tests.is_a?(Hash) ? tests[:framework] : nil
510
- case framework
511
- when "rspec" then "bundle exec rspec"
512
- when "minitest" then "rails test"
513
- else "rails test"
514
- end
515
- end
516
508
  end
517
509
  end
518
510
  end
@@ -6,6 +6,8 @@ module RailsAiContext
6
6
  # In :compact mode (default), produces ≤150 lines with MCP tool references.
7
7
  # In :full mode, delegates to MarkdownSerializer with OpenCode header.
8
8
  class OpencodeSerializer
9
+ include TestCommandDetection
10
+
9
11
  attr_reader :context
10
12
 
11
13
  def initialize(context)
@@ -227,16 +229,6 @@ module RailsAiContext
227
229
  ]
228
230
  end
229
231
 
230
- def detect_test_command
231
- tests = context[:tests]
232
- framework = tests.is_a?(Hash) ? tests[:framework] : nil
233
- case framework
234
- when "rspec" then "bundle exec rspec"
235
- when "minitest" then "rails test"
236
- else "rails test"
237
- end
238
- end
239
-
240
232
  def render_footer
241
233
  [
242
234
  "## Rules",
@@ -251,17 +243,9 @@ module RailsAiContext
251
243
 
252
244
  # Internal: full-mode OpenCode serializer (wraps MarkdownSerializer)
253
245
  class FullOpencodeSerializer < MarkdownSerializer
254
- private
246
+ include TestCommandDetection
255
247
 
256
- def detect_test_command
257
- tests = context[:tests]
258
- framework = tests.is_a?(Hash) ? tests[:framework] : nil
259
- case framework
260
- when "rspec" then "bundle exec rspec"
261
- when "minitest" then "rails test"
262
- else "rails test"
263
- end
264
- end
248
+ private
265
249
 
266
250
  def header
267
251
  <<~MD
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsAiContext
4
+ module Serializers
5
+ # Shared helper for detecting the correct test command from introspection data.
6
+ # Include in any serializer that needs to output a test command.
7
+ module TestCommandDetection
8
+ private
9
+
10
+ def detect_test_command
11
+ tests = context[:tests]
12
+ framework = tests.is_a?(Hash) ? tests[:framework] : nil
13
+ case framework
14
+ when "rspec" then "bundle exec rspec"
15
+ when "minitest" then "rails test"
16
+ else "rails test"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -5,6 +5,8 @@ module RailsAiContext
5
5
  # Generates .windsurfrules within Windsurf's hard 6,000 character limit.
6
6
  # Always produces compact output regardless of context_mode.
7
7
  class WindsurfSerializer
8
+ include TestCommandDetection
9
+
8
10
  MAX_CHARS = 5_800 # Leave buffer below 6K limit
9
11
 
10
12
  attr_reader :context
@@ -169,7 +171,7 @@ module RailsAiContext
169
171
  lines << "# Rules"
170
172
  lines << "- Follow existing patterns"
171
173
  lines << "- Check schema via MCP before writing migrations"
172
- lines << "- Run tests after changes"
174
+ lines << "- Run `#{detect_test_command}` after changes"
173
175
  lines << "- After editing: use rails_validate, do NOT re-read files to verify"
174
176
  lines << "- Stimulus controllers auto-register — no manual import needed"
175
177
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsAiContext
4
- VERSION = "0.15.2"
4
+ VERSION = "0.15.3"
5
5
  end
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.14.0",
10
+ "version": "0.15.2",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "mcpb",
14
- "identifier": "https://github.com/crisnahine/rails-ai-context/releases/download/v0.14.0/rails-ai-context-mcp.mcpb",
14
+ "identifier": "https://github.com/crisnahine/rails-ai-context/releases/download/v0.15.2/rails-ai-context-mcp.mcpb",
15
15
  "fileSha256": "dd711a0ad6c4de943ae4da94eaf59a6dc9494b9d57f726e24649ed4e2f156990",
16
16
  "transport": {
17
17
  "type": "stdio"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-ai-context
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.2
4
+ version: 0.15.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - crisnahine
@@ -239,6 +239,7 @@ files:
239
239
  - lib/rails_ai_context/serializers/opencode_rules_serializer.rb
240
240
  - lib/rails_ai_context/serializers/opencode_serializer.rb
241
241
  - lib/rails_ai_context/serializers/rules_serializer.rb
242
+ - lib/rails_ai_context/serializers/test_command_detection.rb
242
243
  - lib/rails_ai_context/serializers/windsurf_rules_serializer.rb
243
244
  - lib/rails_ai_context/serializers/windsurf_serializer.rb
244
245
  - lib/rails_ai_context/server.rb