Skip to main content

State

Struct State 

Source
pub struct State {
Show 13 fields pub lifecycle: LifecyclePhase, pub processes: HashMap<u32, ProcessRecord>, pub windows: HashMap<String, WindowMirror>, pub pool: HashSet<String>, pub instance_registry: HashMap<String, u32>, pub next_instance_num: u32, pub backend_window_ids: HashMap<String, String>, pub event_version: u64, pub next_client_id: u64, pub monitors: Vec<Rect>, pub pending_hwnds: HashMap<u64, PendingHwnd>, pub just_promoted_labels: HashSet<String>, pub background_service_enabled: bool,
}
Expand description

Top-level launcher state. Single Arc<Mutex> owned by the IPC server; passed into update(state, cmd, conn) for every incoming command.

Fields§

§lifecycle: LifecyclePhase§processes: HashMap<u32, ProcessRecord>

Keyed by PID. Multiple records per PID would be a bug — the reducer enforces unique-pid on insert.

§windows: HashMap<String, WindowMirror>

Read-only window mirror (Phase B.4). Keyed by label. Source of truth still lives in agentmux-cef::AppState.browsers / window_meta; this is a passive copy fed by host ReportWindow* commands. B.5 inverts the dependency: host queries this map instead of maintaining its own.

§pool: HashSet<String>

Phase B.4 follow-up — pre-warmed pool inventory. Tracked separately from windows because pool entries are not user-visible until promote. On promote the host emits ReportPoolWindowRemoved + ReportWindowOpened so the same label transitions atomically (from launcher’s perspective) from pool to windows. On pre-promote destroy: only ReportPoolWindowRemoved.

§instance_registry: HashMap<String, u32>

Phase B.5 — authoritative window instance registry. Maps label → sequential instance number (1 for “main”, 2 for the second window opened, etc.). Numbers are never reused within a launcher run — when a window closes the entry is removed but next_instance_num keeps advancing. Sole source of truth post-B.5e (host’s WindowInstanceRegistry was deleted in PR #584); host holds a passive shadow projection in agentmux-cef::AppState.shadow_instance_registry. Updated by the same reducer paths that mutate windows.

§next_instance_num: u32

Next instance number to assign. Starts at 2 — “main” is pre-seeded with 1 in Default (matching host’s WindowInstanceRegistry::new behavior so a synthetic main open wouldn’t collide).

§backend_window_ids: HashMap<String, String>

Phase B.5 (window_id_map step a) — authoritative label → backend window ID map. Mirrors host’s existing agentmux-cef::AppState.window_id_map. Populated by Command::ReportBackendWindowIdRegistered (sent from host when the frontend calls register_backend_window IPC after init); drained by ReportBackendWindowIdUnregistered on close. Will become host-side authoritative through the standard a→b→c→d→e ratchet.

§event_version: u64

Monotonic counter for Event.version. Bumped by bump_version().

§next_client_id: u64

Monotonic counter for client_id (returned in Registered events).

§monitors: Vec<Rect>

Phase B.9.1 (WRR) — current monitor topology, replaced wholesale on ReportMonitorTopologyChanged. Empty by default until the host’s wrr/win_event.rs reports its one-time initial topology probe at startup (WM_DISPLAYCHANGE updates are not wired yet). OffMonitor drift is suppressed when this is empty — we don’t know enough to classify yet.

§pending_hwnds: HashMap<u64, PendingHwnd>

Phase B.9.1 — HWNDs the reducer has seen via ReportHwndOpened but couldn’t yet associate with a WindowMirror. Three reasons an entry lives here transiently:

  1. The OS create event raced ahead of the host’s OnAfterCreated → ReportWindowOpened chain.
  2. The host couldn’t determine label_hint at create time.
  3. The HWND belongs to a pool window not yet promoted. Drained on each ReportWindowOpened (we try to match a pending HWND by label_hint/timing). Anything still here after a follow-up event is classified as HwndWithoutBrowser.
§just_promoted_labels: HashSet<String>

Drift-storm fix (PR #708 round 3) — labels for which the host emitted ReportPoolWindowPromoted but the corresponding ReportWindowOpened hasn’t arrived yet. The actual host emit order on tear-off is ReportPoolWindowRemoved → ReportPoolWindowPromoted → ReportWindowOpened, so at promote-time the launcher has NO WindowMirror for the label — the mirror is created by ReportWindowOpened a few ms later. Without this set, the post-promote mirror is initialized with foregrounded_since_open: false, the open-transient drift detector then fires HiddenSinceOpen on every visible→hidden flicker during HWND repositioning, the host fans each event out across the bridge and the renderer’s V8 isolate crashes. ReportWindowOpened consumes the entry to initialize the new mirror with foregrounded_since_open: true. Removed on ReportWindowClosed if open never arrived (bounded leak). See docs/specs/ANALYSIS_DRIFT_STORM_RENDERER_CRASH_2026-05-06.md.

§background_service_enabled: bool

Workstream 0 Phase 1 (SPEC_TRAY_OPTIONAL_BACKGROUND_SERVICE_2026_09_04.md §7) — mirrors the host’s AGENTMUX_BACKGROUND_SERVICE opt-in, set once via Command::ReportBackgroundServiceEnabled right after connect. Defaults false (today’s behavior unchanged) until the host reports otherwise. Consulted by handle_report_window_closed and wrr’s crash-detected twin so an intentionally-resting host (zero windows, by design) doesn’t get classified as OrphanInstance and arm the teardown_backstop — see PR #2983 review (Codex P2): without this, a host correctly staying alive on purpose would still get its whole process tree killed by the backstop after a transient UI-thread probe hiccup, since “armed” would otherwise last for the entire (now potentially long) resting period instead of the few seconds it used to.

Implementations§

Source§

impl State

Source

pub fn bump_version(&mut self) -> u64

Bump and return the new event version. Always called inside the reducer when constructing an Event so version numbers stay strictly monotonic.

Strict (non-wrapping) add: Phase D’s GetSnapshot resync protocol relies on monotonicity (event.version > snapshot.version), and a wrap to 0 would silently break that contract. u64 at one event/ns would take 584 years to overflow — never going to happen in practice; if it ever does, the panic is the right failure mode. (gemini MEDIUM PR #574 round-1.)

Source

pub fn alloc_client_id(&mut self) -> u64

Bump and return the next client_id. Client IDs are stable per launcher run; not persisted across restart. Same strict- add reasoning as bump_version.

Trait Implementations§

Source§

impl Debug for State

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for State

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for State

§

impl RefUnwindSafe for State

§

impl Send for State

§

impl Sync for State

§

impl Unpin for State

§

impl UnsafeUnpin for State

§

impl UnwindSafe for State

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> NoneValue for T
where T: Default,

§

type NoneType = T

§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more