rails-ai-context 5.35.0 → 5.35.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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -0
  3. data/CONTEXT.md +37 -7
  4. data/CONTRIBUTING.md +30 -1
  5. data/README.md +9 -9
  6. data/SECURITY.md +2 -2
  7. data/docs/ARCHITECTURE.md +12 -4
  8. data/docs/CLI.md +44 -15
  9. data/docs/COMPATIBILITY.md +34 -8
  10. data/docs/CONFIGURATION.md +28 -5
  11. data/docs/CUSTOM_TOOLS.md +8 -2
  12. data/docs/FAQ.md +5 -5
  13. data/docs/GUIDE.md +33 -65
  14. data/docs/INTROSPECTORS.md +4 -4
  15. data/docs/QUICKSTART.md +1 -1
  16. data/docs/RECIPES.md +5 -5
  17. data/docs/RELEASING.md +3 -1
  18. data/docs/SECURITY.md +255 -74
  19. data/docs/SETUP.md +1 -1
  20. data/docs/STANDALONE.md +2 -2
  21. data/docs/TOOLS.md +151 -90
  22. data/docs/TROUBLESHOOTING.md +123 -8
  23. data/docs/_config.yml +1 -1
  24. data/docs/adr/0008-query-runs-only-where-it-can-guard.md +38 -0
  25. data/docs/adr/0009-dbhub-shapes-in-ruby.md +26 -0
  26. data/docs/adr/0010-one-config-tool-with-sections.md +32 -0
  27. data/docs/index.md +2 -2
  28. data/exe/rails-ai-context +24 -9
  29. data/lib/generators/rails_ai_context/install/install_generator.rb +2 -0
  30. data/lib/rails_ai_context/app_databases.rb +377 -0
  31. data/lib/rails_ai_context/app_kind.rb +2 -0
  32. data/lib/rails_ai_context/cli/app_root.rb +1 -0
  33. data/lib/rails_ai_context/cli/tool_runner.rb +110 -99
  34. data/lib/rails_ai_context/configuration.rb +15 -8
  35. data/lib/rails_ai_context/database_family/mysql_runtime.rb +170 -0
  36. data/lib/rails_ai_context/database_family/postgresql_plan.rb +124 -0
  37. data/lib/rails_ai_context/database_family/postgresql_runtime.rb +211 -0
  38. data/lib/rails_ai_context/database_family/sqlite_runtime.rb +391 -0
  39. data/lib/rails_ai_context/database_family.rb +282 -0
  40. data/lib/rails_ai_context/database_file.rb +61 -7
  41. data/lib/rails_ai_context/database_yml.rb +7 -29
  42. data/lib/rails_ai_context/doctor.rb +15 -16
  43. data/lib/rails_ai_context/instrumentation.rb +1 -1
  44. data/lib/rails_ai_context/introspectors/connection_pool_introspector.rb +8 -23
  45. data/lib/rails_ai_context/introspectors/database_stats_introspector.rb +6 -70
  46. data/lib/rails_ai_context/introspectors/declared_constant.rb +19 -7
  47. data/lib/rails_ai_context/introspectors/env_introspector.rb +1 -1
  48. data/lib/rails_ai_context/introspectors/env_references.rb +1 -1
  49. data/lib/rails_ai_context/introspectors/job_introspector.rb +7 -7
  50. data/lib/rails_ai_context/introspectors/migration_introspector.rb +8 -11
  51. data/lib/rails_ai_context/introspectors/migration_replay/statements.rb +9 -9
  52. data/lib/rails_ai_context/introspectors/model_introspector.rb +33 -39
  53. data/lib/rails_ai_context/introspectors/multi_database_introspector.rb +33 -30
  54. data/lib/rails_ai_context/introspectors/node_source.rb +2 -0
  55. data/lib/rails_ai_context/introspectors/performance_introspector.rb +80 -24
  56. data/lib/rails_ai_context/introspectors/pg_partitions.rb +1 -4
  57. data/lib/rails_ai_context/introspectors/schema_conventions.rb +6 -8
  58. data/lib/rails_ai_context/introspectors/schema_dump_path.rb +12 -14
  59. data/lib/rails_ai_context/introspectors/schema_introspector.rb +47 -27
  60. data/lib/rails_ai_context/introspectors/schema_reader.rb +1 -1
  61. data/lib/rails_ai_context/introspectors/source_scan.rb +39 -4
  62. data/lib/rails_ai_context/migration_status.rb +18 -46
  63. data/lib/rails_ai_context/payload.rb +48 -1
  64. data/lib/rails_ai_context/pending_migrations.rb +3 -4
  65. data/lib/rails_ai_context/run_cache.rb +5 -0
  66. data/lib/rails_ai_context/schema_adapter.rb +13 -18
  67. data/lib/rails_ai_context/secret_columns.rb +506 -0
  68. data/lib/rails_ai_context/serializers/claude_rules_serializer.rb +2 -2
  69. data/lib/rails_ai_context/serializers/markdown_serializer.rb +14 -10
  70. data/lib/rails_ai_context/serializers/section_facts.rb +12 -2
  71. data/lib/rails_ai_context/serializers/stack_overview_helper.rb +5 -2
  72. data/lib/rails_ai_context/serializers/tool_guide_helper.rb +35 -7
  73. data/lib/rails_ai_context/server.rb +143 -29
  74. data/lib/rails_ai_context/sql_gate.rb +1007 -0
  75. data/lib/rails_ai_context/tasks/rails_ai_context.rake +1 -2
  76. data/lib/rails_ai_context/test_helper.rb +3 -1
  77. data/lib/rails_ai_context/tools/analyze_feature.rb +11 -7
  78. data/lib/rails_ai_context/tools/base_tool.rb +71 -48
  79. data/lib/rails_ai_context/tools/dependency_graph.rb +1 -1
  80. data/lib/rails_ai_context/tools/diagnose.rb +105 -42
  81. data/lib/rails_ai_context/tools/generate_test.rb +4 -6
  82. data/lib/rails_ai_context/tools/get_active_support.rb +1 -6
  83. data/lib/rails_ai_context/tools/get_api.rb +1 -6
  84. data/lib/rails_ai_context/tools/get_autoload.rb +1 -6
  85. data/lib/rails_ai_context/tools/get_callbacks.rb +5 -5
  86. data/lib/rails_ai_context/tools/get_component_catalog.rb +6 -7
  87. data/lib/rails_ai_context/tools/get_concern.rb +6 -6
  88. data/lib/rails_ai_context/tools/get_config.rb +189 -12
  89. data/lib/rails_ai_context/tools/get_context.rb +111 -105
  90. data/lib/rails_ai_context/tools/get_controllers.rb +8 -5
  91. data/lib/rails_ai_context/tools/get_conventions.rb +1 -6
  92. data/lib/rails_ai_context/tools/get_engines.rb +1 -6
  93. data/lib/rails_ai_context/tools/get_env.rb +1 -6
  94. data/lib/rails_ai_context/tools/get_env_config.rb +2 -8
  95. data/lib/rails_ai_context/tools/get_frontend_stack.rb +1 -6
  96. data/lib/rails_ai_context/tools/get_gems.rb +1 -6
  97. data/lib/rails_ai_context/tools/get_helper_methods.rb +4 -5
  98. data/lib/rails_ai_context/tools/get_i18n.rb +1 -7
  99. data/lib/rails_ai_context/tools/get_job_pattern.rb +1 -1
  100. data/lib/rails_ai_context/tools/get_mailers.rb +1 -1
  101. data/lib/rails_ai_context/tools/get_model_details.rb +5 -8
  102. data/lib/rails_ai_context/tools/get_partial_interface.rb +3 -4
  103. data/lib/rails_ai_context/tools/get_schema.rb +10 -8
  104. data/lib/rails_ai_context/tools/get_service_pattern.rb +60 -24
  105. data/lib/rails_ai_context/tools/get_turbo_map.rb +1 -1
  106. data/lib/rails_ai_context/tools/migration_advisor.rb +47 -32
  107. data/lib/rails_ai_context/tools/onboard.rb +24 -24
  108. data/lib/rails_ai_context/tools/performance_check.rb +15 -2
  109. data/lib/rails_ai_context/tools/query.rb +142 -1356
  110. data/lib/rails_ai_context/tools/read_logs.rb +1 -1
  111. data/lib/rails_ai_context/tools/review_changes.rb +6 -7
  112. data/lib/rails_ai_context/tools/runtime_info.rb +125 -88
  113. data/lib/rails_ai_context/tools/safe_call.rb +70 -28
  114. data/lib/rails_ai_context/tools/search_code.rb +0 -4
  115. data/lib/rails_ai_context/tools/search_docs.rb +3 -1
  116. data/lib/rails_ai_context/tools/security_scan.rb +9 -5
  117. data/lib/rails_ai_context/tools/session_context.rb +18 -12
  118. data/lib/rails_ai_context/tools/validate.rb +1 -0
  119. data/lib/rails_ai_context/tools/validate_semantics.rb +5 -5
  120. data/lib/rails_ai_context/version.rb +1 -1
  121. data/lib/rails_ai_context.rb +4 -7
  122. data/server.json +2 -2
  123. metadata +14 -3
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "time"
4
+
3
5
  module RailsAiContext
