rails-ai-context 5.30.1 → 5.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +295 -0
- data/docs/CLI.md +1 -1
- data/docs/COMPATIBILITY.md +23 -7
- data/docs/CONFIGURATION.md +5 -2
- data/docs/FAQ.md +1 -1
- data/docs/GUIDE.md +8 -2
- data/docs/INTROSPECTORS.md +6 -1
- data/docs/SECURITY.md +23 -1
- data/docs/TOOLS.md +11 -2
- data/exe/rails-ai-context +3 -4
- data/lib/rails_ai_context/action_filters.rb +68 -6
- data/lib/rails_ai_context/base_mixins.rb +44 -16
- data/lib/rails_ai_context/boot_manager.rb +21 -5
- data/lib/rails_ai_context/cli/entry_boot.rb +3 -2
- data/lib/rails_ai_context/cli/tool_runner.rb +22 -3
- data/lib/rails_ai_context/concern_macros.rb +698 -92
- data/lib/rails_ai_context/concern_membership.rb +6 -4
- data/lib/rails_ai_context/concern_paths.rb +31 -4
- data/lib/rails_ai_context/configuration.rb +8 -8
- data/lib/rails_ai_context/erb_source.rb +22 -3
- data/lib/rails_ai_context/git_ignore.rb +13 -11
- data/lib/rails_ai_context/introspector.rb +13 -2
- data/lib/rails_ai_context/introspectors/action_presence.rb +5 -3
- data/lib/rails_ai_context/introspectors/action_resolver.rb +2 -1
- data/lib/rails_ai_context/introspectors/call_site_expansion.rb +198 -18
- data/lib/rails_ai_context/introspectors/controller_introspector.rb +46 -19
- data/lib/rails_ai_context/introspectors/declared_constant.rb +15 -6
- data/lib/rails_ai_context/introspectors/eager_load.rb +22 -10
- data/lib/rails_ai_context/introspectors/i18n_introspector.rb +4 -3
- data/lib/rails_ai_context/introspectors/job_introspector.rb +76 -17
- data/lib/rails_ai_context/introspectors/listeners/associations_listener.rb +12 -0
- data/lib/rails_ai_context/introspectors/listeners/base_listener.rb +3 -3
- data/lib/rails_ai_context/introspectors/listeners/callbacks_listener.rb +28 -1
- data/lib/rails_ai_context/introspectors/listeners/generic_macro_listener.rb +3 -1
- data/lib/rails_ai_context/introspectors/listeners/migration_replay_listener.rb +9 -1
- data/lib/rails_ai_context/introspectors/listeners/mixins_listener.rb +21 -28
- data/lib/rails_ai_context/introspectors/listeners/mount_listener.rb +13 -6
- data/lib/rails_ai_context/introspectors/listeners/owner_scope.rb +67 -0
- data/lib/rails_ai_context/introspectors/listeners/proc_literal_listener.rb +42 -0
- data/lib/rails_ai_context/introspectors/listeners/schema_dsl_listener.rb +81 -25
- data/lib/rails_ai_context/introspectors/listeners/with_options_scope.rb +49 -12
- data/lib/rails_ai_context/introspectors/migration_replay/statements.rb +15 -0
- data/lib/rails_ai_context/introspectors/migration_replay.rb +2 -0
- data/lib/rails_ai_context/introspectors/model_introspector.rb +291 -121
- data/lib/rails_ai_context/introspectors/route_introspector.rb +62 -4
- data/lib/rails_ai_context/introspectors/schema_conventions.rb +8 -0
- data/lib/rails_ai_context/introspectors/schema_introspector.rb +7 -4
- data/lib/rails_ai_context/introspectors/schema_reader.rb +2 -0
- data/lib/rails_ai_context/introspectors/source_scan.rb +5 -3
- data/lib/rails_ai_context/introspectors/stimulus_introspector.rb +13 -4
- data/lib/rails_ai_context/introspectors/structure_sql_reader.rb +107 -23
- data/lib/rails_ai_context/introspectors/view_template_introspector.rb +18 -16
- data/lib/rails_ai_context/method_name.rb +31 -0
- data/lib/rails_ai_context/migration_status.rb +6 -1
- data/lib/rails_ai_context/output_guard.rb +6 -4
- data/lib/rails_ai_context/pending_migrations.rb +3 -2
- data/lib/rails_ai_context/portable_path.rb +14 -0
- data/lib/rails_ai_context/redaction.rb +8 -2
- data/lib/rails_ai_context/safe_file.rb +4 -1
- data/lib/rails_ai_context/safe_path.rb +17 -4
- data/lib/rails_ai_context/schema_adapter.rb +6 -1
- data/lib/rails_ai_context/serializers/context_file_serializer.rb +2 -2
- data/lib/rails_ai_context/serializers/cursor_rules_serializer.rb +5 -0
- data/lib/rails_ai_context/server.rb +26 -7
- data/lib/rails_ai_context/tasks/rails_ai_context.rake +1 -1
- data/lib/rails_ai_context/tools/base_tool.rb +20 -10
- data/lib/rails_ai_context/tools/diagnose.rb +4 -0
- data/lib/rails_ai_context/tools/generate_test.rb +19 -0
- data/lib/rails_ai_context/tools/get_callbacks.rb +14 -6
- data/lib/rails_ai_context/tools/get_concern.rb +1 -1
- data/lib/rails_ai_context/tools/get_conventions.rb +5 -7
- data/lib/rails_ai_context/tools/get_job_pattern.rb +8 -2
- data/lib/rails_ai_context/tools/get_model_details.rb +5 -4
- data/lib/rails_ai_context/tools/get_partial_interface.rb +18 -4
- data/lib/rails_ai_context/tools/get_routes.rb +19 -9
- data/lib/rails_ai_context/tools/get_schema.rb +26 -4
- data/lib/rails_ai_context/tools/get_service_pattern.rb +44 -25
- data/lib/rails_ai_context/tools/get_test_info.rb +8 -0
- data/lib/rails_ai_context/tools/performance_check.rb +5 -13
- data/lib/rails_ai_context/tools/query.rb +125 -33
- data/lib/rails_ai_context/tools/runtime_info.rb +5 -3
- data/lib/rails_ai_context/tools/search_code.rb +64 -22
- data/lib/rails_ai_context/tools/search_docs.rb +4 -5
- data/lib/rails_ai_context/tools/security_scan.rb +3 -1
- data/lib/rails_ai_context/tools/validate_semantics.rb +49 -13
- data/lib/rails_ai_context/version.rb +1 -1
- data/lib/rails_ai_context.rb +1 -1
- data/server.json +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 44b4fb64c009d96449f8f05375947d6713b07d0a45c7f27e779e0ac271c0bfa6
|
|
4
|
+
data.tar.gz: d0045d00ef00250f97eeae2ff105b09c7f991a3746c9198bc8126b3e79d8dc2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e60a1a843d881a90404c7f87b6a29e829a60210195375c94a90151b82850d749820828b752e9e6f5f60b22dd92bf948bb8275f207c7df801ce954bd9a53705cd
|
|
7
|
+
data.tar.gz: 4aa95471cb0a3a4ad1cec127db6322b9b0b5d1f39f00826b1c73dd246cf0acfadc51e14f3e9f16b1cd6f3602acb618ee520eadc2b674825d2f95e675dfa7e6c1
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,301 @@ 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
|
+
## [5.31.0] - 2026-10-05
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **A committed placeholder is not a secret.** A file whose name ends in
|
|
13
|
+
`.example`, `.sample`, `.template` or `.dist` (`.env.example`) is readable by
|
|
14
|
+
`rails_get_edit_context` and the other file tools, although the default
|
|
15
|
+
`.env.*` pattern matches it, and `doctor` no longer lists it as unread or
|
|
16
|
+
says to gitignore it. A `sensitive_patterns` entry that names the file
|
|
17
|
+
exactly, with no glob characters, still blocks it, and so does a path
|
|
18
|
+
pattern with a `/` (`.ssh/*` keeps `.ssh/id_rsa.template` blocked).
|
|
19
|
+
Redaction treats the four suffixes alike. `rails_search_code` now drops
|
|
20
|
+
sensitive files from ripgrep's output where it used to exclude them by glob,
|
|
21
|
+
so a sensitive file ripgrep cannot open is not reported as an error and does
|
|
22
|
+
not send a no-match search through the Ruby fallback. (#267)
|
|
23
|
+
- **`rails_query` on a SQLite file stops at `query_timeout`.** The query runs
|
|
24
|
+
in a child process with its own read-only connection, which is stopped at the
|
|
25
|
+
deadline. sqlite3 2.x's `statement_timeout=` interrupts any statement of more
|
|
26
|
+
than a few thousand steps whatever the value, and the extension holds the GVL
|
|
27
|
+
while a statement runs, so no in-process limit exists. The child takes the
|
|
28
|
+
app's `extensions:` and waits on a locked database as the app would. An
|
|
29
|
+
in-memory database, a platform without `fork`, or a query that needs a
|
|
30
|
+
function, virtual-table module, collation or encryption key only the app's
|
|
31
|
+
own connection has runs in-process; the table and EXPLAIN answers then say it
|
|
32
|
+
ran without a time limit, and CSV output stays plain data. (#256)
|
|
33
|
+
- **`rails_get_callbacks` lists callbacks in the order Rails runs them**: base
|
|
34
|
+
classes first, a concern's callbacks where its `include` line stands, then
|
|
35
|
+
the model's own, and a `before_` or `around_` callback with `prepend: true`
|
|
36
|
+
first. `after_commit` and `after_rollback` list last declared first, as
|
|
37
|
+
Rails runs them, unless `run_after_transaction_callbacks_in_order_defined`
|
|
38
|
+
is on (`load_defaults 7.1` or later). The static tier reads that from
|
|
39
|
+
`config/application.rb` and the initializers, the last line that sets it
|
|
40
|
+
winning, and when the config does not tell, `rails_get_callbacks` and
|
|
41
|
+
`rails_get_model_details` say so. A method declared twice under one callback
|
|
42
|
+
type shows the declaration Rails keeps, the later one, which corrects the
|
|
43
|
+
5.30.0 entry that said each declaration is shown. A declaration inside a
|
|
44
|
+
method body counts where the class calls the method, and not at all when
|
|
45
|
+
nothing does, so an uncalled method that redeclares a callback no longer
|
|
46
|
+
hides it. A call counts written bare or as `self.name`, made inside a class
|
|
47
|
+
method it runs, or made from a concern's `included` block. A module joins a
|
|
48
|
+
class chain once, at the first place the chain adds it: the outermost class
|
|
49
|
+
that adds it, at its first include there, which can be a call to a class
|
|
50
|
+
method that includes it. A Concern's `included` block runs there only; a
|
|
51
|
+
plain `self.included` hook runs on every include. A call runs the definition
|
|
52
|
+
Ruby's lookup finds as of the call: a module the class prepends to its
|
|
53
|
+
singleton class, the class's own class methods, then the modules it extends
|
|
54
|
+
and its concerns' class methods, the last added first, then the same for
|
|
55
|
+
each base, then what every model has: class methods an initializer writes in
|
|
56
|
+
`ActiveRecord::Base.class_eval` or a reopened base, the file Rails loads
|
|
57
|
+
later winning (Canvas's `validates_locale` adds its `before_validation` to
|
|
58
|
+
Account, User and Course), then the modules mixed into the base. One an
|
|
59
|
+
initializer writes on `ApplicationRecord` replaces ApplicationRecord's own.
|
|
60
|
+
A class's own class methods are its `def self.`, an `alias_method` in
|
|
61
|
+
`class << self` (it runs what its original name ran at the alias), and those
|
|
62
|
+
a Concern's `included` block or a hook writes on the class (`def self.x` or
|
|
63
|
+
`class << self`, in the block, in `base.class_eval` or in `class << base`),
|
|
64
|
+
each from its line where that code runs. A module counts from the line
|
|
65
|
+
adding it, where that line runs: an `extend`, `singleton_class.include` or
|
|
66
|
+
`singleton_class.prepend` (which counts as prepended) in the class, in a
|
|
67
|
+
hook or in a Concern's `included` block, and an `extend` in a class method a
|
|
68
|
+
call reaches (an `acts_as_x` that extends its methods, whose `self.extended`
|
|
69
|
+
hook then runs); a plain module's nested `ClassMethods` counts only when
|
|
70
|
+
something extends it. A module a hook includes runs its own hooks. Two
|
|
71
|
+
concerns' modules of one name (each concern's `ClassMethods`) stay two: each
|
|
72
|
+
name is the constant it resolves to where it is written, and one that
|
|
73
|
+
resolves to nothing no longer hides the other. A `super` runs the next
|
|
74
|
+
definition, at the `super`. An instance method or a nested class's method of
|
|
75
|
+
the same name never runs. A module a class method includes joins only when a
|
|
76
|
+
call reaches that method, and only calls after it see its methods. A nested
|
|
77
|
+
class's callbacks are its own, and a module nested in the model's file reads
|
|
78
|
+
like any concern: `include` runs its `included` block, `extend` its methods
|
|
79
|
+
and `self.extended` only. A module a plugin's lib loads by a glob `require`
|
|
80
|
+
is read from beside the file naming it, and from its definition rather than
|
|
81
|
+
an empty namespace stub above it, so OpenProject's journalized models list
|
|
82
|
+
`save_journals`. A Mongoid document's own callbacks list in the same run
|
|
83
|
+
order, one in a class method where the document calls it. Neither tier
|
|
84
|
+
evaluates `send`, `define_singleton_method` or a module included in
|
|
85
|
+
`class << self` for this, so the list can miss what they register or show
|
|
86
|
+
the definition they replace. (#253)
|
|
87
|
+
- **A lambda or Proc given to `queue_as` reads as what ActiveJob does with
|
|
88
|
+
it.** ActiveJob never calls it; it names the queue after the Proc's text.
|
|
89
|
+
Both tiers now say so, with the source, where the booted tier printed the
|
|
90
|
+
Proc's address and the static tier called it computed. A `queue_as` block is
|
|
91
|
+
the computed case and now shows its source too; a block argument
|
|
92
|
+
(`queue_as(&pick)`) reads as computed in both tiers. The 5.30.0 entry used
|
|
93
|
+
`queue_as -> { ... }` as its example of a computed queue; that was wrong.
|
|
94
|
+
(#271)
|
|
95
|
+
- **An MCP stdio session carries nothing but JSON-RPC on stdout for its whole
|
|
96
|
+
life.** Output written during a tool call (a logger built on first use, as
|
|
97
|
+
Sidekiq's is, `puts`, a child process) goes to stderr; only boot was guarded
|
|
98
|
+
before. (#255)
|
|
99
|
+
- **The booted `rails_security_scan` parses in its own process.** Brakeman's
|
|
100
|
+
forked parse workers could not return a parse error from an app that loads
|
|
101
|
+
web-console, and the scan failed where the static tier scanned. (#257)
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- **A concern's declarations name the module the include resolves to.**
|
|
106
|
+
`rails_get_callbacks` on OpenProject's WorkPackage lists
|
|
107
|
+
`after_save :save_journals` from `Acts::Journalized::SaveHooks`, where it
|
|
108
|
+
said `SaveHooks`.
|
|
109
|
+
- **A module declared in its outer module's file is read from there.**
|
|
110
|
+
Canvas's `Role::AssociationHelper` lives in role.rb, and its `included`
|
|
111
|
+
hook adds `before_save :resolve_cross_account_role` to Enrollment and its
|
|
112
|
+
subclasses, AccountUser and RoleOverride; the static tier called the
|
|
113
|
+
module unread and missed the callback. `rails_get_callbacks`,
|
|
114
|
+
`rails_get_model_details` and the controller filters and actions find it
|
|
115
|
+
there and read that module, not the outer class.
|
|
116
|
+
- **`rails_get_callbacks` lists models of one callback count by name**, so a
|
|
117
|
+
model gaining a callback no longer moves the sections around it.
|
|
118
|
+
- **A model macro written over `*args` reads each call's own arguments.**
|
|
119
|
+
The list binds to the call's positionals past the method's other
|
|
120
|
+
parameters, less the options hash the body takes off the end
|
|
121
|
+
(`args.extract_options!`), plus literals its leading statements push. A
|
|
122
|
+
block over the list is read once per item, so Canvas's
|
|
123
|
+
`validates_locale :locale, :browser_locale, allow_nil: true` lists an
|
|
124
|
+
inclusion validation on each field with its own `if: :<field>_changed?`, in
|
|
125
|
+
place of the macro's own row and one on a computed `field`. An options
|
|
126
|
+
hash, list or parameter the method changes in place (`options[:x] = 1`,
|
|
127
|
+
`options[:x] ||= 1`, `reverse_merge!`, `delete`) is not read as the call's
|
|
128
|
+
value. A declaration it decides, the method name included (`before_save
|
|
129
|
+
name` after `name.strip!`), is held back and listed under "Not decided from
|
|
130
|
+
the source (the method name or a condition)", the heading that was "Only
|
|
131
|
+
under a condition the source does not decide".
|
|
132
|
+
- **A `load_defaults` written after `belongs_to_required_by_default = false`
|
|
133
|
+
turns the default back on** in the static tier, as Rails does, so the
|
|
134
|
+
implicit presence of a required `belongs_to` is listed. A literal assignment
|
|
135
|
+
used to win wherever it stood. A value the source cannot evaluate
|
|
136
|
+
(`ENV.fetch(...) == "true"`), app-wide or in the class, makes the presence
|
|
137
|
+
conditional on it, named in the answer. A literal `nil` reads as off, as
|
|
138
|
+
Rails reads it, here and for the commit-order setting. A `belongs_to` with
|
|
139
|
+
`required: nil` is optional, and `required:` decides over `optional:` when
|
|
140
|
+
both are written, as in Rails.
|
|
141
|
+
- **`rails_get_callbacks` prints `on:`** for validation callbacks and any
|
|
142
|
+
callback whose type does not already name the event, before `if:` and
|
|
143
|
+
`unless:`. (#252)
|
|
144
|
+
- **`rails_performance_check` with `model` and `category` counts only what it
|
|
145
|
+
lists.** (#265)
|
|
146
|
+
- **`rails_search_docs` caches a fetched guide whole.** A guide with non-ASCII
|
|
147
|
+
text failed to write in the booted tier and left an empty file that read as a
|
|
148
|
+
cached guide for 24 hours; the write is now binary and atomic, and an empty
|
|
149
|
+
cache file is a miss. (#266)
|
|
150
|
+
- **`rails_search_code` trace finds one definition and no sibling of itself**:
|
|
151
|
+
`qa_ping` no longer matches `def qa_ping?`, `qa_ping!` or `qa_ping=`, and
|
|
152
|
+
`def self.qa_ping` is left out of its own sibling list, where a setter now
|
|
153
|
+
appears. Every method-body lookup (concerns, callbacks, actions, conventions)
|
|
154
|
+
ends a name the same way, and ripgrep and the Ruby fallback agree on
|
|
155
|
+
non-ASCII text, where any character outside ASCII is part of the name, as
|
|
156
|
+
Ruby reads it. (#258)
|
|
157
|
+
- **`rails_search_code` call sites skip comment lines** with the rule trace
|
|
158
|
+
uses, by file type: `#` in Ruby, `//` and `/*` in JS and TS, `/*` in CSS and
|
|
159
|
+
`//` too in SCSS, Sass and Less, `-#` in Haml, `/` in Slim. A stylesheet
|
|
160
|
+
line that starts with a `#id` selector is not a call site either. A line
|
|
161
|
+
holding a live ERB tag is a call site, and a spaced setter call
|
|
162
|
+
(`obj.qa_ping = 1`) is not a call of `qa_ping`. (#269)
|
|
163
|
+
- **Both search backends read the same excludes file.** The Ruby fallback read
|
|
164
|
+
`core.excludesFile` from the repository's own config, which ripgrep does not.
|
|
165
|
+
It now reads what ripgrep 15 reads: `~/.gitconfig`, then the XDG git config,
|
|
166
|
+
then the default ignore file. (#268)
|
|
167
|
+
- **A `db/structure.sql` table that `INHERITS` reads its parent's columns
|
|
168
|
+
first, then its own**, with multiple parents, chains, a parent defined later
|
|
169
|
+
in the file, and `ALTER COLUMN ... SET NOT NULL`/`SET DEFAULT`. A parent in
|
|
170
|
+
another schema resolves; one the file does not define is named. An index, key
|
|
171
|
+
or foreign key lands on the table its statement names, schema included. The
|
|
172
|
+
one-line form read its column type as `integer) INHERITS (...`. (#259)
|
|
173
|
+
- **A Stimulus controller under `app/javascript/controllers` keeps its
|
|
174
|
+
identifier** when another `controllers` directory holds the same path, and a
|
|
175
|
+
nested `controllers` directory stays in the name (`admin--controllers--x`).
|
|
176
|
+
(#264)
|
|
177
|
+
- **`query_allowed_columns` exempts a column from result redaction too**, as
|
|
178
|
+
it does from the pre-query check. Columns declared with `encrypts` stay
|
|
179
|
+
redacted. (#270)
|
|
180
|
+
|
|
181
|
+
## [5.30.2] - 2026-10-01
|
|
182
|
+
|
|
183
|
+
### Changed
|
|
184
|
+
|
|
185
|
+
- **`generate_root_files: false` leaves out `.cursorrules` too, and always
|
|
186
|
+
writes `.ai-context.json`.** `.cursorrules` is the same compact file as
|
|
187
|
+
`CLAUDE.md` at the repo root, so it is a root file and now reports "Not
|
|
188
|
+
applicable (root files disabled)". `.ai-context.json` is data for tools, not
|
|
189
|
+
an instruction file, and is written whatever the key says.
|
|
190
|
+
- **`serve --port` has no default of its own.** An explicit `--port` wins, then
|
|
191
|
+
`http_port` from the config, then 6029. The config key never reached `serve`
|
|
192
|
+
before, although `docs/STANDALONE.md` documents it, and the
|
|
193
|
+
`streamable_http` alias ignored `--port`.
|
|
194
|
+
- **A PostGIS connection is labelled PostgreSQL everywhere.** The booted schema
|
|
195
|
+
said PostGIS and the static tier PostgreSQL for the same app. The raw adapter
|
|
196
|
+
name stays in `.ai-context.json` as `adapter_source`.
|
|
197
|
+
- **The booted schema header lists pending migrations**, as the static tier
|
|
198
|
+
already did.
|
|
199
|
+
|
|
200
|
+
### Fixed
|
|
201
|
+
|
|
202
|
+
- **No machine path in an introspector's error.** A model file that could not
|
|
203
|
+
load put the absolute path of the app into `rails_get_model_details`,
|
|
204
|
+
`CLAUDE.md`, the models rules file and `.ai-context.json`, and the controller,
|
|
205
|
+
component, middleware, migration and rake-task errors did the same. Every
|
|
206
|
+
section's errors are now written relative to the app root, the resolved
|
|
207
|
+
`/private/tmp` form included.
|
|
208
|
+
- **A declared, unmigrated table names the migration that adds it.** The booted
|
|
209
|
+
answer said the table was missing from the database and stopped there. Rails
|
|
210
|
+
7.2+ refuses to load a migration dated in the future, which also emptied the
|
|
211
|
+
pending list; the list now comes from the applied versions and the files.
|
|
212
|
+
- **An unreadable model file still counts as the model file for its table**,
|
|
213
|
+
instead of listing the table under "Tables with no model file".
|
|
214
|
+
- **The static tier carries each `belongs_to` foreign key.** Static
|
|
215
|
+
association records had none unless the source spelled one, so
|
|
216
|
+
`rails_get_model_details`, the context files and `.ai-context.json` left it
|
|
217
|
+
out, and `rails_validate` stayed silent on an unindexed key where the booted
|
|
218
|
+
tier warned. A polymorphic key indexed as `[type, id]` counts as indexed.
|
|
219
|
+
- **A composite foreign key in `db/structure.sql` is read**, pg_dump and
|
|
220
|
+
mysqldump both, and renders as a column list like the schema.rb one.
|
|
221
|
+
- **Minitest tests from `rails_generate_test` can pass.** Absence,
|
|
222
|
+
confirmation, acceptance and exclusion validations asserted on a valid
|
|
223
|
+
fixture; each now sets up an invalid record, or emits `skip` where it cannot.
|
|
224
|
+
- **A mount at a computed path prints no path.** `mount X => ENV.fetch(...)`
|
|
225
|
+
printed `` at `[INFERRED]` ``, a bare constant printed its name as the path,
|
|
226
|
+
and a gem engine mounted that way read as "not mounted by the app's routes".
|
|
227
|
+
A path written without its leading slash gets one, as Rails does.
|
|
228
|
+
- **Static routes say which engine tables they could not read.** An engine
|
|
229
|
+
whose routes live in its gem (PgHero, LetterOpenerWeb) dropped out of the
|
|
230
|
+
static answer with no note; it is listed under "Mounted engines whose routes
|
|
231
|
+
were not read". A constant the app defines counts as an engine only when it
|
|
232
|
+
subclasses `Rails::Engine`. An engine mounted at several paths is one line
|
|
233
|
+
naming each.
|
|
234
|
+
- **Booted filter attribution matches the static tier.** An inherited
|
|
235
|
+
`after_action` lost its "from" credit when the child declared a
|
|
236
|
+
`before_action` of the same name, filters from a controller concern were not
|
|
237
|
+
credited to it, and a concern's `only:`/`except:`/`if:`/`unless:` and its
|
|
238
|
+
`skip_*_action` calls never reached the booted record. A body that
|
|
239
|
+
re-declares a concern's filter owns it, and a concern an ancestor already
|
|
240
|
+
includes stays the ancestor's.
|
|
241
|
+
- **An ERB comment is not read for instance variables**, while a Ruby comment
|
|
242
|
+
line inside a multi-line code tag no longer hides the code after it.
|
|
243
|
+
- **`rails_get_partial_interface` finds `render(partial: ...)`** with
|
|
244
|
+
parentheses, on one line or several, counts a nested render once, and a
|
|
245
|
+
multi-line snippet stops at the call's end.
|
|
246
|
+
- **Jobs on Rails 7.0 to 8.1.** A job with no `queue_as` read as "computed by a
|
|
247
|
+
block", since ActiveJob's default queue is a lambda; it now shows the
|
|
248
|
+
resolved default. The booted tier dropped every `retry_on`/`discard_on`, and
|
|
249
|
+
a job in a code root Zeitwerk does not manage.
|
|
250
|
+
- **A mailer outside `app/mailers` is a mailer in the booted tier too**, and
|
|
251
|
+
`rails_get_service_pattern` no longer answers a mailer, concern or mixin by
|
|
252
|
+
name when its listing leaves them out.
|
|
253
|
+
- **`app/concerns` reads as `other`** when the app root directory is itself
|
|
254
|
+
named `app`, as in Docker's `/app`.
|
|
255
|
+
- **The static default locale reads `Rails.application.config.i18n`** in an
|
|
256
|
+
initializer, where the last assignment wins.
|
|
257
|
+
- **A bad value for a required enum fails the call.**
|
|
258
|
+
`migration_advisor --action bogus` said "action is required" and exited 0;
|
|
259
|
+
it says `bogus` is not a valid `action`, names the allowed values and exits 1.
|
|
260
|
+
- **`rails_diagnose` never suggests a path it refused**, refuses it with or
|
|
261
|
+
without `--line`, and prints the tier footer once.
|
|
262
|
+
- **`rails_validate` names a `belongs_to` whose key column the table lacks**
|
|
263
|
+
instead of calling that column unindexed, and says nothing about a table's
|
|
264
|
+
indexes when its schema calls a helper the reader cannot interpret (Canvas's
|
|
265
|
+
`t.replica_identity_index`), since that helper may add the index.
|
|
266
|
+
- **A multi-name `t.references :a, :b, :c` adds every column**, with its index
|
|
267
|
+
and foreign key, in the schema.rb reader and the migration replay. The replay
|
|
268
|
+
also records `foreign_key: true` on a single reference, which it dropped.
|
|
269
|
+
- **A declaration inside a block the model may not run is kept but not
|
|
270
|
+
trusted.** `has_details_table do belongs_to :parent end` put a `parent_id`
|
|
271
|
+
key on the model's own table, and `rails_validate` checked it there. Such
|
|
272
|
+
declarations are still listed, and `rails_validate`'s schema, column and
|
|
273
|
+
`:dependent` checks skip them. `with_options`, `included`, `class_methods`,
|
|
274
|
+
`concerning`, `state_machine` and `aasm` blocks run on the model and are
|
|
275
|
+
trusted as before.
|
|
276
|
+
- **A foreign key given as a constant or an expression is not read as a column
|
|
277
|
+
name**, and a composite key stays a column list in both tiers instead of the
|
|
278
|
+
text of a Ruby array.
|
|
279
|
+
- **Every column type reads as a column in the static schema**, `t.vector`,
|
|
280
|
+
`t.citext`, `t.enum`, the range and PostGIS types included, and so does a
|
|
281
|
+
column whose options sit in braces. They were left out of the table.
|
|
282
|
+
- **`attr_reader` and `alias_attribute` names count as attributes** for
|
|
283
|
+
`rails_validate`'s "column not found" check.
|
|
284
|
+
- **Filters inherited through a Devise or Doorkeeper controller.** The static
|
|
285
|
+
walk stopped at the gem class, so a controller under `Devise::` or
|
|
286
|
+
`Doorkeeper::` lost every filter its app base declares and was credited with
|
|
287
|
+
a concern that base already includes. It now continues at the base the gem's
|
|
288
|
+
initializer names (`parent_controller`, `base_controller`).
|
|
289
|
+
- **In-repo route files are read statically.** A mounted in-repo engine's own
|
|
290
|
+
routes are listed under its mount, and a file that draws, appends or prepends
|
|
291
|
+
to the app's routes adds to the app's table; only an unmounted engine's file
|
|
292
|
+
still counts as not read.
|
|
293
|
+
- **A failed boot names missing gems once.** A bundle missing many gems listed
|
|
294
|
+
every name three times; the banner now gives the count and the first few,
|
|
295
|
+
and `doctor` and `DEBUG=1` keep the full list.
|
|
296
|
+
- **A test file over `max_test_file_size` is named as too large**, not missing.
|
|
297
|
+
- **`rails_runtime_info` says how many rows it left out** of the unused-index
|
|
298
|
+
list and the summary table sizes, which it cut at 10 and 5 with no note.
|
|
299
|
+
- **`rails_query` on MySQL** reads a `MAX_EXECUTION_TIME` interruption as the
|
|
300
|
+
timeout, and names `INTO OUTFILE`/`DUMPFILE` as a disk write.
|
|
301
|
+
- The defaults in `configuration.rb`'s comments match the values it sets.
|
|
302
|
+
|
|
8
303
|
## [5.30.1] - 2026-09-28
|
|
9
304
|
|
|
10
305
|
### Fixed
|
data/docs/CLI.md
CHANGED
|
@@ -36,7 +36,7 @@ rails-ai-context serve --transport http --port 6029 # HTTP transport
|
|
|
36
36
|
| Option | Default | Description |
|
|
37
37
|
|:-------|:--------|:------------|
|
|
38
38
|
| `--transport` | `stdio` | `stdio` or `http` |
|
|
39
|
-
| `--port` | `6029` | HTTP listen port |
|
|
39
|
+
| `--port` | `http_port` from config, else `6029` | HTTP listen port |
|
|
40
40
|
| `--no-boot` | off | Skip booting the app; answer from source alone |
|
|
41
41
|
|
|
42
42
|
### `tool`
|
data/docs/COMPATIBILITY.md
CHANGED
|
@@ -215,7 +215,14 @@ Proof sources:
|
|
|
215
215
|
PostgreSQL 17 with a partitioned table added, booted and static from
|
|
216
216
|
schema.rb and structure.sql, a Rails 7.2 app whose schema.rb carries no
|
|
217
217
|
partition marker, and Discourse, Mastodon, OpenFoodNetwork and Forem
|
|
218
|
-
answering as before.
|
|
218
|
+
answering as before. In the v5.30.2 release QA: 14 real apps answered by
|
|
219
|
+
v5.30.1 and by the release branch side by side, and the lab regressions on
|
|
220
|
+
SQLite in all three tiers, PostgreSQL and MySQL. In the v5.31.0 release QA:
|
|
221
|
+
a private Rails 8.0 API app booted and static, and Discourse, Mastodon,
|
|
222
|
+
Forem, OpenFoodNetwork, OpenProject, Consul, Canvas and Errbit answered by
|
|
223
|
+
v5.30.2 and by the release branch side by side, every changed answer
|
|
224
|
+
checked against the app's source; the lab regressions on SQLite in all three
|
|
225
|
+
tiers, PostgreSQL and MySQL; and the unit suite on Ruby 3.1 with Rails 7.0.
|
|
219
226
|
2. Non-crash coverage for every built-in tool including `get_view` in
|
|
220
227
|
`spec/e2e/in_gemfile_install_spec.rb`'s full-tool sweep; output correctness
|
|
221
228
|
(ivar cross-check, render-form detection, partial interfaces) verified
|
|
@@ -275,12 +282,21 @@ Postgres instance in `spec/e2e/postgres_install_spec.rb`, opt-in via
|
|
|
275
282
|
stay marked `[UNAVAILABLE]`. A concern whose file cannot be found, a gem's
|
|
276
283
|
module for example, is named under `Concerns` as not read.
|
|
277
284
|
- **Callbacks are what the file declares.** In both tiers the callback list is
|
|
278
|
-
what the model file, the app concerns it includes and the classes it
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
what the model file, the app concerns it includes and the classes it inherits
|
|
286
|
+
from declare. A callback a gem registers on include without an `include` line
|
|
287
|
+
in the model file (Devise, counter caches, attachment purges) is not listed.
|
|
288
|
+
Within one type the order is the order Rails runs them: base classes first, a
|
|
289
|
+
concern's callbacks where its `include` line stands, then the model's own,
|
|
290
|
+
and a `before_` or `around_` callback with `prepend: true` first.
|
|
291
|
+
`after_commit` and `after_rollback` run last declared first unless
|
|
292
|
+
`run_after_transaction_callbacks_in_order_defined` is on (`load_defaults 7.1`
|
|
293
|
+
or later; Rails 7.0 has no such setting). The booted tier reads the setting;
|
|
294
|
+
the static tier reads `load_defaults` and any assignment in
|
|
295
|
+
`config/application.rb` or an initializer, the last line that sets it
|
|
296
|
+
winning, and when those do not say, keeps declaration order and the answer
|
|
297
|
+
says so. The static tier does not read `config/environments/*.rb` for this
|
|
298
|
+
setting or for `belongs_to_required_by_default`, so a value set per
|
|
299
|
+
environment is missed. The order across types is Rails' event order.
|
|
284
300
|
- **Concern-style Mongoid documents in runtime results.** Mongoid documents
|
|
285
301
|
are invisible to ActiveRecord reflection, so `ModelIntrospector#call` falls
|
|
286
302
|
back to the same source-parsing pass used in the static tier even when the
|
data/docs/CONFIGURATION.md
CHANGED
|
@@ -86,7 +86,7 @@ config file is written. Before v5.27.0 an empty list wrote every tool's files.
|
|
|
86
86
|
| `preset` | Symbol | `:full` | `:full` (40 introspectors) or `:standard` (17 introspectors) |
|
|
87
87
|
| `context_mode` | Symbol | `:compact` | `:compact` (context files capped at ~150 lines) or `:full` (no line cap) |
|
|
88
88
|
| `introspectors` | Array of symbols | (from preset) | Override the introspector list directly |
|
|
89
|
-
| `generate_root_files` | Boolean | `true` | Set `false` to generate split rules only
|
|
89
|
+
| `generate_root_files` | Boolean | `true` | Set `false` to generate split rules only: no CLAUDE.md, AGENTS.md, .cursorrules or copilot-instructions.md (`.ai-context.json` is still written) |
|
|
90
90
|
| `anti_hallucination_rules` | Boolean | `true` | Embed 6-rule verification protocol in generated context files |
|
|
91
91
|
| `claude_max_lines` | Integer | `150` | Max non-blank lines in a compact context file's gem-managed block, the `<!-- BEGIN/END rails-ai-context -->` markers included. Over budget, data lines are cut and the Commands, Warnings, Rules and MCP-tools sections kept whole |
|
|
92
92
|
|
|
@@ -213,6 +213,9 @@ fits neither that shape nor the conventional one.
|
|
|
213
213
|
|:-------|:-----|:--------|:------------|
|
|
214
214
|
| `sensitive_patterns` | Array | 34 patterns | File patterns blocked from search/read (`.env*`, `*.env`, `.envrc`, `*.key`, `*.pem`, `config/credentials.yml.enc`, `config/application.yml`, `config/settings.local.yml`, `.ssh/*`, etc.) |
|
|
215
215
|
|
|
216
|
+
A placeholder such as `.env.example` stays readable unless a path pattern or
|
|
217
|
+
its exact name blocks it; see [SECURITY.md](SECURITY.md).
|
|
218
|
+
|
|
216
219
|
### Extensibility
|
|
217
220
|
|
|
218
221
|
| Option | Type | Default | Description |
|
|
@@ -247,7 +250,7 @@ Lightweight subset for faster generation:
|
|
|
247
250
|
| AI Tool | Root File | Split Rules | MCP Config |
|
|
248
251
|
|:--------|:----------|:------------|:-----------|
|
|
249
252
|
| Claude Code | `CLAUDE.md` | `.claude/rules/*.md` | `.mcp.json` |
|
|
250
|
-
| Cursor |
|
|
253
|
+
| Cursor | `.cursorrules` (legacy fallback) | `.cursor/rules/*.mdc` | `.cursor/mcp.json` |
|
|
251
254
|
| GitHub Copilot | `.github/copilot-instructions.md` | `.github/instructions/*.instructions.md` | `.vscode/mcp.json` |
|
|
252
255
|
| OpenCode | `AGENTS.md` | `app/*/AGENTS.md` | `opencode.json` |
|
|
253
256
|
| Codex CLI | (shares `AGENTS.md`) | (shares OpenCode rules) | `.codex/config.toml` |
|
data/docs/FAQ.md
CHANGED
|
@@ -126,7 +126,7 @@ Yes. The file is applied first and a `configure` block wins only the keys it ass
|
|
|
126
126
|
|
|
127
127
|
### What's `generate_root_files`?
|
|
128
128
|
|
|
129
|
-
When `true` (default), generates root files
|
|
129
|
+
When `true` (default), generates the root files: CLAUDE.md, AGENTS.md, .cursorrules and copilot-instructions.md. Set to `false` to only generate split rules (.claude/rules/, .cursor/rules/, etc.). `.ai-context.json` is written either way.
|
|
130
130
|
|
|
131
131
|
---
|
|
132
132
|
|
data/docs/GUIDE.md
CHANGED
|
@@ -826,7 +826,13 @@ rails_get_callbacks(model: "Order", detail: "full")
|
|
|
826
826
|
→ Order's callbacks with the actual method source code for each callback
|
|
827
827
|
```
|
|
828
828
|
|
|
829
|
-
**Returns:** Callbacks grouped by type, in Rails event order. Includes
|
|
829
|
+
**Returns:** Callbacks grouped by type, in Rails event order. Includes
|
|
830
|
+
concern-provided callbacks, with their bodies read from the concern file.
|
|
831
|
+
Within one type the order is the order Rails runs them, base classes first, a
|
|
832
|
+
`before_` or `around_` callback with `prepend: true` first, and
|
|
833
|
+
`after_commit`/`after_rollback` last declared first unless the app runs them in
|
|
834
|
+
order (`load_defaults 7.1`). A method declared again shows once with the later
|
|
835
|
+
declaration's conditions.
|
|
830
836
|
|
|
831
837
|
### rails_get_helper_methods
|
|
832
838
|
|
|
@@ -1353,7 +1359,7 @@ end
|
|
|
1353
1359
|
| `live_reload_debounce` | Float | `1.5` | Debounce interval in seconds for live reload |
|
|
1354
1360
|
| `server_name` | String | `"rails-ai-context"` | MCP server name |
|
|
1355
1361
|
| `server_version` | String | gem version | MCP server version |
|
|
1356
|
-
| `generate_root_files` | Boolean | `true` |
|
|
1362
|
+
| `generate_root_files` | Boolean | `true` | Set `false` to generate split rules only: no CLAUDE.md, AGENTS.md, .cursorrules or copilot-instructions.md (`.ai-context.json` is still written) |
|
|
1357
1363
|
| `anti_hallucination_rules` | Boolean | `true` | Embed 6-rule Anti-Hallucination Protocol in generated context files - set `false` to skip |
|
|
1358
1364
|
| `hydration_enabled` | Boolean | `true` | Inject schema hints into controller/view tool responses |
|
|
1359
1365
|
| `hydration_max_hints` | Integer | `5` | Max schema hints per tool response |
|
data/docs/INTROSPECTORS.md
CHANGED
|
@@ -186,7 +186,7 @@ It runs a single-pass Dispatcher that walks the AST once and feeds events to all
|
|
|
186
186
|
| CallbacksListener | All AR callback types including `around_*`, `after_touch`, `after_initialize` and `after_find`; `after_commit` with `on:` resolution; a callback object by its constant, a block as `[inline_block]`; `if:`/`unless:` kept as the source wrote them, and the options of an enclosing `with_options` block |
|
|
187
187
|
| MacrosListener | `encrypts`, `normalizes`, `delegate`, `has_secure_password`, `serialize`, `store`, `has_one_attached`, `has_many_attached`, `has_rich_text`, `generates_token_for`, `attribute` |
|
|
188
188
|
| MethodsListener | `def`/`def self.`, visibility tracking, parameter extraction, `class << self`; `include_initialize: true` adds the constructor a caller reports on its own |
|
|
189
|
-
| MixinsListener | `include`, `prepend`, `extend`, flagging the ones that reach the ancestor chain |
|
|
189
|
+
| MixinsListener | `include`, `prepend`, `extend`, `singleton_class.include` and `singleton_class.prepend` (`singleton_class.extend` is not read), flagging the ones that reach the ancestor chain, as reflection reports them |
|
|
190
190
|
|
|
191
191
|
### The targeted-walk listeners
|
|
192
192
|
|
|
@@ -214,8 +214,13 @@ Passed to `SourceIntrospector.walk(path, key => Listener)` when a specific file
|
|
|
214
214
|
| MailboxRoutingListener | Action Mailbox `routing` and processing callbacks |
|
|
215
215
|
| ModelReferenceListener | Model constants used in controllers: `Post.find`, `params.require(:post)`, ivar writes |
|
|
216
216
|
| VariantCallListener | `variant` calls (ChainedCallListener with `:variant` preset) |
|
|
217
|
+
| ProcLiteralListener | Proc literals: line, source, assigned constant |
|
|
217
218
|
| MethodCallListener | Call sites by name or pattern anywhere in a file, inside a `def`, a lambda or a block included, with arguments, options, receiver and line. Used by the Turbo introspector for broadcast calls and by `ActionFilters` for the skip macros |
|
|
218
219
|
|
|
220
|
+
`GenericMacroListener.new(*names, block_source: [:name])` adds `block`, the
|
|
221
|
+
one-line source of the block those macros are given. ProcLiteralListener is
|
|
222
|
+
what the job introspector reads a `queue_as` Proc with.
|
|
223
|
+
|
|
219
224
|
### Adding a listener
|
|
220
225
|
|
|
221
226
|
1. Subclass `BaseListener` in `lib/rails_ai_context/introspectors/listeners/`. Use its helpers rather than re-reading nodes: `extract_symbol_args`, `extract_keyword_options`, `extract_arg_values` (source-slice fallback for expressions like `2.hours`), `extract_keyword_sources`, `extract_keyword_nodes`, `keyword_hash`, `constant_path_string`.
|
data/docs/SECURITY.md
CHANGED
|
@@ -66,10 +66,23 @@ After validation, the query runs inside a transaction:
|
|
|
66
66
|
|:---------|:----------|
|
|
67
67
|
| PostgreSQL | `SET TRANSACTION READ ONLY` + `SET LOCAL statement_timeout` |
|
|
68
68
|
| MySQL | `SET TRANSACTION READ ONLY` + `MAX_EXECUTION_TIME` hint |
|
|
69
|
-
| SQLite |
|
|
69
|
+
| SQLite | A read-only connection in a child process, killed at timeout |
|
|
70
70
|
|
|
71
71
|
All queries execute inside a transaction, then rollback (even if they could write, they can't).
|
|
72
72
|
|
|
73
|
+
A SQLite query runs in-process under `PRAGMA query_only = ON`, with no time
|
|
74
|
+
limit, for an in-memory database, on a platform without `fork`, or when it
|
|
75
|
+
needs a function, virtual-table module, collation or encryption key only the
|
|
76
|
+
app's own connection has. The table and EXPLAIN answers then say so; CSV output
|
|
77
|
+
stays plain data.
|
|
78
|
+
|
|
79
|
+
On sqlite3 1.x a query fails at its timeout, with the statement-timeout error,
|
|
80
|
+
when another connection in the same process held an exclusive lock on a
|
|
81
|
+
rollback-journal database as it started (`BEGIN EXCLUSIVE`): the child
|
|
82
|
+
inherits that lock record and it never clears. A lock held
|
|
83
|
+
by another process is waited on as usual, and an open write transaction or any
|
|
84
|
+
lock in WAL mode does not block it.
|
|
85
|
+
|
|
73
86
|
### Layer 3 - Row limit
|
|
74
87
|
|
|
75
88
|
- Default: 100 rows
|
|
@@ -90,6 +103,9 @@ If one of your own columns merely looks sensitive (an `oauth_applications.secret
|
|
|
90
103
|
config.query_allowed_columns = %w[secret]
|
|
91
104
|
```
|
|
92
105
|
|
|
106
|
+
The exemption covers the results too: an allowed name comes back unredacted. A
|
|
107
|
+
column declared with `encrypts` stays `[FILTERED]` either way.
|
|
108
|
+
|
|
93
109
|
### Environment guard
|
|
94
110
|
|
|
95
111
|
> [!WARNING]
|
|
@@ -115,6 +131,12 @@ config/mongoid.yml config/redis.yml
|
|
|
115
131
|
.ssh/* .aws/credentials .aws/config .netrc .pgpass .my.cnf
|
|
116
132
|
```
|
|
117
133
|
|
|
134
|
+
A placeholder whose name ends in `.example`, `.sample`, `.template` or
|
|
135
|
+
`.dist` (`.env.example`) is committed to be read, so a basename glob such as
|
|
136
|
+
`.env.*` does not block it. A pattern that names it exactly, with no glob
|
|
137
|
+
characters, still does, and so does a path pattern (one with a `/`, such as
|
|
138
|
+
`.ssh/*`), which covers everything under it.
|
|
139
|
+
|
|
118
140
|
### AI context file exclusions
|
|
119
141
|
|
|
120
142
|
Search also excludes generated AI context files to prevent circular references:
|
data/docs/TOOLS.md
CHANGED
|
@@ -179,8 +179,17 @@ Concerns as `[UNAVAILABLE]` rather than dropped.
|
|
|
179
179
|
Callbacks grouped by type, in Rails event order, with source code. The list
|
|
180
180
|
covers concern-declared callbacks too, with the body read from the concern
|
|
181
181
|
file, and the "From Concerns" section says which concern declared each one.
|
|
182
|
-
Within one type the order is
|
|
183
|
-
its
|
|
182
|
+
Within one type the order is the order Rails runs them: base classes first, a
|
|
183
|
+
concern's callbacks where its `include` line stands, then the model's own, and
|
|
184
|
+
a `before_` or `around_` callback with `prepend: true` first. `after_commit`
|
|
185
|
+
and `after_rollback` are last declared first unless the app turns on
|
|
186
|
+
`run_after_transaction_callbacks_in_order_defined` (`load_defaults 7.1`). A
|
|
187
|
+
method declared again for one type shows once, with the later declaration's
|
|
188
|
+
conditions, as Rails keeps it. The order is read from source in both tiers,
|
|
189
|
+
and dynamic dispatch is not evaluated: a callback registered through
|
|
190
|
+
`send(:before_save, ...)`, through a method called with `send` or defined with
|
|
191
|
+
`define_singleton_method`, or through a module included in `class << self` is
|
|
192
|
+
not read, so the list can miss it or show the definition it replaces.
|
|
184
193
|
|
|
185
194
|
| Parameter | Type | Default | Description |
|
|
186
195
|
|:----------|:-----|:--------|:------------|
|
data/exe/rails-ai-context
CHANGED
|
@@ -175,15 +175,14 @@ class RailsAiContextCLI < Thor
|
|
|
175
175
|
|
|
176
176
|
desc "serve", "Start MCP server (stdio transport)"
|
|
177
177
|
option :transport, type: :string, default: "stdio", desc: "Transport: stdio or http"
|
|
178
|
-
option :port, type: :numeric,
|
|
178
|
+
option :port, type: :numeric, desc: "HTTP port (only for http transport; default: config http_port, else 6029)"
|
|
179
179
|
option :no_boot, type: :boolean, default: false, desc: "Skip booting the app; serve static analysis only"
|
|
180
180
|
def serve
|
|
181
181
|
boot_rails!(command: "serve", allow_static: true)
|
|
182
182
|
|
|
183
183
|
transport = options[:transport].to_sym
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
end
|
|
184
|
+
# No Thor default: it would overwrite the config file's http_port.
|
|
185
|
+
::RailsAiContext.configuration.http_port = options[:port] if options[:port]
|
|
187
186
|
|
|
188
187
|
::RailsAiContext.start_mcp_server(transport: transport)
|
|
189
188
|
end
|