Summary
The generated OpenCode plugin can fire session-start twice for the same session because currentSessionID is updated only after an await.
Problem
Current generated code:
case "session.created": {
const session = (event as any).properties?.info
if (!session?.id) break
// Reset per-session tracking state when switching sessions.
if (currentSessionID !== session.id) {
seenUserMessages.clear()
messageStore.clear()
currentModel = null
await callHook("session-start", {
session_id: session.id,
})
}
currentSessionID = session.id
break
}
Because callHook() awaits the subprocess, the handler yields before currentSessionID is updated. If another session.created event for the same session arrives during that window, it passes the same guard and fires session-start again.
Suggested fix
Update currentSessionID before the await:
case "session.created": {
const session = (event as any).properties?.info
if (!session?.id) break
if (currentSessionID !== session.id) {
seenUserMessages.clear()
messageStore.clear()
currentModel = null
currentSessionID = session.id
await callHook("session-start", {
session_id: session.id,
})
}
break
}
Why this is safer
- closes the race window around
await callHook(...)
- keeps
session-start scoped to actual session changes
- preserves the intended state reset behavior without duplicate hook execution
Summary
The generated OpenCode plugin can fire
session-starttwice for the same session becausecurrentSessionIDis updated only after anawait.Problem
Current generated code:
Because
callHook()awaits the subprocess, the handler yields beforecurrentSessionIDis updated. If anothersession.createdevent for the same session arrives during that window, it passes the same guard and firessession-startagain.Suggested fix
Update
currentSessionIDbefore theawait:Why this is safer
await callHook(...)session-startscoped to actual session changes