Skip to content

Review: agent-browser-plugin-firecrawl (full repo) - #1

Closed
rakshith48 wants to merge 1 commit into
coderabbit-basefrom
coderabbit-review
Closed

rakshith48 wants to merge 1 commit into
coderabbit-basefrom
coderabbit-review

Conversation

@rakshith48

@rakshith48 rakshith48 commented Jun 16, 2026 •

Copy link
Copy Markdown
Collaborator

Full plugin as a single diff against an empty baseline so CodeRabbit reviews the entire codebase.

Scope: bin/plugin.js (agent-browser.plugin.v1 — browser.provider + command.run), test/plugin.test.js (9 hermetic tests), .github/workflows/ci.yml, README, packaging.

Review-only — not intended to merge.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • New Firecrawl plugin for browser automation and web scraping
    • Browser session management with CDP WebSocket support
    • Command execution for scrape, search, crawl, and map operations
  • Chores

    • Added CI/CD pipeline, project configuration, and MIT License
    • Added comprehensive test suite and documentation

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces the initial implementation of agent-browser-plugin-firecrawl, a Node.js CLI plugin that implements the agent-browser.plugin.v1 stdio protocol to integrate Firecrawl cloud browser sessions and scrape/search/crawl/map commands. It includes the package scaffold, CI workflow, plugin binary, hermetic test suite, and README.

Changes

Firecrawl agent-browser plugin

Layer / File(s) Summary
Package scaffold, CI, and license
package.json, .github/workflows/ci.yml, .gitignore, LICENSE
Defines the agent-browser-plugin-firecrawl npm package with a CLI binary entry point, Node >=18 engine requirement, node --test CI matrix across Node 18/20/22, standard gitignore rules, and MIT license.
Plugin constants, API client, and request body builder
bin/plugin.js (lines 1–107)
Declares protocol identity, capability names, and endpoint path map; implements stdout write helpers, stdin reader, and the Firecrawl fetch client with API key enforcement and structured error extraction; builds the POST /v2/browser body by merging top-level fields with launchOptions and resolving persistent profile from env or explicit field.
Request handler and entrypoint
bin/plugin.js (lines 109–175)
Implements handle() routing all protocol request types (plugin.manifest, browser.launch, browser.close, firecrawl.*) to the appropriate Firecrawl API calls; entrypoint IIFE reads stdin, validates the protocol field, dispatches to handle(), and emits a single fail response on any exception.
Hermetic test suite
test/plugin.test.js
Spawns the plugin binary as a subprocess against a local mock HTTP server; covers protocol validation, manifest, missing API key, browser.launch payload and response fields, profile env precedence vs explicit launchOptions, browser.close DELETE URL, and firecrawl.scrape payload forwarding.
README documentation
README.md
Documents plugin purpose, installation, browser provider and command runner usage, agent-browser.json configuration, environment variables, two-layer authentication, browser.launch field forwarding, policy gating, and end-to-end testing instructions.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as Caller (stdin/stdout)
  participant Plugin as bin/plugin.js
  participant Firecrawl as Firecrawl /v2 API

  rect rgba(70, 130, 180, 0.5)
    note over Caller,Plugin: browser.launch
    Caller->>Plugin: { type: "browser.launch", launchOptions: { ttl, profile } }
    Plugin->>Firecrawl: POST /v2/browser (ttl, profile, activityTtl)
    Firecrawl-->>Plugin: { cdpUrl, id, ... }
    Plugin-->>Caller: { cdpUrl, metadata, cleanup: { sessionId } }
  end

  rect rgba(60, 179, 113, 0.5)
    note over Caller,Plugin: command.run
    Caller->>Plugin: { type: "command.run", command: "firecrawl.scrape", payload }
    Plugin->>Firecrawl: POST /v2/scrape (payload)
    Firecrawl-->>Plugin: { data }
    Plugin-->>Caller: { success: true, data }
  end

  rect rgba(205, 92, 92, 0.5)
    note over Caller,Plugin: browser.close
    Caller->>Plugin: { type: "browser.close", sessionId }
    Plugin->>Firecrawl: DELETE /v2/browser/:sessionId
    Firecrawl-->>Plugin: 200 OK
    Plugin-->>Caller: { success: true }
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 A bunny hops through stdio streams,
Firecrawl CDP — just what it seems!
One JSON in, one JSON out,
Browser sessions spun about.
With mock servers and tests so neat,
This plugin's launch is oh-so-sweet! 🌐

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Review: agent-browser-plugin-firecrawl (full repo)' is vague and uses non-descriptive phrasing. It indicates a review action rather than describing the actual changes being made. Consider using a more descriptive title that summarizes the main changes, such as 'Add agent-browser plugin for Firecrawl integration' or 'Implement agent-browser-plugin-firecrawl with browser provider and command support'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch coderabbit-review

