rails_console_ai 0.13.0 → 0.14.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +17 -17
  4. data/app/controllers/rails_console_ai/application_controller.rb +5 -5
  5. data/app/controllers/rails_console_ai/sessions_controller.rb +1 -1
  6. data/app/helpers/rails_console_ai/sessions_helper.rb +1 -1
  7. data/app/models/rails_console_ai/session.rb +2 -2
  8. data/app/views/layouts/rails_console_ai/application.html.erb +2 -2
  9. data/config/routes.rb +1 -1
  10. data/lib/generators/rails_console_ai/install_generator.rb +3 -3
  11. data/lib/generators/rails_console_ai/templates/initializer.rb +4 -4
  12. data/lib/rails_console_ai/channel/base.rb +1 -1
  13. data/lib/rails_console_ai/channel/console.rb +15 -15
  14. data/lib/rails_console_ai/channel/slack.rb +2 -2
  15. data/lib/rails_console_ai/configuration.rb +1 -1
  16. data/lib/rails_console_ai/console_methods.rb +19 -19
  17. data/lib/rails_console_ai/context_builder.rb +6 -6
  18. data/lib/rails_console_ai/conversation_engine.rb +29 -29
  19. data/lib/rails_console_ai/engine.rb +2 -2
  20. data/lib/rails_console_ai/executor.rb +11 -11
  21. data/lib/rails_console_ai/providers/anthropic.rb +1 -1
  22. data/lib/rails_console_ai/providers/base.rb +3 -3
  23. data/lib/rails_console_ai/providers/bedrock.rb +1 -1
  24. data/lib/rails_console_ai/providers/local.rb +1 -1
  25. data/lib/rails_console_ai/providers/openai.rb +1 -1
  26. data/lib/rails_console_ai/railtie.rb +6 -6
  27. data/lib/rails_console_ai/repl.rb +1 -1
  28. data/lib/rails_console_ai/safety_guards.rb +6 -6
  29. data/lib/rails_console_ai/session_logger.rb +13 -13
  30. data/lib/rails_console_ai/slack_bot.rb +12 -12
  31. data/lib/rails_console_ai/storage/base.rb +1 -1
  32. data/lib/rails_console_ai/storage/file_storage.rb +1 -1
  33. data/lib/rails_console_ai/tools/code_tools.rb +1 -1
  34. data/lib/rails_console_ai/tools/memory_tools.rb +4 -4
  35. data/lib/rails_console_ai/tools/model_tools.rb +1 -1
  36. data/lib/rails_console_ai/tools/registry.rb +3 -3
  37. data/lib/rails_console_ai/tools/schema_tools.rb +1 -1
  38. data/lib/rails_console_ai/version.rb +2 -2
  39. data/lib/rails_console_ai.rb +14 -14
  40. data/lib/tasks/rails_console_ai.rake +2 -2
  41. metadata +1 -1
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  class ConversationEngine
3
3
  attr_reader :history, :total_input_tokens, :total_output_tokens,
4
4
  :interactive_session_id, :session_name
@@ -65,10 +65,10 @@ module RailsConsoleAI
65
65
  log_session(@_last_log_attrs.merge(console_output: console_capture.string))
66
66
  exec_result
67
67
  rescue Providers::ProviderError => e
68
- @channel.display_error("RailsConsoleAI Error: #{e.message}")
68
+ @channel.display_error("RailsConsoleAi Error: #{e.message}")
69
69
  nil
70
70
  rescue => e
71
- @channel.display_error("RailsConsoleAI Error: #{e.class}: #{e.message}")
71
+ @channel.display_error("RailsConsoleAi Error: #{e.class}: #{e.message}")
72
72
  nil
73
73
  end
74
74
 
@@ -93,10 +93,10 @@ module RailsConsoleAI
93
93
  log_session(@_last_log_attrs.merge(console_output: console_capture.string))
94
94
  nil
95
95
  rescue Providers::ProviderError => e
96
- @channel.display_error("RailsConsoleAI Error: #{e.message}")
96
+ @channel.display_error("RailsConsoleAi Error: #{e.message}")
97
97
  nil
98
98
  rescue => e
99
- @channel.display_error("RailsConsoleAI Error: #{e.class}: #{e.message}")
99
+ @channel.display_error("RailsConsoleAi Error: #{e.class}: #{e.message}")
100
100
  nil
101
101
  end
102
102
 
@@ -115,9 +115,9 @@ module RailsConsoleAI
115
115
  end
116
116
 
117
117
  def init_guide
