79 lines · 2.7 KB · TypeScript
RawDownload
import { scopeProjectRef } from "@t3tools/client-runtime/environment";import type { EnvironmentId, ProjectId, ScopedProjectRef } from "@t3tools/contracts";import type { DraftThreadEnvMode } from "../composerDraftStore"; interface ThreadContextLike {  environmentId: EnvironmentId;  projectId: ProjectId;} interface NewThreadHandler {  (    projectRef: ScopedProjectRef,    options?: {      branch?: string | null;      worktreePath?: string | null;      envMode?: DraftThreadEnvMode;      startFromOrigin?: boolean;    },  ): Promise<void>;} export interface ChatThreadActionContext {  readonly activeDraftThread: ThreadContextLike | null;  readonly activeThread: ThreadContextLike | undefined;  readonly defaultProjectRef: ScopedProjectRef | null;  readonly handleNewThread: NewThreadHandler;} export function resolveNewDraftStartFromOrigin(input: {  envMode: DraftThreadEnvMode;  newWorktreesStartFromOrigin: boolean;}): boolean {  return input.envMode === "worktree" && input.newWorktreesStartFromOrigin;} 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;} // `defaultProjectRef` resolves to workspaces only by design, so a user whose// sole project is an agent has none — and "new thread" would silently no-op.// The fallback applies only when there is exactly one destination: with// several, an absent default means "no obvious target" and the user should// pick rather than have one chosen for them.export function resolveSoleNewThreadProjectRef(  targets: ReadonlyArray<{ environmentId: EnvironmentId; id: ProjectId }>,): ScopedProjectRef | null {  const sole = targets.length === 1 ? targets[0] : undefined;  return sole ? scopeProjectRef(sole.environmentId, sole.id) : null;} // New threads inherit only the *project* from the current context. Branch,// worktree, and env mode always come from the user's configured defaults —// carrying them over from the viewed thread meant "new thread" silently// reused checkouts and branches. Explicit affordances (branch toolbar's// "new thread in this worktree") pass those options to handleNewThread// directly instead.export async function startNewThreadFromContext(  context: ChatThreadActionContext,): Promise<boolean> {  const projectRef = resolveThreadActionProjectRef(context);  if (!projectRef) {    return false;  }   await context.handleNewThread(projectRef);  return true;}