import { scopeProjectRef } from "@t3tools/client-runtime/environment"; import { DEFAULT_PROVIDER_INTERACTION_MODE, type EnvironmentId, type ProjectId, type ProviderInteractionMode, type RuntimeMode, type ScopedProjectRef, } from "@t3tools/contracts"; import type { DraftThreadEnvMode } from "../composerDraftStore"; interface ThreadContextLike { environmentId: EnvironmentId; projectId: ProjectId; branch: string | null; worktreePath: string | null; } interface DraftThreadContextLike extends ThreadContextLike { envMode: DraftThreadEnvMode; startFromOrigin: boolean; } interface NewThreadHandler { ( projectRef: ScopedProjectRef, options?: { branch?: string | null; worktreePath?: string | null; envMode?: DraftThreadEnvMode; startFromOrigin?: boolean; }, ): Promise; } type NewThreadOptions = NonNullable[1]>; export interface ChatThreadActionContext { readonly activeDraftThread: DraftThreadContextLike | null; readonly activeThread: ThreadContextLike | undefined; readonly defaultProjectRef: ScopedProjectRef | null; readonly defaultThreadEnvMode: DraftThreadEnvMode; readonly handleNewThread: NewThreadHandler; } export function resolveNewDraftStartFromOrigin(input: { envMode: DraftThreadEnvMode; newWorktreesStartFromOrigin: boolean; }): boolean { return input.envMode === "worktree" && input.newWorktreesStartFromOrigin; } export function buildNewDraftExecutionDefaults(defaultRuntimeMode: RuntimeMode): { runtimeMode: RuntimeMode; interactionMode: ProviderInteractionMode; } { return { runtimeMode: defaultRuntimeMode, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, }; } export function resolveThreadActionProjectRef( context: ChatThreadActionContext, ): ScopedProjectRef | null { if (context.activeThread) { return scopeProjectRef(context.activeThread.environmentId, context.activeThread.projectId); } if (context.activeDraftThread) { return scopeProjectRef( context.activeDraftThread.environmentId, context.activeDraftThread.projectId, ); } return context.defaultProjectRef; } function buildContextualThreadOptions(context: ChatThreadActionContext): NewThreadOptions { return { branch: context.activeThread?.branch ?? context.activeDraftThread?.branch ?? null, worktreePath: context.activeThread?.worktreePath ?? context.activeDraftThread?.worktreePath ?? null, envMode: context.activeDraftThread?.envMode ?? (context.activeThread?.worktreePath ? "worktree" : "local"), ...(context.activeDraftThread ? { startFromOrigin: context.activeDraftThread.startFromOrigin } : {}), }; } function buildDefaultThreadOptions(context: ChatThreadActionContext): NewThreadOptions { return { envMode: context.defaultThreadEnvMode, }; } export async function startNewThreadInProjectFromContext( context: ChatThreadActionContext, projectRef: ScopedProjectRef, ): Promise { await context.handleNewThread(projectRef, buildContextualThreadOptions(context)); } export async function startNewThreadFromContext( context: ChatThreadActionContext, ): Promise { const projectRef = resolveThreadActionProjectRef(context); if (!projectRef) { return false; } await startNewThreadInProjectFromContext(context, projectRef); return true; } export async function startNewLocalThreadFromContext( context: ChatThreadActionContext, ): Promise { const projectRef = resolveThreadActionProjectRef(context); if (!projectRef) { return false; } await context.handleNewThread(projectRef, buildDefaultThreadOptions(context)); return true; }