refactor(runtime-fallback): decompose index.ts into focused modules

Split 1021-line index.ts into 10 focused modules per project conventions.

New structure:

- error-classifier.ts: error analysis with dynamic status code extraction

- agent-resolver.ts: agent detection utilities

- fallback-state.ts: state management and cooldown logic

- fallback-models.ts: model resolution from config

- auto-retry.ts: retry helpers with mutual recursion support

- event-handler.ts: session lifecycle events

- message-update-handler.ts: message.updated event handling

- chat-message-handler.ts: chat message interception

- hook.ts: main factory with proper cleanup

- types.ts: updated with HookDeps interface

- index.ts: 2-line barrel re-export

Embedded fixes:

- Fix setInterval leak with .unref()

- Replace require() with ESM import

- Add log warning on invalid model format

- Update sessionLastAccess on normal traffic

- Make extractStatusCode dynamic from config

- Remove unused SessionErrorInfo type

All 61 tests pass without modification.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Youngbin Kim
2026-02-17 16:29:52 -05:00
committed by YeonGyu-Kim
parent 03c0e5acfc
commit df990f1174
11 changed files with 1106 additions and 1059 deletions
@@ -0,0 +1,54 @@
import { getSessionAgent } from "../../features/claude-code-session-state"
export const AGENT_NAMES = [
"sisyphus",
"oracle",
"librarian",
"explore",
"prometheus",
"atlas",
"metis",
"momus",
"hephaestus",
"sisyphus-junior",
"build",
"plan",
"multimodal-looker",
]
export const agentPattern = new RegExp(
`\\b(${AGENT_NAMES
.sort((a, b) => b.length - a.length)
.map((a) => a.replace(/-/g, "\\-"))
.join("|")})\\b`,
"i",
)
export function detectAgentFromSession(sessionID: string): string | undefined {
const match = sessionID.match(agentPattern)
if (match) {
return match[1].toLowerCase()
}
return undefined
}
export function normalizeAgentName(agent: string | undefined): string | undefined {
if (!agent) return undefined
const normalized = agent.toLowerCase().trim()
if (AGENT_NAMES.includes(normalized)) {
return normalized
}
const match = normalized.match(agentPattern)
if (match) {
return match[1].toLowerCase()
}
return undefined
}
export function resolveAgentForSession(sessionID: string, eventAgent?: string): string | undefined {
return (
normalizeAgentName(eventAgent) ??
normalizeAgentName(getSessionAgent(sessionID)) ??
detectAgentFromSession(sessionID)
)
}