Releases: winoooops/herdr-agent-watcher
Release list
v0.2.8
- feat(sidebar): export format for embedders
herdr's trace detail panel needs duration_ms and age. Keeping format
crate-private forces embedders to reimplement them, and a second
implementation drifts from what the cards render.
- feat(sidebar): export style and per-card trace spans
A host embedding the cards needs both: CardCtx names
style::AgentAppearances, so a card cannot be built without that module,
and a host that draws the cards has to hit-test their trace rows.
expanded_card_with_traces already computed the (toolUseId, line) pairs
and expanded_card discarded them. Recovering row positions from the
rendered lines instead would be a second implementation of
selectable_call's rules, free to drift from the one that rendered them.
No behavior change; visibility only.
What's Changed
- feat(sidebar): export format for embedders by @winoooops in #4
Full Changelog: v0.2.7...v0.2.8
v0.2.7
- fix(kimi): bind lazily-created sessions
kimi-code creates its session at the FIRST prompt, not at process
start — measured 4m30s after launch on a live pane. The process-
ownership window required creation within 30s of the process start,
so both the index match and the bucket fallback rejected a perfectly
matching idle session (proc-fd short-circuits while kimi is active,
which is why only IDLE sessions flickered). The daemon then looped
bind -> fail -> remove every reconcile tick, rendering the flashing
unnamed kimi card in the sidebar.
The window is now one-sided: any session created at or after the
process start (minus clock slack) is process-owned. Sessions created
before the process remain rejected, and the resume path is unchanged.
Co-Authored-By: codex executor noreply@openai.com
- chore: 0.2.7
Fixes the flickering unnamed kimi card in the sidebar: kimi-code
creates its session at the first prompt — potentially minutes after
the process starts — but the session locator only accepted sessions
created within 30 seconds of process start. Idle kimi sessions were
therefore rejected on every locate, and the daemon looped
bind/fail/remove once per second, flashing a half-built card. The
ownership window is now one-sided (created at or after process start),
stale sessions from earlier runs are still rejected, and resumed
sessions bind exactly as before.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- fix(kimi): resolve sessions by the reported id, end-to-end
The locate trait has always carried a session identifier, but the
production chain passed the PANE id and the kimi locator ignored the
parameter entirely — inferring sessions from cwd and process
ownership. With the ownership window one-sided, two kimi processes
sharing a cwd could cross-bind. The herdr-reported session id (byte-
identical to session_index.jsonl's sessionId and the session dir name)
now flows from SidecarAdapter::bind through the watcher lifecycle into
the kimi locator, which resolves it first: trusted exact index match,
then a bounded bucket scan. A reported id with no on-disk match is a
retryable error, never an inference — and the supervisor's refresh
keeps the reported session rather than re-inferring. Legacy callers
without a reported id keep the inference chain unchanged.
Addresses chatgpt-codex-connector review on PR #3 and the codex-verify
findings on the first attempt (id never plumbed; refresh bypass;
miss-fallback cross-bind).
Co-Authored-By: codex executor noreply@openai.com
Co-authored-by: codex executor noreply@openai.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com
What's Changed
- fix(kimi): bind lazily-created sessions by @winoooops in #3
Full Changelog: v0.2.6...v0.2.7
v0.2.6
- docs(spec): sidebar-trace-navigation
Design spec for trace interaction in the sidebar: l/h descend into and
return from an expanded card's traces, j/k walk the settled-call ring
(full ring while focused), o/Enter and mouse click-again open a detail
panel showing the retained args preview with width-aware scrolling.
Covers the pair-identity focus model (card + toolUseId), OpenTrace
outcome plumbing with the run loop as single resolver, sub-card span
export with newest-first dedup, honest cross-card reflow, settled-only
data reality, and the test plan.
Written via /lifeline:planner with per-section codex review (6 section
passes, 20 findings applied).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(spec): apply codex feedback
Final whole-spec pass: l becomes an EnterTraces outcome resolved by the
run loop against the canonical ring (rendered geometry cannot pick a
hidden selectable row); the when-line freezes at open so the minute
tick never rewrites panel text; l is inert inside the trace zone (only
zone entry and j/k reattach); every cursor-changing card click clears
trace focus (pane-unique ids could leak across cards); rows without an
exact done/failed status are display-only, enforcing the settled-only
guarantee instead of assuming it.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(spec): mark spec codex-reviewed
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(plan): sidebar-trace-navigation
Ten-task TDD plan for the trace-navigation spec: duration formatter,
pure trace hit-test, view geometry export with focus rendering,
pair-safe reconcile, key/mouse outcome plumbing, the frozen TraceDetail
panel with shared-width scrolling, the snapshot builder, the run-loop
resolver with row-granularity follow, and the help surface — each task
red-green with exact code and its own commit.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(plan): apply codex feedback
Plan-review round 1: expanded_card keeps its signature via a
_with_traces sibling (30+ callers); the e2e ViewInput literal joins
Task 3; reconcile takes the pre-rehome cursor and corrections re-render
synchronously; route_mouse test migration named; Row gains Clone,
cursor_mut its arm; Row::Text implements the spec's verbatim wrapping
(Note collapses indentation) with a genuinely width-sensitive scroll
test; the snapshot narrows to (title, rows) with a recorded spec
amendment; newest_selectable_id deduplicates before selecting; named
resolvers with happy-path/refusal tests; routed accepts outcome
variants as observable.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(plan): apply codex feedback round 2
Task boundaries made self-contained: the second ViewInput constructor
and the e2e literal are listed and staged; the focused full ring drops
the +N older remainder with a test; Task 4's test blocks match the
five-argument reconcile; import edits scheduled (LineSpan/trace_at,
qualified AutoExpand, serde_json::Value); the rows_text exhaustive
match gains its Text arm; wrap_verbatim splits hard newlines first with
a line_count test; the spec's snapshot sentence is amended before this
plan (not during implementation); missing §6 cases added (header-click
onto another card, q-close, collapse-drop reconcile, content-compared
snapshot survival, frozen when-line across differing now).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(spec): narrow the TraceDetail snapshot to rendered content
The panel model is a frozen (title, rows) pair; card id, agent label,
and tool_use_id were listed but never rendered or needed — the panel
opens from the selected card. Amended before plan finalization so the
plan implements the current spec, not an in-flight rewrite.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(plan): apply codex feedback round 3
view_input gains the trace-focus parameter with all four call sites
named; Panel/Row enter tui.rs scope via a module-level import; the
q/esc test drops its dead outer binding and the when-closure takes a
slice; the nonexistent offset accessor instruction is gone.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(plan): apply codex feedback round 4
Remove the last stale offset-accessor reference in Task 7.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- docs(plan): mark plan codex-reviewed
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- feat(sidebar): compact duration formatter
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): pure trace-row hit-test
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): export trace-row geometry and render trace focus
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): trace-focus state with pair-safe reconcile
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): trace-zone key transitions as outcomes
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): trace-aware mouse outcomes
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): frozen TraceDetail panel with verbatim width-aware scrolling
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): frozen trace snapshot builder
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): resolve trace outcomes and follow the selected row
Co-Authored-By: codex executor noreply@openai.com
- fix(sidebar): eager then_some in trace_at
Clippy unnecessary_lazy_evaluations, introduced by the plan's own Task 2
snippet; authorized as an out-of-task edit in the M5 fix cycle.
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): trace keys on the help sheet and trailer
Co-Authored-By: codex executor noreply@openai.com
- feat(sidebar): zone-aware key footer
The pinned footer names what the keys do right now: 'l traces' appears
only while the cursor card is expanded with a selectable trace (the
exact state where l acts, and it outlives 'x menu' when narrowing);
inside the trace zone the hints flip to 'o/↵ open · h back'. The footer
thereby doubles as a zone indicator. Spec §4 amended accordingly.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- chore: 0.2.6
Trace navigation for the sidebar: press l on an expanded card to enter
its traces (full 50-call ring), walk rows with j/k, open a frozen
detail panel with o/Enter showing status, timing, and the complete
retained args preview (pretty-printed JSON, scrollable at any width);
h returns to the cards. Mouse: click a trace row to deep-select, click
it again to open — extending 0.2.5's opt-in mouse support one level
deeper. The key footer is now zone-aware and doubles as an indicator,
advertising l only when it works and flipping to 'o open · h back'
inside the trace zone.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- fix(sidebar): canonical descendability and nonempty trace identities
Two chatgpt-codex-connector findings on PR #2, both judged valid
against the code-reviewer principles and fixed:
F1: the zone-aware footer computed descendability from rendered
trace_spans, so with trace_lines = 1 and a display-only newest row the
'l traces' hint hid while l still entered the hidden selectable row.
The footer now derives from the canonical ring via the same predicate
the resolver uses.
F2: an empty-string toolUseId passed as_str().is_some() and became a
selectable identity, and multiple empty-id rows deduplicated into one.
call_id() now treats empty as missing: display-only, never deduped,
never exported.
Consolidation: call_id / selectable_call / newest_selectable_id now
live once in view.rs; tui.rs imports them, removing the drift class
that caused F1.
Codex-Verify: cycle-1 pass
Closes-Codex-Threads: PRRT_kwDOT46cgc6fgAh6 PRRT_kwDOT46cgc6fgAh7
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com
Co-authored-by: codex executor noreply@openai.com
What's Changed
- feat(sidebar): trace navigation with detail panel and zone-aware footer by @winoooops in #2
New Contributors
- @winoooops made their first contribution in #2
Full Changelog: v0.2.5...v0.2.6
v0.2.5
Opt-in mouse support for the sidebar: set [cards] mouse = true (or
flip the new settings row) to click a card header to expand or collapse
it, click a card body to select it without collapsing, and scroll the
list with the wheel (3 lines per notch, matching herdr). The default
stays off so drag-to-select text keeps working out of the box, and
capture is released on every exit path — including the in-pane update
re-exec — so a crash or upgrade never leaves your shell with a stuck
mouse.
Also ships the previously unreleased context-percentage rounding fix
(#1) and a mouse-probe example for checking whether a terminal or
multiplexer forwards SGR mouse events to pane apps.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
What's Changed
New Contributors
Full Changelog: v0.2.4...v0.2.5
v0.2.4
The plugin can update itself. A new update action reinstalls the latest
release and restarts the daemon in one step, and the sidebar's Update panel
does the same without asking to be reopened afterwards. Both refuse on a
linked checkout -- that tree belongs to whoever is editing it.
The restart is confirmed rather than requested. herdr plugin action invoke
returns zero for accepting an action, not for finishing it, so an upgrade
whose daemon failed to boot used to read as success; the daemon's build is
now polled until the new version answers.
Two failures found while building it, both older than this release:
A daemon restart could end with no daemon at all. The incumbent needs up to
its Herdr read timeout to notice a shutdown request, which measured 4.36 s
against a four-second takeover deadline. The deadline is eight seconds now,
derived from the worst case rather than from the read timeout alone.
StateStream announced a reconnection as soon as a socket connected, before
any data proved the feed alive. A listener on its way out can accept one
last connection and close in silence, so the sidebar could report itself
reconnected and then hand its caller the disconnect. It waits for a line
now. This one sat directly under the restart-on-upgrade path added above.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
Full Changelog: v0.2.3...v0.2.4
v0.2.3
v0.2.2
Codex plan usage was labelled wrong on every account whose plan has no
five-hour window. Codex publishes the length of each window and we ignored
it, so a seven-day window was drawn as 5h and the 7d row never appeared.
Both data sources now route by the published length; older Codex builds,
which send no length, keep behaving exactly as they did.
The header lookup also went silent whenever a Codex session read or edited
the agent-watcher source, because it accepted any log row that merely
mentioned the header name -- including Codex echoing that source back. It
now scans a bounded number of rows and takes the first that parses.
Two tests cover ground 0.2.0 left open: shutdown with an agent actually
bound, which is the half that can leak threads, and the
enable-claude-bridge invocation, whose failure mode is silent -- the
generated hooks would call a subcommand that does not exist and exit zero.
Known, unrelated, and not fixed here: Kimi plan usage stops after its OAuth
token expires. The fetcher reads access_token without checking
expires_at and never refreshes, and the failure is logged below the
default level, so the bars just stop.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
Full Changelog: v0.2.1...v0.2.2
v0.2.1
v0.2.0
v0.1.9
Expanded cards now show how much of your plan you have spent. The 5h and 7d
windows sit at the top of the card, above the context and cache meters,
because a window that is nearly full is the thing that changes what you do
next. Claude and Codex report it with no setup; Kimi needs usage consent
enabled, since its numbers come from a network fetch; OpenCode does not
report it yet. Turn the whole display off with cards.plan_usage = false.
A window that has already ended now says ended instead of resets now.
The old wording was indistinguishable from a window resetting this second,
so a stale reading looked like a live one.
Resumed Kimi sessions no longer blink once per reconcile tick. The fallback
path did not look for a resume marker, so a resumed session unbound and
rebound roughly every second.
Release notes are now the body of this commit. Before, an empty body left
GitHub to generate notes from merged pull requests -- and this repository
merges release branches, so the notes were a compare link and nothing else.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
Full Changelog: v0.1.8...v0.1.9