118
- storage = RailsConsoleAI.storage
118
+ storage = RailsConsoleAi.storage
119
119
  existing_guide = begin
120
- content = storage.read(RailsConsoleAI::GUIDE_KEY)
120
+ content = storage.read(RailsConsoleAi::GUIDE_KEY)
121
121
  (content && !content.strip.empty?) ? content.strip : nil
122
122
  rescue
123
123
  nil
@@ -134,8 +134,8 @@ module RailsConsoleAI
134
134
  sys_prompt = init_system_prompt(existing_guide)
135
135
  messages = [{ role: :user, content: "Explore this Rails application and generate the application guide." }]
136
136
 
137
- original_timeout = RailsConsoleAI.configuration.timeout
138
- RailsConsoleAI.configuration.timeout = [original_timeout, 120].max
137
+ original_timeout = RailsConsoleAi.configuration.timeout
138
+ RailsConsoleAi.configuration.timeout = [original_timeout, 120].max
139
139
 
140
140
  result, _ = send_query_with_tools(messages, system_prompt: sys_prompt, tools_override: init_tools)
141
141
 
@@ -148,8 +148,8 @@ module RailsConsoleAI
148
148
  return nil
149
149
  end
150
150
 
151
- storage.write(RailsConsoleAI::GUIDE_KEY, guide_text)
152
- path = storage.respond_to?(:root_path) ? File.join(storage.root_path, RailsConsoleAI::GUIDE_KEY) : RailsConsoleAI::GUIDE_KEY
151
+ storage.write(RailsConsoleAi::GUIDE_KEY, guide_text)
152
+ path = storage.respond_to?(:root_path) ? File.join(storage.root_path, RailsConsoleAi::GUIDE_KEY) : RailsConsoleAi::GUIDE_KEY
153
153
  $stdout.puts "\e[32m Guide saved to #{path} (#{guide_text.length} chars)\e[0m"
154
154
  display_usage(result)
155
155
  nil
@@ -157,13 +157,13 @@ module RailsConsoleAI
157
157
  $stdout.puts "\n\e[33m Interrupted.\e[0m"
158
158
  nil
159
159
  rescue Providers::ProviderError => e
160
- @channel.display_error("RailsConsoleAI Error: #{e.message}")
160
+ @channel.display_error("RailsConsoleAi Error: #{e.message}")
161
161
  nil
162
162
  rescue => e
163
- @channel.display_error("RailsConsoleAI Error: #{e.class}: #{e.message}")
163
+ @channel.display_error("RailsConsoleAi Error: #{e.class}: #{e.message}")
164
164
  nil
165
165
  ensure
166
- RailsConsoleAI.configuration.timeout = original_timeout if original_timeout
166
+ RailsConsoleAi.configuration.timeout = original_timeout if original_timeout
167
167
  end
168
168
 
169
169
  # --- Interactive session management ---
@@ -250,7 +250,7 @@ module RailsConsoleAI
250
250
  if e.message.include?("prompt is too long") && @history.length >= 6
251
251
  @channel.display_warning(" Context limit reached. Run /compact to reduce context size, then try again.")
252
252
  else
253
- @channel.display_error("RailsConsoleAI Error: #{e.class}: #{e.message}")
253
+ @channel.display_error("RailsConsoleAi Error: #{e.class}: #{e.message}")
254
254
  end
255
255
  return :error
256
256
  rescue Interrupt
@@ -271,7 +271,7 @@ module RailsConsoleAI
271
271
  return :no_code unless code && !code.strip.empty?
272
272
  return :cancelled if @channel.cancelled?
273
273
 
274
- exec_result = if RailsConsoleAI.configuration.auto_execute
274
+ exec_result = if RailsConsoleAi.configuration.auto_execute
275
275
  @executor.execute(code)
276
276
  else
277
277
  @executor.confirm_and_execute(code)
@@ -352,7 +352,7 @@ module RailsConsoleAI
352
352
 
353
353
  @token_usage.each do |model, usage|
354
354
  pricing = Configuration::PRICING[model]
355
- pricing ||= { input: 0.0, output: 0.0 } if RailsConsoleAI.configuration.provider == :local
355
+ pricing ||= { input: 0.0, output: 0.0 } if RailsConsoleAi.configuration.provider == :local
356
356
  input_str = "in: #{format_tokens(usage[:input])}"
357
357
  output_str = "out: #{format_tokens(usage[:output])}"
358
358
 
@@ -406,7 +406,7 @@ module RailsConsoleAI
406
406
  end
407
407
 
