diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index f3145df4500..d0f6bababe9 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -188,6 +188,7 @@ import { useEnvironmentQuery } from "../state/query"; import { primaryServerAvailableEditorsAtom, primaryServerKeybindingsAtom, + primaryServerSettingsAtom, serverEnvironment, } from "../state/server"; import { terminalEnvironment } from "../state/terminal"; @@ -1139,6 +1140,10 @@ function ChatViewContent(props: ChatViewProps) { (store) => store.threadLastVisitedAtById[routeThreadKey], ); const settings = useEnvironmentSettings(environmentId); + // New-thread defaults live in the primary environment's settings.json (the + // settings UI never writes to remote environments), so read them from the + // primary server rather than the thread's environment. + const primaryServerSettings = useAtomValue(primaryServerSettingsAtom); const setStickyComposerModelSelection = useComposerDraftStore( (store) => store.setStickyModelSelection, ); @@ -3734,7 +3739,7 @@ function ChatViewContent(props: ChatViewProps) { ? (draftThread?.startFromOrigin ?? false) : canOverrideServerThreadEnvMode ? (pendingServerThreadStartFromOriginByThreadId[activeThread?.id ?? ""] ?? - settings.newWorktreesStartFromOrigin) + primaryServerSettings.newWorktreesStartFromOrigin) : false; const sendEnvMode = resolveSendEnvMode({ requestedEnvMode: envMode, @@ -5023,7 +5028,7 @@ function ChatViewContent(props: ChatViewProps) { envMode: mode, startFromOrigin: resolveNewDraftStartFromOrigin({ envMode: mode, - newWorktreesStartFromOrigin: settings.newWorktreesStartFromOrigin, + newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin, }), ...(mode === "worktree" && draftThread?.worktreePath ? { worktreePath: null } : {}), }); @@ -5035,7 +5040,7 @@ function ChatViewContent(props: ChatViewProps) { composerDraftTarget, draftThread?.worktreePath, isLocalDraftThread, - settings.newWorktreesStartFromOrigin, + primaryServerSettings.newWorktreesStartFromOrigin, setPendingServerThreadEnvMode, scheduleComposerFocus, setDraftThreadContext, diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index cf3fa30cf8d..217bdbd5af1 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -42,7 +42,6 @@ import { restrictToFirstScrollableAncestor, restrictToVerticalAxis } from "@dnd- import { CSS } from "@dnd-kit/utilities"; import { type ContextMenuItem, - DEFAULT_SERVER_SETTINGS, ProjectId, type ScopedThreadRef, type ResolvedKeybindingsConfig, @@ -80,7 +79,6 @@ import { readThreadShell, useProject, useProjects, - useServerConfigs, useThreadShells, useThreadShellsForProjectRefs, } from "../state/entities"; @@ -202,7 +200,7 @@ import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; import { useIsMobile } from "~/hooks/useMediaQuery"; import { CommandDialogTrigger } from "./ui/command"; import { useClientSettings, useUpdateClientSettings } from "~/hooks/useSettings"; -import { primaryServerKeybindingsAtom } from "../state/server"; +import { primaryServerKeybindingsAtom, primaryServerSettingsAtom } from "../state/server"; import { derivePhysicalProjectKey, deriveProjectGroupingOverrideKey, @@ -1106,7 +1104,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec (settings) => settings.confirmThreadArchive, ); const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); - const serverConfigs = useServerConfigs(); + const primaryServerSettings = useAtomValue(primaryServerSettingsAtom); const deleteProject = useAtomCommand(projectEnvironment.delete, { reportFailure: false, }); @@ -1894,10 +1892,10 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec : null; const seedContext = resolveSidebarNewThreadSeedContext({ projectId: member.id, + // The default env mode is a user preference stored on the primary + // environment's settings.json; remote environments never carry it. defaultEnvMode: resolveSidebarNewThreadEnvMode({ - defaultEnvMode: - serverConfigs.get(member.environmentId)?.settings.defaultThreadEnvMode ?? - DEFAULT_SERVER_SETTINGS.defaultThreadEnvMode, + defaultEnvMode: primaryServerSettings.defaultThreadEnvMode, }), activeThread: currentActiveThread && currentActiveThread.projectId === member.id @@ -1946,7 +1944,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec } })(); }, - [handleNewThread, isMobile, router, serverConfigs, setOpenMobile], + [handleNewThread, isMobile, primaryServerSettings.defaultThreadEnvMode, router, setOpenMobile], ); const handleCreateThreadClick = useCallback( diff --git a/apps/web/src/hooks/useHandleNewThread.ts b/apps/web/src/hooks/useHandleNewThread.ts index 232551349db..cd8546893b0 100644 --- a/apps/web/src/hooks/useHandleNewThread.ts +++ b/apps/web/src/hooks/useHandleNewThread.ts @@ -1,13 +1,10 @@ +import { useAtomValue } from "@effect/atom-react"; import { scopedProjectKey, scopeProjectRef, scopeThreadRef, } from "@t3tools/client-runtime/environment"; -import { - DEFAULT_RUNTIME_MODE, - DEFAULT_SERVER_SETTINGS, - type ScopedProjectRef, -} from "@t3tools/contracts"; +import { DEFAULT_RUNTIME_MODE, type ScopedProjectRef } from "@t3tools/contracts"; import { useParams, useRouter } from "@tanstack/react-router"; import { useCallback, useMemo } from "react"; import { @@ -23,15 +20,21 @@ import { getProjectOrderKey, selectProjectGroupingSettings, } from "../logicalProject"; -import { readThreadShell, useProjects, useServerConfigs, useThread } from "../state/entities"; +import { readThreadShell, useProjects, useThread } from "../state/entities"; import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions"; +import { primaryServerSettingsAtom } from "../state/server"; import { resolveThreadRouteTarget } from "../threadRoutes"; import { legacyProjectCwdPreferenceKey, useUiStateStore } from "../uiStateStore"; import { useClientSettings } from "./useSettings"; export function useNewThreadHandler() { const projects = useProjects(); - const serverConfigs = useServerConfigs(); + // New-thread defaults are a user preference, and the settings UI only ever + // edits the primary environment's settings.json. Reading the target + // environment's own settings here would silently reset remote projects to + // the decoded defaults ("local" mode, current branch), since nothing can + // set those values on a remote server. + const primaryServerSettings = useAtomValue(primaryServerSettingsAtom); const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); const router = useRouter(); const getCurrentRouteTarget = useCallback(() => { @@ -64,8 +67,6 @@ export function useNewThreadHandler() { candidate.id === projectRef.projectId && candidate.environmentId === projectRef.environmentId, ); - const environmentSettings = - serverConfigs.get(projectRef.environmentId)?.settings ?? DEFAULT_SERVER_SETTINGS; const logicalProjectKey = project ? deriveLogicalProjectKeyFromSettings(project, projectGroupingSettings) : scopedProjectKey(projectRef); @@ -161,7 +162,7 @@ export function useNewThreadHandler() { const draftId = newDraftId(); const threadId = newThreadId(); const createdAt = new Date().toISOString(); - const initialEnvMode = options?.envMode ?? environmentSettings.defaultThreadEnvMode; + const initialEnvMode = options?.envMode ?? primaryServerSettings.defaultThreadEnvMode; return (async () => { setLogicalProjectDraftThreadId(logicalProjectKey, projectRef, draftId, { threadId, @@ -173,7 +174,7 @@ export function useNewThreadHandler() { options?.startFromOrigin ?? resolveNewDraftStartFromOrigin({ envMode: initialEnvMode, - newWorktreesStartFromOrigin: environmentSettings.newWorktreesStartFromOrigin, + newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin, }), runtimeMode: DEFAULT_RUNTIME_MODE, }); @@ -186,7 +187,7 @@ export function useNewThreadHandler() { }); })(); }, - [getCurrentRouteTarget, projectGroupingSettings, projects, router, serverConfigs], + [getCurrentRouteTarget, primaryServerSettings, projectGroupingSettings, projects, router], ); }