fix: cancel hook completion on title working (#4175)

This commit is contained in:
Neil
2026-05-31 06:57:12 -07:00
committed by GitHub
parent fc35a0607a
commit 403ac726aa
3 changed files with 90 additions and 0 deletions
@@ -646,6 +646,36 @@ describe('agent completion coordinator', () => {
})
})
it('cancels a hook completion when title tracking observes resumed work before quiet', () => {
const dispatchCompletion = vi.fn()
const coordinator = createAgentCompletionCoordinator({
paneKey: 'tab-1:leaf-1',
getPtyId: () => 'pty-1',
getSettings: () => null,
inspectProcess: vi.fn(),
dispatchCompletion,
isLive: () => true
})
coordinator.observeHookStatus({
state: 'working',
prompt: 'run the goal',
agentType: 'codex'
})
coordinator.observeHookStatus({
state: 'done',
prompt: 'run the goal',
agentType: 'codex'
})
expect(coordinator.hasPendingHookDoneCompletion()).toBe(true)
coordinator.observeTitleWorking()
expect(coordinator.hasPendingHookDoneCompletion()).toBe(false)
vi.advanceTimersByTime(HOOK_DONE_QUIET_MS)
expect(dispatchCompletion).not.toHaveBeenCalled()
})
it.each([
'claude',
'codex',
@@ -361,6 +361,9 @@ export function createAgentCompletionCoordinator(
}
function recordTitleWorking(): boolean {
// Why: hooks can report `done` before title tracking notices the next
// milestone. The title working signal must cancel that provisional done.
clearPendingHookDone()
if (
lastCompletionSource === 'hook' &&
Date.now() - lastCompletionAt < COMPLETION_REPLAY_GUARD_MS
@@ -4565,6 +4565,63 @@ describe('connectPanePty', () => {
)
})
it('restores a suppressed terminal bell when a delayed hook completion resumes via title tracking', async () => {
const { connectPanePty } = await import('./pty-connection')
const transport = createMockTransport('pty-hook')
transportFactoryQueue.push(transport)
vi.useFakeTimers()
const pane = createPane(1)
const manager = createManager(1)
const deps = createDeps()
connectPanePty(pane as never, manager as never, deps as never)
const statusHandler = createdTransportOptions[0]?.onAgentStatus as
| ((payload: {
state: 'working' | 'done'
prompt: string
agentType: 'codex'
lastAssistantMessage?: string
}) => void)
| undefined
const bellHandler = createdTransportOptions[0]?.onBell as (() => void) | undefined
const workingHandler = createdTransportOptions[0]?.onAgentBecameWorking as
| (() => void)
| undefined
if (!statusHandler || !bellHandler || !workingHandler) {
throw new Error('Expected hook status, bell, and working handlers to be registered')
}
statusHandler({
state: 'working',
prompt: 'finish the implementation',
agentType: 'codex'
})
statusHandler({
state: 'done',
prompt: 'finish the implementation',
agentType: 'codex',
lastAssistantMessage: 'Milestone complete.'
})
bellHandler()
vi.advanceTimersByTime(AGENT_TASK_COMPLETE_NOTIFICATION_GRACE_MS)
expect(deps.dispatchNotification).not.toHaveBeenCalledWith(
expect.objectContaining({ source: 'terminal-bell' })
)
workingHandler()
vi.advanceTimersByTime(AGENT_TASK_COMPLETE_NOTIFICATION_GRACE_MS)
expect(deps.dispatchNotification).toHaveBeenCalledWith(
expect.objectContaining({ source: 'terminal-bell' })
)
vi.advanceTimersByTime(AGENT_TASK_COMPLETE_NOTIFICATION_MAX_WAIT_MS)
expect(deps.dispatchNotification).not.toHaveBeenCalledWith(
expect.objectContaining({ source: 'agent-task-complete' })
)
})
it('restores a suppressed terminal bell when the pending agent completion is canceled', async () => {
const { connectPanePty } = await import('./pty-connection')
const transport = createMockTransport()