fix(hooks): merge surfaces the WINNING decision's reason, not only deny's
mergeHookOutputs collected reasons only from rank-3 (deny/block) hooks, so an ask-winning outcome lost its reason — a bridge mapping an `ask` decision to a PreToolDecision had no reason to attach. Collect reasons per rank and emit the ones explaining the winning decision: a deny-winning fold shows deny reasons, an ask-winning fold shows ask reasons, allow contributes none. Found while building the hooks-claude bridge's PreToolUse `ask` path.
This commit is contained in:
@@ -47,6 +47,24 @@ describe('mergeHookOutputs — reasons, stop, context, systemMessages accumulate
|
||||
expect(mergeHookOutputs([out({ decision: 'allow' })]).reason).toBeUndefined()
|
||||
})
|
||||
|
||||
it('surfaces the reason of the WINNING decision: an ask-winning outcome shows the ask reason', () => {
|
||||
const m = mergeHookOutputs([
|
||||
out({ decision: 'allow', reason: 'allow reason — not surfaced' }),
|
||||
out({ decision: 'ask', reason: 'needs approval' }),
|
||||
])
|
||||
expect(m.decision).toBe('ask')
|
||||
expect(m.reason).toBe('needs approval')
|
||||
})
|
||||
|
||||
it('when deny wins over ask, the ask reasons are dropped (only the winning rank\'s reasons)', () => {
|
||||
const m = mergeHookOutputs([
|
||||
out({ decision: 'ask', reason: 'ask reason — not surfaced once deny wins' }),
|
||||
out({ decision: 'deny', reason: 'the real objection' }),
|
||||
])
|
||||
expect(m.decision).toBe('deny')
|
||||
expect(m.reason).toBe('the real objection')
|
||||
})
|
||||
|
||||
it('stop is sticky on the first continue:false, capturing its stopReason', () => {
|
||||
const m = mergeHookOutputs([
|
||||
out({ continue: true }),
|
||||
|
||||
Reference in New Issue
Block a user