headless_browser_tool 0.1.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 +7 -0
- data/.claude/settings.json +21 -0
- data/.rubocop.yml +56 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CLAUDE.md +298 -0
- data/LICENSE.md +7 -0
- data/README.md +522 -0
- data/Rakefile +12 -0
- data/config.ru +8 -0
- data/exe/hbt +7 -0
- data/lib/headless_browser_tool/browser.rb +374 -0
- data/lib/headless_browser_tool/browser_adapter.rb +320 -0
- data/lib/headless_browser_tool/cli.rb +34 -0
- data/lib/headless_browser_tool/directory_setup.rb +25 -0
- data/lib/headless_browser_tool/logger.rb +31 -0
- data/lib/headless_browser_tool/server.rb +150 -0
- data/lib/headless_browser_tool/session_manager.rb +199 -0
- data/lib/headless_browser_tool/session_middleware.rb +158 -0
- data/lib/headless_browser_tool/session_persistence.rb +146 -0
- data/lib/headless_browser_tool/stdio_server.rb +73 -0
- data/lib/headless_browser_tool/strict_session_middleware.rb +88 -0
- data/lib/headless_browser_tool/tools/attach_file_tool.rb +40 -0
- data/lib/headless_browser_tool/tools/auto_narrate_tool.rb +155 -0
- data/lib/headless_browser_tool/tools/base_tool.rb +39 -0
- data/lib/headless_browser_tool/tools/check_tool.rb +35 -0
- data/lib/headless_browser_tool/tools/choose_tool.rb +56 -0
- data/lib/headless_browser_tool/tools/click_button_tool.rb +49 -0
- data/lib/headless_browser_tool/tools/click_link_tool.rb +48 -0
- data/lib/headless_browser_tool/tools/click_tool.rb +45 -0
- data/lib/headless_browser_tool/tools/close_window_tool.rb +31 -0
- data/lib/headless_browser_tool/tools/double_click_tool.rb +37 -0
- data/lib/headless_browser_tool/tools/drag_tool.rb +46 -0
- data/lib/headless_browser_tool/tools/evaluate_script_tool.rb +20 -0
- data/lib/headless_browser_tool/tools/execute_script_tool.rb +29 -0
- data/lib/headless_browser_tool/tools/fill_in_tool.rb +66 -0
- data/lib/headless_browser_tool/tools/find_all_tool.rb +42 -0
- data/lib/headless_browser_tool/tools/find_element_tool.rb +21 -0
- data/lib/headless_browser_tool/tools/find_elements_containing_text_tool.rb +259 -0
- data/lib/headless_browser_tool/tools/get_attribute_tool.rb +21 -0
- data/lib/headless_browser_tool/tools/get_current_path_tool.rb +16 -0
- data/lib/headless_browser_tool/tools/get_current_url_tool.rb +16 -0
- data/lib/headless_browser_tool/tools/get_narration_history_tool.rb +35 -0
- data/lib/headless_browser_tool/tools/get_page_context_tool.rb +188 -0
- data/lib/headless_browser_tool/tools/get_page_source_tool.rb +16 -0
- data/lib/headless_browser_tool/tools/get_page_title_tool.rb +16 -0
- data/lib/headless_browser_tool/tools/get_session_info_tool.rb +37 -0
- data/lib/headless_browser_tool/tools/get_text_tool.rb +20 -0
- data/lib/headless_browser_tool/tools/get_value_tool.rb +20 -0
- data/lib/headless_browser_tool/tools/get_window_handles_tool.rb +29 -0
- data/lib/headless_browser_tool/tools/go_back_tool.rb +29 -0
- data/lib/headless_browser_tool/tools/go_forward_tool.rb +29 -0
- data/lib/headless_browser_tool/tools/has_element_tool.rb +21 -0
- data/lib/headless_browser_tool/tools/has_text_tool.rb +21 -0
- data/lib/headless_browser_tool/tools/hover_tool.rb +38 -0
- data/lib/headless_browser_tool/tools/is_visible_tool.rb +20 -0
- data/lib/headless_browser_tool/tools/maximize_window_tool.rb +34 -0
- data/lib/headless_browser_tool/tools/open_new_window_tool.rb +25 -0
- data/lib/headless_browser_tool/tools/refresh_tool.rb +32 -0
- data/lib/headless_browser_tool/tools/resize_window_tool.rb +43 -0
- data/lib/headless_browser_tool/tools/right_click_tool.rb +37 -0
- data/lib/headless_browser_tool/tools/save_page_tool.rb +32 -0
- data/lib/headless_browser_tool/tools/screenshot_tool.rb +199 -0
- data/lib/headless_browser_tool/tools/search_page_tool.rb +224 -0
- data/lib/headless_browser_tool/tools/search_source_tool.rb +148 -0
- data/lib/headless_browser_tool/tools/select_tool.rb +44 -0
- data/lib/headless_browser_tool/tools/switch_to_window_tool.rb +30 -0
- data/lib/headless_browser_tool/tools/uncheck_tool.rb +35 -0
- data/lib/headless_browser_tool/tools/visit_tool.rb +27 -0
- data/lib/headless_browser_tool/tools/visual_diff_tool.rb +177 -0
- data/lib/headless_browser_tool/tools.rb +104 -0
- data/lib/headless_browser_tool/version.rb +5 -0
- data/lib/headless_browser_tool.rb +8 -0
- metadata +256 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_tool"
|
4
|
+
|
5
|
+
module HeadlessBrowserTool
|
6
|
+
module Tools
|
7
|
+
class SwitchToWindowTool < BaseTool
|
8
|
+
tool_name "switch_to_window"
|
9
|
+
description "Switch to specific browser window/tab"
|
10
|
+
|
11
|
+
arguments do
|
12
|
+
required(:window_handle).filled(:string).description("Handle of the window to switch to")
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(window_handle:)
|
16
|
+
previous_window = browser.current_window
|
17
|
+
browser.switch_to_window(window_handle)
|
18
|
+
|
19
|
+
{
|
20
|
+
window_handle: window_handle,
|
21
|
+
previous_window: previous_window,
|
22
|
+
current_url: browser.current_url,
|
23
|
+
title: browser.title,
|
24
|
+
total_windows: browser.windows.count,
|
25
|
+
status: "switched"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_tool"
|
4
|
+
|
5
|
+
module HeadlessBrowserTool
|
6
|
+
module Tools
|
7
|
+
class UncheckTool < BaseTool
|
8
|
+
tool_name "uncheck"
|
9
|
+
description "Uncheck a checkbox by selector"
|
10
|
+
|
11
|
+
arguments do
|
12
|
+
required(:checkbox_selector).filled(:string).description("CSS selector of the checkbox to uncheck")
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(checkbox_selector:)
|
16
|
+
element = browser.find(checkbox_selector)
|
17
|
+
was_checked = element.checked?
|
18
|
+
browser.uncheck(checkbox_selector)
|
19
|
+
|
20
|
+
{
|
21
|
+
selector: checkbox_selector,
|
22
|
+
was_checked: was_checked,
|
23
|
+
is_checked: false,
|
24
|
+
element: {
|
25
|
+
id: element[:id],
|
26
|
+
name: element[:name],
|
27
|
+
value: element[:value],
|
28
|
+
type: element[:type]
|
29
|
+
}.compact,
|
30
|
+
status: "unchecked"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_tool"
|
4
|
+
|
5
|
+
module HeadlessBrowserTool
|
6
|
+
module Tools
|
7
|
+
class VisitTool < BaseTool
|
8
|
+
tool_name "visit"
|
9
|
+
description "Navigate to a URL"
|
10
|
+
|
11
|
+
arguments do
|
12
|
+
required(:url).filled(:string).description("The URL to navigate to")
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(url:)
|
16
|
+
browser.visit(url)
|
17
|
+
|
18
|
+
{
|
19
|
+
url: url,
|
20
|
+
current_url: browser.current_url,
|
21
|
+
title: browser.title,
|
22
|
+
status: "success"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base_tool"
|
4
|
+
|
5
|
+
module HeadlessBrowserTool
|
6
|
+
module Tools
|
7
|
+
class VisualDiffTool < BaseTool
|
8
|
+
tool_name "visual_diff"
|
9
|
+
description "Capture what changed on the page after an action"
|
10
|
+
|
11
|
+
def execute
|
12
|
+
# Capture current state
|
13
|
+
current_state = capture_page_state
|
14
|
+
|
15
|
+
# Compare with previous state if exists
|
16
|
+
previous_state = browser.previous_state || {}
|
17
|
+
|
18
|
+
changes = {
|
19
|
+
url_changed: previous_state[:url] != current_state[:url],
|
20
|
+
title_changed: previous_state[:title] != current_state[:title],
|
21
|
+
new_elements: find_new_elements(previous_state[:elements], current_state[:elements]),
|
22
|
+
removed_elements: find_removed_elements(previous_state[:elements], current_state[:elements]),
|
23
|
+
text_changes: find_text_changes(previous_state[:texts], current_state[:texts]),
|
24
|
+
form_values_changed: compare_form_values(previous_state[:forms], current_state[:forms]),
|
25
|
+
new_images: current_state[:images] - (previous_state[:images] || []),
|
26
|
+
viewport_position: current_state[:scroll]
|
27
|
+
}
|
28
|
+
|
29
|
+
# Store current state for next comparison
|
30
|
+
browser.previous_state = current_state
|
31
|
+
|
32
|
+
# Return human-readable summary
|
33
|
+
summarize_changes(changes, current_state)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def capture_page_state
|
39
|
+
state_script = <<~JS
|
40
|
+
(() => {
|
41
|
+
// Get all visible text nodes
|
42
|
+
const texts = [];
|
43
|
+
const walker = document.createTreeWalker(
|
44
|
+
document.body,
|
45
|
+
NodeFilter.SHOW_TEXT,
|
46
|
+
{
|
47
|
+
acceptNode: (node) => {
|
48
|
+
const parent = node.parentElement;
|
49
|
+
if (parent && parent.offsetWidth > 0 && parent.offsetHeight > 0) {
|
50
|
+
const text = node.textContent.trim();
|
51
|
+
if (text.length > 0) return NodeFilter.FILTER_ACCEPT;
|
52
|
+
}
|
53
|
+
return NodeFilter.FILTER_REJECT;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
);
|
57
|
+
|
58
|
+
let node;
|
59
|
+
while (node = walker.nextNode()) {
|
60
|
+
texts.push(node.textContent.trim());
|
61
|
+
}
|
62
|
+
|
63
|
+
// Get form values
|
64
|
+
const forms = {};
|
65
|
+
document.querySelectorAll('input, select, textarea').forEach(el => {
|
66
|
+
if (el.name || el.id) {
|
67
|
+
forms[el.name || el.id] = el.value;
|
68
|
+
}
|
69
|
+
});
|
70
|
+
|
71
|
+
// Get interactive elements count
|
72
|
+
const elements = {
|
73
|
+
buttons: document.querySelectorAll('button, [role="button"]').length,
|
74
|
+
links: document.querySelectorAll('a[href]').length,
|
75
|
+
inputs: document.querySelectorAll('input, textarea, select').length,
|
76
|
+
images: document.querySelectorAll('img').length
|
77
|
+
};
|
78
|
+
|
79
|
+
// Get images
|
80
|
+
const images = Array.from(document.querySelectorAll('img')).map(img => img.alt || img.src);
|
81
|
+
|
82
|
+
return {
|
83
|
+
url: window.location.href,
|
84
|
+
title: document.title,
|
85
|
+
texts: texts,
|
86
|
+
forms: forms,
|
87
|
+
elements: elements,
|
88
|
+
images: images,
|
89
|
+
scroll: { x: window.scrollX, y: window.scrollY }
|
90
|
+
};
|
91
|
+
})();
|
92
|
+
JS
|
93
|
+
|
94
|
+
state = browser.evaluate_script(state_script)
|
95
|
+
state || {}
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_new_elements(old_elements, new_elements)
|
99
|
+
return {} unless old_elements && new_elements
|
100
|
+
|
101
|
+
changes = {}
|
102
|
+
new_elements.each do |key, count|
|
103
|
+
old_count = old_elements[key] || 0
|
104
|
+
changes[key] = count - old_count if count > old_count
|
105
|
+
end
|
106
|
+
changes
|
107
|
+
end
|
108
|
+
|
109
|
+
def find_removed_elements(old_elements, new_elements)
|
110
|
+
return {} unless old_elements && new_elements
|
111
|
+
|
112
|
+
changes = {}
|
113
|
+
old_elements.each do |key, count|
|
114
|
+
new_count = new_elements[key] || 0
|
115
|
+
changes[key] = count - new_count if count > new_count
|
116
|
+
end
|
117
|
+
changes
|
118
|
+
end
|
119
|
+
|
120
|
+
def find_text_changes(old_texts, new_texts)
|
121
|
+
return [] unless old_texts && new_texts
|
122
|
+
|
123
|
+
# Find completely new text blocks
|
124
|
+
new_text_blocks = new_texts - old_texts
|
125
|
+
new_text_blocks.select { |text| text.length > 20 } # Only significant text
|
126
|
+
end
|
127
|
+
|
128
|
+
def compare_form_values(old_forms, new_forms)
|
129
|
+
return {} unless old_forms && new_forms
|
130
|
+
|
131
|
+
changes = {}
|
132
|
+
new_forms.each do |field, value|
|
133
|
+
changes[field] = { from: old_forms[field], to: value } if old_forms[field] != value && !value.empty?
|
134
|
+
end
|
135
|
+
changes
|
136
|
+
end
|
137
|
+
|
138
|
+
def summarize_changes(changes, current_state)
|
139
|
+
summary = []
|
140
|
+
|
141
|
+
# URL change
|
142
|
+
summary << "📍 Navigated to: #{current_state[:url]}" if changes[:url_changed]
|
143
|
+
|
144
|
+
# Title change
|
145
|
+
summary << "📄 Page title: \"#{current_state[:title]}\"" if changes[:title_changed]
|
146
|
+
|
147
|
+
# New elements appeared
|
148
|
+
if changes[:new_elements].any?
|
149
|
+
changes[:new_elements].each do |type, count|
|
150
|
+
summary << "➕ #{count} new #{type} appeared"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Elements removed
|
155
|
+
if changes[:removed_elements].any?
|
156
|
+
changes[:removed_elements].each do |type, count|
|
157
|
+
summary << "➖ #{count} #{type} removed"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Form changes
|
162
|
+
summary << "✏️ Form fields updated: #{changes[:form_values_changed].keys.join(", ")}" if changes[:form_values_changed].any?
|
163
|
+
|
164
|
+
# New significant text
|
165
|
+
summary << "💬 New text appeared: \"#{changes[:text_changes].first[0..100]}...\"" if changes[:text_changes].any?
|
166
|
+
|
167
|
+
# Scroll position
|
168
|
+
summary << "📜 Page scrolled to position: #{changes[:viewport_position][:y]}px" if changes[:viewport_position][:y] > 100
|
169
|
+
|
170
|
+
# If no changes detected
|
171
|
+
summary << "No significant visual changes detected" if summary.empty?
|
172
|
+
|
173
|
+
summary.join("\n")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "tools/base_tool"
|
4
|
+
require_relative "tools/visit_tool"
|
5
|
+
require_relative "tools/refresh_tool"
|
6
|
+
require_relative "tools/go_back_tool"
|
7
|
+
require_relative "tools/go_forward_tool"
|
8
|
+
require_relative "tools/click_tool"
|
9
|
+
require_relative "tools/right_click_tool"
|
10
|
+
require_relative "tools/double_click_tool"
|
11
|
+
require_relative "tools/hover_tool"
|
12
|
+
require_relative "tools/drag_tool"
|
13
|
+
require_relative "tools/find_element_tool"
|
14
|
+
require_relative "tools/find_all_tool"
|
15
|
+
require_relative "tools/find_elements_containing_text_tool"
|
16
|
+
require_relative "tools/get_text_tool"
|
17
|
+
require_relative "tools/get_attribute_tool"
|
18
|
+
require_relative "tools/get_value_tool"
|
19
|
+
require_relative "tools/is_visible_tool"
|
20
|
+
require_relative "tools/has_element_tool"
|
21
|
+
require_relative "tools/has_text_tool"
|
22
|
+
require_relative "tools/fill_in_tool"
|
23
|
+
require_relative "tools/select_tool"
|
24
|
+
require_relative "tools/check_tool"
|
25
|
+
require_relative "tools/uncheck_tool"
|
26
|
+
require_relative "tools/choose_tool"
|
27
|
+
require_relative "tools/attach_file_tool"
|
28
|
+
require_relative "tools/click_button_tool"
|
29
|
+
require_relative "tools/click_link_tool"
|
30
|
+
require_relative "tools/get_current_url_tool"
|
31
|
+
require_relative "tools/get_current_path_tool"
|
32
|
+
require_relative "tools/get_page_title_tool"
|
33
|
+
require_relative "tools/get_page_source_tool"
|
34
|
+
require_relative "tools/execute_script_tool"
|
35
|
+
require_relative "tools/evaluate_script_tool"
|
36
|
+
require_relative "tools/save_page_tool"
|
37
|
+
require_relative "tools/switch_to_window_tool"
|
38
|
+
require_relative "tools/open_new_window_tool"
|
39
|
+
require_relative "tools/close_window_tool"
|
40
|
+
require_relative "tools/get_window_handles_tool"
|
41
|
+
require_relative "tools/maximize_window_tool"
|
42
|
+
require_relative "tools/resize_window_tool"
|
43
|
+
require_relative "tools/screenshot_tool"
|
44
|
+
require_relative "tools/search_page_tool"
|
45
|
+
require_relative "tools/search_source_tool"
|
46
|
+
require_relative "tools/visual_diff_tool"
|
47
|
+
require_relative "tools/get_page_context_tool"
|
48
|
+
require_relative "tools/auto_narrate_tool"
|
49
|
+
require_relative "tools/get_narration_history_tool"
|
50
|
+
require_relative "tools/get_session_info_tool"
|
51
|
+
|
52
|
+
module HeadlessBrowserTool
|
53
|
+
module Tools
|
54
|
+
ALL_TOOLS = [
|
55
|
+
VisitTool,
|
56
|
+
RefreshTool,
|
57
|
+
GoBackTool,
|
58
|
+
GoForwardTool,
|
59
|
+
ClickTool,
|
60
|
+
RightClickTool,
|
61
|
+
DoubleClickTool,
|
62
|
+
HoverTool,
|
63
|
+
DragTool,
|
64
|
+
FindElementTool,
|
65
|
+
FindAllTool,
|
66
|
+
FindElementsContainingTextTool,
|
67
|
+
GetTextTool,
|
68
|
+
GetAttributeTool,
|
69
|
+
GetValueTool,
|
70
|
+
IsVisibleTool,
|
71
|
+
HasElementTool,
|
72
|
+
HasTextTool,
|
73
|
+
FillInTool,
|
74
|
+
SelectTool,
|
75
|
+
CheckTool,
|
76
|
+
UncheckTool,
|
77
|
+
ChooseTool,
|
78
|
+
AttachFileTool,
|
79
|
+
ClickButtonTool,
|
80
|
+
ClickLinkTool,
|
81
|
+
GetCurrentUrlTool,
|
82
|
+
GetCurrentPathTool,
|
83
|
+
GetPageTitleTool,
|
84
|
+
GetPageSourceTool,
|
85
|
+
ExecuteScriptTool,
|
86
|
+
EvaluateScriptTool,
|
87
|
+
SavePageTool,
|
88
|
+
SwitchToWindowTool,
|
89
|
+
OpenNewWindowTool,
|
90
|
+
CloseWindowTool,
|
91
|
+
GetWindowHandlesTool,
|
92
|
+
MaximizeWindowTool,
|
93
|
+
ResizeWindowTool,
|
94
|
+
ScreenshotTool,
|
95
|
+
SearchPageTool,
|
96
|
+
SearchSourceTool,
|
97
|
+
VisualDiffTool,
|
98
|
+
GetPageContextTool,
|
99
|
+
AutoNarrateTool,
|
100
|
+
GetNarrationHistoryTool,
|
101
|
+
GetSessionInfoTool
|
102
|
+
].freeze
|
103
|
+
end
|
104
|
+
end
|
metadata
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: headless_browser_tool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paulo Arruda
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-05-24 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: capybara
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: fast-mcp
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: json
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: ostruct
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: puma
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: rackup
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: selenium-webdriver
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: sinatra
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
type: :runtime
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: sinatra-contrib
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: thor
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
type: :runtime
|
146
|
+
prerelease: false
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
description: Provides an MCP server with tools to control a headless browser using
|
153
|
+
Capybara and Selenium
|
154
|
+
email:
|
155
|
+
- parrudaj@gmail.com
|
156
|
+
executables:
|
157
|
+
- hbt
|
158
|
+
extensions: []
|
159
|
+
extra_rdoc_files: []
|
160
|
+
files:
|
161
|
+
- ".claude/settings.json"
|
162
|
+
- ".rubocop.yml"
|
163
|
+
- ".ruby-version"
|
164
|
+
- CHANGELOG.md
|
165
|
+
- CLAUDE.md
|
166
|
+
- LICENSE.md
|
167
|
+
- README.md
|
168
|
+
- Rakefile
|
169
|
+
- config.ru
|
170
|
+
- exe/hbt
|
171
|
+
- lib/headless_browser_tool.rb
|
172
|
+
- lib/headless_browser_tool/browser.rb
|
173
|
+
- lib/headless_browser_tool/browser_adapter.rb
|
174
|
+
- lib/headless_browser_tool/cli.rb
|
175
|
+
- lib/headless_browser_tool/directory_setup.rb
|
176
|
+
- lib/headless_browser_tool/logger.rb
|
177
|
+
- lib/headless_browser_tool/server.rb
|
178
|
+
- lib/headless_browser_tool/session_manager.rb
|
179
|
+
- lib/headless_browser_tool/session_middleware.rb
|
180
|
+
- lib/headless_browser_tool/session_persistence.rb
|
181
|
+
- lib/headless_browser_tool/stdio_server.rb
|
182
|
+
- lib/headless_browser_tool/strict_session_middleware.rb
|
183
|
+
- lib/headless_browser_tool/tools.rb
|
184
|
+
- lib/headless_browser_tool/tools/attach_file_tool.rb
|
185
|
+
- lib/headless_browser_tool/tools/auto_narrate_tool.rb
|
186
|
+
- lib/headless_browser_tool/tools/base_tool.rb
|
187
|
+
- lib/headless_browser_tool/tools/check_tool.rb
|
188
|
+
- lib/headless_browser_tool/tools/choose_tool.rb
|
189
|
+
- lib/headless_browser_tool/tools/click_button_tool.rb
|
190
|
+
- lib/headless_browser_tool/tools/click_link_tool.rb
|
191
|
+
- lib/headless_browser_tool/tools/click_tool.rb
|
192
|
+
- lib/headless_browser_tool/tools/close_window_tool.rb
|
193
|
+
- lib/headless_browser_tool/tools/double_click_tool.rb
|
194
|
+
- lib/headless_browser_tool/tools/drag_tool.rb
|
195
|
+
- lib/headless_browser_tool/tools/evaluate_script_tool.rb
|
196
|
+
- lib/headless_browser_tool/tools/execute_script_tool.rb
|
197
|
+
- lib/headless_browser_tool/tools/fill_in_tool.rb
|
198
|
+
- lib/headless_browser_tool/tools/find_all_tool.rb
|
199
|
+
- lib/headless_browser_tool/tools/find_element_tool.rb
|
200
|
+
- lib/headless_browser_tool/tools/find_elements_containing_text_tool.rb
|
201
|
+
- lib/headless_browser_tool/tools/get_attribute_tool.rb
|
202
|
+
- lib/headless_browser_tool/tools/get_current_path_tool.rb
|
203
|
+
- lib/headless_browser_tool/tools/get_current_url_tool.rb
|
204
|
+
- lib/headless_browser_tool/tools/get_narration_history_tool.rb
|
205
|
+
- lib/headless_browser_tool/tools/get_page_context_tool.rb
|
206
|
+
- lib/headless_browser_tool/tools/get_page_source_tool.rb
|
207
|
+
- lib/headless_browser_tool/tools/get_page_title_tool.rb
|
208
|
+
- lib/headless_browser_tool/tools/get_session_info_tool.rb
|
209
|
+
- lib/headless_browser_tool/tools/get_text_tool.rb
|
210
|
+
- lib/headless_browser_tool/tools/get_value_tool.rb
|
211
|
+
- lib/headless_browser_tool/tools/get_window_handles_tool.rb
|
212
|
+
- lib/headless_browser_tool/tools/go_back_tool.rb
|
213
|
+
- lib/headless_browser_tool/tools/go_forward_tool.rb
|
214
|
+
- lib/headless_browser_tool/tools/has_element_tool.rb
|
215
|
+
- lib/headless_browser_tool/tools/has_text_tool.rb
|
216
|
+
- lib/headless_browser_tool/tools/hover_tool.rb
|
217
|
+
- lib/headless_browser_tool/tools/is_visible_tool.rb
|
218
|
+
- lib/headless_browser_tool/tools/maximize_window_tool.rb
|
219
|
+
- lib/headless_browser_tool/tools/open_new_window_tool.rb
|
220
|
+
- lib/headless_browser_tool/tools/refresh_tool.rb
|
221
|
+
- lib/headless_browser_tool/tools/resize_window_tool.rb
|
222
|
+
- lib/headless_browser_tool/tools/right_click_tool.rb
|
223
|
+
- lib/headless_browser_tool/tools/save_page_tool.rb
|
224
|
+
- lib/headless_browser_tool/tools/screenshot_tool.rb
|
225
|
+
- lib/headless_browser_tool/tools/search_page_tool.rb
|
226
|
+
- lib/headless_browser_tool/tools/search_source_tool.rb
|
227
|
+
- lib/headless_browser_tool/tools/select_tool.rb
|
228
|
+
- lib/headless_browser_tool/tools/switch_to_window_tool.rb
|
229
|
+
- lib/headless_browser_tool/tools/uncheck_tool.rb
|
230
|
+
- lib/headless_browser_tool/tools/visit_tool.rb
|
231
|
+
- lib/headless_browser_tool/tools/visual_diff_tool.rb
|
232
|
+
- lib/headless_browser_tool/version.rb
|
233
|
+
homepage: https://github.com/parruda/headless-browser-tool
|
234
|
+
licenses: []
|
235
|
+
metadata:
|
236
|
+
homepage_uri: https://github.com/parruda/headless-browser-tool
|
237
|
+
source_code_uri: https://github.com/parruda/headless-browser-tool
|
238
|
+
changelog_uri: https://github.com/parruda/headless-browser-tool/blob/main/CHANGELOG.md
|
239
|
+
rdoc_options: []
|
240
|
+
require_paths:
|
241
|
+
- lib
|
242
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
243
|
+
requirements:
|
244
|
+
- - ">="
|
245
|
+
- !ruby/object:Gem::Version
|
246
|
+
version: 3.1.0
|
247
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
248
|
+
requirements:
|
249
|
+
- - ">="
|
250
|
+
- !ruby/object:Gem::Version
|
251
|
+
version: '0'
|
252
|
+
requirements: []
|
253
|
+
rubygems_version: 3.6.2
|
254
|
+
specification_version: 4
|
255
|
+
summary: A headless browser control tool with MCP server
|
256
|
+
test_files: []
|