Comment @coderabbitai help to get the list of available commands and usage tips.

@rakshith48

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 15-16: Replace the tag-based action references
(actions/checkout@v4 and actions/setup-node@v4) with pinned full commit SHAs
instead of version tags to prevent supply-chain attacks. Additionally, add the
persist-credentials: false configuration option to the checkout action to
disable credential persistence and reduce token exposure risk. Both actions
should reference their specific commit SHA rather than relying on floating
version tags.

In `@bin/plugin.js`:
- Around line 127-140: The code validates that session.cdpUrl exists before
returning the browser metadata, but does not validate that session.id exists,
even though session.id is used in the cleanup object on line 139. Add a
validation check for session.id immediately after or in conjunction with the
existing cdpUrl validation to ensure that both required properties are present
before returning the ok() response. If session.id is missing, throw an error
with a descriptive message similar to the cdpUrl validation, preventing the
plugin from reporting success when it cannot properly track the session for
later cleanup.
- Around line 58-67: The fetch call in the api function lacks a timeout
mechanism, which can cause the plugin to hang indefinitely if a network request
stalls. Add an AbortController with a timeout to the fetch invocation: create an
AbortController instance, set up a timeout that calls abort() on the controller
after a reasonable duration (e.g., 30 seconds), pass the controller's signal in
the fetch options, and ensure the timeout is cleared if the fetch completes
successfully to avoid memory leaks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b237836f-1f8f-4c1a-87fd-8972ae7d104a

📥 Commits

Reviewing files that changed from the base of the PR and between d1a6471 and d1769e1.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • .gitignore
  • LICENSE
  • README.md
  • bin/plugin.js
  • package.json
  • test/plugin.test.js

Comment thread .github/workflows/ci.yml
Comment on lines +15 to +16
- uses: actions/checkout@v4
- uses: actions/setup-node@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify workflow actions are SHA-pinned and checkout disables persisted credentials.
set -euo pipefail

echo "== action refs in workflow =="
rg -n 'uses:\s*actions/(checkout|setup-node)@' .github/workflows/ci.yml

echo
echo "== check for full SHA pins (40-hex) =="
rg -nP 'uses:\s*actions/(checkout|setup-node)@[0-9a-f]{40}\b' .github/workflows/ci.yml || true

echo
echo "== check checkout persist-credentials setting =="
rg -n 'persist-credentials:\s*false' .github/workflows/ci.yml || true

echo
echo "Expected:"
echo "1) checkout/setup-node lines use @<40-hex-sha>"
echo "2) checkout step includes 'persist-credentials: false'"

Repository: rakshith48/agent-browser-plugin-firecrawl

Length of output: 394


Pin action SHAs and disable credential persistence in checkout.

Lines 15–16 use tag-based action refs (@v4). Pin both actions to full commit SHAs and set persist-credentials: false on checkout to mitigate supply-chain and token-exposure risk.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 15-15: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 15-15: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 16-16: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 15 - 16, Replace the tag-based action
references (actions/checkout@v4 and actions/setup-node@v4) with pinned full
commit SHAs instead of version tags to prevent supply-chain attacks.
Additionally, add the persist-credentials: false configuration option to the
checkout action to disable credential persistence and reduce token exposure
risk. Both actions should reference their specific commit SHA rather than
relying on floating version tags.

