import { useAtomValue } from "@effect/atom-react"; import type { EnvironmentProject, EnvironmentThread, EnvironmentThreadShell, } from "@t3tools/client-runtime/state/shell"; import { mergeEnvironmentThread } from "@t3tools/client-runtime/state/threads"; import type { OrchestrationMessage, OrchestrationProposedPlan, OrchestrationSession, OrchestrationThreadActivity, ScopedProjectRef, ScopedThreadRef, ServerConfig, } from "@t3tools/contracts"; import type { EnvironmentId, ThreadId } from "@t3tools/contracts"; import { Atom } from "effect/unstable/reactivity"; import { useMemo } from "react"; import { appAtomRegistry } from "../rpc/atomRegistry"; import { environmentProjects } from "./projects"; import { environmentServerConfigsAtom } from "./server"; import { environmentThreadDetails, environmentThreadShells } from "./threads"; const EMPTY_PROJECT_REFS: ReadonlyArray = Object.freeze([]); const EMPTY_THREAD_REFS: ReadonlyArray = Object.freeze([]); const EMPTY_MESSAGES: ReadonlyArray = Object.freeze([]); const EMPTY_ACTIVITIES: ReadonlyArray = Object.freeze([]); const EMPTY_PROPOSED_PLANS: ReadonlyArray = Object.freeze([]); const EMPTY_PROJECT_ATOM = Atom.make(null).pipe( Atom.withLabel("web-project:empty"), ); const EMPTY_PROJECT_REFS_ATOM = Atom.make(EMPTY_PROJECT_REFS).pipe( Atom.withLabel("web-project-refs:empty"), ); const EMPTY_THREAD_REFS_ATOM = Atom.make(EMPTY_THREAD_REFS).pipe( Atom.withLabel("web-thread-refs:empty"), ); const EMPTY_THREAD_SHELL_ATOM = Atom.make(null).pipe( Atom.withLabel("web-thread-shell:empty"), ); const EMPTY_THREAD_DETAIL_ATOM = Atom.make(null).pipe( Atom.withLabel("web-thread-detail:empty"), ); const EMPTY_MESSAGES_ATOM = Atom.make(EMPTY_MESSAGES).pipe( Atom.withLabel("web-thread-messages:empty"), ); const EMPTY_ACTIVITIES_ATOM = Atom.make(EMPTY_ACTIVITIES).pipe( Atom.withLabel("web-thread-activities:empty"), ); const EMPTY_PROPOSED_PLANS_ATOM = Atom.make(EMPTY_PROPOSED_PLANS).pipe( Atom.withLabel("web-thread-proposed-plans:empty"), ); const EMPTY_SESSION_ATOM = Atom.make(null).pipe( Atom.withLabel("web-thread-session:empty"), ); export const activeEnvironmentIdAtom = Atom.make(null).pipe( Atom.keepAlive, Atom.withLabel("web-active-environment-id"), ); export function useActiveEnvironmentId(): EnvironmentId | null { return useAtomValue(activeEnvironmentIdAtom); } export function readActiveEnvironmentId(): EnvironmentId | null { return appAtomRegistry.get(activeEnvironmentIdAtom); } export function setActiveEnvironmentId(environmentId: EnvironmentId | null): void { appAtomRegistry.set(activeEnvironmentIdAtom, environmentId); } export function useProjectRefs(): ReadonlyArray { return useAtomValue(environmentProjects.projectRefsAtom); } export function useThreadRefs(): ReadonlyArray { return useAtomValue(environmentThreadShells.threadRefsAtom); } export function useEnvironmentProjectRefs( environmentId: EnvironmentId | null, ): ReadonlyArray { return useAtomValue( environmentId === null ? EMPTY_PROJECT_REFS_ATOM : environmentProjects.environmentProjectRefsAtom(environmentId), ); } export function useEnvironmentThreadRefs( environmentId: EnvironmentId | null, ): ReadonlyArray { return useAtomValue( environmentId === null ? EMPTY_THREAD_REFS_ATOM : environmentThreadShells.environmentThreadRefsAtom(environmentId), ); } export function useProjects(): ReadonlyArray { return useAtomValue(environmentProjects.projectsAtom); } export function useServerConfigs(): ReadonlyMap { return useAtomValue(environmentServerConfigsAtom); } export function useThreadShells(): ReadonlyArray { return useAtomValue(environmentThreadShells.threadShellsAtom); } export function useThreadShellsForProjectRefs( refs: ReadonlyArray, ): ReadonlyArray { return useAtomValue(environmentThreadShells.threadShellsForProjectRefsAtom(refs)); } export function useProject(ref: ScopedProjectRef | null): EnvironmentProject | null { return useAtomValue(ref === null ? EMPTY_PROJECT_ATOM : environmentProjects.projectAtom(ref)); } export function useThreadShell(ref: ScopedThreadRef | null): EnvironmentThreadShell | null { return useAtomValue( ref === null ? EMPTY_THREAD_SHELL_ATOM : environmentThreadShells.threadShellAtom(ref), ); } export function useThreadDetail(ref: ScopedThreadRef | null): EnvironmentThread | null { return useAtomValue( ref === null ? EMPTY_THREAD_DETAIL_ATOM : environmentThreadDetails.detailAtom(ref), ); } /** Detail collections composed with shell-authoritative thread/workspace metadata. */ export function useThread(ref: ScopedThreadRef | null): EnvironmentThread | null { const shell = useThreadShell(ref); const detail = useThreadDetail(ref); return useMemo(() => mergeEnvironmentThread(detail, shell), [detail, shell]); } export function useThreadMessages( ref: ScopedThreadRef | null, ): ReadonlyArray { return useAtomValue( ref === null ? EMPTY_MESSAGES_ATOM : environmentThreadDetails.messagesAtom(ref), ); } export function useThreadActivities( ref: ScopedThreadRef | null, ): ReadonlyArray { return useAtomValue( ref === null ? EMPTY_ACTIVITIES_ATOM : environmentThreadDetails.activitiesAtom(ref), ); } export function useThreadProposedPlans( ref: ScopedThreadRef | null, ): ReadonlyArray { return useAtomValue( ref === null ? EMPTY_PROPOSED_PLANS_ATOM : environmentThreadDetails.proposedPlansAtom(ref), ); } export function useThreadSession(ref: ScopedThreadRef | null): OrchestrationSession | null { return useAtomValue( ref === null ? EMPTY_SESSION_ATOM : environmentThreadDetails.sessionAtom(ref), ); } export function readProject(ref: ScopedProjectRef): EnvironmentProject | null { return appAtomRegistry.get(environmentProjects.projectAtom(ref)); } export function readThreadShell(ref: ScopedThreadRef): EnvironmentThreadShell | null { return appAtomRegistry.get(environmentThreadShells.threadShellAtom(ref)); } export function readThreadDetail(ref: ScopedThreadRef): EnvironmentThread | null { return appAtomRegistry.get(environmentThreadDetails.detailAtom(ref)); } export function readEnvironmentThreadRefs( environmentId: EnvironmentId, ): ReadonlyArray { return appAtomRegistry.get(environmentThreadShells.environmentThreadRefsAtom(environmentId)); } export function readThreadRefs(): ReadonlyArray { return appAtomRegistry.get(environmentThreadShells.threadRefsAtom); } export function findThreadRef(threadId: ThreadId): ScopedThreadRef | null { return ( appAtomRegistry .get(environmentThreadShells.threadRefsAtom) .find((ref) => ref.threadId === threadId) ?? null ); }