Module: SharedTools

Defined in:
lib/shared_tools/tools.rb,
lib/shared_tools.rb,
lib/shared_tools/version.rb,
lib/shared_tools/utilities.rb,
lib/shared_tools/tools/version.rb,
lib/shared_tools/tools/dns_tool.rb,
lib/shared_tools/tools/doc_tool.rb,
lib/shared_tools/tools/cron_tool.rb,
lib/shared_tools/tools/disk_tool.rb,
lib/shared_tools/tools/eval_tool.rb,
lib/shared_tools/tools/browser_tool.rb,
lib/shared_tools/tools/weather_tool.rb,
lib/shared_tools/tools/computer_tool.rb,
lib/shared_tools/tools/database_tool.rb,
lib/shared_tools/tools/clipboard_tool.rb,
lib/shared_tools/tools/disk/base_tool.rb,
lib/shared_tools/tools/calculator_tool.rb,
lib/shared_tools/tools/data_science_kit.rb,
lib/shared_tools/tools/disk/base_driver.rb,
lib/shared_tools/tools/docker/base_tool.rb,
lib/shared_tools/tools/system_info_tool.rb,
lib/shared_tools/tools/browser/base_tool.rb,
lib/shared_tools/tools/disk/local_driver.rb,
lib/shared_tools/tools/notification_tool.rb,
lib/shared_tools/tools/browser/click_tool.rb,
lib/shared_tools/tools/browser/visit_tool.rb,
lib/shared_tools/tools/browser/base_driver.rb,
lib/shared_tools/tools/computer/mac_driver.rb,
lib/shared_tools/tools/database_query_tool.rb,
lib/shared_tools/tools/disk/file_move_tool.rb,
lib/shared_tools/tools/disk/file_read_tool.rb,
lib/shared_tools/tools/doc/pdf_reader_tool.rb,
lib/shared_tools/tools/error_handling_tool.rb,
lib/shared_tools/tools/eval/ruby_eval_tool.rb,
lib/shared_tools/tools/browser/inspect_tool.rb,
lib/shared_tools/tools/browser/watir_driver.rb,
lib/shared_tools/tools/computer/base_driver.rb,
lib/shared_tools/tools/database/base_driver.rb,
lib/shared_tools/tools/disk/file_write_tool.rb,
lib/shared_tools/tools/doc/docx_reader_tool.rb,
lib/shared_tools/tools/doc/text_reader_tool.rb,
lib/shared_tools/tools/eval/shell_eval_tool.rb,
lib/shared_tools/tools/search_codebase_tool.rb,
lib/shared_tools/tools/secure_tool_template.rb,
lib/shared_tools/tools/browser/ferrum_driver.rb,
lib/shared_tools/tools/browser/inspect_utils.rb,
lib/shared_tools/tools/disk/file_create_tool.rb,
lib/shared_tools/tools/disk/file_delete_tool.rb,
lib/shared_tools/tools/eval/python_eval_tool.rb,
lib/shared_tools/tools/workflow_manager_tool.rb,
lib/shared_tools/tools/current_date_time_tool.rb,
lib/shared_tools/tools/database/sqlite_driver.rb,
lib/shared_tools/tools/disk/file_replace_tool.rb,
lib/shared_tools/tools/composite_analysis_tool.rb,
lib/shared_tools/tools/docker/compose_run_tool.rb,
lib/shared_tools/tools/notification/mac_driver.rb,
lib/shared_tools/tools/database/postgres_driver.rb,
lib/shared_tools/tools/disk/directory_list_tool.rb,
lib/shared_tools/tools/disk/directory_move_tool.rb,
lib/shared_tools/tools/notification/base_driver.rb,
lib/shared_tools/tools/notification/null_driver.rb,
lib/shared_tools/tools/browser/page_inspect_tool.rb,
lib/shared_tools/tools/notification/linux_driver.rb,
lib/shared_tools/tools/browser/selector_generator.rb,
lib/shared_tools/tools/disk/directory_create_tool.rb,
lib/shared_tools/tools/disk/directory_delete_tool.rb,
lib/shared_tools/tools/doc/spreadsheet_reader_tool.rb,
lib/shared_tools/tools/browser/page_screenshot_tool.rb,
lib/shared_tools/tools/browser/selector_inspect_tool.rb,
lib/shared_tools/tools/browser/elements/element_grouper.rb,
lib/shared_tools/tools/browser/text_field_area_set_tool.rb,
lib/shared_tools/tools/browser/formatters/input_formatter.rb,
lib/shared_tools/tools/browser/formatters/action_formatter.rb,
lib/shared_tools/tools/browser/formatters/element_formatter.rb,
lib/shared_tools/tools/browser/page_inspect/form_summarizer.rb,
lib/shared_tools/tools/browser/page_inspect/html_summarizer.rb,
lib/shared_tools/tools/browser/page_inspect/link_summarizer.rb,
lib/shared_tools/tools/browser/page_inspect/button_summarizer.rb,
lib/shared_tools/tools/browser/formatters/data_entry_formatter.rb,
lib/shared_tools/tools/browser/elements/nearby_element_detector.rb,
lib/shared_tools/tools/browser/selector_generator/base_selectors.rb,
lib/shared_tools/tools/browser/selector_generator/contextual_selectors.rb

