Four fixes from a branch-wide review of the hot paths:
- useChatWorkAutomation content-compares its snapshot: a fresh object
per storage event re-ran every consumer effect and re-rendered the
panel even when nothing changed.
- ChatMessageRow and ChatActivityTranscript are memoized: ChatDetail
re-renders on every observer frame during a live turn, and every
persisted message re-rendered its whole Markdown tree each time.
- The active-agent pubkey list is key-stabilized: the managed-agents
30s refetch minted a fresh array identity that resubscribed the
transcript store with an unchanged set.
- GitHub API commands share one reqwest client: the PR monitor polls
on short intervals and built a new connection pool + TLS session
cache per call.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The monitor went stale-empty overnight because every failure path
compounded: the app usually launches without GITHUB_TOKEN in its env,
so all GitHub calls ran anonymous (60 req/h) while the panel polls
~180 req/h — rate-limited within minutes — and non-success responses
returned Ok(None), which the UI rendered as a confident "No checks /
0 open comments" instead of an error.
Three fixes: ambient_github_token falls back to `gh auth token`
(resolved once per process) so the desktop uses the CLI credential
that's actually on the machine; GitHub commands now return Err on
non-404 failures so React Query keeps the last good snapshot and
retries instead of overwriting it with nothing; and polling pauses
entirely while the drawer is closed — unless automation is armed,
which keeps watching in the background.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Preset cards: taller cards with breathing room between the icon and the
text block; the agent picker no longer lists the welcome guide's
managed instance next to the Default agent row (the duplicate Fizz);
the invite search now goes through useUserSearchQuery — the same
normalized, cached path the channel invite uses — instead of a raw
searchUsers call whose un-lowercased query could miss on relay search.
Work panel: when no PR link was ever posted in the chat, the panel now
discovers the pull request from the branch itself — a new
find_github_pr_for_branch command reads the project's origin remote
(ssh or https GitHub URLs), asks the pulls API for the branch head, and
falls back to scanning open PRs for fork-headed branches. The panel
runs this only while it has a branch + project directory and no posted
link, polling slowly so a PR opened mid-conversation surfaces on its
own.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The CI chip in the chat work panel is now a dropdown: the summary row
keeps the aggregate state plus a chevron, and expanding it lists each
check run with its own pass/fail/pending icon, followed by the two
automation checkboxes (moved out of their standalone chip).
The comment count now shows review threads still awaiting the PR
author's reply instead of the raw total — REST can't see GitHub's
resolved bit, so replying is what clears a thread. New
fetch_github_pr_comment_state command groups review comments into
threads and counts the ones whose last word isn't the author's; the
address-comments automation nudges on rises in that count and re-arms
once it returns to zero.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The work drawer becomes a PR monitor: a CI chip shows running (with
progress), failing (red, count), or passing (green) from the head
commit's check runs, alongside the PR's comment count — both polled
while the panel is mounted.
Two persisted per-chat checkboxes arm automation: "Auto-fix CI
failures" prompts the chat's agent to investigate and fix once a head
sha's checks settle red (one nudge per sha), and "Address comments &
resolve" prompts it to work through comments and replies, reply, and
resolve addressed threads whenever the comment count rises (watermarked
so it never repeats).
Adds fetch_github_check_summary and head sha/comment counts to the PR
fetch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Chat stream:
- Activity markers span the full conversation column (matching the
"Thought for Xs" row) instead of capping at 42rem.
- Own bubbles drop the redundant "You" header.
PR work panel: when the chat's agent posts a pull request, a module
docks top-right inside the chat area (conversation and composer shrink
to make room) showing the PR's source branch and the live PR card.
fetch_github_pull_request now returns head.ref for the branch chip.
Branch e2e repairs (both regressions pre-dated today):
- "Jump to latest" now re-asserts the bottom until row re-measurement
settles — a smooth jump aimed at a stale scrollHeight landed short
once grouped rows changed height estimates.
- Sidebar dnd gains a keyboard sensor with keyboard-aware collision
detection, and channel-assignment drop zones are disabled while a
section drag is active. The dnd e2e uses a viewport tall enough that
auto-scroll can't move the drop target mid-drag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR links in messages now show a live card instead of the static
preview: repo and PR number, PR title, current status (open / draft /
merged / closed with a matching state icon), additions in green,
deletions in red, and the files-changed count. The whole card links to
the PR.
Details come from the GitHub REST API via a new Tauri command —
anonymous for public repos, with GITHUB_TOKEN/GH_TOKEN attached when
the shell that launched the app has one. Any fetch failure (rate
limit, private repo without a token, offline) falls back to the
existing compact card.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The shared reqwest client had no timeout, so a stalled connection (e.g.
an expired VPN tunnel that blackholes packets) left relay bridge calls
pending forever — chat creation and message sends spun indefinitely with
no error surfaced. Relay requests now carry a 30s per-request deadline
and the shared client gets a 10s connect timeout (connect-phase only, so
media streaming stays unbounded).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>