From 8f94032dc117f722eb25d0dcce63bd489b390de9 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:20:53 -0500 Subject: [PATCH] fix: prefer target entry for inline abort cutoff --- ...ine-actions.skip-when-config-empty.test.ts | 37 +++++++++++++++++++ .../reply/get-reply-inline-actions.ts | 8 ++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts b/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts index c84067767f3..680ec99620e 100644 --- a/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts +++ b/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts @@ -419,6 +419,43 @@ describe("handleInlineActions", () => { expect(handleCommandsMock).not.toHaveBeenCalled(); }); + it("prefers the target session entry for inline /stop cutoff checks", async () => { + const typing = createTypingController(); + const wrapperSessionEntry: SessionEntry = { + sessionId: "wrapper-session", + updatedAt: Date.now(), + abortCutoffMessageSid: "40", + abortedLastRun: true, + }; + const targetSessionEntry: SessionEntry = { + sessionId: "target-session", + updatedAt: Date.now(), + abortCutoffMessageSid: "42", + abortedLastRun: true, + }; + const ctx = buildTestCtx({ + Body: "old queued message", + CommandBody: "old queued message", + MessageSid: "41", + }); + + await expectInlineActionSkipped({ + ctx, + typing, + cleanedBody: "old queued message", + command: { + rawBodyNormalized: "old queued message", + commandBodyNormalized: "old queued message", + }, + overrides: { + sessionEntry: wrapperSessionEntry, + sessionStore: { + "s:main": targetSessionEntry, + }, + }, + }); + }); + it("rewrites Claude bundle markdown commands into a native agent prompt", async () => { const typing = createTypingController(); handleCommandsMock.mockResolvedValue({ shouldContinue: false, reply: { text: "done" } }); diff --git a/src/auto-reply/reply/get-reply-inline-actions.ts b/src/auto-reply/reply/get-reply-inline-actions.ts index 034c6f6ee72..7fc55b04f82 100644 --- a/src/auto-reply/reply/get-reply-inline-actions.ts +++ b/src/auto-reply/reply/get-reply-inline-actions.ts @@ -297,8 +297,9 @@ export async function handleInlineActions(params: { }; const isStopLikeInbound = isAbortRequestText(command.rawBodyNormalized); - if (!isStopLikeInbound && sessionEntry) { - const cutoff = readAbortCutoffFromSessionEntry(sessionEntry); + const targetSessionEntry = sessionStore?.[sessionKey] ?? sessionEntry; + if (!isStopLikeInbound && targetSessionEntry) { + const cutoff = readAbortCutoffFromSessionEntry(targetSessionEntry); const incoming = resolveAbortCutoffFromContext(ctx); const shouldSkip = cutoff ? shouldSkipMessageByAbortCutoff({ @@ -316,7 +317,7 @@ export async function handleInlineActions(params: { await ( await import("./abort-cutoff.runtime.js") ).clearAbortCutoffInSessionRuntime({ - sessionEntry, + sessionEntry: targetSessionEntry, sessionStore, sessionKey, storePath, @@ -347,7 +348,6 @@ export async function handleInlineActions(params: { let didSendInlineStatus = false; if (handleInlineStatus) { const { buildStatusReply } = await import("./commands.runtime.js"); - const targetSessionEntry = sessionStore?.[sessionKey] ?? sessionEntry; const inlineStatusReply = await buildStatusReply({ cfg, command,