Skip to content

Commit 646f549

Browse files
IAmJSDclaude
andcommitted
fix(web): finish the settings-environment migration
Two consumers were left on the primary environment after the settings panels moved to the resolved settings environment, so on a hosted session with no primary device they disagreed with the panels that write them. - New-thread defaults (`defaultThreadEnvMode`, `newWorktreesStartFromOrigin`) read `primaryServerSettingsAtom` in `useNewThreadHandler` and `ChatView`, so the General controls saved and re-displayed while new drafts kept the schema defaults. Both now read `settingsServerSettingsAtom` — the environment those controls write. - `SourceControlSettingsPanel` still resolved its discovery target and gated `SourceControlWritingSettingsSection` on `usePrimaryEnvironment`, so the writer-model and fetch-interval controls never mounted there. It now uses `useSettingsEnvironmentId`, matching the section's own hooks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 31a9067 commit 646f549

3 files changed

Lines changed: 24 additions & 19 deletions

File tree

apps/web/src/components/ChatView.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ import { useEnvironmentQuery } from "../state/query";
220220
import {
221221
primaryServerAvailableEditorsAtom,
222222
primaryServerKeybindingsAtom,
223-
primaryServerSettingsAtom,
224223
serverEnvironment,
224+
settingsServerSettingsAtom,
225225
} from "../state/server";
226226
import { terminalEnvironment } from "../state/terminal";
227227
import { threadEnvironment, useEnvironmentThread } from "../state/threads";
@@ -1261,10 +1261,10 @@ function ChatViewContent(props: ChatViewProps) {
12611261
}, [routeKind, routeThreadRef, routeThreadState]);
12621262
const markThreadVisited = useUiStateStore((store) => store.markThreadVisited);
12631263
const settings = useEnvironmentSettings(environmentId);
1264-
// New-thread defaults live in the primary environment's settings.json (the
1265-
// settings UI never writes to remote environments), so read them from the
1266-
// primary server rather than the thread's environment.
1267-
const primaryServerSettings = useAtomValue(primaryServerSettingsAtom);
1264+
// New-thread defaults live in the settings environment's settings.json
1265+
// the one the settings UI writes to so read them from there rather than
1266+
// from the thread's own environment.
1267+
const settingsServerSettings = useAtomValue(settingsServerSettingsAtom);
12681268
const setStickyComposerModelSelection = useComposerDraftStore(
12691269
(store) => store.setStickyModelSelection,
12701270
);
@@ -3980,7 +3980,7 @@ function ChatViewContent(props: ChatViewProps) {
39803980
? (draftThread?.startFromOrigin ?? false)
39813981
: canOverrideServerThreadEnvMode
39823982
? (pendingServerThreadStartFromOriginByThreadId[activeThread?.id ?? ""] ??
3983-
primaryServerSettings.newWorktreesStartFromOrigin)
3983+
settingsServerSettings.newWorktreesStartFromOrigin)
39843984
: false;
39853985
const sendEnvMode = resolveSendEnvMode({
39863986
requestedEnvMode: envMode,
@@ -5816,7 +5816,7 @@ function ChatViewContent(props: ChatViewProps) {
58165816
envMode: mode,
58175817
startFromOrigin: resolveNewDraftStartFromOrigin({
58185818
envMode: mode,
5819-
newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin,
5819+
newWorktreesStartFromOrigin: settingsServerSettings.newWorktreesStartFromOrigin,
58205820
}),
58215821
...(mode === "worktree" && draftThread?.worktreePath ? { worktreePath: null } : {}),
58225822
});
@@ -5828,7 +5828,7 @@ function ChatViewContent(props: ChatViewProps) {
58285828
composerDraftTarget,
58295829
draftThread?.worktreePath,
58305830
isLocalDraftThread,
5831-
primaryServerSettings.newWorktreesStartFromOrigin,
5831+
settingsServerSettings.newWorktreesStartFromOrigin,
58325832
setPendingServerThreadEnvMode,
58335833
scheduleComposerFocus,
58345834
setDraftThreadContext,

apps/web/src/components/settings/SourceControlSettings.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import {
1919

2020
import { useGlobalSettings, useUpdateGlobalSettings } from "../../hooks/useSettings";
2121
import { cn } from "../../lib/utils";
22-
import { usePrimaryEnvironment } from "../../state/environments";
2322
import { useEnvironmentQuery } from "../../state/query";
23+
import { useSettingsEnvironmentId } from "../../state/settingsEnvironment";
2424
import { sourceControlEnvironment } from "../../state/sourceControl";
2525
import { Badge } from "../ui/badge";
2626
import { Button } from "../ui/button";
@@ -508,7 +508,10 @@ function EmptySourceControlDiscovery({
508508
}
509509

510510
export function SourceControlSettingsPanel() {
511-
const environmentId = usePrimaryEnvironment()?.environmentId ?? null;
511+
// The same environment the writing settings below read and write, so the
512+
// discovery scan and the writer controls agree about which device they
513+
// describe — and so both still mount on a session with no primary device.
514+
const environmentId = useSettingsEnvironmentId();
512515
const discovery = useEnvironmentQuery(
513516
environmentId === null
514517
? null

apps/web/src/hooks/useHandleNewThread.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ import {
2222
} from "../logicalProject";
2323
import { readThreadShell, useProjects, useThread } from "../state/entities";
2424
import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions";
25-
import { primaryServerSettingsAtom } from "../state/server";
25+
import { settingsServerSettingsAtom } from "../state/server";
2626
import { resolveThreadRouteTarget } from "../threadRoutes";
2727
import { legacyProjectCwdPreferenceKey, useUiStateStore } from "../uiStateStore";
2828
import { useClientSettings } from "./useSettings";
2929

3030
export function useNewThreadHandler() {
3131
const projects = useProjects();
3232
// New-thread defaults are a user preference, and the settings UI only ever
33-
// edits the primary environment's settings.json. Reading the target
33+
// edits the settings environment's settings.json. Reading the target
3434
// environment's own settings here would silently reset remote projects to
3535
// the decoded defaults ("local" mode, current branch), since nothing can
36-
// set those values on a remote server.
37-
const primaryServerSettings = useAtomValue(primaryServerSettingsAtom);
36+
// set those values on a remote server. This must stay the same environment
37+
// the settings panels write to, or the General controls would save and
38+
// re-display values that new threads never pick up.
39+
const settingsServerSettings = useAtomValue(settingsServerSettingsAtom);
3840
const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
3941
const router = useRouter();
4042
const getCurrentRouteTarget = useCallback(() => {
@@ -146,7 +148,7 @@ export function useNewThreadHandler() {
146148
// preserved. When the draft is already open and no options were
147149
// passed, leave it alone entirely — the user may have just picked a
148150
// branch in the composer.
149-
const defaultEnvMode = primaryServerSettings.defaultThreadEnvMode;
151+
const defaultEnvMode = settingsServerSettings.defaultThreadEnvMode;
150152
const workspaceContext = hasExplicitWorkspaceOption
151153
? {
152154
...(hasBranchOption ? { branch: options?.branch ?? null } : {}),
@@ -162,7 +164,7 @@ export function useNewThreadHandler() {
162164
envMode: defaultEnvMode,
163165
startFromOrigin: resolveNewDraftStartFromOrigin({
164166
envMode: defaultEnvMode,
165-
newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin,
167+
newWorktreesStartFromOrigin: settingsServerSettings.newWorktreesStartFromOrigin,
166168
}),
167169
};
168170
if (workspaceContext) {
@@ -244,7 +246,7 @@ export function useNewThreadHandler() {
244246
const draftId = newDraftId();
245247
const threadId = newThreadId();
246248
const createdAt = new Date().toISOString();
247-
const initialEnvMode = options?.envMode ?? primaryServerSettings.defaultThreadEnvMode;
249+
const initialEnvMode = options?.envMode ?? settingsServerSettings.defaultThreadEnvMode;
248250
return (async () => {
249251
setLogicalProjectDraftThreadId(logicalProjectKey, projectRef, draftId, {
250252
threadId,
@@ -256,7 +258,7 @@ export function useNewThreadHandler() {
256258
options?.startFromOrigin ??
257259
resolveNewDraftStartFromOrigin({
258260
envMode: initialEnvMode,
259-
newWorktreesStartFromOrigin: primaryServerSettings.newWorktreesStartFromOrigin,
261+
newWorktreesStartFromOrigin: settingsServerSettings.newWorktreesStartFromOrigin,
260262
}),
261263
runtimeMode: carryRuntimeMode ?? DEFAULT_RUNTIME_MODE,
262264
...(carryInteractionMode ? { interactionMode: carryInteractionMode } : {}),
@@ -278,7 +280,7 @@ export function useNewThreadHandler() {
278280
});
279281
})();
280282
},
281-
[getCurrentRouteTarget, primaryServerSettings, projectGroupingSettings, projects, router],
283+
[getCurrentRouteTarget, settingsServerSettings, projectGroupingSettings, projects, router],
282284
);
283285
}
284286

0 commit comments

Comments
 (0)