b4n1-web 0.16.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1bca04f5554abef830a51a42c237da9da3eb184f3feecc24c6c9ab6e4873077e
4
+ data.tar.gz: 88e3f08e1ef4ef23984e86a7d0bdb71a8bc56377456705392b5e75cbabf1e850
5
+ SHA512:
6
+ metadata.gz: 37baa9b36f5ec03ff363ce45f5402ce9ad155856ca4b8e5ad78536ce2663c46e400e40b85c2c1b7efb6ba5e822db7459424378af2dcfb7d41fd2f719abfd1b19
7
+ data.tar.gz: 6c0fd5f2d3eae01dbbd274ce1623f3bdf100f185b06f794173d21fb43fe56d2c998b4361e9bce201d46e23038ab4eccca77749c41ad4b0aefbe11e84e8a04e76
data/EULA.txt ADDED
@@ -0,0 +1,79 @@
1
+ B4N1-WEB — END USER LICENSE AGREEMENT (BINARIES)
2
+ ==================================================
3
+
4
+ Version: 1.0 | Effective: 2026-09-27 | Applies to: b4n1-web 0.13.0+
5
+
6
+ This End User License Agreement ("EULA") governs your use of the B4N1
7
+ BINARY ARTIFACTS of b4n1-web — the bundled per-platform `b4n1web`
8
+ executables (`b4n1web-linux-amd64`, `b4n1web-macos-arm64`,
9
+ `b4n1web-windows-amd64.exe` and the remaining platform builds shipped
10
+ under each SDK's `bin/` or `native/` directory), the packaged
11
+ per-language bindings (`*.jar`, `*.nupkg`, `*.whl`, npm tarball),
12
+ and the `b4n1web` standalone executable.
13
+
14
+ The SDK wrapper source files (the thin per-language bindings) are licensed
15
+ separately under the Business Source License 1.1 — see the `LICENSE` file
16
+ and each registry's license metadata.
17
+
18
+ 1. DEFINITIONS
19
+ "Binaries" means the compiled artifacts described above.
20
+ "SDK" means the BSL 1.1 licensed wrapper source distributed for each language.
21
+ "Source" means the Rust implementation, build scripts, internal tests and
22
+ internal documentation of the B4N1 engine. Source is NOT distributed under
23
+ this EULA or any other license and remains proprietary.
24
+
25
+ 2. GRANT OF LICENSE
26
+ Subject to your compliance with this EULA and payment of any applicable
27
+ subscription, B4N1 grants you a limited, non-exclusive, non-transferable,
28
+ revocable license to install and use the Binaries within your own products
29
+ and internal tooling, in object form only.
30
+
31
+ 3. RESTRICTIONS (strictly enforced)
32
+ a. NO REDISTRIBUTION OF SOURCE. You may not publish, disclose, sublicense
33
+ or otherwise make the B4N1 Rust Source available, in whole or in part,
34
+ modified or unmodified, by any means, including in public repositories.
35
+ b. NO DECOMPILATION OR REVERSE ENGINEERING. You may not decompile,
36
+ disassemble, deobfuscate, or otherwise reverse engineer the Binaries
37
+ except to the extent such restriction is prohibited by applicable law
38
+ that cannot be waived.
39
+ c. NO REMOVAL OF NOTICES. You may not remove, alter, or obscure any
40
+ copyright, license, watermark, or proprietary notices in the Binaries.
41
+ d. NO RESALE AS A STANDALONE PRODUCT. The Binaries may not be resold,
42
+ sublicensed, or offered as a competing product.
43
+ e. COMPLIANCE AND AUDIT. You will cooperate with reasonable verification of
44
+ license status, including honoring embedded license validation.
45
+
46
+ 4. SUBSCRIPTION TIERS
47
+ The Binaries operate under the applicable tier, validated offline against a
48
+ license file (`.b4n1lic`):
49
+ - Community: free, with attribution/watermark obligations.
50
+ - Pro / Corporate / Enterprise: paid tiers, no watermark, per the
51
+ commercial license purchased from B4N1.
52
+ License files are validated fully offline; no network calls are made at
53
+ runtime to verify entitlement.
54
+
55
+ 5. TERMINATION
56
+ This EULA terminates automatically if you breach any term. Upon
57
+ termination you must cease all use and destroy the Binaries and copies.
58
+
59
+ 6. DISCLAIMER OF WARRANTY
60
+ The Binaries are provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or
61
+ implied, including merchantability, fitness for a particular purpose, and
62
+ non-infringement. B4N1 does not warrant that the Binaries will be
63
+ uninterrupted or error-free.
64
+
65
+ 7. LIMITATION OF LIABILITY
66
+ To the maximum extent permitted by law, B4N1 shall not be liable for any
67
+ indirect, incidental, special, consequential, or punitive damages, or for
68
+ any loss of profits, revenue, data, or goodwill, arising out of your use
69
+ of the Binaries, regardless of the legal theory, even if advised of the
70
+ possibility of such damages.
71
+
72
+ 8. GOVERNING LAW AND SEVERABILITY
73
+ This EULA is governed by applicable law. If any provision is held
74
+ unenforceable, the remaining provisions stay in full force.
75
+
76
+ 9. CONTACT
77
+ Licensing questions: licensing@b4n1.com | https://b4n1.com
78
+
79
+ B4N1 — Todos los derechos reservados. Fuente proprietary: privada y secreta.
data/LICENSE ADDED
@@ -0,0 +1,95 @@
1
+ Business Source License 1.1
2
+
3
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
4
+ "Business Source License" is a trademark of MariaDB Corporation Ab.
5
+
6
+ -----------------------------------------------------------------------------
7
+
8
+ Parameters
9
+
10
+ Licensor: B4N1 (b4n1.com)
11
+ Licensed Work: b4n1-web — Agentic browser engine for web automation,
12
+ testing, and AI-powered browsing tasks.
13
+ Additional Use Grant: You may use the Licensed Work in production, free of
14
+ charge, provided that your organization's total annual
15
+ gross revenue does not exceed USD $100,000. Organizations
16
+ whose annual gross revenue exceeds USD $100,000 must
17
+ obtain a commercial license from the Licensor before any
18
+ production use. You may not resell or provide the
19
+ Licensed Work as a managed commercial service without
20
+ authorization from the Licensor.
21
+ Change Date: Four years after the first publicly available
22
+ distribution of the Licensed Work under this License.
23
+ Change License: Apache License, Version 2.0
24
+
25
+ For information about alternative licensing arrangements for the Licensed
26
+ Work, please contact b4n1@b4n1.com.
27
+
28
+ -----------------------------------------------------------------------------
29
+
30
+ Terms
31
+
32
+ The Licensor hereby grants you the right to copy, modify, create derivative
33
+ works, redistribute, and make non-production use of the Licensed Work. The
34
+ Licensor may make an Additional Use Grant, above, permitting limited
35
+ production use.
36
+
37
+ Effective on the Change Date, or the fourth anniversary of the first publicly
38
+ available distribution of a specific version of the Licensed Work under this
39
+ License, whichever comes first, the Licensor hereby grants you rights under
40
+ the terms of the Change License, and the rights granted in the paragraph
41
+ above terminate.
42
+
43
+ If your use of the Licensed Work does not comply with the requirements
44
+ currently in effect as described in this License, you must purchase a
45
+ commercial license from the Licensor, its affiliated entities, or authorized
46
+ resellers, or you must refrain from using the Licensed Work.
47
+
48
+ All copies of the original and modified Licensed Work, and derivative works
49
+ of the Licensed Work, are subject to this License. This License applies
50
+ separately for each version of the Licensed Work and the Change Date may vary
51
+ for each version of the Licensed Work released by Licensor.
52
+
53
+ You must conspicuously display this License on each original or modified copy
54
+ of the Licensed Work. If you receive the Licensed Work in original or
55
+ modified form from a third party, the terms and conditions set forth in this
56
+ License apply to your use of that work.
57
+
58
+ Any use of the Licensed Work in violation of this License will automatically
59
+ terminate your rights under this License for the current and all other
60
+ versions of the Licensed Work.
61
+
62
+ This License does not grant you any right in any trademark or logo of
63
+ Licensor or its affiliates (provided that you may use a trademark or logo of
64
+ Licensor as expressly required by this License).
65
+
66
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
67
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
68
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
69
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
70
+ TITLE. MariaDB hereby grants you permission to use this License's text to
71
+ license your works, and to refer to it using the trademark "Business Source
72
+ License", as long as you comply with the Covenants of Licensor below.
73
+
74
+ Covenants of Licensor
75
+
76
+ In consideration of the right to use this License's text and the "Business
77
+ Source License" name and trademark, Licensor covenants to MariaDB, and to all
78
+ other recipients of the licensed work to be provided by Licensor:
79
+
80
+ To specify as the Change License a license that is compatible with GPL
81
+ Version 2.0 or a later version, where "compatible" means that software
82
+ provided under the Change License can be included in a program with software
83
+ provided under GPL Version 2.0 or a later version. Licensor may specify
84
+ additional Change Licenses without limitation.
85
+
86
+ To either: (a) specify an additional grant of rights to use that does not
87
+ impose any additional restriction on the right granted in this License, as
88
+ the Additional Use Grant; or (b) insert the text "None" to specify a Change
89
+ License. Not to modify this License in any other way.
90
+
91
+ Notice
92
+
93
+ The Business Source License (this document, or the "License") is not an Open
94
+ Source license. However, the Licensed Work will eventually be made available
95
+ under an Open Source License, as stated in this License.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # b4n1-web Ruby SDK
2
+
3
+ Ultra-lightweight agentic browser for AI agents — Ruby gem wrapping the
4
+ `b4n1web` binary.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ gem install b4n1-web
10
+ ```
11
+
12
+ The gem resolves the browser binary in this order:
13
+
14
+ 1. `B4N1WEB_BIN_PATH` (explicit override)
15
+ 2. bundled binary inside the gem (when shipped)
16
+ 3. well-known user/system locations (`~/.local/bin`, `~/.b4n1web/bin`, …)
17
+ 4. `PATH`
18
+
19
+ If nothing resolves, it fails loudly (no silent fallback) with an actionable
20
+ install hint.
21
+
22
+ ## Usage
23
+
24
+ ```ruby
25
+ require "b4n1web"
26
+
27
+ browser = B4n1Web::AgentBrowser.new(mode: B4n1Web::BrowserMode::LIGHT)
28
+ page = browser.goto("https://example.com")
29
+
30
+ puts page.markdown # extracted markdown
31
+ puts page.links # array of links (JSON-parsed)
32
+ puts page.get_main_content # main content heuristic
33
+ puts page.find_links_by_text("docs")
34
+ browser.close # no-op (binary is stateless)
35
+
36
+ # Execute JavaScript in the page context
37
+ result = browser.evaluate("https://example.com", "document.title")
38
+ ```
39
+
40
+ ### Modes
41
+
42
+ | Mode | Purpose |
43
+ |------|---------|
44
+ | `B4n1Web::BrowserMode::LIGHT` | Fast HTTP fetch, no JS (default) |
45
+ | `B4n1Web::BrowserMode::JS` | Headless Chromium with JavaScript |
46
+ | `B4n1Web::BrowserMode::RENDER` | Full render + wait-for selector |
47
+
48
+ ### CLI wrapper
49
+
50
+ The gem installs a `b4n1web` executable that passes arguments straight to the
51
+ resolved binary:
52
+
53
+ ```bash
54
+ b4n1web goto https://example.com --mode light
55
+ ```
56
+
57
+ ### Options
58
+
59
+ - `mode:` — browser mode (default `light`)
60
+ - `timeout:` — seconds before killing the binary (default `30`)
61
+ - `binary:` — explicit binary path (skips auto-resolution)
62
+ - `runner:` — injectable process runner (tests only)
63
+
64
+ ## License
65
+
66
+ BUSL-1.1 (see `LICENSE`). Binary use is subject to `EULA.txt`.
data/bin/b4n1web ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # CLI wrapper: resolves the bundled/system b4n1web binary and passes all
5
+ # arguments through (e.g. `b4n1web goto https://example.com --mode light`).
6
+
7
+ require_relative "../lib/b4n1web"
8
+
9
+ binary = B4n1Web::Binary.resolve
10
+ if binary.nil?
11
+ warn "ERROR: b4n1web binary not found."
12
+ warn " Install: curl -sL https://raw.githubusercontent.com/B4N1-com/b4n1-web/master/scripts/install.sh | bash"
13
+ warn " Or set B4N1WEB_BIN_PATH to an existing binary."
14
+ exit 1
15
+ end
16
+
17
+ exec(binary, *ARGV)
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require "timeout"
5
+ require_relative "binary"
6
+ require_relative "page"
7
+ require_relative "errors"
8
+ require_relative "version"
9
+
10
+ module B4n1Web
11
+ # Browser modes accepted by the binary.
12
+ module BrowserMode
13
+ LIGHT = "light"
14
+ JS = "js"
15
+ RENDER = "render"
16
+ end
17
+
18
+ # Thin async-free wrapper over the b4n1web binary.
19
+ #
20
+ # browser = B4n1Web::AgentBrowser.new(mode: B4n1Web::BrowserMode::LIGHT)
21
+ # page = browser.goto("https://example.com")
22
+ # puts page.markdown
23
+ # browser.close
24
+ class AgentBrowser
25
+ attr_reader :mode, :timeout
26
+
27
+ # runner: injectable process runner (object responding to
28
+ # run(argv, timeout:) -> [stdout, stderr, status_int]). Tests inject a
29
+ # fake; production uses the real Open3-based runner below.
30
+ # binary: explicit binary path override (skips auto-resolution).
31
+ def initialize(mode: BrowserMode::LIGHT, timeout: 30, runner: nil, binary: nil)
32
+ @mode = mode
33
+ @timeout = timeout
34
+ @runner = runner || RealRunner.new
35
+ @binary = binary || Binary.resolve!
36
+ end
37
+
38
+ # Binary path resolved at construction (parity with the other SDKs).
39
+ def binary_path
40
+ @binary
41
+ end
42
+
43
+ # Navigate + extract. wait_for: CSS selector (render mode).
44
+ def goto(url, wait_for: nil)
45
+ argv = [@binary, "goto", url, "--mode", @mode]
46
+ argv.push("--wait-for", wait_for) if wait_for
47
+ stdout, stderr, status = @runner.run(argv, timeout: @timeout)
48
+ raise NavigationError, "b4n1web timed out after #{@timeout}s" if status.nil?
49
+ unless status.zero?
50
+ raise NavigationError, "b4n1web exited #{status}: #{stderr.to_s.strip}"
51
+ end
52
+
53
+ Page.parse(url, stdout)
54
+ end
55
+
56
+ # Execute JavaScript in the page context, return raw result string.
57
+ def evaluate(url, js)
58
+ argv = [@binary, "evaluate", url, js]
59
+ stdout, stderr, status = @runner.run(argv, timeout: @timeout)
60
+ raise NavigationError, "b4n1web timed out after #{@timeout}s" if status.nil?
61
+ unless status.zero?
62
+ raise NavigationError, "b4n1web exited #{status}: #{stderr.to_s.strip}"
63
+ end
64
+
65
+ stdout.to_s.strip
66
+ end
67
+
68
+ # The binary is stateless: close is a no-op kept for API parity.
69
+ def close; end
70
+
71
+ # Default runner: Open3 with hard timeout. On timeout the whole process
72
+ # GROUP is killed (the binary spawns Chromium children that inherit
73
+ # stdout; killing only the leader would leave them holding the pipe and
74
+ # the readers below would block past the timeout) and status is nil
75
+ # (so callers raise NavigationError). The group is also released after a
76
+ # NORMAL exit so a lingering descendant can never hang the reads (parity
77
+ # with the Go SDK's cmd.WaitDelay).
78
+ class RealRunner
79
+ def run(argv, timeout:)
80
+ stdout = +""
81
+ stderr = +""
82
+ status = nil
83
+ Open3.popen3(*argv, pgroup: true) do |pin, pout, perr, wait_thr|
84
+ pid = wait_thr.pid
85
+ reader = Thread.new { pout.read }
86
+ err_reader = Thread.new { perr.read }
87
+ begin
88
+ Timeout.timeout(timeout) { status = wait_thr.value.exitstatus }
89
+ rescue Timeout::Error
90
+ status = nil
91
+ end
92
+ # Leader done (exit or timeout): kill the whole group so no
93
+ # descendant keeps stdout/stderr open and blocks the drains.
94
+ begin
95
+ Process.kill("KILL", -pid) # negative pid = whole process group
96
+ rescue Errno::ESRCH, Errno::EPERM
97
+ Process.kill("KILL", pid) rescue nil
98
+ end
99
+ await_group_gone(pid)
100
+ stdout = drain(reader)
101
+ stderr = drain(err_reader)
102
+ pin.close rescue nil
103
+ end
104
+ [stdout, stderr, status]
105
+ end
106
+
107
+ private
108
+
109
+ # Join with a hard bound: after the group kill the pipes hit EOF
110
+ # immediately; a pathological holder cannot hang the SDK.
111
+ def drain(thread, seconds: 2)
112
+ return thread.value if thread.join(seconds)
113
+ thread.kill
114
+ +""
115
+ end
116
+
117
+ # Signal delivery is asynchronous: after the KILL above the group is
118
+ # signalled, not necessarily dead yet. Wait (bounded) until the group
119
+ # is actually gone so callers get a deterministic "dead on return"
120
+ # contract (parity with Go's cmd.WaitDelay). A killed orphan that is
121
+ # still awaiting reaping answers kill(0, ...) — the bound keeps this
122
+ # honest under any load.
123
+ def await_group_gone(pgid, seconds: 2)
124
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
125
+ loop do
126
+ begin
127
+ Process.kill(0, -pgid)
128
+ rescue Errno::ESRCH
129
+ return
130
+ end
131
+ return if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
132
+ sleep 0.01
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+ require_relative "errors"
5
+
6
+ module B4n1Web
7
+ # Resolves the b4n1web binary. Order mirrors the Python/JS/C#/Java SDKs:
8
+ # 1. B4N1WEB_BIN_PATH (explicit override, must exist + be executable)
9
+ # 2. bundled binary shipped inside the gem (lib/b4n1web/bin/*)
10
+ # well-known user/system locations
11
+ # 4. PATH scan
12
+ module Binary
13
+ PLATFORM_BINARIES = {
14
+ ["linux", "x86_64"] => "b4n1web-linux-amd64",
15
+ ["linux", "aarch64"] => "b4n1web-linux-arm64",
16
+ ["linux", "i686"] => "b4n1web-linux-ia32",
17
+ ["darwin", "x86_64"] => "b4n1web-macos-x64",
18
+ ["darwin", "arm64"] => "b4n1web-macos-arm64",
19
+ ["mingw", "x64"] => "b4n1web-windows-amd64.exe",
20
+ ["mswin", "x64"] => "b4n1web-windows-amd64.exe"
21
+ }.freeze
22
+
23
+ module_function
24
+
25
+ def platform_binary_name
26
+ os = RbConfig::CONFIG["host_os"]
27
+ arch = RbConfig::CONFIG["host_cpu"]
28
+ arch = "x86_64" if arch == "amd64"
29
+ arch = "i686" if arch == "i386"
30
+ plat = case os
31
+ when /linux/ then "linux"
32
+ when /darwin|mac os/ then "darwin"
33
+ when /mingw|cygwin/ then "mingw"
34
+ when /mswin|windows/ then "mswin"
35
+ end
36
+ return nil unless plat
37
+ PLATFORM_BINARIES[[plat, arch]]
38
+ end
39
+
40
+ # Returns the absolute path of a runnable b4n1web binary or nil.
41
+ def resolve
42
+ env = ENV["B4N1WEB_BIN_PATH"]
43
+ return env if env && File.file?(env) && File.executable?(env)
44
+
45
+ name = platform_binary_name
46
+ if name
47
+ bundled = File.expand_path(File.join(__dir__, "bin", name))
48
+ return bundled if File.file?(bundled) && File.executable?(bundled)
49
+ end
50
+
51
+ candidates = []
52
+ candidates << ENV["B4N1WEB_BINARY"] if ENV["B4N1WEB_BINARY"]
53
+ home = Dir.home
54
+ candidates << File.join(home, ".local", "bin", "b4n1web")
55
+ candidates << File.join(home, ".b4n1web", "bin", "b4n1web")
56
+ candidates << "/usr/local/bin/b4n1web"
57
+ candidates << "/usr/bin/b4n1web"
58
+ ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).each do |dir|
59
+ candidates << File.join(dir, "b4n1web")
60
+ end
61
+
62
+ candidates.compact.find { |p| File.file?(p) && File.executable?(p) }
63
+ end
64
+
65
+ # Same as resolve but raises loudly (no silent nil).
66
+ def resolve!
67
+ resolve || raise(BinaryNotFoundError,
68
+ "b4n1web binary not found. Install it (curl -sL " \
69
+ "https://raw.githubusercontent.com/B4N1-com/b4n1-web/" \
70
+ "master/scripts/install.sh | bash) or set B4N1WEB_BIN_PATH.")
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module B4n1Web
4
+ class Error < StandardError; end
5
+
6
+ # Raised when no b4n1web binary can be resolved (bundled/system/PATH).
7
+ class BinaryNotFoundError < Error; end
8
+
9
+ # Raised when the binary exits non-zero or times out.
10
+ class NavigationError < Error; end
11
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module B4n1Web
6
+ # Structured page data returned by the b4n1web binary.
7
+ class Page
8
+ attr_reader :url, :markdown, :links, :screenshot
9
+
10
+ def initialize(url:, markdown:, links:, screenshot: nil)
11
+ @url = url
12
+ @markdown = markdown
13
+ @links = links
14
+ @screenshot = screenshot
15
+ end
16
+
17
+ # Parses the binary's text protocol:
18
+ # URL: <url>
19
+ # Markdown:
20
+ # <free-form markdown lines...>
21
+ # Links: ["https://...", ...]
22
+ # Screenshot: <path> (optional)
23
+ def self.parse(url, output)
24
+ markdown = +""
25
+ links = []
26
+ screenshot = nil
27
+ in_markdown = false
28
+
29
+ output.to_s.each_line do |line|
30
+ line = line.chomp
31
+ if line.start_with?("URL:")
32
+ next
33
+ elsif line.start_with?("Markdown:")
34
+ in_markdown = true
35
+ rest = line.delete_prefix("Markdown:").strip
36
+ markdown << "#{rest}\n" unless rest.empty?
37
+ elsif line.start_with?("Links:")
38
+ in_markdown = false
39
+ links = JSON.parse(line.delete_prefix("Links:").strip) || []
40
+ elsif line.start_with?("Screenshot:")
41
+ in_markdown = false
42
+ shot = line.delete_prefix("Screenshot:").strip
43
+ screenshot = shot.empty? ? nil : shot
44
+ else
45
+ markdown << "#{line}\n" if in_markdown
46
+ end
47
+ end
48
+
49
+ new(url: url, markdown: markdown.strip, links: links, screenshot: screenshot)
50
+ end
51
+
52
+ # Main content heuristics: drop the first two lines (title + empty line).
53
+ def get_main_content
54
+ lines = markdown.split("\n")
55
+ content = lines.length > 2 ? lines[2..] : lines
56
+ content.join("\n").strip
57
+ end
58
+
59
+ def find_links_by_text(text)
60
+ return [] if text.nil? || text.empty?
61
+ needle = text.downcase
62
+ links.select { |link| link.downcase.include?(needle) }
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module B4n1Web
4
+ VERSION = "0.16.0"
5
+ end
data/lib/b4n1web.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "b4n1web/version"
4
+ require_relative "b4n1web/errors"
5
+ require_relative "b4n1web/binary"
6
+ require_relative "b4n1web/page"
7
+ require_relative "b4n1web/agent_browser"
8
+
9
+ # B4n1Web Ruby SDK — ultra-lightweight agentic browser for AI agents.
10
+ #
11
+ # require "b4n1web"
12
+ # browser = B4n1Web::AgentBrowser.new
13
+ # page = browser.goto("https://example.com")
14
+ # puts page.markdown
15
+ # browser.close
16
+ module B4n1Web
17
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: b4n1-web
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.16.0
5
+ platform: ruby
6
+ authors:
7
+ - Bani Montoya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-10-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ultra-lightweight headless browser with bundled binary for AI agents.
14
+ Supports Light/JS/Render modes.
15
+ email:
16
+ - b4n1@b4n1.com
17
+ executables:
18
+ - b4n1web
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - EULA.txt
23
+ - LICENSE
24
+ - README.md
25
+ - bin/b4n1web
26
+ - lib/b4n1web.rb
27
+ - lib/b4n1web/agent_browser.rb
28
+ - lib/b4n1web/binary.rb
29
+ - lib/b4n1web/errors.rb
30
+ - lib/b4n1web/page.rb
31
+ - lib/b4n1web/version.rb
32
+ homepage: https://b4n1.com
33
+ licenses:
34
+ - BUSL-1.1
35
+ metadata:
36
+ homepage_uri: https://b4n1.com
37
+ source_code_uri: https://github.com/B4N1-com/b4n1-web
38
+ changelog_uri: https://github.com/B4N1-com/b4n1-web/blob/master/CHANGELOG.md
39
+ bug_tracker_uri: https://github.com/B4N1-com/b4n1-web/issues
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '3.0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.3.5
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: B4n1Web - Agentic Browser Engine for AI agents
59
+ test_files: []