Repository navigation
Conversation
… was ordered for Astra measured (R107) that a delayed releaseSession(port) from a closed connection closed tab 99 of a NEW session on the same port and deleted that session: the extension keys sessions on the port alone. - offscreen.js gives every WebSocket a generation (random per document + counter); mcp_command, session_disconnect and terminate_mcp_session carry it. A terminate ordered for another generation does not close the connection that holds the port now. - background.js: a session records the generation that owns it (gen) and each tab the generation that opened it (faneGen), persisted and restored. A command from a new generation takes the session over. A release for an older generation closes only that generation's tabs; a release for the session's own generation takes the session out of the map before the first await, so a command arriving meanwhile gets a fresh session. The voluntary-release mark is bound to the generation it was ordered for. - Messages without a generation (a bridge from before 1.32) behave as before. test/sessionsgeneration.test.mjs: 11 tests (9 red before the fix, log in ~/.claude/plans/browsermcp-132/). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d persist only live tabs' generations The tab-cap source guard reads the first 500 characters of addTabToSession; the generation line pushed the eviction condition past it (suite-a90c542: 1 of 3 failures; the other two are load-timing tests that pass 3 of 3 in isolation). Persisted faneGen now only holds tabs still in the session. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… built on the lanes (#20) The idea is ugbodagadave's (PR #20): an extra listener per partition, so the extension gives each one its own tab group and active tab, and a `partition` parameter on every browser tool. It is built on the 1.31 lanes instead of the PR's own listener (R106 measured five faults in it): same createWSS, reply check, null guard, profile choice and installation lock, and pid null so the extension never adopts another lane's tabs. - browser_partition({action:'new', profile?, label?} | {action:'close', partition}). Ids p1, p2, ... are never reused. "new" binds the partition's port and chooses its installation right away by the 1.31 rules (profile = BROWSER_MCP_PROFILE for that lane; without it the client's BROWSER_MCP_PROFILE), through a harmless list_tabs. Errors: partition-limit (4 open per server), port-capacity-exhausted, profile-* (no partition is created and its port is released), profile-invalid. - "close" marks the partition closed first, closes its tabs through its own connection and releases the port: port_released, and tabs_closed true only when the extension confirmed it (or no tool call was ever routed to it), otherwise "unknown". - `partition` on every browser tool including browser_extract_token; it is stripped before the call is sent. Unknown id -> partition-not-found, closed -> partition-closed, sent:false; never the default lane. - browser_about lists the partitions; a partition call gets its own lane's notes; INSTRUCTIONS explain it. Guard tests updated where they read the source: the single response wrapper now passes the lane, browser_partition is server-local, and `partition` is a server-level parameter (not in set_combobox's case). test/partitioner.test.mjs: 22 tests (20 written first, 20 of 20 red against 6ddcbe0; log in ~/.claude/plans/browsermcp-132/). The surfaces (README table and tool count) follow in the next commit. Co-authored-by: ugbodagadave <ugbodagadave@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…face; 41 tools; flow harness covers it - CHANGELOG: "## 1.32.0 (not released yet)" above 1.31.0, crediting @ugbodagadave and #20, with the new answers. - README (and the byte-identical npm README): a Parallel agents tool row, a "Parallel agents in one chat" section with every answer, browser_about lists partitions; 40 -> 41 tools. - content/ + regenerated docs/: the tools page gets a "Parallel agents - 1 tool" section and the partition parameter; the five install pages that list every tool get a row; 40 -> 41 tools wherever the count is claimed (check-docs.py: all green, tool count 41). llms.txt, llms-install.md, server.json x2, gemini-extension.json, mcpb-manifest.json, both extension manifests (description only), CONTRIBUTING. - test/flow/run.mjs: a browser_partition step (new -> navigate in it -> its own list has the tab, the default list does not -> close with tabs_closed true), so the release gate does not see it as uncovered. Versions stay 1.30.3; the bump is the prepare PR's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e more partition tests - nyPartition puts the lane's choice note (several installations, no profile) in new's own answer and clears it, instead of leaving it for the partition's next call. - Tests: that note; a call (and a second close) while close is still closing the tabs answers partition-closed and sends nothing; a call on a partition gets the partition lane's own connection warning through the response wrapper (real server), not the default lane's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… follows the call that now carries its lane suite-2e4e12c: 1541 of 1543. billedkilder-tal read "40 tools" in demo-video-src (the rendered pictures are rebuilt from these sources at release); ejerskab looked for the send call without its lane argument. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s under a mutant fails instead of holding the run Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…also frees closed partitions' lanes Mutant P18 (no port release when closed during the bind) survived on 6dbd045, and P2 timed out because a closed lane outside `baner` kept a listener open after the test. Both covered now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kills it before failing aegteServer asserted on initialize before it had handed the test a `luk`, so a slow start left the spawned server alive and the test process never exited (measured at load ~140: three servers survived, the run hung after its last test). The server is now killed and its HOME removed before the failure, and the start gets 20 s inside the test's 60 s. Proven with a server that never answers: the old form hung until the 150 s alarm, the new form fails red in 7 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itioner No conflicts. Brings the R119/R120 fixes into 1.32: one ambiguity verdict for tool and diagnosis, the first-choice wait guarded on both sides, test deadlines and cleanup, the 1.31 honesty result, and CI job timeouts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… never rebinds the port or sends Astra measured (R121, model) that close did not stop a call that was waiting for the partition's installation: when the installation came back, the call bound the closed partition's port again and sent its command after close had answered port_released: true. The same happened to new's own list_tabs, which answered partition-closed but left the rebound port behind. - A partition's lane is now closed for good (bane.lukket), and close wakes every call waiting on it (retry wait and first-choice wait are interruptible). - sendTilBane stops a call on a closed lane at the entry, before the port is bound, and after each wait, before anything is sent. If close finished while a bind the call started was still in flight, the port is released there. Close's own calls (closing the tabs) are exempt. Tests, each red on e166751 before the fix (R121-roed-foer-rettelse.log): close during the retry wait (answered at once, no new bind, nothing sent), close during new's wait, a call that starts in the same moment as close, close while a call rebinds the port, and close during the first-choice wait. Test harness: aegteServer registers its server with 1.31's sporProces at creation, so the file's after() kills it even when a test is cut off by its deadline. Sync waits in partitioner.test.mjs wait up to 15 s, calls have a 15 s answer deadline and the bridge retry is 300 ms (measured red without a mutant at load 100-290). broModel can change the retry time during a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed; how new chooses without a profile README (both copies), the docs page and the tool description said tabs_closed: true comes only after the extension confirmed it. The code also answers true, without asking, for a partition no tool call ever used (the CHANGELOG already said so). The tool description said a partition without profile takes "the first installation that connects"; it makes the default partition's choice: it waits about 2.5 seconds, then takes the newest extension version, on a tie the one that connected last, and says which one. check-docs: all green (41 tools, 42 pages, 43 sitemap URLs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…empt If the partition's connection disappears while close is closing its tabs, close does not wait for it to come back: the retry stops at the closed lane, and close answers tabs_closed "unknown" as before. This removes the exemption from the retry path, which no test could tell apart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the retry wait proof cannot race Mutant run on c567858 (120 of 122): Q2 (no partition-closed in baneForKald) survived, because the new lane guard answered partition-closed too. The closed-id answer now has to carry the door's advice (create a new partition), not the note of a call that was waiting. Q26 (uninterruptible retry wait) survived on a race between the 30 s retry and the 15 s bound; the retry is 60 s and the bound 10 s now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nnected last", not the millisecond Astra measured (R122, model) that two installations with the same version and the same `since` millisecond made new choose the first one, while the tool description promises the one that connected last. activeConnection now breaks a version tie on the connection counter `seq` alone: `since` is only set when the connection is made, so `seq` is the same order without ties. Regression test (red before the fix, R122-roed-foer-rettelse.log): two installations, same version, same since; new must choose and send list_tabs to the one with the highest seq. README (both copies) now states the tie rule as well. check-docs: all green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… running command on a closed partition answers partition-closed
Opus measured (R122, real headless Chrome) that a call to a partition id that new was still creating got
the lane, because ids are predictable. When new then gave up (profile-not-connected, "port released"),
the call kept waiting, bound the port again and, once the profile came back, sent its command; the port
stayed bound in both runs.
Two ways to close it were on the table: let opgiv() mark the lane closed and wake its waiters, or refuse
the id until new has answered. The second has the fewest races: no call can touch the lane while new is
choosing its installation, so a call can neither lock the lane before new's own list_tabs nor survive
new giving up, and opgiv() needs no new state. baneForKald now answers partition-not-found ("still being
created") until new returns the id, and browser_about shows such a partition as state "creating".
A command that was already running when close came used to get "the connection disappeared ... start
Chrome again", which sends the agent after the wrong cause. It now answers partition-closed with
sent: true.
Tests (red before the fix, R122b-roed-foer-rettelse.log): a call during new + new fails -> no rebind,
nothing sent, port free, partition-not-found; the running-command case answers partition-closed,
sent: true. The model now closes every listener the bridge created, also one on a lane that no longer
exists (on the unfixed source the leaked port kept the test process alive). The R121 first-choice-wait
test measures its wait from now, not from the port's bind (under load the wait was already over).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…artition-closed; creating state Every surface said "ids are never reused"; that holds while the server runs, and after a restart the numbering starts at p1 again. README, CHANGELOG and the tool description now also say that new answers partition-closed when the partition is closed while it is being created, that a command already running when close came answers partition-closed with sent: true, that a partition new is still creating answers partition-not-found, and (CHANGELOG) that browser_about's state is creating, open or closed. check-docs: all green (41 tools, 42 pages, 43 sitemap URLs). README copies byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uto-reload only uses a lane that can be used Astra measured (R123, model, normal waits) that auto-reload (BROWSER_MCP_EXTENSION_UPDATED=1, set by the CLI's extension update) sent reload_extension on the lane whose connection came first, without going through baneForKald. If that was a partition being created and new gave up (profile-ambiguous, "port released"), the reload call bound the port again and sent once one installation came back. - opgiv() marks the lane closed and wakes its waiters, so no sender - also an internal one that skips baneForKald - can bind the port again or send after new gave up (stopHvisLukket). - Auto-reload uses only a lane that can be used: the default lane, or an open partition new has answered. Otherwise the update is kept for the next connection on such a lane, also when the lane closes within the reload second. The other senders were checked: tool calls and extract_token go through baneForKald, and only new's and close's own calls touch a lane directly. Runtime texts: the instructions tell partition-closed with sent: false (nothing sent) from sent: true (sent, may have been carried out); the sent: true answer no longer claims the tabs are closed, it points to close's tabs_closed; "ids are never reused" says "while this server runs". Tests, red on 5f3b096 (R123-roed-foer-rettelse.log): auto-reload on a partition new abandons (no rebind, nothing sent, update kept for the default lane), an internal sender during creation (Astra's control), and an open partition closed within the reload second (update not lost). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… still waiting when close releases the port Astra measured a normal success answer for a command the extension answered while close's list_tabs was still waiting. README (both copies), CHANGELOG and the tool description now limit the promise to what the code does: a command still waiting for its answer when close releases the port answers partition-closed with sent: true (it may have been carried out); one answered before that gets its normal answer. check-docs: all green (41 tools, 42 pages, 43 sitemap URLs). README copies byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ters Waking changed nothing a caller can see: a waiting call is stopped at its next check (at most one retry later) and binds or sends nothing before it; the only sender that can wait there is the internal auto-reload, whose answer is not shown. A mutant without the wake could therefore not be told apart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and promises no tab closing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… at this process's bridge The full suite on 77e35fb failed once in profilvalg.test.mjs: a third installation connected to its port. node --test runs the files in parallel, and partitioner.test.mjs's returning scanner (tilbage) kept dialling a port the partition had released - which another test process may bind. The scanner now connects only while the bridge in this process listens on the port (broModel.lytterPaa), and the "nothing listens" checks ask the bridge instead of binding the port at the OS level. The R121, R122 and R123 tests are still red against e166751, 71c4305 and 5f3b096. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nstruction says which connections get it R124 (Astra): close's two answers still said 'The id is not reused' without the per-process qualifier. R124 (Opus): the instructions said the server 'tells the connected extension to reload itself', but the reload only goes to a connection on the default partition or an open partition, never while a partition is being created. Text only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion with its key code and code Reported by @arasmileska (#76, 1.30.3, Windows 11, Chrome 155): Enter was sent without text, so the page got keydown/keyup 13 but no keypress, and "," got keyCode 0 and code "," (not a code Chrome knows). Tag and chip inputs that commit on Enter or comma by keypress or keyCode 188 never made the tag. - Enter sends text "\r" and unmodifiedText "\r" on keyDown, as Chrome's own Enter does. With ctrl, meta or alt it stays a shortcut without text (#68). - A one-character key gets its code from the US-layout table browser_type already uses (cdpCodeForChar), and its key code from that physical key: "," 188 Comma, "." 190 Period, "-" 189, "=" 187, ";" 186, "'" 222, "/" 191, "\" 220, "[" 219, "]" 221, "`" 192. A character not on a US keyboard gets no code instead of itself. An explicit code still wins. - A shifted character (< > ? : " { } | _ + ~ ! @ # $ % ^ & * ( )) is that physical key with Shift held, as on a real US keyboard: "<" is keyCode 188, code Comma, and Shift is in modifiers, so shiftKey is true on the page as it would be. Without Shift a page that checks shiftKey would see a key no keyboard sends. Tests (test/tast-76.test.mjs): red before the fix on the CDP parameters (76-roed-foer-rettelse.log), except the guard that ctrl/meta/alt+Enter gets no text. The extension copy in mcp-server/ is identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@arasmileska CHANGELOG under 1.32.0 credits @arasmileska for #76. README (both copies), the docs page and the tool description say that Enter gives keypress 13, punctuation has its key code and code, and shifted characters are sent with Shift; the code parameter says it defaults to the key's place in the US layout. check-docs: all green (41 tools, 42 pages, 43 sitemap URLs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s per-character typing, clearing, Tab, PageUp/Down The same class as #76 sat in browser_fill's per-character typing (typeCharsAttached, used for text= selectors and when a field does not hear the value setter): it sent a code but no key code, so keydown had keyCode 0 for punctuation, and a tag input listening for keyCode 188 never got its comma. The clear (ctrl/cmd+a, Backspace), the masked-date Tab and the date picker's PageUp/PageDown also had no key code. One shared helper, fysiskTast(key), now gives code, key code and Shift for every sender, with the rule press_key got in f28a6d1: the US-layout code table (cdpCodeForChar), the key code of that physical key, and Shift held for a shifted character. press_key uses it too. What is typed does not change: each character is still sent with itself as text. "\n" and "\t" stay as before (no Enter or Tab key code): turned into real Enter/Tab keys they could submit a form or move focus in the middle of the text. Capital letters get no Shift, as press_key never gave them. The code comment called the typing path "browser_type"; there is no such tool here. It is browser_fill. Tests (red on ca8d8a0, 76b-roed-foer-rettelse.log): typing "a,<b" gives 188 Comma for "," and "<" with Shift, and the same text; "\n"/"\t" unchanged; clearing sends 65 and 8; and a source check that every key sent over CDP carries its key code. tast-slippes' source check now allows the key code after code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… key codes One line under the #76 paragraph in CHANGELOG. The browser_fill descriptions (tool, README, docs) say nothing about key codes, so they stay as they are. check-docs: all green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…al letter gets no Shift Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ce, emoji, "\n", and set_date's clearing R125 (Astra and Opus) on 52afb28: - browser_fill text= into a tag field: the keys reached the page, the page made "tag," a tag and emptied the field, and the answer was field-is-empty with "switch tab and try again" - doing so added the tag twice (Astra, model). Typing character by character now measures delivery with press_key's listener (skrivTegnMedBevis). Keys delivered and an empty field: ok:true, differs, keys_delivered:true, "the page has handled the text, check it before typing again". Unknown delivery: check the page first, retry only if nothing happened. The direct retry advice is given only when no key reached the page. Same rule in the CSS path's per-character fallback (fyldSvar). - press_key("Space"): the page got e.key "" and the delivery proof waited for "Space", so a key that landed was answered key-not-delivered (Opus, Chrome). "Space" is now the space bar: key " ", code Space, 32, and a space as text (not with ctrl/meta/alt). - A key that is one code point is a character (an emoji too) and never gets itself as code; only a name like "Enter" or "F5" is its own code (Astra: "😀" got code "😀"). - "\n" and "\t" in fill no longer carry code "Enter"/"Tab": a page listening for e.code === 'Enter' was triggered by a line break in the value (Opus). - set_date's masked path: the clear (cmd/ctrl+a, Backspace) did not select all on macOS, and a prefilled field ended as "16/10/202601/01/2000" (Opus, Chrome). The select-all now carries Chrome's selectAll command (#68). A thrown calendar path is now an answer, and when every path fails after the field was written, the answer says so (value_before, field_changed) instead of a bare error. Tests (red on 52afb28, R125-roed-foer-rettelse.log): tag field via fill text= (no retry advice), unknown delivery, fyldSvar with delivered keys, set_date on a prefilled masked field and the failing-paths answer, Space, emoji, "\n"/"\t" without code, and selectAll in the clear. The background-tab case keeps its advice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ls on; the frame binding is dropped Blocking in R178: - Astra (measured in the model, confirmed in Chrome 155 with her fixture): ff98f01 let an inner scroll box's place replace BOTH axes, so an outer box that clips on the axis the inner one does not scroll on lost the text's position - a false found in ordinary clipped panels (a regression from da14743). The box's place now replaces only the axes it can scroll on. This was the first version; a "simplification" removed it without a test that told the two apart. - Opus' unfinished R178 measured in Chrome that the frame binding from ff98f01 closed the prerender race (35/35), but dialogs from a cross-site iframe were no longer answered: such a frame runs in another process and is not in Page.getFrameTree (on da14743 they are answered). That is a regression from 1.32 in an ordinary case, and telling an out-of-process iframe from a new prerendered main frame needs event-order data nobody has measured. The binding is removed; the dialog code is da14743's again, which R177 approved in Chrome, and the race (a dialog within about 10 ms of a prerender activation) is a known rest, as both reviews classified it. A comment says why, and a test keeps a cross-site iframe's dialog answered. - Surfaces: the sentence about frames is gone; handle_dialog reads as on da14743 everywhere. Mutants: the both-axes version, text-based clipping (two axes), swapped axes, the whole ff98f01 binding, 3A-6, the lookup after the final check, and "loading" not asking - all killed. Chrome: Opus' builders v2-v5 without new deviations, the eight fixtures 67/67, Astra's R177 fixture 3/3, Astra's R178 fixture hidden on both axes (false found on f3fcad7). Suite: 1878/1878. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ast content commit, 877a40c) The regen-diff gate failed on 877a40c: the two generated files were restored from da14743 and kept its date (2026-10-22), while the generator dates them from the last commit that touched content/browsermcp-docs-tools.md (877a40c, 2026-10-23). Only the date changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…12.0, 2026-10-22) The sentence paired 59 tools with v1.10.1 (58) and September's star count. v1.12.0 has 59 tools; the 60th (configure_webauthn) is only on their main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Versions from main (1.31.0), descriptions and the 1.32/1.33 changelog sections from this branch (41 tools). Site regenerated; docs and competitor guards green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng, email as fallback Private vulnerability reporting is enabled on the repository. The address hello@agent360.dk stays as the fallback for reporters who cannot use GitHub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ased on its own) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The docs gate correctly flagged the line as calling 1.31.0 unreleased after v1.31.0 was tagged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The docs gate correctly flagged the line as calling 1.31.0 unreleased after v1.31.0 was tagged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hed 29/10 P182-Opus: 1.32 is never released on its own, so 'from 1.32' pointed to a version that will not exist (15 places, regenerated pages follow). CHANGELOG dates the release by its GitHub publication (2026-10-29), and the 1.33 notes say that the 1.32 work follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p tools in the user's own Chrome, or name Computer MCP once with its install line Gustav 29/10: browser-mcp hands over to computer-mcp when it can't do a step; without it, the agent tells the user how to get it. Kept to the family 19/9 measured as truly outside the page (desktop app, OS dialog, native file picker, menu bar); never installs. test/server-instructions.test.mjs pins the four new parts (each mutation-proven). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ons' template literal and the server did not start Caught by the flow gate (spaerre) on 2ad544e. The text tests read the source as text and could not see it; a new test runs node --check on the server file (proven red on the unescaped line). Server started once on ports 19950-19954: initialize answers with the new paragraph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r MCP named only on macOS, changelog says what the instruction says, guard against the mention spreading Opus P183: GODKENDT MED RETTELSER (B1, B2, A1, A2 applied verbatim). New guards proven red: an extra Computer MCP mention on the CAPTCHA line, and the file picker without its OS-dialog scope. Server started once on ports 19950-19954 and sent the line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 29, 2026
…00, npm last month 3,849) The live page said 6,052 npm downloads last month; npm's last month (29/9-28/10) is 3,849, so the page overstated. Written by scripts/stjerner.py, which #81 will run on every build; until then by hand. stjerner.py --tjek OK, docs gate green, forside 25/25. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…regen gate) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GLouv
pushed a commit
that referenced
this pull request
Oct 30, 2026
…nto 1.34 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (R189) npm reaches users minutes after a release; the Chrome Web Store update days later. Until the extension is 1.33.0, it accepts any dialog - "Leave site?" too - and keeps an arming for 60 s, also across a page change, while 1.33's tool text promises the opposite. The server now refuses browser_handle_dialog with an accept (also the default) and without leave_page: true to an extension older than 1.33.0 or one that reports no version (extension-too-old-for-leave-page, nothing sent), and caps the arming it sends at 30 s. A 1.33.0+ extension gets the call untouched. "Everything else works meanwhile" (three places) now says that newer features and safeguards wait for the update. test/dialog-gammel-udvidelse.test.mjs: 7 tests on the real bridge with fake extensions (1.30.3, 1.31.0, no version, 1.33.0, 1.34.0); four mutants (guard removed, version flipped, default action bound to accept, cap removed) each turn it red. Full suite 1886/1886. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
R190 (Astra + Opus): both approved 74c8ec2 with corrections, all taken. - The guard is decided by what the extension reports, not only by its version: the 1.33 extension says dialog_leave_page: true in its hello (offscreen.js, three places). The branch's own extension is 1.31.0 in its manifest until --prepare, so the version alone refused it and the flow test's handle_dialog accept would fail. The version stays as a fallback for an extension that does not report the capability. - The note and tool text say what the older extension actually does: it knows a "Leave site?" but does not enforce leave_page, and an arming it is sent (capped at 30 s) still survives a page or tab change. The page/tab-change drop is now stated for 1.33.0+. - Tests: a list_tabs barrier before counting zero sends (a send-then-refuse mutant had passed), timeout 0, wait: true, the capability on a 1.31.0, the same installation updated and downgraded, and a partition lane next to the default lane. 9 mutants red. - test/udgivelse-script.test.mjs: git clone --local --no-hardlinks; on CI's node 24 runner /tmp is another disk and the hard links failed (Invalid cross-device link). Full suite 1890/1890; docs gate green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GLouv
pushed a commit
that referenced
this pull request
Nov 1, 2026
…puter MCP npm only has computer-mcp 0.1.0, which GHSA-pc3h covers (< 0.4.1). Until 0.4.1 is published, Browser MCP must not hand users an install command for it. The server instruction, both READMEs and the changelog now point to computermcp.dev, which says itself what is published. A test guards against an npx/claude mcp add line returning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YNkLWcoDV5PGezcYGMAAoT
…0 (review) The independent review found that computermcp.dev itself shows the npx command, so "how to install it is at computermcp.dev" still led one click to the vulnerable 0.1.0. The instruction now names the site only as the maker and forbids giving an install command; the READMEs drop the install line. Tests: the line may not contain the package name or 'how to install', and no tracked file outside test/ may name @agent360/computer-mcp (catches npm i -g, bunx, pnpm dlx and a reverted README). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YNkLWcoDV5PGezcYGMAAoT
A dialog that was closed, answered, re-armed or lost between being seen and the reply being written was still reported as waiting, with the advice to answer it. Following that advice arms a fresh 30-second window that can auto-answer the NEXT dialog on the tab. An open box now answers in the present with dialog_open; one that is gone answers in the past, with no advice. Page.enable is now ensured for key presses, double-click and right-click too, not only for single click - without it javascriptDialogOpening never fires and the dialog is never seen. And sikrSideDomaene no longer spends its full 3-second deadline when a box already stands: the answer is known in advance. Tests: dialog-lukket-boks covers both states against both copies of background.js; klik-identitet gains an integration test that closes the dialog mid-click. Both mutants (branch removed, staarAaben forced true) go red. repro-100 now exits non-zero when a tab wedges, and when no round ran at all, so it can gate instead of always reporting success. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hree states A panel review found four defects in the first fix, each measured. The worst was mine: Page.enable sat at each input site with a per-tab cache beside it. Chrome sends no onDetach for a detach we make ourselves (R108), so after browser_reattach_debugger the cache still said "on" while the new CDP session had the domain off - and dialog detection was blind in exactly the tool an agent reaches for when a tab looks stuck. The reporter had asked for it in the right place: "when the debugger attaches". It is there now, on both attach paths, and the cache is gone. Hover, press_key, double-click and right-click get it for free. The enable is not awaited. Awaiting it moved its wait in front of the busy-tab gate and used the busy window up, so a page busy longer than the gate looked free and the address was sent after all (dialog-1303 S7+T4). CDP processes commands in order on a session, so the enable still lands before the next call. The verdict is now three-way, not two. "Answered but not confirmed by Chrome" and "debugger came off the tab" are not gone - the dialog may still be on screen and our tools cannot reach it, which is what reattach_debugger already tells the user. The box is also re-read at the end: if the one we caught closed while the page opened another, the answer names the one standing now, instead of saying it is gone and advising against answering it. The guard path (a dialog holding the page during the check) answered a bare dialog: true and fell through to the old advice to call browser_handle_dialog - the very advice that arms a fresh window where no box is visible. It now names the box, or says plainly that it could not be identified. Five mutants, all red: three-way verdict, the re-read, dialogHolderSiden, the enable on attach, and the standing-box short-circuit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…good A probe from the review found the last fix had introduced a third way back to the original bug, in the fix itself. When a session is released and the tab cannot be closed (#13), the debugger comes off without Chrome sending onDetach, and the dialog box stays in the coordinator without being marked lost. The short-circuit then saw a box that looked like it was standing and skipped Page.enable - on every later attach, for good. The new CDP session had the domain off, javascriptDialogOpening never fired, and the tab was blind to dialogs again. Measured: one Page.enable before the fix, two after. The short-circuit was only needed while the enable was awaited at each input site, where three seconds of waiting was a real cost. It is not awaited any more: if the enable hangs behind a dialog, nobody is waiting for it, and when the dialog is answered the domain comes on - which is what we want. The test that asserted the short-circuit is now the regression guard for its removal, and goes red if it comes back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The release notes described every other part of 1.33 and said nothing about the bug that most of this work went into. They also credit @arasmileska by name for #76 in the same release - so the reader learns she found one issue and never hears that she found the other, or that it is fixed. The entry says what was wrong, what an agent sees now, and what is still open on the other input paths, so nobody has to find that out the hard way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1.33.0 (includes the 1.32 work below)
1.32 was never released on its own; this PR ships as 1.33.0, with main (1.31.0) merged in. On top of the 1.32 work described below, 1.33 answers a private report:
browser_handle_dialogaccepts "Leave site?" only withleave_page: true(#90), no call guesses another tab,browser_waitwaits for something that can be seen, closing the last tab no longer closes Chrome, and a screenshot path is a .png file that never replaces a file by accident. Full text:CHANGELOG.md, 1.33.0.Also in 1.33: a step outside the browser points somewhere. When what is asked for is not in a web page at all (a desktop app, an OS-level dialog, the native file picker once it has opened as an OS dialog), the server's instructions hand that step to desktop tools when the session has them, keeping the web part in the Chrome the user is signed in to. When there are none and the user is on macOS, the agent names Computer MCP once with its install line; it never installs anything. Reviewed in P183; pairs with Agent360dk/computerMCP#10.
1.32.0:
browser_partition- one partition per parallel agent (#20), real keys (#76), and honest answers when Chrome stallsBuilds the idea from #20 by @ugbodagadave (a listener per partition, a
partitionparameter on the browser tools) on the lanes that 1.31 (#75) introduced. The commit that adds the tool carriesCo-authored-by: ugbodagadave, and the CHANGELOG credits #20. #20 will be closed with a link when this is merged. Thanks to @arasmileska for #76.What changes (full text in
CHANGELOG.md, 1.32.0)browser_partition({action: 'new', profile?, label?})opens a partition with its own listener port, tab group and active tab;{action: 'close', partition}closes its tabs and frees the port. Ids are not reused while the server runs; at most 4 per server.partitionworks on every browser tool. New errors:partition-not-found,partition-closed,partition-limit,port-capacity-exhausted.connection-closed,sent: false) once the extension has registered it: at once for a closed connection or a replaced bridge, and for a bridge that closes by itself at the latest at the next heartbeat (scheduled once a minute, Chrome may run it later), and taking over an orphaned session re-checks, right before it changes anything, that the session is still orphaned.browser_press_keysends Enter and punctuation like a real keyboard. Inbrowser_fill, line breaks are written as line breaks only in text areas and editable fields, as one space only in single-line text inputs, and left out everywhere else, so a line break does not become a space-key press on a button, submit button or checkbox the tool recognises (a page that moves focus in the moment between that check and the key gets the space like any other typed character); the answer says which (line_breaks_as_spaces,line_breaks_left_out).browser_execute_scriptandbrowser_select_frame, and if still no answer arrives it saysno-answer,sent: "unknown"(the code MAY have run; not repeated). One late answer no longer tears down the extension's bridge.Base: this branch contains 1.31 (#75) and is released after the Chrome Web Store serves 1.31.0. Versions stay at 1.30.3; the bump comes in a separate prepare PR.
Evidence (on 9fd6227; 9dc101b only adds the honesty result file)
test/aerlighed/RESULTAT-2026-10-19-132-gh.md.hasDocumentalone no longer marks a live bridge dead.🤖 Generated with Claude Code