Skip to content

Add the TinyFlows Chrome workflow companion#15

Merged
senamakel merged 32 commits into
mainfrom
feat/chrome-extension
Jul 22, 2026
Merged

Add the TinyFlows Chrome workflow companion#15
senamakel merged 32 commits into
mainfrom
feat/chrome-extension

Conversation

@senamakel

@senamakel senamakel commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary

  • add the versioned Rust/TypeScript browser action protocol and explicit browser tool routing while preserving host integration dispatch
  • add an authenticated loopback companion with exact extension-origin checks, subprotocol pairing, explicit run/tab binding, cancellation, heartbeat handling, workflow control, and stable errors
  • add the MV3 Chrome extension with debugger-backed actions, explicit TinyFlows tab sharing, service-worker rehydration, badges, popup, and persistent run side panel
  • ship CLI pairing/companion/tab/workflow/run commands plus an embedded unpacked extension that survives cargo install
  • add canonical fixtures/schema, documentation, deterministic ZIP/checksum, CI gates, mocked extension tests, mixed-routing Rust coverage, and Playwright extension journeys

Security and behavior

The extension never owns workflow state, credentials, approvals, retries, or non-browser integrations. It can only control ordinary HTTP(S) tabs explicitly shared into the TinyFlows tab group. Every run is bound to one selected shared tab and fails closed on revocation, timeout, cancellation, protocol mismatch, or relay loss.

The relay binds only to loopback, authenticates the exact paired chrome-extension:// origin and every session, and carries the host-local secret in the WebSocket subprotocol rather than the URL.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo build --all-targets --all-features
  • cargo test --all-features (367 unit tests plus integration and doc tests)
  • cargo package
  • cargo llvm-cov --all-features --workspace --summary-only --fail-under-lines 90 (90.39% lines)
  • npm run verify (20 Vitest tests; 94.19% lines across protocol/relay/CDP/tab-manager core)
  • npm run test:e2e (3 Playwright MV3 journeys)
  • actionlint .github/workflows/ci.yml
  • deterministic archive SHA-256: 657de561f3b6beefd6810b540885b18b77b9159944b30134251a043e36dd09a2

Chrome Web Store submission and OpenHuman host wiring remain follow-up work, as scoped.

Summary by CodeRabbit

  • New Features

    • Added an optional Chrome workflow companion with a locally bundled Manifest V3 extension.
    • Run browser actions such as navigation, clicking, typing, screenshots, and page inspection in explicitly shared tabs.
    • Added pairing, tab-sharing controls, workflow side panel, run monitoring, and cancellation.
    • Added CLI commands for extension setup, pairing, companion startup, tab and workflow listing, and workflow execution.
    • Added versioned browser action contracts and secure loopback authentication with pairing-secret rotation.
  • Documentation

    • Added installation, pairing, security, usage, and troubleshooting guidance.
  • Tests

    • Added unit, end-to-end, CLI, and coverage enforcement.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 3 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5dabaf3c-c004-4379-872d-eb118722c7cc

📥 Commits

Reviewing files that changed from the base of the PR and between ca436da and 4c379b2.