4
6
  module Tools
5
7
  class SessionContext < BaseTool
@@ -24,7 +26,7 @@ module RailsAiContext
24
26
  )
25
27
 
26
28
  guide_row(
27
- order: 39,
29
+ order: 34,
28
30
  mcp: "rails_session_context(action:\"status\")",
29
31
  cli_args: "action=status",
30
32
  summary: "Track what you've already queried, avoid redundant calls"
@@ -39,9 +41,11 @@ module RailsAiContext
39
41
 
40
42
  if mark
41
43
  tool, params = parse_mark(mark)
42
- known = known_tool_name(tool)
44
+ known, section = known_tool(tool)
43
45
  return error_response(unknown_mark_message(tool)) unless known
44
46
 
47
+ # A recorded call's parameters run in name order, and `section` follows every other a section reads.
48
+ params = [ params, "section:#{section.name}" ].reject(&:empty?).join(",") if section
45
49
  session_record(known, params)
46
50
  return text_response("Marked `#{known}` with params `#{echo_input(params)}` as queried.")
47
51
  end
@@ -57,8 +61,6 @@ module RailsAiContext
57
61
  else
58
62
  text_response("Unknown action: #{echo_input(action)}. Use status, summary, or reset.")
59
63
  end
60
- rescue => e
61
- text_response("Session context error: #{e.message}")
62
64
  end
63
65
 
64
66
  class << self
@@ -71,22 +73,26 @@ module RailsAiContext
71
73
  [ tool, params ]
72
74
  end
73
75
 
74
- # The tool a mark names, spelled the way the server names it, so a
75
- # mark and the call it stands for are one entry. Takes the short forms
76
- # the CLI takes (`schema`, `get_schema`). An empty or unknown name
77
- # recorded a query nothing could ever have answered.
78
- def known_tool_name(name)
76
+ # The tool a mark names, spelled as the server names it, so a mark and the call it stands for are one
77
+ # entry, with the config section a retired name stands for. Takes the short forms the CLI takes.
78
+ def known_tool(name)
79
79
  return nil if name.to_s.empty?
80
80
 
81
- tools = RailsAiContext::CLI::ToolRunner.available_tools.map(&:tool_name)
82
- [ name, "rails_#{name}", "rails_get_#{name}" ].find { |candidate| tools.include?(candidate) }
81
+ candidates = RailsAiContext::CLI::ToolRunner.candidate_names(name)
82
+ tools = RailsAiContext::Server.exposed_tools.map(&:tool_name)
83
+ found = candidates.find { |candidate| tools.include?(candidate) }
84
+ return [ found, nil ] if found
85
+
86
+ section = candidates.filter_map { |candidate| GetConfig.retired_section(candidate) }.find(&:served?)
87
+ [ "rails_get_config", section ] if section
83
88
  end
84
89
 
85
90
  def unknown_mark_message(name)
86
91
  usage = "Pass `tool:params`, e.g. `get_schema:users`."
87
92
  return "`mark` names no tool. #{usage}" if name.to_s.empty?
88
93
 
89
- short_names = RailsAiContext::CLI::ToolRunner.available_tools.map { |t| RailsAiContext::CLI::ToolRunner.short_name(t.tool_name) }
94
+ names = RailsAiContext::Server.exposed_tools.map(&:tool_name) | RailsAiContext::Server.retired_names
95
+ short_names = names.map { |tool_name| RailsAiContext::CLI::ToolRunner.short_name(tool_name) }
90
96
  suggestion = find_closest_match(name, short_names)
91
97
  "Unknown tool '#{echo_input(name)}' in `mark`.#{" Did you mean '#{suggestion}'?" if suggestion} #{usage}"
92
98
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pathname"
3
4
  require "open3"
4
5
  require "json"
5
6
  require "set"
@@ -514,7 +514,7 @@ module RailsAiContext
514
514
 
515
515
  private_class_method def self.check_column_references_ast(file, visitor, context)
516
516
  warnings = []
517
- return warnings unless file.start_with?("app/models/") && !file.include?("/concerns/")
517
+ return warnings unless file.start_with?("app/models/")
518
518
 
519
519
  valid = model_valid_columns(file, context)
520
520
  return warnings unless valid
@@ -534,7 +534,7 @@ module RailsAiContext
534
534
  # Regex fallback
535
535
  private_class_method def self.check_column_references_regex(file, content, context)
536
536
  warnings = []
537
- return warnings unless file.start_with?("app/models/") && !file.include?("/concerns/")
537
+ return warnings unless file.start_with?("app/models/")
538
538
 
539
539
  valid = model_valid_columns(file, context)
540
540
  return warnings unless valid
@@ -647,7 +647,7 @@ module RailsAiContext
647
647
 
648
648
  private_class_method def self.check_callback_existence_ast(file, visitor, context)
649
649
  warnings = []
650
- return warnings unless file.start_with?("app/models/") && !file.include?("/concerns/")
650
+ return warnings unless file.start_with?("app/models/")
651
651
  return warnings if visitor.callback_registrations.empty?
652
652
 
653
653
  models = Payload.models(context)
@@ -740,7 +740,7 @@ module RailsAiContext
740
740
  # `:versions`) has no line in the app to fix.
741
741
  private_class_method def self.check_has_many_dependent(file, context, content)
742
742
  warnings = []
743
- return warnings unless file.start_with?("app/models/") && !file.include?("/concerns/")
743
+ return warnings unless file.start_with?("app/models/")
744
744
 
745
745
  models = Payload.models(context)
746
746
  return warnings if models.empty?
@@ -767,7 +767,7 @@ module RailsAiContext
767
767
 
768
768
  private_class_method def self.check_missing_fk_index(file, context)
769
769
  warnings = []
770
- return warnings unless file.start_with?("app/models/") && !file.include?("/concerns/")
770
+ return warnings unless file.start_with?("app/models/")
771
771
 
772
772
  schema = Payload.section(context, :schema)
773
773
  models = Payload.models(context)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsAiContext
4
- VERSION = "5.35.0"
4
+ VERSION = "5.35.2"
5
5
  end
@@ -6,17 +6,14 @@ require "zeitwerk"
6
6
  # boot that copy is the one on the load path.
7
7
  require "logger"
8
8
 
9
- # Introspectors and tools lean on ActiveSupport's core extensions (camelize,
10
- # underscore, deep_dup, presence, ...) without requiring them individually.
11
- # In runtime tier that's harmless - booting the host Rails app loads all of
12
- # ActiveSupport as a side effect before any of this code runs. In static
13
- # tier nothing boots Rails, so those methods are only defined by accident of
14
- # which introspector happens to run first. Requiring them here up front
15
- # makes both tiers behave the same regardless of load order.
9
+ # The static tier boots no Rails, so the core extensions the gem leans on load here.
10
+ # active_support first: on 7.1 array/conversions calls ActiveSupport.deprecator as it loads.
11
+ require "active_support"
16
12
  require "active_support/core_ext/string/inflections"
17
13
  require "active_support/core_ext/string/filters"
18
14
  require "active_support/core_ext/object/deep_dup"
19
15
  require "active_support/core_ext/object/blank"
16
+ require "active_support/core_ext/array/conversions"
20
17
 
21
18
  # Same reason, for two stdlib constants. `Set` is autoloaded on newer Rubies
22
19
  # and not on the oldest one supported here; `Date` is never autoloaded. Both
data/server.json CHANGED
@@ -2,12 +2,12 @@
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
3
  "name": "io.github.crisnahine/rails-ai-context",
4
4
  "title": "Rails AI Context",
5
- "description": "45 MCP tools give AI agents live Rails schema, routes, models, and conventions.",
5
+ "description": "35 MCP tools give AI agents live Rails schema, routes, models, and conventions.",
6
6
  "repository": {
7
7
  "url": "https://github.com/crisnahine/rails-ai-context",
8
8
  "source": "github"
9
9
  },
10
- "version": "5.35.0",
10
+ "version": "5.35.2",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "mcpb",
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: 5.35.0
4
+ version: 5.35.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - crisnahine
@@ -210,7 +210,7 @@ dependencies:
210
210
  description: |
211
211
  rails-ai-context turns your running Rails app into the source of truth for AI
212
212
  coding assistants. Instead of guessing from training data or stale file reads,
213
- agents query 45 live tools (via MCP server or CLI) to get your actual schema,
213
+ agents query 35 live tools (via MCP server or CLI) to get your actual schema,
214
214
  associations, routes, inherited filters, conventions, and test patterns.
215
215
  Semantic validation catches cross-file errors (wrong columns, missing partials,
216
216
  broken routes) before code runs - so AI writes correct code on the first try.
@@ -264,6 +264,9 @@ files:
264
264
  - docs/adr/0005-workspace-mcp-entries.md
265
265
  - docs/adr/0006-strong-params-resolve-as-ruby-runs.md
266
266
  - docs/adr/0007-every-install-question-has-a-flag.md
267
+ - docs/adr/0008-query-runs-only-where-it-can-guard.md
268
+ - docs/adr/0009-dbhub-shapes-in-ruby.md
269
+ - docs/adr/0010-one-config-tool-with-sections.md
267
270
  - docs/agents/domain.md
268
271
  - docs/agents/issue-tracker.md
269
272
  - docs/agents/triage-labels.md
@@ -275,6 +278,7 @@ files:
275
278
  - lib/rails_ai_context/action_filters.rb
276
279
  - lib/rails_ai_context/action_outcome.rb
277
280
  - lib/rails_ai_context/app_commands.rb
281
+ - lib/rails_ai_context/app_databases.rb
278
282
  - lib/rails_ai_context/app_kind.rb
279
283
  - lib/rails_ai_context/ast_cache.rb
280
284
  - lib/rails_ai_context/base_mixins.rb
@@ -295,6 +299,11 @@ files:
295
299
  - lib/rails_ai_context/context_file_report.rb
296
300
  - lib/rails_ai_context/count_phrase.rb
297
301
  - lib/rails_ai_context/data/docs/index.json
302
+ - lib/rails_ai_context/database_family.rb
303
+ - lib/rails_ai_context/database_family/mysql_runtime.rb
304
+ - lib/rails_ai_context/database_family/postgresql_plan.rb
305
+ - lib/rails_ai_context/database_family/postgresql_runtime.rb
306
+ - lib/rails_ai_context/database_family/sqlite_runtime.rb
298
307
  - lib/rails_ai_context/database_file.rb
299
308
  - lib/rails_ai_context/database_yml.rb
300
309
  - lib/rails_ai_context/detail_level.rb
@@ -493,6 +502,7 @@ files:
493
502
  - lib/rails_ai_context/schema_adapter.rb
494
503
  - lib/rails_ai_context/schema_hint.rb
495
504
  - lib/rails_ai_context/schema_version.rb
505
+ - lib/rails_ai_context/secret_columns.rb
496
506
  - lib/rails_ai_context/serializers.rb
497
507
  - lib/rails_ai_context/serializers/base.rb
498
508
  - lib/rails_ai_context/serializers/claude_rules_serializer.rb
@@ -514,6 +524,7 @@ files:
514
524
  - lib/rails_ai_context/serializers/test_command_detection.rb
515
525
  - lib/rails_ai_context/serializers/tool_guide_helper.rb
516
526
  - lib/rails_ai_context/server.rb
527
+ - lib/rails_ai_context/sql_gate.rb
517
528
  - lib/rails_ai_context/static_app.rb
518
529
  - lib/rails_ai_context/tasks/rails_ai_context.rake
519
530
  - lib/rails_ai_context/test_framework.rb
@@ -614,6 +625,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
614
625
  requirements: []
615
626
  rubygems_version: 3.6.9
616
627
  specification_version: 4
617
- summary: Stop AI from guessing your Rails app. 45 tools give coding agents ground
628
+ summary: Stop AI from guessing your Rails app. 35 tools give coding agents ground
618
629
  truth - schema, models, routes, conventions - on demand. MCP or CLI.
619
630
  test_files: []