- Auto-connect WebSocket on page load in service console - Settings modal for editing sgclaw_config.json (API key, base URL, model, skills dir, etc.) - UpdateConfig/ConfigUpdated protocol messages for remote config save - save_to_path() for SgClawSettings serialization - ConfigUpdated handler in sg_claw_client binary - Protocol serialization tests for new message types - HTML test assertions for auto-connect and settings UI - Additional pending changes: deterministic submit, org units, lineloss xlsx export, browser script tool, and docs 🤖 Generated with [Qoder][https://qoder.com]
2.5 KiB
2.5 KiB
Helper Page Lifecycle Fix v2 — Same-Connection Close + Open
Date: 2026-04-14 Status: Approved
Problem
Two issues remain after v1:
- Process restart leaves orphaned helper pages: When the sg_claw process restarts, the old helper page tab remains open in the browser. The new process opens another one.
- Helper page is visible: Uses
sgBrowerserOpenPage(visible tab API) instead ofsgHideBrowerserOpenPage(hidden domain API).
Root Cause of v1 Failure
The v1 close_helper_page function created a second WebSocket connection to the browser during Drop. This likely conflicted with the existing bootstrap connection, causing the browser's WebSocket state to become confused.
Solution
Send the close command on the same WebSocket connection used for bootstrap, before sending the open command:
- Connect to browser WS
- Register as "web" role
- Blindly send
sgHideBrowerserClosePage(helper_url)— closes any orphaned page from a previous process run - Send
sgHideBrowerserOpenPage(helper_url)— opens the new helper page - Poll
/sgclaw/callback/readyfor page readiness
Both use_hidden_domain = true and the close+open logic are combined into a single change.
Why This Works
- Same connection: Only one WebSocket connection to the browser. No conflict with existing connections.
- Best-effort close: If no orphaned page exists (first run ever), the close command is silently ignored by the browser. This does not affect the subsequent open command.
- Fire-and-forget: Both close and open commands use the same fire-and-forget semantics as the existing bootstrap command.
API Reference
| API | Wire format | Effect |
|---|---|---|
sgHideBrowerserOpenPage (API #6) |
[requesturl, "sgHideBrowerserOpenPage", url] |
Opens in hidden domain |
sgHideBrowerserClosePage (API #68) |
[requesturl, "sgHideBrowerserClosePage", url] |
Closes hidden domain page |
Affected Files
| File | Change |
|---|---|
src/browser/callback_host.rs |
In bootstrap_helper_page: add close command before open command |
src/service/server.rs |
Change use_hidden_domain from false to true |
What Does NOT Change
callback_backend.rs—SHOW_AREA,build_commandunchangedsgBrowserExcuteJsCodeByDomainarea parameter — stays"show"- Helper page HTML content — unchanged
Drop for LiveBrowserCallbackHost— remains simple (shutdown only, no close attempt)cached_hostinmod.rs— remains lifted to outer loop