Pin each chat's PR so panels stop converging on one PR

Two live effects made different chats' work panels show the same PR:
the windowed message fetch ages the posted PR link out of the loaded
history (losing the strongest per-chat signal), and agents reuse a
worktree across chats in one project, so branch discovery resolves
several chats to the same pull request.

Each chat now pins the PR it resolves (localStorage): a link posted in
the chat always wins and re-pins, the pin covers revisits after the
link leaves the window, and branch discovery only runs for chats with
no posted link and no pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
klopez4212
2026-07-05 08:30:10 +01:00
parent 73340ac6ce
commit 2f4867619f
2 changed files with 43 additions and 2 deletions

View File

@@ -143,3 +143,33 @@ export function useChatWorkAutomation(chatId: string): ChatWorkAutomation {
return state;
}
const PR_STORAGE_PREFIX = "buzz:chat-work-pr:v1";
/**
* The PR pinned to a chat. Posted links age out of the windowed message
* fetch and branch discovery can resolve several chats sharing a reused
* worktree to the same PR — the pin keeps each chat on the PR it actually
* resolved first, with posted links always overriding.
*/
export function readChatPinnedPr(chatId: string): string | null {
if (typeof window === "undefined") {
return null;
}
try {
return window.localStorage.getItem(`${PR_STORAGE_PREFIX}:${chatId}`);
} catch {
return null;
}
}
export function writeChatPinnedPr(chatId: string, href: string) {
if (typeof window === "undefined") {
return;
}
try {
window.localStorage.setItem(`${PR_STORAGE_PREFIX}:${chatId}`, href);
} catch {
// Best-effort.
}
}

View File

@@ -11,8 +11,10 @@ import {
} from "lucide-react";
import {
readChatPinnedPr,
updateChatWorkAutomation,
useChatWorkAutomation,
writeChatPinnedPr,
} from "@/features/chats/lib/chatWorkAutomation";
import {
type GithubCheckSummary,
@@ -83,11 +85,20 @@ export function ChatWorkPanel({
// hidden panel stops polling entirely.
const monitorActive =
open || automation.autoFixCi || automation.addressComments;
// Pin resolution order: a link posted in THIS chat wins, then the chat's
// previously pinned PR, then branch discovery — discovery alone is
// ambiguous when agents reuse a worktree across chats in one project.
const pinnedHref = React.useMemo(() => readChatPinnedPr(chatId), [chatId]);
const discoveredPrQuery = useGithubPrForBranchQuery(
monitorActive && !prHref ? projectPath : null,
monitorActive && !prHref && !pinnedHref ? projectPath : null,
branch,
);
const effectiveHref = prHref ?? discoveredPrQuery.data ?? null;
const effectiveHref = prHref ?? pinnedHref ?? discoveredPrQuery.data ?? null;
React.useEffect(() => {
if (effectiveHref && effectiveHref !== readChatPinnedPr(chatId)) {
writeChatPinnedPr(chatId, effectiveHref);
}
}, [chatId, effectiveHref]);
const preview = effectiveHref
? parseSupportedLinkPreview(effectiveHref)
: null;