408
408
  def upgrade_to_thinking_model
409
- config = RailsConsoleAI.configuration
409
+ config = RailsConsoleAi.configuration
410
410
  current = config.resolved_model
411
411
  thinking = config.resolved_thinking_model
412
412
 
@@ -558,7 +558,7 @@ module RailsConsoleAI
558
558
  private
559
559
 
560
560
  def safety_context
561
- guards = RailsConsoleAI.configuration.safety_guards
561
+ guards = RailsConsoleAi.configuration.safety_guards
562
562
  return nil if guards.empty?
563
563
 
564
564
  if !@channel.supports_danger?
@@ -597,7 +597,7 @@ module RailsConsoleAI
597
597
  has_code = code && !code.strip.empty?
598
598
 
599
599
  if has_code
600
- exec_result = if RailsConsoleAI.configuration.auto_execute
600
+ exec_result = if RailsConsoleAi.configuration.auto_execute
601
601
  @executor.execute(code)
602
602
  else
603
603
  @executor.confirm_and_execute(code)
@@ -682,7 +682,7 @@ module RailsConsoleAI
682
682
  end
683
683
 
684
684
  def send_query(query, conversation: nil)
685
- RailsConsoleAI.configuration.validate!
685
+ RailsConsoleAi.configuration.validate!
686
686
 
687
687
  messages = if conversation
688
688
  conversation.dup
@@ -699,7 +699,7 @@ module RailsConsoleAI
699
699
  require 'rails_console_ai/tools/registry'
700
700
  tools = tools_override || Tools::Registry.new(executor: @executor, channel: @channel)
701
701
  active_system_prompt = system_prompt || context
702
- max_rounds = RailsConsoleAI.configuration.max_tool_rounds
702
+ max_rounds = RailsConsoleAi.configuration.max_tool_rounds
703
703
  total_input = 0
704
704
  total_output = 0
705
705
  result = nil
@@ -726,7 +726,7 @@ module RailsConsoleAI
726
726
  @channel.display_dim(" #{llm_status(round, messages, total_input, last_thinking, last_tool_names)}")
727
727
  end
728
728
 
729
- if RailsConsoleAI.configuration.debug
729
+ if RailsConsoleAi.configuration.debug
730
730
  debug_pre_call(round, messages, active_system_prompt, tools, total_input, total_output)
731
731
  end
732
732
 
@@ -742,7 +742,7 @@ module RailsConsoleAI
742
742
 
743
743
  break if @channel.cancelled?
744
744
 
745
- if RailsConsoleAI.configuration.debug
745
+ if RailsConsoleAi.configuration.debug
746
746
  debug_post_call(round, result, @total_input_tokens + total_input, @total_output_tokens + total_output)
747
747
  end
748
748
 
@@ -770,7 +770,7 @@ module RailsConsoleAI
770
770
  @channel.display_dim(" #{preview}#{cached_tag}")
771
771
  end
772
772
 
773
- if RailsConsoleAI.configuration.debug
773
+ if RailsConsoleAi.configuration.debug
774
774
  $stderr.puts "\e[35m[debug] tool result (#{tool_result.to_s.length} chars)\e[0m"
775
775
  end
776
776
 
@@ -786,7 +786,7 @@ module RailsConsoleAI
786
786
  end
787
787
 
788
788
  if exhausted
789
- $stdout.puts "\e[33m Hit tool round limit (#{max_rounds}). Forcing final answer. Increase with: RailsConsoleAI.configure { |c| c.max_tool_rounds = 200 }\e[0m"
789
+ $stdout.puts "\e[33m Hit tool round limit (#{max_rounds}). Forcing final answer. Increase with: RailsConsoleAi.configure { |c| c.max_tool_rounds = 200 }\e[0m"
790
790
  messages << { role: :user, content: "You've used all available tool rounds. Please provide your best answer now based on what you've learned so far." }
791
791
  result = provider.chat(messages, system_prompt: active_system_prompt)
792
792
  total_input += result.input_tokens || 0
@@ -806,7 +806,7 @@ module RailsConsoleAI
806
806
  @total_input_tokens += result.input_tokens || 0
807
807
  @total_output_tokens += result.output_tokens || 0
808
808
 
809
- model = RailsConsoleAI.configuration.resolved_model
809
+ model = RailsConsoleAi.configuration.resolved_model
810
810
  @token_usage[model][:input] += result.input_tokens || 0
811
811
  @token_usage[model][:output] += result.output_tokens || 0
812
812
  @token_usage[model][:cache_read] = (@token_usage[model][:cache_read] || 0) + (result.cache_read_input_tokens || 0)
@@ -1006,9 +1006,9 @@ module RailsConsoleAI
1006
1006
 
1007
1007
  input_t = result.input_tokens || 0
1008
1008
  output_t = result.output_tokens || 0
1009
- model = RailsConsoleAI.configuration.resolved_model
1009
+ model = RailsConsoleAi.configuration.resolved_model
1010
1010
  pricing = Configuration::PRICING[model]
1011
- pricing ||= { input: 0.0, output: 0.0 } if RailsConsoleAI.configuration.provider == :local
1011
+ pricing ||= { input: 0.0, output: 0.0 } if RailsConsoleAi.configuration.provider == :local
1012
1012
 
1013
1013
  cache_r = result.cache_read_input_tokens || 0
1014
1014
  cache_w = result.cache_write_input_tokens || 0
@@ -1,5 +1,5 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  class Engine < ::Rails::Engine
3
- isolate_namespace RailsConsoleAI
3
+ isolate_namespace RailsConsoleAi
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  require 'stringio'
2
2
 
3
- module RailsConsoleAI
3
+ module RailsConsoleAi
4
4
  # Writes to two IO streams simultaneously
5
5
  class TeeIO
6
6
  attr_reader :secondary
@@ -112,7 +112,7 @@ module RailsConsoleAI
112
112
 
113
113
  @last_output = captured_output.string
114
114
  result
115
- rescue RailsConsoleAI::SafetyError => e
115
+ rescue RailsConsoleAi::SafetyError => e
116
116
  $stdout = old_stdout if old_stdout
117
117
  @last_error = "SafetyError: #{e.message}"
118
118
  @last_safety_error = true
@@ -280,7 +280,7 @@ module RailsConsoleAI
280
280
  case answer
281
281
  when 'a', 'allow'
282
282
  if blocked_key && guard
283
- RailsConsoleAI.configuration.safety_guards.allow(guard, blocked_key)
283
+ RailsConsoleAi.configuration.safety_guards.allow(guard, blocked_key)
284
284
  allow_desc = allow_description(guard, blocked_key)
285
285
  $stdout.puts colorize("Allowed #{allow_desc} for this session.", :green)
286
286
  return execute(code)
@@ -328,7 +328,7 @@ module RailsConsoleAI
328
328
  end
329
329
 
330
330
  def execute_unsafe(code)
331
- guards = RailsConsoleAI.configuration.safety_guards
331
+ guards = RailsConsoleAi.configuration.safety_guards
332
332
  guards.disable!
333
333
  execute(code)
334
334
  ensure
@@ -336,7 +336,7 @@ module RailsConsoleAI
336
336
  end
337
337
 
338
338
  def execute_prompt
339
- guards = RailsConsoleAI.configuration.safety_guards
339
+ guards = RailsConsoleAi.configuration.safety_guards
340
340
  if !guards.empty? && guards.enabled? && danger_allowed?
341
341
  "Execute? [y/N/edit/danger] "
342
342
  else
@@ -345,26 +345,26 @@ module RailsConsoleAI
345
345
  end
346
346
 
347
347
  def with_safety_guards(&block)
348
- RailsConsoleAI.configuration.safety_guards.wrap(&block)
348
+ RailsConsoleAi.configuration.safety_guards.wrap(&block)
349
349
  end
350
350
 
351
351
  # Check if an exception is or wraps a SafetyError (e.g. AR::StatementInvalid wrapping it)
352
352
  def safety_error?(exception)
353
- return true if exception.is_a?(RailsConsoleAI::SafetyError)
354
- return true if exception.message.include?("RailsConsoleAI safe mode")
353
+ return true if exception.is_a?(RailsConsoleAi::SafetyError)
354
+ return true if exception.message.include?("RailsConsoleAi safe mode")
355
355
  cause = exception.cause
356
356
  while cause
357
- return true if cause.is_a?(RailsConsoleAI::SafetyError)
357
+ return true if cause.is_a?(RailsConsoleAi::SafetyError)
358
358
  cause = cause.cause
359
359
  end
360
360
  false
361
361
  end
362
362
 
363
363
  def extract_safety_exception(exception)
364
- return exception if exception.is_a?(RailsConsoleAI::SafetyError)
364
+ return exception if exception.is_a?(RailsConsoleAi::SafetyError)
365
365
  cause = exception.cause
366
366
  while cause
