Files
claw/docs/superpowers/specs/2026-04-14-helper-page-lifecycle-fix-v2-design.md
木炎 c60cd308ca feat: service console auto-connect, settings panel, and batch of enhancements
- 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]
2026-04-14 14:32:46 +08:00

2.5 KiB

Helper Page Lifecycle Fix v2 — Same-Connection Close + Open

Date: 2026-04-14 Status: Approved

Problem

Two issues remain after v1:

  1. 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.
  2. Helper page is visible: Uses sgBrowerserOpenPage (visible tab API) instead of sgHideBrowerserOpenPage (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:

  1. Connect to browser WS
  2. Register as "web" role
  3. Blindly send sgHideBrowerserClosePage(helper_url) — closes any orphaned page from a previous process run
  4. Send sgHideBrowerserOpenPage(helper_url) — opens the new helper page
  5. Poll /sgclaw/callback/ready for 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.rsSHOW_AREA, build_command unchanged
  • sgBrowserExcuteJsCodeByDomain area parameter — stays "show"
  • Helper page HTML content — unchanged
  • Drop for LiveBrowserCallbackHost — remains simple (shutdown only, no close attempt)
  • cached_host in mod.rs — remains lifted to outer loop