1. High-Level Summary (TL;DR)
- Impact: Low. A bug-fix release for
new-page and the [target:name] stderr line. No flag or command was added, removed or renamed.
- Key Changes:
- π·οΈ Friendly Name from
new-page: It prints the word-pair name (e.g. icy-goat) that list-pages shows, instead of the raw CDP target ID.
- π
[target:name] Is Back in Daemon Mode: Page-level commands print it on stderr again. In daemon mode, the default path, it had stopped appearing.
- π§ Emulation Stays on the New Tab:
new-page with --viewport, --mobile, --geolocation or --block-url no longer loses the override on the new tab or applies it to the tab that was active before.
- π‘
network Survives --extra-headers: After a navigate --extra-headers, the tab silently stopped collecting requests. It keeps collecting now.
2. Visual Overview (Code & Logic Map)
graph TD
%% Business Goals
BG1["Name the New Tab Like list-pages"]:::goal
BG2["Print [target:name] in Daemon Mode"]:::goal
BG3["Keep Emulation on the New Tab"]:::goal
BG4["Keep Network Collection Alive"]:::goal
%% Files/Modules
subgraph "src/commands/pages.rs (Page Commands)"
P1["opened_page()"]
P2["new_page()"]
P3["clear_extra_headers()"]
end
subgraph "src/protocol.rs & src/daemon.rs (IPC)"
I1["DaemonResponse.target_id"]
I2["handle_request()"]
end
subgraph "src/lib.rs (CLI Output)"
L1["print_response()"]
L2["print_output()"]
end
BG1 <--> P1
BG2 <--> I1
BG2 <--> L1
BG3 <--> P2
BG4 <--> P3
P2 --> P1
P2 --> P3
P1 --> I2
I2 --> I1
I1 --> L1
L1 --> L2
classDef goal fill:#e3f2fd,color:#0d47a1,stroke:#0d47a1,stroke-width:2px;
3. Detailed Change Analysis
π·οΈ Naming the New Tab
- Component:
Page Commands (src/commands/pages.rs)
- What Changed:
new-page printed the raw CDP target ID where list-pages, close-page and select-page use the friendly name. opened_page now names the tab the way list-pages does and tags the result with that name. Browser-level commands skip the step that tags page commands with their target, so new-page has to set the tag itself.
- Output:
| Stream |
Before |
After |
| stdout |
Opened new page: <url> (target: C08EA3F291931B3333A12DFB7B570CF6) |
Opened new page: <url> (target: icy-goat) |
| stderr |
(nothing in daemon mode) |
[target:icy-goat] |
- Note:
--target accepts either the raw ID or the friendly name, so a script that captures the name from stdout and passes it to --target needs no change.
π [target:name] in Daemon Mode
- Component:
Daemon IPC (src/protocol.rs, src/daemon.rs, src/lib.rs)
- What Changed: The line had moved from an appended output line into
CommandResult.target_id, but DaemonResponse only carried navigated_to, so on the default daemon path the CLI had nothing to print. DaemonResponse now carries target_id, handle_request fills it, and print_response passes it to print_output.
- Format:
[target:name], with no space after the colon. That is the form README and SKILL.md document. The spaced [target: name] only ever appeared in the no-daemon fallback, and it now prints the documented form too.
- Compatibility: An older daemon's response has no
target_id and parses as None (covered by a unit test). An older CLI ignores the extra field.
π§ Emulation on the New Tab
- Component:
new-page (src/commands/pages.rs)
- What Changed: With an emulation flag or
--extra-headers, new-page opens about:blank, applies the settings, then loads the URL. It used to run emulate() on a throwaway session for the new tab, but emulate() records overrides as the state of the persistent session's tab. The new tab lost them when the throwaway session detached, and the daemon credited them to whichever tab was active before. new-page now attaches the persistent session to the new tab, runs emulate() there, then runs navigate's header, navigation and load-wait flow, the same path navigate takes for an existing tab. The overrides become the new tab's own per-tab state, as if set with emulate on that tab.
- Behavior:
| Scenario |
Before |
After |
new-page <url> --viewport 375x812 --mobile |
The new tab lost the viewport, and the previously active tab later rendered at 375x812. |
The new tab keeps 375x812. The other tab keeps its own size. |
new-page <url> --block-url '*.png' |
The previously active tab's requests were blocked. |
Only the new tab's requests are blocked. |
new-page with these flags and a failed navigation |
Same leak. |
The tab is closed and forgotten, so the daemon is not left pointing at it and nothing leaks. |
π‘ Network Collection After --extra-headers
- Component:
Extra Headers (src/commands/pages.rs)
- What Changed:
clear_extra_headers ended with Network.disable on whatever session it was given, the persistent one included. The network command drains what that session collects, so after any navigate --extra-headers the tab stopped collecting requests with no error. Network.disable now only runs on a per-command session, where it undoes apply_extra_headers' Network.enable. Headers still reach only the navigation they were set for. new-page takes this path too now.
π Docs
- Component:
Agent Skill (skill/chrome-devtools/SKILL.md)
- What Changed: The
new-page stdout example now shows the real output (Opened new page: β¦ (target: icy-goat)) instead of Opened: β¦.
4. Fixes
- π
new-page printed the raw CDP target ID where every other page command uses the friendly name.
- π The
[target:name] stderr line never appeared in daemon mode, although README and SKILL.md promise it for page-level commands. evaluate, screenshot, select-page and new-page print it again.
- π
new-page emulation leaked onto the wrong tab. --viewport, --mobile, --geolocation and --block-url were lost on the new tab and credited to the tab that was active before, which then rendered at the new tab's viewport or had its requests blocked. A failed navigation leaked the same way.
- π
network stopped collecting after navigate --extra-headers, silently, with no error.
5. Impact & Risk Assessment
β οΈ Breaking Changes
- None. No flag or command was removed or renamed. The output changes below are listed under Upgrade Notes.
π Upgrade Notes
- A daemon that is already running keeps the old behavior. The fixes live in the daemon process, so they apply only to a daemon started by 2.1.1. An old daemon exits on its 5-minute idle timeout.
kill-daemon ends it sooner, but it drops the daemon's approved Chrome connection, so Chrome may ask for consent again.
new-page stdout carries the friendly name. --target accepts it, so capture-and-pin scripts keep working. A script that used the hex ID outside the CLI, for example in direct CDP calls, no longer gets it from this line.
[target: name] in the no-daemon fallback is now [target:name]. A script that matches the spaced form must drop the space.
new-page with flags makes the new tab the daemon's active tab. As with any command on another tab, that discards the previous tab's undrained console and network events, so drain them first if you need them. In return, the new tab's initial load now shows up in its network output.
- A failed
new-page navigation reads Navigation error: β¦ instead of Page.navigate failed: β¦ when emulation flags or --extra-headers are used. Anything matching the old text must change.
π Known Limitations
- The
new-page flag path was verified live, not by an automated test. The change is about which CDP session the calls run on, and the repo has no CDP mock. It was exercised in daemon mode against Chrome 154 with a local server recording request headers.