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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +295 -0
- data/LICENSE.txt +21 -0
- data/README.md +229 -0
- data/Rakefile +6 -0
- data/SECURITY.md +43 -0
- data/config/routes.rb +5 -0
- data/lib/generators/hyperdrive/content_sync_support.rb +54 -0
- data/lib/generators/hyperdrive/discover/discover_generator.rb +103 -0
- data/lib/generators/hyperdrive/gitignore_support.rb +28 -0
- data/lib/generators/hyperdrive/install/USAGE +22 -0
- data/lib/generators/hyperdrive/install/install_generator.rb +168 -0
- data/lib/generators/hyperdrive/install/templates/initializer.rb.tt +3 -0
- data/lib/generators/hyperdrive/install_summary.rb +70 -0
- data/lib/generators/hyperdrive/sync/USAGE +21 -0
- data/lib/generators/hyperdrive/sync/sync_generator.rb +40 -0
- data/lib/generators/hyperdrive/sync_runner.rb +70 -0
- data/lib/rails/hyperdrive/artifact_status.rb +86 -0
- data/lib/rails/hyperdrive/audit_header.rb +83 -0
- data/lib/rails/hyperdrive/auto_install.rb +98 -0
- data/lib/rails/hyperdrive/bundler_artifact_discovery.rb +320 -0
- data/lib/rails/hyperdrive/claude_md_import.rb +69 -0
- data/lib/rails/hyperdrive/companion_discovery.rb +232 -0
- data/lib/rails/hyperdrive/console_executor.rb +64 -0
- data/lib/rails/hyperdrive/data/gem_categories.yml +52 -0
- data/lib/rails/hyperdrive/drift_verdict.rb +42 -0
- data/lib/rails/hyperdrive/eager_footprint.rb +48 -0
- data/lib/rails/hyperdrive/engine.rb +22 -0
- data/lib/rails/hyperdrive/index_document.rb +49 -0
- data/lib/rails/hyperdrive/install_layout.rb +45 -0
- data/lib/rails/hyperdrive/install_pipeline.rb +415 -0
- data/lib/rails/hyperdrive/install_plan.rb +78 -0
- data/lib/rails/hyperdrive/install_shell.rb +43 -0
- data/lib/rails/hyperdrive/lock_file.rb +171 -0
- data/lib/rails/hyperdrive/mcp_server.rb +80 -0
- data/lib/rails/hyperdrive/resources/skill.rb +63 -0
- data/lib/rails/hyperdrive/resources/stack_profile.rb +32 -0
- data/lib/rails/hyperdrive/safety/rack_middleware.rb +54 -0
- data/lib/rails/hyperdrive/skill_template.rb +52 -0
- data/lib/rails/hyperdrive/sql_safety.rb +28 -0
- data/lib/rails/hyperdrive/stack_profile.rb +176 -0
- data/lib/rails/hyperdrive/tools/base.rb +39 -0
- data/lib/rails/hyperdrive/tools/describe_app.rb +21 -0
- data/lib/rails/hyperdrive/tools/list_models.rb +76 -0
- data/lib/rails/hyperdrive/tools/list_routes.rb +33 -0
- data/lib/rails/hyperdrive/tools/locate_source.rb +86 -0
- data/lib/rails/hyperdrive/tools/lookup_doc.rb +60 -0
- data/lib/rails/hyperdrive/tools/run_ruby.rb +31 -0
- data/lib/rails/hyperdrive/tools/run_sql.rb +49 -0
- data/lib/rails/hyperdrive/tools/tail_logs.rb +65 -0
- data/lib/rails/hyperdrive/version.rb +5 -0
- data/lib/rails/hyperdrive.rb +37 -0
- data/lib/rails-hyperdrive.rb +2 -0
- data/lib/tasks/hyperdrive.rake +22 -0
- 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,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,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: []
|