367
- return cause if cause.is_a?(RailsConsoleAI::SafetyError)
367
+ return cause if cause.is_a?(RailsConsoleAi::SafetyError)
368
368
  cause = cause.cause
369
369
  end
370
370
  nil
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Providers
3
3
  class Anthropic < Base
4
4
  API_URL = 'https://api.anthropic.com'.freeze
@@ -1,12 +1,12 @@
1
1
  require 'faraday'
2
2
  require 'json'
3
3
 
4
- module RailsConsoleAI
4
+ module RailsConsoleAi
5
5
  module Providers
6
6
  class Base
7
7
  attr_reader :config
8
8
 
9
- def initialize(config = RailsConsoleAI.configuration)
9
+ def initialize(config = RailsConsoleAi.configuration)
10
10
  @config = config
11
11
  end
12
12
 
@@ -95,7 +95,7 @@ module RailsConsoleAI
95
95
  end
96
96
  end
97
97
 
98
- def self.build(config = RailsConsoleAI.configuration)
98
+ def self.build(config = RailsConsoleAi.configuration)
99
99
  case config.provider
100
100
  when :anthropic
101
101
  require 'rails_console_ai/providers/anthropic'
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Providers
3
3
  class Bedrock < Base
4
4
  def chat(messages, system_prompt: nil)
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Providers
3
3
  class Local < OpenAI
4
4
  private
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Providers
3
3
  class OpenAI < Base
4
4
  API_URL = 'https://api.openai.com'.freeze
@@ -1,6 +1,6 @@
1
1
  require 'rails_console_ai'
2
2
 
3
- module RailsConsoleAI
3
+ module RailsConsoleAi
4
4
  class Railtie < Rails::Railtie
5
5
  rake_tasks do
6
6
  load File.expand_path('../tasks/rails_console_ai.rake', __dir__)
@@ -11,23 +11,23 @@ module RailsConsoleAI
11
11
 
12
12
  # Inject into IRB if available
13
13
  if defined?(IRB::ExtendCommandBundle)
14
- IRB::ExtendCommandBundle.include(RailsConsoleAI::ConsoleMethods)
14
+ IRB::ExtendCommandBundle.include(RailsConsoleAi::ConsoleMethods)
15
15
  end
16
16
 
17
17
  # Extend TOPLEVEL_BINDING's receiver as well
18
- TOPLEVEL_BINDING.eval('self').extend(RailsConsoleAI::ConsoleMethods)
18
+ TOPLEVEL_BINDING.eval('self').extend(RailsConsoleAi::ConsoleMethods)
19
19
 
20
20
  # Welcome message
21
21
  if $stdout.respond_to?(:tty?) && $stdout.tty?
22
- $stdout.puts "\e[36m[RailsConsoleAI v#{RailsConsoleAI::VERSION}] AI assistant loaded. Try: ai \"show me all tables\"\e[0m"
22
+ $stdout.puts "\e[36m[RailsConsoleAi v#{RailsConsoleAi::VERSION}] AI assistant loaded. Try: ai \"show me all tables\"\e[0m"
23
23
  end
24
24
 
25
25
  # Pre-build context in background
26
26
  Thread.new do
27
27
  require 'rails_console_ai/context_builder'
28
- RailsConsoleAI::ContextBuilder.new.build
28
+ RailsConsoleAi::ContextBuilder.new.build
29
29
  rescue => e
30
- RailsConsoleAI.logger.debug("RailsConsoleAI: background context build failed: #{e.message}")
30
+ RailsConsoleAi.logger.debug("RailsConsoleAi: background context build failed: #{e.message}")
31
31
  end
32
32
  end
33
33
  end
@@ -1,7 +1,7 @@
1
1
  require 'rails_console_ai/channel/console'
2
2
  require 'rails_console_ai/conversation_engine'
3
3
 
4
- module RailsConsoleAI
4
+ module RailsConsoleAi
5
5
  class Repl
6
6
  def initialize(binding_context)
7
7
  @binding_context = binding_context
@@ -1,7 +1,7 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  # Raised by safety guards to block dangerous operations.
3
3
  # Host apps should raise this error in their custom guards.
4
- # RailsConsoleAI will catch it and guide the user to use 'd' or /danger.
4
+ # RailsConsoleAi will catch it and guide the user to use 'd' or /danger.
5
5
  class SafetyError < StandardError
6
6
  attr_reader :guard, :blocked_key
7
7
 
@@ -98,10 +98,10 @@ module RailsConsoleAI
98
98
  return unless Thread.current[:rails_console_ai_block_writes] && sql.match?(WRITE_PATTERN)
