333 lines · 11.4 KB · TypeScript
RawDownload
import type {  BackgroundActivityProfile,  BackgroundActivitySettings,  ProviderDriverKind,  ProviderInstanceConfig,  PreviewViewportSetting,  ProviderInstanceId,  ServerSettings,  SidebarProjectGroupingMode,  UnifiedSettings,} from "@t3tools/contracts";import { DEFAULT_UNIFIED_SETTINGS } from "@t3tools/contracts/settings";import {  getBackgroundActivityBaseProfile,  normalizeBackgroundActivitySettings,  normalizeServerBackgroundActivitySettings,  resolveServerBackgroundActivitySettings,} from "@t3tools/shared/backgroundActivitySettings";import * as Duration from "effect/Duration";import * as Equal from "effect/Equal"; export function isProjectGroupingEnabled(mode: SidebarProjectGroupingMode): boolean {  return mode !== "separate";} export function projectGroupingModeFromToggle(  enabled: boolean,  lastEnabledMode: SidebarProjectGroupingMode = "repository",): SidebarProjectGroupingMode {  if (!enabled) return "separate";  return lastEnabledMode === "repository_path" ? "repository_path" : "repository";} const LAST_ENABLED_PROJECT_GROUPING_MODE_KEY = "t3code:last-enabled-project-grouping-mode"; export function readLastEnabledProjectGroupingMode(): SidebarProjectGroupingMode {  try {    return localStorage.getItem(LAST_ENABLED_PROJECT_GROUPING_MODE_KEY) === "repository_path"      ? "repository_path"      : "repository";  } catch {    return "repository";  }} export function rememberEnabledProjectGroupingMode(mode: SidebarProjectGroupingMode): void {  if (mode === "separate") return;  try {    localStorage.setItem(LAST_ENABLED_PROJECT_GROUPING_MODE_KEY, mode);  } catch {    // Storage can be unavailable in restricted browser contexts.  }} export function hasChangedBackgroundActivitySettings(  settings: Pick<    UnifiedSettings,    | "backgroundActivity"    | "backgroundActivityProfile"    | "automaticGitFetchInterval"    | "providerHealthRefreshInterval"  >,): boolean {  return (    !Equal.equals(settings.backgroundActivity, DEFAULT_UNIFIED_SETTINGS.backgroundActivity) ||    settings.backgroundActivityProfile !== DEFAULT_UNIFIED_SETTINGS.backgroundActivityProfile ||    !Equal.equals(      settings.automaticGitFetchInterval,      DEFAULT_UNIFIED_SETTINGS.automaticGitFetchInterval,    ) ||    !Equal.equals(      settings.providerHealthRefreshInterval,      DEFAULT_UNIFIED_SETTINGS.providerHealthRefreshInterval,    )  );} type TypographySettings = Pick<  UnifiedSettings,  | "fontFamilySans"  | "fontFamilyComposer"  | "fontFamilyCode"  | "fontFamilyTerminal"  | "fontSizeInterface"  | "fontSizePrompt"  | "fontSizeCode"  | "fontSizeTerminal">; /** Labels the font rows whose family or size differs from the defaults. */export function getChangedTypographySettingLabels(settings: TypographySettings): string[] {  return [    ...(settings.fontFamilySans !== DEFAULT_UNIFIED_SETTINGS.fontFamilySans ||    settings.fontSizeInterface !== DEFAULT_UNIFIED_SETTINGS.fontSizeInterface      ? ["Interface font"]      : []),    ...(settings.fontFamilyComposer !== DEFAULT_UNIFIED_SETTINGS.fontFamilyComposer ||    settings.fontSizePrompt !== DEFAULT_UNIFIED_SETTINGS.fontSizePrompt      ? ["Prompt font"]      : []),    ...(settings.fontFamilyCode !== DEFAULT_UNIFIED_SETTINGS.fontFamilyCode ||    settings.fontSizeCode !== DEFAULT_UNIFIED_SETTINGS.fontSizeCode      ? ["Code font"]      : []),    ...(settings.fontFamilyTerminal !== DEFAULT_UNIFIED_SETTINGS.fontFamilyTerminal ||    settings.fontSizeTerminal !== DEFAULT_UNIFIED_SETTINGS.fontSizeTerminal      ? ["Terminal font"]      : []),  ];} export type BrowserDefaultSettings = Pick<  UnifiedSettings,  | "browserDefaultViewport"  | "browserDefaultZoomFactor"  | "browserDefaultAppearance"  | "browserAutoShowFloatingPreview">; /** * True when two viewport settings describe the same viewport. * * The setting is a tagged union rather than a scalar, so identity comparison * reports every stored viewport as changed — including one that matches the * default. */export function isSamePreviewViewport(  left: PreviewViewportSetting,  right: PreviewViewportSetting,): boolean {  if (left._tag !== right._tag) return false;  if (left._tag === "fill" || right._tag === "fill") return true;  if (left.width !== right.width || left.height !== right.height) return false;  return left._tag === "preset" && right._tag === "preset"    ? left.presetId === right.presetId    : true;} /** Labels the browser-default rows that differ from the defaults. */export function getChangedBrowserSettingLabels(settings: BrowserDefaultSettings): string[] {  return [    ...(isSamePreviewViewport(      settings.browserDefaultViewport,      DEFAULT_UNIFIED_SETTINGS.browserDefaultViewport,    )      ? []      : ["Browser viewport"]),    ...(settings.browserDefaultZoomFactor !== DEFAULT_UNIFIED_SETTINGS.browserDefaultZoomFactor      ? ["Browser zoom"]      : []),    ...(settings.browserDefaultAppearance !== DEFAULT_UNIFIED_SETTINGS.browserDefaultAppearance      ? ["Browser appearance"]      : []),    ...(settings.browserAutoShowFloatingPreview !==    DEFAULT_UNIFIED_SETTINGS.browserAutoShowFloatingPreview      ? ["Floating preview"]      : []),  ];} export function resolveBackgroundActivityProfileOption(  settings: ServerSettings,): BackgroundActivityProfile | "advanced" {  const resolved = resolveServerBackgroundActivitySettings(settings);  const normalized = normalizeBackgroundActivitySettings({    schemaVersion: 1,    profile: "custom",    baseProfile: resolved.profile,    overrides: {      automaticGitFetchInterval: resolved.automaticGitFetchInterval,      providerHealthRefreshInterval: resolved.providerHealthRefreshInterval,      hostPowerMonitorActiveInterval: resolved.hostPowerMonitorActiveInterval,      hostPowerMonitorIdleInterval: resolved.hostPowerMonitorIdleInterval,      idleClientTtl: resolved.idleClientTtl,      pauseWhenHostLocked: resolved.pauseWhenHostLocked,      pauseWhenHostLowPower: resolved.pauseWhenHostLowPower,      pauseWhenClientLowPower: resolved.pauseWhenClientLowPower,      pauseWhenOnBattery: resolved.pauseWhenOnBattery,    },  });  return normalized.profile === "custom" ? "advanced" : normalized.profile;} export function backgroundActivitySharedPolicySettings(  settings: ServerSettings,  profile: BackgroundActivityProfile,): BackgroundActivitySettings {  const normalized = normalizeServerBackgroundActivitySettings(settings);  return {    schemaVersion: 1,    profile: "custom",    baseProfile: profile,    overrides: normalized.profile === "custom" ? normalized.overrides : {},  };} function collapseOtelSignalsUrl(input: {  readonly tracesUrl: string;  readonly metricsUrl: string;}): string | null {  const tracesSuffix = "/traces";  const metricsSuffix = "/metrics";  if (!input.tracesUrl.endsWith(tracesSuffix) || !input.metricsUrl.endsWith(metricsSuffix)) {    return null;  }   const tracesBase = input.tracesUrl.slice(0, -tracesSuffix.length);  const metricsBase = input.metricsUrl.slice(0, -metricsSuffix.length);  if (tracesBase !== metricsBase) {    return null;  }   return `${tracesBase}/{traces,metrics}`;} export function formatDiagnosticsDescription(input: {  readonly localTracingEnabled: boolean;  readonly otlpTracesEnabled: boolean;  readonly otlpTracesUrl?: string | undefined;  readonly otlpMetricsEnabled: boolean;  readonly otlpMetricsUrl?: string | undefined;}): string {  const mode = input.localTracingEnabled ? "Local trace file" : "Terminal logs only";  const tracesUrl = input.otlpTracesEnabled ? input.otlpTracesUrl : undefined;  const metricsUrl = input.otlpMetricsEnabled ? input.otlpMetricsUrl : undefined;   if (tracesUrl && metricsUrl) {    const collapsedUrl = collapseOtelSignalsUrl({ tracesUrl, metricsUrl });    return collapsedUrl      ? `${mode}. Exporting OTEL to ${collapsedUrl}.`      : `${mode}. Exporting OTEL traces to ${tracesUrl} and metrics to ${metricsUrl}.`;  }   if (tracesUrl) {    return `${mode}. Exporting OTEL traces to ${tracesUrl}.`;  }   if (metricsUrl) {    return `${mode}. Exporting OTEL metrics to ${metricsUrl}.`;  }   return `${mode}.`;} export function buildProviderInstanceUpdatePatch(input: {  readonly settings: Pick<ServerSettings, "providers" | "providerInstances">;  readonly instanceId: ProviderInstanceId;  readonly instance: ProviderInstanceConfig;  readonly driver: ProviderDriverKind;  readonly isDefault: boolean;  readonly textGenerationModelSelection?:    | ServerSettings["textGenerationModelSelection"]    | undefined;}): Partial<UnifiedSettings> {  type LegacyProviderSettings = ServerSettings["providers"][keyof ServerSettings["providers"]];  const legacyProviderDefaults = DEFAULT_UNIFIED_SETTINGS.providers as Record<    string,    LegacyProviderSettings | undefined  >;  const legacyProviderDefault = input.isDefault ? legacyProviderDefaults[input.driver] : undefined;  return {    ...(legacyProviderDefault !== undefined      ? {          providers: {            ...input.settings.providers,            [input.driver]: legacyProviderDefault,          } as ServerSettings["providers"],        }      : {}),    providerInstances: {      ...input.settings.providerInstances,      [input.instanceId]: input.instance,    },    ...(input.textGenerationModelSelection !== undefined      ? { textGenerationModelSelection: input.textGenerationModelSelection }      : {}),  };} // ── Background-activity interval helpers ─────────────────────────────// Shared by the General panel's interval rows and the Providers panel's// health-check row. export const PROVIDER_HEALTH_INTERVAL_STEP_SECONDS = 30; type BackgroundActivityOverridePatch = Partial<{  [K in keyof BackgroundActivitySettings["overrides"]]:    | BackgroundActivitySettings["overrides"][K]    | undefined;}>; export function durationToSeconds(duration: Duration.Duration): number {  return Math.round(Duration.toMillis(duration) / 1_000);} export function normalizeIntervalSeconds(value: number | null, minimum = 0): number {  if (value === null || !Number.isFinite(value)) {    return minimum;  }  return Math.max(minimum, Math.round(value));} export function backgroundActivityOverrideSettings(  current: BackgroundActivitySettings,  resolved: ReturnType<typeof resolveServerBackgroundActivitySettings>,  overrides: BackgroundActivityOverridePatch,) {  const nextOverrides: BackgroundActivityOverridePatch = {    automaticGitFetchInterval: resolved.automaticGitFetchInterval,    providerHealthRefreshInterval: resolved.providerHealthRefreshInterval,    hostPowerMonitorActiveInterval: resolved.hostPowerMonitorActiveInterval,    hostPowerMonitorIdleInterval: resolved.hostPowerMonitorIdleInterval,    idleClientTtl: resolved.idleClientTtl,    pauseWhenHostLocked: resolved.pauseWhenHostLocked,    pauseWhenHostLowPower: resolved.pauseWhenHostLowPower,    pauseWhenClientLowPower: resolved.pauseWhenClientLowPower,    pauseWhenOnBattery: resolved.pauseWhenOnBattery,    ...overrides,  };  for (const [key, value] of Object.entries(nextOverrides)) {    if (value === undefined) {      delete nextOverrides[key as keyof typeof nextOverrides];    }  }  return {    backgroundActivity: {      schemaVersion: 1 as const,      profile: "custom" as const,      baseProfile: getBackgroundActivityBaseProfile(current),      overrides: nextOverrides as BackgroundActivitySettings["overrides"],    },  };}