YeonGyu-Kim 119e18c810 refactor: wave 2 - split atlas, auto-update-checker, session-recovery, todo-enforcer, background-task hooks
- Extract atlas/ into 15 focused modules (hook, event handler, tool policies, types, etc.)
- Split auto-update-checker into checker/ and hook/ subdirectories with single-purpose files
- Decompose session-recovery into separate recovery strategy files per error type
- Extract todo-continuation-enforcer from monolith to directory with dedicated modules
- Split background-task/tools.ts into individual tool creator files
- Extract command-executor, tmux-utils into focused sub-modules
- Split config/schema.ts into domain-specific schema files
- Decompose cli/config-manager.ts into focused modules
- Rollback skill-mcp-manager, model-availability, index.ts splits that broke tests
- Fix all import path depths for moved files (../../ -> ../../../)
- Add explicit type annotations to resolve TS7006 implicit any errors

Typecheck: 0 errors
Tests: 2359 pass, 5 fail (all pre-existing)
2026-02-08 15:01:42 +09:00

84 lines
2.0 KiB
TypeScript

import type { PluginInput } from "@opencode-ai/plugin"
import type { BackgroundManager } from "../../features/background-agent"
import { log } from "../../shared/logger"
import {
COUNTDOWN_SECONDS,
HOOK_NAME,
TOAST_DURATION_MS,
} from "./constants"
import type { ResolvedMessageInfo } from "./types"
import type { SessionStateStore } from "./session-state"
import { injectContinuation } from "./continuation-injection"
async function showCountdownToast(
ctx: PluginInput,
seconds: number,
incompleteCount: number
): Promise<void> {
await ctx.client.tui
.showToast({
body: {
title: "Todo Continuation",
message: `Resuming in ${seconds}s... (${incompleteCount} tasks remaining)`,
variant: "warning" as const,
duration: TOAST_DURATION_MS,
},
})
.catch(() => {})
}
export function startCountdown(args: {
ctx: PluginInput
sessionID: string
incompleteCount: number
total: number
resolvedInfo?: ResolvedMessageInfo
backgroundManager?: BackgroundManager
skipAgents: string[]
sessionStateStore: SessionStateStore
}): void {
const {
ctx,
sessionID,
incompleteCount,
resolvedInfo,
backgroundManager,
skipAgents,
sessionStateStore,
} = args
const state = sessionStateStore.getState(sessionID)
sessionStateStore.cancelCountdown(sessionID)
let secondsRemaining = COUNTDOWN_SECONDS
showCountdownToast(ctx, secondsRemaining, incompleteCount)
state.countdownStartedAt = Date.now()
state.countdownInterval = setInterval(() => {
secondsRemaining--
if (secondsRemaining > 0) {
showCountdownToast(ctx, secondsRemaining, incompleteCount)
}
}, 1000)
state.countdownTimer = setTimeout(() => {
sessionStateStore.cancelCountdown(sessionID)
injectContinuation({
ctx,
sessionID,
backgroundManager,
skipAgents,
resolvedInfo,
sessionStateStore,
})
}, COUNTDOWN_SECONDS * 1000)
log(`[${HOOK_NAME}] Countdown started`, {
sessionID,
seconds: COUNTDOWN_SECONDS,
incompleteCount,
})
}