rails-hyperdrive 0.3.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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +295 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +229 -0
  5. data/Rakefile +6 -0
  6. data/SECURITY.md +43 -0
  7. data/config/routes.rb +5 -0
  8. data/lib/generators/hyperdrive/content_sync_support.rb +54 -0
  9. data/lib/generators/hyperdrive/discover/discover_generator.rb +103 -0
  10. data/lib/generators/hyperdrive/gitignore_support.rb +28 -0
  11. data/lib/generators/hyperdrive/install/USAGE +22 -0
  12. data/lib/generators/hyperdrive/install/install_generator.rb +168 -0
  13. data/lib/generators/hyperdrive/install/templates/initializer.rb.tt +3 -0
  14. data/lib/generators/hyperdrive/install_summary.rb +70 -0
  15. data/lib/generators/hyperdrive/sync/USAGE +21 -0
  16. data/lib/generators/hyperdrive/sync/sync_generator.rb +40 -0
  17. data/lib/generators/hyperdrive/sync_runner.rb +70 -0
  18. data/lib/rails/hyperdrive/artifact_status.rb +86 -0
  19. data/lib/rails/hyperdrive/audit_header.rb +83 -0
  20. data/lib/rails/hyperdrive/auto_install.rb +98 -0
  21. data/lib/rails/hyperdrive/bundler_artifact_discovery.rb +320 -0
  22. data/lib/rails/hyperdrive/claude_md_import.rb +69 -0
  23. data/lib/rails/hyperdrive/companion_discovery.rb +232 -0
  24. data/lib/rails/hyperdrive/console_executor.rb +64 -0
  25. data/lib/rails/hyperdrive/data/gem_categories.yml +52 -0
  26. data/lib/rails/hyperdrive/drift_verdict.rb +42 -0
  27. data/lib/rails/hyperdrive/eager_footprint.rb +48 -0
  28. data/lib/rails/hyperdrive/engine.rb +22 -0
  29. data/lib/rails/hyperdrive/index_document.rb +49 -0
  30. data/lib/rails/hyperdrive/install_layout.rb +45 -0
  31. data/lib/rails/hyperdrive/install_pipeline.rb +415 -0
  32. data/lib/rails/hyperdrive/install_plan.rb +78 -0
  33. data/lib/rails/hyperdrive/install_shell.rb +43 -0
  34. data/lib/rails/hyperdrive/lock_file.rb +171 -0
  35. data/lib/rails/hyperdrive/mcp_server.rb +80 -0
  36. data/lib/rails/hyperdrive/resources/skill.rb +63 -0
  37. data/lib/rails/hyperdrive/resources/stack_profile.rb +32 -0
  38. data/lib/rails/hyperdrive/safety/rack_middleware.rb +54 -0
  39. data/lib/rails/hyperdrive/skill_template.rb +52 -0
  40. data/lib/rails/hyperdrive/sql_safety.rb +28 -0
  41. data/lib/rails/hyperdrive/stack_profile.rb +176 -0
  42. data/lib/rails/hyperdrive/tools/base.rb +39 -0
  43. data/lib/rails/hyperdrive/tools/describe_app.rb +21 -0
  44. data/lib/rails/hyperdrive/tools/list_models.rb +76 -0
  45. data/lib/rails/hyperdrive/tools/list_routes.rb +33 -0
  46. data/lib/rails/hyperdrive/tools/locate_source.rb +86 -0
  47. data/lib/rails/hyperdrive/tools/lookup_doc.rb +60 -0
  48. data/lib/rails/hyperdrive/tools/run_ruby.rb +31 -0
  49. data/lib/rails/hyperdrive/tools/run_sql.rb +49 -0
  50. data/lib/rails/hyperdrive/tools/tail_logs.rb +65 -0
  51. data/lib/rails/hyperdrive/version.rb +5 -0
  52. data/lib/rails/hyperdrive.rb +37 -0
  53. data/lib/rails-hyperdrive.rb +2 -0
  54. data/lib/tasks/hyperdrive.rake +22 -0
  55. metadata +161 -0
@@ -0,0 +1,86 @@
1
+ require_relative "base"
2
+
3
+ module Rails
4
+ module Hyperdrive
5
+ module Tools
6
+ class LocateSource < Base
7
+ tool_name "locate_source"
8
+ description "Resolve a reference to file:line. Accepts 'Const#instance_method', 'Const.class_method', 'Const' (constant location), or 'dep:<gem>' (gem path)."
9
+
10
+ input_schema(
11
+ properties: {
12
+ reference: { type: "string", description: "Reference to locate." }
13
+ },
14
+ required: ["reference"]
15
+ )
16
+
17
+ def self.call(reference:, server_context: nil)
18
+ with_dev_guard do
19
+ resolve(reference.to_s.strip)
20
+ end
21
+ end
22
+
23
+ def self.resolve(reference)
24
+ if reference.start_with?("dep:")
25
+ return resolve_gem(reference.sub(/\Adep:/, ""), reference)
26
+ end
27
+
28
+ if reference.include?("#")
29
+ klass_name, method = reference.split("#", 2)
30
+ klass = constantize(klass_name)
31
+ unless instance_method_defined?(klass, method)
32
+ return respond_error("could not resolve: #{reference}")
33
+ end
34
+ file, line = klass.instance_method(method.to_sym).source_location
35
+ file ? respond_text("#{file}:#{line}") : respond_error("could not resolve: #{reference}")
36
+ elsif reference.include?(".")
37
+ klass_name, method = reference.split(".", 2)
38
+ klass = constantize(klass_name)
39
+ unless klass.respond_to?(method, true)
40
+ return respond_error("could not resolve: #{reference}")
41
+ end
42
+ file, line = klass.method(method.to_sym).source_location
43
+ file ? respond_text("#{file}:#{line}") : respond_error("could not resolve: #{reference}")
44
+ else
45
+ owner_name, const_name = split_const(reference)
46
+ owner = constantize(owner_name)
47
+ return respond_error("could not resolve: #{reference}") unless owner.respond_to?(:const_source_location)
48
+ location = owner.const_source_location(const_name)
49
+ location && location.first ? respond_text("#{location[0]}:#{location[1]}") : respond_error("could not resolve: #{reference}")
50
+ end
51
+ rescue NameError
52
+ respond_error("could not resolve: #{reference}")
53
+ end
54
+
55
+ def self.split_const(reference)
56
+ if reference.include?("::")
57
+ parts = reference.split("::")
58
+ [parts[0..-2].join("::"), parts.last]
59
+ else
60
+ ["Object", reference]
61
+ end
62
+ end
63
+
64
+ def self.instance_method_defined?(klass, method)
65
+ sym = method.to_sym
66
+ klass.instance_methods(true).include?(sym) ||
67
+ klass.private_instance_methods(true).include?(sym)
68
+ end
69
+
70
+ def self.resolve_gem(name, reference)
71
+ spec = Gem::Specification.find_all_by_name(name).first
72
+ return respond_error("could not resolve: #{reference}") unless spec
73
+ respond_text(spec.full_gem_path)
74
+ end
75
+
76
+ def self.constantize(name)
77
+ if defined?(::ActiveSupport) && String.method_defined?(:constantize)
78
+ name.constantize
79
+ else
80
+ name.split("::").inject(Object) { |m, c| m.const_get(c) }
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,60 @@
1
+ require "open3"
2
+ require "timeout"
3
+ require_relative "base"
4
+
5
+ module Rails
6
+ module Hyperdrive
7
+ module Tools
8
+ class LookupDoc < Base
9
+ tool_name "lookup_doc"
10
+ description "Look up documentation for a Ruby/Rails symbol via `ri`. Returns markdown text."
11
+
12
+ RI_TIMEOUT_SECONDS = 10
13
+
14
+ input_schema(
15
+ properties: {
16
+ reference: { type: "string", description: "Symbol to document (e.g. 'String#strip', 'ActiveRecord::Base.find')." }
17
+ },
18
+ required: ["reference"]
19
+ )
20
+
21
+ def self.call(reference:, server_context: nil)
22
+ with_dev_guard do
23
+ ref = reference.to_s.strip
24
+ stdout, stderr, status = run_ri(ref)
25
+ return respond_error("ri not available") if status.nil?
26
+ return respond_text(stdout) if status.success?
27
+ first_stderr_line = stderr.to_s.lines.first.to_s.strip
28
+ respond_error("ri exited #{status.exitstatus}: #{first_stderr_line}")
29
+ end
30
+ end
31
+
32
+ # The manual timeout lets a hung ri be TERMed; a missing ri returns
33
+ # [nil, nil, nil].
34
+ def self.run_ri(reference)
35
+ Open3.popen3("ri", "-T", "--format=markdown", reference) do |_in, out, err, wait_thr|
36
+ begin
37
+ ::Timeout.timeout(RI_TIMEOUT_SECONDS) do
38
+ stdout = out.read
39
+ stderr = err.read
40
+ [stdout, stderr, wait_thr.value]
41
+ end
42
+ rescue ::Timeout::Error
43
+ begin
44
+ Process.kill("TERM", wait_thr.pid)
45
+ rescue Errno::ESRCH
46
+ end
47
+ ["", "ri timeout after #{RI_TIMEOUT_SECONDS}s", FakeStatus.new(124)]
48
+ end
49
+ end
50
+ rescue Errno::ENOENT
51
+ [nil, nil, nil]
52
+ end
53
+
54
+ FakeStatus = Struct.new(:exitstatus) do
55
+ def success?; false; end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,31 @@
1
+ require_relative "base"
2
+ require_relative "../console_executor"
3
+
4
+ module Rails
5
+ module Hyperdrive
6
+ module Tools
7
+ class RunRuby < Base
8
+ tool_name "run_ruby"
9
+ description "Eval Ruby in the booted Rails process with timeout and stdout/stderr capture. Returns { result, stdout, stderr, elapsed_ms, exception }."
10
+
11
+ MAX_TIMEOUT_SECONDS = 120
12
+
13
+ input_schema(
14
+ properties: {
15
+ code: { type: "string", description: "Ruby source to eval at TOPLEVEL_BINDING." },
16
+ timeout: { type: "integer", description: "Timeout in seconds (default 30, max 120)." }
17
+ },
18
+ required: ["code"]
19
+ )
20
+
21
+ def self.call(code:, timeout: Rails::Hyperdrive::ConsoleExecutor::DEFAULT_TIMEOUT_SECONDS, server_context: nil)
22
+ with_dev_guard do
23
+ t = [[timeout.to_i, 1].max, MAX_TIMEOUT_SECONDS].min
24
+ result = Rails::Hyperdrive::ConsoleExecutor.eval(code, timeout: t)
25
+ respond_json(result.to_h)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ require_relative "base"
2
+ require_relative "../sql_safety"
3
+
4
+ module Rails
5
+ module Hyperdrive
6
+ module Tools
7
+ class RunSql < Base
8
+ tool_name "run_sql"
9
+ description "Read-only SQL via ActiveRecord::Base.connection. Rejects INSERT/UPDATE/DELETE/DROP/etc. at the parser level. Caps results at 100 rows."
10
+
11
+ ROW_CAP = 100
12
+
13
+ input_schema(
14
+ properties: {
15
+ sql: { type: "string", description: "A SELECT / WITH / EXPLAIN / SHOW / PRAGMA statement." }
16
+ },
17
+ required: ["sql"]
18
+ )
19
+
20
+ def self.call(sql:, server_context: nil)
21
+ with_dev_guard do
22
+ begin
23
+ Rails::Hyperdrive::SqlSafety.assert_read_only!(sql)
24
+ rescue Rails::Hyperdrive::SqlSafety::Error => e
25
+ return respond_error("SQL not allowed: #{e.message}")
26
+ end
27
+
28
+ begin
29
+ result = ActiveRecord::Base.connection.exec_query(sql)
30
+ rescue ActiveRecord::ActiveRecordError => e
31
+ return respond_error("#{e.class}: #{e.message}")
32
+ end
33
+
34
+ respond_text(format_table(result))
35
+ end
36
+ end
37
+
38
+ def self.format_table(result)
39
+ rows = result.rows
40
+ shown = rows.first(ROW_CAP)
41
+ lines = [result.columns.join("\t")]
42
+ shown.each { |row| lines << row.map { |v| v.to_s }.join("\t") }
43
+ lines << "(#{rows.length} rows, truncated)" if rows.length > ROW_CAP
44
+ lines.join("\n")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,65 @@
1
+ require_relative "base"
2
+
3
+ module Rails
4
+ module Hyperdrive
5
+ module Tools
6
+ class TailLogs < Base
7
+ tool_name "tail_logs"
8
+ description "Return the last N lines of a log file under Rails.root/log/. Defaults to <env>.log."
9
+
10
+ DEFAULT_LINES = 200
11
+ MAX_LINES = 2_000
12
+
13
+ input_schema(
14
+ properties: {
15
+ lines: { type: "integer", description: "Number of trailing lines (default 200, max 2000)." },
16
+ file: { type: "string", description: "Log file path. Default: log/<Rails.env>.log. Must resolve inside Rails.root/log/." }
17
+ }
18
+ )
19
+
20
+ def self.call(lines: DEFAULT_LINES, file: nil, server_context: nil)
21
+ with_dev_guard do
22
+ n = [[lines.to_i, 1].max, MAX_LINES].min
23
+ log_dir = ::Rails.root.join("log").expand_path
24
+ requested = file.to_s.empty? ? "#{::Rails.env}.log" : file.to_s
25
+ log_path = resolve_path(log_dir, requested)
26
+ return respond_error("log not allowed: path escapes Rails.root/log/") unless log_path
27
+ return respond_error("log not found: #{log_path}") unless File.exist?(log_path)
28
+ respond_text(tail(log_path, n))
29
+ end
30
+ end
31
+
32
+ # Path-traversal guard: the resolved target must stay inside log_dir.
33
+ def self.resolve_path(log_dir, requested)
34
+ base = Pathname.new(requested)
35
+ target = base.absolute? ? base : (log_dir + base)
36
+ target = Pathname.new(File.expand_path(target.to_s))
37
+ return nil unless target.to_s == log_dir.to_s || target.to_s.start_with?(log_dir.to_s + File::SEPARATOR)
38
+ target
39
+ end
40
+
41
+ # Pure-Ruby `tail -n` — portable and avoids shell-escaping risk.
42
+ def self.tail(path, lines)
43
+ block_size = 8 * 1024
44
+ File.open(path, "rb") do |f|
45
+ f.seek(0, IO::SEEK_END)
46
+ file_size = f.pos
47
+ buffer = +""
48
+ newline_count = 0
49
+ while f.pos > 0 && newline_count <= lines
50
+ read_size = [block_size, f.pos].min
51
+ f.seek(-read_size, IO::SEEK_CUR)
52
+ chunk = f.read(read_size)
53
+ f.seek(-read_size, IO::SEEK_CUR)
54
+ buffer.prepend(chunk)
55
+ newline_count = buffer.count("\n")
56
+ end
57
+ buffer.force_encoding(Encoding.default_external).scrub
58
+ last = buffer.lines.last(lines).join
59
+ last.empty? && file_size > 0 ? buffer : last
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ module Rails
2
+ module Hyperdrive
3
+ VERSION = "0.3.0"
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ require "rails/hyperdrive/version"
2
+
3
+ module Rails
4
+ module Hyperdrive
5
+ class Configuration
6
+ DEFAULT_MOUNT_AT = "/_hyperdrive".freeze
7
+
8
+ attr_accessor :mount_at
9
+
10
+ def initialize
11
+ @mount_at = DEFAULT_MOUNT_AT
12
+ end
13
+ end
14
+
15
+ def self.root
16
+ @root ||= File.expand_path("..", __dir__)
17
+ end
18
+
19
+ def self.dev_mode?
20
+ defined?(::Rails) && ::Rails.respond_to?(:env) && ::Rails.env.development?
21
+ end
22
+
23
+ def self.configuration
24
+ @configuration ||= Configuration.new
25
+ end
26
+
27
+ def self.configure
28
+ yield(configuration)
29
+ end
30
+
31
+ def self.reset_configuration!
32
+ @configuration = nil
33
+ end
34
+ end
35
+ end
36
+
37
+ require "rails/hyperdrive/engine" if defined?(::Rails::Engine)
@@ -0,0 +1,2 @@
1
+ # Bundler auto-requires this gem by its dashed name ("rails-hyperdrive").
2
+ require "rails/hyperdrive"
@@ -0,0 +1,22 @@
1
+ namespace :hyperdrive do
2
+ desc "Install Rails Hyperdrive into this app (writes .mcp.json, CLAUDE.md, skills, guidelines, mounts engine)"
3
+ task :init do
4
+ require "rails/generators"
5
+ require "generators/hyperdrive/install/install_generator"
6
+ Rails::Generators::Hyperdrive::InstallGenerator.start(ARGV.drop(1))
7
+ end
8
+
9
+ desc "Sync Rails Hyperdrive content (skills, guidelines, index.md, lockfile); locally-edited files are preserved — pass --overwrite to restore gem-shipped content"
10
+ task :sync do
11
+ require "rails/generators"
12
+ require "generators/hyperdrive/sync/sync_generator"
13
+ Rails::Generators::Hyperdrive::SyncGenerator.start(ARGV.drop(1))
14
+ end
15
+
16
+ desc "Suggest uninstalled rails-hyperdrive companion gems for this app's stack (networked, cached; pass --refresh to re-query)"
17
+ task :discover do
18
+ require "rails/generators"
19
+ require "generators/hyperdrive/discover/discover_generator"
20
+ Rails::Generators::Hyperdrive::DiscoverGenerator.start(ARGV.drop(1))
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-hyperdrive
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Bakaface
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: railties
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: activerecord
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: mcp
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.25'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.25'
54
+ - !ruby/object:Gem::Dependency
55
+ name: bundler
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '2.3'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '2.3'
68
+ description: |
69
+ Rails Hyperdrive mounts an MCP (Model Context Protocol) server at /_hyperdrive/mcp in development,
70
+ exposing introspection tools for AI coding agents (eval Ruby, query DB, tail logs,
71
+ list models/routes, locate source, fetch docs, snapshot stack). It also ships a
72
+ `hyperdrive:init` generator that discovers and installs two artifact types — lazy skills
73
+ and eager guidelines — shipped by companion gems under a documented contract.
74
+ rails-hyperdrive is the mechanism; companion gems (rails-hyperdrive-<library>) are the content.
75
+ email:
76
+ - afaceisnomore@gmail.com
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - CHANGELOG.md
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - SECURITY.md
86
+ - config/routes.rb
87
+ - lib/generators/hyperdrive/content_sync_support.rb
88
+ - lib/generators/hyperdrive/discover/discover_generator.rb
89
+ - lib/generators/hyperdrive/gitignore_support.rb
90
+ - lib/generators/hyperdrive/install/USAGE
91
+ - lib/generators/hyperdrive/install/install_generator.rb
92
+ - lib/generators/hyperdrive/install/templates/initializer.rb.tt
93
+ - lib/generators/hyperdrive/install_summary.rb
94
+ - lib/generators/hyperdrive/sync/USAGE
95
+ - lib/generators/hyperdrive/sync/sync_generator.rb
96
+ - lib/generators/hyperdrive/sync_runner.rb
97
+ - lib/rails-hyperdrive.rb
98
+ - lib/rails/hyperdrive.rb
99
+ - lib/rails/hyperdrive/artifact_status.rb
100
+ - lib/rails/hyperdrive/audit_header.rb
101
+ - lib/rails/hyperdrive/auto_install.rb
102
+ - lib/rails/hyperdrive/bundler_artifact_discovery.rb
103
+ - lib/rails/hyperdrive/claude_md_import.rb
104
+ - lib/rails/hyperdrive/companion_discovery.rb
105
+ - lib/rails/hyperdrive/console_executor.rb
106
+ - lib/rails/hyperdrive/data/gem_categories.yml
107
+ - lib/rails/hyperdrive/drift_verdict.rb
108
+ - lib/rails/hyperdrive/eager_footprint.rb
109
+ - lib/rails/hyperdrive/engine.rb
110
+ - lib/rails/hyperdrive/index_document.rb
111
+ - lib/rails/hyperdrive/install_layout.rb
112
+ - lib/rails/hyperdrive/install_pipeline.rb
113
+ - lib/rails/hyperdrive/install_plan.rb
114
+ - lib/rails/hyperdrive/install_shell.rb
115
+ - lib/rails/hyperdrive/lock_file.rb
116
+ - lib/rails/hyperdrive/mcp_server.rb
117
+ - lib/rails/hyperdrive/resources/skill.rb
118
+ - lib/rails/hyperdrive/resources/stack_profile.rb
119
+ - lib/rails/hyperdrive/safety/rack_middleware.rb
120
+ - lib/rails/hyperdrive/skill_template.rb
121
+ - lib/rails/hyperdrive/sql_safety.rb
122
+ - lib/rails/hyperdrive/stack_profile.rb
123
+ - lib/rails/hyperdrive/tools/base.rb
124
+ - lib/rails/hyperdrive/tools/describe_app.rb
125
+ - lib/rails/hyperdrive/tools/list_models.rb
126
+ - lib/rails/hyperdrive/tools/list_routes.rb
127
+ - lib/rails/hyperdrive/tools/locate_source.rb
128
+ - lib/rails/hyperdrive/tools/lookup_doc.rb
129
+ - lib/rails/hyperdrive/tools/run_ruby.rb
130
+ - lib/rails/hyperdrive/tools/run_sql.rb
131
+ - lib/rails/hyperdrive/tools/tail_logs.rb
132
+ - lib/rails/hyperdrive/version.rb
133
+ - lib/tasks/hyperdrive.rake
134
+ homepage: https://github.com/rails-hyperdrive/rails-hyperdrive
135
+ licenses:
136
+ - MIT
137
+ metadata:
138
+ homepage_uri: https://github.com/rails-hyperdrive/rails-hyperdrive
139
+ source_code_uri: https://github.com/rails-hyperdrive/rails-hyperdrive
140
+ changelog_uri: https://github.com/rails-hyperdrive/rails-hyperdrive/blob/main/CHANGELOG.md
141
+ allowed_push_host: https://rubygems.org
142
+ rubygems_mfa_required: 'true'
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: 3.2.0
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubygems_version: 3.6.9
158
+ specification_version: 4
159
+ summary: Dev-only Rails engine that bootstraps an MCP server + skills/guidelines for
160
+ AI coding agents.
161
+ test_files: []