YeonGyu-Kim d53bcfbced refactor(background-agent): extract inline logic from manager.ts into focused modules
Extract 5 concerns from BackgroundManager into dedicated modules:
- error-classifier.ts: enhance with extractErrorName, extractErrorMessage, getSessionErrorMessage, isRecord
- fallback-retry-handler.ts: standalone tryFallbackRetry with full retry logic
- process-cleanup.ts: registerManagerForCleanup/unregisterManagerForCleanup
- compaction-aware-message-resolver.ts: isCompactionAgent/findNearestMessageExcludingCompaction
- Delete notification-builder.ts (duplicate of background-task-notification-template.ts)

Manager.ts method bodies now delegate to extracted modules.
Wire duration-formatter.ts and task-poller.ts (existing but unused).

manager.ts: 2036 -> 1647 LOC (19% reduction).
All 161 existing tests pass unchanged.
2026-02-22 11:58:57 +09:00

82 lines
2.0 KiB
TypeScript

import { log } from "../../shared"
type ProcessCleanupEvent = NodeJS.Signals | "beforeExit" | "exit"
function registerProcessSignal(
signal: ProcessCleanupEvent,
handler: () => void,
exitAfter: boolean
): () => void {
const listener = () => {
handler()
if (exitAfter) {
process.exitCode = 0
setTimeout(() => process.exit(), 6000)
}
}
process.on(signal, listener)
return listener
}
interface CleanupTarget {
shutdown(): void
}
const cleanupManagers = new Set<CleanupTarget>()
let cleanupRegistered = false
const cleanupHandlers = new Map<ProcessCleanupEvent, () => void>()
export function registerManagerForCleanup(manager: CleanupTarget): void {
cleanupManagers.add(manager)
if (cleanupRegistered) return
cleanupRegistered = true
const cleanupAll = () => {
for (const m of cleanupManagers) {
try {
m.shutdown()
} catch (error) {
log("[background-agent] Error during shutdown cleanup:", error)
}
}
}
const registerSignal = (signal: ProcessCleanupEvent, exitAfter: boolean): void => {
const listener = registerProcessSignal(signal, cleanupAll, exitAfter)
cleanupHandlers.set(signal, listener)
}
registerSignal("SIGINT", true)
registerSignal("SIGTERM", true)
if (process.platform === "win32") {
registerSignal("SIGBREAK", true)
}
registerSignal("beforeExit", false)
registerSignal("exit", false)
}
export function unregisterManagerForCleanup(manager: CleanupTarget): void {
cleanupManagers.delete(manager)
if (cleanupManagers.size > 0) return
for (const [signal, listener] of cleanupHandlers.entries()) {
process.off(signal, listener)
}
cleanupHandlers.clear()
cleanupRegistered = false
}
/** @internal — test-only reset for module-level singleton state */
export function _resetForTesting(): void {
for (const manager of [...cleanupManagers]) {
cleanupManagers.delete(manager)
}
for (const [signal, listener] of cleanupHandlers.entries()) {
process.off(signal, listener)
}
cleanupHandlers.clear()
cleanupRegistered = false
}