d0bd24bede
Use hook-written continuation marker state to gate run completion checks and remove the noisy event-stream shutdown timeout log in run mode.
81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
import { join } from "node:path"
|
|
import { CONTINUATION_MARKER_DIR } from "./constants"
|
|
import type {
|
|
ContinuationMarker,
|
|
ContinuationMarkerSource,
|
|
ContinuationMarkerState,
|
|
} from "./types"
|
|
|
|
function getMarkerPath(directory: string, sessionID: string): string {
|
|
return join(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`)
|
|
}
|
|
|
|
export function readContinuationMarker(
|
|
directory: string,
|
|
sessionID: string,
|
|
): ContinuationMarker | null {
|
|
const markerPath = getMarkerPath(directory, sessionID)
|
|
if (!existsSync(markerPath)) return null
|
|
|
|
try {
|
|
const raw = readFileSync(markerPath, "utf-8")
|
|
const parsed = JSON.parse(raw)
|
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null
|
|
return parsed as ContinuationMarker
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function setContinuationMarkerSource(
|
|
directory: string,
|
|
sessionID: string,
|
|
source: ContinuationMarkerSource,
|
|
state: ContinuationMarkerState,
|
|
reason?: string,
|
|
): ContinuationMarker {
|
|
const now = new Date().toISOString()
|
|
const existing = readContinuationMarker(directory, sessionID)
|
|
const next: ContinuationMarker = {
|
|
sessionID,
|
|
updatedAt: now,
|
|
sources: {
|
|
...(existing?.sources ?? {}),
|
|
[source]: {
|
|
state,
|
|
...(reason ? { reason } : {}),
|
|
updatedAt: now,
|
|
},
|
|
},
|
|
}
|
|
|
|
const markerPath = getMarkerPath(directory, sessionID)
|
|
mkdirSync(join(directory, CONTINUATION_MARKER_DIR), { recursive: true })
|
|
writeFileSync(markerPath, JSON.stringify(next, null, 2), "utf-8")
|
|
return next
|
|
}
|
|
|
|
export function clearContinuationMarker(directory: string, sessionID: string): void {
|
|
const markerPath = getMarkerPath(directory, sessionID)
|
|
if (!existsSync(markerPath)) return
|
|
|
|
try {
|
|
rmSync(markerPath)
|
|
} catch {
|
|
}
|
|
}
|
|
|
|
export function isContinuationMarkerActive(marker: ContinuationMarker | null): boolean {
|
|
if (!marker) return false
|
|
return Object.values(marker.sources).some((entry) => entry?.state === "active")
|
|
}
|
|
|
|
export function getActiveContinuationMarkerReason(marker: ContinuationMarker | null): string | null {
|
|
if (!marker) return null
|
|
const active = Object.entries(marker.sources).find(([, entry]) => entry?.state === "active")
|
|
if (!active || !active[1]) return null
|
|
const [source, entry] = active
|
|
return entry.reason ?? `${source} continuation is active`
|
|
}
|