Overview

lib/shared_tools/utilities.rb

General-purpose utility methods for SharedTools MCP clients and tools. Loaded automatically by lib/shared_tools.rb.

Defined Under Namespace

Modules: Tools

Constant Summary collapse

VERSION =
"0.4.4"
MCP_LOG_MUTEX =
Mutex.new

Class Method Summary collapse

Class Method Details

.apt_install(*packages) ⇒ Object

Ensures each named binary is available in PATH, installing via apt-get if missing. Raises LoadError if any package install fails.

SharedTools.apt_install("curl")
SharedTools.apt_install("curl", "jq")


134
135
136
137
138
139
140
141
142
# File 'lib/shared_tools/utilities.rb', line 134

def apt_install(*packages)
  packages.each do |pkg|
    # SMELL: what if package is a library?
    next if system("which #{pkg} > /dev/null 2>&1")

    warn "SharedTools — #{pkg} not found, installing via apt-get..."
    raise LoadError, "#{pkg} could not be installed" unless system("sudo apt-get install -y -q #{pkg} > /dev/null 2>&1")
  end
end

.auto_execute(wildwest = true) ⇒ Object



37
38
39
# File 'lib/shared_tools.rb', line 37

def auto_execute(wildwest=true)
  @auto_execute = wildwest
end

.brew_install(*packages) ⇒ Object

Ensures each named binary is available in PATH, installing via brew if missing. Raises LoadError if brew is not installed or any package install fails.

SharedTools.brew_install("github-mcp-server")
SharedTools.brew_install("gh", "jq")

Raises:

  • (LoadError)


118
119
120
121
122
123
124
125
126
127
# File 'lib/shared_tools/utilities.rb', line 118

def brew_install(*packages)
  raise LoadError, "Homebrew is not installed (https://brew.sh)" unless system("which brew > /dev/null 2>&1")

  packages.each do |pkg|
    next unless `brew list --versions #{pkg} 2>/dev/null`.strip.empty?

    warn "SharedTools — #{pkg} not found, installing via brew..."
    raise LoadError, "#{pkg} could not be installed" unless system("brew install --quiet #{pkg} > /dev/null 2>&1")
  end
end

.dnf_install(*packages) ⇒ Object

Ensures each named binary is available in PATH, installing via dnf if missing. Raises LoadError if any package install fails.

SharedTools.dnf_install("curl")
SharedTools.dnf_install("curl", "jq")


149
150
151
152
153
154
155
156
157
# File 'lib/shared_tools/utilities.rb', line 149

def dnf_install(*packages)
  packages.each do |pkg|
    # SMELL: What if package is a library?
    next if system("which #{pkg} > /dev/null 2>&1")

    warn "SharedTools — #{pkg} not found, installing via dnf..."
    raise LoadError, "#{pkg} could not be installed" unless system("sudo dnf install -y -q #{pkg} > /dev/null 2>&1")
  end
end

.execute?(tool: 'unknown', stuff: '') ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/shared_tools.rb', line 41

def execute?(tool: 'unknown', stuff: '')
  # Return true if auto_execute is explicitly enabled
  return true if @auto_execute == true

  puts "\n\nThe AI (tool: #{tool}) wants to do the following ..."
  puts "="*42
  puts(stuff.empty? ? "unknown strange and mysterious things" : stuff)
  puts "="*42

  sleep 0.2 if defined?(AIA) # Allows CLI spinner to recycle
  print "\nIs it okay to proceed? (y/N"
  STDIN.getch == "y"
end

.gem_install(*packages) ⇒ Object

Ensures each named gem is available, installing via gem install if missing. Raises LoadError if gem is not available or any install fails.

SharedTools.gem_install("nokogiri")
SharedTools.gem_install("nokogiri", "oj")

Raises:

  • (LoadError)


181
182
183
184
185
186
187
188
189
190
# File 'lib/shared_tools/utilities.rb', line 181

def gem_install(*packages)
  raise LoadError, "gem is not available" unless system("which gem > /dev/null 2>&1")

  packages.each do |pkg|
    next if system("gem list -i #{pkg} > /dev/null 2>&1")

    warn "SharedTools — #{pkg} not found, installing via gem..."
    raise LoadError, "#{pkg} could not be installed" unless system("gem install --silent #{pkg} > /dev/null 2>&1")
  end
end

.load_all_toolsObject

Force-load all tool classes into ObjectSpace. Called by AIA’s GemActivator.trigger_tool_loading when shared_tools is passed to –require. Without this, Zeitwerk lazy-loads classes on first reference, so no RubyLLM::Tool subclasses appear in ObjectSpace at scan time.



59
60
61
# File 'lib/shared_tools.rb', line 59

def load_all_tools
  SharedToolsLoader.eager_load
end

.mcp_failedObject

Returns a hash of client names that failed to load, mapped to their error messages.

