Rename across all layers to eliminate naming ambiguity: - Tool: session_handoff → switch_agent - Hook: agent-handoff → agent-switch - Feature: agent-handoff/ → agent-switch/ - Types: SessionHandoffArgs → SwitchAgentArgs, PendingHandoff → PendingSwitch - Functions: setPendingHandoff → setPendingSwitch, consumePendingHandoff → consumePendingSwitch /handoff = inter-session context summary (existing command) switch_agent = intra-session active agent change (our new tool)
131 lines
4.6 KiB
TypeScript
131 lines
4.6 KiB
TypeScript
import type { HookName, OhMyOpenCodeConfig } from "../../config"
|
|
import type { BackgroundManager } from "../../features/background-agent"
|
|
import type { PluginContext } from "../types"
|
|
|
|
import {
|
|
createTodoContinuationEnforcer,
|
|
createBackgroundNotificationHook,
|
|
createStopContinuationGuardHook,
|
|
createCompactionContextInjector,
|
|
createCompactionTodoPreserverHook,
|
|
createAtlasHook,
|
|
createAgentSwitchHook,
|
|
} from "../../hooks"
|
|
import { safeCreateHook } from "../../shared/safe-create-hook"
|
|
import { createUnstableAgentBabysitter } from "../unstable-agent-babysitter"
|
|
|
|
export type ContinuationHooks = {
|
|
stopContinuationGuard: ReturnType<typeof createStopContinuationGuardHook> | null
|
|
compactionContextInjector: ReturnType<typeof createCompactionContextInjector> | null
|
|
compactionTodoPreserver: ReturnType<typeof createCompactionTodoPreserverHook> | null
|
|
todoContinuationEnforcer: ReturnType<typeof createTodoContinuationEnforcer> | null
|
|
unstableAgentBabysitter: ReturnType<typeof createUnstableAgentBabysitter> | null
|
|
backgroundNotificationHook: ReturnType<typeof createBackgroundNotificationHook> | null
|
|
atlasHook: ReturnType<typeof createAtlasHook> | null
|
|
agentSwitchHook: ReturnType<typeof createAgentSwitchHook> | null
|
|
}
|
|
|
|
type SessionRecovery = {
|
|
setOnAbortCallback: (callback: (sessionID: string) => void) => void
|
|
setOnRecoveryCompleteCallback: (callback: (sessionID: string) => void) => void
|
|
} | null
|
|
|
|
export function createContinuationHooks(args: {
|
|
ctx: PluginContext
|
|
pluginConfig: OhMyOpenCodeConfig
|
|
isHookEnabled: (hookName: HookName) => boolean
|
|
safeHookEnabled: boolean
|
|
backgroundManager: BackgroundManager
|
|
sessionRecovery: SessionRecovery
|
|
}): ContinuationHooks {
|
|
const {
|
|
ctx,
|
|
pluginConfig,
|
|
isHookEnabled,
|
|
safeHookEnabled,
|
|
backgroundManager,
|
|
sessionRecovery,
|
|
} = args
|
|
|
|
const safeHook = <T>(hookName: HookName, factory: () => T): T | null =>
|
|
safeCreateHook(hookName, factory, { enabled: safeHookEnabled })
|
|
|
|
const stopContinuationGuard = isHookEnabled("stop-continuation-guard")
|
|
? safeHook("stop-continuation-guard", () => createStopContinuationGuardHook(ctx))
|
|
: null
|
|
|
|
const compactionContextInjector = isHookEnabled("compaction-context-injector")
|
|
? safeHook("compaction-context-injector", () => createCompactionContextInjector(backgroundManager))
|
|
: null
|
|
|
|
const compactionTodoPreserver = isHookEnabled("compaction-todo-preserver")
|
|
? safeHook("compaction-todo-preserver", () => createCompactionTodoPreserverHook(ctx))
|
|
: null
|
|
|
|
const todoContinuationEnforcer = isHookEnabled("todo-continuation-enforcer")
|
|
? safeHook("todo-continuation-enforcer", () =>
|
|
createTodoContinuationEnforcer(ctx, {
|
|
backgroundManager,
|
|
isContinuationStopped: stopContinuationGuard?.isStopped,
|
|
}))
|
|
: null
|
|
|
|
const unstableAgentBabysitter = isHookEnabled("unstable-agent-babysitter")
|
|
? safeHook("unstable-agent-babysitter", () =>
|
|
createUnstableAgentBabysitter({ ctx, backgroundManager, pluginConfig }))
|
|
: null
|
|
|
|
if (sessionRecovery) {
|
|
const onAbortCallbacks: Array<(sessionID: string) => void> = []
|
|
const onRecoveryCompleteCallbacks: Array<(sessionID: string) => void> = []
|
|
|
|
if (todoContinuationEnforcer) {
|
|
onAbortCallbacks.push(todoContinuationEnforcer.markRecovering)
|
|
onRecoveryCompleteCallbacks.push(todoContinuationEnforcer.markRecoveryComplete)
|
|
}
|
|
|
|
|
|
if (onAbortCallbacks.length > 0) {
|
|
sessionRecovery.setOnAbortCallback((sessionID: string) => {
|
|
for (const callback of onAbortCallbacks) callback(sessionID)
|
|
})
|
|
}
|
|
|
|
if (onRecoveryCompleteCallbacks.length > 0) {
|
|
sessionRecovery.setOnRecoveryCompleteCallback((sessionID: string) => {
|
|
for (const callback of onRecoveryCompleteCallbacks) callback(sessionID)
|
|
})
|
|
}
|
|
}
|
|
|
|
const backgroundNotificationHook = isHookEnabled("background-notification")
|
|
? safeHook("background-notification", () => createBackgroundNotificationHook(backgroundManager))
|
|
: null
|
|
|
|
const atlasHook = isHookEnabled("atlas")
|
|
? safeHook("atlas", () =>
|
|
createAtlasHook(ctx, {
|
|
directory: ctx.directory,
|
|
backgroundManager,
|
|
isContinuationStopped: (sessionID: string) =>
|
|
stopContinuationGuard?.isStopped(sessionID) ?? false,
|
|
agentOverrides: pluginConfig.agents,
|
|
}))
|
|
: null
|
|
|
|
const agentSwitchHook = isHookEnabled("agent-switch")
|
|
? safeHook("agent-switch", () => createAgentSwitchHook(ctx))
|
|
: null
|
|
|
|
return {
|
|
stopContinuationGuard,
|
|
compactionContextInjector,
|
|
compactionTodoPreserver,
|
|
todoContinuationEnforcer,
|
|
unstableAgentBabysitter,
|
|
backgroundNotificationHook,
|
|
atlasHook,
|
|
agentSwitchHook,
|
|
}
|
|
}
|