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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/settings.json +21 -0
  3. data/.rubocop.yml +56 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +5 -0
  6. data/CLAUDE.md +298 -0
  7. data/LICENSE.md +7 -0
  8. data/README.md +522 -0
  9. data/Rakefile +12 -0
  10. data/config.ru +8 -0
  11. data/exe/hbt +7 -0
  12. data/lib/headless_browser_tool/browser.rb +374 -0
  13. data/lib/headless_browser_tool/browser_adapter.rb +320 -0
  14. data/lib/headless_browser_tool/cli.rb +34 -0
  15. data/lib/headless_browser_tool/directory_setup.rb +25 -0
  16. data/lib/headless_browser_tool/logger.rb +31 -0
  17. data/lib/headless_browser_tool/server.rb +150 -0
  18. data/lib/headless_browser_tool/session_manager.rb +199 -0
  19. data/lib/headless_browser_tool/session_middleware.rb +158 -0
  20. data/lib/headless_browser_tool/session_persistence.rb +146 -0
  21. data/lib/headless_browser_tool/stdio_server.rb +73 -0
  22. data/lib/headless_browser_tool/strict_session_middleware.rb +88 -0
  23. data/lib/headless_browser_tool/tools/attach_file_tool.rb +40 -0
  24. data/lib/headless_browser_tool/tools/auto_narrate_tool.rb +155 -0
  25. data/lib/headless_browser_tool/tools/base_tool.rb +39 -0
  26. data/lib/headless_browser_tool/tools/check_tool.rb +35 -0
  27. data/lib/headless_browser_tool/tools/choose_tool.rb +56 -0
  28. data/lib/headless_browser_tool/tools/click_button_tool.rb +49 -0
  29. data/lib/headless_browser_tool/tools/click_link_tool.rb +48 -0
  30. data/lib/headless_browser_tool/tools/click_tool.rb +45 -0
  31. data/lib/headless_browser_tool/tools/close_window_tool.rb +31 -0
  32. data/lib/headless_browser_tool/tools/double_click_tool.rb +37 -0
  33. data/lib/headless_browser_tool/tools/drag_tool.rb +46 -0
  34. data/lib/headless_browser_tool/tools/evaluate_script_tool.rb +20 -0
  35. data/lib/headless_browser_tool/tools/execute_script_tool.rb +29 -0
  36. data/lib/headless_browser_tool/tools/fill_in_tool.rb +66 -0
  37. data/lib/headless_browser_tool/tools/find_all_tool.rb +42 -0
  38. data/lib/headless_browser_tool/tools/find_element_tool.rb +21 -0
  39. data/lib/headless_browser_tool/tools/find_elements_containing_text_tool.rb +259 -0
  40. data/lib/headless_browser_tool/tools/get_attribute_tool.rb +21 -0
  41. data/lib/headless_browser_tool/tools/get_current_path_tool.rb +16 -0
  42. data/lib/headless_browser_tool/tools/get_current_url_tool.rb +16 -0
  43. data/lib/headless_browser_tool/tools/get_narration_history_tool.rb +35 -0
  44. data/lib/headless_browser_tool/tools/get_page_context_tool.rb +188 -0
  45. data/lib/headless_browser_tool/tools/get_page_source_tool.rb +16 -0
  46. data/lib/headless_browser_tool/tools/get_page_title_tool.rb +16 -0
  47. data/lib/headless_browser_tool/tools/get_session_info_tool.rb +37 -0
  48. data/lib/headless_browser_tool/tools/get_text_tool.rb +20 -0
  49. data/lib/headless_browser_tool/tools/get_value_tool.rb +20 -0
  50. data/lib/headless_browser_tool/tools/get_window_handles_tool.rb +29 -0
  51. data/lib/headless_browser_tool/tools/go_back_tool.rb +29 -0
  52. data/lib/headless_browser_tool/tools/go_forward_tool.rb +29 -0
  53. data/lib/headless_browser_tool/tools/has_element_tool.rb +21 -0
  54. data/lib/headless_browser_tool/tools/has_text_tool.rb +21 -0
  55. data/lib/headless_browser_tool/tools/hover_tool.rb +38 -0
  56. data/lib/headless_browser_tool/tools/is_visible_tool.rb +20 -0
  57. data/lib/headless_browser_tool/tools/maximize_window_tool.rb +34 -0
  58. data/lib/headless_browser_tool/tools/open_new_window_tool.rb +25 -0
  59. data/lib/headless_browser_tool/tools/refresh_tool.rb +32 -0
  60. data/lib/headless_browser_tool/tools/resize_window_tool.rb +43 -0
  61. data/lib/headless_browser_tool/tools/right_click_tool.rb +37 -0
  62. data/lib/headless_browser_tool/tools/save_page_tool.rb +32 -0
  63. data/lib/headless_browser_tool/tools/screenshot_tool.rb +199 -0
  64. data/lib/headless_browser_tool/tools/search_page_tool.rb +224 -0
  65. data/lib/headless_browser_tool/tools/search_source_tool.rb +148 -0
  66. data/lib/headless_browser_tool/tools/select_tool.rb +44 -0
  67. data/lib/headless_browser_tool/tools/switch_to_window_tool.rb +30 -0
  68. data/lib/headless_browser_tool/tools/uncheck_tool.rb +35 -0
  69. data/lib/headless_browser_tool/tools/visit_tool.rb +27 -0
  70. data/lib/headless_browser_tool/tools/visual_diff_tool.rb +177 -0
  71. data/lib/headless_browser_tool/tools.rb +104 -0
  72. data/lib/headless_browser_tool/version.rb +5 -0
  73. data/lib/headless_browser_tool.rb +8 -0
  74. 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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HeadlessBrowserTool
4
+ VERSION = "0.1.1"
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "headless_browser_tool/version"
4
+ require_relative "headless_browser_tool/cli"
5
+
6
+ module HeadlessBrowserTool
7
+ class Error < StandardError; end
8
+ 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: []