⛔ Files ignored due to path filters (2)
  • extension/artifacts/tinyflows-chrome-extension-0.1.0.zip is excluded by !**/*.zip
  • extension/dist/background.js is excluded by !**/dist/**
📒 Files selected for processing (21)
  • extension/.gitignore
  • extension/artifacts/tinyflows-chrome-extension-0.1.0.zip.sha256
  • extension/package.json
  • extension/scripts/package.mjs
  • extension/src/background.ts
  • extension/src/cdp.ts
  • extension/src/errors.ts
  • extension/src/protocol.ts
  • extension/src/relay.ts
  • extension/src/tab-manager.ts
  • extension/tests/cdp.test.ts
  • extension/tests/e2e/extension.spec.ts
  • extension/tests/errors.test.ts
  • extension/tests/protocol.test.ts
  • extension/tests/relay.test.ts
  • extension/tests/tab-manager.test.ts
  • src/browser/protocol.rs
  • src/companion/control.rs
  • src/companion/server.rs
  • src/lib.rs
  • src/main.rs
📝 Walkthrough

Walkthrough

The PR adds a versioned browser automation protocol, authenticated loopback companion, MV3 Chrome extension, debugger-based actions, explicit tab sharing, CLI commands, deterministic packaging, documentation, and CI coverage and end-to-end validation.

Changes

Chrome companion workflow

Layer / File(s) Summary
Browser protocol and tool routing
src/browser/*, protocol/*, extension/src/protocol.ts
Defines browser actions, strict message validation, correlated responses, schema fixtures, and routing for slug: "browser" while preserving host-tool delegation.
Pairing, tab authorization, and relay state
src/companion/auth.rs, src/companion/tabs.rs, src/companion/relay.rs
Adds pairing-secret storage and rotation, WebSocket authentication, explicit tab/run bindings, heartbeat tracking, timeout handling, revocation, cancellation, and disconnect failures.
Native companion server and control API
src/companion/control.rs, src/companion/server.rs
Adds authenticated HTTP/WebSocket handling, workflow loading and execution, browser action correlation, control requests, run events, and cancellation.
Extension relay, tab sharing, and CDP execution
extension/src/{background,relay,tab-manager,cdp,errors}.ts
Connects the extension to the companion, manages shared debugger-attached tabs, executes browser actions, emits lifecycle events, and normalizes failures.
Extension pairing and workflow UI
extension/src/{popup,sidepanel}.*, extension/src/ui.css
Adds popup pairing and sharing controls plus side-panel workflow listing, execution, cancellation, connection state, and event rendering.
CLI provisioning, packaging, and validation
src/main.rs, extension/scripts/*, extension/tests/*, tests/*, .github/workflows/ci.yml
Adds CLI provisioning and pairing commands, deterministic archives and checksums, unit/E2E coverage, and CI jobs for Rust coverage and Chrome extension validation.
Documentation and release contract
README.md, docs/chrome-extension.md, extension/README.md, CHANGELOG.md
Documents installation, pairing, browser actions, security boundaries, packaging, and unreleased companion deliverables.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChromeExtension
  participant CompanionServer
  participant WorkflowEngine
  participant BrowserRelay
  User->>ChromeExtension: Pair and share tab
  ChromeExtension->>CompanionServer: Authenticated WebSocket connection
  User->>CompanionServer: Start workflow for tab
  CompanionServer->>WorkflowEngine: Execute workflow
  WorkflowEngine->>BrowserRelay: Invoke browser tool
  BrowserRelay->>ChromeExtension: Send browser action
  ChromeExtension-->>BrowserRelay: Return action response
  BrowserRelay-->>WorkflowEngine: Return browser result
  WorkflowEngine-->>User: Publish run events
Loading

Poem

I’m a rabbit with a relay to run,
Browser hops now follow the sun.
Tabs share, secrets turn,
Tiny workflows leap and learn,
With zipped-up code and tests that thrum!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding the TinyFlows Chrome workflow companion and related extension/relay support.
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.

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

@senamakel
senamakel marked this pull request as ready for review July 22, 2026 14:23

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca436dacb1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extension/src/cdp.ts Outdated
Comment thread extension/src/protocol.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe3e7a4149

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/companion/server.rs Outdated
Comment thread extension/src/cdp.ts Outdated
@senamakel

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 10

🧹 Nitpick comments (3)
extension/src/cdp.ts (1)

105-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

evaluate() discards the underlying exception, hindering debugging.

exceptionDetails is checked only for presence; the actual failure text/description is dropped in favor of a generic 'Page evaluation failed'. This makes it hard for a workflow author to diagnose why get_text/fill/find/wait failed on a given page.

♻️ Surface the exception text
   const result = response as { result?: { value?: unknown }; exceptionDetails?: unknown };
-  if (result.exceptionDetails) throw new BrowserError('browser_failure', 'Page evaluation failed');
+  if (result.exceptionDetails) {
+    const details = result.exceptionDetails as { exception?: { description?: string }, text?: string };
+    throw new BrowserError('browser_failure', details.exception?.description ?? details.text ?? 'Page evaluation failed');
+  }
🤖 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 `@extension/src/cdp.ts` around lines 105 - 110, Update evaluate() to extract
the exception text or description from result.exceptionDetails and include it in
the BrowserError message while preserving the existing browser_failure code and
generic fallback when no details are available.
extension/src/tab-manager.ts (1)

108-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant tabs.get call in announcement(); reuse the tab already fetched by assertShared.

assertShared already fetches the tab (line 90) and validates its URL. announcement() then fetches it again independently and asserts tab.url! non-null. Besides the extra API call, there's a small TOCTOU window where the tab could close or navigate between the two fetches.

♻️ Reuse the validated tab
-  async announcement(tabId: number): Promise<SharedTabAnnouncement> {
-    const shared = await this.assertShared(tabId);
-    const tab = await this.api.tabs.get(tabId);
-    return {
-      id: tabId,
-      window_id: shared.windowId,
-      url: tab.url!,
-      title: tab.title ?? ''
-    };
-  }
+  async announcement(tabId: number): Promise<SharedTabAnnouncement> {
+    const shared = await this.assertShared(tabId);
+    const tab = await this.api.tabs.get(tabId); // still needed if assertShared doesn't return the Tab
+    return {
+      id: tabId,
+      window_id: shared.windowId,
+      url: tab.url ?? '',
+      title: tab.title ?? ''
+    };
+  }

(Ideally have assertShared return the already-fetched Tab alongside the SharedTab record to avoid the second call.)

🤖 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 `@extension/src/tab-manager.ts` around lines 108 - 117, Update assertShared and
announcement to reuse the tab fetched and URL-validated by assertShared: return
the validated Tab alongside the SharedTab record, then use that returned tab
when constructing SharedTabAnnouncement. Remove the independent api.tabs.get
call and the non-null URL assertion while preserving the existing shared-tab
validation behavior.
extension/src/errors.ts (1)

14-21: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Tab-revocation detection relies on matching Chrome's internal error wording.

toBrowserError classifies tab_revoked by checking message.toLowerCase().includes('no tab with id'), which is Chrome's undocumented internal phrasing for a missing tab (e.g. from chrome.tabs.remove/chrome.debugger.sendCommand). Given how central tab_revoked is to the fail-closed contract (per src/browser/routing.rs's stable_relay_error_code_reaches_engine_retry_surface test), a wording change in a future Chrome release would silently degrade this to browser_failure without any test failure in this repo. Consider proactively checking tab existence (e.g. via chrome.tabs.get before relying on string matching) rather than depending solely on error text.

🤖 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 `@extension/src/errors.ts` around lines 14 - 21, Update toBrowserError and its
callers so tab-revocation classification is based on an explicit chrome.tabs.get
existence check rather than relying solely on the “no tab with id” message.
Preserve tab_revoked for confirmed missing tabs, while retaining browser_failure
for other errors and existing BrowserError instances; adjust the flow to support
the required asynchronous lookup.
🤖 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 `@extension/.gitignore`:
- Around line 2-4: Update the ignore rules for the artifacts directory so
generated archive files remain ignored while checksum files matching *.sha256
remain visible and trackable by Git. Replace the broad artifacts/ rule with
specific archive exclusion and checksum negation patterns.

In `@extension/package.json`:
- Line 13: Update the package script in package.json so it runs the project
build before invoking scripts/package.mjs, ensuring packaging uses freshly
generated dist output.

In `@extension/src/relay.ts`:
- Around line 40-46: Guard the socket handlers in connect() so onerror and
onclose ignore events from sockets that are no longer this.socket, matching the
existing onopen check. Update stop() to clear this.socket when stopping, while
ensuring the active socket cleanup and pending-request rejection still occur.
Only clear timers, reject pending requests, and schedule reconnects for the
current socket and configuration.
- Around line 139-150: Update the pairingToken validation in isRelayConfig to
allow the full base64url character set, including hyphen and underscore, while
preserving the existing length requirement and rejecting other characters.

In `@extension/tests/e2e/extension.spec.ts`:
- Around line 58-144: Wrap the relay setup and test actions, including the
existing close-response assertions, in a try/finally block. In finally, close
extensionSocket if present and await relayServer.close completion so the mock
WebSocketServer is always shut down even when an assertion or action fails.

In `@src/browser/protocol.rs`:
- Around line 14-16: The BrowserAction unit variants still accept unknown
payload fields despite deny_unknown_fields. Update the BrowserAction
representation or add explicit deserialization validation so Snapshot, GetTitle,
GetUrl, and Close reject inputs such as {"action":"snapshot","foo":1}, while
preserving valid decoding; add a test covering rejection of extra fields.

In `@src/browser/routing.rs`:
- Around line 169-172: Align native Fill validation with the extension validator
by updating validate_action’s BrowserAction::Fill branch to require a non-empty
value as well as a non-empty selector. Preserve the existing selector validation
and fail native pre-validation for empty Fill values.

In `@src/lib.rs`:
- Around line 22-25: Add doc comments to the public module declarations
`browser` and `companion` in `lib.rs`, briefly describing each module’s purpose,
so they satisfy the existing `missing_docs` lint.

In `@src/main.rs`:
- Around line 273-287: Update MemoryState::load to propagate a poisoned mutex
error instead of converting it to None, matching MemoryState::store’s error
behavior. Reuse unavailable("state store") or an appropriate
state-store-specific error, and ensure the existing key lookup still returns
None only when the lock succeeds and the key is absent.
- Around line 88-117: Add a finite request timeout to the reqwest clients used
by native_get and native_run, using the existing client builder pattern and the
repository’s established timeout value or configuration. Ensure both calls
retain their current request behavior while failing instead of blocking
indefinitely.

---

Nitpick comments:
In `@extension/src/cdp.ts`:
- Around line 105-110: Update evaluate() to extract the exception text or
description from result.exceptionDetails and include it in the BrowserError
message while preserving the existing browser_failure code and generic fallback
when no details are available.

In `@extension/src/errors.ts`:
- Around line 14-21: Update toBrowserError and its callers so tab-revocation
classification is based on an explicit chrome.tabs.get existence check rather
than relying solely on the “no tab with id” message. Preserve tab_revoked for
confirmed missing tabs, while retaining browser_failure for other errors and
existing BrowserError instances; adjust the flow to support the required
asynchronous lookup.

In `@extension/src/tab-manager.ts`:
- Around line 108-117: Update assertShared and announcement to reuse the tab
fetched and URL-validated by assertShared: return the validated Tab alongside
the SharedTab record, then use that returned tab when constructing
SharedTabAnnouncement. Remove the independent api.tabs.get call and the non-null
URL assertion while preserving the existing shared-tab validation behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee98e0ce-9628-4f8d-bf1e-522e215dc97b

📥 Commits

Reviewing files that changed from the base of the PR and between fb24363 and ca436da.

⛔ Files ignored due to path filters (10)
  • Cargo.lock is excluded by !**/*.lock
  • extension/artifacts/tinyflows-chrome-extension-0.1.0.zip is excluded by !**/*.zip
  • extension/dist/background.js is excluded by !**/dist/**
  • extension/dist/manifest.json is excluded by !**/dist/**
  • extension/dist/popup.html is excluded by !**/dist/**
  • extension/dist/popup.js is excluded by !**/dist/**
  • extension/dist/sidepanel.html is excluded by !**/dist/**
  • extension/dist/sidepanel.js is excluded by !**/dist/**
  • extension/dist/ui.css is excluded by !**/dist/**
  • extension/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (53)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • Cargo.toml
  • README.md
  • docs/chrome-extension.md
  • extension/.gitignore
  • extension/README.md
  • extension/artifacts/tinyflows-chrome-extension-0.1.0.zip.sha256
  • extension/eslint.config.js
  • extension/manifest.json
  • extension/package.json
  • extension/playwright.config.ts
  • extension/scripts/build.mjs
  • extension/scripts/package.mjs
  • extension/src/background.ts
  • extension/src/cdp.ts
  • extension/src/errors.ts
  • extension/src/popup.html
  • extension/src/popup.ts
  • extension/src/protocol.ts
  • extension/src/relay.ts
  • extension/src/sidepanel.html
  • extension/src/sidepanel.ts
  • extension/src/tab-manager.ts
  • extension/src/ui.css
  • extension/tests/cdp.test.ts
  • extension/tests/e2e/extension.spec.ts
  • extension/tests/errors.test.ts
  • extension/tests/protocol.test.ts
  • extension/tests/relay.test.ts
  • extension/tests/tab-manager.test.ts
  • extension/tsconfig.json
  • extension/vitest.config.ts
  • protocol/browser-v1.schema.json
  • protocol/fixtures/browser-cancel.v1.json
  • protocol/fixtures/browser-request.v1.json
  • protocol/fixtures/browser-response.v1.json
  • protocol/fixtures/tab-shared.v1.json
  • src/browser/mod.rs
  • src/browser/protocol.rs
  • src/browser/routing.rs
  • src/companion/auth.rs
  • src/companion/control.rs
  • src/companion/mod.rs
  • src/companion/relay.rs
  • src/companion/server.rs
  • src/companion/tabs.rs
  • src/engine.rs
  • src/lib.rs
  • src/main.rs
  • src/observability.rs
  • tests/browser_routing_e2e.rs
  • tests/cli_e2e.rs

Comment thread extension/.gitignore Outdated
Comment thread extension/package.json Outdated
Comment thread extension/src/relay.ts
Comment thread extension/src/relay.ts
Comment thread extension/tests/e2e/extension.spec.ts
Comment thread src/browser/protocol.rs Outdated
Comment thread src/browser/routing.rs
Comment thread src/lib.rs
Comment thread src/main.rs
Comment thread src/main.rs

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b57ccb839

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extension/src/background.ts Outdated
Comment thread src/companion/server.rs Outdated
Comment thread extension/src/cdp.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13cc80422c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/companion/server.rs Outdated
Comment thread extension/src/cdp.ts Outdated
Comment thread extension/src/tab-manager.ts Outdated
@senamakel

Copy link
Copy Markdown
Member Author

Also addressed the remaining review notes in 3e8b4fe: page-evaluation errors now preserve CDP exception diagnostics, shared-tab announcements reuse the already validated tab, and tab revocation is confirmed with chrome.tabs.get instead of Chrome error-string matching. All corresponding unit/E2E tests pass locally.

@senamakel
senamakel merged commit fa7a31b into main Jul 22, 2026
5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c379b2542

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extension/src/relay.ts
this.onState('connected');
this.heartbeatTimer = setInterval(() => this.send({ protocol_version: PROTOCOL_VERSION, type: 'heartbeat' }), 15_000);
};
socket.onmessage = (event) => { void this.handleMessage(String(event.data)); };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Serialize browser requests per tab

When a workflow fans out into two browser tool nodes for the same shared tab, the native side can send both requests over the socket as separate pending actions. This handler starts handleMessage for each WebSocket frame without awaiting or queueing the prior one, so both onBrowserRequest calls can drive CDP concurrently (for example, an open racing a click or fill) and a step can run against the wrong document while both report success; queue browser requests per tab/run before invoking onBrowserRequest.

Useful? React with 👍 / 👎.

async function announceAllSharedTabs(): Promise<void> {
for (const { tabId } of tabs.list()) {
try { relay.send(tabSharedEvent(await tabs.announcement(tabId))); }
catch { /* assertShared revokes stale attachment metadata */ }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Revoke stale shared tabs on reconnect

