ruby-ai-gem-context 0.1.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.
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyAiGemContext
4
+ module Platforms
5
+ class LlmTxt < Platform
6
+ class << self
7
+ def name
8
+ "llm.txt"
9
+ end
10
+
11
+ def filename
12
+ "llm.txt"
13
+ end
14
+
15
+ def description
16
+ "llm.txt - Universal LLM context file (like robots.txt for AI)"
17
+ end
18
+
19
+ def generation_prompt
20
+ <<~PROMPT
21
+ Generate an llm.txt file for this Ruby project. The llm.txt format is like robots.txt but for LLMs - it helps AI systems understand what this project is and how to use it.
22
+
23
+ Format the file as:
24
+
25
+ # Project Name
26
+ > Brief one-line description
27
+
28
+ ## About
29
+ Paragraph explaining what this project does, who it's for, and why it exists.
30
+
31
+ ## Quick Start
32
+ The fastest way to get started with this project.
33
+
34
+ ## Documentation
35
+ - Link to or description of where to find docs
36
+ - Key files to read to understand the project
37
+
38
+ ## API
39
+ Key classes/methods and what they do.
40
+
41
+ ## Examples
42
+ Short, practical code examples.
43
+
44
+ ## License
45
+ License information.
46
+
47
+ Keep it concise and scannable. This is meant to be quickly parsed by AI systems.
48
+ PROMPT
49
+ end
50
+
51
+ def template
52
+ <<~TEMPLATE
53
+ # Project Name
54
+ > One-line description of the project
55
+
56
+ ## About
57
+ Longer description of what this project does, its purpose, and target audience.
58
+
59
+ ## Quick Start
60
+ ```bash
61
+ gem install project-name
62
+ ```
63
+
64
+ ```ruby
65
+ require 'project_name'
66
+ # Minimal usage example
67
+ ```
68
+
69
+ ## Documentation
70
+ - README.md - Overview and setup
71
+ - lib/ - Source code
72
+ - spec/ - Test examples
73
+
74
+ ## API
75
+ - `MainModule` - Entry point
76
+ - `MainModule.method` - Key functionality
77
+
78
+ ## Examples
79
+ ```ruby
80
+ # Practical example
81
+ ```
82
+
83
+ ## License
84
+ MIT License - See LICENSE file
85
+ TEMPLATE
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyAiGemContext
4
+ module Platforms
5
+ class Windsurf < Platform
6
+ class << self
7
+ def name
8
+ "Windsurf"
9
+ end
10
+
11
+ def filename
12
+ ".windsurfrules"
13
+ end
14
+
15
+ def description
16
+ "Windsurf IDE - Project rules file"
17
+ end
18
+
19
+ def generation_prompt
20
+ <<~PROMPT
21
+ Generate a .windsurfrules file for this Ruby project. This file tells Windsurf AI how to work with this codebase.
22
+
23
+ Structure it as clear rules and guidelines:
24
+
25
+ 1. Project context - What this project is
26
+ 2. Language and framework details
27
+ 3. Code conventions to follow
28
+ 4. Architecture patterns
29
+ 5. Testing requirements
30
+ 6. Important files and their purposes
31
+ 7. Commands for common tasks
32
+ 8. Pitfalls and things to avoid
33
+
34
+ Write in a direct, instructional style. Focus on actionable guidance.
35
+ PROMPT
36
+ end
37
+
38
+ def template
39
+ <<~TEMPLATE
40
+ # Project Context
41
+ This is a Ruby project. Describe its purpose here.
42
+
43
+ # Language & Framework
44
+ - Ruby 3.x
45
+ - Add frameworks used (Rails, Sinatra, etc.)
46
+ - Key gems and their purposes
47
+
48
+ # Code Conventions
49
+ - Follow Ruby style guide
50
+ - Use snake_case for methods/variables
51
+ - Use CamelCase for classes/modules
52
+ - Document public APIs with YARD
53
+
54
+ # Architecture
55
+ - Describe the overall structure
56
+ - Key patterns used
57
+ - How components interact
58
+
59
+ # Testing
60
+ - RSpec for unit tests
61
+ - Run with: bundle exec rspec
62
+ - Write tests for all new code
63
+
64
+ # Important Files
65
+ - lib/ - Main code
66
+ - spec/ - Tests
67
+ - Gemfile - Dependencies
68
+
69
+ # Common Commands
70
+ - bundle install - Install dependencies
71
+ - bundle exec rspec - Run tests
72
+ - bundle exec rubocop - Run linter
73
+
74
+ # Pitfalls
75
+ - Things to watch out for
76
+ - Common mistakes in this codebase
77
+ TEMPLATE
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ module RubyAiGemContext
6
+ class Railtie < Rails::Railtie
7
+ rake_tasks do
8
+ load File.expand_path("tasks/ruby_ai_gem_context.rake", __dir__)
9
+ end
10
+
11
+ initializer "ruby_ai_gem_context.configure" do |app|
12
+ # Allow Rails config to override gem configuration
13
+ if app.config.respond_to?(:ruby_ai_gem_context)
14
+ RubyAiGemContext.configure do |config|
15
+ rails_config = app.config.ruby_ai_gem_context
16
+
17
+ config.model = rails_config.model if rails_config.respond_to?(:model) && rails_config.model
18
+ config.temperature = rails_config.temperature if rails_config.respond_to?(:temperature)
19
+ config.max_tokens = rails_config.max_tokens if rails_config.respond_to?(:max_tokens)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,311 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :ai_context do
4
+ desc "Setup: Generate boilerplate context files for selected AI platforms"
5
+ task :setup do
6
+ require "ruby_ai_gem_context"
7
+
8
+ ui = RubyAiGemContext::Interactive.new
9
+ config_file = RubyAiGemContext::ConfigFile.new
10
+
11
+ ui.header("AI Context Setup")
12
+
13
+ # Ask which platforms to generate for
14
+ selected = ui.select_platforms
15
+
16
+ if selected.empty?
17
+ ui.warning("No platforms selected. Exiting.")
18
+ exit 0
19
+ end
20
+
21
+ ui.info("Selected: #{selected.map { |k| RubyAiGemContext.platform(k).name }.join(', ')}")
22
+
23
+ # Process each platform
24
+ selected.each do |platform_key|
25
+ platform = RubyAiGemContext.platform(platform_key)
26
+
27
+ if platform.exists?
28
+ action = ui.handle_collision(platform)
29
+
30
+ case action
31
+ when :skip
32
+ ui.info("Skipping #{platform.filename}")
33
+ next
34
+ when :backup
35
+ backup_path = platform.backup
36
+ ui.info("Backed up to #{backup_path}")
37
+ when :diff
38
+ existing = platform.read
39
+ action = ui.show_diff(existing, platform.template)
40
+ case action
41
+ when :skip
42
+ ui.info("Keeping existing #{platform.filename}")
43
+ next
44
+ when :backup
45
+ backup_path = platform.backup
46
+ ui.info("Backed up to #{backup_path}")
47
+ end
48
+ when :overwrite
49
+ # Continue to write
50
+ end
51
+ end
52
+
53
+ # Write the template
54
+ path = platform.write(platform.template)
55
+ config_file.record_generated(platform_key, model: "template")
56
+ ui.success("Created #{path}")
57
+ end
58
+
59
+ puts
60
+ ui.info("Boilerplate files created!")
61
+ ui.info("Next step: Run `rake ai_context:generate` to fill them with AI-generated content")
62
+ ui.info("Or edit the files manually with your project's specific information")
63
+ end
64
+
65
+ desc "Generate: Fill context files with AI-generated content from your project"
66
+ task :generate do
67
+ require "ruby_ai_gem_context"
68
+
69
+ ui = RubyAiGemContext::Interactive.new
70
+ config_file = RubyAiGemContext::ConfigFile.new
71
+
72
+ ui.header("AI Context Generation")
73
+
74
+ # Check which platforms have been set up
75
+ existing_platforms = config_file.generated_platforms
76
+
77
+ if existing_platforms.empty?
78
+ ui.warning("No context files have been set up yet.")
79
+ ui.info("Run `rake ai_context:setup` first to create boilerplate files.")
80
+ exit 0
81
+ end
82
+
83
+ # Ask which to regenerate
84
+ selected = ui.select_platforms_to_regenerate(existing_platforms)
85
+
86
+ if selected.empty?
87
+ ui.warning("No platforms selected. Exiting.")
88
+ exit 0
89
+ end
90
+
91
+ # Ask about source folders
92
+ folders = ui.select_source_folders
93
+
94
+ # Show what will be scanned
95
+ collector = RubyAiGemContext::FileCollector.new(Dir.pwd, folders: folders)
96
+ summary = collector.summary
97
+
98
+ unless ui.confirm_source_folders(folders, summary)
99
+ ui.info("Generation cancelled.")
100
+ exit 0
101
+ end
102
+
103
+ # Record source folders
104
+ config_file.record_source_folders(folders)
105
+
106
+ # Show model info
107
+ model = RubyAiGemContext.configuration.model
108
+ ui.info("Using model: #{model}")
109
+ ui.info("(Change in config or set RUBY_LLM_MODEL env var)")
110
+ puts
111
+
112
+ # Generate for each platform
113
+ selected.each do |platform_key|
114
+ platform = RubyAiGemContext.platform(platform_key)
115
+
116
+ content = ui.with_spinner("Generating #{platform.name} context...") do
117
+ generator = RubyAiGemContext::Generator.new(
118
+ platform: platform,
119
+ file_collector: collector,
120
+ model: model
121
+ )
122
+ generator.generate
123
+ end
124
+
125
+ # Handle existing file
126
+ if platform.exists?
127
+ action = ui.handle_collision(platform)
128
+
129
+ case action
130
+ when :skip
131
+ ui.info("Skipping #{platform.filename}")
132
+ next
133
+ when :backup
134
+ platform.backup
135
+ when :diff
136
+ existing = platform.read
137
+ action = ui.show_diff(existing, content)
138
+ case action
139
+ when :skip
140
+ next
141
+ when :backup
142
+ platform.backup
143
+ end
144
+ end
145
+ end
146
+
147
+ path = platform.write(content)
148
+ config_file.record_generated(platform_key, model: model)
149
+ ui.success("Generated #{path}")
150
+ end
151
+
152
+ ui.review_reminder
153
+ end
154
+
155
+ desc "Generate context for a third-party gem: rake ai_context:generate_for_gem[gem_name]"
156
+ task :generate_for_gem, [:gem_name] do |_t, args|
157
+ require "ruby_ai_gem_context"
158
+
159
+ ui = RubyAiGemContext::Interactive.new
160
+
161
+ ui.header("Generate Context for Gem")
162
+
163
+ # Get gem name
164
+ gem_name = args[:gem_name] || ui.ask_gem_name
165
+
166
+ # Find the gem
167
+ begin
168
+ spec = Gem::Specification.find_by_name(gem_name)
169
+ rescue Gem::MissingSpecError
170
+ ui.error("Gem '#{gem_name}' not found. Is it installed?")
171
+ exit 1
172
+ end
173
+
174
+ ui.info("Found: #{spec.name} v#{spec.version}")
175
+ ui.info("Location: #{spec.gem_dir}")
176
+ puts
177
+
178
+ # Ask which platforms to generate for
179
+ selected = ui.select_platforms
180
+
181
+ if selected.empty?
182
+ ui.warning("No platforms selected. Exiting.")
183
+ exit 0
184
+ end
185
+
186
+ # Collect files from the gem
187
+ collector = RubyAiGemContext::FileCollector.new(spec.gem_dir)
188
+ summary = collector.summary
189
+
190
+ ui.info("Gem has #{summary[:total_files]} files (#{format_size(summary[:total_size])})")
191
+
192
+ unless ui.prompt.yes?("Generate context for this gem?")
193
+ ui.info("Generation cancelled.")
194
+ exit 0
195
+ end
196
+
197
+ # Create output directory
198
+ output_dir = File.join(Dir.pwd, ".ai_context", "gems", gem_name)
199
+ FileUtils.mkdir_p(output_dir)
200
+
201
+ model = RubyAiGemContext.configuration.model
202
+ ui.info("Using model: #{model}")
203
+ puts
204
+
205
+ # Generate for each platform
206
+ selected.each do |platform_key|
207
+ platform = RubyAiGemContext.platform(platform_key)
208
+
209
+ content = ui.with_spinner("Generating #{platform.name} context for #{gem_name}...") do
210
+ generator = RubyAiGemContext::Generator.new(
211
+ platform: platform,
212
+ file_collector: collector,
213
+ model: model
214
+ )
215
+ generator.generate
216
+ end
217
+
218
+ output_path = File.join(output_dir, platform.filename)
219
+ File.write(output_path, content)
220
+ ui.success("Generated #{output_path}")
221
+ end
222
+
223
+ puts
224
+ ui.info("Context files saved to: #{output_dir}/")
225
+ ui.info("You can copy these to your project or reference them as needed.")
226
+ ui.review_reminder
227
+ end
228
+
229
+ desc "List generated context files"
230
+ task :list do
231
+ require "ruby_ai_gem_context"
232
+
233
+ config_file = RubyAiGemContext::ConfigFile.new
234
+ config = config_file.load
235
+
236
+ puts "AI Context Files"
237
+ puts "=" * 40
238
+
239
+ generated = config["generated"] || {}
240
+
241
+ if generated.empty?
242
+ puts "No context files have been generated yet."
243
+ puts "Run `rake ai_context:setup` to get started."
244
+ else
245
+ generated.each do |platform_key, info|
246
+ platform = RubyAiGemContext.platform(platform_key)
247
+ exists = platform.exists? ? "✓" : "✗ (missing)"
248
+ puts
249
+ puts "#{platform.name}"
250
+ puts " File: #{info['path']} #{exists}"
251
+ puts " Model: #{info['model']}"
252
+ puts " Generated: #{info['created_at']}"
253
+ end
254
+ end
255
+
256
+ if config["source_folders"]
257
+ puts
258
+ puts "Source folders: #{config['source_folders'].join(', ')}"
259
+ end
260
+ end
261
+
262
+ desc "Clear all generated context files"
263
+ task :clear do
264
+ require "ruby_ai_gem_context"
265
+
266
+ ui = RubyAiGemContext::Interactive.new
267
+ config_file = RubyAiGemContext::ConfigFile.new
268
+
269
+ platforms = config_file.generated_platforms
270
+
271
+ if platforms.empty?
272
+ ui.info("No context files to clear.")
273
+ exit 0
274
+ end
275
+
276
+ ui.warning("This will delete the following files:")
277
+ platforms.each do |key|
278
+ platform = RubyAiGemContext.platform(key)
279
+ puts " - #{platform.path}" if platform.exists?
280
+ end
281
+ puts
282
+
283
+ unless ui.prompt.yes?("Are you sure you want to delete these files?")
284
+ ui.info("Cancelled.")
285
+ exit 0
286
+ end
287
+
288
+ platforms.each do |key|
289
+ platform = RubyAiGemContext.platform(key)
290
+ if platform.exists?
291
+ File.delete(platform.full_path)
292
+ ui.success("Deleted #{platform.path}")
293
+ end
294
+ end
295
+
296
+ # Clear config
297
+ config_dir = File.join(Dir.pwd, RubyAiGemContext.configuration.config_dir)
298
+ FileUtils.rm_rf(config_dir)
299
+ ui.success("Cleared #{config_dir}/")
300
+ end
301
+ end
302
+
303
+ def format_size(bytes)
304
+ if bytes < 1024
305
+ "#{bytes} B"
306
+ elsif bytes < 1024 * 1024
307
+ "#{(bytes / 1024.0).round(1)} KB"
308
+ else
309
+ "#{(bytes / (1024.0 * 1024)).round(1)} MB"
310
+ end
311
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyAiGemContext
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "yaml"
5
+ require "time"
6
+
7
+ require_relative "ruby_ai_gem_context/version"
8
+ require_relative "ruby_ai_gem_context/configuration"
9
+ require_relative "ruby_ai_gem_context/platform"
10
+ require_relative "ruby_ai_gem_context/platforms/claude"
11
+ require_relative "ruby_ai_gem_context/platforms/cursor"
12
+ require_relative "ruby_ai_gem_context/platforms/windsurf"
13
+ require_relative "ruby_ai_gem_context/platforms/codex"
14
+ require_relative "ruby_ai_gem_context/platforms/llm_txt"
15
+ require_relative "ruby_ai_gem_context/config_file"
16
+ require_relative "ruby_ai_gem_context/file_collector"
17
+ require_relative "ruby_ai_gem_context/generator"
18
+ require_relative "ruby_ai_gem_context/interactive"
19
+
20
+ module RubyAiGemContext
21
+ class Error < StandardError; end
22
+
23
+ # All supported platforms
24
+ PLATFORMS = {
25
+ claude: Platforms::Claude,
26
+ cursor: Platforms::Cursor,
27
+ windsurf: Platforms::Windsurf,
28
+ codex: Platforms::Codex,
29
+ llm_txt: Platforms::LlmTxt
30
+ }.freeze
31
+
32
+ class << self
33
+ attr_writer :configuration
34
+
35
+ def configuration
36
+ @configuration ||= Configuration.new
37
+ end
38
+
39
+ def configure
40
+ yield(configuration)
41
+ end
42
+
43
+ def reset_configuration!
44
+ @configuration = Configuration.new
45
+ end
46
+
47
+ # Get platform class by key
48
+ def platform(key)
49
+ PLATFORMS[key.to_sym] || raise(Error, "Unknown platform: #{key}")
50
+ end
51
+
52
+ # List all platform keys
53
+ def platform_keys
54
+ PLATFORMS.keys
55
+ end
56
+ end
57
+ end
58
+
59
+ # Load Rails integration if Rails is defined
60
+ require_relative "ruby_ai_gem_context/railtie" if defined?(Rails::Railtie)
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/ruby_ai_gem_context/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ruby-ai-gem-context"
7
+ spec.version = RubyAiGemContext::VERSION
8
+ spec.authors = ["Your Name"]
9
+ spec.email = ["your.email@example.com"]
10
+
11
+ spec.summary = "Generate AI context files for Ruby projects"
12
+ spec.description = "Interactive rake tasks to generate context files for AI coding assistants " \
13
+ "(Claude, Cursor, Windsurf, Codex, llm.txt). Uses RubyLLM to analyze your " \
14
+ "codebase and create platform-specific context that helps AI understand your project."
15
+ spec.homepage = "https://github.com/AAlvAAro/ruby-ai-gem-context"
16
+ spec.license = "MIT"
17
+ spec.required_ruby_version = ">= 3.0.0"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = spec.homepage
21
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
22
+
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (File.expand_path(f) == __FILE__) ||
26
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
27
+ end
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ # Core dependencies
34
+ spec.add_dependency "ruby_llm", ">= 1.0" # AI generation via multiple providers
35
+ spec.add_dependency "tty-prompt", "~> 0.23" # Interactive terminal prompts
36
+ spec.add_dependency "tty-spinner", "~> 0.9" # Progress spinners
37
+
38
+ spec.add_development_dependency "bundler", ">= 2.0"
39
+ spec.add_development_dependency "rake", "~> 13.0"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
41
+ end