| author | |
| committer | |
| log | 16491a84b9bb2842ad6db41635d087647fc2df5b |
| tree | e0275fe2c0679620cd50db5acae33cb7c075fed4 |
| parent | b44ed835c63caafae619e303ca019a251c2698b2 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>3 files changed, 27 insertions(+), 23 deletions(-)
apps/web/src/components/ChatView.tsx+8-3| ... | @@ -189,6 +189,7 @@ import { useEnvironmentQuery } from "../state/query"; | ... | @@ -189,6 +189,7 @@ import { useEnvironmentQuery } from "../state/query"; |
| 189 | import { | 189 | import { |
| 190 | primaryServerAvailableEditorsAtom, | 190 | primaryServerAvailableEditorsAtom, |
| 191 | primaryServerKeybindingsAtom, | 191 | primaryServerKeybindingsAtom, |
| 192 | primaryServerSettingsAtom, | ||
| 192 | serverEnvironment, | 193 | serverEnvironment, |
| 193 | } from "../state/server"; | 194 | } from "../state/server"; |
| 194 | import { terminalEnvironment } from "../state/terminal"; | 195 | import { terminalEnvironment } from "../state/terminal"; |
| ... | @@ -1153,6 +1154,10 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -1153,6 +1154,10 @@ function ChatViewContent(props: ChatViewProps) { |
| 1153 | (store) => store.threadLastVisitedAtById[routeThreadKey], | 1154 | (store) => store.threadLastVisitedAtById[routeThreadKey], |
| 1154 | ); | 1155 | ); |
| 1155 | const settings = useEnvironmentSettings(environmentId); | 1156 | const settings = useEnvironmentSettings(environmentId); |
| 1157 | // New-thread defaults live in the primary environment's settings.json (the | ||
| 1158 | // settings UI never writes to remote environments), so read them from the | ||
| 1159 | // primary server rather than the thread's environment. | ||
| 1160 | const primaryServerSettings = useAtomValue(primaryServerSettingsAtom); | ||
| 1156 | const setStickyComposerModelSelection = useComposerDraftStore( | 1161 | const setStickyComposerModelSelection = useComposerDraftStore( |
| 1157 | (store) => store.setStickyModelSelection, | 1162 | (store) => store.setStickyModelSelection, |
| 1158 | ); | 1163 | ); |
| ... | @@ -3785,7 +3790,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -3785,7 +3790,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 3785 | ? (draftThread?.startFromOrigin ?? false) | 3790 | ? (draftThread?.startFromOrigin ?? false) |
| 3786 | : canOverrideServerThreadEnvMode | 3791 | : canOverrideServerThreadEnvMode |
| 3787 | ? (pendingServerThreadStartFromOriginByThreadId[activeThread?.id ?? ""] ?? | 3792 | ? (pendingServerThreadStartFromOriginByThreadId[activeThread?.id ?? ""] ?? |
| 3788 | settings.newWorktreesStartFromOrigin) | 3793 | primaryServerSettings.newWorktreesStartFromOrigin) |
| 3789 | : false; | 3794 | : false; |
| 3790 | const sendEnvMode = resolveSendEnvMode({ | 3795 | const sendEnvMode = resolveSendEnvMode({ |
| 3791 | requestedEnvMode: envMode, | 3796 | requestedEnvMode: envMode, |
| ... | @@ -5254,7 +5259,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -5254,7 +5259,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 5254 | envMode: mode, | 5259 | envMode: mode, |
| 5255 | startFromOrigin: resolveNewDraftStartFromOrigin({ | 5260 | startFromOrigin: resolveNewDraftStartFromOrigin({ |
| 5256 | envMode: mode, | 5261 | envMode: mode, |
| 5257 | newWorktreesStartFromOrigin: settings.newWorktreesStartFromOrigin, | 5262 | newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin, |
| 5258 | }), | 5263 | }), |
| 5259 | ...(mode === "worktree" && draftThread?.worktreePath ? { worktreePath: null } : {}), | 5264 | ...(mode === "worktree" && draftThread?.worktreePath ? { worktreePath: null } : {}), |
| 5260 | }); | 5265 | }); |
| ... | @@ -5266,7 +5271,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -5266,7 +5271,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 5266 | composerDraftTarget, | 5271 | composerDraftTarget, |
| 5267 | draftThread?.worktreePath, | 5272 | draftThread?.worktreePath, |
| 5268 | isLocalDraftThread, | 5273 | isLocalDraftThread, |
| 5269 | settings.newWorktreesStartFromOrigin, | 5274 | primaryServerSettings.newWorktreesStartFromOrigin, |
| 5270 | setPendingServerThreadEnvMode, | 5275 | setPendingServerThreadEnvMode, |
| 5271 | scheduleComposerFocus, | 5276 | scheduleComposerFocus, |
| 5272 | setDraftThreadContext, | 5277 | setDraftThreadContext, |
apps/web/src/components/Sidebar.tsx+6-8| ... | @@ -43,7 +43,6 @@ import { restrictToFirstScrollableAncestor, restrictToVerticalAxis } from "@dnd- | ... | @@ -43,7 +43,6 @@ import { restrictToFirstScrollableAncestor, restrictToVerticalAxis } from "@dnd- |
| 43 | import { CSS } from "@dnd-kit/utilities"; | 43 | import { CSS } from "@dnd-kit/utilities"; |
| 44 | import { | 44 | import { |
| 45 | type ContextMenuItem, | 45 | type ContextMenuItem, |
| 46 | DEFAULT_SERVER_SETTINGS, | ||
| 47 | ProjectId, | 46 | ProjectId, |
| 48 | type ScopedThreadRef, | 47 | type ScopedThreadRef, |
| 49 | type ResolvedKeybindingsConfig, | 48 | type ResolvedKeybindingsConfig, |
| ... | @@ -81,7 +80,6 @@ import { | ... | @@ -81,7 +80,6 @@ import { |
| 81 | readThreadShell, | 80 | readThreadShell, |
| 82 | useProject, | 81 | useProject, |
| 83 | useProjects, | 82 | useProjects, |
| 84 | useServerConfigs, | ||
| 85 | useThreadShells, | 83 | useThreadShells, |
| 86 | useThreadShellsForProjectRefs, | 84 | useThreadShellsForProjectRefs, |
| 87 | } from "../state/entities"; | 85 | } from "../state/entities"; |
| ... | @@ -203,7 +201,7 @@ import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; | ... | @@ -203,7 +201,7 @@ import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; |
| 203 | import { useIsMobile } from "~/hooks/useMediaQuery"; | 201 | import { useIsMobile } from "~/hooks/useMediaQuery"; |
| 204 | import { CommandDialogTrigger } from "./ui/command"; | 202 | import { CommandDialogTrigger } from "./ui/command"; |
| 205 | import { useClientSettings, useUpdateClientSettings } from "~/hooks/useSettings"; | 203 | import { useClientSettings, useUpdateClientSettings } from "~/hooks/useSettings"; |
| 206 | import { primaryServerKeybindingsAtom } from "../state/server"; | 204 | import { primaryServerKeybindingsAtom, primaryServerSettingsAtom } from "../state/server"; |
| 207 | import { | 205 | import { |
| 208 | derivePhysicalProjectKey, | 206 | derivePhysicalProjectKey, |
| 209 | deriveProjectGroupingOverrideKey, | 207 | deriveProjectGroupingOverrideKey, |
| ... | @@ -1113,7 +1111,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec | ... | @@ -1113,7 +1111,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec |
| 1113 | (settings) => settings.confirmThreadArchive, | 1111 | (settings) => settings.confirmThreadArchive, |
| 1114 | ); | 1112 | ); |
| 1115 | const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); | 1113 | const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); |
| 1116 | const serverConfigs = useServerConfigs(); | 1114 | const primaryServerSettings = useAtomValue(primaryServerSettingsAtom); |
| 1117 | const deleteProject = useAtomCommand(projectEnvironment.delete, { | 1115 | const deleteProject = useAtomCommand(projectEnvironment.delete, { |
| 1118 | reportFailure: false, | 1116 | reportFailure: false, |
| 1119 | }); | 1117 | }); |
| ... | @@ -1901,10 +1899,10 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec | ... | @@ -1901,10 +1899,10 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec |
| 1901 | : null; | 1899 | : null; |
| 1902 | const seedContext = resolveSidebarNewThreadSeedContext({ | 1900 | const seedContext = resolveSidebarNewThreadSeedContext({ |
| 1903 | projectId: member.id, | 1901 | projectId: member.id, |
| 1902 | // The default env mode is a user preference stored on the primary | ||
| 1903 | // environment's settings.json; remote environments never carry it. | ||
| 1904 | defaultEnvMode: resolveSidebarNewThreadEnvMode({ | 1904 | defaultEnvMode: resolveSidebarNewThreadEnvMode({ |
| 1905 | defaultEnvMode: | 1905 | defaultEnvMode: primaryServerSettings.defaultThreadEnvMode, |
| 1906 | serverConfigs.get(member.environmentId)?.settings.defaultThreadEnvMode ?? | ||
| 1907 | DEFAULT_SERVER_SETTINGS.defaultThreadEnvMode, | ||
| 1908 | }), | 1906 | }), |
| 1909 | activeThread: | 1907 | activeThread: |
| 1910 | currentActiveThread && currentActiveThread.projectId === member.id | 1908 | currentActiveThread && currentActiveThread.projectId === member.id |
| ... | @@ -1953,7 +1951,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec | ... | @@ -1953,7 +1951,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec |
| 1953 | } | 1951 | } |
| 1954 | })(); | 1952 | })(); |
| 1955 | }, | 1953 | }, |
| 1956 | [handleNewThread, isMobile, router, serverConfigs, setOpenMobile], | 1954 | [handleNewThread, isMobile, primaryServerSettings.defaultThreadEnvMode, router, setOpenMobile], |
| 1957 | ); | 1955 | ); |
| 1958 | 1956 | ||
| 1959 | const handleCreateThreadClick = useCallback( | 1957 | const handleCreateThreadClick = useCallback( |
apps/web/src/hooks/useHandleNewThread.ts+13-12| ... | @@ -1,13 +1,10 @@ | ... | @@ -1,13 +1,10 @@ |
| 1 | import { useAtomValue } from "@effect/atom-react"; | ||
| 1 | import { | 2 | import { |
| 2 | scopedProjectKey, | 3 | scopedProjectKey, |
| 3 | scopeProjectRef, | 4 | scopeProjectRef, |
| 4 | scopeThreadRef, | 5 | scopeThreadRef, |
| 5 | } from "@t3tools/client-runtime/environment"; | 6 | } from "@t3tools/client-runtime/environment"; |
| 6 | import { | 7 | import { DEFAULT_RUNTIME_MODE, type ScopedProjectRef } from "@t3tools/contracts"; |
| 7 | DEFAULT_RUNTIME_MODE, | ||
| 8 | DEFAULT_SERVER_SETTINGS, | ||
| 9 | type ScopedProjectRef, | ||
| 10 | } from "@t3tools/contracts"; | ||
| 11 | import { useParams, useRouter } from "@tanstack/react-router"; | 8 | import { useParams, useRouter } from "@tanstack/react-router"; |
| 12 | import { useCallback, useMemo } from "react"; | 9 | import { useCallback, useMemo } from "react"; |
| 13 | import { | 10 | import { |
| ... | @@ -23,15 +20,21 @@ import { | ... | @@ -23,15 +20,21 @@ import { |
| 23 | getProjectOrderKey, | 20 | getProjectOrderKey, |
| 24 | selectProjectGroupingSettings, | 21 | selectProjectGroupingSettings, |
| 25 | } from "../logicalProject"; | 22 | } from "../logicalProject"; |
| 26 | import { readThreadShell, useProjects, useServerConfigs, useThread } from "../state/entities"; | 23 | import { readThreadShell, useProjects, useThread } from "../state/entities"; |
| 27 | import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions"; | 24 | import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions"; |
| 25 | import { primaryServerSettingsAtom } from "../state/server"; | ||
| 28 | import { resolveThreadRouteTarget } from "../threadRoutes"; | 26 | import { resolveThreadRouteTarget } from "../threadRoutes"; |
| 29 | import { legacyProjectCwdPreferenceKey, useUiStateStore } from "../uiStateStore"; | 27 | import { legacyProjectCwdPreferenceKey, useUiStateStore } from "../uiStateStore"; |
| 30 | import { useClientSettings } from "./useSettings"; | 28 | import { useClientSettings } from "./useSettings"; |
| 31 | 29 | ||
| 32 | export function useNewThreadHandler() { | 30 | export function useNewThreadHandler() { |
| 33 | const projects = useProjects(); | 31 | const projects = useProjects(); |
| 34 | const serverConfigs = useServerConfigs(); | 32 | // New-thread defaults are a user preference, and the settings UI only ever |
| 33 | // edits the primary environment's settings.json. Reading the target | ||
| 34 | // environment's own settings here would silently reset remote projects to | ||
| 35 | // the decoded defaults ("local" mode, current branch), since nothing can | ||
| 36 | // set those values on a remote server. | ||
| 37 | const primaryServerSettings = useAtomValue(primaryServerSettingsAtom); | ||
| 35 | const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); | 38 | const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); |
| 36 | const router = useRouter(); | 39 | const router = useRouter(); |
| 37 | const getCurrentRouteTarget = useCallback(() => { | 40 | const getCurrentRouteTarget = useCallback(() => { |
| ... | @@ -64,8 +67,6 @@ export function useNewThreadHandler() { | ... | @@ -64,8 +67,6 @@ export function useNewThreadHandler() { |
| 64 | candidate.id === projectRef.projectId && | 67 | candidate.id === projectRef.projectId && |
| 65 | candidate.environmentId === projectRef.environmentId, | 68 | candidate.environmentId === projectRef.environmentId, |
| 66 | ); | 69 | ); |
| 67 | const environmentSettings = | ||
| 68 | serverConfigs.get(projectRef.environmentId)?.settings ?? DEFAULT_SERVER_SETTINGS; | ||
| 69 | const logicalProjectKey = project | 70 | const logicalProjectKey = project |
| 70 | ? deriveLogicalProjectKeyFromSettings(project, projectGroupingSettings) | 71 | ? deriveLogicalProjectKeyFromSettings(project, projectGroupingSettings) |
| 71 | : scopedProjectKey(projectRef); | 72 | : scopedProjectKey(projectRef); |
| ... | @@ -161,7 +162,7 @@ export function useNewThreadHandler() { | ... | @@ -161,7 +162,7 @@ export function useNewThreadHandler() { |
| 161 | const draftId = newDraftId(); | 162 | const draftId = newDraftId(); |
| 162 | const threadId = newThreadId(); | 163 | const threadId = newThreadId(); |
| 163 | const createdAt = new Date().toISOString(); | 164 | const createdAt = new Date().toISOString(); |
| 164 | const initialEnvMode = options?.envMode ?? environmentSettings.defaultThreadEnvMode; | 165 | const initialEnvMode = options?.envMode ?? primaryServerSettings.defaultThreadEnvMode; |
| 165 | return (async () => { | 166 | return (async () => { |
| 166 | setLogicalProjectDraftThreadId(logicalProjectKey, projectRef, draftId, { | 167 | setLogicalProjectDraftThreadId(logicalProjectKey, projectRef, draftId, { |
| 167 | threadId, | 168 | threadId, |
| ... | @@ -173,7 +174,7 @@ export function useNewThreadHandler() { | ... | @@ -173,7 +174,7 @@ export function useNewThreadHandler() { |
| 173 | options?.startFromOrigin ?? | 174 | options?.startFromOrigin ?? |
| 174 | resolveNewDraftStartFromOrigin({ | 175 | resolveNewDraftStartFromOrigin({ |
| 175 | envMode: initialEnvMode, | 176 | envMode: initialEnvMode, |
| 176 | newWorktreesStartFromOrigin: environmentSettings.newWorktreesStartFromOrigin, | 177 | newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin, |
| 177 | }), | 178 | }), |
| 178 | runtimeMode: DEFAULT_RUNTIME_MODE, | 179 | runtimeMode: DEFAULT_RUNTIME_MODE, |
| 179 | }); | 180 | }); |
| ... | @@ -186,7 +187,7 @@ export function useNewThreadHandler() { | ... | @@ -186,7 +187,7 @@ export function useNewThreadHandler() { |
| 186 | }); | 187 | }); |
| 187 | })(); | 188 | })(); |
| 188 | }, | 189 | }, |
| 189 | [getCurrentRouteTarget, projectGroupingSettings, projects, router, serverConfigs], | 190 | [getCurrentRouteTarget, primaryServerSettings, projectGroupingSettings, projects, router], |
| 190 | ); | 191 | ); |
| 191 | } | 192 | } |
| 192 | 193 |