When the extension reconnects after a user closed, ungrouped, or navigated a previously shared tab while the relay was down, tabs.announcement(tabId) revokes the local record and then this catch swallows the failure without sending tab_revoked. Because the native relay keeps its shared-tab registry across disconnects, it can still list and bind workflows to that stale tab until the first browser action fails, allowing earlier non-browser workflow steps to run after tab consent was effectively revoked; send a revocation for this tabId when re-announcement fails.

Useful? React with 👍 / 👎.

Comment thread extension/src/cdp.ts
Comment on lines +75 to +78
const ok = await evaluate(this.debuggerApi, target, `(() => { const e=document.querySelector(${JSON.stringify(action.selector)}); if(!e)return null; e.focus(); return true; })()`);
if (ok !== true) throw new BrowserError('element_not_found', `No element matches ${action.selector}`);
}
await this.debuggerApi.sendCommand(target, 'Input.insertText', { text: action.text });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Verify focus before inserting typed text

When the selector resolves to a hidden, disabled, or otherwise non-focusable element, e.focus() can leave focus on whatever control was previously active, but this expression still returns true and the following Input.insertText types there while reporting success. For workflows with a stale or broad selector, that can mutate the wrong field instead of failing/retrying; ensure the target is visible/editable and became document.activeElement before inserting text.

Useful? React with 👍 / 👎.

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