Merge pull request #3279 from code-yeongyu/fix/stop-continuation-persistence
fix(stop-continuation): persist stop state across user messages (#3276)
This commit is contained in:
@@ -100,10 +100,16 @@ export function createStopContinuationGuardHook(
|
||||
}: {
|
||||
sessionID?: string
|
||||
}): Promise<void> => {
|
||||
if (sessionID && stoppedSessions.has(sessionID)) {
|
||||
clear(sessionID)
|
||||
log(`[${HOOK_NAME}] Cleared stop state on new user message`, { sessionID })
|
||||
}
|
||||
// Intentionally no-op: stop state should persist across user messages.
|
||||
// Previously this cleared the stop on any new user message, but that caused
|
||||
// /stop-continuation to be ineffective — the user's very next message
|
||||
// (including normal chat) would re-enable continuation.
|
||||
//
|
||||
// Stop state is now only cleared by:
|
||||
// 1. /start-work (or /ulw-loop, /ralph-loop) via explicit clear() call
|
||||
// 2. session.deleted event
|
||||
// 3. Future /resume-continuation command
|
||||
void sessionID
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -162,7 +162,7 @@ describe("stop-continuation-guard", () => {
|
||||
expect(guard.isStopped(session2)).toBe(false)
|
||||
})
|
||||
|
||||
test("should clear stopped state on new user message (chat.message)", async () => {
|
||||
test("should NOT clear stopped state on new user message (chat.message)", async () => {
|
||||
// given - a session that was stopped
|
||||
const guard = createStopContinuationGuardHook(createMockPluginInput())
|
||||
const sessionID = "test-session-4"
|
||||
@@ -172,7 +172,38 @@ describe("stop-continuation-guard", () => {
|
||||
// when - user sends a new message
|
||||
await guard["chat.message"]({ sessionID })
|
||||
|
||||
// then - stop state should be cleared (one-time only)
|
||||
// then - stop state should persist (not cleared by user messages)
|
||||
// Stop is only cleared by explicit work-starting commands (/start-work, /ralph-loop, /ulw-loop)
|
||||
// or session deletion. This prevents /stop-continuation from being ineffective.
|
||||
expect(guard.isStopped(sessionID)).toBe(true)
|
||||
})
|
||||
|
||||
test("should persist stop state across multiple user messages", async () => {
|
||||
// given - a session that was stopped
|
||||
const guard = createStopContinuationGuardHook(createMockPluginInput())
|
||||
const sessionID = "test-session-persist"
|
||||
guard.stop(sessionID)
|
||||
|
||||
// when - user sends multiple messages
|
||||
await guard["chat.message"]({ sessionID })
|
||||
await guard["chat.message"]({ sessionID })
|
||||
await guard["chat.message"]({ sessionID })
|
||||
|
||||
// then - stop state remains active
|
||||
expect(guard.isStopped(sessionID)).toBe(true)
|
||||
})
|
||||
|
||||
test("should clear stop state only via explicit clear() call", () => {
|
||||
// given - a session that was stopped
|
||||
const guard = createStopContinuationGuardHook(createMockPluginInput())
|
||||
const sessionID = "test-session-explicit-clear"
|
||||
guard.stop(sessionID)
|
||||
expect(guard.isStopped(sessionID)).toBe(true)
|
||||
|
||||
// when - clear is called (simulating /start-work or /ralph-loop)
|
||||
guard.clear(sessionID)
|
||||
|
||||
// then - stop state is cleared
|
||||
expect(guard.isStopped(sessionID)).toBe(false)
|
||||
})
|
||||
|
||||
|
||||
@@ -184,6 +184,19 @@ export function createToolExecuteBeforeHandler(args: {
|
||||
sessionID,
|
||||
})
|
||||
}
|
||||
|
||||
// Clear stop state when user explicitly resumes work via work-starting commands.
|
||||
// This ensures /stop-continuation persists until the user intentionally restarts.
|
||||
const workStartingCommands = ["start-work", "ralph-loop", "ulw-loop"]
|
||||
if (workStartingCommands.includes(command ?? "") && sessionID) {
|
||||
if (hooks.stopContinuationGuard?.isStopped(sessionID)) {
|
||||
hooks.stopContinuationGuard.clear(sessionID)
|
||||
log("[stop-continuation] Stop state cleared by work-starting command", {
|
||||
sessionID,
|
||||
command,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user