fix(cursor): accept BOM-prefixed hook JSON (#12652)
* fix(cursor): accept BOM-prefixed hook JSON * test(cursor): pin the hook BOM allowance to one leading U+FEFF Document why the BOM strip exists and cover the narrowness the fix claims: a double BOM, a whitespace-then-BOM prefix, and a BOM inside the JSON body are all still rejected. --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
This commit is contained in:
parent
8331fe5995
commit
e20845eedb
|
|
@ -152,6 +152,45 @@ describe('shared agent-hook-listener', () => {
|
|||
expect(event!.payload.agentType).toBe('claude')
|
||||
})
|
||||
|
||||
it('normalizes a BOM-prefixed Cursor hook payload to a working state', () => {
|
||||
const event = normalizeHookPayload(
|
||||
state,
|
||||
'cursor',
|
||||
{
|
||||
paneKey: PANE_KEY,
|
||||
payload: '\uFEFF{"hook_event_name":"beforeSubmitPrompt","prompt":"Synthetic Cursor prompt"}'
|
||||
},
|
||||
'production'
|
||||
)
|
||||
|
||||
expect(event?.payload).toMatchObject({
|
||||
agentType: 'cursor',
|
||||
state: 'working',
|
||||
prompt: 'Synthetic Cursor prompt'
|
||||
})
|
||||
expect(event?.hookEventName).toBe('beforeSubmitPrompt')
|
||||
})
|
||||
|
||||
// Why: pins the allowance to exactly one leading U+FEFF, so nobody widens it into a trim.
|
||||
it('still rejects a hook payload that is malformed once the BOM is removed', () => {
|
||||
const bom = '\uFEFF'
|
||||
const body = '{"hook_event_name":"beforeSubmitPrompt"}'
|
||||
for (const payload of [
|
||||
`${bom}${bom}${body}`,
|
||||
`${bom}not json`,
|
||||
` ${bom}${body}`,
|
||||
`{"hook_event_name"${bom}:"beforeSubmitPrompt"}`
|
||||
]) {
|
||||
const event = normalizeHookPayload(
|
||||
state,
|
||||
'cursor',
|
||||
{ paneKey: PANE_KEY, payload },
|
||||
'production'
|
||||
)
|
||||
expect(event).toBeNull()
|
||||
}
|
||||
})
|
||||
|
||||
it('normalizes Gemini BeforeTool to working with tool fields', () => {
|
||||
const event = normalizeHookPayload(
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -85,8 +85,12 @@ const AGENT_HOOK_JSON_STRUCTURE_LIMITS = {
|
|||
} as const
|
||||
|
||||
function parseAgentHookJson(content: string): unknown {
|
||||
assertJsonTextStructureWithinLimits(content, AGENT_HOOK_JSON_STRUCTURE_LIMITS)
|
||||
return JSON.parse(content) as unknown
|
||||
// Why: Cursor on Windows writes UTF-8-with-BOM to the hook's stdin and `JSON.parse` rejects U+FEFF,
|
||||
// so the whole event was dropped. Strip exactly one leading BOM — not a trim — to keep every other
|
||||
// malformed payload rejected as before.
|
||||
const normalizedContent = content.charCodeAt(0) === 0xfeff ? content.slice(1) : content
|
||||
assertJsonTextStructureWithinLimits(normalizedContent, AGENT_HOOK_JSON_STRUCTURE_LIMITS)
|
||||
return JSON.parse(normalizedContent) as unknown
|
||||
}
|
||||
|
||||
/** Bound the warn-once Sets so a client varying `version`/`env` per request can't grow them unbounded. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue