StatusPoller
Defined in: src/poller.ts:86
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new StatusPoller(
store,herdr,onChange,onBlock,intervalMs?,reclassifyMs?,classify?,now?,probe?,stallCfg?,probeCheckMs?,onReady?,onActivity?,preview?,liveness?,onWorkingBlocked?,pruneHooks?,onStopWindow?,onHalt?,usageLimits?):StatusPoller
Defined in: src/poller.ts:206
Parameters
Section titled “Parameters”Pick<HerdrDriver, "list" | "read" | "readAsync">
onChange
Section titled “onChange”(id, status) => void
onBlock
Section titled “onBlock”(id, block) => void
intervalMs?
Section titled “intervalMs?”number = 1000
reclassifyMs?
Section titled “reclassifyMs?”number = 3000
classify?
Section titled “classify?”(text) => BlockReason
() => number
probe?
Section titled “probe?”(s) => TranscriptSignals
Both transcript-derived signals (stall snapshot + activity) for a running session, from a SINGLE read+parse of its JSONL. Defaults to reading the file; injectable in tests. One read feeds both the stall decision and the activity emit, so the transcript is no longer parsed twice per running agent per tick.
stallCfg?
Section titled “stallCfg?”StallConfig = DEFAULT_STALL
probeCheckMs?
Section titled “probeCheckMs?”number = 7000
onReady?
Section titled “onReady?”(id, ready) => void
Pushed when a session’s manual readyToMerge flag is auto-cleared on resume.
onActivity?
Section titled “onActivity?”(id, activity) => void
Pushed when a running session’s heartbeat or current activity changes.
preview?
Section titled “preview?”Partial<PreviewWiring>
Preview wiring: injectable for tests; defaults to real PreviewService + real scan/pick + config.previewSweepMs. Omit to leave preview disabled (existing poller tests that don’t pass this still work).
liveness?
Section titled “liveness?”Partial<LivenessWiring>
Claude-liveness wiring: injectable for tests; defaults to the real /proc scan
with a no-op onChange. Drives session:claude-alive so the UI only offers
Resume when the claude process is actually gone (husk shell).
onWorkingBlocked?
Section titled “onWorkingBlocked?”(id, working) => void
Pushed when a session enters/leaves the working-while-blocked display state
(herdr latched “blocked” but the TUI shows a live turn spinner). true fires
once per suppression episode, false when the episode ends — same tick as
(and before) any re-armed block emission.
pruneHooks?
Section titled “pruneHooks?”(activeIds) => void
Phase-1 (issue #704): prune the HookIngest ring buffers for sessions no longer
active, called from pruneInactive so dead sessions’ buffers don’t grow
unbounded by session count (Task-2 reviewer flag). Undefined ⇒ no-op (the
ingest module isn’t wired, e.g. in tests / flag off).
onStopWindow?
Section titled “onStopWindow?”((id, windowMs) => void) | undefined
Observe-only Stop↔herdr-done window emitter (issue #713), flag-gated. Called once per
resolved pairing with the SIGNED offset between a Stop hook and herdr’s done flip:
windowMs > 0 ⇒ Stop arrived first (stop-wins); windowMs <= 0 ⇒ herdr flipped first
(herdr-wins); windowMs === null ⇒ a done-flip never paired (no Stop within the
horizon). Pure measurement — never mutates status/routing. Defaults to a single
greppable [hooks] log line; tests inject a capturer.
onHalt?
Section titled “onHalt?”(id, haltReason, haltedAt) => void
Pushed when a session’s transcript signals a usage-limit halt at the
done transition. Wired in src/index.ts to emit session:halt.
Defaults to a no-op so existing tests that omit it still compile.
Optional (undefined ⇒ no-op) so callers can skip it with a positional
undefined after onStopWindow.
usageLimits?
Section titled “usageLimits?”Usage-limits service — provides the latest window percentages for the
corroboration check in classifyHalt. Injectable for tests; defaults to
a stub that returns fully-null limits (uncalibrated fallback).
Optional (undefined ⇒ stub) so callers can skip it.
limits
Section titled “limits”Returns
Section titled “Returns”StatusPoller
Methods
Section titled “Methods”acknowledgeStall()
Section titled “acknowledgeStall()”acknowledgeStall(
id):boolean
Defined in: src/poller.ts:1166
Manually clear a stall flag without re-arming it: broadcasts the clear but
keeps lastSig so maybeProbe’s once-per-episode guard suppresses an
immediate re-fire. The episode re-arms on its own when activity resumes
(the !isStalled path in maybeProbe calls clearBlock), so a later
genuine stall still surfaces. No-op (returns false) unless a stall is live.
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”boolean
activitySnapshot()
Section titled “activitySnapshot()”activitySnapshot():
Record<string,SessionActivity>
Defined in: src/poller.ts:620
Last-emitted activity signal per running session, for client bootstrap.
Returns
Section titled “Returns”Record<string, SessionActivity>
claudeAliveSnapshot()
Section titled “claudeAliveSnapshot()”claudeAliveSnapshot():
Record<string,boolean>
Defined in: src/poller.ts:393
Last-swept claude-process liveness per session, for client bootstrap.
Returns
Section titled “Returns”Record<string, boolean>
ingestActivity()
Section titled “ingestActivity()”ingestActivity(
id,ev):void
Defined in: src/poller.ts:637
Phase-1 push activity (issue #704), fed by HookIngest.onSignal for both
PostToolUse (status:"ok") and PostToolUseFailure (status:"error"). Builds
a SessionActivity from the tool name + a windowed heat-strip tick and routes it
through the existing dedup emitActivity — the SAME sink the poll path uses, so
push + poll never bypass the dedup or oscillate. A PostToolUse push carries a
REAL tool summary (vs. the interim heartbeat’s summary:null), so it beats the
interim emit on the freshness guard below.
No-op when config.hooksSignals is off (the sink is never wired in that case, so
this is belt-and-suspenders for direct callers/tests). Records lastHookActivityAt
so maybeProbe knows the push path is fresh.
Parameters
Section titled “Parameters”string
status?
Section titled “status?”"ok" | "error"
toolName?
Section titled “toolName?”string
number
Returns
Section titled “Returns”void
ingestNotification()
Section titled “ingestNotification()”ingestNotification(
id,type):void
Defined in: src/poller.ts:680
Phase-1 push notification (issue #704), fed by HookIngest.onSignal for
Notification events. An awaiting-input type (see BLOCK_NOTIFICATION_TYPES) sets a
marker consumed by reconcileAgent to classify THIS tick — surfacing the block
≤ ~1 tick after the agent asks, independent of herdr’s latchy blocked status.
idle_prompt clears the marker (idle is handled by herdr mapping; never force a
block). Any other type is a no-op here — unknown types are already logged upstream,
and an awaiting-input edge we haven’t confirmed simply stays on the existing
herdr-blocked → classifyBlocked fallback (no regression).
No-op when config.hooksSignals is off.
Parameters
Section titled “Parameters”string
string
Returns
Section titled “Returns”void
ingestSessionStart()
Section titled “ingestSessionStart()”ingestSessionStart(
id):void
Defined in: src/poller.ts:696
Phase-2 push lifecycle (issue #709): a SessionStart hook confirms the agent booted.
Flips claude-liveness → true immediately (ahead of the throttled liveness sweep),
reusing the sweep’s own map + flip-dedup so push + poll never double-emit. Boot
liveness is monotonic (true until exit), so this cannot oscillate with the sweep,
which will agree (the process is alive — the hook fired from inside it). No-op when
config.hooksSignals is off.
(Stop/SessionEnd consumption is deferred to #713 — observe-only this phase.)
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”void
ingestStopMeasure()
Section titled “ingestStopMeasure()”ingestStopMeasure(
id,stopAt):void
Defined in: src/poller.ts:715
Observe-only Stop measurement (issue #713), fed by HookIngest.onSignal for Stop
events. Records the Stop’s receive time as one half of the Stop↔herdr-done pairing.
If a done-flip is already pending within the horizon, herdr won this turn’s race —
emit the (≤0) window immediately and clear the pending done. Otherwise park the Stop
so the next done-flip in measureStopWindow can pair it (a stale prior pending stop
is silently overwritten — Stop is a per-turn edge, only the latest matters).
Pure measurement: never touches status, routing, or any block/activity state — polling
stays authoritative. No-op when config.hooksSignals is off.
Parameters
Section titled “Parameters”string
stopAt
Section titled “stopAt”number
Returns
Section titled “Returns”void
start()
Section titled “start()”start():
void
Defined in: src/poller.ts:1314
Returns
Section titled “Returns”void
stop()
Section titled “stop()”stop():
void
Defined in: src/poller.ts:1317
Returns
Section titled “Returns”void
tick()
Section titled “tick()”tick():
void
Defined in: src/poller.ts:321
Returns
Section titled “Returns”void
workingBlockedSnapshot()
Section titled “workingBlockedSnapshot()”workingBlockedSnapshot():
Record<string,boolean>
Defined in: src/poller.ts:398
Sessions currently in the working-while-blocked display state, for client bootstrap.
Returns
Section titled “Returns”Record<string, boolean>