oh-my-opencode/src/cli/run/poll-for-completion.ts
YeonGyu-Kim 1199e2b839 fix(background): Wave 2 - fix interrupt status checks, display text, error recovery grace, LSP JSONC
- fix(background): include "interrupt" status in all terminal status checks (3 files)
- fix(background): display "INTERRUPTED" instead of "CANCELLED" for interrupted tasks
- fix(cli): add error recovery grace period in poll-for-completion
- fix(lsp): use JSONC parser for config loading to support comments

All changes verified with tests and typecheck.
2026-02-10 22:00:54 +09:00

78 lines
2.1 KiB
TypeScript

import pc from "picocolors"
import type { RunContext } from "./types"
import type { EventState } from "./events"
import { checkCompletionConditions } from "./completion"
const DEFAULT_POLL_INTERVAL_MS = 500
const DEFAULT_REQUIRED_CONSECUTIVE = 3
const ERROR_GRACE_CYCLES = 3
export interface PollOptions {
pollIntervalMs?: number
requiredConsecutive?: number
}
export async function pollForCompletion(
ctx: RunContext,
eventState: EventState,
abortController: AbortController,
options: PollOptions = {}
): Promise<number> {
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS
const requiredConsecutive =
options.requiredConsecutive ?? DEFAULT_REQUIRED_CONSECUTIVE
let consecutiveCompleteChecks = 0
let errorCycleCount = 0
while (!abortController.signal.aborted) {
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs))
// ERROR CHECK FIRST — errors must not be masked by other gates
if (eventState.mainSessionError) {
errorCycleCount++
if (errorCycleCount >= ERROR_GRACE_CYCLES) {
console.error(
pc.red(`\n\nSession ended with error: ${eventState.lastError}`)
)
console.error(
pc.yellow("Check if todos were completed before the error.")
)
return 1
}
// Continue polling during grace period to allow recovery
continue
} else {
// Reset error counter when error clears (recovery succeeded)
errorCycleCount = 0
}
if (!eventState.mainSessionIdle) {
consecutiveCompleteChecks = 0
continue
}
if (eventState.currentTool !== null) {
consecutiveCompleteChecks = 0
continue
}
if (!eventState.hasReceivedMeaningfulWork) {
consecutiveCompleteChecks = 0
continue
}
const shouldExit = await checkCompletionConditions(ctx)
if (shouldExit) {
consecutiveCompleteChecks++
if (consecutiveCompleteChecks >= requiredConsecutive) {
console.log(pc.green("\n\nAll tasks completed."))
return 0
}
} else {
consecutiveCompleteChecks = 0
}
}
return 130
}