import { batch, createMemo, type Accessor } from "solid-js" import type { ToolState } from "@opencode-ai/sdk" import type { Session } from "../../../types/session" import { activeParentSessionId, activeSessionId as activeSessionMap, getSessionFamily, getSessionInfo, getSessionThreads, sessions, setActiveParentSession, setActiveSession, } from "../../../stores/sessions" import { messageStoreBus } from "../../../stores/message-v2/bus" import { getBackgroundProcesses } from "../../../stores/background-processes" import type { LatestTodoSnapshot, SessionUsageState } from "../../../stores/message-v2/types" type InstanceSessionContextOptions = { instanceId: Accessor } type InstanceSessionContextState = { // Session collections and selections allInstanceSessions: Accessor> sessionThreads: Accessor> activeSessions: Accessor> activeSessionIdForInstance: Accessor parentSessionIdForInstance: Accessor activeSessionForInstance: Accessor activeSessionDiffs: Accessor // Usage / info summaries activeSessionUsage: Accessor activeSessionInfoDetails: Accessor | null> tokenStats: Accessor<{ used: number; avail: number | null }> // Todo state latestTodoSnapshot: Accessor latestTodoState: Accessor // Background processes backgroundProcessList: Accessor> // Controller handleSessionSelect: (sessionId: string) => void } type SessionFamilyMember = ReturnType[number] export function useInstanceSessionContext(options: InstanceSessionContextOptions): InstanceSessionContextState { const messageStore = createMemo(() => messageStoreBus.getOrCreate(options.instanceId())) const allInstanceSessions = createMemo>(() => { return sessions().get(options.instanceId()) ?? new Map() }) const sessionThreads = createMemo(() => getSessionThreads(options.instanceId())) const activeSessions = createMemo(() => { const parentId = activeParentSessionId().get(options.instanceId()) if (!parentId) return new Map[number]>() const sessionFamily = getSessionFamily(options.instanceId(), parentId) return new Map(sessionFamily.map((s) => [s.id, s])) }) const activeSessionIdForInstance = createMemo(() => { return activeSessionMap().get(options.instanceId()) || null }) const parentSessionIdForInstance = createMemo(() => { return activeParentSessionId().get(options.instanceId()) || null }) const activeSessionForInstance = createMemo(() => { const sessionId = activeSessionIdForInstance() if (!sessionId || sessionId === "info") return null return activeSessions().get(sessionId) ?? null }) const activeSessionDiffs = createMemo(() => { const session = activeSessionForInstance() return session?.diff }) const activeSessionUsage = createMemo(() => { const sessionId = activeSessionIdForInstance() if (!sessionId) return null const store = messageStore() return store?.getSessionUsage(sessionId) ?? null }) const activeSessionInfoDetails = createMemo(() => { const sessionId = activeSessionIdForInstance() if (!sessionId) return null return getSessionInfo(options.instanceId(), sessionId) ?? null }) const tokenStats = createMemo(() => { const usage = activeSessionUsage() const info = activeSessionInfoDetails() return { used: usage?.actualUsageTokens ?? info?.actualUsageTokens ?? 0, avail: info?.contextAvailableTokens ?? null, } }) const latestTodoSnapshot = createMemo(() => { const sessionId = activeSessionIdForInstance() if (!sessionId || sessionId === "info") return null const store = messageStore() if (!store) return null const snapshot = store.state.latestTodos[sessionId] return snapshot ?? null }) const latestTodoState = createMemo(() => { const snapshot = latestTodoSnapshot() if (!snapshot) return null const store = messageStore() if (!store) return null const message = store.getMessage(snapshot.messageId) if (!message) return null const partRecord = message.parts?.[snapshot.partId] const part = partRecord?.data as { type?: string; tool?: string; state?: ToolState } if (!part || part.type !== "tool" || part.tool !== "todowrite") return null const state = part.state if (!state || state.status !== "completed") return null return state }) const backgroundProcessList = createMemo(() => getBackgroundProcesses(options.instanceId())) const handleSessionSelect = (sessionId: string) => { const instanceId = options.instanceId() if (sessionId === "info") { setActiveSession(instanceId, sessionId) return } const session = allInstanceSessions().get(sessionId) if (!session) return if (session.parentId === null) { setActiveParentSession(instanceId, sessionId) return } const parentId = session.parentId if (!parentId) return batch(() => { setActiveParentSession(instanceId, parentId) setActiveSession(instanceId, sessionId) }) } return { allInstanceSessions, sessionThreads, activeSessions, activeSessionIdForInstance, parentSessionIdForInstance, activeSessionForInstance, activeSessionDiffs, activeSessionUsage, activeSessionInfoDetails, tokenStats, latestTodoSnapshot, latestTodoState, backgroundProcessList, handleSessionSelect, } }