shared_tools 0.3.0 → 0.3.1
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/shared_tools/tools/browser_tool.rb +8 -2
- data/lib/shared_tools/tools/clipboard_tool.rb +194 -0
- data/lib/shared_tools/tools/computer_tool.rb +8 -2
- data/lib/shared_tools/tools/cron_tool.rb +474 -0
- data/lib/shared_tools/tools/current_date_time_tool.rb +154 -0
- data/lib/shared_tools/tools/database_tool.rb +8 -3
- data/lib/shared_tools/tools/dns_tool.rb +356 -0
- data/lib/shared_tools/tools/system_info_tool.rb +417 -0
- data/lib/shared_tools/version.rb +1 -1
- data/lib/shared_tools.rb +54 -13
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5775624c9ae2d7f0fb1a47c515b2dbe7316faaee9de7bc62823e0d602274a0a
|
|
4
|
+
data.tar.gz: 480df1266dc12f1bd4104ef3f80a78b895ac22ebf149b9090f0bcf679bcb8a99
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 00a01f1113bb7e728b00aa196f998850c66246d4e5e26d7e1db16d0314bf3f2993f1632dafe964ea347690a6a03a9e9c04440ed47ef1f1870c858c1f2eda3aed
|
|
7
|
+
data.tar.gz: 613fbbae8478fa3b805d368102e31cf9c9709e16f954f87a8fea10aa8f148550147f884b68956714eb817cd6288b1f4213b3612ea887ad502e8be8d13973db74
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
5
|
## Released
|
|
6
|
+
### [0.3.1] 2025-12-17
|
|
7
|
+
|
|
8
|
+
- added ClipboardTool for cross-platform clipboard read/write operations
|
|
9
|
+
- added CronTool for cron expression parsing and scheduling
|
|
10
|
+
- added CurrentDateTimeTool for date/time retrieval with timezone support
|
|
11
|
+
- added DnsTool for DNS lookups and resolution
|
|
12
|
+
- added SystemInfoTool for system information retrieval
|
|
13
|
+
- updated gem dependencies and Zeitwerk configuration
|
|
14
|
+
- improved BrowserTool, ComputerTool, and DatabaseTool implementations
|
|
15
|
+
- updated GitHub Pages deployment workflow
|
|
16
|
+
- fixed a problem with eager loading when used with the `aia` gem
|
|
17
|
+
|
|
6
18
|
### [0.3.0] 2025-11-08
|
|
7
19
|
- changed focus of shared_tools to only support the ruby_llm and ruby_llm-mcp ecosystem
|
|
8
20
|
|
|
@@ -146,12 +146,15 @@ module SharedTools
|
|
|
146
146
|
|
|
147
147
|
|
|
148
148
|
# @param logger [Logger] optional logger
|
|
149
|
-
# @param driver [SharedTools::Tools::Browser::BaseDriver] optional, will attempt to create WatirDriver
|
|
149
|
+
# @param driver [SharedTools::Tools::Browser::BaseDriver] optional, will attempt to create WatirDriver when execute is called
|
|
150
150
|
def initialize(logger: nil, driver: nil)
|
|
151
151
|
@logger = logger || RubyLLM.logger
|
|
152
|
-
@driver = driver
|
|
152
|
+
@driver = driver # Defer default_driver to execute time to support RubyLLM tool discovery
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
# Set driver after instantiation (useful when tool is discovered by RubyLLM)
|
|
156
|
+
attr_writer :driver
|
|
157
|
+
|
|
155
158
|
def cleanup!
|
|
156
159
|
@driver.close
|
|
157
160
|
end
|
|
@@ -166,6 +169,9 @@ module SharedTools
|
|
|
166
169
|
#
|
|
167
170
|
# @return [String]
|
|
168
171
|
def execute(action:, url: nil, selector: nil, value: nil, context_size: 2, full_html: false, text_content: nil)
|
|
172
|
+
# Lazily resolve driver at execute time
|
|
173
|
+
@driver ||= default_driver
|
|
174
|
+
|
|
169
175
|
case action.to_s.downcase
|
|
170
176
|
when Action::VISIT
|
|
171
177
|
require_param!(:url, url)
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ruby_llm/tool'
|
|
4
|
+
|
|
5
|
+
module SharedTools
|
|
6
|
+
module Tools
|
|
7
|
+
# A tool for reading from and writing to the system clipboard.
|
|
8
|
+
# Supports macOS (pbcopy/pbpaste), Linux (xclip/xsel), and Windows (clip).
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# tool = SharedTools::Tools::ClipboardTool.new
|
|
12
|
+
# tool.execute(action: 'write', content: 'Hello, World!')
|
|
13
|
+
# result = tool.execute(action: 'read')
|
|
14
|
+
# puts result[:content] # "Hello, World!"
|
|
15
|
+
class ClipboardTool < RubyLLM::Tool
|
|
16
|
+
def self.name = 'clipboard'
|
|
17
|
+
|
|
18
|
+
description <<~'DESCRIPTION'
|
|
19
|
+
Read from or write to the system clipboard.
|
|
20
|
+
|
|
21
|
+
This tool provides cross-platform clipboard access:
|
|
22
|
+
- macOS: Uses pbcopy/pbpaste
|
|
23
|
+
- Linux: Uses xclip or xsel (must be installed)
|
|
24
|
+
- Windows: Uses clip/powershell
|
|
25
|
+
|
|
26
|
+
Actions:
|
|
27
|
+
- 'read': Get the current clipboard contents
|
|
28
|
+
- 'write': Set the clipboard contents
|
|
29
|
+
- 'clear': Clear the clipboard
|
|
30
|
+
|
|
31
|
+
Example usage:
|
|
32
|
+
tool = SharedTools::Tools::ClipboardTool.new
|
|
33
|
+
|
|
34
|
+
# Write to clipboard
|
|
35
|
+
tool.execute(action: 'write', content: 'Hello, World!')
|
|
36
|
+
|
|
37
|
+
# Read from clipboard
|
|
38
|
+
result = tool.execute(action: 'read')
|
|
39
|
+
puts result[:content]
|
|
40
|
+
|
|
41
|
+
# Clear clipboard
|
|
42
|
+
tool.execute(action: 'clear')
|
|
43
|
+
DESCRIPTION
|
|
44
|
+
|
|
45
|
+
params do
|
|
46
|
+
string :action, description: <<~DESC.strip
|
|
47
|
+
The clipboard action to perform:
|
|
48
|
+
- 'read': Get current clipboard contents
|
|
49
|
+
- 'write': Set clipboard contents (requires 'content' parameter)
|
|
50
|
+
- 'clear': Clear the clipboard
|
|
51
|
+
DESC
|
|
52
|
+
|
|
53
|
+
string :content, description: <<~DESC.strip, required: false
|
|
54
|
+
The text content to write to the clipboard.
|
|
55
|
+
Required when action is 'write'.
|
|
56
|
+
DESC
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @param logger [Logger] optional logger
|
|
60
|
+
def initialize(logger: nil)
|
|
61
|
+
@logger = logger || RubyLLM.logger
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Execute clipboard action
|
|
65
|
+
#
|
|
66
|
+
# @param action [String] 'read', 'write', or 'clear'
|
|
67
|
+
# @param content [String, nil] content to write (required for 'write' action)
|
|
68
|
+
# @return [Hash] result with success status and content/error
|
|
69
|
+
def execute(action:, content: nil)
|
|
70
|
+
@logger.info("ClipboardTool#execute action=#{action.inspect}")
|
|
71
|
+
|
|
72
|
+
case action.to_s.downcase
|
|
73
|
+
when 'read'
|
|
74
|
+
read_clipboard
|
|
75
|
+
when 'write'
|
|
76
|
+
write_clipboard(content)
|
|
77
|
+
when 'clear'
|
|
78
|
+
clear_clipboard
|
|
79
|
+
else
|
|
80
|
+
{
|
|
81
|
+
success: false,
|
|
82
|
+
error: "Unknown action: #{action}. Valid actions are: read, write, clear"
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
rescue => e
|
|
86
|
+
@logger.error("ClipboardTool error: #{e.message}")
|
|
87
|
+
{
|
|
88
|
+
success: false,
|
|
89
|
+
error: e.message
|
|
90
|
+
}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def read_clipboard
|
|
96
|
+
content = case platform
|
|
97
|
+
when :macos
|
|
98
|
+
`pbpaste 2>/dev/null`
|
|
99
|
+
when :linux
|
|
100
|
+
if command_exists?('xclip')
|
|
101
|
+
`xclip -selection clipboard -o 2>/dev/null`
|
|
102
|
+
elsif command_exists?('xsel')
|
|
103
|
+
`xsel --clipboard --output 2>/dev/null`
|
|
104
|
+
else
|
|
105
|
+
raise "No clipboard tool found. Install xclip or xsel."
|
|
106
|
+
end
|
|
107
|
+
when :windows
|
|
108
|
+
`powershell -command "Get-Clipboard" 2>nul`.chomp
|
|
109
|
+
else
|
|
110
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
success: true,
|
|
115
|
+
content: content,
|
|
116
|
+
length: content.length
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def write_clipboard(content)
|
|
121
|
+
if content.nil? || content.empty?
|
|
122
|
+
return {
|
|
123
|
+
success: false,
|
|
124
|
+
error: "Content is required for write action"
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
case platform
|
|
129
|
+
when :macos
|
|
130
|
+
IO.popen('pbcopy', 'w') { |io| io.print content }
|
|
131
|
+
when :linux
|
|
132
|
+
if command_exists?('xclip')
|
|
133
|
+
IO.popen('xclip -selection clipboard', 'w') { |io| io.print content }
|
|
134
|
+
elsif command_exists?('xsel')
|
|
135
|
+
IO.popen('xsel --clipboard --input', 'w') { |io| io.print content }
|
|
136
|
+
else
|
|
137
|
+
raise "No clipboard tool found. Install xclip or xsel."
|
|
138
|
+
end
|
|
139
|
+
when :windows
|
|
140
|
+
IO.popen('clip', 'w') { |io| io.print content }
|
|
141
|
+
else
|
|
142
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
{
|
|
146
|
+
success: true,
|
|
147
|
+
message: "Content written to clipboard",
|
|
148
|
+
length: content.length
|
|
149
|
+
}
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def clear_clipboard
|
|
153
|
+
case platform
|
|
154
|
+
when :macos
|
|
155
|
+
IO.popen('pbcopy', 'w') { |io| io.print '' }
|
|
156
|
+
when :linux
|
|
157
|
+
if command_exists?('xclip')
|
|
158
|
+
IO.popen('xclip -selection clipboard', 'w') { |io| io.print '' }
|
|
159
|
+
elsif command_exists?('xsel')
|
|
160
|
+
IO.popen('xsel --clipboard --input', 'w') { |io| io.print '' }
|
|
161
|
+
else
|
|
162
|
+
raise "No clipboard tool found. Install xclip or xsel."
|
|
163
|
+
end
|
|
164
|
+
when :windows
|
|
165
|
+
IO.popen('clip', 'w') { |io| io.print '' }
|
|
166
|
+
else
|
|
167
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
{
|
|
171
|
+
success: true,
|
|
172
|
+
message: "Clipboard cleared"
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def platform
|
|
177
|
+
case RUBY_PLATFORM
|
|
178
|
+
when /darwin/
|
|
179
|
+
:macos
|
|
180
|
+
when /linux/
|
|
181
|
+
:linux
|
|
182
|
+
when /mswin|mingw|cygwin/
|
|
183
|
+
:windows
|
|
184
|
+
else
|
|
185
|
+
:unknown
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def command_exists?(cmd)
|
|
190
|
+
system("which #{cmd} > /dev/null 2>&1")
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -139,13 +139,16 @@ module SharedTools
|
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
# @param driver [Computer::BaseDriver] optional, will attempt to create platform-specific driver
|
|
142
|
+
# @param driver [Computer::BaseDriver] optional, will attempt to create platform-specific driver when execute is called
|
|
143
143
|
# @param logger [Logger] optional logger
|
|
144
144
|
def initialize(driver: nil, logger: nil)
|
|
145
145
|
@logger = logger || RubyLLM.logger
|
|
146
|
-
@driver = driver
|
|
146
|
+
@driver = driver # Defer default_driver to execute time to support RubyLLM tool discovery
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
# Set driver after instantiation (useful when tool is discovered by RubyLLM)
|
|
150
|
+
attr_writer :driver
|
|
151
|
+
|
|
149
152
|
# @param action [String]
|
|
150
153
|
# @param coordinate [Hash<{ width: Integer, height: Integer }>] the (x,y) coordinate
|
|
151
154
|
# @param text [String]
|
|
@@ -162,6 +165,9 @@ module SharedTools
|
|
|
162
165
|
scroll_direction: nil,
|
|
163
166
|
scroll_amount: nil
|
|
164
167
|
)
|
|
168
|
+
# Lazily resolve driver at execute time
|
|
169
|
+
@driver ||= default_driver
|
|
170
|
+
|
|
165
171
|
@logger.info({
|
|
166
172
|
action:,
|
|
167
173
|
coordinate:,
|