99
99
 
100
100
  table = sql.match(TABLE_PATTERN)&.captures&.first
101
- guards = RailsConsoleAI.configuration.safety_guards
101
+ guards = RailsConsoleAi.configuration.safety_guards
102
102
  return if table && guards.allowed?(:database_writes, table)
103
103
 
104
- raise RailsConsoleAI::SafetyError.new(
104
+ raise RailsConsoleAi::SafetyError.new(
105
105
  "Database write blocked: #{sql.strip.split(/\s+/).first(3).join(' ')}...",
106
106
  guard: :database_writes,
107
107
  blocked_key: table
@@ -157,9 +157,9 @@ module RailsConsoleAI
157
157
  def request(req, *args, &block)
158
158
  if Thread.current[:rails_console_ai_block_http] && !SAFE_METHODS.include?(req.method)
159
159
  host = @address.to_s
160
- guards = RailsConsoleAI.configuration.safety_guards
160
+ guards = RailsConsoleAi.configuration.safety_guards
161
161
  unless guards.allowed?(:http_mutations, host)
162
- raise RailsConsoleAI::SafetyError.new(
162
+ raise RailsConsoleAi::SafetyError.new(
163
163
  "HTTP #{req.method} blocked (#{host}#{req.path})",
164
164
  guard: :http_mutations,
165
165
  blocked_key: host
@@ -1,8 +1,8 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module SessionLogger
3
3
  class << self
4
4
  def log(attrs)
5
- return unless RailsConsoleAI.configuration.session_logging
5
+ return unless RailsConsoleAi.configuration.session_logging
6
6
  return unless table_exists?
7
7
 
8
8
  create_attrs = {
@@ -18,8 +18,8 @@ module RailsConsoleAI
18
18
  code_result: attrs[:code_result],
19
19
  console_output: attrs[:console_output],
20
20
  executed: attrs[:executed] || false,
21
- provider: RailsConsoleAI.configuration.provider.to_s,
22
- model: RailsConsoleAI.configuration.resolved_model,
21
+ provider: RailsConsoleAi.configuration.provider.to_s,
22
+ model: RailsConsoleAi.configuration.resolved_model,
23
23
  duration_ms: attrs[:duration_ms],
24
24
  created_at: Time.respond_to?(:current) ? Time.current : Time.now
25
25
  }
@@ -27,24 +27,24 @@ module RailsConsoleAI
27
27
  record = session_class.create!(create_attrs)
28
28
  record.id
29
29
  rescue => e
30
- msg = "RailsConsoleAI: session logging failed: #{e.class}: #{e.message}"
30
+ msg = "RailsConsoleAi: session logging failed: #{e.class}: #{e.message}"
31
31
  $stderr.puts "\e[33m#{msg}\e[0m" if $stderr.respond_to?(:puts)
32
- RailsConsoleAI.logger.warn(msg)
32
+ RailsConsoleAi.logger.warn(msg)
33
33
  nil
34
34
  end
35
35
 
36
36
  def find_by_slack_thread(thread_ts)
37
- return nil unless RailsConsoleAI.configuration.session_logging
37
+ return nil unless RailsConsoleAi.configuration.session_logging
38
38
  return nil unless table_exists?
39
39
  session_class.where(slack_thread_ts: thread_ts).order(created_at: :desc).first
40
40
  rescue => e
41
- RailsConsoleAI.logger.warn("RailsConsoleAI: session lookup failed: #{e.class}: #{e.message}")
41
+ RailsConsoleAi.logger.warn("RailsConsoleAi: session lookup failed: #{e.class}: #{e.message}")
42
42
  nil
43
43
  end
44
44
 
45
45
  def update(id, attrs)
46
46
  return unless id
47
- return unless RailsConsoleAI.configuration.session_logging
47
+ return unless RailsConsoleAi.configuration.session_logging
48
48
  return unless table_exists?
49
49
 
50
50
  updates = {}
@@ -61,9 +61,9 @@ module RailsConsoleAI
61
61
 
62
62
  session_class.where(id: id).update_all(updates) unless updates.empty?
63
63
  rescue => e
64
- msg = "RailsConsoleAI: session update failed: #{e.class}: #{e.message}"
64
+ msg = "RailsConsoleAi: session update failed: #{e.class}: #{e.message}"
65
65
  $stderr.puts "\e[33m#{msg}\e[0m" if $stderr.respond_to?(:puts)
66
- RailsConsoleAI.logger.warn(msg)
66
+ RailsConsoleAi.logger.warn(msg)
67
67
  nil
68
68
  end
69
69
 
@@ -79,11 +79,11 @@ module RailsConsoleAI
79
79
  end
80
80
 
81
81
  def session_class
82
- Object.const_get('RailsConsoleAI::Session')
82
+ Object.const_get('RailsConsoleAi::Session')
83
83
  end
84
84
 
85
85
  def current_user_name
86
- RailsConsoleAI.current_user || ENV['USER']
86
+ RailsConsoleAi.current_user || ENV['USER']
87
87
  end
88
88
  end
89
89
  end
@@ -8,16 +8,16 @@ require 'rails_console_ai/context_builder'
8
8
  require 'rails_console_ai/providers/base'
9
9
  require 'rails_console_ai/executor'
10
10
 
11
- module RailsConsoleAI
11
+ module RailsConsoleAi
12
12
  class SlackBot
13
13
  def initialize
14
- @bot_token = RailsConsoleAI.configuration.slack_bot_token || ENV['SLACK_BOT_TOKEN']
15
- @app_token = RailsConsoleAI.configuration.slack_app_token || ENV['SLACK_APP_TOKEN']
14
+ @bot_token = RailsConsoleAi.configuration.slack_bot_token || ENV['SLACK_BOT_TOKEN']
15
+ @app_token = RailsConsoleAi.configuration.slack_app_token || ENV['SLACK_APP_TOKEN']
16
16
  @channel_ids = resolve_channel_ids
17
17
 
18
18
  raise ConfigurationError, "SLACK_BOT_TOKEN is required" unless @bot_token
19
19
  raise ConfigurationError, "SLACK_APP_TOKEN is required (Socket Mode)" unless @app_token
20
- raise ConfigurationError, "slack_allowed_usernames must be configured (e.g. ['alice'] or 'ALL')" unless RailsConsoleAI.configuration.slack_allowed_usernames
20
+ raise ConfigurationError, "slack_allowed_usernames must be configured (e.g. ['alice'] or 'ALL')" unless RailsConsoleAi.configuration.slack_allowed_usernames
21
21
 
22
22
  @bot_user_id = nil
23
23
  @sessions = {} # thread_ts → { channel:, engine:, thread: }
@@ -242,7 +242,7 @@ module RailsConsoleAI
242
242
  user_id = event[:user]
243
243
  user_name = resolve_user_name(user_id)
244
244
 
245
- allowed_list = Array(RailsConsoleAI.configuration.slack_allowed_usernames).map(&:to_s).map(&:downcase)
245
+ allowed_list = Array(RailsConsoleAi.configuration.slack_allowed_usernames).map(&:to_s).map(&:downcase)
246
246
  unless allowed_list.include?('all') || allowed_list.include?(user_name.to_s.downcase)
247
247
  puts "[#{channel_id}/#{thread_ts}] @#{user_name} << (ignored — not in allowed usernames)"
248
248
  post_message(channel: channel_id, thread_ts: thread_ts, text: "Sorry, I don't recognize your username (@#{user_name}). Ask an admin to add you to the allowed usernames list.")
@@ -283,7 +283,7 @@ module RailsConsoleAI
283
283
  start_session(channel_id, thread_ts, text.strip, user_name)
284
284
  end
285
285
  rescue => e
286
- RailsConsoleAI.logger.error("SlackBot event handling error: #{e.class}: #{e.message}")
286
+ RailsConsoleAi.logger.error("SlackBot event handling error: #{e.class}: #{e.message}")
287
287
  end
288
288
 
289
289
  def start_session(channel_id, thread_ts, text, user_name)
@@ -318,7 +318,7 @@ module RailsConsoleAI
318
318
  engine.process_message(text)
319
319
  rescue => e
320
320
  channel.display_error("Error: #{e.class}: #{e.message}")
321
- RailsConsoleAI.logger.error("SlackBot session error: #{e.class}: #{e.message}\n#{e.backtrace.first(5).join("\n")}")
321
+ RailsConsoleAi.logger.error("SlackBot session error: #{e.class}: #{e.message}\n#{e.backtrace.first(5).join("\n")}")
322
322
  ensure
323
323
  ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
324
324
  end
@@ -334,7 +334,7 @@ module RailsConsoleAI
334
334
  engine.restore_session(saved)
335
335
  true
336
336
  rescue => e
337
- RailsConsoleAI.logger.warn("SlackBot: failed to restore session for #{thread_ts}: #{e.message}")
337
+ RailsConsoleAi.logger.warn("SlackBot: failed to restore session for #{thread_ts}: #{e.message}")
338
338
  false
339
339
  end
340
340
 
@@ -355,7 +355,7 @@ module RailsConsoleAI
355
355
  engine.process_message(text)
356
356
  rescue => e
357
357
  channel.display_error("Error: #{e.class}: #{e.message}")
358
- RailsConsoleAI.logger.error("SlackBot session error: #{e.class}: #{e.message}\n#{e.backtrace.first(5).join("\n")}")
358
+ RailsConsoleAi.logger.error("SlackBot session error: #{e.class}: #{e.message}\n#{e.backtrace.first(5).join("\n")}")
359
359
  ensure
360
360
  ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
361
361
  end
@@ -422,7 +422,7 @@ module RailsConsoleAI
422
422
  end
423
423
 
424
424
  def resolve_channel_ids
425
- ids = RailsConsoleAI.configuration.slack_channel_ids || ENV['CONSOLE_AGENT_SLACK_CHANNELS']
425
+ ids = RailsConsoleAi.configuration.slack_channel_ids || ENV['CONSOLE_AGENT_SLACK_CHANNELS']
426
426
  return nil if ids.nil?
427
427
  ids = ids.split(',').map(&:strip) if ids.is_a?(String)
428
428
  ids
@@ -446,7 +446,7 @@ module RailsConsoleAI
446
446
  name = result.dig("user", "name") if name.nil? || name.empty?
447
447
  @user_cache[user_id] = name || user_id
448
448
  rescue => e
449
- RailsConsoleAI.logger.warn("Failed to resolve user name for #{user_id}: #{e.message}")
449
+ RailsConsoleAi.logger.warn("Failed to resolve user name for #{user_id}: #{e.message}")
450
450
  @user_cache[user_id] = user_id
451
451
  end
452
452
 
@@ -456,7 +456,7 @@ module RailsConsoleAI
456
456
  else
457
457
  "all channels"
458
458
  end
459
- puts "RailsConsoleAI SlackBot started (#{channel_info}, bot: #{@bot_user_id})"
459
+ puts "RailsConsoleAi SlackBot started (#{channel_info}, bot: #{@bot_user_id})"
460
460
 
461
461
  channel = Channel::Slack.new(slack_bot: self, channel_id: "boot", thread_ts: "boot")
462
462
  engine = ConversationEngine.new(
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Storage
3
3
  class StorageError < StandardError; end
4
4
 
@@ -1,7 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'rails_console_ai/storage/base'
3
3
 
4
- module RailsConsoleAI
4
+ module RailsConsoleAi
5
5
  module Storage
6
6
  class FileStorage < Base
7
7
  attr_reader :root_path
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Tools
3
3
  class CodeTools
4
4
  MAX_FILE_LINES = 500
@@ -1,12 +1,12 @@
1
1
  require 'yaml'
2
2
 
3
- module RailsConsoleAI
3
+ module RailsConsoleAi
4
4
  module Tools
5
5
  class MemoryTools
6
6
  MEMORIES_DIR = 'memories'
7
7
 
8
8
  def initialize(storage = nil)
9
- @storage = storage || RailsConsoleAI.storage
9
+ @storage = storage || RailsConsoleAi.storage
10
10
  end
11
11
 
12
12
  def save_memory(name:, description:, tags: [])
@@ -105,7 +105,7 @@ module RailsConsoleAI
105
105
  return nil if content.nil? || content.strip.empty?
106
106
  parse_memory(content)
107
107
  rescue => e
108
- RailsConsoleAI.logger.warn("RailsConsoleAI: failed to load memory #{key}: #{e.message}")
108
+ RailsConsoleAi.logger.warn("RailsConsoleAi: failed to load memory #{key}: #{e.message}")
109
109
  nil
110
110
  end
111
111
 
@@ -113,7 +113,7 @@ module RailsConsoleAI
113
113
  keys = @storage.list("#{MEMORIES_DIR}/*.md")
114
114
  keys.map { |key| load_memory(key) }.compact
115
115
  rescue => e
116
- RailsConsoleAI.logger.warn("RailsConsoleAI: failed to load memories: #{e.message}")
116
+ RailsConsoleAi.logger.warn("RailsConsoleAi: failed to load memories: #{e.message}")
117
117
  []
118
118
  end
119
119
 
@@ -1,4 +1,4 @@
1
- module RailsConsoleAI
1
+ module RailsConsoleAi
2
2
  module Tools
3
3
  class ModelTools
4
4
  def list_models