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:
@@ -2,6 +2,7 @@ import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import type { TmuxConfig } from "../../config/schema"
|
||||
import type { TrackedSession, CapacityConfig, WindowState } from "./types"
|
||||
import * as sharedModule from "../../shared"
|
||||
import { resolveSessionEventID } from "../../shared/event-session-id"
|
||||
import {
|
||||
isInsideTmux as defaultIsInsideTmux,
|
||||
getCurrentPaneId as defaultGetCurrentPaneId,
|
||||
@@ -1098,9 +1099,9 @@ export class TmuxSessionManager {
|
||||
if (event.type !== "session.created") return
|
||||
|
||||
const info = event.properties?.info
|
||||
if (!info?.id || !info?.parentID) return
|
||||
const sessionId = resolveSessionEventID(event.properties)
|
||||
if (!sessionId || !info?.parentID) return
|
||||
|
||||
const sessionId = info.id
|
||||
const title = info.title ?? "Subagent"
|
||||
|
||||
if (!this.sourcePaneId) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
|
||||
import { TmuxPollingManager } from "./polling-manager"
|
||||
import type { TrackedSession } from "./types"
|
||||
|
||||
describe("TmuxPollingManager event session ids", () => {
|
||||
test("#given legacy message.part.updated properties #when handling activity #then part session id increments activity version", () => {
|
||||
const sessions = new Map<string, TrackedSession>()
|
||||
sessions.set("ses-part-only", {
|
||||
sessionId: "ses-part-only",
|
||||
paneId: "%1",
|
||||
description: "test",
|
||||
createdAt: new Date(),
|
||||
lastSeenAt: new Date(),
|
||||
closePending: false,
|
||||
closeRetryCount: 0,
|
||||
activityVersion: 0,
|
||||
})
|
||||
|
||||
const client = {
|
||||
session: {
|
||||
status: async () => ({ data: {} }),
|
||||
messages: async () => ({ data: [] }),
|
||||
},
|
||||
}
|
||||
const manager = new TmuxPollingManager(client as never, sessions, async () => {})
|
||||
|
||||
manager.handleEvent({
|
||||
type: "message.part.updated",
|
||||
properties: {
|
||||
part: {
|
||||
id: "part-1",
|
||||
messageID: "msg-1",
|
||||
sessionID: "ses-part-only",
|
||||
type: "text",
|
||||
text: "working",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(sessions.get("ses-part-only")?.activityVersion).toBe(1)
|
||||
})
|
||||
})
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import type { TrackedSession } from "./types"
|
||||
import { log } from "../../shared"
|
||||
import { normalizeSDKResponse } from "../../shared"
|
||||
import { resolveMessageEventSessionID } from "../../shared/event-session-id"
|
||||
|
||||
const MIN_STABILITY_TIME_MS = 10 * 1000
|
||||
const STABLE_POLLS_REQUIRED = 3
|
||||
@@ -170,10 +171,7 @@ export class TmuxPollingManager {
|
||||
if (!properties) return undefined
|
||||
|
||||
if (event.type === "message.updated") {
|
||||
const info = properties.info
|
||||
if (!info || typeof info !== "object") return undefined
|
||||
const sessionId = (info as { sessionID?: unknown }).sessionID
|
||||
return typeof sessionId === "string" ? sessionId : undefined
|
||||
return resolveMessageEventSessionID(properties)
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -182,8 +180,7 @@ export class TmuxPollingManager {
|
||||
|| event.type === "message.part.removed"
|
||||
|| event.type === "message.removed"
|
||||
) {
|
||||
const sessionId = properties.sessionID
|
||||
return typeof sessionId === "string" ? sessionId : undefined
|
||||
return resolveMessageEventSessionID(properties)
|
||||
}
|
||||
|
||||
return undefined
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import type { TmuxConfig } from "../../config/schema"
|
||||
import type { CapacityConfig, TrackedSession } from "./types"
|
||||
import { log } from "../../shared"
|
||||
import { resolveSessionEventID } from "../../shared/event-session-id"
|
||||
import { queryWindowState } from "./pane-state-querier"
|
||||
import { decideSpawnActions, type SessionMapping } from "./decision-engine"
|
||||
import { executeActions } from "./action-executor"
|
||||
@@ -44,9 +45,9 @@ export async function handleSessionCreated(
|
||||
if (event.type !== "session.created") return
|
||||
|
||||
const info = event.properties?.info
|
||||
if (!info?.id || !info?.parentID) return
|
||||
const sessionId = resolveSessionEventID(event.properties)
|
||||
if (!sessionId || !info?.parentID) return
|
||||
|
||||
const sessionId = info.id
|
||||
const title = info.title ?? "Subagent"
|
||||
|
||||
if (deps.sessions.has(sessionId) || deps.pendingSessions.has(sessionId)) {
|
||||
|
||||
Reference in New Issue
Block a user