fix(plugin): normalize event session ids

Handle OpenCode session events that carry the session ID under properties.info.id or properties.info.sessionID so background tasks and continuation hooks do not miss idle/error/delete events.

Add regression coverage for nested session.idle events completing background tasks and waking continuation hooks.
This commit is contained in:
YeonGyu-Kim
2026-05-12 11:48:18 +09:00
parent 67f90a819e
commit 4da48555ee
51 changed files with 740 additions and 254 deletions
@@ -7,6 +7,7 @@ import {
applyMemberSessionRouting,
buildMemberPromptBody,
} from "../../features/team-mode/member-session-routing"
import { resolveSessionEventID } from "../../shared/event-session-id"
import { log } from "../../shared/logger"
import { settleAfterSessionIdle } from "../shared/session-idle-settle"
@@ -35,8 +36,7 @@ export type HookImpl = (input: HookInput) => Promise<void>
type TeamIdleWakeHintOptions = { idleSettleMs?: number }
function getIdleSessionID(properties: unknown): string | undefined {
const record = properties as { sessionID?: string } | undefined
return record?.sessionID
return resolveSessionEventID(properties)
}
function buildWakeHint(unreadCount: number): string {
@@ -3,14 +3,14 @@ import type { BackgroundManager } from "../../features/background-agent/manager"
import { lookupTeamSession } from "../../features/team-mode/team-session-registry"
import { loadRuntimeState, listActiveTeams, transitionRuntimeState } from "../../features/team-mode/team-state-store/store"
import type { TmuxSessionManager } from "../../features/tmux-subagent/manager"
import { resolveSessionEventID } from "../../shared/event-session-id"
import { log } from "../../shared/logger"
type HookInput = { event: { type: string; properties?: unknown } }
export type HookImpl = (input: HookInput) => Promise<void>
function getDeletedSessionID(properties: unknown): string | undefined {
const record = properties as { info?: { id?: string } } | undefined
return record?.info?.id
return resolveSessionEventID(properties)
}
async function findLeadTeamRunId(
@@ -1,14 +1,14 @@
import type { TeamModeConfig } from "../../config/schema/team-mode"
import { findResolvedMemberSession } from "../../features/team-mode/member-session-resolution"
import { loadRuntimeState, transitionRuntimeState } from "../../features/team-mode/team-state-store/store"
import { resolveSessionEventID } from "../../shared/event-session-id"
import { log } from "../../shared/logger"
type HookInput = { event: { type: string; properties?: unknown } }
export type HookImpl = (input: HookInput) => Promise<void>
function getErroredSessionID(properties: unknown): string | undefined {
const record = properties as { sessionID?: string } | undefined
return record?.sessionID
return resolveSessionEventID(properties)
}
export function createTeamMemberErrorHandler(config: TeamModeConfig): HookImpl {
@@ -2,6 +2,7 @@ import type { TeamModeConfig } from "../../config/schema/team-mode"
import { findResolvedMemberSession } from "../../features/team-mode/member-session-resolution"
import { loadRuntimeState, transitionRuntimeState } from "../../features/team-mode/team-state-store/store"
import type { RuntimeStateMember } from "../../features/team-mode/types"
import { resolveSessionEventID } from "../../shared/event-session-id"
import { log } from "../../shared/logger"
type HookInput = { event: { type: string; properties?: unknown } }
@@ -13,13 +14,11 @@ const IDLE_TRANSITION_SOURCE_STATUSES: ReadonlySet<MemberStatus> = new Set(["run
const COMPLETED_TRANSITION_SOURCE_STATUSES: ReadonlySet<MemberStatus> = new Set(["running", "idle", "pending"])
function getSessionIDFromIdleEvent(properties: unknown): string | undefined {
const record = properties as { sessionID?: string } | undefined
return record?.sessionID
return resolveSessionEventID(properties)
}
function getSessionIDFromDeletedEvent(properties: unknown): string | undefined {
const record = properties as { info?: { id?: string } } | undefined
return record?.info?.id
return resolveSessionEventID(properties)
}
async function transitionMemberStatus(