merge: integrate origin/dev into modular-enforcement branch

Resolves all merge conflicts, preserving our split module structure
while integrating all dev changes:
- Custom agent summaries support (parseRegisteredAgentSummaries)
- Background notification queue (enqueueNotificationForParent)
- Atlas shared git-worktree module (collectGitDiffStats, formatFileChanges)
- Ralph-loop withTimeout + DEFAULT_API_TIMEOUT=5000
- Session recovery assistant_prefill_unsupported error type
- Atlas agentOverrides forwarding
- Config handler plan model demotion (buildPlanDemoteConfig)
- Delegate-task agentOverrides, promptSyncWithModelSuggestionRetry, variant
- LSP init timeout + stale init detection
- isPlanFamily function + task-continuation-enforcer hook
- Handoff command
This commit is contained in:
YeonGyu-Kim
2026-02-08 17:34:47 +09:00
74 changed files with 4016 additions and 654 deletions
+20 -19
View File
@@ -28,25 +28,26 @@ export function createEventHandler(args: {
const { ctx, firstMessageVariantGate, managers, hooks } = args
return async (input): Promise<void> => {
await hooks.autoUpdateChecker?.event?.(input)
await hooks.claudeCodeHooks?.event?.(input)
await hooks.backgroundNotificationHook?.event?.(input)
await hooks.sessionNotification?.(input)
await hooks.todoContinuationEnforcer?.handler?.(input)
await hooks.unstableAgentBabysitter?.event?.(input)
await hooks.contextWindowMonitor?.event?.(input)
await hooks.directoryAgentsInjector?.event?.(input)
await hooks.directoryReadmeInjector?.event?.(input)
await hooks.rulesInjector?.event?.(input)
await hooks.thinkMode?.event?.(input)
await hooks.anthropicContextWindowLimitRecovery?.event?.(input)
await hooks.agentUsageReminder?.event?.(input)
await hooks.categorySkillReminder?.event?.(input)
await hooks.interactiveBashSession?.event?.(input)
await hooks.ralphLoop?.event?.(input)
await hooks.stopContinuationGuard?.event?.(input)
await hooks.compactionTodoPreserver?.event?.(input)
await hooks.atlasHook?.handler?.(input)
await Promise.resolve(hooks.autoUpdateChecker?.event?.(input))
await Promise.resolve(hooks.claudeCodeHooks?.event?.(input))
await Promise.resolve(hooks.backgroundNotificationHook?.event?.(input))
await Promise.resolve(hooks.sessionNotification?.(input))
await Promise.resolve(hooks.todoContinuationEnforcer?.handler?.(input))
await Promise.resolve(hooks.taskContinuationEnforcer?.handler?.(input))
await Promise.resolve(hooks.unstableAgentBabysitter?.event?.(input))
await Promise.resolve(hooks.contextWindowMonitor?.event?.(input))
await Promise.resolve(hooks.directoryAgentsInjector?.event?.(input))
await Promise.resolve(hooks.directoryReadmeInjector?.event?.(input))
await Promise.resolve(hooks.rulesInjector?.event?.(input))
await Promise.resolve(hooks.thinkMode?.event?.(input))
await Promise.resolve(hooks.anthropicContextWindowLimitRecovery?.event?.(input))
await Promise.resolve(hooks.agentUsageReminder?.event?.(input))
await Promise.resolve(hooks.categorySkillReminder?.event?.(input))
await Promise.resolve(hooks.interactiveBashSession?.event?.(input))
await Promise.resolve(hooks.ralphLoop?.event?.(input))
await Promise.resolve(hooks.stopContinuationGuard?.event?.(input))
await Promise.resolve(hooks.compactionTodoPreserver?.event?.(input))
await Promise.resolve(hooks.atlasHook?.handler?.(input))
const { event } = input
const props = event.properties as Record<string, unknown> | undefined
+36 -3
View File
@@ -4,6 +4,7 @@ import type { PluginContext } from "../types"
import {
createTodoContinuationEnforcer,
createTaskContinuationEnforcer,
createBackgroundNotificationHook,
createStopContinuationGuardHook,
createCompactionContextInjector,
@@ -18,6 +19,7 @@ export type ContinuationHooks = {
compactionContextInjector: ReturnType<typeof createCompactionContextInjector> | null
compactionTodoPreserver: ReturnType<typeof createCompactionTodoPreserverHook> | null
todoContinuationEnforcer: ReturnType<typeof createTodoContinuationEnforcer> | null
taskContinuationEnforcer: ReturnType<typeof createTaskContinuationEnforcer> | null
unstableAgentBabysitter: ReturnType<typeof createUnstableAgentBabysitter> | null
backgroundNotificationHook: ReturnType<typeof createBackgroundNotificationHook> | null
atlasHook: ReturnType<typeof createAtlasHook> | null
@@ -68,14 +70,43 @@ export function createContinuationHooks(args: {
}))
: null
const taskContinuationEnforcer = isHookEnabled("task-continuation-enforcer")
? safeHook("task-continuation-enforcer", () =>
createTaskContinuationEnforcer(ctx, pluginConfig, {
backgroundManager,
isContinuationStopped: stopContinuationGuard?.isStopped,
}))
: null
const unstableAgentBabysitter = isHookEnabled("unstable-agent-babysitter")
? safeHook("unstable-agent-babysitter", () =>
createUnstableAgentBabysitter({ ctx, backgroundManager, pluginConfig }))
: null
if (sessionRecovery && todoContinuationEnforcer) {
sessionRecovery.setOnAbortCallback(todoContinuationEnforcer.markRecovering)
sessionRecovery.setOnRecoveryCompleteCallback(todoContinuationEnforcer.markRecoveryComplete)
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 (taskContinuationEnforcer) {
onAbortCallbacks.push(taskContinuationEnforcer.markRecovering)
onRecoveryCompleteCallbacks.push(taskContinuationEnforcer.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")
@@ -89,6 +120,7 @@ export function createContinuationHooks(args: {
backgroundManager,
isContinuationStopped: (sessionID: string) =>
stopContinuationGuard?.isStopped(sessionID) ?? false,
agentOverrides: pluginConfig.agents,
}))
: null
@@ -97,6 +129,7 @@ export function createContinuationHooks(args: {
compactionContextInjector,
compactionTodoPreserver,
todoContinuationEnforcer,
taskContinuationEnforcer,
unstableAgentBabysitter,
backgroundNotificationHook,
atlasHook,
+1
View File
@@ -88,6 +88,7 @@ export function createToolExecuteBeforeHandler(args: {
if (command === "stop-continuation" && sessionID) {
hooks.stopContinuationGuard?.stop(sessionID)
hooks.todoContinuationEnforcer?.cancelAllCountdowns()
hooks.taskContinuationEnforcer?.cancelAllCountdowns()
hooks.ralphLoop?.cancelLoop(sessionID)
clearBoulderState(ctx.directory)
log("[stop-continuation] All continuation mechanisms stopped", {