1import type { ServerSettings, ServerSettingsPatch } from "@t3tools/contracts";
2import { isModelSelectionProviderEnabled } from "@t3tools/shared/serverSettings";
3import * as Struct from "effect/Struct";
4
5import type { EnvironmentConnectionPhase } from "../connection/presentation.ts";
6
7const SHARED_SERVER_SETTING_KEYS = [
8 "continueThreadsAfterServerUpdate",
9 "sidebarAutoSettleAfterDays",
10 "sidebarAutoSettleOnMerge",
11 "autoResumeLimitedThreads",
12 "snoozeLimitedThreads",
13 "snoozePresets",
14 "newWorktreesStartFromOrigin",
15 "sourceControlWritingStyle",
16 "textGenerationModelSelection",
17] as const satisfies ReadonlyArray<keyof ServerSettings & keyof ServerSettingsPatch>;
18
19const SHARED_KEY_SET = new Set<string>(SHARED_SERVER_SETTING_KEYS);
20
21export function splitSharedServerPatch(patch: ServerSettingsPatch): {
22 sharedPatch: ServerSettingsPatch;
23 localPatch: ServerSettingsPatch;
24} {
25 const sharedPatch: Record<string, unknown> = {};
26 const localPatch: Record<string, unknown> = {};
27 for (const [key, value] of Object.entries(patch)) {
28 if (SHARED_KEY_SET.has(key)) {
29 sharedPatch[key] = value;
30 } else {
31 localPatch[key] = value;
32 }
33 }
34 return {
35 sharedPatch: sharedPatch as ServerSettingsPatch,
36 localPatch: localPatch as ServerSettingsPatch,
37 };
38}
39
40export function filterSharedServerPatch(
41 patch: ServerSettingsPatch,
42 settings?: ServerSettings,
43 sourceSettings = settings,
44 targetIsSource = false,
45): ServerSettingsPatch {
46 const instanceId =
47 patch.textGenerationModelSelection?.instanceId ??
48 sourceSettings?.textGenerationModelSelection.instanceId;
49 if (
50 !targetIsSource &&
51 patch.textGenerationModelSelection &&
52 (!settings ||
53 (instanceId !== undefined &&
54 (sourceSettings?.providerInstances[instanceId]?.driver ?? instanceId) !==
55 (settings.providerInstances[instanceId]?.driver ?? instanceId)) ||
56 !isModelSelectionProviderEnabled(settings, {
57 ...settings.textGenerationModelSelection,
58 ...patch.textGenerationModelSelection,
59 }))
60 ) {
61 patch = Struct.omit(patch, ["textGenerationModelSelection"]);
62 }
63 return settings ? patch : Struct.omit(patch, ["continueThreadsAfterServerUpdate"]);
64}
65
66export function supportsSharedSettingsSync(environment: {
67 readonly connection: { readonly phase: EnvironmentConnectionPhase };
68 readonly serverConfig: object | null;
69}): boolean {
70 return environment.connection.phase === "connected" && environment.serverConfig !== null;
71}