Skip to content

[feat] Introduce @workglow/browser Package for Browser Automation - #223

Closed
sroussey wants to merge 3 commits into
mainfrom
browser
Closed

[feat] Introduce @workglow/browser Package for Browser Automation#223
sroussey wants to merge 3 commits into
mainfrom
browser

Conversation

@sroussey

Copy link
Copy Markdown
Collaborator
  • Launched the initial version (0.0.1) of the @workglow/browser package, providing browser automation capabilities using accessibility trees for stable element selection.
  • Implemented features including multi-backend support (Playwright, Electron), session isolation, cookie management, and a task-based architecture for composable browser actions.
  • Added comprehensive documentation, examples, and tests to ensure functionality and ease of use.
  • Included a changelog and implementation details for better tracking of changes and features.

- Launched the initial version (0.0.1) of the @workglow/browser package, providing browser automation capabilities using accessibility trees for stable element selection.
- Implemented features including multi-backend support (Playwright, Electron), session isolation, cookie management, and a task-based architecture for composable browser actions.
- Added comprehensive documentation, examples, and tests to ensure functionality and ease of use.
- Included a changelog and implementation details for better tracking of changes and features.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces the initial version (0.0.1) of the @workglow/browser package, providing comprehensive browser automation capabilities using accessibility trees for stable element selection. The package supports multiple backends (Playwright, Electron, and remote browser services like Browserless, Browserbase, and Bright Data), includes session isolation features, cookie management, and a chainable task-based API for composable browser actions.

Changes:

  • New browser automation package with 6 backend implementations
  • Accessibility tree-based element selection system
  • Cookie store with domain/path scoping and serialization
  • 8 browser automation tasks (navigate, click, type, extract, wait, screenshot, run script, browser init)

Reviewed changes

Copilot reviewed 56 out of 57 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/browser/package.json Package configuration with multi-target builds and peer dependencies
packages/browser/tsconfig.json TypeScript configuration for the browser package
packages/browser/src/a11y/* Accessibility tree parser and query system
packages/browser/src/context/* Browser context implementations for Playwright, Electron, and remote services
packages/browser/src/task/* Browser automation task implementations
packages/browser/src/workflow/* Workflow integration and helper functions
packages/browser/src/test/* Comprehensive test suite with 40+ passing tests
packages/browser/docs/* Documentation for session isolation, partitions, and remote browsers
packages/browser/examples/* Working examples demonstrating usage patterns
test-electron/* Electron integration test application

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/browser/src/a11y/A11yParser.ts Outdated
Comment on lines +513 to +517
const label = document.querySelector(`label[for="${htmlElement.id}"]`);
if (label) {
const labelText = label.textContent?.trim();
if (labelText) {
return labelText;

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

The computeAccessibleName function uses document.getElementById() with an unsanitized id from aria-labelledby attribute. While this is generally safe because getElementById does not execute code, the selector construction on line 513 uses string interpolation with htmlElement.id directly in querySelector(). This could be vulnerable to selector injection if the ID contains special characters. Consider using document.getElementById(htmlElement.id) instead or sanitizing the ID before constructing the selector.

Suggested change
const label = document.querySelector(`label[for="${htmlElement.id}"]`);
if (label) {
const labelText = label.textContent?.trim();
if (labelText) {
return labelText;
const labels = document.getElementsByTagName("label");
for (let i = 0; i < labels.length; i++) {
const labelElement = labels[i] as HTMLLabelElement;
if (labelElement.htmlFor === htmlElement.id) {
const labelText = labelElement.textContent?.trim();
if (labelText) {
return labelText;
}
break;

Copilot uses AI. Check for mistakes.
Comment on lines +340 to +368
// Close with a timeout to prevent hanging
const closePromise = (async () => {
try {
if (this.context) {
await this.context.close();
}
} catch {
// Ignore errors during close
}
})();

// Race against a 5-second timeout
await Promise.race([
closePromise,
new Promise<void>((resolve) => setTimeout(resolve, 5000)),
]);

// Always clear references
this.page = undefined;
this.context = undefined;
this.browser = undefined;
this.responseHandler = undefined;

// Remove from global tracker
activeContexts.delete(this);

// Small delay to let browser process fully terminate
await new Promise((resolve) => setTimeout(resolve, 100));
}

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

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

The close() method races the cleanup against a 5-second timeout, but then always clears references regardless of whether context.close() completed successfully. If the close promise is still running after the timeout, this could result in attempting to close an already-freed context or leave resources hanging. Consider awaiting the close promise with a timeout wrapper instead of racing, or add a flag to track whether cleanup completed.

Copilot uses AI. Check for mistakes.
@sroussey

Copy link
Copy Markdown
Collaborator Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copilot AI commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

@sroussey I've opened a new pull request, #224, to work on those changes. Once the pull request is ready, I'll request review from you.

@sroussey

Copy link
Copy Markdown
Collaborator Author

@copilot fix issues found via build/test

Copilot AI commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

@sroussey I've opened a new pull request, #225, to work on those changes. Once the pull request is ready, I'll request review from you.

@sroussey sroussey closed this Feb 25, 2026
@sroussey
sroussey deleted the browser branch March 19, 2026 21:00
@sroussey
sroussey restored the browser branch March 19, 2026 21:00
@sroussey
sroussey deleted the browser branch April 9, 2026 16:15
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.

3 participants