SharedTools.mcp_failed  #=> {"tavily" => "Missing envars: TAVILY_API_KEY", ...}


39
40
41
42
43
# File 'lib/shared_tools/utilities.rb', line 39

def mcp_failed
  MCP_LOG_MUTEX.synchronize do
    @mcp_load_log.select { |_, v| v[:status] == :failed }.transform_values { |v| v[:reason] }
  end
end

.mcp_loadedObject

Returns an array of client names that loaded successfully.

SharedTools.mcp_loaded  #=> ["github", "memory", "chart"]


32
33
34
# File 'lib/shared_tools/utilities.rb', line 32

def mcp_loaded
  MCP_LOG_MUTEX.synchronize { @mcp_load_log.select { |_, v| v[:status] == :ok }.keys }
end

.mcp_statusObject

Prints a summary table of MCP client load results and returns the full log hash.

SharedTools.mcp_status
# MCP Client Status
# ✓ github
# ✓ memory
# ✗ tavily   — Missing envars: TAVILY_API_KEY


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/shared_tools/utilities.rb', line 52

def mcp_status
  log = MCP_LOG_MUTEX.synchronize { @mcp_load_log.dup }

  if log.empty?
    puts "No MCP clients have been loaded yet. Try: require 'shared_tools/mcp'"
    return log
  end

  puts "MCP Client Status"
  puts "-" * 40
  log.sort.each do |name, entry|
    if entry[:status] == :ok
      puts "  \u2713 #{name}"
    else
      puts "  \u2717 #{name}  \u2014 #{entry[:reason]}"
    end
  end
  puts "-" * 40
  puts "  #{log.count { |_, v| v[:status] == :ok }} loaded, " \
       "#{log.count { |_, v| v[:status] == :failed }} skipped"

  log
end

.npm_install(*packages) ⇒ Object

Ensures each named npm package binary is available in PATH, installing globally via npm if missing. Raises LoadError if npm is not found or any install fails.

SharedTools.npm_install("typescript")
SharedTools.npm_install("typescript", "ts-node")

Raises:

  • (LoadError)


164
165
166
167
168
169
170
171
172
173
174
# File 'lib/shared_tools/utilities.rb', line 164

def npm_install(*packages)
  raise LoadError, "npm is not installed (https://nodejs.org)" unless system("which npm > /dev/null 2>&1")

  packages.each do |pkg|
    # SMELL: What if package is a library?
    next if system("which #{pkg} > /dev/null 2>&1")

    warn "SharedTools — #{pkg} not found, installing via npm..."
    raise LoadError, "#{pkg} could not be installed" unless system("npm install -g --silent #{pkg} > /dev/null 2>&1")
  end
end

.package_install(*packages) ⇒ Object

High-level package installer. Detects the current platform and calls the appropriate *_install method. Raises LoadError if any package cannot be installed.

SharedTools.package_install("github-mcp-server")
SharedTools.package_install("curl", "jq")


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/shared_tools/utilities.rb', line 94

def package_install(*packages)
  case RUBY_PLATFORM
  when /darwin/
    brew_install(*packages)
  when /linux/
    if system("which apt-get > /dev/null 2>&1")
      apt_install(*packages)
    elsif system("which dnf > /dev/null 2>&1")
      dnf_install(*packages)
    elsif system("which brew > /dev/null 2>&1")
      brew_install(*packages)
    else
      raise LoadError, "No supported package manager found (apt-get, dnf, brew)"
    end
  else
    raise LoadError, "Unsupported platform: #{RUBY_PLATFORM}"
  end
end

.record_mcp_result(name, error: nil) ⇒ Object

Record the outcome of loading a single MCP client. Called by mcp.rb from within each loader thread.

SharedTools.record_mcp_result("tavily")              # success
SharedTools.record_mcp_result("notion", error: e)    # failure


23
24
25
26
27
# File 'lib/shared_tools/utilities.rb', line 23

def record_mcp_result(name, error: nil)
  MCP_LOG_MUTEX.synchronize do
    @mcp_load_log[name] = error ? { status: :failed, reason: error.message } : { status: :ok }
  end
end

.toolsObject

Return all loaded RubyLLM::Tool subclasses provided by this gem. Also triggers eager loading so the list is complete.



65
66
67
68
# File 'lib/shared_tools.rb', line 65

def tools
  load_all_tools
  ObjectSpace.each_object(Class).select { |k| k < ::RubyLLM::Tool }.to_a
end

.verify_envars(*names) ⇒ Object

Returns true if all named environment variables are set and non-empty. Warns for each missing variable and returns false if any are absent.

SharedTools.verify_envars("GITHUB_PERSONAL_ACCESS_TOKEN")
SharedTools.verify_envars("TAVILY_API_KEY", "ANOTHER_KEY")


81
82
83
84
85
86
87
# File 'lib/shared_tools/utilities.rb', line 81

def verify_envars(*names)
  missing = names.select { |n| ENV.fetch(n, "").empty? }
  missing.each { |n| warn "SharedTools — #{n} is not set" }
  unless missing.empty?
    raise LoadError, "Missing envars: #{missing.join(', ')}"
  end
end