- Fix #1991 crash: optional chaining for task-history sessionID access - Fix #1992 think-mode: add antigravity entries to HIGH_VARIANT_MAP - Fix #1949 Copilot premium misattribution: use createInternalAgentTextPart - Fix #1982 load_skills: pass directory to discoverSkills for project-level skills - Fix command priority: sort scopePriority before .find(), project-first return - Fix Google provider transform: apply in userFallbackModels path - Fix ralph-loop TUI: optional chaining for event handler - Fix runtime-fallback: unify dual fallback engines, remove HTTP 400 from retry, fix pendingFallbackModel stuck state, add priority gate to skip model-fallback when runtime-fallback is active - Fix Prometheus task system: exempt from todowrite/todoread deny - Fix background_output: default full_session to true - Remove orphan hooks: hashline-edit-diff-enhancer (redundant with hashline_edit built-in diff), task-reminder (dead code) - Remove orphan config entries: 3 stale hook names from Zod schema - Fix disabled_hooks schema: accept arbitrary strings for forward compatibility - Register json-error-recovery hook in tool-guard pipeline - Add disabled_hooks gating for question-label-truncator, task-resume-info, claude-code-hooks - Update test expectations to match new behavior
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import type { BackgroundTaskStatus } from "./types"
|
|
|
|
const MAX_ENTRIES_PER_PARENT = 100
|
|
|
|
export interface TaskHistoryEntry {
|
|
id: string
|
|
sessionID?: string
|
|
agent: string
|
|
description: string
|
|
status: BackgroundTaskStatus
|
|
category?: string
|
|
startedAt?: Date
|
|
completedAt?: Date
|
|
}
|
|
|
|
export class TaskHistory {
|
|
private entries: Map<string, TaskHistoryEntry[]> = new Map()
|
|
|
|
record(parentSessionID: string | undefined, entry: TaskHistoryEntry): void {
|
|
if (!parentSessionID) return
|
|
|
|
const list = this.entries.get(parentSessionID) ?? []
|
|
const existing = list.findIndex((e) => e.id === entry.id)
|
|
|
|
if (existing !== -1) {
|
|
const current = list[existing]
|
|
list[existing] = {
|
|
...current,
|
|
...(entry.sessionID !== undefined ? { sessionID: entry.sessionID } : {}),
|
|
...(entry.agent !== undefined ? { agent: entry.agent } : {}),
|
|
...(entry.description !== undefined ? { description: entry.description } : {}),
|
|
...(entry.status !== undefined ? { status: entry.status } : {}),
|
|
...(entry.category !== undefined ? { category: entry.category } : {}),
|
|
...(entry.startedAt !== undefined ? { startedAt: entry.startedAt } : {}),
|
|
...(entry.completedAt !== undefined ? { completedAt: entry.completedAt } : {}),
|
|
}
|
|
} else {
|
|
if (list.length >= MAX_ENTRIES_PER_PARENT) {
|
|
list.shift()
|
|
}
|
|
list.push({ ...entry })
|
|
}
|
|
|
|
this.entries.set(parentSessionID, list)
|
|
}
|
|
|
|
getByParentSession(parentSessionID: string): TaskHistoryEntry[] {
|
|
const list = this.entries.get(parentSessionID)
|
|
if (!list) return []
|
|
return list.map((e) => ({ ...e }))
|
|
}
|
|
|
|
clearSession(parentSessionID: string): void {
|
|
this.entries.delete(parentSessionID)
|
|
}
|
|
|
|
formatForCompaction(parentSessionID: string): string | null {
|
|
const list = this.getByParentSession(parentSessionID)
|
|
if (list.length === 0) return null
|
|
|
|
const lines = list.map((e) => {
|
|
const desc = e.description?.replace(/[\n\r]+/g, " ").trim() ?? ""
|
|
const parts = [
|
|
`- **${e.agent}**`,
|
|
e.category ? `[${e.category}]` : null,
|
|
`(${e.status})`,
|
|
`: ${desc}`,
|
|
e.sessionID ? ` | session: \`${e.sessionID}\`` : null,
|
|
]
|
|
return parts.filter(Boolean).join("")
|
|
})
|
|
|
|
return lines.join("\n")
|
|
}
|
|
}
|