fix(team-mode): cleanup team runs on shutdown
This commit is contained in:
@@ -8,11 +8,23 @@ import { createManagers } from "./create-managers"
|
|||||||
import * as openclawRuntimeDispatch from "./openclaw/runtime-dispatch"
|
import * as openclawRuntimeDispatch from "./openclaw/runtime-dispatch"
|
||||||
import { createModelCacheState } from "./plugin-state"
|
import { createModelCacheState } from "./plugin-state"
|
||||||
|
|
||||||
|
type CleanupRegistration = {
|
||||||
|
shutdown: () => void | Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
type CleanupSessionTeamRunsFn = typeof import("./features/team-mode/team-runtime/session-cleanup").cleanupSessionTeamRuns
|
||||||
|
|
||||||
const markServerRunningInProcess = mock(() => {})
|
const markServerRunningInProcess = mock(() => {})
|
||||||
let backgroundManagerOptions: {
|
let backgroundManagerOptions: {
|
||||||
onSubagentSessionCreated?: (event: { sessionID: string; parentID: string; title: string }) => Promise<void>
|
onSubagentSessionCreated?: (event: { sessionID: string; parentID: string; title: string }) => Promise<void>
|
||||||
} | null = null
|
} | null = null
|
||||||
const trackedPaneBySession = new Map<string, string>()
|
const trackedPaneBySession = new Map<string, string>()
|
||||||
|
const registeredCleanupManagers: CleanupRegistration[] = []
|
||||||
|
const cleanupSessionTeamRunsMock = mock(async () => ({
|
||||||
|
cleanedTeamRunIds: [],
|
||||||
|
removedLayoutTeamRunIds: [],
|
||||||
|
errors: [],
|
||||||
|
}))
|
||||||
|
|
||||||
class MockBackgroundManager {
|
class MockBackgroundManager {
|
||||||
constructor(config: {
|
constructor(config: {
|
||||||
@@ -51,7 +63,9 @@ function initTaskToastManager(): ReturnType<typeof import("./features/task-toast
|
|||||||
return {} as ReturnType<typeof import("./features/task-toast-manager").initTaskToastManager>
|
return {} as ReturnType<typeof import("./features/task-toast-manager").initTaskToastManager>
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerManagerForCleanup(): void {}
|
function registerManagerForCleanup(manager: CleanupRegistration): void {
|
||||||
|
registeredCleanupManagers.push(manager)
|
||||||
|
}
|
||||||
|
|
||||||
function createDeps(): NonNullable<Parameters<typeof createManagers>[0]["deps"]> {
|
function createDeps(): NonNullable<Parameters<typeof createManagers>[0]["deps"]> {
|
||||||
return {
|
return {
|
||||||
@@ -60,6 +74,7 @@ function createDeps(): NonNullable<Parameters<typeof createManagers>[0]["deps"]>
|
|||||||
TmuxSessionManagerClass: MockTmuxSessionManager as typeof import("./features/tmux-subagent").TmuxSessionManager,
|
TmuxSessionManagerClass: MockTmuxSessionManager as typeof import("./features/tmux-subagent").TmuxSessionManager,
|
||||||
initTaskToastManagerFn: initTaskToastManager,
|
initTaskToastManagerFn: initTaskToastManager,
|
||||||
registerManagerForCleanupFn: registerManagerForCleanup,
|
registerManagerForCleanupFn: registerManagerForCleanup,
|
||||||
|
cleanupSessionTeamRunsFn: cleanupSessionTeamRunsMock as CleanupSessionTeamRunsFn,
|
||||||
createConfigHandlerFn: createConfigHandler,
|
createConfigHandlerFn: createConfigHandler,
|
||||||
markServerRunningInProcessFn: markServerRunningInProcess,
|
markServerRunningInProcessFn: markServerRunningInProcess,
|
||||||
}
|
}
|
||||||
@@ -122,6 +137,8 @@ describe("createManagers", () => {
|
|||||||
dispatchOpenClawEvent.mockReset()
|
dispatchOpenClawEvent.mockReset()
|
||||||
backgroundManagerOptions = null
|
backgroundManagerOptions = null
|
||||||
trackedPaneBySession.clear()
|
trackedPaneBySession.clear()
|
||||||
|
registeredCleanupManagers.length = 0
|
||||||
|
cleanupSessionTeamRunsMock.mockClear()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -193,4 +210,32 @@ describe("createManagers", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("#given team mode is enabled #when process cleanup runs #then session team runs are cleaned with tmux visualization dependencies", async () => {
|
||||||
|
const args = {
|
||||||
|
ctx: createContext("/tmp/project"),
|
||||||
|
pluginConfig: OhMyOpenCodeConfigSchema.parse({
|
||||||
|
team_mode: {
|
||||||
|
enabled: true,
|
||||||
|
tmux_visualization: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tmuxConfig: createTmuxConfig(true),
|
||||||
|
modelCacheState: createModelCacheState(),
|
||||||
|
backgroundNotificationHookEnabled: false,
|
||||||
|
deps: createDeps(),
|
||||||
|
}
|
||||||
|
|
||||||
|
createManagers(args)
|
||||||
|
|
||||||
|
await registeredCleanupManagers[0]?.shutdown()
|
||||||
|
|
||||||
|
expect(cleanupSessionTeamRunsMock).toHaveBeenCalledTimes(1)
|
||||||
|
const cleanupArgs = cleanupSessionTeamRunsMock.mock.calls[0]?.[0]
|
||||||
|
expect(cleanupArgs).toMatchObject({
|
||||||
|
config: args.pluginConfig.team_mode,
|
||||||
|
})
|
||||||
|
expect(cleanupArgs?.tmuxMgr).toBeInstanceOf(MockTmuxSessionManager)
|
||||||
|
expect(cleanupArgs?.bgMgr).toBeInstanceOf(MockBackgroundManager)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+23
-1
@@ -5,6 +5,7 @@ import type { PluginContext, TmuxConfig } from "./plugin/types"
|
|||||||
import type { SubagentSessionCreatedEvent } from "./features/background-agent"
|
import type { SubagentSessionCreatedEvent } from "./features/background-agent"
|
||||||
import { BackgroundManager } from "./features/background-agent"
|
import { BackgroundManager } from "./features/background-agent"
|
||||||
import { SkillMcpManager } from "./features/skill-mcp-manager"
|
import { SkillMcpManager } from "./features/skill-mcp-manager"
|
||||||
|
import { cleanupSessionTeamRuns } from "./features/team-mode/team-runtime/session-cleanup"
|
||||||
import { createModelFallbackControllerAccessor } from "./hooks/model-fallback"
|
import { createModelFallbackControllerAccessor } from "./hooks/model-fallback"
|
||||||
import { initTaskToastManager } from "./features/task-toast-manager"
|
import { initTaskToastManager } from "./features/task-toast-manager"
|
||||||
import { TmuxSessionManager } from "./features/tmux-subagent"
|
import { TmuxSessionManager } from "./features/tmux-subagent"
|
||||||
@@ -21,6 +22,7 @@ type CreateManagersDeps = {
|
|||||||
TmuxSessionManagerClass: typeof TmuxSessionManager
|
TmuxSessionManagerClass: typeof TmuxSessionManager
|
||||||
initTaskToastManagerFn: typeof initTaskToastManager
|
initTaskToastManagerFn: typeof initTaskToastManager
|
||||||
registerManagerForCleanupFn: typeof registerManagerForCleanup
|
registerManagerForCleanupFn: typeof registerManagerForCleanup
|
||||||
|
cleanupSessionTeamRunsFn: typeof cleanupSessionTeamRuns
|
||||||
createConfigHandlerFn: typeof createConfigHandler
|
createConfigHandlerFn: typeof createConfigHandler
|
||||||
markServerRunningInProcessFn: typeof markServerRunningInProcess
|
markServerRunningInProcessFn: typeof markServerRunningInProcess
|
||||||
}
|
}
|
||||||
@@ -31,6 +33,7 @@ const defaultCreateManagersDeps: CreateManagersDeps = {
|
|||||||
TmuxSessionManagerClass: TmuxSessionManager,
|
TmuxSessionManagerClass: TmuxSessionManager,
|
||||||
initTaskToastManagerFn: initTaskToastManager,
|
initTaskToastManagerFn: initTaskToastManager,
|
||||||
registerManagerForCleanupFn: registerManagerForCleanup,
|
registerManagerForCleanupFn: registerManagerForCleanup,
|
||||||
|
cleanupSessionTeamRunsFn: cleanupSessionTeamRuns,
|
||||||
createConfigHandlerFn: createConfigHandler,
|
createConfigHandlerFn: createConfigHandler,
|
||||||
markServerRunningInProcessFn: markServerRunningInProcess,
|
markServerRunningInProcessFn: markServerRunningInProcess,
|
||||||
}
|
}
|
||||||
@@ -59,16 +62,32 @@ export function createManagers(args: {
|
|||||||
}
|
}
|
||||||
const tmuxSessionManager = new deps.TmuxSessionManagerClass(ctx, tmuxConfig)
|
const tmuxSessionManager = new deps.TmuxSessionManagerClass(ctx, tmuxConfig)
|
||||||
const modelFallbackControllerAccessor = createModelFallbackControllerAccessor()
|
const modelFallbackControllerAccessor = createModelFallbackControllerAccessor()
|
||||||
|
let backgroundManager: BackgroundManager | undefined
|
||||||
|
|
||||||
|
const cleanupTeamModeRuns = async (): Promise<void> => {
|
||||||
|
if (!pluginConfig.team_mode?.enabled) return
|
||||||
|
const report = await deps.cleanupSessionTeamRunsFn({
|
||||||
|
config: pluginConfig.team_mode,
|
||||||
|
tmuxMgr: tmuxSessionManager,
|
||||||
|
bgMgr: backgroundManager,
|
||||||
|
})
|
||||||
|
if (report.cleanedTeamRunIds.length > 0 || report.errors.length > 0) {
|
||||||
|
log("[create-managers] team-mode session cleanup complete", report)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
deps.registerManagerForCleanupFn({
|
deps.registerManagerForCleanupFn({
|
||||||
shutdown: async () => {
|
shutdown: async () => {
|
||||||
|
await cleanupTeamModeRuns().catch((error) => {
|
||||||
|
log("[create-managers] team-mode cleanup error during process shutdown:", error)
|
||||||
|
})
|
||||||
await tmuxSessionManager.cleanup().catch((error) => {
|
await tmuxSessionManager.cleanup().catch((error) => {
|
||||||
log("[create-managers] tmux cleanup error during process shutdown:", error)
|
log("[create-managers] tmux cleanup error during process shutdown:", error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const backgroundManager = new deps.BackgroundManagerClass({
|
backgroundManager = new deps.BackgroundManagerClass({
|
||||||
pluginContext: ctx,
|
pluginContext: ctx,
|
||||||
config: pluginConfig.background_task,
|
config: pluginConfig.background_task,
|
||||||
tmuxConfig,
|
tmuxConfig,
|
||||||
@@ -105,6 +124,9 @@ export function createManagers(args: {
|
|||||||
log("[create-managers] onSubagentSessionCreated callback completed")
|
log("[create-managers] onSubagentSessionCreated callback completed")
|
||||||
},
|
},
|
||||||
onShutdown: async () => {
|
onShutdown: async () => {
|
||||||
|
await cleanupTeamModeRuns().catch((error) => {
|
||||||
|
log("[create-managers] team-mode cleanup error during shutdown:", error)
|
||||||
|
})
|
||||||
await tmuxSessionManager.cleanup().catch((error) => {
|
await tmuxSessionManager.cleanup().catch((error) => {
|
||||||
log("[create-managers] tmux cleanup error during shutdown:", error)
|
log("[create-managers] tmux cleanup error during shutdown:", error)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user