fix(review round 2): daemon symlink tars, orphan-safe removes, unique seed names, git ctx, IsErrNotFound, collision-free slugs, branch validation; web first-run WS, draft reset, IME guard, churn fix, test swap repair; 106 daemon + 190 web tests green

This commit is contained in:
Raphael Westphal
2026-08-18 19:13:51 +02:00
parent 95d2b5da4b
commit 66c90e48bb
22 changed files with 1476 additions and 964 deletions
+10 -2
View File
@@ -76,6 +76,10 @@ export default function ChatView({ store, pushToast }: Props) {
setEvents([]);
setHasOlder(false);
lastSeqRef.current = 0;
// a draft (or stuck sending state) from the previous session must not
// leak into the new one
setDraft("");
setSending(false);
let alive = true;
void (async () => {
try {
@@ -96,11 +100,13 @@ export default function ChatView({ store, pushToast }: Props) {
};
}, [sessionId, applyEvents]);
// ws subscription
// ws subscription: dep on store.subscribe (stable per manager) rather than
// the whole store object — every sessions-list change would otherwise
// churn unsubscribe/resubscribe and can drop events in the gap
useEffect(() => {
if (sessionId.length === 0 || store.state !== "open") return;
return store.subscribe(sessionId, applyEvents);
}, [sessionId, store.state, store, applyEvents]);
}, [sessionId, store.state, store.subscribe, applyEvents]);
// missed events after reconnect (persisted only); a response for a
// previous session must not merge here nor touch the cursor (S1)
@@ -187,6 +193,8 @@ export default function ChatView({ store, pushToast }: Props) {
};
const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {
// IME composition: Enter confirms the candidate window, not a send
if (e.nativeEvent.isComposing) return;
if (e.key === SEND_KEY && !e.shiftKey) {
e.preventDefault();
void send();