Documentation
¶
Overview ¶
Package browser — chromeHandleImpl: cross-platform ChromeHandle owning *exec.Cmd.
Used by:
- All Workspace implementations (darwin/linux/windows/other) — wraps the Chrome fork they spawn and exposes lifecycle to caller via ChromeHandle.
- NoopWorkspace fallback for tests.
Invariants:
- cmd.Process != nil after successful startChromeProcess return.
- doneCh is closed when cmd.Wait returns (any cause).
- Kill is idempotent — multiple callers wait on the same doneCh.
- Wait blocks until process exits and returns cmd.Wait's error.
[Ref: TH-0419 — Workspace as visible-Chrome SSOT]
compat.go provides backward-compatible stubs for types that were in the old go-rod-based browser package and are still referenced by internal/desktop (Wails UI). These types are deprecated and will be removed after the desktop package is migrated to BS-09 BrowserCore API.
DO NOT add new usages of these types. Use BrowserCore instead.
Package browser — CookieImporter: 从本机浏览器导入 Cookie。 [Ref: CAP-BS09-C4 §3.2b, SC-22, TC-C4-07~11, r2 Delta-REQ TH-0418-c9x]
铁律 IR-01: 本包零依赖 Deepwork 上下文。 安全约束: 只读打开源 Cookie 文件,不修改用户浏览器数据。
Package browser — Cookie 加解密共享工具函数。 [Ref: CAP-BS09-C4 §3.2b, TC-C4-07]
Package browser 实现 BS-09 Browser Runtime。 以 A11y+Element Refs 为核心,为 LLM 提供低 token 高精度 Web 感知通道。
铁律 IR-01: 本包零依赖 Deepwork 上下文(conversation/topic/webui/memory/agent/llm 均不得引入)。 铁律 IR-02: 使用 chromedp Go 直连 CDP,不引入 Node.js/TS 运行时。
Package browser — DisplayManager: 虚拟 display 生命周期管理 (跨平台)。 从 BrowserPool 提取,供 Pool 和 dw-browser CLI (NewBrowserCore) 共享。
Package browser implements BS-09 Browser Runtime. 旧错误定义已迁移到 core.go,此文件保留以兼容旧引用。 新错误变量定义见 core.go。
Package browser — Browser Fingerprint Presets. 消除 headless Chrome 指纹,模拟真实浏览器环境。 设计依据: TH-0405-k8r + CAP-BS09-C4 Profile Management
Package browser — identity 三元组类型定义 [v2 Phase_v2_1, TH-0419-w3p MERGED]
来源:
- CAP-BS09-C4 §2.bis (IdentityRegistry / IsolationPolicy interface 契约)
- T5-BS-09 §0.2 (identity 三元组 (Profile, Preset, IsolationPolicy) → IdentityKey)
- BP-BS-09 §V2.B.1 (Phase_v2_1 必读数据契约)
范围 (Phase_v2_1):
- 类型定义: IdentityKey / Preset / Viewport / IdentityDescriptor / IsolationPolicy / NoopPolicy / Identity / BrowserSessionHandle 占位
- IdentityKey() 工厂函数: 三元组 → 确定性 hash
不在范围 (deferred to Phase_v2_2/v2_3/v2_4):
- Pool 集成 (Phase_v2_2): identity-keyed Chrome 实例池
- 6 入口迁移 (Phase_v2_3): webui/tool/dw-browser/council/live_sync/desktop 走 Pool API
- ProxyPolicy 首例 (Phase_v2_4 P1): 当前只有 NoopPolicy stub (D9 SL-2)
推迟标记 (BP §V2.B.3, T5 §0 D9 SL-2):
- 推迟项: ProxyPolicy 实装
- 理由分类: 认知未闭合 (J3 默认值待 Round 7+ 冻结)
- 触发条件: Phase_v2_4 启动 + J3 默认值确认
- 验证标准: TC-09-U-48 之外新增 ProxyPolicy.Apply 走 CDP Network.setProxy
Package browser — IdentityRegistry: identity 三元组解析与归一化 [v2 Phase_v2_1]
来源:
- CAP-BS09-C4 §2.bis (IdentityRegistry interface 契约)
- T5-BS-09 §0.2 + BP §V2.C.1 (Phase_v2_1 必须实现)
范围 (Phase_v2_1):
- 接口 + 内存实现 (sync.Map 后备 store).
- Resolve / Inspect / List 三方法.
- 不做 Pool 集成 (Phase_v2_2 才把 IdentityKey 传给 BrowserPool.AcquireTab).
推迟标记:
- 推迟项: 持久化 (跨进程 IdentityRegistry 共享).
- 理由分类: 技术依赖 — 需要 BS-09 Pool 重构后才能确定持久化粒度.
- 触发条件: Phase_v2_2 启动 + Pool snapshot 持久化协议确认.
- 验证标准: TC-09-I-50 (重启后 Pool 状态恢复 + IdentityKey 同前一致).
Package browser — observability: STG constants, package logger, metrics, ValidateDeps. [T5-BS-09, pkg/obs, IR-01: zero deepwork context dependency]
Package browser — BrowserPool: identity-keyed Chrome 实例池 [v2 Phase_v2_2]
设计依据:
- r1/r2: TH-0405-k8r (8 轮碰撞, 14 DDC, 10 要点冻结) — 单 Chrome 多 Tab
- v2: TH-0419-w3p MERGED — identity-keyed 多 Chrome 多 Tab
核心架构 (v2 Phase_v2_2):
- 每个 IdentityKey 对应独立 chromePoolEntry (含独立 allocCtx + profileDir + chromePath)
- 每个 entry 内多 Tab (chromedp NewContext per consumer)
- lazy init: 首次该 IdentityKey 的 AcquireTab 时启动对应 Chrome
- graceful shutdown: 通过 GracefulShutdown 接口暴露 (Phase_v2_2 内部仍 SIGTERM-only, 双阶段 bounded wait + SIGKILL fallback 由 Phase_v2_4 实装 — 接口已 final)
- 孤儿清理: 启动时删除旧 SingletonLock
- maxTabs 保护: 防 OOM (全局上限, 跨 entry 计数)
- 跨平台 dataDir: {dataDir}/browser-data/profiles/{profile}/{preset-vN}/
Caller 复用语义 (v2):
- 旧 r1/r2 LegacyAcquireTab(purpose) 已删除. 上层调用方 (webui-panel/tool-default 等) 自己缓存 TabHandle 实现"同 caller 同 Tab"语义 (见 webui/browser_routes.go 的 panelHandle, internal/tool/browser_tools.go 的 toolTabHandle).
- SwitchProfile/UpdateViewport — 对 default identity entry 操作 (UpdateViewport 通过 handle.WorkspaceID == "webui-panel" 反查 panel Tab).
CAP 锚点: CAP-BS09-C4 §2.bis (BrowserPool interface) + §3.5/§3.6 + T5 §0.1, §0.3
Package browser — startup recovery: 启动期 Chrome profile 健康检查 [v2 Phase_v2_4]
来源:
- CAP-BS09-C4 §3.5 (启动期 Recovery 4 步协议)
- BP-BS-09 §V2.D (Phase_v2_4 实施范围)
协议 (4 步, 在 startChromeLocked 启动 Chrome 之前执行):
- Singleton lock 残留检测: 解析 SingletonLock symlink 拿 PID; PID 已死 → 删除残留; PID 仍活 → 强杀 (orphan, 上次崩溃未清理)
- profile health check: stat user-data-dir/Cookies + 校验 SQLite header (前 16 字节)
- 损坏 → 整体重命名为 user-data-dir.broken/{timestamp}/ (隔离不污染下次) ProfileManager 会在下次自动重建 (空 profile_dir → Chrome 首次启动行为)
- 返回 nil (健康) 或 error (隔离/清理失败)
不在范围:
- .dw-pid 文件机制 — chromedp 不暴露 Chrome 进程 PID; 当前用 SingletonLock 反查代替
- ProfileManager.Repair — 隔离后重建逻辑由 Pool 自然 lazy launch 接管
audit 事件 (log only, 与 GracefulShutdown 风格对齐):
- "startup_recovery_lock_cleaned" — Singleton 残留已删除
- "startup_recovery_orphan_killed" — orphan Chrome 强杀
- "startup_recovery_quarantined" — profile 损坏隔离
Package browser — startup recovery 平台 dispatch (Unix: macOS / Linux / *BSD).
用 syscall.Kill(pid, signal) 实现:
- signal 0 → 仅校验 PID 是否合法 (kill -0 语义)
- SIGTERM / SIGKILL → 双阶段终止
Package browser — TabIndex: Tab 四元身份注册表 [v2 Phase_v2_2]
来源:
- CAP-BS09-C4 §2.bis (TabHandle / TabRole / PoolSnapshot 类型契约)
- T5-BS-09 §0.3 (Tab 四元身份: TargetID, IdentityKey, WorkspaceID, Role)
- BP-BS-09 §V2.B.2 + §V2.E Phase_v2_2 (TabIndex 新增)
范围 (Phase_v2_2):
- TabHandle 类型 + 4 Role 枚举 (CAP §2.bis lines 127-150)
- TabIndex 接口 + 内存实现: Register / Lookup / Unregister / ByIdentity / ByWorkspace
- PoolSnapshot / IdentityPoolStatus 类型 (CAP §2.bis lines 143-150)
不在范围:
- Pool 主流程集成由 pool.go 完成 (本文件仅提供索引数据结构)
- first-claim-wins 协调逻辑在 input_gateway.go (Phase_v2_3+, J4 默认值)
设计说明:
- TabIndex 是 BrowserPool 内部依赖, 不直接暴露给业务调用方.
- 业务调用方拿到 *TabHandle 后通过 TargetID 反查 (Pool.Inspect / Pool.ReleaseTab).
- "唯一性"约束: 同 TargetID 不可重复 Register (TC-09-U-43 守护).
关于 BrowserCore 句柄:
- Phase_v2_2: TabHandle 暂不携带 BrowserCore 引用 (CAP §2.bis 字段集 final).
- Pool 内部维护并行 map[TargetID]BrowserCore (通过 BrowserPool.GetCore(targetID) 暴露) (Phase_v2_3 4 入口迁移完成后, BrowserCore 句柄会从业务消失 — 走 SessionCore 模型).
Package browser — Workspace: Cross-Platform Isolated Workspace abstraction.
Phase 0 (terminal architecture v7) — refined 2026-04-19 (TH-0419): Workspace is the SSOT for **visible** Chrome launches. Headless Chrome callers do NOT go through Workspace (no NSWindow → no Space binding to manage). Mode-conditional split lives at every caller.
Strategy (DDC-I-21, BRR-12, TH-0418-c9x PoC verified 2026-04-19):
- macOS: own-process SLSManagedDisplaySetCurrentSpace switch (SIP-safe). The cross-process SLSMoveWindowsToManagedSpace is silent no-op under SIP; instead we switch view → fork Chrome (it inherits current Space) → wait window committed → switch back.
- Linux: Xvfb already isolates; LaunchChromeInSpace just exec's Chrome (Chrome inherits DISPLAY=:99 from parent process env).
- Windows: stub — direct exec (TODO: IVirtualDesktopManager COM bridge).
Lifecycle: ChromeHandle owns the spawned process. Caller attaches via chromedp.NewRemoteAllocator(ctx, h.WSURL()). Caller MUST call h.Kill() (or rely on process-exit) for explicit teardown — chromedp.Cancel only closes the CDP session, not the process (RemoteAllocator does not own the fork).
[Ref: DDC-I-11, DDC-I-21, BRR-12, BRR-MODE-1]
Package browser — Linux Workspace (no-op: Xvfb provides isolation).
On Linux, display isolation is already achieved by running Chrome inside an Xvfb virtual display (managed by DisplayManager.ensureDisplayLinux). The Workspace abstraction is a no-op on Linux — Xvfb IS the isolated workspace.
[Ref: DDC-I-11 — Linux Xvfb / macOS Spaces are isomorphic Isolated Workspace primitives] [Ref: Iron Rule — Linux display_manager.go::ensureDisplayLinux() MUST NOT be modified]
Index ¶
- Constants
- Variables
- func ApplyDetachedProcAttr(cmd *exec.Cmd)
- func BrowserMuxHostIDFromBrowserSessionID(browserSessionID string) string
- func BrowserMuxHostLogPath(hostID string) string
- func BrowserMuxHostManifestPath(hostID string) string
- func BrowserMuxHostRootDir() string
- func BrowserMuxHostRuntimeDir(hostID string) string
- func BrowserPoolProfileDir(dataDir, profileID, presetID string) string
- func BrowserRuntimeIDFromBrowserSessionID(browserSessionID string) string
- func BrowserRuntimeManifestPath(runtimeID string) string
- func BrowserSessionIDFromPoolIdentity(identityKey IdentityKey) string
- func BrowserSessionIDFromSessionID(sessionID string) string
- func BuildDetachedChromeArgs(opts DetachedChromeLaunchOptions) []string
- func DefaultPresetID() string
- func DefaultProfileID() string
- func DeleteSession(sessionID string) error
- func ExecAllocatorOptionsFromArgs(chromePath string, args []string) []chromedp.ExecAllocatorOption
- func ExtractDevToolsTargetID(target map[string]interface{}) string
- func ExtractDevToolsTargetURL(target map[string]interface{}) string
- func FetchChromeTargets(port int) ([]map[string]interface{}, error)
- func FindFreePort() (int, error)
- func GenerateStealthScript(p *FingerprintPreset) string
- func GetCDPVersion(port int) (*cdpVersionResponse, error)
- func GlobalBrowserMuxHostID() string
- func InjectCookiesDirectCDP(ctx context.Context, cookies []*network.CookieParam) error
- func IsBlankTargetURL(raw string) bool
- func IsChromeInitialPageURL(raw string) bool
- func IsDevToolsPageTarget(target map[string]interface{}) bool
- func IsUserPageTargetURL(raw string) bool
- func IsValidRole(r TabRole) bool
- func LegacyBrowserMuxHostIDFromBrowserSessionID(browserSessionID string) string
- func NewBrowserMuxHostID(browserSessionID string, pid int) string
- func NewBrowserRunID(browserSessionID string, chromePID int) string
- func NewChromeLauncher() *chromeLauncherImpl
- func NewChromeSupervisor() *chromeSupervisorImpl
- func NewCookieImporter(bc BrowserCore) *cookieImporter
- func NormalizePresetID(presetID string) string
- func NormalizeProfileID(id string) string
- func NormalizeSessionInfo(info *SessionInfo)
- func NormalizeTargetCreateURL(raw string) string
- func PrepareProfileForControlledLaunch(profileDir string) error
- func RecoverBrowserRuntimeState(dataDir string) error
- func RemoveProfileOwnerMarker(profileDir string, identityKey IdentityKey)
- func ResolveSessionTarget(session *SessionInfo) (string, error)
- func RunStartupRecovery(profileDir string, identityKey IdentityKey) error
- func SaveSession(info *SessionInfo) error
- func ServeBrowserMuxHost(ctx context.Context, req BrowserMuxHostRequest) error
- func URLOrigin(rawURL string) string
- func URLsEquivalent(a, b string) bool
- func ValidateCoreImpl(snapshotEng *snapshotEngine, liveEng *liveViewEngine)
- func ValidatePoolConfig(cfg PoolConfig)
- func ValidatePresetID(presetID string) (string, error)
- func WaitForChromeReady(port int, timeout time.Duration) (string, error)
- func WriteProfileOwnerMarker(profileDir string, identityKey IdentityKey, chromePID, cdpPort int) error
- func WriteProfileOwnerMarkerWithMetadata(profileDir string, identityKey IdentityKey, chromePID, cdpPort int, ...) error
- type AcquireTabRequest
- type ActionResult
- type AgentState
- type Box
- type BrowserCore
- type BrowserEngine
- type BrowserMode
- type BrowserMuxHostRequest
- type BrowserMuxHostState
- func BrowserMuxHostHealth(ctx context.Context, state *BrowserMuxHostState) (*BrowserMuxHostState, error)
- func EnsureBrowserMuxHost(ctx context.Context, req BrowserMuxHostRequest) (*BrowserMuxHostState, error)
- func LoadBrowserMuxHostState(hostID string) (*BrowserMuxHostState, error)
- func LoadBrowserRuntimeState(runtimeID string) (*BrowserMuxHostState, error)
- func ReleaseBrowserMuxHost(ctx context.Context, state *BrowserMuxHostState) (*BrowserMuxHostState, error)
- func ShutdownBrowserMuxHost(ctx context.Context, state *BrowserMuxHostState) (*BrowserMuxHostState, error)
- func TouchBrowserMuxHost(ctx context.Context, state *BrowserMuxHostState, ownerPID int) (*BrowserMuxHostState, error)
- type BrowserOption
- type BrowserPool
- func (p *BrowserPool) AcquireTab(ctx context.Context, req AcquireTabRequest) (*TabHandle, error)
- func (p *BrowserPool) DataDir() string
- func (p *BrowserPool) DefaultIdentity() IdentityKey
- func (p *BrowserPool) GetCore(targetID string) (BrowserCore, bool)
- func (p *BrowserPool) GetPresetID() string
- func (p *BrowserPool) GetProfileID() string
- func (p *BrowserPool) GracefulShutdown(ctx context.Context) error
- func (p *BrowserPool) Inspect() PoolSnapshot
- func (p *BrowserPool) IsStarted() bool
- func (p *BrowserPool) Registry() IdentityRegistry
- func (p *BrowserPool) ReleaseTab(ctx context.Context, targetID string) error
- func (p *BrowserPool) ResetDefaultIdentity(reason string) bool
- func (p *BrowserPool) ResetIdentity(identityKey IdentityKey, reason string) bool
- func (p *BrowserPool) ResolveProfileIdentity(profileID string) (IdentityKey, error)
- func (p *BrowserPool) Shutdown(ctx context.Context)
- func (p *BrowserPool) SwitchProfile(ctx context.Context, profileID string) (restarted bool, err error)
- func (p *BrowserPool) UpdateViewport(ctx context.Context, width, height int, dpr float64, mobile, touch bool, ...) error
- func (p *BrowserPool) UpdateViewportForIdentity(ctx context.Context, identityKey IdentityKey, workspaceID string, ...) error
- type BrowserRuntimeSummary
- type BrowserSession
- type BrowserSessionDefaults
- type BrowserSessionHandle
- type BrowserSessionKind
- type CDPConfig
- type CDPContextProvider
- type CDPManager
- func (m *CDPManager) Connect(ctx context.Context) error
- func (m *CDPManager) Disconnect() error
- func (m *CDPManager) GetAllPages() ([]*CompatPage, error)
- func (m *CDPManager) GetCurrentPage() (*CompatPage, error)
- func (m *CDPManager) IsConnected() bool
- func (m *CDPManager) Navigate(ctx context.Context, pageID, url string) error
- func (m *CDPManager) NewPage(ctx context.Context, url string) (*CompatPage, string, error)
- type CanonicalFilter
- type ChromeHandle
- type ChromeLaunchSpec
- type CompatPage
- type CompatTargetInfo
- type CookieImportResult
- type CoreFactoryRequest
- type CursorDetector
- type DetachedChromeLaunchOptions
- type DisplayManager
- type ElementRef
- type FingerprintPreset
- type FrameBroadcastHub
- type HUDConfig
- type HUDRenderer
- type HumanOverride
- type Identity
- type IdentityDescriptor
- type IdentityKey
- type IdentityPoolStatus
- type IdentityRegistry
- type InputAck
- type InputEvent
- type InputGateway
- func (g *InputGateway) GetOnStateChange() func()
- func (g *InputGateway) GetRecordBuffer() *RecordBuffer
- func (g *InputGateway) HandleInput(connID string, msg *InputMessage) *InputAck
- func (g *InputGateway) LeaseExpiry() time.Time
- func (g *InputGateway) LeaseToken() string
- func (g *InputGateway) Mode() TakeoverMode
- func (g *InputGateway) OnDisconnect(connID string)
- func (g *InputGateway) OnReconnect(connID string)
- func (g *InputGateway) Owner() string
- func (g *InputGateway) ReleaseTakeover(connID string) error
- func (g *InputGateway) RequestTakeover(connID string) (leaseToken string, expiresAt time.Time, err error)
- func (g *InputGateway) SetCDPContext(ctx context.Context)
- func (g *InputGateway) SetCDPContextProvider(fn func() context.Context)
- func (g *InputGateway) SetOnAcceptedInput(fn func(event *InputEvent))
- func (g *InputGateway) SetOnStateChange(fn func())
- func (g *InputGateway) SetRecordBuffer(rb *RecordBuffer)
- type InputMessage
- type IsolationPolicy
- type JavaScriptDialogEvent
- type LiveViewportSyncer
- type MemoryHUDRenderer
- func (r *MemoryHUDRenderer) ClearHighlight() error
- func (r *MemoryHUDRenderer) Close() error
- func (r *MemoryHUDRenderer) GetRippleHistory() []MemoryRippleCall
- func (r *MemoryHUDRenderer) Hide() error
- func (r *MemoryHUDRenderer) Highlight(_ int) error
- func (r *MemoryHUDRenderer) Init(_ context.Context, _ HUDConfig) error
- func (r *MemoryHUDRenderer) Render(nodes []SuperNode) error
- func (r *MemoryHUDRenderer) RenderRipple(x, y int, t RippleType) error
- func (r *MemoryHUDRenderer) SetPosition(_, _, _, _ int) error
- func (r *MemoryHUDRenderer) SetStatus(status string) error
- func (r *MemoryHUDRenderer) Show() error
- type MemoryRippleCall
- type NodeLocator
- type NoopPolicy
- type NoopWorkspace
- type PageTargetSelection
- type ParsedAction
- type ParsedSelector
- type PhantomHUD
- type PoolConfig
- type PoolSnapshot
- type Preset
- type Profile
- type ProfileManager
- func (m *ProfileManager) Create(name string) (*Profile, error)
- func (m *ProfileManager) Delete(id string) error
- func (m *ProfileManager) EnsureDefault() (*Profile, error)
- func (m *ProfileManager) GetOrCreate(id string) (*Profile, error)
- func (m *ProfileManager) InjectStealth(ctx context.Context) error
- func (m *ProfileManager) List() ([]*Profile, error)
- func (m *ProfileManager) Repair(id string) (*Profile, error)
- type ProfileOwnerMetadata
- type RecordBuffer
- func (rb *RecordBuffer) AppendKeyEvent(event *InputEvent)
- func (rb *RecordBuffer) AppendMouseEvent(event *InputEvent)
- func (rb *RecordBuffer) ExportJSON() ([]byte, error)
- func (rb *RecordBuffer) IsRecording() bool
- func (rb *RecordBuffer) SetSnapshotFn(fn func(x, y float64) string)
- func (rb *RecordBuffer) Start(domain, url string)
- func (rb *RecordBuffer) StepCount() int
- func (rb *RecordBuffer) Stop() RecordTrace
- type RecordStep
- type RecordTarget
- type RecordTrace
- type RecordXY
- type Rect
- type RippleType
- type ScreencastFrame
- type SelectorType
- type SessionAuthority
- func (a *SessionAuthority) GetState() SessionState
- func (a *SessionAuthority) Subscribe(connID string) chan *SessionState
- func (a *SessionAuthority) Unsubscribe(connID string, ch chan *SessionState)
- func (a *SessionAuthority) UpdateCursor(cursor string)
- func (a *SessionAuthority) UpdateMode(mode, owner, leaseToken string, leaseExpiry int64)
- func (a *SessionAuthority) UpdateNavigation(url, title string)
- func (a *SessionAuthority) UpdateRecording(recording bool, elapsedMs int64)
- func (a *SessionAuthority) UpdateTargetInfo(url, title string, targetCount int, tabs ...[]TabInfo)
- func (a *SessionAuthority) UpdateViewport(cssW, cssH int)
- type SessionCore
- type SessionInfo
- type SessionRef
- type SessionState
- type SiteDataClearResult
- type SiteDataInfo
- type SnapOptions
- type Snapshot
- type StableKey
- type SuperNode
- type TabHandle
- type TabIndex
- type TabInfo
- type TabRole
- type TakeoverMode
- type TargetTracker
- func (tt *TargetTracker) ActiveTargetID() target.ID
- func (tt *TargetTracker) ActiveTargetRef() (string, context.Context)
- func (tt *TargetTracker) CloseTarget(targetID string) error
- func (tt *TargetTracker) CreateTab(url string) (string, error)
- func (tt *TargetTracker) GetActiveCDPContext() context.Context
- func (tt *TargetTracker) HandleTargetCreated(info *target.Info)
- func (tt *TargetTracker) HandleTargetDestroyed(targetID target.ID)
- func (tt *TargetTracker) HandleTargetInfoChanged(info *target.Info)
- func (tt *TargetTracker) ListTargets() []TabInfo
- func (tt *TargetTracker) RecordUserGesture(event *InputEvent)
- func (tt *TargetTracker) RefreshTargets() error
- func (tt *TargetTracker) SetForegroundGuard(fn func(target.ID, string) error)
- func (tt *TargetTracker) SetLiveEngine(engine *liveViewEngine, hub *FrameBroadcastHub)
- func (tt *TargetTracker) SetOnCDPSwitch(fn func(newCtx context.Context))
- func (tt *TargetTracker) SetOnJavaScriptDialog(fn func(JavaScriptDialogEvent))
- func (tt *TargetTracker) SetOnSwitch(fn func(url, title string, targetCount int))
- func (tt *TargetTracker) SetTargetCloser(fn func(target.ID) error)
- func (tt *TargetTracker) SetupListeners(browserCtx context.Context)
- func (tt *TargetTracker) SwitchToTarget(targetID string) error
- func (tt *TargetTracker) TargetCDPContext(targetID string) context.Context
- func (tt *TargetTracker) TargetCount() int
- func (tt *TargetTracker) UpdateTabInfo(targetID string, url, title string) bool
- type TouchPoint
- type Viewport
- type VirtualDisplayManager
- func (vdm *VirtualDisplayManager) Close() error
- func (vdm *VirtualDisplayManager) CountWindowsOutsideDisplay(pid int) int
- func (vdm *VirtualDisplayManager) DisplayID() uint32
- func (vdm *VirtualDisplayManager) Ensure() error
- func (vdm *VirtualDisplayManager) VerifyChromeContained(pid int, timeout time.Duration) error
- func (vdm *VirtualDisplayManager) WindowPosition() (x, y int)
- func (vdm *VirtualDisplayManager) WindowPositionAt(offset int) (x, y int)
- type VirtualDisplayWindowRescueRecord
- type VirtualDisplayWindowRescueResult
- type Workspace
Constants ¶
const ( PresetWindowsChrome = "windows-chrome" PresetLinuxChrome = "linux-chrome" PresetMacOSChrome = "macos-chrome" PresetAndroidChrome = "android-chrome" PresetMacOSSafariUA = "macos-safari-ua" PresetIPhoneSafariUA = "iphone-safari-ua" )
const ( // STGSessionCreate is the stage for acquiring/creating a browser tab or session. STGSessionCreate = "browser/session/create" STGSessionNavigate = "browser/session/navigate" // STGSessionAction is the stage for Act / ActWithSessionMode calls. STGSessionAction = "browser/session/action" // STGSnapshot is the stage for Snap / SnapWithSessionMode A11y snapshot capture. STGSnapshot = "browser/snapshot" // STGLiveView is the stage for StartLiveView / Screencast frame pipeline. STGLiveView = "browser/liveview" )
const ( // BrowserProfileWorkspace 供所有 Workspace AI session 共用(持久,共享站点登录态)。 BrowserProfileWorkspace = "workspace" // BrowserProfileWebChat 供 Council / WebChat AI 使用(持久,保持 Gemini/ChatGPT 等登录)。 BrowserProfileWebChat = "webchat" )
系统级 Browser Profile 常量 — 三域隔离模型。 Human 浏览(Browser Portal)使用单独的 browser-sidebar-main,由各路由自行维护。
const ( DefaultViewportWidth = 1920 DefaultViewportHeight = 1080 DefaultMaxTabs = 10 // ChromeInitialPageURL is Chrome/CDP's startup sentinel page. It is a // runtime state, not product state: callers must not use it to infer user // intent, session progress, or tab ownership. ChromeInitialPageURL = "about:blank" )
const ( BrowserPoolDefaultIdleTimeout = 5 * time.Minute BrowserPoolShutdownGrace = 5 * time.Second BrowserPoolMaxShutdownGrace = 30 * time.Second BrowserPoolMinReapInterval = 15 * time.Second BrowserPoolReleaseTimeout = 5 * time.Second BrowserPoolChromeWarmup = 15 * time.Second BrowserPoolCDPActionTimeout = 5 * time.Second ProfileOwnerMuxHostKillGrace = 2 * time.Second ProfileOwnerChromeKillGrace = 1 * time.Second ProcessExitPollInterval = 50 * time.Millisecond ChromeReadyPollInterval = 150 * time.Millisecond ChromeVersionRequestTimeout = 2 * time.Second ChromeTargetsRequestTimeout = 3 * time.Second ChromeCDPStartupAttempts = 20 ChromeCDPStartupPollInterval = 500 * time.Millisecond BrowserMuxHostDefaultIdleTTL = 10 * time.Minute BrowserMuxHostReadyTimeout = 45 * time.Second BrowserMuxHostLaunchReadyTimeout = 30 * time.Second BrowserMuxHostControlRequestTimeout = 5 * time.Second BrowserMuxHostShutdownTimeout = 3 * time.Second BrowserMuxHostReadyPollInterval = 250 * time.Millisecond BrowserMuxHostProcessPollInterval = 100 * time.Millisecond BrowserMuxHostHealthPollInterval = 2 * time.Second BrowserMuxHostIdleCheckInterval = 5 * time.Second BrowserMuxHostWindowEnforceTimeout = 10 * time.Second BrowserMuxHostWindowContainmentTimeout = 2500 * time.Millisecond BrowserMuxHostForegroundGuardTimeout = 1500 * time.Millisecond BrowserMuxHostForegroundContainmentCheck = 750 * time.Millisecond BrowserMuxHostSnapshotContainmentCheck = 200 * time.Millisecond VirtualDisplayRegistrationDelay = 1 * time.Second VirtualDisplayContainmentPollInterval = 75 * time.Millisecond )
const ( TargetClaimWindow = 2 * time.Second TargetWindowOpenHintTTL = 2 * time.Second TargetMaxAttributionHints = 8 TargetWarmTimeout = 10 * time.Second TargetPageListenerTimeout = 5 * time.Second TargetActivateTimeout = 2500 * time.Millisecond TargetMaterializeTimeout = 1500 * time.Millisecond TargetDiscoveryTimeout = 8 * time.Second TargetCreateTimeout = 5 * time.Second TargetCreateWaitTimeout = 12 * time.Second TargetCloseLocalWaitTimeout = 1200 * time.Millisecond TargetCloseLocalPollInterval = 25 * time.Millisecond TargetBootstrapCleanupWindow = 5 * time.Second TargetPostActionDiscoveryDelay = 500 * time.Millisecond TargetWindowOpenRefreshDelay = 250 * time.Millisecond DevToolsRequestTimeout = 5 * time.Second )
const ( SessionOwnerAgent = "agent" SessionOwnerHuman = "human" SessionOwnerService = "service" SessionIsolationEphemeral = "ephemeral" SessionIsolationDedicated = "dedicated" SessionIsolationPool = "profile-pool" AuthorityAgentic = "agentic" AuthorityHuman = "human" )
const DefaultGraceTimeout = 5 * time.Second
DefaultGraceTimeout 是断连 grace 超时(5秒),超时前重连可恢复。
const DefaultIdleTimeout = 5 * time.Minute
DefaultIdleTimeout 是默认 idle 超时(5分钟),每次 accepted input 后重置。
const DefaultTakeoverTimeout = 5 * time.Minute
DefaultTakeoverTimeout 是默认接管超时时间(5分钟)[TC-09-L4-10]。
const MinimalWebdriverStealthScript = `` /* 694-byte string literal not displayed */
MinimalWebdriverStealthScript is used only for real headed Chrome (headed/visible modes). In those modes the browser should expose its native WebGL, screen, fonts, canvas, audio, languages, and hardware surfaces. The only automation residue we remove is navigator.webdriver, because some bot tests fail on property presence even when the value is not truthy.
Variables ¶
var ( // ErrBrowserNotFound — 无 Chrome/Edge 安装。 ErrBrowserNotFound = errors.New("browser: no Chrome/Edge found") // ErrBrowserCrashed — Chrome 进程崩溃。 ErrBrowserCrashed = errors.New("browser: Chrome process crashed") // ErrCDPDisconnected — CDP 连接断开。 ErrCDPDisconnected = errors.New("browser: CDP connection lost") // ErrActFailed — 操作执行失败。 ErrActFailed = errors.New("browser: action execution failed") // ErrRefNotFound — Element Ref 不存在。 ErrRefNotFound = errors.New("browser: element ref not found") // ErrTakeoverActive — 接管模式激活,AI 操作被拒绝。 ErrTakeoverActive = errors.New("browser: takeover mode active") // ErrPasswordField — 密码字段需要安全输入,不经 LLM/WS 明文通道处理 [IR-03]。 ErrPasswordField = errors.New("browser: password field requires secure input") // ErrSnapshotEmpty — A11y 快照返回空。 ErrSnapshotEmpty = errors.New("browser: A11y snapshot returned empty") // ErrAmbiguousLocator — 定位器匹配多个元素。 ErrAmbiguousLocator = errors.New("browser: ambiguous locator matches multiple elements") // ErrStaleRef — ref 已失效(页面自上次 snap 后已变化)。 ErrStaleRef = errors.New("browser: ref is stale (page has changed since last snap)") // ErrSessionNotFound — 会话不存在。 ErrSessionNotFound = errors.New("browser: session not found") // ErrInvalidRefInOneShot — @rN ref 在无 session 模式下不可用。 ErrInvalidRefInOneShot = errors.New("browser: @rN refs require --session mode") // ErrSelectorNotFound — CSS 选择器无匹配元素。 ErrSelectorNotFound = errors.New("browser: CSS selector matched no elements") // ErrEvalFailed — JavaScript 求值失败。 ErrEvalFailed = errors.New("browser: JavaScript evaluation failed") // ErrCookieDecryptFailed — Cookie 解密失败(macOS Keychain/Linux SecretService 拒绝)。 ErrCookieDecryptFailed = errors.New("browser: cookie decryption failed") // ErrCookieDBLocked — Cookie 数据库锁定且无法复制。 ErrCookieDBLocked = errors.New("browser: cookie database locked") )
var BuiltinPresets = map[string]*FingerprintPreset{ PresetWindowsChrome: { ID: PresetWindowsChrome, Name: "Windows 11 · Chrome 133", UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", Platform: "Win32", Vendor: "Google Inc.", Languages: "['en-US','en']", WebGLVendor: "Google Inc. (NVIDIA)", WebGLRenderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)", ViewportW: 1920, ViewportH: 1080, DeviceScaleFactor: 1.0, }, PresetLinuxChrome: { ID: PresetLinuxChrome, Name: "Ubuntu 24.04 · Chrome 133", UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", Platform: "Linux x86_64", Vendor: "Google Inc.", Languages: "['en-US','en']", WebGLVendor: "Google Inc. (NVIDIA)", WebGLRenderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 OpenGL ES 3.2, OpenGL 4.6.0)", ViewportW: 1920, ViewportH: 1080, DeviceScaleFactor: 1.0, }, PresetMacOSChrome: { ID: PresetMacOSChrome, Name: "macOS Sequoia · Chrome 133", UserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", Platform: "MacIntel", Vendor: "Google Inc.", Languages: "['en-US','en']", WebGLVendor: "Google Inc. (Apple)", WebGLRenderer: "ANGLE (Apple, ANGLE Metal Renderer: Apple M4 Pro, Unspecified Version)", ViewportW: 1512, ViewportH: 982, DeviceScaleFactor: 2.0, }, PresetAndroidChrome: { ID: PresetAndroidChrome, Name: "Android · Chrome 133", UserAgent: "Mozilla/5.0 (Linux; Android 15; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Mobile Safari/537.36", Platform: "Linux armv8l", Vendor: "Google Inc.", Languages: "['en-US','en']", WebGLVendor: "Google Inc. (Qualcomm)", WebGLRenderer: "ANGLE (Qualcomm, Adreno 750, OpenGL ES 3.2)", ViewportW: 412, ViewportH: 923, DeviceScaleFactor: 2.625, Mobile: true, Touch: true, MaxTouchPoints: 5, }, PresetMacOSSafariUA: { ID: PresetMacOSSafariUA, Name: "macOS Sequoia · Safari UA 模拟", UserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15", Platform: "MacIntel", Vendor: "Apple Computer, Inc.", Languages: "['en-US','en']", WebGLVendor: "Apple", WebGLRenderer: "Apple M4 Pro", ViewportW: 1512, ViewportH: 982, DeviceScaleFactor: 2.0, }, PresetIPhoneSafariUA: { ID: PresetIPhoneSafariUA, Name: "iPhone · Safari UA 模拟", UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Mobile/15E148 Safari/604.1", Platform: "iPhone", Vendor: "Apple Computer, Inc.", Languages: "['en-US','en']", WebGLVendor: "Apple Inc.", WebGLRenderer: "Apple GPU", ViewportW: 430, ViewportH: 932, DeviceScaleFactor: 3.0, Mobile: true, Touch: true, MaxTouchPoints: 5, }, }
BuiltinPresets 内置浏览器指纹预设 (2026-04 主流版本 + 主流硬件)。
Languages 选择: 仅 en-US/en — 中文 IP + Chromium + zh-CN Accept-Language 是 Cloudflare 反爬高危组合 (中国区 ASN 已被标记),反而拉低 Turnstile 通过率。 真实用户可以随时在 Chrome 设置切换语言,fingerprint 层不暴露 zh 即可。
ErrBrowserUnavailable is returned by deprecated stub methods.
var ErrIdentityNotFound = errors.New("identity not found in registry")
ErrIdentityNotFound — Inspect 未命中.
var ErrIdentityUnresolved = errors.New("browser pool: identity not resolved (call IdentityRegistry.Resolve first)")
ErrIdentityUnresolved — AcquireTabRequest.IdentityKey 未在 Registry 注册过.
var ErrInvalidRole = errors.New("browser pool: invalid role (allowed: human/agent/council/background)")
ErrInvalidRole — AcquireTabRequest.Role 不在 4 枚举矩阵 (TC-09-U-41).
var ErrInvalidRoleIdentity = errors.New("browser pool: council role requires council-* profile prefix")
ErrInvalidRoleIdentity — Role=council 但 IdentityKey 对应 Profile 非 council-* 前缀 (TC-09-U-42, P1).
var ErrMaxTabsReached = errors.New("browser pool: max tabs reached")
ErrMaxTabsReached — Tab 总数达上限且无可回收 entry.
var ErrPoolClosed = errors.New("browser pool: closed")
ErrPoolClosed — Pool 已 Shutdown.
var ErrTabAlreadyRegistered = errors.New("tab already registered for TargetID")
ErrTabAlreadyRegistered — Register 重复 TargetID.
var ErrTabNotFound = errors.New("tab not found in index")
ErrTabNotFound — Unregister / Lookup 未命中.
var PresetOrder = []string{ PresetWindowsChrome, PresetLinuxChrome, PresetMacOSChrome, PresetAndroidChrome, PresetMacOSSafariUA, PresetIPhoneSafariUA, }
PresetOrder 前端展示顺序。
var TargetBootstrapCleanupDelays = []time.Duration{ 350 * time.Millisecond, 1500 * time.Millisecond, 3500 * time.Millisecond, }
Functions ¶
func ApplyDetachedProcAttr ¶
ApplyDetachedProcAttr sets Setpgid so the spawned Chrome lives in its own process group. This decouples Chrome's lifetime from the parent process's signal-handling pgrp (important for dw-browser CLI which exits while Chrome must remain).
Exported so dw-browser CLI (headless path) can reuse the same cross-platform helper without re-implementing platform-specific syscall imports.
func BrowserMuxHostIDFromBrowserSessionID ¶
BrowserMuxHostIDFromBrowserSessionID returns the stable host key for a BrowserSession. New BrowserMuxHost manifests use this stable id so Deepwork and CLI clients can reconnect to the same muxhost after a client restart.
func BrowserMuxHostLogPath ¶
func BrowserMuxHostRootDir ¶
func BrowserMuxHostRootDir() string
func BrowserPoolProfileDir ¶
BrowserPoolProfileDir returns the canonical on-disk profile directory used by BrowserPool for a logical profile and preset on the local runtime.
func BrowserSessionIDFromPoolIdentity ¶
func BrowserSessionIDFromPoolIdentity(identityKey IdentityKey) string
BrowserSessionIDFromPoolIdentity returns the stable BrowserSession id used by BrowserPool's legacy interactive coordination path for an identity.
func BrowserSessionIDFromSessionID ¶
BrowserSessionIDFromSessionID keeps old local session files readable while making the public identifier explicit.
func BuildDetachedChromeArgs ¶
func BuildDetachedChromeArgs(opts DetachedChromeLaunchOptions) []string
BuildDetachedChromeArgs 生成 detached Chrome 的启动参数。 设计目标:
- headless/headed/visible 三模式共用同一组生命周期必需参数
- visible 保留本机 Chrome 的真实指纹面,不叠加自动化/CI flags
- headed 使用真实 Chrome + 虚拟显示,并补最小反后台节流参数保证 LiveView 切 tab 稳定
- headless 只在必要处补偿 UA/webdriver,不关闭 GPU/WebGL
func DefaultPresetID ¶
func DefaultPresetID() string
DefaultPresetID 返回当前平台的默认桌面浏览器指纹。 目的: 避免 macOS/Windows 本地调试时仍落回 windows-chrome 的硬编码默认。
func ExecAllocatorOptionsFromArgs ¶
func ExecAllocatorOptionsFromArgs(chromePath string, args []string) []chromedp.ExecAllocatorOption
ExecAllocatorOptionsFromArgs 将 detached Chrome 参数转换为 chromedp ExecAllocatorOption。 设计目标:
- BrowserPool 与 detached dw-browser 复用同一套跨平台 launch args
- 避免两条路径各维护一份 flags,导致 Cloudflare / Turnstile 行为分叉
func ExtractDevToolsTargetID ¶
func FetchChromeTargets ¶
FetchChromeTargets Chrome の /json エンドポイントからターゲット一覧を取得。
func GenerateStealthScript ¶
func GenerateStealthScript(p *FingerprintPreset) string
GenerateStealthScript 根据 Preset 生成定制化 Stealth 脚本。
func GetCDPVersion ¶
GetCDPVersion 查询 CDP /json/version 返回版本信息。
func GlobalBrowserMuxHostID ¶
func GlobalBrowserMuxHostID() string
func InjectCookiesDirectCDP ¶
func InjectCookiesDirectCDP(ctx context.Context, cookies []*network.CookieParam) error
InjectCookiesDirectCDP 通过直接 CDP 协议注入 Cookie(需要 chromedp context)。 此函数供 cookie_importer_cdp.go 中的集成测试调用。
func IsBlankTargetURL ¶
func IsChromeInitialPageURL ¶
func IsDevToolsPageTarget ¶
func IsUserPageTargetURL ¶
func NewBrowserMuxHostID ¶
func NewBrowserRunID ¶
func NewChromeLauncher ¶
func NewChromeLauncher() *chromeLauncherImpl
NewChromeLauncher 返回默认 ChromeLauncher 实现。
func NewChromeSupervisor ¶
func NewChromeSupervisor() *chromeSupervisorImpl
NewChromeSupervisor 返回默认 ChromeSupervisor 实现。
func NewCookieImporter ¶
func NewCookieImporter(bc BrowserCore) *cookieImporter
NewCookieImporter 创建 CookieImporter 实例。 bc 用于通过 CDP 注入 Cookie(Network.setCookies)。
func NormalizePresetID ¶
NormalizePresetID 只处理空值与空白。 未知 ID 会原样返回,必须由 ValidatePresetID 或调用方报错,避免旧契约静默回退。
func NormalizeProfileID ¶
NormalizeProfileID 规范化逻辑 profile ID。 允许用户直接输入显示名,最终转换为稳定的 ASCII slug。
func NormalizeSessionInfo ¶
func NormalizeSessionInfo(info *SessionInfo)
NormalizeSessionInfo backfills the r8 BrowserSession contract on session files loaded from older dw-browser builds.
func PrepareProfileForControlledLaunch ¶
PrepareProfileForControlledLaunch removes Chrome session-restore artifacts without touching cookies, local storage, IndexedDB, passwords, or permissions.
This matters for invisible headed mode: a restored Chrome window can ignore the requested --window-position and briefly appear on the Human's main Space.
func RecoverBrowserRuntimeState ¶
RecoverBrowserRuntimeState performs a startup-wide owner-marker sweep for all BrowserPool profile directories under dataDir. It is intentionally separate from RunStartupRecovery: the app calls this at process startup, before any Browser Portal is opened, so a SIGKILLed BrowserMuxHost cannot leave headed Chrome visible on the user's primary Space until the next lazy acquire.
func RemoveProfileOwnerMarker ¶
func RemoveProfileOwnerMarker(profileDir string, identityKey IdentityKey)
func ResolveSessionTarget ¶
func ResolveSessionTarget(session *SessionInfo) (string, error)
ResolveSessionTarget 解析有效的 target ID。 快速路径: 存储的 target_id 仍有效 → 直接返回。 恢复路径: target 不存在 → 查询 Chrome /json → 选最佳 page target → 更新 session 文件。
func RunStartupRecovery ¶
func RunStartupRecovery(profileDir string, identityKey IdentityKey) error
RunStartupRecovery 在 Chrome 启动前对 profileDir 做 4 步健康检查 (CAP §3.5).
调用方:
- BrowserPool.startChromeLocked (进程内 service 模式, IdentityKey 来自 Registry)
- dw-browser open (CLI 短命模式, IdentityKey 用 "dw-cli-{sessionID}" 仅作 audit 标签)
返回 nil → profile 可直接启动 Chrome. 返回 err → 上层决定是否致命 (隔离失败应 abort, 清理失败可继续).
identityKey 仅用于 audit log (定位故障 Chrome 实例).
func ServeBrowserMuxHost ¶
func ServeBrowserMuxHost(ctx context.Context, req BrowserMuxHostRequest) error
func URLsEquivalent ¶
func ValidateCoreImpl ¶
func ValidateCoreImpl(snapshotEng *snapshotEngine, liveEng *liveViewEngine)
ValidateCoreImpl panics if a BrowserCoreImpl's essential internal engines are nil. Pass the concrete impl fields; call after construction before serving operations.
func ValidatePoolConfig ¶
func ValidatePoolConfig(cfg PoolConfig)
ValidatePoolConfig panics if the BrowserPool configuration violates required invariants. Call in NewBrowserPool after field defaults are applied.
func ValidatePresetID ¶
ValidatePresetID 返回已知 preset;未知值必须显式失败。
func WaitForChromeReady ¶
WaitForChromeReady Chrome の CDP エンドポイントが準備完了するまでポーリング。 成功時に WebSocket URL を返す。
func WriteProfileOwnerMarker ¶
func WriteProfileOwnerMarker(profileDir string, identityKey IdentityKey, chromePID, cdpPort int) error
func WriteProfileOwnerMarkerWithMetadata ¶
func WriteProfileOwnerMarkerWithMetadata(profileDir string, identityKey IdentityKey, chromePID, cdpPort int, meta ProfileOwnerMetadata) error
Types ¶
type AcquireTabRequest ¶
type AcquireTabRequest struct {
IdentityKey IdentityKey // 来自 IdentityRegistry.Resolve, 必填; 不允许字符串拼装
WorkspaceID string // 任务隔离维度 (T5 §0.3, 不影响 Chrome 资源边界)
Role TabRole // 4 枚举之一; 不在矩阵 → ErrInvalidRole
InitialURL string // 可选, 创建 Tab 时直接 navigate (Phase_v2_2 暂不实装 navigate)
Ephemeral bool // true → 复用 ephemeral profile (dw-browser --ephemeral)
Mode BrowserMode // 可选; 空值使用 PoolConfig.Mode. BS-15 Fast runtime 用 headless.
// BrowserSession contract passthrough. These fields let service callers
// preserve their owner contract when BrowserPool coordinates a headed
// BrowserMuxHost. Empty values keep the legacy interactive pool defaults.
BrowserSessionID string
SessionKind BrowserSessionKind
Goal string
Owner string
Isolation string
ServiceName string
AccountID string
}
AcquireTabRequest — BrowserPool.AcquireTab 入参 (CAP §2.bis lines 119-125).
type ActionResult ¶
ActionResult is a deprecated result type from the old browser package. Kept for backward compatibility.
type AgentState ¶
type AgentState string
AgentState represents the visual state of the agent in the HUD. Deprecated.
const ( // AgentStateThinking indicates the agent is thinking. AgentStateThinking AgentState = "thinking" // AgentStateActing indicates the agent is acting. AgentStateActing AgentState = "acting" )
type Box ¶
Box represents a bounding box for an element. Deprecated: kept for compat with internal/desktop.
type BrowserCore ¶
type BrowserCore interface {
Navigate(ctx context.Context, url string) (*Snapshot, error)
// Snap 获取当前页面 A11y 快照(不导航)。
Snap(ctx context.Context) (*Snapshot, error)
// Act 执行操作,返回操作后快照。
// action 语法: "click e3" | "type e5 'hello'" | "scroll down" | "hover e7" | "select e4 'opt2'"
// observe=false 时不返回 snap(连续操作优化)[D.2-C2]。
Act(ctx context.Context, action string, observe bool) (*Snapshot, error)
// Text 提取当前页面纯文本(~500-800 tok,focus 为可选 ref 或 CSS selector)。
Text(ctx context.Context, focus *string) (string, error)
// Screenshot 截图,annotate=true 时叠加 Element Ref 标注。
Screenshot(ctx context.Context, annotate bool) ([]byte, error)
// StartLiveView 启动 Screencast 帧推送,返回 FrameBroadcastHub。
// 多次调用安全:已活跃时返回同一 hub,不重启 Screencast。
// WS handler 通过 hub.Subscribe(connID) 获取独立帧 channel [CAP-BS09-C3 r2]。
StartLiveView(ctx context.Context) (*FrameBroadcastHub, error)
// StopLiveView 停止 Screencast。
StopLiveView(ctx context.Context) error
// EnableTakeover 切换到 Takeover 模式(Human 接管)。
EnableTakeover(ctx context.Context) error
// DisableTakeover 释放 Takeover,恢复 OBSERVE 模式。
DisableTakeover(ctx context.Context) error
// DispatchInput 在接管模式下转发输入事件。
DispatchInput(ctx context.Context, event *InputEvent) error
// Close 关闭 Browser,释放资源。
Close(ctx context.Context) error
// EvalJS 在当前活跃标签上执行 JavaScript 表达式,结果写入 result 指针。
// 活跃标签由 TargetTracker 决定: 有新标签(如 target=_blank)时在新标签执行,
// 否则在主标签(browserCtx)执行。[BUG-FIX + TH-0414-b3m]
EvalJS(ctx context.Context, expr string, result interface{}) error
// GetTargetTracker 返回 TargetTracker(多 Target 自动跟随)[r3]。
// 返回 nil 表示不支持(如 session 模式)。
GetTargetTracker() *TargetTracker
}
BrowserCore — internal/browser/ 对外服务接口(Core 层,零 Deepwork 依赖)。
func NewBrowserCore ¶
func NewBrowserCore(ctx context.Context, profileID string, optFns ...BrowserOption) (BrowserCore, error)
NewBrowserCore 创建并初始化 BrowserCore 实例。 optFns 为可选参数: WithViewport / WithUserAgent / WithTouchEmulation / WithMode。
该 one-shot 入口必须与 BrowserPool 使用同一套三模式启动语义。所有 mode 都 先用 BuildDetachedChromeArgs fork 本机 Chrome,再通过 RemoteAllocator attach, 避免 CLI/测试入口绕过 CGVirtualDisplay/Workspace。
type BrowserEngine ¶
type BrowserEngine string
BrowserEngine 标识浏览器引擎类型。
const ( EngineChrome BrowserEngine = "chrome" EngineSafari BrowserEngine = "safari" )
func NormalizeEngine ¶
func NormalizeEngine(e BrowserEngine) BrowserEngine
NormalizeEngine 标准化引擎名称。空值和未知值默认为 Chrome。
type BrowserMode ¶
type BrowserMode string
BrowserMode 定义浏览器运行模式 [TH-0414-b3m]。
const ( // ModeHeadless 极速模式:Chrome --headless=new,零 display 依赖。 ModeHeadless BrowserMode = "headless" // ModeHeaded 标准模式:真实 headed Chrome + 平台虚拟显示器,对 Human 不可见。 ModeHeaded BrowserMode = "headed" // ModeVisible 可见模式:真实 headed Chrome 显示到用户可见工作区。 ModeVisible BrowserMode = "visible" // Deprecated compatibility aliases. BrowserModeHeadless BrowserMode = ModeHeadless BrowserModeHuman BrowserMode = "human" )
func NormalizeBrowserMode ¶
func NormalizeBrowserMode(mode BrowserMode, fallback BrowserMode) BrowserMode
type BrowserMuxHostRequest ¶
type BrowserMuxHostRequest struct {
BrowserSessionID string
SessionKind BrowserSessionKind
MuxHostID string
RuntimeID string
MuxHostBinary string
IdentityKey IdentityKey
OwnerPID int
Goal string
Owner string
Isolation string
ServiceName string
AccountID string
ChromePath string
ProfileID string
ProfileDir string
DebugPort int
Mode BrowserMode
PresetID string
Width int
Height int
UserAgent string
Touch bool
IdleTTL time.Duration
}
BrowserMuxHostRequest describes the runtime that should own Chrome and its display server. It is intentionally free of Deepwork product vocabulary so dw-browser can remain a general AOT/HTR runtime.
type BrowserMuxHostState ¶
type BrowserMuxHostState struct {
MuxHostID string `json:"browser_mux_host_id"`
MuxHostPID int `json:"browser_mux_host_pid"`
ControlURL string `json:"control_url"`
Token string `json:"token,omitempty"`
RuntimeID string `json:"runtime_id,omitempty"`
RuntimeCount int `json:"runtime_count,omitempty"`
Runtimes []BrowserRuntimeSummary `json:"runtimes,omitempty"`
BrowserSessionID string `json:"browser_session_id"`
SessionKind BrowserSessionKind `json:"session_kind,omitempty"`
Goal string `json:"goal,omitempty"`
Owner string `json:"owner,omitempty"`
OwnerPID int `json:"owner_pid,omitempty"`
Isolation string `json:"isolation,omitempty"`
ServiceName string `json:"service,omitempty"`
AccountID string `json:"account_id,omitempty"`
ProfileID string `json:"profile_id"`
ProfileDir string `json:"profile_dir"`
BrowserPID int `json:"browser_pid,omitempty"`
ChromePID int `json:"chrome_pid"`
WSURL string `json:"ws_url"`
DebugPort int `json:"debug_port"`
Mode BrowserMode `json:"mode"`
PresetID string `json:"preset_id,omitempty"`
ViewportW int `json:"viewport_w"`
ViewportH int `json:"viewport_h"`
UserAgent string `json:"user_agent,omitempty"`
Touch bool `json:"touch,omitempty"`
BrowserRunID string `json:"browser_run_id"`
DisplayBackend string `json:"display_backend"`
DisplayID uint32 `json:"display_id,omitempty"`
DisplayVerified bool `json:"display_verified"`
ChromeWindowContained bool `json:"chrome_window_contained"`
StartedAt string `json:"started_at"`
LastTouchedAt string `json:"last_touched_at"`
IdleTTLMillis int64 `json:"idle_ttl_ms"`
MuxHostAlive bool `json:"browser_mux_host_alive"`
ChromeAlive bool `json:"chrome_alive"`
ReusedExisting bool `json:"-"`
}
BrowserMuxHostState is the on-disk manifest and loopback API response for a BrowserMuxHost. It is the attach contract used by Deepwork, dw-browser CLI, and service adapters.
func BrowserMuxHostHealth ¶
func BrowserMuxHostHealth(ctx context.Context, state *BrowserMuxHostState) (*BrowserMuxHostState, error)
func EnsureBrowserMuxHost ¶
func EnsureBrowserMuxHost(ctx context.Context, req BrowserMuxHostRequest) (*BrowserMuxHostState, error)
func LoadBrowserMuxHostState ¶
func LoadBrowserMuxHostState(hostID string) (*BrowserMuxHostState, error)
func LoadBrowserRuntimeState ¶
func LoadBrowserRuntimeState(runtimeID string) (*BrowserMuxHostState, error)
func ReleaseBrowserMuxHost ¶
func ReleaseBrowserMuxHost(ctx context.Context, state *BrowserMuxHostState) (*BrowserMuxHostState, error)
func ShutdownBrowserMuxHost ¶
func ShutdownBrowserMuxHost(ctx context.Context, state *BrowserMuxHostState) (*BrowserMuxHostState, error)
func TouchBrowserMuxHost ¶
func TouchBrowserMuxHost(ctx context.Context, state *BrowserMuxHostState, ownerPID int) (*BrowserMuxHostState, error)
type BrowserOption ¶
type BrowserOption func(*browserOptions)
BrowserOption 是可选参数函数类型。
func WithFingerprintPreset ¶
func WithFingerprintPreset(presetID string) BrowserOption
WithFingerprintPreset 设置运行时指纹 preset。 dw-browser 的 device/UA 模拟必须同时驱动启动参数与 JS/runtime 指纹。
func WithMode ¶
func WithMode(mode BrowserMode) BrowserOption
WithMode 设置浏览器模式。默认 headless(CLI/测试场景)。
func WithTouchEmulation ¶
func WithTouchEmulation(enabled bool) BrowserOption
WithTouchEmulation 设置触控模拟(Mobile 设备预设使用)。
type BrowserPool ¶
type BrowserPool struct {
// contains filtered or unexported fields
}
BrowserPool — identity-keyed Chrome 实例池 (实现 CAP §2.bis BrowserPool interface).
func NewBrowserPool ¶
func NewBrowserPool(config PoolConfig) *BrowserPool
NewBrowserPool 创建 BrowserPool (不启动 Chrome — lazy init).
func (*BrowserPool) AcquireTab ¶
func (p *BrowserPool) AcquireTab(ctx context.Context, req AcquireTabRequest) (*TabHandle, error)
AcquireTab 获取或创建一个 Tab (CAP §2.bis lines 99-102).
不变式:
- 同 IdentityKey 多次 AcquireTab 复用同一 Chrome 实例 (TC-09-U-40, TC-09-I-47).
- 不同 IdentityKey 的 AcquireTab 启动独立 Chrome 实例 (TC-09-U-40 反向断言).
- Role 不在 4 枚举 → ErrInvalidRole + 不启动 Chrome (TC-09-U-41).
- Role=council 但 IdentityKey 对应 Profile 非 council-* 前缀 → ErrInvalidRoleIdentity (TC-09-U-42, P1).
- lazy launch: IdentityKey 未见过 → 调 ChromeLauncher + ProfileManager + IsolationPolicy.Apply (TC-09-I-48).
校验顺序:
- p.closed → ErrPoolClosed
- !IsValidRole → ErrInvalidRole (无副作用)
- registry.Inspect → ErrIdentityUnresolved (上层必先 Resolve)
- council role + 非 council-* profile → ErrInvalidRoleIdentity
- tab 上限检查 (跨 entry 总和)
- lazy launch + Tab 创建
- TabIndex.Register
返回值: TabHandle 副本 (调用方持有, 通过 TargetID 反向 ReleaseTab).
func (*BrowserPool) DataDir ¶
func (p *BrowserPool) DataDir() string
DataDir 返回 BrowserPool 绑定的 deepwork dataDir (legacy).
func (*BrowserPool) DefaultIdentity ¶
func (p *BrowserPool) DefaultIdentity() IdentityKey
DefaultIdentity 返回 Pool 在 NewBrowserPool 时由 PoolConfig.Profile/Preset + NoopPolicy 预解析的默认 IdentityKey. 上层调用方 (webui-panel / tool-default) 没有特定 identity 需求时 用此默认值, 保证与 PoolConfig 配置语义一致.
func (*BrowserPool) GetCore ¶
func (p *BrowserPool) GetCore(targetID string) (BrowserCore, bool)
GetCore 返回指定 TargetID 对应的 BrowserCore (AcquireTab 之后取操作句柄).
设计: AcquireTab 只返回 *TabHandle (CAP §2.bis 冻结签名); 上层执行浏览器动作需要 BrowserCore. GetCore 把 TargetID → BrowserCore 反查暴露给调用方, 不引入新所有权.
返回 (nil, false) 当 TargetID 未在 TabIndex / entry.tabs 中找到 (Tab 已被 Release/Evict).
func (*BrowserPool) GetPresetID ¶
func (p *BrowserPool) GetPresetID() string
GetPresetID 返回当前默认 Preset ID (legacy).
func (*BrowserPool) GetProfileID ¶
func (p *BrowserPool) GetProfileID() string
GetProfileID 返回当前默认 Profile ID (legacy).
func (*BrowserPool) GracefulShutdown ¶
func (p *BrowserPool) GracefulShutdown(ctx context.Context) error
GracefulShutdown 双阶段退出 (CAP §2.bis lines 109-113 + §3.5) [Phase_v2_4].
协议 (per entry):
- cancel 所有 tab context (释放 chromedp 资源)
- cancel browserCtx 异步触发 Chrome graceful close (Browser.close → flush cookie/storage)
- bounded wait (default 5s, env BS09_SHUTDOWN_GRACE_SEC, max 30s): - chromedp.Cancel 在 goroutine 中执行 graceful Browser.close + 等待清理 - 超时 → cancel allocCtx (chromedp 内部 SIGKILL fallback) + audit event
- 清理 entry 状态
audit event (CAP §3.5): wait 超时 → log "BROWSER-POOL/v2 AUDIT: chrome_killed_after_grace" 包含 identity + grace_sec, 便于运维定位 stuck Chrome.
注: 单 mutex 持有期间为所有 entry 串行执行 bounded wait. N 个 identity → 最多 N*grace 串行. 实际生产 N 通常 ≤2 (default + council), 串行 10s 上限可接受.
func (*BrowserPool) Inspect ¶
func (p *BrowserPool) Inspect() PoolSnapshot
Inspect 返回 Pool 当前状态快照 (CAP §2.bis lines 116-117).
Identities 按 IdentityKey 字典序; 每 identity 内 Tabs 按 TargetID 字典序. ChromePID 当前由 Pool 反查 entry.allocCtx 推断 (Phase_v2_2 简化为 entry.started ? -1 : 0, 真实 PID 提取由 Phase_v2_4 双阶段退出实装时引入 process tracking).
func (*BrowserPool) IsStarted ¶
func (p *BrowserPool) IsStarted() bool
IsStarted 返回 default identity 的 Chrome 是否已启动.
func (*BrowserPool) Registry ¶
func (p *BrowserPool) Registry() IdentityRegistry
Registry 返回 Pool 内置的 IdentityRegistry (供上层 Resolve 后传入 AcquireTab).
设计: Pool 内部和外部共享同一 registry, 避免上层用独立 registry 导致 IdentityKey 来源 不一致 (registry.Inspect 反查会失败).
func (*BrowserPool) ReleaseTab ¶
func (p *BrowserPool) ReleaseTab(ctx context.Context, targetID string) error
ReleaseTab 释放指定 TargetID 的 Tab (CAP §2.bis lines 105-107).
不立即关闭 Chrome — 由 Pool 自身决定 idle eviction (Phase_v2_4 实装 idle policy).
func (*BrowserPool) ResetDefaultIdentity ¶
func (p *BrowserPool) ResetDefaultIdentity(reason string) bool
ResetDefaultIdentity forcefully tears down the current default-identity Chrome entry so callers can reacquire a clean BrowserCore after interruption or target/core corruption. It is a no-op when the default entry does not exist.
func (*BrowserPool) ResetIdentity ¶
func (p *BrowserPool) ResetIdentity(identityKey IdentityKey, reason string) bool
ResetIdentity tears down a specific identity so callers can reacquire it with a different execution mode. This is the primitive BS-15 uses for Fast → Trusted BrowserRun migration; profile ownership remains with the identity.
func (*BrowserPool) ResolveProfileIdentity ¶
func (p *BrowserPool) ResolveProfileIdentity(profileID string) (IdentityKey, error)
ResolveProfileIdentity resolves a profile against the pool's canonical default preset/policy. Callers that only need "this saved profile" must use this instead of Registry().Resolve(profile, Preset{FingerprintTag: ...}) so one physical profile dir maps to one BrowserPool entry.
func (*BrowserPool) Shutdown ¶
func (p *BrowserPool) Shutdown(ctx context.Context)
Shutdown 是 GracefulShutdown 的 r1/r2 兼容签名 (无返回值, 不返回 error).
现有 cmd/deepwork/main.go 走此入口; Phase_v2_3+ 调用方应改用 GracefulShutdown(ctx) error.
func (*BrowserPool) SwitchProfile ¶
func (p *BrowserPool) SwitchProfile(ctx context.Context, profileID string) (restarted bool, err error)
SwitchProfile 切换 default identity 的 Profile.
func (*BrowserPool) UpdateViewport ¶
func (p *BrowserPool) UpdateViewport(ctx context.Context, width, height int, dpr float64, mobile, touch bool, maxTouchPoints int64) error
UpdateViewport 更新 default identity 上 webui-panel Tab 的 viewport.
func (*BrowserPool) UpdateViewportForIdentity ¶
func (p *BrowserPool) UpdateViewportForIdentity(ctx context.Context, identityKey IdentityKey, workspaceID string, width, height int, dpr float64, mobile, touch bool, maxTouchPoints int64) error
UpdateViewportForIdentity updates the LiveView viewport for the tab owned by a scoped BrowserPool identity/workspace pair.
v2: 通过 entry.tabs 扫描 handle.WorkspaceID 定位 caller-owned Tab (legacy purpose index 已删除).
type BrowserRuntimeSummary ¶
type BrowserRuntimeSummary struct {
RuntimeID string `json:"runtime_id"`
BrowserSessionID string `json:"browser_session_id"`
SessionKind BrowserSessionKind `json:"session_kind,omitempty"`
ServiceName string `json:"service,omitempty"`
AccountID string `json:"account_id,omitempty"`
ProfileID string `json:"profile_id,omitempty"`
BrowserPID int `json:"browser_pid,omitempty"`
ChromePID int `json:"chrome_pid,omitempty"`
ChromeAlive bool `json:"chrome_alive"`
DisplayBackend string `json:"display_backend,omitempty"`
DisplayID uint32 `json:"display_id,omitempty"`
}
type BrowserSession ¶
type BrowserSession struct {
FrameHub *FrameBroadcastHub
Authority *SessionAuthority
InputGW *InputGateway
RecordBuf *RecordBuffer // 当前录制缓冲区(nil = 未录制)[CAP-BS09-C3 §6.bis]
RecordStartTime time.Time // 录制开始时间(用于 elapsed 计算)
// contains filtered or unexported fields
}
BrowserSession 是 LiveView 监督层的底座对象。 统一管理三层:
- FrameHub (L1): 帧广播 — Screencast 帧 fan-out 给所有 WS subscriber
- Authority (L2): 状态权威 — SessionState 单一权威 + 广播
- InputGW (L3): 输入网关 — 接管模式 + 租约 + 输入转发
func NewBrowserSession ¶
func NewBrowserSession(viewportW, viewportH int) *BrowserSession
NewBrowserSession 创建 BrowserSession 底座实例(不需要 cdpCtx)。
内部流程:
- 创建 SessionAuthority(viewportW/H 初始化)
- 创建 InputGateway(cdpCtx 为 nil,后续由 AttachBrowserCore / InputGW.SetCDPContext 注入)
- FrameHub 初始为 nil,由 AttachFrameHub(hub) 连接到 BrowserCore 内部 hub
启动时序:
NewBrowserSession → SetBrowserSession(bs) →(第一个 WS 连接到来时)→ bc.StartLiveView(ctx) → bs.AttachFrameHub(hub) → bs.AttachBrowserCore(bc)
func (*BrowserSession) AttachBrowserCore ¶
func (bs *BrowserSession) AttachBrowserCore(bc BrowserCore)
AttachBrowserCore 注入 BrowserCore(SEV-H1 + SEV-H2 修复)。
- 注入 cdpCtx 给 InputGateway,使输入事件可以分发到 Chrome。
- SEV-H1: 将 InputGateway 的 onStateChange 回调扩展为同步调用 BrowserCore 的 EnableTakeover/DisableTakeover,消除 takeoverCtrl 与 InputGateway 的状态分裂。 InputGateway 是唯一入口,旧 takeoverCtrl 自动跟随。
func (*BrowserSession) AttachCursorDetection ¶
func (bs *BrowserSession) AttachCursorDetection(bc BrowserCore)
AttachCursorDetection 向 BrowserCore 注入 cursor 检测,将 cursor 变更广播到 Authority。 如果 bc 未实现 CursorDetector 接口则静默忽略(向后兼容)。
func (*BrowserSession) AttachFrameHub ¶
func (bs *BrowserSession) AttachFrameHub(hub *FrameBroadcastHub)
AttachFrameHub 连接 BrowserCore 内部帧广播 hub(问题 2 修复)。 必须在 BrowserCore.StartLiveView 返回后调用。 统一真相源: 帧由 BrowserCore 的 liveViewEngine 直接 Publish 到此 hub。
func (*BrowserSession) AttachedBrowserCore ¶
func (bs *BrowserSession) AttachedBrowserCore() BrowserCore
AttachedBrowserCore 返回 Browser Portal LiveView 当前绑定的 canonical core。 REST API 必须优先复用它,否则 tabs/status 等读路径会创建第二个 TargetTracker, 造成 Chrome 已有标签页但 UI 投影不切换的状态分裂。
func (*BrowserSession) ResetAttach ¶
func (bs *BrowserSession) ResetAttach()
ResetAttach 重置 attach 状态 + 恢复原始回调(不含旧 BrowserCore 包装)。 必须在 preset switch (Chrome 重启) 后调用。 Codex #1 修复: 恢复 baseCallback 而非在旧包装上再包装,防止回调链无限增长。
type BrowserSessionDefaults ¶
type BrowserSessionDefaults struct {
Kind BrowserSessionKind
Owner string
Mode BrowserMode
Isolation string
AuthorityState string
}
BrowserSessionDefaults captures the policy implied by a session kind.
func DefaultsForBrowserSessionKind ¶
func DefaultsForBrowserSessionKind(kind BrowserSessionKind) BrowserSessionDefaults
DefaultsForBrowserSessionKind is the single policy table for kind-driven runtime defaults. Callers may override mode/profile/account explicitly.
type BrowserSessionHandle ¶
type BrowserSessionHandle interface{}
BrowserSessionHandle — IsolationPolicy.Apply 的 session 句柄占位.
Phase_v2_1: 接口型空 marker, Phase_v2_4 由 BrowserSession 实现 (e.g. 暴露 CDP target / 配置写入接口). 这里仅声明类型, 让 IsolationPolicy 接口可编译, 不约束方法集.
type BrowserSessionKind ¶
type BrowserSessionKind string
BrowserSessionKind is the public scenario identity for a browser session. It must stay domain-neutral: product terms such as portal or webchat belong to callers, not to dw-browser's public contract.
const ( SessionKindTask BrowserSessionKind = "task" SessionKindInteractive BrowserSessionKind = "interactive" SessionKindService BrowserSessionKind = "service" SessionKindDebug BrowserSessionKind = "debug" SessionKindTest BrowserSessionKind = "test" )
func NormalizeBrowserSessionKind ¶
func NormalizeBrowserSessionKind(raw string, fallback BrowserSessionKind) BrowserSessionKind
NormalizeBrowserSessionKind accepts only public, general-purpose kind names.
type CDPConfig ¶
CDPConfig holds CDP connection configuration. Deprecated: use browser.BrowserCore instead.
func DefaultCDPConfig ¶
func DefaultCDPConfig() CDPConfig
DefaultCDPConfig returns a default CDP configuration. Deprecated.
type CDPContextProvider ¶
CDPContextProvider 暴露 Chrome 的 CDP context 给外层(BrowserSession 注入 InputGateway 用)。 browserCoreImpl 实现此接口。
type CDPManager ¶
type CDPManager struct{}
CDPManager is the old browser manager type. Deprecated: use BrowserCore instead.
func NewCDPManager ¶
func NewCDPManager(cfg CDPConfig) *CDPManager
NewCDPManager creates a deprecated CDPManager stub.
func (*CDPManager) Connect ¶
func (m *CDPManager) Connect(ctx context.Context) error
Connect is a no-op on the stub CDPManager.
func (*CDPManager) Disconnect ¶
func (m *CDPManager) Disconnect() error
Disconnect is a no-op on the stub CDPManager.
func (*CDPManager) GetAllPages ¶
func (m *CDPManager) GetAllPages() ([]*CompatPage, error)
GetAllPages returns empty on the stub CDPManager.
func (*CDPManager) GetCurrentPage ¶
func (m *CDPManager) GetCurrentPage() (*CompatPage, error)
GetCurrentPage returns nil on the stub CDPManager.
func (*CDPManager) IsConnected ¶
func (m *CDPManager) IsConnected() bool
IsConnected always returns false on the stub CDPManager.
func (*CDPManager) Navigate ¶
func (m *CDPManager) Navigate(ctx context.Context, pageID, url string) error
Navigate is a no-op on the stub CDPManager.
func (*CDPManager) NewPage ¶
func (m *CDPManager) NewPage(ctx context.Context, url string) (*CompatPage, string, error)
NewPage returns a stub page on the deprecated CDPManager.
type CanonicalFilter ¶
type CanonicalFilter struct {
Field string // "name", "placeholder", "testid"
Op string // "=" (exact), "*=" (contains), "^=" (prefix)
Value string
}
CanonicalFilter canonical DSL 过滤器(name/placeholder/testid + op)。
type ChromeHandle ¶
type ChromeHandle interface {
WSURL() string // CDP WebSocket URL (ready when LaunchChromeInSpace returns)
PID() int // Chrome process PID
Kill() error // SIGKILL the process and wait for exit (idempotent)
Done() <-chan struct{} // closed when process exits (any cause)
Wait() error // block until process exits, return cmd.Wait error
}
ChromeHandle owns a Chrome process spawned via Workspace.LaunchChromeInSpace.
Invariants:
- WSURL() is non-empty when LaunchChromeInSpace returns nil error.
- PID() is the OS pid of the spawned chrome process.
- Done() is closed when the process exits (any cause).
- Kill() is idempotent and waits for process exit before returning.
func NewBrowserMuxHostChromeHandle ¶
func NewBrowserMuxHostChromeHandle(state *BrowserMuxHostState) ChromeHandle
type ChromeLaunchSpec ¶
type ChromeLaunchSpec struct {
ChromePath string // absolute path to chrome binary
Args []string // full Chrome args (must include --remote-debugging-port=N)
DebugPort int // must match --remote-debugging-port in Args
ReadyTimeout time.Duration // CDP ready timeout (default 30s if zero)
}
ChromeLaunchSpec — input to Workspace.LaunchChromeInSpace.
type CompatPage ¶
type CompatPage struct{}
CompatPage is a stub page type for backward compatibility. Deprecated.
func (*CompatPage) Info ¶
func (p *CompatPage) Info() (*CompatTargetInfo, error)
Info returns stub target info.
type CompatTargetInfo ¶
CompatTargetInfo is a stub for target info in compat layer.
type CookieImportResult ¶
type CookieImportResult struct {
TotalImported int // 导入 Cookie 总数
ByDomain map[string]int // 按域名统计
SourceBrowser string // 实际使用的源浏览器
}
CookieImportResult 是 Cookie 导入的结果统计。
type CoreFactoryRequest ¶
type CoreFactoryRequest struct {
Engine BrowserEngine // EngineChrome | EngineSafari
DeviceQuery string // Safari: 设备名/预设名
DeviceUDID string // Safari: 直接指定 UDID
ProfileID string // Chrome: profile ID
Options []BrowserOption // Chrome: 浏览器选项
}
CoreFactoryRequest 统一 BrowserCore 创建请求。 实际的 factory 函数(switch-case)放在 CLI 层(cmd/dw-browser/main.go), 避免 internal/browser 导入子包 internal/browser/safari 造成循环依赖。
type CursorDetector ¶
CursorDetector 是 cursor 检测接口。 browserCoreImpl 实现此接口;BrowserSession 通过类型断言调用。
type DetachedChromeLaunchOptions ¶
type DetachedChromeLaunchOptions struct {
DebugPort int
ProfileDir string
Width int
Height int
PresetID string
UserAgent string
Touch bool
Mode BrowserMode
}
DetachedChromeLaunchOptions 描述 detached Chrome 进程的启动参数。 用于需要独立 Chrome 生命周期的场景(如 dw-browser open/session)。
type DisplayManager ¶
type DisplayManager struct {
// contains filtered or unexported fields
}
DisplayManager 管理独立虚拟 display 的生命周期 (跨平台)。 Pool 和 NewBrowserCore 共享此组件。goroutine-safe。
func (*DisplayManager) ChromeGLOpts ¶
func (dm *DisplayManager) ChromeGLOpts() []chromedp.ExecAllocatorOption
ChromeGLOpts 返回平台专用 GPU/display 的 chromedp ExecAllocatorOption。 human 模式下,各平台需要不同的 GL 渲染参数。
func (*DisplayManager) Close ¶
func (dm *DisplayManager) Close() error
Close 清理 Xvfb 进程。实现 io.Closer 语义。
func (*DisplayManager) Display ¶
func (dm *DisplayManager) Display() string
Display 返回当前 display 字符串 (e.g. ":99")。空字符串表示未启动。
func (*DisplayManager) EnsureDisplay ¶
func (dm *DisplayManager) EnsureDisplay() bool
EnsureDisplay 确保虚拟 display 就绪 (幂等,可多次调用)。 仅在 human 模式下有意义;headless 模式调用为 no-op。 返回 true 表示 display 已就绪,false 表示应降级为 headless。
func (*DisplayManager) UsesHeadlessHumanMode ¶
func (dm *DisplayManager) UsesHeadlessHumanMode() bool
UsesHeadlessHumanMode 返回当前平台的 human 模式是否底层使用 headless=new。 当前终局策略:
- Linux: Xvfb + EGL (headed)
- macOS: offscreen window + Metal (headed)
- Windows: offscreen window + D3D11 (headed)
调用者在此返回 true 时应:
- 显式覆写 UA(移除 HeadlessChrome 签名)
- 注入完整 stealth 脚本(与 headless 模式一致)
func (*DisplayManager) XvfbPID ¶
func (dm *DisplayManager) XvfbPID() int
XvfbPID 返回 Xvfb 进程 PID。0 表示未启动或非 Linux。
type ElementRef ¶
type ElementRef struct {
Ref string // "e1", "e2", ... 或 session 模式下 "@r1", "@r2", ...
BackendNodeID int64 // CDP BackendNodeID
Locator NodeLocator `json:"-"` // 引擎无关定位器(内部使用,不序列化到 CLI 输出)
AXPath string `json:"-"` // Safari AX 树路径(便捷别名,Chrome 为空)
Role string // ARIA role
Name string // accessible name
Placeholder string // input placeholder
TestID string // data-testid 属性值
Interactable bool // 是否可交互(button/input/link/select...)
NameFull string // 完整 accessible name(不截断)
NameShort string // 截断后的 name(≤50 字符,用于显示)
RecommendedLocator string // 推荐的 locator(供 Agent 直接使用)
MatchCount int // 同 role+name 的元素数量
}
ElementRef 是可交互元素的语义引用(每次 snap 后重建)。
type FingerprintPreset ¶
type FingerprintPreset struct {
ID string `json:"id"`
Name string `json:"name"`
UserAgent string `json:"user_agent"`
Platform string `json:"platform"` // navigator.platform
Vendor string `json:"vendor"` // navigator.vendor
Languages string `json:"languages"` // JS array literal
WebGLVendor string `json:"webgl_vendor"`
WebGLRenderer string `json:"webgl_renderer"`
ViewportW int `json:"viewport_w"`
ViewportH int `json:"viewport_h"`
DeviceScaleFactor float64 `json:"device_scale_factor"`
Mobile bool `json:"mobile"`
Touch bool `json:"touch"`
MaxTouchPoints int `json:"max_touch_points"`
}
FingerprintPreset 浏览器指纹预设。
func ResolveRuntimeFingerprintPreset ¶
func ResolveRuntimeFingerprintPreset(presetID string, chromePath string) *FingerprintPreset
ResolveRuntimeFingerprintPreset returns a runtime copy of the preset with the local Chrome major version injected into UA/name for Chrome-based presets.
type FrameBroadcastHub ¶
type FrameBroadcastHub struct {
// contains filtered or unexported fields
}
FrameBroadcastHub 将 Screencast 帧 fan-out 给所有 WS subscriber。
设计要点:
- 每个 subscriber (WS 连接) 持有独立的 1-slot channel,避免单 channel 竞争消费 [CAP-BS09-C3]
- 保新丢旧: Publish 时 channel 满则替换为最新帧(非阻塞生产者)[TC-09-U-09]
- fan-out: 一帧广播给所有 subscriber,互不干扰
- close 安全: Unsubscribe 时安全关闭 channel,不会 panic
func NewFrameBroadcastHub ¶
func NewFrameBroadcastHub() *FrameBroadcastHub
NewFrameBroadcastHub 创建 FrameBroadcastHub 实例。
func (*FrameBroadcastHub) Publish ¶
func (h *FrameBroadcastHub) Publish(frame *ScreencastFrame)
Publish 将帧广播给所有 subscriber(非阻塞,保新丢旧)[TC-09-U-09]。
保新丢旧逻辑:
- 尝试直接写入 channel
- channel 满时先取出旧帧,再写入新帧 (内层 default 防止并发 Unsubscribe 导致 channel 被关闭后二次操作)
func (*FrameBroadcastHub) Subscribe ¶
func (h *FrameBroadcastHub) Subscribe(connID string) chan *ScreencastFrame
Subscribe 为 connID 注册独立的 1-slot 帧 channel,返回 channel 本身(用于 Unsubscribe 匹配)。 重复注册同一 connID 会先关闭旧 channel 再创建新的(幂等注册)。
返回值是双向 channel,用于传给 Unsubscribe 做代次匹配。 读取端请用 <-chan *ScreencastFrame 类型接收。
func (*FrameBroadcastHub) Unsubscribe ¶
func (h *FrameBroadcastHub) Unsubscribe(connID string, ch chan *ScreencastFrame)
Unsubscribe 用 channel 指针做代次匹配,只关闭与传入 ch 相同的 channel。 若 connID 已被新连接替换(ch 不匹配),静默忽略,不影响新连接。 这是 SEV-H2 的关键修复:防止旧连接的 defer 关掉新连接的 channel。
type HUDConfig ¶
HUDConfig is the config for the Phantom HUD renderer. Deprecated: kept for compat with internal/desktop.
func DefaultHUDConfig ¶
func DefaultHUDConfig() HUDConfig
DefaultHUDConfig returns the default HUD configuration. Deprecated.
type HUDRenderer ¶
type HUDRenderer interface {
Init(ctx context.Context, cfg HUDConfig) error
Show() error
Hide() error
Render(nodes []SuperNode) error
RenderRipple(x, y int, t RippleType) error
SetStatus(status string) error
Highlight(nodeID int) error
ClearHighlight() error
SetPosition(x, y, width, height int) error
Close() error
}
HUDRenderer is the interface for Phantom HUD rendering. Deprecated: kept for compat with internal/desktop.
func NewCDPHUDRenderer ¶
func NewCDPHUDRenderer(controlURL string) HUDRenderer
NewCDPHUDRenderer creates a deprecated HUD renderer stub. Deprecated: use LiveView WebSocket API instead.
type HumanOverride ¶
type HumanOverride struct {
// contains filtered or unexported fields
}
HumanOverride is a stub for the old human-override mechanism. Deprecated.
func NewHumanOverride ¶
func NewHumanOverride() *HumanOverride
NewHumanOverride creates a new HumanOverride stub.
func (*HumanOverride) IsActive ¶
func (h *HumanOverride) IsActive() bool
IsActive returns true if human override is active.
type Identity ¶
type Identity struct {
Profile string
Preset Preset
Policy IsolationPolicy
}
Identity — 三元组逻辑聚合 (便于上层调用方按值传递).
注意: Identity 本身不参与 hash, IdentityKey 由 NewIdentityKey(profile, preset, policy) 三参数计算; 此结构体只是便利封装.
type IdentityDescriptor ¶
type IdentityDescriptor struct {
Key IdentityKey
Profile string // 物理身份 (profileID, 与 user-data-dir 一一对应)
Preset Preset // UA / viewport / locale / timezone / 指纹
Policy IsolationPolicy // 隔离策略 (Phase_v2_1: 仅 NoopPolicy)
}
IdentityDescriptor — IdentityKey 反查结果 (Inspect / List 用).
type IdentityKey ¶
type IdentityKey string
IdentityKey — identity 三元组的确定性 hash, 稳定可比较 + 跨进程一致. 实现: SHA-256(profile|preset.canonical|policy.PolicyKey()) 截断 32 字节 hex.
不变式:
- 同三元组多次调用 NewIdentityKey 必须返回同一 IdentityKey (字节相等).
- 三个维度任一变化 → IdentityKey 必变 (D1 + DDC-10 3 维正交).
func NewIdentityKey ¶
func NewIdentityKey(profile string, preset Preset, policy IsolationPolicy) IdentityKey
NewIdentityKey 把三元组归一化为 IdentityKey (确定性 SHA-256 hash 截断).
算法:
raw = "profile=" + profile + "||preset=" + preset.canonical() + "||policy=" + policy.PolicyKey() hash = sha256(raw) key = hex(hash[:16]) // 32 字符, 128 bit, 抗碰撞充足
约束 (TC-09-U-38 守护):
- 同三元组多次调用必须返回字节相等的 IdentityKey.
- policy=nil 时按 NoopPolicy 处理 (不会 panic), 但调用方应显式传 NoopPolicy{}.
type IdentityPoolStatus ¶
type IdentityPoolStatus struct {
Key IdentityKey
ChromePID int // Chrome 主进程 PID; 0 = 尚未启动 / 已退出
TabCount int // 当前活跃 Tab 数
Mode BrowserMode // 当前 Chrome 进程运行模式: human/headless
Tabs []TabHandle // 该 identity 下所有 Tab (按 TargetID 字典序)
}
IdentityPoolStatus — 单个 identity 在 Pool 中的状态.
type IdentityRegistry ¶
type IdentityRegistry interface {
// Resolve 把 (profile, preset, policy) 三元组归一化为 IdentityKey.
// 同三元组多次 Resolve 必须返回同一 IdentityKey (确定性, TC-09-U-38).
// 同时把 IdentityDescriptor 注册到内部 store (供 Inspect / List 反查).
Resolve(profile string, preset Preset, policy IsolationPolicy) (IdentityKey, error)
// Inspect 反查 IdentityKey 对应的三元组. 未注册 → ErrIdentityNotFound.
Inspect(key IdentityKey) (*IdentityDescriptor, error)
// List 列出当前 Registry 已知的所有 identity (按 IdentityKey 字典序).
List() []IdentityDescriptor
}
IdentityRegistry — identity 三元组解析与归一化 (D1).
对照 Cap §2.bis:
Resolve(profile, preset, policy) → IdentityKey // 确定性归一化 Inspect(key) → *IdentityDescriptor // 反查 List() → []IdentityDescriptor // 全量列表 (诊断/可观测)
线程安全: 实现必须支持并发 Resolve / Inspect / List.
func NewIdentityRegistry ¶
func NewIdentityRegistry() IdentityRegistry
NewIdentityRegistry 返回一个新的内存 IdentityRegistry.
初始为空; 首次 Resolve 即 lazy-register.
type InputAck ¶
type InputAck struct {
Type string `json:"type"` // 固定为 "input-ack"
Seq int64 `json:"seq"` // 对应客户端 seq
Status string `json:"status"` // "accepted" / "rejected" / "error"
Reason string `json:"reason,omitempty"` // 拒绝原因(仅 rejected/error 时填充)
}
InputAck 是服务端对 InputMessage 的 ACK 响应。
type InputEvent ¶
type InputEvent struct {
Type string `json:"type"` // "mouse" | "keyboard" | "touch"
Event string `json:"event"` // mousePressed/mouseReleased/mouseMoved/mouseWheel/keyDown/keyUp/char/touchStart/touchMove/touchEnd/touchCancel
X float64 `json:"x"`
Y float64 `json:"y"`
Button string `json:"button"`
ClickCount int `json:"clickCount"`
DeltaX float64 `json:"deltaX"` // scroll
DeltaY float64 `json:"deltaY"` // scroll
Key string `json:"key"`
Code string `json:"code"`
Text string `json:"text"`
Modifiers int `json:"modifiers"` // bit flags: Alt=1, Ctrl=2, Meta=4, Shift=8
TouchPoints []TouchPoint `json:"touchPoints,omitempty"` // touch 事件的触摸点列表
}
InputEvent 是前端接管模式下的输入事件。
type InputGateway ¶
type InputGateway struct {
// contains filtered or unexported fields
}
InputGateway 输入网关 — 替代 TakeoverController [CAP-BS09-C3 r2, DDC-I-06, DDC-I-07]
func NewInputGateway ¶
func NewInputGateway(cdpCtx context.Context, onStateChange func()) *InputGateway
NewInputGateway 创建 InputGateway,初始状态为 OBSERVE。
cdpCtx: chromedp 会话 context,用于 CDP dispatch。 onStateChange: 模式变化时触发的回调(由 browser_session 注册,用于向前端广播状态)。
func (*InputGateway) GetOnStateChange ¶
func (g *InputGateway) GetOnStateChange() func()
GetOnStateChange 返回当前 onStateChange 回调(供 AttachBrowserCore 链式包装用)。
func (*InputGateway) GetRecordBuffer ¶
func (g *InputGateway) GetRecordBuffer() *RecordBuffer
GetRecordBuffer 返回当前注入的录制缓冲区(nil 表示未启用)。
func (*InputGateway) HandleInput ¶
func (g *InputGateway) HandleInput(connID string, msg *InputMessage) *InputAck
HandleInput 校验 lease → CDP dispatch → 返回 ACK → 续租。
校验顺序:
- mode == TakeoverModeTakeover
- connID == g.owner
- msg.Lease == g.leaseToken
- time.Now() < g.leaseExpiry
任何校验失败返回 rejected + reason。 dispatch 成功返回 accepted,并在成功后续租(reset idle timer)。
func (*InputGateway) LeaseExpiry ¶
func (g *InputGateway) LeaseExpiry() time.Time
LeaseExpiry 返回 lease 过期时间(OBSERVE 模式下返回零值)。
func (*InputGateway) LeaseToken ¶
func (g *InputGateway) LeaseToken() string
LeaseToken 返回当前 lease token(OBSERVE 模式下返回空字符串)。
func (*InputGateway) OnDisconnect ¶
func (g *InputGateway) OnDisconnect(connID string)
OnDisconnect 断连处理 — 启动 grace timer。
5s 内重连(OnReconnect)可取消 grace timer 恢复接管。 超时后 auto-release + 合成释放所有按压输入。
func (*InputGateway) OnReconnect ¶
func (g *InputGateway) OnReconnect(connID string)
OnReconnect 重连处理 — 取消 grace timer(如果 connID 匹配 owner)。
重连后 owner 可继续使用原有 lease token 发送输入。
func (*InputGateway) Owner ¶
func (g *InputGateway) Owner() string
Owner 返回当前 owner connID(OBSERVE 模式下返回空字符串)。
func (*InputGateway) ReleaseTakeover ¶
func (g *InputGateway) ReleaseTakeover(connID string) error
ReleaseTakeover 主动释放接管,恢复 OBSERVE 模式,并合成释放所有按压输入。
只有当前 owner 才能释放。
func (*InputGateway) RequestTakeover ¶
func (g *InputGateway) RequestTakeover(connID string) (leaseToken string, expiresAt time.Time, err error)
RequestTakeover CAS 抢锁,切换到 TAKEOVER 模式。
已有 owner 时返回 error,包含 currentOwner 和 leaseRemaining 信息。 成功返回 leaseToken 和 expiresAt(= now + idleTimeout)。
func (*InputGateway) SetCDPContext ¶
func (g *InputGateway) SetCDPContext(ctx context.Context)
SetCDPContext 延迟注入 Chrome CDP context(Chrome 启动后由 AttachBrowserCore 调用)。 允许 BrowserSession 在 Chrome 启动前创建,Chrome 就绪后再连接。
func (*InputGateway) SetCDPContextProvider ¶
func (g *InputGateway) SetCDPContextProvider(fn func() context.Context)
SetCDPContextProvider 注册“当前活跃 Target 的 CDP context”解析器。 InputGateway 在每次 dispatch 时动态取值,避免持有已经被取消的快照 ctx。
func (*InputGateway) SetOnAcceptedInput ¶
func (g *InputGateway) SetOnAcceptedInput(fn func(event *InputEvent))
SetOnAcceptedInput 注册”已通过接管校验的真实用户输入”回调。 用于把输入链与 TargetTracker 的 target-claim 协议衔接起来,避免 liveview 侧靠 heuristic 猜 target 归属。
func (*InputGateway) SetOnStateChange ¶
func (g *InputGateway) SetOnStateChange(fn func())
SetOnStateChange 替换 onStateChange 回调(供 AttachBrowserCore 链式包装用)。 用于 SEV-H1: AttachBrowserCore 将原有回调包装后重新注入,实现 InputGateway → BrowserCore 状态同步。
func (*InputGateway) SetRecordBuffer ¶
func (g *InputGateway) SetRecordBuffer(rb *RecordBuffer)
SetRecordBuffer 注入录制缓冲区。nil 表示禁用录制 tap。 Recording tap 在 dispatch 成功 (accepted) 后触发,零侵入主路径 (SK-D4)。
type InputMessage ¶
type InputMessage struct {
Type string `json:"type"` // 固定为 "input"
Seq int64 `json:"seq"` // 客户端单调递增序号
Lease string `json:"lease"` // 当前租约令牌(必须与 leaseToken 匹配)
Event InputEvent `json:"event"` // 具体输入事件
}
InputMessage 是前端通过 WebSocket 发送的输入消息(接管模式)。
type IsolationPolicy ¶
type IsolationPolicy interface {
// PolicyKey 返回稳定 key 参与 IdentityKey hash.
// 同一类型 policy 同一配置 → 必返回同一 key (确定性).
PolicyKey() string
// Apply 在 Chrome 启动后通过 CDP 把 policy 落地 (proxy / permission / download / extension / geo / compliance).
// Phase_v2_1: NoopPolicy.Apply 直接返回 nil.
Apply(ctx context.Context, session BrowserSessionHandle) error
}
IsolationPolicy — identity 第 3 正交维度 (DDC-10, BRR-07, D9 SL-2).
Phase_v2_1: 仅 NoopPolicy stub (P0 skeleton). Phase_v2_4: ProxyPolicy 首例 (J3 默认值, P1 deferred).
type JavaScriptDialogEvent ¶
type JavaScriptDialogEvent struct {
ID string `json:"id"`
TargetID string `json:"target_id"`
URL string `json:"url"`
FrameID string `json:"frame_id"`
Message string `json:"message"`
Type string `json:"type"`
DefaultPrompt string `json:"default_prompt,omitempty"`
}
JavaScriptDialogEvent describes a page-level alert/confirm/prompt that must be surfaced through LiveView when Chrome itself is running on a virtual display.
type LiveViewportSyncer ¶
type LiveViewportSyncer interface {
// SetLiveViewport 更新当前 liveview 目标 viewport 配置,并立即应用到活跃 target。
SetLiveViewport(width, height int, dpr float64, mobile bool) error
// SyncActiveTargetViewport 将最近一次 liveview viewport 配置重放到指定活跃 target。
SyncActiveTargetViewport(targetCtx context.Context) error
}
LiveViewportSyncer 暴露 LiveView viewport 的跨 target 同步能力。 适用于 BrowserPool/WebUI 场景:前端真实容器尺寸变化后,当前活跃 target 与 后续切换到的新 target(新 tab / auth popup)都应继承同一套 viewport 语义。
设计目标:
- PC / iOS 共用一套接口,不拆平台特判
- 不仅同步 Screencast 分辨率,也同步 CDP DeviceMetrics / Touch 语义
- 新 target 激活时可重放当前 liveview viewport,避免多 tab 出现黑边或错位
type MemoryHUDRenderer ¶
type MemoryHUDRenderer struct {
// contains filtered or unexported fields
}
MemoryHUDRenderer is an in-memory HUDRenderer for use in unit tests.
func NewMemoryHUDRenderer ¶
func NewMemoryHUDRenderer() *MemoryHUDRenderer
NewMemoryHUDRenderer creates a new in-memory HUD renderer for testing.
func (*MemoryHUDRenderer) ClearHighlight ¶
func (r *MemoryHUDRenderer) ClearHighlight() error
func (*MemoryHUDRenderer) Close ¶
func (r *MemoryHUDRenderer) Close() error
func (*MemoryHUDRenderer) GetRippleHistory ¶
func (r *MemoryHUDRenderer) GetRippleHistory() []MemoryRippleCall
GetRippleHistory returns a copy of all recorded RippleRender calls.
func (*MemoryHUDRenderer) Hide ¶
func (r *MemoryHUDRenderer) Hide() error
func (*MemoryHUDRenderer) Highlight ¶
func (r *MemoryHUDRenderer) Highlight(_ int) error
func (*MemoryHUDRenderer) Init ¶
func (r *MemoryHUDRenderer) Init(_ context.Context, _ HUDConfig) error
func (*MemoryHUDRenderer) Render ¶
func (r *MemoryHUDRenderer) Render(nodes []SuperNode) error
func (*MemoryHUDRenderer) RenderRipple ¶
func (r *MemoryHUDRenderer) RenderRipple(x, y int, t RippleType) error
func (*MemoryHUDRenderer) SetPosition ¶
func (r *MemoryHUDRenderer) SetPosition(_, _, _, _ int) error
func (*MemoryHUDRenderer) SetStatus ¶
func (r *MemoryHUDRenderer) SetStatus(status string) error
func (*MemoryHUDRenderer) Show ¶
func (r *MemoryHUDRenderer) Show() error
type MemoryRippleCall ¶
type MemoryRippleCall struct {
X int
Y int
RippleType RippleType
}
MemoryRippleCall records a single RenderRipple call.
type NodeLocator ¶
type NodeLocator struct {
Engine BrowserEngine `json:"engine"`
BackendNodeID int64 `json:"backend_node_id,omitempty"` // Chrome only
AXPath string `json:"ax_path,omitempty"` // Safari: AX 树路径 (如 "0.3.1")
StableKey string `json:"stable_key,omitempty"` // Safari: role+name+identifier 组合,用于漂移重定位
Ordinal int `json:"ordinal,omitempty"` // DFS 序号
Frame Rect `json:"frame,omitempty"` // 元素位置 (Safari coordinate tap fallback)
}
NodeLocator 是引擎无关的元素定位器。Chrome 使用 BackendNodeID,Safari 使用 AXPath + StableKey。
type NoopPolicy ¶
type NoopPolicy struct{}
NoopPolicy — Phase_v2_1 默认隔离策略, 不施加任何额外约束.
不变式: 所有 NoopPolicy 实例 PolicyKey 相同 (= "noop"), 因此 (profile, preset, NoopPolicy{}) 三元组的 IdentityKey 也相同, 实现"默认 identity 即 (profile, preset)"语义.
func (NoopPolicy) Apply ¶
func (NoopPolicy) Apply(_ context.Context, _ BrowserSessionHandle) error
Apply 是 no-op, 直接返回 nil (不修改 session).
type NoopWorkspace ¶
type NoopWorkspace struct{}
NoopWorkspace is a no-op for tests / unsupported platforms. LaunchChromeInSpace falls back to a direct fork (no Space switching).
func (*NoopWorkspace) Close ¶
func (n *NoopWorkspace) Close() error
func (*NoopWorkspace) EnsureSpace ¶
func (n *NoopWorkspace) EnsureSpace() (int64, error)
func (*NoopWorkspace) LaunchChromeInSpace ¶
func (n *NoopWorkspace) LaunchChromeInSpace(spec ChromeLaunchSpec) (ChromeHandle, error)
type PageTargetSelection ¶
func SelectAttachablePageTarget ¶
func SelectAttachablePageTarget(targets []map[string]interface{}, expectedURL, fallbackID string) PageTargetSelection
SelectAttachablePageTarget chooses the page target that best represents the user's current browser state. It never treats ChromeInitialPageURL as user intent; that URL is only a Chrome startup sentinel.
type ParsedAction ¶
type ParsedAction struct {
Op string // "click" | "clickat" | "tap" | "tapat" | "type" | "scroll" | "hover" | "select"
Ref string // Element Ref(如 "e3")或语义选择器(如 "#testid", "button:'name'")
Value string // type/select 的值
CoordX float64 // clickat 的相对 X 坐标(0..1)
CoordY float64 // clickat 的相对 Y 坐标(0..1)
}
ParsedAction 是解析后的操作结构。
func ParseAction ¶
func ParseAction(action string) (*ParsedAction, error)
ParseAction 解析操作语法字符串 [TC-09-U-05, TC-09-U-06]。
支持操作:
- "click #testid" | "click button:'名称'"
- "clickat #canvas 92% 8%" — 对元素相对坐标执行真实鼠标点击
- "tap button:'接管'" | "tapat #browser-liveview 92% 8%" — 对元素执行真实触控点击
- "fill #input 'text'" — 清空后输入
- "type textbox:'名称' 'hello'"
- "press Enter" | "press Ctrl+A" | "press #btn Ctrl+K"
- "hover button:'名称'"
- "scroll down" | "scroll up"
- "select e4 'opt2'"
- "back" | "forward"
- "focus #selector"
- "scrollinto #selector"
- "check #selector" | "uncheck #selector"
type ParsedSelector ¶
type ParsedSelector struct {
SType SelectorType
TestID string
Role string
Name string
NameOp string // "=" exact | "*=" contains | "^=" prefix
Filters []CanonicalFilter // canonical DSL 过滤器
Nth int // nth filter (0 = no nth)
ScopeParent *ParsedSelector // A >> B 中的 A
Raw string // 原始字符串
SessionRef int // @rN 的 N
}
ParsedSelector 解析后的语义选择器。
func ParseSelector ¶
func ParseSelector(selector string) (*ParsedSelector, error)
ParseSelector 解析选择器字符串。
优先级顺序:
- @rN — session ref(仅 session 模式有效)
- #testid — data-testid
- role=TYPE[...] — canonical DSL
- A >> B — scoped selector
- role:'name' — shorthand(contains)
- role="name" — shorthand(exact)
- css=... — explicit CSS
- e{N} — legacy ref(拒绝)
- pure identifier — bare role
10. everything else — CSS fallback
type PhantomHUD ¶
type PhantomHUD struct {
// contains filtered or unexported fields
}
PhantomHUD is a stub for the old Phantom HUD orchestrator. Deprecated.
func NewPhantomHUD ¶
func NewPhantomHUD(cfg HUDConfig, renderer HUDRenderer) *PhantomHUD
NewPhantomHUD creates a new PhantomHUD stub.
func (*PhantomHUD) Update ¶
func (p *PhantomHUD) Update(nodes []SuperNode) error
Update renders the given nodes via the underlying renderer.
type PoolConfig ¶
type PoolConfig struct {
DataDir string // deepwork 数据目录 (e.g. ~/.deepwork)
MaxTabs int // Tab 上限 (default 10) — 全局, 跨所有 identity entry
IdleTimeout time.Duration // Tab 空闲回收时间 (default 5min)
PresetID string // 默认 preset (legacy 入口生效)
ProfileID string // 默认 profile (legacy 入口生效)
Mode BrowserMode // "headed"(默认) / "headless" / "visible"
}
PoolConfig 配置 BrowserPool 默认 (legacy default identity 用).
type PoolSnapshot ¶
type PoolSnapshot struct {
Identities []IdentityPoolStatus
TotalTabs int
}
PoolSnapshot — Pool 当前状态的只读视图 (诊断 / 可观测).
注: Identities 按 IdentityKey 字典序排序 (确定输出, 便于诊断对比).
type Preset ¶
type Preset struct {
UserAgent string // navigator.userAgent
Viewport Viewport // 视口尺寸 + DPR
Locale string // navigator.language (e.g. "en-US")
Timezone string // IANA tz name (e.g. "America/New_York")
FingerprintTag string // TH-0418-c9x 指纹 runtime tag (e.g. "macos-chrome-126")
}
Preset — 浏览器表观属性集 (UA / viewport / locale / timezone / 指纹 runtime tag).
注意: 字段顺序参与 canonical 序列化, 不可随意调整 (会破坏 IdentityKey 稳定性).
type Profile ¶
type Profile struct {
ID string `json:"id"`
Name string `json:"name"`
UserDataDir string `json:"user_data_dir"`
Status string `json:"status"` // "active" | "crashed" | "inactive"
CreatedAt time.Time `json:"created_at"`
}
Profile 是 Browser Profile 实体 [Ref: T5-B2.1]。
type ProfileManager ¶
type ProfileManager struct {
// contains filtered or unexported fields
}
ProfileManager 管理 Browser Profile 生命周期(元数据用 JSON 文件,不用 SQLite)[Ref: BP §B3]。
func NewProfileManager ¶
func NewProfileManager() (*ProfileManager, error)
NewProfileManager 创建 ProfileManager 实例。
func NewProfileManagerForDataDir ¶
func NewProfileManagerForDataDir(dataDir string) (*ProfileManager, error)
NewProfileManagerForDataDir 基于指定 deepwork dataDir 创建 ProfileManager。
func NewProfileManagerWithBase ¶
func NewProfileManagerWithBase(baseDir string) (*ProfileManager, error)
NewProfileManagerWithBase 创建指定 baseDir 的 ProfileManager(测试用)。
func (*ProfileManager) Create ¶
func (m *ProfileManager) Create(name string) (*Profile, error)
Create 创建新的逻辑 profile。 若同名 slug 已存在,则自动追加数值后缀,避免覆盖现有用户状态。
func (*ProfileManager) Delete ¶
func (m *ProfileManager) Delete(id string) error
Delete 删除 Profile(元数据 + user-data-dir)[TC-09-I-14]。
func (*ProfileManager) EnsureDefault ¶
func (m *ProfileManager) EnsureDefault() (*Profile, error)
EnsureDefault 确保默认 profile 存在。
func (*ProfileManager) GetOrCreate ¶
func (m *ProfileManager) GetOrCreate(id string) (*Profile, error)
GetOrCreate 获取或创建 Profile,确保目录存在 [TC-09-U-12, TC-09-U-13]。
func (*ProfileManager) InjectStealth ¶
func (m *ProfileManager) InjectStealth(ctx context.Context) error
InjectStealth 注入 Stealth 脚本(webdriver 伪装)[TC-09-U-15]。
func (*ProfileManager) List ¶
func (m *ProfileManager) List() ([]*Profile, error)
List 返回所有 Profile [TC-09-I-14]。
type ProfileOwnerMetadata ¶
type RecordBuffer ¶
type RecordBuffer struct {
// contains filtered or unexported fields
}
RecordBuffer 接收 InputGateway 事件 tap,按步骤组装录制 trace。 线程安全: 所有公开方法均加锁。
func NewRecordBuffer ¶
func NewRecordBuffer() *RecordBuffer
NewRecordBuffer 创建 RecordBuffer 实例(初始非录制状态)。
func (*RecordBuffer) AppendKeyEvent ¶
func (rb *RecordBuffer) AppendKeyEvent(event *InputEvent)
AppendKeyEvent 处理键盘事件 tap。 keyDown 事件: 可打印字符 → 合并 "type";特殊键 → "keypress"。 其他事件 (keyUp/char) 忽略。 调用前不需要持锁(内部加锁)。
func (*RecordBuffer) AppendMouseEvent ¶
func (rb *RecordBuffer) AppendMouseEvent(event *InputEvent)
AppendMouseEvent 处理鼠标事件 tap。 仅 mousePressed 转为 "click" step(mouseReleased/mouseMoved 忽略)。 调用前不需要持锁(内部加锁)。
func (*RecordBuffer) ExportJSON ¶
func (rb *RecordBuffer) ExportJSON() ([]byte, error)
ExportJSON 将当前 trace 序列化为 JSON。
func (*RecordBuffer) IsRecording ¶
func (rb *RecordBuffer) IsRecording() bool
IsRecording 返回当前是否正在录制。
func (*RecordBuffer) SetSnapshotFn ¶
func (rb *RecordBuffer) SetSnapshotFn(fn func(x, y float64) string)
SetSnapshotFn 注入 A11y 快照回调(DDC-I-24: 操作 target 最小子树)。
func (*RecordBuffer) Start ¶
func (rb *RecordBuffer) Start(domain, url string)
Start 开始录制,重置状态。连续两次 Start 会重置为新录制。
func (*RecordBuffer) StepCount ¶
func (rb *RecordBuffer) StepCount() int
StepCount 返回当前已记录的 step 数量。
func (*RecordBuffer) Stop ¶
func (rb *RecordBuffer) Stop() RecordTrace
Stop 停止录制,计算 duration,返回 trace 快照。 未录制时返回空 trace,不 panic。
type RecordStep ¶
type RecordStep struct {
Seq int `json:"seq"`
Action string `json:"action"` // "click" | "type" | "keypress" | "scroll"
Target *RecordTarget `json:"target,omitempty"`
Text string `json:"text,omitempty"`
Key string `json:"key,omitempty"`
Coordinates *RecordXY `json:"coordinates,omitempty"`
TimestampMs int64 `json:"timestamp_ms"`
SnapshotBefore string `json:"snapshot_before,omitempty"`
}
RecordStep 是 trace 中的单个操作步骤。
type RecordTarget ¶
type RecordTarget struct {
Selector string `json:"selector"`
Role string `json:"role"`
Name string `json:"name"`
Tag string `json:"tag"`
}
RecordTarget 描述操作目标的 A11y 元数据。
type RecordTrace ¶
type RecordTrace struct {
Domain string `json:"domain"`
StartURL string `json:"start_url"`
StartTime time.Time `json:"start_time"`
DurationMs int64 `json:"duration_ms"`
Steps []RecordStep `json:"steps"`
}
RecordTrace 是完整的操作录制记录。
type Rect ¶
type Rect struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Width float64 `json:"width"`
Height float64 `json:"height"`
}
Rect 表示元素矩形区域。
type RippleType ¶
type RippleType string
RippleType is the type of ripple animation. Deprecated.
const ( // RippleTypeClick indicates a click ripple. RippleTypeClick RippleType = "click" // RippleTypeDrag indicates a drag ripple. RippleTypeDrag RippleType = "drag" // RippleTypeKey indicates a keyboard ripple. RippleTypeKey RippleType = "key" )
type ScreencastFrame ¶
type ScreencastFrame struct {
Data []byte // JPEG 字节
Timestamp int64 // Unix ms
SessionID int64 // CDP SessionID(用于 ACK)
TargetID string // Chrome TargetID,用于前端确认首帧归属
}
ScreencastFrame 是 Screencast 帧(LiveView 推送)。
type SelectorType ¶
type SelectorType int
SelectorType 语义选择器类型。
const ( SelectorSessionRef SelectorType = iota // @rN — session ref SelectorTestID // #testid SelectorCanonical // role=button[name*="x"][nth=3] SelectorScoped // A >> B SelectorRoleName // role:'name' (shorthand, contains) SelectorRoleNameExact // role="name" (shorthand, exact) SelectorRole // role (bare role, first match) SelectorCSS // css=... or fallback SelectorLegacyRef // e{N} — rejected )
type SessionAuthority ¶
type SessionAuthority struct {
// contains filtered or unexported fields
}
SessionAuthority 管理 SessionState 并 fan-out 广播给所有 WS subscriber。
设计要点:
- 1-slot channel 保新丢旧(与 FrameBroadcastHub 保持一致)
- seq 原子递增,确保 subscriber 能检测到跳变
func NewSessionAuthority ¶
func NewSessionAuthority(viewportW, viewportH int) *SessionAuthority
NewSessionAuthority 创建 SessionAuthority 实例,初始模式为 "idle"。
func (*SessionAuthority) GetState ¶
func (a *SessionAuthority) GetState() SessionState
GetState 返回当前状态快照(深拷贝,避免调用方修改内部状态)。
func (*SessionAuthority) Subscribe ¶
func (a *SessionAuthority) Subscribe(connID string) chan *SessionState
Subscribe 为 connID 注册 1-slot 状态 channel,返回 channel 本身(用于 Unsubscribe 匹配)。 重复注册同一 connID 会先关闭旧 channel 再创建新的(幂等注册)。
func (*SessionAuthority) Unsubscribe ¶
func (a *SessionAuthority) Unsubscribe(connID string, ch chan *SessionState)
Unsubscribe 用 channel 指针做代次匹配,只关闭与传入 ch 相同的 channel。 若 connID 已被新连接替换(ch 不匹配),静默忽略,不影响新连接。 这是 SEV-H2 的关键修复:防止旧连接的 defer 关掉新连接的 channel。
func (*SessionAuthority) UpdateCursor ¶
func (a *SessionAuthority) UpdateCursor(cursor string)
UpdateCursor 更新远端 cursor 样式 → seq++ → 广播。
func (*SessionAuthority) UpdateMode ¶
func (a *SessionAuthority) UpdateMode(mode, owner, leaseToken string, leaseExpiry int64)
UpdateMode 更新模式(owner / leaseToken / leaseExpiry)→ seq++ → 广播。
func (*SessionAuthority) UpdateNavigation ¶
func (a *SessionAuthority) UpdateNavigation(url, title string)
UpdateNavigation 更新 URL/Title → seq++ → 广播。
func (*SessionAuthority) UpdateRecording ¶
func (a *SessionAuthority) UpdateRecording(recording bool, elapsedMs int64)
UpdateRecording 更新录制状态 → seq++ → 广播 [CAP-BS09-C3 §6.bis]。
func (*SessionAuthority) UpdateTargetInfo ¶
func (a *SessionAuthority) UpdateTargetInfo(url, title string, targetCount int, tabs ...[]TabInfo)
UpdateTargetInfo 更新 Target 信息(URL/Title/Count/Tabs)→ seq++ → 广播 [r3, TH-0414-b3m]。
func (*SessionAuthority) UpdateViewport ¶
func (a *SessionAuthority) UpdateViewport(cssW, cssH int)
UpdateViewport 更新 viewport 尺寸 → seq++ → 广播。
type SessionCore ¶
type SessionCore interface {
BrowserCore
// SnapWithSessionMode 获取快照(session 模式,使用 @rN ref)。
SnapWithSessionMode(ctx context.Context, snapEpoch int) (*Snapshot, error)
// SnapWithOptions 获取快照并应用 SnapOptions 过滤(selector/compact/max-depth)[r2]。
SnapWithOptions(ctx context.Context, opts SnapOptions) (*Snapshot, error)
// ActWithSessionMode 执行操作(session 模式,允许 @rN ref)。
ActWithSessionMode(ctx context.Context, action string, observe bool) (*Snapshot, error)
// RestoreRefsFromSession 从 session 文件恢复 ref 表。
RestoreRefsFromSession(refs []SessionRef)
}
SessionCore — BrowserCore 的 session 扩展接口(含 @rN ref 支持)。
func NewBrowserCoreFromSession ¶
func NewBrowserCoreFromSession(ctx context.Context, wsURL string, targetID string, presetID string, modes ...BrowserMode) (SessionCore, error)
NewBrowserCoreFromSession 连接到已有 Chrome 实例(通过 CDP WebSocket URL)。 用于 session 模式:open 后 snap/act/get/wait 都连接到同一个 Chrome 进程。
type SessionInfo ¶
type SessionInfo struct {
SessionID string `json:"session_id"`
BrowserSessionID string `json:"browser_session_id,omitempty"`
SessionKind BrowserSessionKind `json:"session_kind,omitempty"`
Goal string `json:"goal,omitempty"`
Owner string `json:"owner,omitempty"`
AuthorityState string `json:"authority_state,omitempty"`
ProfileID string `json:"profile_id,omitempty"`
Isolation string `json:"isolation,omitempty"`
ServiceName string `json:"service,omitempty"`
AccountID string `json:"account_id,omitempty"`
ChromePID int `json:"chrome_pid"`
WSURL string `json:"ws_url"` // CDP WebSocket URL
DebugPort int `json:"debug_port"`
TargetID string `json:"target_id"` // CDP target ID for the active page
Mode BrowserMode `json:"mode,omitempty"`
PresetID string `json:"preset_id,omitempty"`
ProfileDir string `json:"profile_dir"`
PageURL string `json:"page_url"`
CreatedAt string `json:"created_at"`
ViewportW int `json:"viewport_w"`
ViewportH int `json:"viewport_h"`
UserAgent string `json:"user_agent"`
Touch bool `json:"touch"`
SnapEpoch int `json:"snap_epoch"` // Incremented on each snap
Refs []SessionRef `json:"refs"` // Ref table from last snap
Ephemeral bool `json:"ephemeral"` // true if --ephemeral was used
XvfbPID int `json:"xvfb_pid"` // Xvfb process PID (headed mode, Linux)
BrowserMuxHostID string `json:"browser_mux_host_id,omitempty"`
BrowserMuxHostPID int `json:"browser_mux_host_pid,omitempty"`
RuntimeID string `json:"runtime_id,omitempty"`
BrowserRunID string `json:"browser_run_id,omitempty"`
DisplayBackend string `json:"display_backend,omitempty"`
DisplayID uint32 `json:"display_id,omitempty"`
DisplayVerified bool `json:"display_verified,omitempty"`
ChromeWindowContained bool `json:"chrome_window_contained,omitempty"`
Engine BrowserEngine `json:"engine,omitempty"` // 空值 = chrome(向后兼容)
DeviceUDID string `json:"device_udid,omitempty"` // Safari Simulator UDID
DeviceName string `json:"device_name,omitempty"` // Safari 设备名
}
SessionInfo Chrome セッション情報(ファイルに永続化)。
func LoadSession ¶
func LoadSession(sessionID string) (*SessionInfo, error)
LoadSession セッションファイルを読み込む。
type SessionRef ¶
type SessionRef struct {
Ref string `json:"ref"` // "@r1", "@r2", ...
BackendNodeID int64 `json:"backend_node_id"`
Role string `json:"role"`
Name string `json:"name"`
TestID string `json:"testid,omitempty"`
Placeholder string `json:"placeholder,omitempty"`
Locator NodeLocator `json:"locator,omitempty"`
AXPath string `json:"ax_path,omitempty"`
StableKey string `json:"stable_key,omitempty"`
}
SessionRef セッション内の要素 ref エントリ。
type SessionState ¶
type SessionState struct {
Mode string `json:"mode"` // "observe" / "takeover" / "idle" / "loading"
Owner string `json:"owner"` // 当前 takeover 持有者 connID
LeaseToken string `json:"leaseToken"` // owner 的租约令牌
LeaseExpiry int64 `json:"leaseExpiry"` // 租约过期时间戳(毫秒)
Viewport struct {
CssW int `json:"cssW"`
CssH int `json:"cssH"`
} `json:"viewport"`
Cursor string `json:"cursor"` // 远端 cursor 样式
URL string `json:"url"` // 当前页面 URL
Title string `json:"title"` // 当前页面标题
Seq int64 `json:"seq"` // 单调递增序列号(原子递增)
TargetCount int `json:"targetCount,omitempty"` // 已知 page Target 数量 [r3]
Tabs []TabInfo `json:"tabs,omitempty"` // 完整 tab 列表 [TH-0414-b3m]
Recording bool `json:"recording,omitempty"` // 当前是否正在录制 [CAP-BS09-C3 §6.bis]
RecordElapsedMs int64 `json:"record_elapsed_ms,omitempty"` // 录制已用时间(毫秒)
}
SessionState 是 BrowserSession 的权威状态。 由 SessionAuthority 持有并管理,通过 channel fan-out 广播给所有 WS subscriber。
type SiteDataClearResult ¶
type SiteDataInfo ¶
type SiteDataInfo struct {
URL string `json:"url"`
Origin string `json:"origin"`
Host string `json:"host"`
Protocol string `json:"protocol"`
Secure bool `json:"secure"`
CookieCount int `json:"cookie_count"`
CookieBytes int64 `json:"cookie_bytes"`
LocalStorageKeys int `json:"local_storage_keys"`
SessionStorageKeys int `json:"session_storage_keys"`
Clearable bool `json:"clearable"`
UnsupportedReason string `json:"unsupported_reason,omitempty"`
}
SiteDataInfo describes storage tied to the active page origin. It is intentionally origin-scoped so Browser Portal can clear the current site's state without touching other profiles or unrelated domains.
type SnapOptions ¶
type SnapOptions struct {
// Selector: CSS 选择器,仅返回该元素的后代节点 (SC-20)。空字符串=全页面。
Selector string
// Compact: 仅保留可交互 role 的元素 (SC-21)。
Compact bool
// MaxDepth: A11y 树 DFS 最大深度 (SC-21),0=不限。
MaxDepth int
// SessionMode: true 时使用 @rN ref(session 模式)。
SessionMode bool
// SnapEpoch: session 模式快照序号(仅 SessionMode=true 时有效)。
SnapEpoch int
}
SnapOptions 控制快照过滤和格式化行为。
type Snapshot ¶
type Snapshot struct {
PageTitle string
URL string
TargetID string // CDP target.ID that produced this snapshot, when known
Text string // compact A11y 文本(含 Element Refs)
Refs []ElementRef // 可交互元素列表(DFS 顺序)
SnapshotType string // "a11y" | "dom_fallback" | "screenshot_fallback" | "progressive_loading"
TokenEst int // 估算 token 数
Progressive bool // true 表示页面可观测但暂不可稳定操作,调用方应稍后重试 action view
LoadState string // "actionable" | "readable" | "visual" | "loading" | "waiting_for_app" | "unavailable"
ReadyState string // document.readyState: "loading" | "interactive" | "complete" | ""
RetryAfterMillis int // 建议调用方下一次刷新 action view 的最小等待时间
ProgressReason string // 渐进状态原因,面向日志和 CLI 输出
Diagnostics map[string]interface{}
}
Snapshot 是页面语义快照(不可变)。
type StableKey ¶
type StableKey struct {
ID string
AriaLabel string
Name string
Role string
Href string
Type string
}
StableKey is the stable key descriptor for a SuperNode. Deprecated: kept for compat.
type SuperNode ¶
type SuperNode struct {
ID int
TagName string
Text string
Clickable bool
Box Box
StableKey StableKey
}
SuperNode is a stable node descriptor from the old browser architecture. Deprecated: kept for compat with internal/desktop.
type TabHandle ¶
type TabHandle struct {
TargetID string // CDP TargetID
IdentityKey IdentityKey // 来自 IdentityRegistry
WorkspaceID string // 任务隔离 (跨 ws 同 identity 复用 Chrome 但 Tab 隔离)
Role TabRole
SessionID string // BrowserSession 三层架构 SessionID (CAP-C3); Phase_v2_2 暂为空串
AcquiredAt time.Time // Pool.AcquireTab 创建时戳 (诊断用)
}
TabHandle — Tab 四元身份 (CAP §2.bis lines 127-133).
不变式:
- TargetID 唯一 (TabIndex 注册时校验, 重复 → ErrTabAlreadyRegistered).
- IdentityKey 来自 IdentityRegistry.Resolve (上层拿到后透传, 不修改).
- WorkspaceID 任务隔离维度 — 不影响 Chrome 资源边界 (T5 §0.3).
- Role 必须 IsValidRole(r) == true (Pool 入口校验).
type TabIndex ¶
type TabIndex interface {
// Register 注册一个 Tab. 同 TargetID 第二次 Register → ErrTabAlreadyRegistered.
Register(handle *TabHandle) error
// Lookup 反查 TargetID 对应的 TabHandle. 不存在 → (nil, false).
Lookup(targetID string) (*TabHandle, bool)
// Unregister 注销 Tab. 不存在的 TargetID → ErrTabNotFound.
Unregister(targetID string) error
// ByIdentity 列出某 identity 下所有 Tab (按 TargetID 字典序; 副本).
ByIdentity(key IdentityKey) []TabHandle
// ByWorkspace 列出某 ws 下所有 Tab (按 TargetID 字典序; 副本).
ByWorkspace(ws string) []TabHandle
// Snapshot 全量索引快照 (按 IdentityKey 字典序 → 内层按 TargetID 字典序).
// 不含 ChromePID (Pool 注入); IdentityPoolStatus.ChromePID 在 Pool.Inspect 阶段填充.
Snapshot() []IdentityPoolStatus
// Len 返回当前注册的 Tab 总数 (诊断用).
Len() int
}
TabIndex — TargetID → *TabHandle 索引 (Pool 内部依赖, 业务不直接持有).
线程安全: 实现必须支持并发 Register / Lookup / Unregister / ByIdentity / ByWorkspace.
type TabInfo ¶
type TabInfo struct {
ID string `json:"id"` // CDP target.ID
Title string `json:"title"`
URL string `json:"url"`
Active bool `json:"active"` // 当前 screencast 是否指向此 tab
Closable bool `json:"closable"` // false = browser root target, cannot be closed through tab UI
}
TabInfo 描述一个浏览器标签页的元数据 [TH-0414-b3m]。
type TabRole ¶
type TabRole string
TabRole — Tab 角色枚举 (4 枚举之一, T5 §0.3 + D11 强约束).
不变式 (D11):
- RoleHuman Tab: Agent ActionEngine 直调必须被 InputGateway 拒绝.
- RoleAgent Tab: Human 可观察, 不可接管 (除 D10 受控 override).
- RoleCouncil Tab: 必须配合 Profile 前缀 "council-*" (Pool 校验, TC-09-U-42 P1).
- RoleBackground Tab: SyncManager 等长跑路径; 无 LiveView, 不接受 takeover.
type TakeoverMode ¶
type TakeoverMode string
TakeoverMode 是接管模式枚举。
const ( // TakeoverModeObserve — AI 控制,Human 监视。 TakeoverModeObserve TakeoverMode = "observe" // TakeoverModeTakeover — Human 接管,AI 操作被拒绝。 TakeoverModeTakeover TakeoverMode = "takeover" )
type TargetTracker ¶
type TargetTracker struct {
// contains filtered or unexported fields
}
TargetTracker 管理所有已知的 page Target,自动跟随活跃 Target 的 Screencast。
func NewTargetTracker ¶
func NewTargetTracker(browserCtx context.Context) *TargetTracker
NewTargetTracker 创建 TargetTracker。initialID 是 Chrome 启动时的第一个 tab。
func (*TargetTracker) ActiveTargetID ¶
func (tt *TargetTracker) ActiveTargetID() target.ID
ActiveTargetID 返回当前活跃 Target ID。
func (*TargetTracker) ActiveTargetRef ¶
func (tt *TargetTracker) ActiveTargetRef() (string, context.Context)
ActiveTargetRef returns the current target id and its CDP context atomically. Async operations must keep this id with their result; reading ActiveTargetID on completion can update the wrong tab if the user switched while the work ran.
func (*TargetTracker) CloseTarget ¶
func (tt *TargetTracker) CloseTarget(targetID string) error
CloseTarget 关闭指定 Target [TH-0414-b3m]。 不能关闭不可关闭 Target。关闭后 TargetTracker 的 HandleTargetDestroyed 会自动处理 fallback。
func (*TargetTracker) CreateTab ¶
func (tt *TargetTracker) CreateTab(url string) (string, error)
CreateTab 创建新标签页并切换 Screencast 到新 tab。 url 为空时默认 ChromeInitialPageURL。该 URL 只表示 Chrome 初始化页, 不能被上层当作用户导航意图。 返回新 Target ID。createTarget 产生的 tab 没有 OpenerID, HandleTargetCreated 不会自动切换 Screencast,因此显式调用 SwitchToTarget。
func (*TargetTracker) GetActiveCDPContext ¶
func (tt *TargetTracker) GetActiveCDPContext() context.Context
GetActiveCDPContext 返回当前活跃 Target 的 CDP context。 activeID 有值时返回该 Target 的 chromedp context;否则返回 browserCtx(primary target)。
func (*TargetTracker) HandleTargetCreated ¶
func (tt *TargetTracker) HandleTargetCreated(info *target.Info)
HandleTargetCreated 处理新 Target 创建事件。 仅跟踪 type=page 的 Target。自动跟随必须通过归属协议判定: 当前 source target 的 OpenerID、Page.windowOpen(userGesture=true) 或 dispatch 成功后的本地 gesture claim。
func (*TargetTracker) HandleTargetDestroyed ¶
func (tt *TargetTracker) HandleTargetDestroyed(targetID target.ID)
HandleTargetDestroyed 处理 Target 关闭事件。活跃 Target 关闭时回退到上一个。
func (*TargetTracker) HandleTargetInfoChanged ¶
func (tt *TargetTracker) HandleTargetInfoChanged(info *target.Info)
HandleTargetInfoChanged 更新 Target 元数据(URL/Title 变化)。 关键: 处理 window.open(”) pendingSwitch 模式 — 空 URL 新标签拿到真实 URL 后立即切换 Screencast。
func (*TargetTracker) ListTargets ¶
func (tt *TargetTracker) ListTargets() []TabInfo
ListTargets 返回当前所有已知 page Target 的元数据列表 [TH-0414-b3m]。 返回值中 Active 标记当前 screencast 指向的 Target。
func (*TargetTracker) RecordUserGesture ¶
func (tt *TargetTracker) RecordUserGesture(event *InputEvent)
RecordUserGesture 记录一次已成功 dispatch 的 takeover 用户手势。 它是 opener-less target 归属的弱证据兜底,只在没有 opener/windowOpen 证据时使用。
func (*TargetTracker) RefreshTargets ¶
func (tt *TargetTracker) RefreshTargets() error
RefreshTargets reconciles TargetTracker state from Chrome's authoritative target list. It repairs missed TargetCreated/Destroyed events and is safe to call from REST handlers.
func (*TargetTracker) SetForegroundGuard ¶
func (tt *TargetTracker) SetForegroundGuard(fn func(target.ID, string) error)
SetForegroundGuard registers a fail-closed safety check before a target is activated or brought to front. macOS headed mode uses this to prove Chrome is still contained by CGVirtualDisplay before any foregrounding CDP command.
func (*TargetTracker) SetLiveEngine ¶
func (tt *TargetTracker) SetLiveEngine(engine *liveViewEngine, hub *FrameBroadcastHub)
SetLiveEngine 注入 liveViewEngine 和 hub(在 StartLiveView 后调用)。
func (*TargetTracker) SetOnCDPSwitch ¶
func (tt *TargetTracker) SetOnCDPSwitch(fn func(newCtx context.Context))
SetOnCDPSwitch 注册 CDP context 切换回调。 每次 Screencast 切换到新 Target 时调用,newCtx 是新活跃 Target 的 chromedp context。 用途: 通知 InputGateway 更新 cdpCtx,确保输入事件分发到正确的 Target(修复 popup/new-tab 导航卡住)。
func (*TargetTracker) SetOnJavaScriptDialog ¶
func (tt *TargetTracker) SetOnJavaScriptDialog(fn func(JavaScriptDialogEvent))
SetOnJavaScriptDialog registers the LiveView bridge for alert/confirm/prompt.
func (*TargetTracker) SetOnSwitch ¶
func (tt *TargetTracker) SetOnSwitch(fn func(url, title string, targetCount int))
SetOnSwitch 注册 Target 切换回调。
func (*TargetTracker) SetTargetCloser ¶
func (tt *TargetTracker) SetTargetCloser(fn func(target.ID) error)
func (*TargetTracker) SetupListeners ¶
func (tt *TargetTracker) SetupListeners(browserCtx context.Context)
SetupListeners 注册两类监听:
- browserCtx: Browser 级 TargetCreated/Destroyed/InfoChanged + discover/auto-attach
- tt.browserCtx: 当前 liveview primary target 的 Page.windowOpen/source-page 监听
关键约束:
- Browser 级 Target 事件必须绑定 browserCtx(entry.browserCtx),否则新 tab 可能漏收
- source page 的 windowOpen 证据必须绑定 primary target ctx(tt.browserCtx/tabCtx), 不能错误绑到 browserCtx,否则 Baidu 这类 opener-less page-opened target 会失去归属证据, 只能在 RefreshTargets() 时被动补登记
func (*TargetTracker) SwitchToTarget ¶
func (tt *TargetTracker) SwitchToTarget(targetID string) error
SwitchToTarget 手动切换 Screencast 到指定 Target [TH-0414-b3m]。 终局约束: Browser LiveView 的 tab 切换必须同步切换真实 Chrome 活跃 tab。 headed Chrome 的后台 tab 不稳定产帧,且 Input.dispatch* 在后台标签上不可依赖; 因此 Target.activateTarget 是语义的一部分。窗口隔离由 DisplayStrategy/CGVirtualDisplay 负责。
func (*TargetTracker) TargetCDPContext ¶
func (tt *TargetTracker) TargetCDPContext(targetID string) context.Context
func (*TargetTracker) TargetCount ¶
func (tt *TargetTracker) TargetCount() int
TargetCount 返回已知 page Target 数量。
func (*TargetTracker) UpdateTabInfo ¶
func (tt *TargetTracker) UpdateTabInfo(targetID string, url, title string) bool
UpdateTabInfo updates one concrete target. Async operations must use this with the target id captured at operation start, so completion cannot write into a newly active tab.
type TouchPoint ¶
TouchPoint 代表一个触摸点(多指触控时区分)。
type VirtualDisplayManager ¶
type VirtualDisplayManager struct{}
VirtualDisplayManager is a no-op stub on non-Darwin platforms.
On Linux, virtual display isolation is handled by Xvfb (:99) managed by DisplayManager. On Windows, the current strategy falls back to headless mode (CreateDesktop Win32 API is P2 scope — DELTA-BS09-THREE-MODE §8).
All methods are safe to call concurrently.
func (*VirtualDisplayManager) Close ¶
func (vdm *VirtualDisplayManager) Close() error
Close is a no-op on non-Darwin platforms. Always returns nil.
func (*VirtualDisplayManager) CountWindowsOutsideDisplay ¶
func (vdm *VirtualDisplayManager) CountWindowsOutsideDisplay(pid int) int
func (*VirtualDisplayManager) DisplayID ¶
func (vdm *VirtualDisplayManager) DisplayID() uint32
DisplayID returns 0 on non-Darwin platforms.
func (*VirtualDisplayManager) Ensure ¶
func (vdm *VirtualDisplayManager) Ensure() error
Ensure is a no-op on non-Darwin platforms. Always returns nil.
func (*VirtualDisplayManager) VerifyChromeContained ¶
func (vdm *VirtualDisplayManager) VerifyChromeContained(pid int, timeout time.Duration) error
func (*VirtualDisplayManager) WindowPosition ¶
func (vdm *VirtualDisplayManager) WindowPosition() (x, y int)
WindowPosition returns (0, 0) on non-Darwin platforms. Linux Chrome instances are positioned via DISPLAY=:99; absolute screen coordinates are managed by the window manager.
func (*VirtualDisplayManager) WindowPositionAt ¶
func (vdm *VirtualDisplayManager) WindowPositionAt(offset int) (x, y int)
WindowPositionAt returns (offset, offset) — helper for tests.
type VirtualDisplayWindowRescueRecord ¶
type VirtualDisplayWindowRescueRecord struct {
WindowID int `json:"window_id"`
PID int `json:"pid"`
Owner string `json:"owner"`
Title string `json:"title,omitempty"`
X int `json:"x"`
Y int `json:"y"`
Width int `json:"width"`
Height int `json:"height"`
TargetX int `json:"target_x,omitempty"`
TargetY int `json:"target_y,omitempty"`
TargetWidth int `json:"target_width,omitempty"`
TargetHeight int `json:"target_height,omitempty"`
Moved bool `json:"moved"`
Reason string `json:"reason"`
VirtualRatio float64 `json:"virtual_ratio"`
}
type VirtualDisplayWindowRescueResult ¶
type VirtualDisplayWindowRescueResult struct {
Platform string `json:"platform"`
DisplayID uint32 `json:"display_id,omitempty"`
ProtectedBrowserPIDs []int `json:"protected_browser_pids,omitempty"`
Scanned int `json:"scanned"`
Matched int `json:"matched"`
Moved int `json:"moved"`
Skipped int `json:"skipped"`
Windows []VirtualDisplayWindowRescueRecord `json:"windows"`
}
func RescueForeignWindowsFromVirtualDisplay ¶
func RescueForeignWindowsFromVirtualDisplay() (*VirtualDisplayWindowRescueResult, error)
type Workspace ¶
type Workspace interface {
// EnsureSpace ensures an isolated workspace exists and returns its ID.
// On macOS: returns a non-current Space ID (Human must have ≥2 Spaces).
// On Linux/Windows: returns (0, nil) — no Space concept needed.
// Idempotent.
EnsureSpace() (int64, error)
// LaunchChromeInSpace forks Chrome inside the isolated workspace,
// waits for CDP ready (with postcondition window-bound check on macOS),
// and returns a ChromeHandle owning the process.
//
// On error, no process is leaked (the partial fork is killed before return).
LaunchChromeInSpace(spec ChromeLaunchSpec) (ChromeHandle, error)
// Close releases workspace resources (does NOT destroy user Spaces and
// does NOT kill outstanding ChromeHandles — caller owns those).
Close() error
}
Workspace manages an isolated OS workspace (Space/VDesktop/Xvfb) for **visible** Chrome instances. Headless Chrome does not need this and MUST NOT go through this interface.
func NewWorkspace ¶
func NewWorkspace() Workspace
NewWorkspace returns a no-op Workspace for Linux. Actual isolation is provided by DisplayManager.ensureDisplayLinux (Xvfb).
Source Files
¶
- action_engine.go
- browser_core_impl.go
- browser_mux_host.go
- browser_runtime_processes.go
- browser_session.go
- chrome_handle.go
- chrome_handle_unix.go
- chrome_launcher.go
- chrome_supervisor.go
- chromedp_logging.go
- compat.go
- cookie_importer.go
- cookie_importer_crypto.go
- cookie_importer_linux.go
- core.go
- display_manager.go
- errors.go
- factory.go
- fingerprint.go
- fingerprint_runtime.go
- frame_broadcast_hub.go
- identity.go
- identity_registry.go
- input_gateway.go
- liveview_engine.go
- observe.go
- pool.go
- profile_launch_hygiene.go
- profile_manager.go
- record_buffer.go
- runtime_policy.go
- session_contract.go
- session_manager.go
- site_data.go
- snapshot_engine.go
- startup_recovery.go
- startup_recovery_unix.go
- tab_index.go
- takeover_controller.go
- target_graph.go
- target_tracker.go
- virtual_display_other.go
- virtual_display_rescue.go
- virtual_display_rescue_other.go
- workspace.go
- workspace_linux.go
Directories
¶
| Path | Synopsis |
|---|---|
|
compat.go provides backward-compatible stubs for types used by internal/desktop and internal/skill that were in the old browser package.
|
compat.go provides backward-compatible stubs for types used by internal/desktop and internal/skill that were in the old browser package. |
|
Package audit 提供引擎无关的浏览器审计框架。
|
Package audit 提供引擎无关的浏览器审计框架。 |
|
Package safari wraps the ax-bridge.swift native binary which reads iOS Simulator accessibility trees via the macOS AXUIElement API.
|
Package safari wraps the ax-bridge.swift native binary which reads iOS Simulator accessibility trees via the macOS AXUIElement API. |