Source: Linters/SAST tools

Comment thread bin/plugin.js
Comment on lines +58 to +67
async function api(method, path, body) {
if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set");
const res = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Bearer ${API_KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout to Firecrawl API calls to prevent hangs.

Line 60 performs fetch without an abort/timeout, so a stuck network call can block the plugin from ever emitting its single response.

Suggested fix
 async function api(method, path, body) {
   if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set");
-  const res = await fetch(`${API_BASE}${path}`, {
+  const controller = new AbortController();
+  const timeoutMs = Number(process.env.FIRECRAWL_HTTP_TIMEOUT_MS || 30000);
+  const timer = setTimeout(() => controller.abort(), timeoutMs);
+  let res;
+  try {
+    res = await fetch(`${API_BASE}${path}`, {
       method,
       headers: {
         Authorization: `Bearer ${API_KEY}`,
         ...(body ? { "Content-Type": "application/json" } : {}),
       },
       body: body ? JSON.stringify(body) : undefined,
-  });
+      signal: controller.signal,
+    });
+  } finally {
+    clearTimeout(timer);
+  }
   const text = await res.text();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function api(method, path, body) {
if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set");
const res = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Bearer ${API_KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
async function api(method, path, body) {
if (!API_KEY) throw new Error("FIRECRAWL_API_KEY is not set");
const controller = new AbortController();
const timeoutMs = Number(process.env.FIRECRAWL_HTTP_TIMEOUT_MS || 30000);
const timer = setTimeout(() => controller.abort(), timeoutMs);
let res;
try {
res = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Bearer ${API_KEY}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
} finally {
clearTimeout(timer);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/plugin.js` around lines 58 - 67, The fetch call in the api function lacks
a timeout mechanism, which can cause the plugin to hang indefinitely if a
network request stalls. Add an AbortController with a timeout to the fetch
invocation: create an AbortController instance, set up a timeout that calls
abort() on the controller after a reasonable duration (e.g., 30 seconds), pass
the controller's signal in the fetch options, and ensure the timeout is cleared
if the fetch completes successfully to avoid memory leaks.

Comment thread bin/plugin.js
Comment on lines +127 to +140
if (!session.cdpUrl) throw new Error("Firecrawl did not return a cdpUrl");
return ok({
browser: {
cdpUrl: session.cdpUrl,
directPage: false,
metadata: {
sessionId: session.id,
liveViewUrl: session.liveViewUrl,
interactiveLiveViewUrl: session.interactiveLiveViewUrl,
expiresAt: session.expiresAt,
},
// Sent back to us as the browser.close request if connect fails.
cleanup: { sessionId: session.id },
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate session.id before returning browser metadata/cleanup.

Line 139 uses session.id for cleanup, but only session.cdpUrl is validated. If Firecrawl returns a cdpUrl without id, the plugin reports success but cannot close the session later.

Suggested fix
   if (type === "browser.launch") {
     const session = await api("POST", "/v2/browser", browserCreateBody(input.request));
     if (!session.cdpUrl) throw new Error("Firecrawl did not return a cdpUrl");
+    if (!session.id) throw new Error("Firecrawl did not return a session id");
     return ok({
       browser: {
         cdpUrl: session.cdpUrl,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/plugin.js` around lines 127 - 140, The code validates that session.cdpUrl
exists before returning the browser metadata, but does not validate that
session.id exists, even though session.id is used in the cleanup object on line
139. Add a validation check for session.id immediately after or in conjunction
with the existing cdpUrl validation to ensure that both required properties are
present before returning the ok() response. If session.id is missing, throw an
error with a descriptive message similar to the cdpUrl validation, preventing
the plugin from reporting success when it cannot properly track the session for
later cleanup.

@rakshith48

Copy link
Copy Markdown
Collaborator Author

Closing: full-repo review surfaced 3 findings, addressed in #2 (merged).

@rakshith48 rakshith48 closed this Jun 16, 2026
@rakshith48
rakshith48 deleted the coderabbit-review branch June 16, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant