Skip to content

cookie-picker UI dies mid-flow: parent-PID watchdog kills server ~15s after CLI exits #985

@karolzdebel

Description

@karolzdebel

Summary

$B cookie-import-browser opens a picker UI served by the browse server, but the parent-PID watchdog kills that server shortly after the spawning CLI exits. Users interacting with the picker UI hit Failed to fetch on import.

Repro

  1. $B cookie-import-browser — picker opens at http://127.0.0.1:<port>/cookie-picker.
  2. Interact with the picker UI (scan domains, search, etc.).
  3. Click + to import a domain.
  4. UI shows Import failed for <domain>: Failed to fetch.

Root cause

Two patches landed close together and their interaction wasn't exercised:

  • Parent-PID watchdog added in browse/src/server.ts:753-768 (commit 03973c2f, fix: community security wave — 8 PRs, 4 contributors (v0.15.13.0) #847, v0.15.13.0). Polls BROWSE_PARENT_PID every 15s and calls shutdown() when the parent is gone.
  • cli.ts:229 always sets BROWSE_PARENT_PID = String(process.pid) — i.e., the CLI's own pid. The CLI exits as soon as cookie-import-browser returns the picker URL, so the next watchdog tick kills the server.
  • The picker UI's subsequent fetch() calls then fail. The 30-min IDLE_TIMEOUT_MS never gets a chance to apply.

The watchdog polls every 15s, so the kill fires 0–15s after the CLI exits. Any picker interaction past that point fails. Likely slipped past testing because a fast click-through (import the first domain in the initial list) can land before the first tick; real use (scanning domains, searching) gives it time to fire.

Proposed fix (by Claude Code)

Let the watchdog skip shutdown while the picker has unexpired codes or sessions. Two-file change:

browse/src/cookie-picker-routes.ts — export state check:

export function hasActivePicker(): boolean {
  const now = Date.now();
  for (const [code, expiry] of pendingCodes) {
    if (expiry > now) return true;
    pendingCodes.delete(code);
  }
  for (const [session, expiry] of validSessions) {
    if (expiry > now) return true;
    validSessions.delete(session);
  }
  return false;
}

browse/src/server.ts — consult it in the watchdog:

} catch {
  if (hasActivePicker()) return;
  console.log(`[browse] Parent process ${BROWSE_PARENT_PID} exited, shutting down`);
  shutdown();
}

Bounded by the existing 1-hour SESSION_TTL_MS, so orphan risk on Windows stays small. Tested locally: server stays up for the picker flow, shuts down normally after session expiry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions