From 8dfc27925804e1a1b51eaf1afc53892ebc77ae71 Mon Sep 17 00:00:00 2001 From: Kenneth Lien Date: Thu, 26 Mar 2026 23:12:19 -0700 Subject: [PATCH] imessage: harden echo filter normalization The self-chat echo filter matches outbound text against what chat.db stores on round-trip. Three divergence sources caused false negatives and duplicate bubbles: - Signature suffix: "\nSent by Claude" is appended on send, but the \n may not round-trip identically through attributedBody - Emoji variation selectors (U+FE00-FE0F) and ZWJ (U+200D): chat.db can add or drop these on emoji characters - Smart quotes: macOS auto-substitutes straight quotes on the way in Strip/normalize all three in echoKey() before the existing whitespace collapse. Fixes #1024 --- external_plugins/imessage/server.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/external_plugins/imessage/server.ts b/external_plugins/imessage/server.ts index 5421f3a..1f2bb98 100644 --- a/external_plugins/imessage/server.ts +++ b/external_plugins/imessage/server.ts @@ -418,7 +418,14 @@ const ECHO_WINDOW_MS = 15000 const echo = new Map() function echoKey(raw: string): string { - return raw.trim().replace(/\s+/g, ' ').slice(0, 120) + return raw + .replace(/\s*Sent by Claude\s*$/, '') // strip signature before \s collapse eats the \n + .replace(/[\u200d\ufe00-\ufe0f]/g, '') // ZWJ + emoji variation selectors (chat.db adds/drops these) + .replace(/[\u2018\u2019]/g, "'") // smart → straight single quote + .replace(/[\u201c\u201d]/g, '"') // smart → straight double quote + .trim() + .replace(/\s+/g, ' ') + .slice(0, 120) } function trackEcho(chatGuid: string, key: string): void {