Skip to content

Commit 622dab8

Browse files
fix: executeCdp uses {target:{tabId}} format with auto-attach
- Discovered executeCdp requires params wrapped in {target:{tabId}} format - Must call attach() before executeCdp to enable debugger - All CDP methods now auto-attach via cdpWithAttach helper - End-to-end test passes: createTab → attach → navigate → listTabs - Simplified CloseTab to use Page.close directly - Fixed claimUserTab to send integer tabId
1 parent c2bc6cd commit 622dab8

6 files changed

Lines changed: 87 additions & 59 deletions

File tree

HANDOFF.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# codex-browser-bridge — 项目交接文档
22

33
> 最后更新: 2026-05-16
4-
> 状态: **早期原型 — pipe 发现已验证,连接层待调试**
4+
> 状态: **Pipe 连接验证通过,核心 API 可用,CDP 层受限**
55
66
---
77

bridge.exe

-3 KB
Binary file not shown.

cmd/test/main.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
"time"
8+
9+
"github.com/user/codex-browser-bridge/internal/client"
10+
)
11+
12+
func main() {
13+
logger := log.New(os.Stderr, "[test] ", log.LstdFlags)
14+
15+
c, err := client.Connect("", logger)
16+
if err != nil {
17+
fmt.Fprintf(os.Stderr, "Connect failed: %v\n", err)
18+
os.Exit(1)
19+
}
20+
defer c.Close()
21+
22+
// 1. Get backend info
23+
info, err := c.GetInfo()
24+
if err != nil {
25+
fmt.Printf("GetInfo error: %v\n", err)
26+
} else {
27+
fmt.Printf("Backend: %s\n", string(info))
28+
}
29+
30+
// 2. Create a new tab
31+
tabID, err := c.CreateTab()
32+
if err != nil {
33+
fmt.Printf("CreateTab error: %v\n", err)
34+
os.Exit(1)
35+
}
36+
fmt.Printf("Created tab: %s\n", tabID)
37+
38+
// 3. Navigate the tab
39+
err = c.Navigate(tabID, "https://example.com")
40+
if err != nil {
41+
fmt.Printf("Navigate error: %v\n", err)
42+
} else {
43+
fmt.Printf("Navigated tab %s to https://example.com\n", tabID)
44+
}
45+
46+
// 4. Wait for page load
47+
time.Sleep(2 * time.Second)
48+
49+
// 5. List tabs to verify
50+
tabs, err := c.ListTabs()
51+
if err != nil {
52+
fmt.Printf("ListTabs error: %v\n", err)
53+
} else {
54+
fmt.Printf("Tabs:\n")
55+
for _, t := range tabs {
56+
fmt.Printf(" [%s] %s — %s\n", t.ID, t.Title, t.URL)
57+
}
58+
}
59+
}

internal/client/browser.go

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -63,35 +63,7 @@ func (c *Client) CloseTab(tabID string) error {
6363
if err != nil {
6464
return fmt.Errorf("close_tab requires numeric tab_id, got %q", tabID)
6565
}
66-
// First get the target info to find the targetId
67-
targets, err := c.executeCdp(id, "Target.getTargets", nil)
68-
if err != nil {
69-
// Fallback: try Page.close
70-
_, err2 := c.executeCdp(id, "Page.close", nil)
71-
return err2
72-
}
73-
// Try to find the targetId for this tab
74-
var targetInfo struct {
75-
TargetInfos []struct {
76-
TargetID string `json:"targetId"`
77-
TabID int `json:"tabId,omitempty"`
78-
} `json:"targetInfos"`
79-
}
80-
if json.Unmarshal(targets, &targetInfo) == nil {
81-
for _, t := range targetInfo.TargetInfos {
82-
if t.TabID == id {
83-
_, err = c.SendRequest("executeCdp", map[string]interface{}{
84-
"tabId": id,
85-
"method": "Target.closeTarget",
86-
"commandParams": map[string]interface{}{
87-
"targetId": t.TargetID,
88-
},
89-
})
90-
return err
91-
}
92-
}
93-
}
94-
_, err = c.executeCdp(id, "Page.close", nil)
66+
_, err = c.cdpWithAttach(id, "Page.close", nil)
9567
return err
9668
}
9769

@@ -109,14 +81,8 @@ func (c *Client) Navigate(tabID, url string) error {
10981
if err != nil {
11082
return fmt.Errorf("navigate requires numeric tab_id, got %q", tabID)
11183
}
112-
// Ensure tab is attached to this session first
113-
_, _ = c.SendRequest("attach", map[string]interface{}{
114-
"tabId": id,
115-
})
116-
_, err = c.SendRequest("executeCdp", map[string]interface{}{
117-
"tabId": id,
118-
"method": "Page.navigate",
119-
"commandParams": map[string]interface{}{"url": url},
84+
_, err = c.cdpWithAttach(id, "Page.navigate", map[string]interface{}{
85+
"url": url,
12086
})
12187
return err
12288
}
@@ -127,7 +93,7 @@ func (c *Client) NavigateBack(tabID string) error {
12793
if err != nil {
12894
return err
12995
}
130-
raw, err := c.executeCdp(id, "Page.getNavigationHistory", nil)
96+
raw, err := c.cdpWithAttach(id, "Page.getNavigationHistory", nil)
13197
if err != nil {
13298
return err
13399
}
@@ -145,7 +111,7 @@ func (c *Client) NavigateBack(tabID string) error {
145111
return fmt.Errorf("no previous page in history")
146112
}
147113
entryID := history.Entries[history.CurrentIndex-1].ID
148-
_, err = c.executeCdp(id, "Page.navigateToHistoryEntry", map[string]interface{}{
114+
_, err = c.cdpWithAttach(id, "Page.navigateToHistoryEntry", map[string]interface{}{
149115
"entryId": entryID,
150116
})
151117
return err
@@ -157,7 +123,7 @@ func (c *Client) NavigateForward(tabID string) error {
157123
if err != nil {
158124
return err
159125
}
160-
raw, err := c.executeCdp(id, "Page.getNavigationHistory", nil)
126+
raw, err := c.cdpWithAttach(id, "Page.getNavigationHistory", nil)
161127
if err != nil {
162128
return err
163129
}
@@ -175,7 +141,7 @@ func (c *Client) NavigateForward(tabID string) error {
175141
return fmt.Errorf("no next page in history")
176142
}
177143
entryID := history.Entries[history.CurrentIndex+1].ID
178-
_, err = c.executeCdp(id, "Page.navigateToHistoryEntry", map[string]interface{}{
144+
_, err = c.cdpWithAttach(id, "Page.navigateToHistoryEntry", map[string]interface{}{
179145
"entryId": entryID,
180146
})
181147
return err
@@ -187,7 +153,7 @@ func (c *Client) Reload(tabID string) error {
187153
if err != nil {
188154
return err
189155
}
190-
_, err = c.executeCdp(id, "Page.reload", nil)
156+
_, err = c.cdpWithAttach(id, "Page.reload", nil)
191157
return err
192158
}
193159

@@ -197,17 +163,29 @@ func (c *Client) executeCdp(tabID int, method string, params map[string]interfac
197163
if params == nil {
198164
params = map[string]interface{}{}
199165
}
200-
// Ensure tab is attached to this session first
201-
_, _ = c.SendRequest("attach", map[string]interface{}{
202-
"tabId": tabID,
203-
})
204166
return c.SendRequest("executeCdp", map[string]interface{}{
205-
"tabId": tabID,
206-
"method": method,
207-
"commandParams": params,
167+
"target": map[string]interface{}{
168+
"tabId": tabID,
169+
},
170+
"method": method,
171+
"commandParams": params,
208172
})
209173
}
210174

175+
// attachTab attaches the debugger to a tab (required before CDP calls).
176+
func (c *Client) attachTab(tabID int) error {
177+
_, err := c.SendRequest("attach", map[string]interface{}{
178+
"tabId": tabID,
179+
})
180+
return err
181+
}
182+
183+
// cdpWithAttach attaches the debugger and then executes a CDP command.
184+
func (c *Client) cdpWithAttach(tabID int, method string, params map[string]interface{}) (json.RawMessage, error) {
185+
_ = c.attachTab(tabID)
186+
return c.executeCdp(tabID, method, params)
187+
}
188+
211189
// --- Playwright API (via executeUnhandledCommand) ---
212190

213191
// DOMSnapshot returns an accessibility tree snapshot of the page.

test_cdp.txt

Lines changed: 0 additions & 4 deletions
This file was deleted.

test_input.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)