rails-ai-context 5.32.0 → 5.32.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/CHANGELOG.md +138 -0
- data/CONTEXT.md +10 -8
- data/CONTRIBUTING.md +2 -2
- data/README.md +14 -11
- data/SECURITY.md +4 -4
- data/docs/ARCHITECTURE.md +11 -10
- data/docs/CLI.md +33 -7
- data/docs/COMPATIBILITY.md +69 -32
- data/docs/CONFIGURATION.md +10 -8
- data/docs/CUSTOM_TOOLS.md +8 -8
- data/docs/FAQ.md +6 -5
- data/docs/GUIDE.md +154 -80
- data/docs/INTROSPECTORS.md +25 -17
- data/docs/QUICKSTART.md +14 -3
- data/docs/RECIPES.md +50 -40
- data/docs/SECURITY.md +23 -13
- data/docs/SETUP.md +23 -26
- data/docs/STANDALONE.md +7 -3
- data/docs/TOOLS.md +79 -45
- data/docs/TROUBLESHOOTING.md +12 -11
- data/exe/rails-ai-context +8 -4
- data/lib/generators/rails_ai_context/install/install_generator.rb +1 -1
- data/lib/rails_ai_context/configuration.rb +2 -2
- data/lib/rails_ai_context/database_yml.rb +52 -2
- data/lib/rails_ai_context/install/ai_tool.rb +11 -2
- data/lib/rails_ai_context/install/cleanup.rb +69 -23
- data/lib/rails_ai_context/install/program.rb +4 -1
- data/lib/rails_ai_context/install/selection_record.rb +20 -2
- data/lib/rails_ai_context/introspectors/listeners/schema_dsl_listener.rb +30 -9
- data/lib/rails_ai_context/introspectors/model_introspector.rb +1 -1
- data/lib/rails_ai_context/introspectors/pg_naming.rb +133 -0
- data/lib/rails_ai_context/introspectors/schema_conventions.rb +0 -6
- data/lib/rails_ai_context/introspectors/schema_introspector.rb +188 -51
- data/lib/rails_ai_context/introspectors/schema_reader.rb +98 -12
- data/lib/rails_ai_context/introspectors/structure_sql_reader.rb +56 -33
- data/lib/rails_ai_context/payload.rb +25 -2
- data/lib/rails_ai_context/serializers/opencode_rules_serializer.rb +2 -2
- data/lib/rails_ai_context/server.rb +2 -2
- data/lib/rails_ai_context/tasks/rails_ai_context.rake +12 -4
- data/lib/rails_ai_context/test_helper.rb +2 -0
- data/lib/rails_ai_context/tools/base_tool.rb +3 -1
- data/lib/rails_ai_context/tools/dependency_graph.rb +2 -2
- data/lib/rails_ai_context/tools/get_concern.rb +1 -1
- data/lib/rails_ai_context/tools/get_env.rb +1 -1
- data/lib/rails_ai_context/tools/get_gems.rb +2 -2
- data/lib/rails_ai_context/tools/get_model_details.rb +2 -0
- data/lib/rails_ai_context/tools/get_schema.rb +17 -14
- data/lib/rails_ai_context/tools/query.rb +107 -39
- data/lib/rails_ai_context/tools/search_code.rb +20 -16
- data/lib/rails_ai_context/version.rb +1 -1
- data/server.json +1 -1
- metadata +2 -1
data/docs/STANDALONE.md
CHANGED
|
@@ -24,14 +24,18 @@ rails-ai-context init
|
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Interactive setup asks:
|
|
27
|
-
1. Which AI tools? (Claude, Cursor, Copilot, OpenCode, Codex, or all)
|
|
28
|
-
2. MCP
|
|
27
|
+
1. Which AI tools? (Claude, Cursor, Copilot, OpenCode, Codex, or all; an empty answer selects all five)
|
|
28
|
+
2. What should it write? (MCP config + context files, context files only for CLI mode, or MCP config only)
|
|
29
|
+
|
|
30
|
+
On a re-run that drops a tool, it also asks whether to remove that tool's files. Unlike the install generator, `init` has no pre-commit hook prompt and no `--defaults` flag. The steps are listed in [What the install generator does](GUIDE.md#what-the-install-generator-does).
|
|
29
31
|
|
|
30
32
|
Creates:
|
|
31
33
|
- `.rails-ai-context.yml` - YAML configuration
|
|
32
34
|
- MCP config files for selected AI tools
|
|
33
35
|
- Context files for selected AI tools
|
|
34
36
|
|
|
37
|
+
It does not create `config/initializers/rails_ai_context.rb`.
|
|
38
|
+
|
|
35
39
|
## Usage
|
|
36
40
|
|
|
37
41
|
```bash
|
|
@@ -141,7 +145,7 @@ bundle remove rails-ai-context
|
|
|
141
145
|
rails-ai-context init
|
|
142
146
|
```
|
|
143
147
|
|
|
144
|
-
The MCP config files are updated automatically. Both modes generate
|
|
148
|
+
The MCP config files are updated automatically. Both modes generate the same set of context files and provide the same 45 tools. The commands named inside the files follow the install mode.
|
|
145
149
|
|
|
146
150
|
Both also take `--mcp-only`, which writes the MCP config and no context files
|
|
147
151
|
at all. See [CONFIGURATION.md](CONFIGURATION.md#mcp-only).
|
data/docs/TOOLS.md
CHANGED
|
@@ -43,7 +43,7 @@ Tool name resolution is flexible - all of these work:
|
|
|
43
43
|
| `get_schema` | `rails_get_schema` |
|
|
44
44
|
| `rails_get_schema` | `rails_get_schema` |
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Most lookup tools accept a **`detail`** parameter: `summary` (compact), `standard` (default), or `full` (everything). Start with summary, drill down as needed. Composite tools (`rails_get_context`, `rails_analyze_feature`) do not accept `detail`.
|
|
47
47
|
|
|
48
48
|
<p align="right"><a href="#table-of-contents">↑ back to top</a></p>
|
|
49
49
|
|
|
@@ -87,7 +87,7 @@ Search your codebase with regex, ripgrep acceleration, and sensitive file blocki
|
|
|
87
87
|
|
|
88
88
|
The header counts matches, not emitted lines, so below the cap it does not move with `context_lines`. When the search hits `max_search_results` (a cap on emitted lines) the header says `first N lines scanned` and marks the count `N+`: it is then the matches among the lines that were scanned, a floor rather than the total, so it falls as `context_lines` grows. `offset` and `limit` count lines, so a search with context returns more lines than matches. A limit smaller than one match's context block would hold only context, so the page starts at the next match instead and says so.
|
|
89
89
|
|
|
90
|
-
> **Trace mode** returns definition + source code + every caller grouped by type + tests - replaces 4-5 sequential file reads.
|
|
90
|
+
> **Trace mode** returns definition + source code + every caller grouped by file and labelled by type + tests - replaces 4-5 sequential file reads.
|
|
91
91
|
|
|
92
92
|
Without ripgrep on the PATH, the Ruby fallback returns the rows ripgrep would, context lines and the line cap included, from the files ripgrep would search: no hidden files, no symlinks followed, no binary files (a NUL byte in the first 64 KiB), and ignore files read with ripgrep's precedence, where the file type decides before depth: any `.rgignore`, then any `.ignore`, then any `.gitignore`, then `.git/info/exclude`, then the global excludes file, the deepest file first within a type. `.ignore` and `.rgignore` apply everywhere, including the directories above the app; the git files apply only inside a repository and only as far up as the nearest `.git` (a file for a worktree or submodule), whose `info/exclude` is the only one read. Patterns match case-sensitively.
|
|
93
93
|
|
|
@@ -100,8 +100,8 @@ Method-aware code extraction with surrounding class context. Every line returned
|
|
|
100
100
|
| Parameter | Type | Default | Description |
|
|
101
101
|
|:----------|:-----|:--------|:------------|
|
|
102
102
|
| `file` | string | *required* | File path relative to Rails root |
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
103
|
+
| `near` | string | *required* | What to find in the file: a method name, keyword or string (e.g. `def index`, `validates`, `STATUSES`) |
|
|
104
|
+
| `context_lines` | integer | `5` | Lines of context above and below the match |
|
|
105
105
|
|
|
106
106
|
<p align="right"><a href="#table-of-contents">↑ back to top</a></p>
|
|
107
107
|
|
|
@@ -116,7 +116,6 @@ Full-stack feature analysis: models + controllers + routes + services + admin re
|
|
|
116
116
|
| Parameter | Type | Default | Description |
|
|
117
117
|
|:----------|:-----|:--------|:------------|
|
|
118
118
|
| `feature` | string | *required* | Feature name (e.g., `billing`, `auth`, `subscription`) |
|
|
119
|
-
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
120
119
|
|
|
121
120
|
### `rails_get_context`
|
|
122
121
|
|
|
@@ -124,9 +123,11 @@ Composite context: schema + model + controller + routes + views for a resource.
|
|
|
124
123
|
|
|
125
124
|
| Parameter | Type | Default | Description |
|
|
126
125
|
|:----------|:-----|:--------|:------------|
|
|
127
|
-
| `
|
|
128
|
-
| `action` | string | - | Specific controller action |
|
|
129
|
-
| `
|
|
126
|
+
| `controller` | string | - | Controller name (e.g., `PostsController`) |
|
|
127
|
+
| `action` | string | - | Specific controller action; requires `controller` |
|
|
128
|
+
| `model` | string | - | Model name (e.g., `Post`) |
|
|
129
|
+
| `feature` | string | - | Feature keyword (e.g., `post`) |
|
|
130
|
+
| `include` | array | - | Extra context to add: `stimulus`, `turbo`, `services`, `jobs`, `conventions`, `helpers`, `env`, `callbacks` |
|
|
130
131
|
|
|
131
132
|
### `rails_onboard`
|
|
132
133
|
|
|
@@ -164,15 +165,20 @@ composite unique index; `[in index after x]` marks a column that only trails
|
|
|
164
165
|
|:----------|:-----|:--------|:------------|
|
|
165
166
|
| `table` | string | - | Specific table (omit for overview) |
|
|
166
167
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
168
|
+
| `limit` | integer | auto | Max tables when listing: 50 for `summary`, 25 for `standard`, 10 for `full` |
|
|
169
|
+
| `offset` | integer | `0` | Skip this many tables |
|
|
170
|
+
| `format` | enum | `markdown` | `markdown`, `json` |
|
|
167
171
|
|
|
168
172
|
### `rails_get_model_details`
|
|
169
173
|
|
|
170
|
-
AST-parsed model internals.
|
|
174
|
+
AST-parsed model internals. The model heading and each scope carry a confidence tag: `[VERIFIED]` or `[INFERRED]` on a booted app, `[STATIC]` without a boot. The method list says how many of the model's methods it is showing.
|
|
171
175
|
|
|
172
176
|
| Parameter | Type | Default | Description |
|
|
173
177
|
|:----------|:-----|:--------|:------------|
|
|
174
|
-
| `model` | string | - | Model name (e.g., `User`, `Post`) |
|
|
178
|
+
| `model` | string | - | Model name (e.g., `User`, `Post`). Omit to list all models |
|
|
175
179
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
180
|
+
| `limit` | integer | `50` | Max models when listing |
|
|
181
|
+
| `offset` | integer | `0` | Skip this many models |
|
|
176
182
|
|
|
177
183
|
Returns: associations, validations, scopes, enums, callbacks, macros, methods, concerns.
|
|
178
184
|
What the included concerns declare is merged in, so the answer does not stop
|
|
@@ -181,7 +187,8 @@ Concerns as `[UNAVAILABLE]` rather than dropped.
|
|
|
181
187
|
|
|
182
188
|
### `rails_get_callbacks`
|
|
183
189
|
|
|
184
|
-
Callbacks grouped by type, in Rails event order, with source code
|
|
190
|
+
Callbacks grouped by type, in Rails event order, with source code at
|
|
191
|
+
`detail:"full"`. The list
|
|
185
192
|
covers concern-declared callbacks too, with the body read from the concern
|
|
186
193
|
file, and the "From Concerns" section says which concern declared each one.
|
|
187
194
|
Within one type the order is the order Rails runs them: base classes first, a
|
|
@@ -198,12 +205,12 @@ not read, so the list can miss it or show the definition it replaces.
|
|
|
198
205
|
|
|
199
206
|
| Parameter | Type | Default | Description |
|
|
200
207
|
|:----------|:-----|:--------|:------------|
|
|
201
|
-
| `model` | string |
|
|
208
|
+
| `model` | string | - | Model name. Omit to list every model with its callbacks |
|
|
202
209
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
203
210
|
|
|
204
211
|
### `rails_get_concern`
|
|
205
212
|
|
|
206
|
-
Concern methods, source code
|
|
213
|
+
Concern methods, their source code at `detail:"full"`, and which models include it. A class under
|
|
207
214
|
`app/models/concerns` that subclasses `ActiveModel::Validator` is listed as a
|
|
208
215
|
validator rather than a concern, and its users are the models that name it in
|
|
209
216
|
`validates_with`. The rule reads the class the file is named for, so a concern
|
|
@@ -230,8 +237,10 @@ Controller actions with inherited filters, render map, strong params. Includes s
|
|
|
230
237
|
| Parameter | Type | Default | Description |
|
|
231
238
|
|:----------|:-----|:--------|:------------|
|
|
232
239
|
| `controller` | string | - | Controller name (e.g., `UsersController`) |
|
|
233
|
-
| `action` | string | - | Specific action |
|
|
240
|
+
| `action` | string | - | Specific action; requires `controller` |
|
|
234
241
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
242
|
+
| `limit` | integer | `50` | Max controllers when listing |
|
|
243
|
+
| `offset` | integer | `0` | Skip this many controllers |
|
|
235
244
|
|
|
236
245
|
### `rails_get_routes`
|
|
237
246
|
|
|
@@ -248,6 +257,9 @@ the summary counts them.
|
|
|
248
257
|
|:----------|:-----|:--------|:------------|
|
|
249
258
|
| `controller` | string | - | Filter by controller |
|
|
250
259
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
260
|
+
| `limit` | integer | auto | Max routes to return; the default depends on `detail` |
|
|
261
|
+
| `offset` | integer | `0` | Skip this many routes |
|
|
262
|
+
| `app_only` | boolean | `true` | Leave out internal Rails routes (Active Storage, Action Mailbox, Conductor) |
|
|
251
263
|
|
|
252
264
|
<p align="right"><a href="#table-of-contents">↑ back to top</a></p>
|
|
253
265
|
|
|
@@ -262,7 +274,7 @@ View templates with instance variables, Turbo frames, Stimulus controllers, part
|
|
|
262
274
|
| Parameter | Type | Default | Description |
|
|
263
275
|
|:----------|:-----|:--------|:------------|
|
|
264
276
|
| `controller` | string | - | Controller name |
|
|
265
|
-
| `
|
|
277
|
+
| `path` | string | - | Specific view path relative to `app/views` (e.g., `posts/index.html.erb`); returns its content |
|
|
266
278
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
267
279
|
|
|
268
280
|
### `rails_get_stimulus`
|
|
@@ -287,6 +299,8 @@ two or more confirmed neighbours that all drop the directory's segment.
|
|
|
287
299
|
|:----------|:-----|:--------|:------------|
|
|
288
300
|
| `controller` | string | - | Stimulus controller name |
|
|
289
301
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
302
|
+
| `limit` | integer | `50` | Max controllers when listing |
|
|
303
|
+
| `offset` | integer | `0` | Skip this many controllers |
|
|
290
304
|
|
|
291
305
|
### `rails_get_partial_interface`
|
|
292
306
|
|
|
@@ -304,6 +318,8 @@ Turbo Stream broadcast-to-subscription wiring with mismatch warnings.
|
|
|
304
318
|
| Parameter | Type | Default | Description |
|
|
305
319
|
|:----------|:-----|:--------|:------------|
|
|
306
320
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
321
|
+
| `stream` | string | - | Filter by stream or channel name (e.g., `notifications`) |
|
|
322
|
+
| `controller` | string | - | Filter by controller name (e.g., `messages`) |
|
|
307
323
|
|
|
308
324
|
### `rails_get_frontend_stack`
|
|
309
325
|
|
|
@@ -335,8 +351,10 @@ Test scaffolding that matches your project's patterns (fixtures vs factories, RS
|
|
|
335
351
|
|
|
336
352
|
| Parameter | Type | Default | Description |
|
|
337
353
|
|:----------|:-----|:--------|:------------|
|
|
338
|
-
| `
|
|
339
|
-
| `
|
|
354
|
+
| `model` | string | - | Model to generate a model test for (e.g., `User`) |
|
|
355
|
+
| `controller` | string | - | Controller to generate a request test for (e.g., `PostsController`) |
|
|
356
|
+
| `file` | string | - | File to generate tests for, relative to Rails root; the type is detected |
|
|
357
|
+
| `type` | enum | `unit` | `unit`, `request`, `system` |
|
|
340
358
|
|
|
341
359
|
### `rails_validate`
|
|
342
360
|
|
|
@@ -353,11 +371,15 @@ Brakeman static analysis: SQL injection, XSS, mass assignment, command injection
|
|
|
353
371
|
|
|
354
372
|
| Parameter | Type | Default | Description |
|
|
355
373
|
|:----------|:-----|:--------|:------------|
|
|
374
|
+
| `files` | array | - | File paths to filter results to (omit to scan the whole app) |
|
|
375
|
+
| `confidence` | enum | `weak` | Minimum confidence: `high`, `medium`, `weak` (`weak` shows every warning) |
|
|
376
|
+
| `checks` | array | - | Run only these Brakeman checks, by class name (e.g., `CheckSQL`) |
|
|
356
377
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
357
378
|
|
|
358
|
-
> Requires the `brakeman` gem. When
|
|
359
|
-
>
|
|
360
|
-
>
|
|
379
|
+
> Requires the `brakeman` gem. When the app's bundle does not carry it but the
|
|
380
|
+
> machine has it, the scan runs brakeman as its own process from outside the
|
|
381
|
+
> bundle and says so. When no scan can run, the answer says which case it is:
|
|
382
|
+
> brakeman is nowhere on the machine, or it is installed and produced no report.
|
|
361
383
|
|
|
362
384
|
### `rails_performance_check`
|
|
363
385
|
|
|
@@ -365,6 +387,8 @@ N+1 query risks, missing indexes, missing counter_cache, eager load candidates.
|
|
|
365
387
|
|
|
366
388
|
| Parameter | Type | Default | Description |
|
|
367
389
|
|:----------|:-----|:--------|:------------|
|
|
390
|
+
| `model` | string | - | Filter results to one model |
|
|
391
|
+
| `category` | enum | `all` | `n_plus_one`, `counter_cache`, `indexes`, `model_all`, `eager_load`, `all` |
|
|
368
392
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
369
393
|
|
|
370
394
|
<p align="right"><a href="#table-of-contents">↑ back to top</a></p>
|
|
@@ -385,17 +409,13 @@ API layer: api_only mode, serialization strategy (Jbuilder, serializers), GraphQ
|
|
|
385
409
|
|
|
386
410
|
Auth checks, flash messages, create action template, test patterns, and the admin resources ActiveAdmin, Administrate, Avo, Madmin and Trestle register (with ActiveAdmin's permitted params).
|
|
387
411
|
|
|
388
|
-
|
|
389
|
-
|:----------|:-----|:--------|:------------|
|
|
390
|
-
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
412
|
+
*No parameters.*
|
|
391
413
|
|
|
392
414
|
### `rails_get_config`
|
|
393
415
|
|
|
394
416
|
Database config, auth framework, assets, cache, queue, Action Cable. The `use` and `map` calls in `config.ru` are listed apart from the stack, since they run before Rails.
|
|
395
417
|
|
|
396
|
-
|
|
397
|
-
|:----------|:-----|:--------|:------------|
|
|
398
|
-
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
418
|
+
*No parameters.*
|
|
399
419
|
|
|
400
420
|
### `rails_get_gems`
|
|
401
421
|
|
|
@@ -405,11 +425,13 @@ found under a load-order prefix too (`config/initializers/3_omniauth.rb`).
|
|
|
405
425
|
|
|
406
426
|
| Parameter | Type | Default | Description |
|
|
407
427
|
|:----------|:-----|:--------|:------------|
|
|
408
|
-
| `
|
|
428
|
+
| `category` | enum | `all` | `auth`, `jobs`, `frontend`, `api`, `database`, `files`, `testing`, `deploy`, `monitoring`, `admin`, `pagination`, `search`, `forms`, `server`, `notifications`, `validation`, `utilities`, `services`, `payments`, `all` |
|
|
429
|
+
| `offset` | integer | `0` | Skip this many gems |
|
|
430
|
+
| `limit` | integer | `50` | Max gems to return |
|
|
409
431
|
|
|
410
432
|
### `rails_get_env`
|
|
411
433
|
|
|
412
|
-
Environment variables + credentials keys (values are never exposed). Scans `.rb`, `.rake`, ERB views and config YAML under `app`, `config` and `lib`, plus `config.ru`, `db/seeds.rb`, `db/seeds/` and the Ruby scripts in `bin/`;
|
|
434
|
+
Environment variables + credentials keys (values are never exposed). Scans `.rb`, `.rake`, ERB views and config YAML under `app`, `config` and `lib`, plus `config.ru`, `db/seeds.rb`, `db/seeds/` and the Ruby scripts in `bin/`; config YAML matching `sensitive_patterns` (`config/database.yml`) is read only for the ENV names in its ERB tags, credentials and keys are never read, and the answer says so. The env Kamal's `config/deploy.yml` gives the app container is listed too: secret names only, and clear values, except one holding a URL or a key-like token, or under a secret-named variable, which shows as hidden, and one an ERB tag sets, which says so. So are the setting keys in the config gem's `config/settings.yml` and `config/settings/<env>.yml` when the bundle has the config gem, and the attributes of each `Anyway::Config` class in `config/configs` or `app/configs` with the env name it reads (`PAYMENT_API_KEY`), never their values. A variable whose call sites pass different defaults is labelled as such rather than with one site's default; `detail:"full"` names each site's. A default is redacted by the rule a source literal gets: a credential format under any name, a URL's password, and under a secret-named variable a value that is not clearly something else, so an address, URL or hostname default prints as written.
|
|
413
435
|
|
|
414
436
|
| Parameter | Type | Default | Description |
|
|
415
437
|
|:----------|:-----|:--------|:------------|
|
|
@@ -417,11 +439,14 @@ Environment variables + credentials keys (values are never exposed). Scans `.rb`
|
|
|
417
439
|
|
|
418
440
|
### `rails_get_helper_methods`
|
|
419
441
|
|
|
420
|
-
Application and framework helpers with view cross-references
|
|
442
|
+
Application and framework helpers, with view cross-references at `detail:"full"`.
|
|
421
443
|
|
|
422
444
|
| Parameter | Type | Default | Description |
|
|
423
445
|
|:----------|:-----|:--------|:------------|
|
|
446
|
+
| `helper` | string | - | Helper module name (e.g., `ApplicationHelper`). Omit to list all helpers |
|
|
424
447
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
448
|
+
| `offset` | integer | `0` | Skip this many helpers |
|
|
449
|
+
| `limit` | integer | `50` | Max helpers to return |
|
|
425
450
|
|
|
426
451
|
### `rails_get_service_pattern`
|
|
427
452
|
|
|
@@ -438,7 +463,7 @@ own file ceiling left the list partial. A module under
|
|
|
438
463
|
|
|
439
464
|
| Parameter | Type | Default | Description |
|
|
440
465
|
|:----------|:-----|:--------|:------------|
|
|
441
|
-
| `service` | string |
|
|
466
|
+
| `service` | string | - | Service class name or filename. Omit to list all services |
|
|
442
467
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
443
468
|
|
|
444
469
|
### `rails_get_job_pattern`
|
|
@@ -481,6 +506,8 @@ ViewComponent/Phlex components: props, slots, previews, sidecar assets, usage ex
|
|
|
481
506
|
|:----------|:-----|:--------|:------------|
|
|
482
507
|
| `component` | string | - | Specific component name |
|
|
483
508
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
509
|
+
| `offset` | integer | `0` | Skip this many components |
|
|
510
|
+
| `limit` | integer | `50` | Max components to return |
|
|
484
511
|
|
|
485
512
|
### `rails_get_i18n`
|
|
486
513
|
|
|
@@ -555,7 +582,7 @@ only.
|
|
|
555
582
|
|
|
556
583
|
### `rails_dependency_graph`
|
|
557
584
|
|
|
558
|
-
Model
|
|
585
|
+
Model association graph in Mermaid or text format.
|
|
559
586
|
|
|
560
587
|
| Parameter | Type | Default | Description |
|
|
561
588
|
|:----------|:-----|:--------|:------------|
|
|
@@ -565,7 +592,7 @@ Model/service dependency graph in Mermaid or text format.
|
|
|
565
592
|
| `show_cycles` | boolean | `false` | Detect and list circular dependencies |
|
|
566
593
|
| `show_sti` | boolean | `false` | Show Single Table Inheritance hierarchies |
|
|
567
594
|
|
|
568
|
-
|
|
595
|
+
The graph is capped at 50 nodes, with or without `model`, and says so when it cuts.
|
|
569
596
|
|
|
570
597
|
### `rails_migration_advisor`
|
|
571
598
|
|
|
@@ -573,10 +600,12 @@ Migration code generation with duplicate/nonexistent column warnings, reversibil
|
|
|
573
600
|
|
|
574
601
|
| Parameter | Type | Default | Description |
|
|
575
602
|
|:----------|:-----|:--------|:------------|
|
|
576
|
-
| `action` |
|
|
603
|
+
| `action` | enum | *required* | `add_column`, `remove_column`, `rename_column`, `add_index`, `add_association`, `change_type`, `create_table` |
|
|
577
604
|
| `table` | string | *required* | Table name |
|
|
578
|
-
| `
|
|
579
|
-
| `
|
|
605
|
+
| `column` | string | - | Column name |
|
|
606
|
+
| `type` | string | - | Column type (e.g., `string`, `integer`, `references`) |
|
|
607
|
+
| `new_name` | string | - | New column name, for `rename_column` only |
|
|
608
|
+
| `options` | string | - | Extra options (e.g., `null: false, default: 0`) |
|
|
580
609
|
|
|
581
610
|
### `rails_search_docs`
|
|
582
611
|
|
|
@@ -585,7 +614,9 @@ Bundled topic index with weighted keyword search. Optional on-demand GitHub fetc
|
|
|
585
614
|
| Parameter | Type | Default | Description |
|
|
586
615
|
|:----------|:-----|:--------|:------------|
|
|
587
616
|
| `query` | string | *required* | Search query |
|
|
588
|
-
| `
|
|
617
|
+
| `source` | enum | `all` | `all`, `guides`, `stimulus`, `turbo`, `hotwire` |
|
|
618
|
+
| `limit` | integer | `5` | Max results to return (1-20) |
|
|
619
|
+
| `fetch` | boolean | `false` | Fetch the full content from GitHub (cached 24h in `tmp/`) |
|
|
589
620
|
|
|
590
621
|
### `rails_query`
|
|
591
622
|
|
|
@@ -593,7 +624,7 @@ Safe read-only SQL with 4-layer security: regex validation, `SET TRANSACTION REA
|
|
|
593
624
|
|
|
594
625
|
| Parameter | Type | Default | Description |
|
|
595
626
|
|:----------|:-----|:--------|:------------|
|
|
596
|
-
| `sql` | string | *required* | SQL query
|
|
627
|
+
| `sql` | string | *required* | SQL query. Only `SELECT`, `WITH`, `SHOW`, `EXPLAIN`, `DESCRIBE` are allowed |
|
|
597
628
|
| `limit` | integer | `100` | Maximum rows to return (hard cap: 1000) |
|
|
598
629
|
| `format` | enum | `table` | `table`, `csv` |
|
|
599
630
|
| `explain` | boolean | `false` | Show query plan instead of results |
|
|
@@ -606,20 +637,21 @@ Reverse file tail with level filtering and sensitive data redaction.
|
|
|
606
637
|
|
|
607
638
|
| Parameter | Type | Default | Description |
|
|
608
639
|
|:----------|:-----|:--------|:------------|
|
|
609
|
-
| `file` | string |
|
|
610
|
-
| `lines` | integer | `50` | Number of lines |
|
|
611
|
-
| `level` | enum |
|
|
640
|
+
| `file` | string | current environment's log | Log file name in `log/` (e.g., `production`, `sidekiq`); the `.log` suffix is optional |
|
|
641
|
+
| `lines` | integer | `50` | Number of lines, max 500 |
|
|
642
|
+
| `level` | enum | `all` | Minimum level: `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`, `all` |
|
|
612
643
|
| `search` | string | - | Keep lines matching this term. The match runs on the redacted line, so a redacted value cannot be searched for |
|
|
613
644
|
|
|
614
645
|
### `rails_diagnose`
|
|
615
646
|
|
|
616
|
-
One-call error diagnosis with classification, context, git
|
|
647
|
+
One-call error diagnosis with classification, context, recent git changes, and log correlation. It does not call a method undefined when the model's method list could be missing one - a concern's, a parent's, or anything past the payload's own cap.
|
|
617
648
|
|
|
618
649
|
| Parameter | Type | Default | Description |
|
|
619
650
|
|:----------|:-----|:--------|:------------|
|
|
620
651
|
| `error` | string | *required* | Error message or class |
|
|
621
652
|
| `file` | string | - | File where error occurred |
|
|
622
653
|
| `line` | integer | - | Line number |
|
|
654
|
+
| `action` | string | - | `controller#action` (e.g., `posts#create`); adds that action's context |
|
|
623
655
|
|
|
624
656
|
### `rails_review_changes`
|
|
625
657
|
|
|
@@ -627,8 +659,8 @@ PR/commit review with per-file context and warnings.
|
|
|
627
659
|
|
|
628
660
|
| Parameter | Type | Default | Description |
|
|
629
661
|
|:----------|:-----|:--------|:------------|
|
|
630
|
-
| `ref` | string | `HEAD` | Git ref to
|
|
631
|
-
| `
|
|
662
|
+
| `ref` | string | `HEAD` | Git ref to diff against. `HEAD` reviews uncommitted changes |
|
|
663
|
+
| `files` | array | - | Review only these changed files (omit for all) |
|
|
632
664
|
|
|
633
665
|
### `rails_runtime_info`
|
|
634
666
|
|
|
@@ -637,14 +669,16 @@ Live database pool stats, table sizes, pending migrations, cache stats, queue de
|
|
|
637
669
|
| Parameter | Type | Default | Description |
|
|
638
670
|
|:----------|:-----|:--------|:------------|
|
|
639
671
|
| `detail` | enum | `standard` | `summary`, `standard`, `full` |
|
|
672
|
+
| `section` | enum | - | One section only: `database`, `cache`, `jobs`, `connections` |
|
|
640
673
|
|
|
641
674
|
### `rails_session_context`
|
|
642
675
|
|
|
643
|
-
Session-aware context tracking across tool calls within a conversation.
|
|
676
|
+
Session-aware context tracking across tool calls within a conversation. Pass `action` or `mark`; a call with neither is an error.
|
|
644
677
|
|
|
645
678
|
| Parameter | Type | Default | Description |
|
|
646
679
|
|:----------|:-----|:--------|:------------|
|
|
647
|
-
| `
|
|
680
|
+
| `action` | enum | - | `status` (queried tools with timestamps), `summary` (short recap), `reset` (clear the session) |
|
|
681
|
+
| `mark` | string | - | Record a tool and its params as already queried (e.g., `get_schema:users`) |
|
|
648
682
|
|
|
649
683
|
<p align="right"><a href="#table-of-contents">↑ back to top</a></p>
|
|
650
684
|
|
data/docs/TROUBLESHOOTING.md
CHANGED
|
@@ -40,14 +40,14 @@ The gem is likely in a `:development` group but you're running in another enviro
|
|
|
40
40
|
|
|
41
41
|
```ruby
|
|
42
42
|
# config/initializers/rails_ai_context.rb
|
|
43
|
-
if defined?(RailsAiContext)
|
|
43
|
+
if defined?(RailsAiContext) && RailsAiContext.respond_to?(:configure)
|
|
44
44
|
RailsAiContext.configure do |config|
|
|
45
45
|
# ...
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
The
|
|
50
|
+
The guard prevents crashes when the gem isn't loaded. `rails ai:doctor` warns about a guard that checks `defined?(RailsAiContext)` alone, since the constant can exist where `configure` does not.
|
|
51
51
|
|
|
52
52
|
### "Permission denied" during install
|
|
53
53
|
|
|
@@ -172,7 +172,7 @@ config.generate_root_files = false
|
|
|
172
172
|
|
|
173
173
|
## Query tool issues
|
|
174
174
|
|
|
175
|
-
### "
|
|
175
|
+
### "rails_query is disabled in production"
|
|
176
176
|
|
|
177
177
|
By design. Override if needed:
|
|
178
178
|
|
|
@@ -180,20 +180,21 @@ By design. Override if needed:
|
|
|
180
180
|
config.allow_query_in_production = true
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
### "
|
|
183
|
+
### "Blocked: contains INSERT" and other "Blocked:" messages
|
|
184
184
|
|
|
185
|
-
The 4-layer SQL validator blocks write operations and injection patterns. Ensure you're only running SELECT queries.
|
|
185
|
+
The 4-layer SQL validator blocks write operations and injection patterns, and the message names what it hit. Ensure you're only running SELECT queries.
|
|
186
186
|
|
|
187
187
|
Common false positives:
|
|
188
|
-
-
|
|
188
|
+
- A blocked keyword inside a string (`WHERE note = 'please insert coin'`) → the validator matches words, not SQL structure, so the query is refused
|
|
189
|
+
- Hash characters → a `#` starts a comment on MySQL only, and never inside a quoted string
|
|
189
190
|
- JSONB operators (`#>>`) → preserved correctly since v5.6.0
|
|
190
191
|
|
|
191
192
|
### "Column values show [FILTERED]"
|
|
192
193
|
|
|
193
|
-
Columns
|
|
194
|
+
Columns whose names look sensitive are redacted, and a query that names one is rejected with "Blocked: query references sensitive column". Shortening `config.query_redacted_columns` does not lift either, because a built-in list applies as well. Exempt a column of your own by name:
|
|
194
195
|
|
|
195
196
|
```ruby
|
|
196
|
-
config.
|
|
197
|
+
config.query_allowed_columns = %w[secret]
|
|
197
198
|
```
|
|
198
199
|
|
|
199
200
|
---
|
|
@@ -203,11 +204,11 @@ config.query_redacted_columns = %w[password_digest encrypted_password]
|
|
|
203
204
|
### "Search returns no results"
|
|
204
205
|
|
|
205
206
|
1. Check the case: the search is case-sensitive on both backends, as ripgrep is by default
|
|
206
|
-
2. Check excluded paths: `config.excluded_paths` excludes `node_modules`, `tmp`, `log`, `doc` and `docs` directories at any depth
|
|
207
|
+
2. Check excluded paths: `config.excluded_paths` excludes `node_modules`, `tmp`, `log`, `vendor`, `.git`, `doc` and `docs` directories at any depth
|
|
207
208
|
3. Check `config.search_extensions`: when set, it narrows the Ruby fallback to those extensions
|
|
208
209
|
4. Check sensitive patterns: some files are blocked by design
|
|
209
210
|
|
|
210
|
-
### "ripgrep not
|
|
211
|
+
### "ripgrep not installed" warning
|
|
211
212
|
|
|
212
213
|
Install ripgrep for faster search:
|
|
213
214
|
|
|
@@ -245,7 +246,7 @@ The file is read from the app root, once, at boot, and an initializer does not r
|
|
|
245
246
|
|
|
246
247
|
## Security scan issues
|
|
247
248
|
|
|
248
|
-
### "Brakeman not installed"
|
|
249
|
+
### "Brakeman is not installed"
|
|
249
250
|
|
|
250
251
|
The `rails_security_scan` tool requires Brakeman:
|
|
251
252
|
|
data/exe/rails-ai-context
CHANGED
|
@@ -269,7 +269,7 @@ class RailsAiContextCLI < Thor
|
|
|
269
269
|
end
|
|
270
270
|
end
|
|
271
271
|
|
|
272
|
-
desc "init", "Set up rails-ai-context for standalone use (creates .rails-ai-context.yml and
|
|
272
|
+
desc "init", "Set up rails-ai-context for standalone use (creates .rails-ai-context.yml, each AI tool's MCP config and its context files)"
|
|
273
273
|
option :no_boot, type: :boolean, default: false, desc: "Skip booting the app; serve static analysis only"
|
|
274
274
|
option :mcp_only, type: :boolean, default: false,
|
|
275
275
|
desc: "Write the MCP config and nothing else: no CLAUDE.md, AGENTS.md, rules files or .ai-context.json"
|
|
@@ -295,7 +295,7 @@ class RailsAiContextCLI < Thor
|
|
|
295
295
|
cleanup_removed_tools(previous_tools, ai_tools) if previous_tools&.any?
|
|
296
296
|
|
|
297
297
|
# --- One-time v5.0.0 legacy UI-pattern files cleanup prompt ---
|
|
298
|
-
::RailsAiContext::LegacyCleanup.prompt_legacy_files(ai_tools, root: Dir.pwd)
|
|
298
|
+
::RailsAiContext::LegacyCleanup.prompt_legacy_files(ai_tools, root: Dir.pwd) if context_files
|
|
299
299
|
|
|
300
300
|
# --- Record the selection (YAML, plus the initializer line) ---
|
|
301
301
|
record_selection(ai_tools, tool_mode, context_files)
|
|
@@ -397,9 +397,13 @@ class RailsAiContextCLI < Thor
|
|
|
397
397
|
ai_tools, root: Dir.pwd,
|
|
398
398
|
extra_yaml: { "tool_mode" => tool_mode.to_s, "context_files" => context_files }
|
|
399
399
|
)
|
|
400
|
-
::RailsAiContext::Install::SelectionRecord
|
|
400
|
+
record = ::RailsAiContext::Install::SelectionRecord
|
|
401
|
+
conflicts = [
|
|
402
|
+
record.conflict_message(:context_files, record.write_context_files(context_files, root: Dir.pwd)),
|
|
403
|
+
record.conflict_message(:tool_mode, record.write_tool_mode(tool_mode, root: Dir.pwd))
|
|
404
|
+
].compact
|
|
401
405
|
|
|
402
|
-
|
|
406
|
+
(record.messages(result) + conflicts).each do |level, text|
|
|
403
407
|
$stderr.puts(level == :warn ? "Warning: #{text}" : text)
|
|
404
408
|
end
|
|
405
409
|
end
|
|
@@ -550,7 +550,7 @@ module RailsAiContext
|
|
|
550
550
|
|
|
551
551
|
# One-time v5.0.0 legacy UI-pattern files cleanup prompt
|
|
552
552
|
RailsAiContext::LegacyCleanup.prompt_legacy_files(
|
|
553
|
-
@selected_formats, root: Rails.root
|
|
553
|
+
@selected_formats, root: Rails.root, warn_only: options[:defaults]
|
|
554
554
|
)
|
|
555
555
|
|
|
556
556
|
begin
|
|
@@ -235,7 +235,7 @@ module RailsAiContext
|
|
|
235
235
|
attr_accessor :max_tool_response_chars
|
|
236
236
|
|
|
237
237
|
# Live reload: auto-invalidate MCP tool caches on file changes
|
|
238
|
-
# :auto (default) - enable if `listen` gem is available,
|
|
238
|
+
# :auto (default) - enable if `listen` gem is available, say so on stderr otherwise
|
|
239
239
|
# true - enable, raise if `listen` gem is missing
|
|
240
240
|
# false - disable entirely
|
|
241
241
|
attr_accessor :live_reload
|
|
@@ -372,7 +372,7 @@ module RailsAiContext
|
|
|
372
372
|
# Database query tool settings (rails_query)
|
|
373
373
|
attr_accessor :query_timeout # Statement timeout in seconds (default: 5)
|
|
374
374
|
attr_accessor :query_row_limit # Max rows returned (default: 100, hard cap: 1000)
|
|
375
|
-
attr_accessor :query_redacted_columns # Column names
|
|
375
|
+
attr_accessor :query_redacted_columns # Column names a query may not reference, redacted in output
|
|
376
376
|
attr_accessor :query_allowed_columns # Column names to exempt from the built-in sensitive list
|
|
377
377
|
attr_accessor :allow_query_in_production # Allow rails_query in production (default: false)
|
|
378
378
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "uri"
|
|
3
4
|
require "yaml"
|
|
4
5
|
|
|
5
6
|
module RailsAiContext
|
|
@@ -69,6 +70,41 @@ module RailsAiContext
|
|
|
69
70
|
databases(root)[primary_name(root)]
|
|
70
71
|
end
|
|
71
72
|
|
|
73
|
+
# A database's schema_search_path as PostgreSQL reads it: an unquoted name folds to
|
|
74
|
+
# lowercase and "$user" is the configured username. Unset, PostgreSQL's "$user", public.
|
|
75
|
+
# namespace.c recomputeNamespacePath keeps a repeated schema's first place only.
|
|
76
|
+
def schema_search_path(root, name = "primary")
|
|
77
|
+
search_path_entries(root, name).map(&:first).uniq
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The schema only the search path's "$user" names, or nil: one the path also names outright is configured.
|
|
81
|
+
def user_schema(root, name = "primary")
|
|
82
|
+
entries = search_path_entries(root, name)
|
|
83
|
+
user = entries.find(&:last)&.first
|
|
84
|
+
user unless entries.any? { |schema, from_user| !from_user && schema == user }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# [schema, from_user] per search path entry.
|
|
88
|
+
def search_path_entries(root, name)
|
|
89
|
+
settings = entry(root, name)
|
|
90
|
+
settings = {} unless settings.is_a?(Hash)
|
|
91
|
+
known = adapter(name, settings).first
|
|
92
|
+
return [ [ "public", false ] ] if known && !known.start_with?("postg")
|
|
93
|
+
|
|
94
|
+
settings = settings.merge(url_settings(name, settings["url"]))
|
|
95
|
+
# postgresql_adapter.rb:984 (8.1), :865 (7.0): schema_order is the older name.
|
|
96
|
+
text = (settings["schema_search_path"] || settings["schema_order"]).to_s
|
|
97
|
+
text = '"$user", public' if text.strip.empty?
|
|
98
|
+
user = settings["username"].to_s
|
|
99
|
+
text.split(",").filter_map do |part|
|
|
100
|
+
part = part.strip
|
|
101
|
+
next if part.empty? || computed?(part)
|
|
102
|
+
next ([ user, true ] unless user.empty? || computed?(user)) if part.delete('"') == "$user"
|
|
103
|
+
|
|
104
|
+
[ part.start_with?('"') ? part.delete('"') : part.downcase, false ]
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
72
108
|
# The named database's settings in the running environment, or nil.
|
|
73
109
|
def entry(root, name)
|
|
74
110
|
entry_in(databases(root), name)
|
|
@@ -99,13 +135,27 @@ module RailsAiContext
|
|
|
99
135
|
# Rails' DatabaseConfigurations: an entry's own url wins over its keys, and an entry
|
|
100
136
|
# without one takes <NAME>_DATABASE_URL, or DATABASE_URL for the primary.
|
|
101
137
|
def url_adapter(name, own_url)
|
|
102
|
-
url =
|
|
103
|
-
return nil if url.to_s.empty? || computed?(url)
|
|
138
|
+
url = url_for(name, own_url) or return nil
|
|
104
139
|
|
|
105
140
|
scheme = url[/\A([a-z][a-z0-9+.-]*):/i, 1]&.tr("-", "_")
|
|
106
141
|
scheme && URL_SCHEME_ADAPTERS.fetch(scheme, scheme)
|
|
107
142
|
end
|
|
108
143
|
|
|
144
|
+
def url_for(name, own_url)
|
|
145
|
+
url = own_url.nil? ? ENV["#{name.upcase}_DATABASE_URL"] || (ENV["DATABASE_URL"] if name == "primary") : own_url.to_s
|
|
146
|
+
url unless url.to_s.empty? || computed?(url)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# The username and schema_search_path a database URL carries, which Rails merges over the entry's keys.
|
|
150
|
+
def url_settings(name, own_url)
|
|
151
|
+
uri = URI.parse(url_for(name, own_url).to_s)
|
|
152
|
+
found = uri.query ? URI.decode_www_form(uri.query).to_h.slice("schema_search_path") : {}
|
|
153
|
+
found["username"] = URI.decode_www_form_component(uri.user) if uri.user
|
|
154
|
+
found
|
|
155
|
+
rescue URI::Error, ArgumentError
|
|
156
|
+
{}
|
|
157
|
+
end
|
|
158
|
+
|
|
109
159
|
# [adapter, from_default]: the URL's scheme wins, then the entry's adapter. An ERB-computed
|
|
110
160
|
# value is unknown unless it is one tag carrying its own literal default.
|
|
111
161
|
def adapter(name, entry)
|