authorgravatar for 45952970+repparw@users.noreply.github.comUlises Britos <45952970+repparw@users.noreply.github.com> 2026-06-19 15:07:23-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-19 11:07:23-07:00
log5d4e2fae012b74cfb323cc2cb45687caf93997cc
treeff7a70b3799b9ab0fd1eb2fc3ba5c0467b219bd6
parent3e01c4bc572ea6a938c9a47143c914ff042ea41a
signature Signed by PGP key B5690EEEBB952194

feat: allow disabling provider update checks (#3130)

Co-authored-by: codex <codex@users.noreply.github.com>

14 files changed, 239 insertions(+), 57 deletions(-)

apps/server/src/provider/Drivers/ClaudeDriver.ts+19-9
...@@ -20,12 +20,12 @@ import * as Effect from "effect/Effect";...@@ -20,12 +20,12 @@ import * as Effect from "effect/Effect";
20import * as FileSystem from "effect/FileSystem";20import * as FileSystem from "effect/FileSystem";
21import * as Path from "effect/Path";21import * as Path from "effect/Path";
22import * as Schema from "effect/Schema";22import * as Schema from "effect/Schema";
23import * as Stream from "effect/Stream";
24import { HttpClient } from "effect/unstable/http";23import { HttpClient } from "effect/unstable/http";
25import { ChildProcessSpawner } from "effect/unstable/process";24import { ChildProcessSpawner } from "effect/unstable/process";
2625
27import { makeClaudeTextGeneration } from "../../textGeneration/ClaudeTextGeneration.ts";26import { makeClaudeTextGeneration } from "../../textGeneration/ClaudeTextGeneration.ts";
28import { ServerConfig } from "../../config.ts";27import { ServerConfig } from "../../config.ts";
28import { ServerSettingsService } from "../../serverSettings.ts";
29import { ProviderDriverError } from "../Errors.ts";29import { ProviderDriverError } from "../Errors.ts";
30import { makeClaudeAdapter } from "../Layers/ClaudeAdapter.ts";30import { makeClaudeAdapter } from "../Layers/ClaudeAdapter.ts";
31import {31import {
...@@ -48,6 +48,11 @@ import {...@@ -48,6 +48,11 @@ import {
48 normalizeCommandPath,48 normalizeCommandPath,
49 resolveProviderMaintenanceCapabilitiesEffect,49 resolveProviderMaintenanceCapabilitiesEffect,
50} from "../providerMaintenance.ts";50} from "../providerMaintenance.ts";
51import {
52 haveProviderSnapshotSettingsChanged,
53 makeProviderSnapshotSettingsSource,
54 type ProviderSnapshotSettings,
55} from "../providerUpdateSettings.ts";
51import { makeClaudeCapabilitiesCacheKey, makeClaudeContinuationGroupKey } from "./ClaudeHome.ts";56import { makeClaudeCapabilitiesCacheKey, makeClaudeContinuationGroupKey } from "./ClaudeHome.ts";
52const decodeClaudeSettings = Schema.decodeSync(ClaudeSettings);57const decodeClaudeSettings = Schema.decodeSync(ClaudeSettings);
5358
...@@ -83,7 +88,8 @@ export type ClaudeDriverEnv =...@@ -83,7 +88,8 @@ export type ClaudeDriverEnv =
83 | HttpClient.HttpClient88 | HttpClient.HttpClient
84 | Path.Path89 | Path.Path
85 | ProviderEventLoggers90 | ProviderEventLoggers
86 | ServerConfig;91 | ServerConfig
92 | ServerSettingsService;
8793
88const withInstanceIdentity =94const withInstanceIdentity =
89 (input: {95 (input: {
...@@ -114,6 +120,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {...@@ -114,6 +120,7 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {
114 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;120 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
115 const path = yield* Path.Path;121 const path = yield* Path.Path;
116 const httpClient = yield* HttpClient.HttpClient;122 const httpClient = yield* HttpClient.HttpClient;
123 const serverSettings = yield* ServerSettingsService;
117 const eventLoggers = yield* ProviderEventLoggers;124 const eventLoggers = yield* ProviderEventLoggers;
118 const processEnv = mergeProviderInstanceEnvironment(environment);125 const processEnv = mergeProviderInstanceEnvironment(environment);
119 const fallbackContinuationIdentity = defaultProviderContinuationIdentity({126 const fallbackContinuationIdentity = defaultProviderContinuationIdentity({
...@@ -163,16 +170,19 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {...@@ -163,16 +170,19 @@ export const ClaudeDriver: ProviderDriver<ClaudeSettings, ClaudeDriverEnv> = {
163 Effect.provideService(Path.Path, path),170 Effect.provideService(Path.Path, path),
164 );171 );
165172
166 const snapshot = yield* makeManagedServerProvider<ClaudeSettings>({173 const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
174 const snapshot = yield* makeManagedServerProvider<ProviderSnapshotSettings<ClaudeSettings>>({
167 maintenanceCapabilities,175 maintenanceCapabilities,
168 getSettings: Effect.succeed(effectiveConfig),176 getSettings: snapshotSettings.getSettings,
169 streamSettings: Stream.never,177 streamSettings: snapshotSettings.streamSettings,
170 haveSettingsChanged: () => false,178 haveSettingsChanged: haveProviderSnapshotSettingsChanged,
171 initialSnapshot: (settings) =>179 initialSnapshot: (settings) =>
172 makePendingClaudeProvider(settings).pipe(Effect.map(stampIdentity)),180 makePendingClaudeProvider(settings.provider).pipe(Effect.map(stampIdentity)),
173 checkProvider,181 checkProvider,
174 enrichSnapshot: ({ snapshot, publishSnapshot }) =>182 enrichSnapshot: ({ settings, snapshot, publishSnapshot }) =>
175 enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities).pipe(183 enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities, {
184 enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
185 }).pipe(
176 Effect.provideService(HttpClient.HttpClient, httpClient),186 Effect.provideService(HttpClient.HttpClient, httpClient),
177 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),187 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),
178 ),188 ),
apps/server/src/provider/Drivers/CodexDriver.ts+19-9
...@@ -28,12 +28,12 @@ import * as Effect from "effect/Effect";...@@ -28,12 +28,12 @@ import * as Effect from "effect/Effect";
28import * as FileSystem from "effect/FileSystem";28import * as FileSystem from "effect/FileSystem";
29import * as Path from "effect/Path";29import * as Path from "effect/Path";
30import * as Schema from "effect/Schema";30import * as Schema from "effect/Schema";
31import * as Stream from "effect/Stream";
32import { HttpClient } from "effect/unstable/http";31import { HttpClient } from "effect/unstable/http";
33import { ChildProcessSpawner } from "effect/unstable/process";32import { ChildProcessSpawner } from "effect/unstable/process";
3433
35import { makeCodexTextGeneration } from "../../textGeneration/CodexTextGeneration.ts";34import { makeCodexTextGeneration } from "../../textGeneration/CodexTextGeneration.ts";
36import { ServerConfig } from "../../config.ts";35import { ServerConfig } from "../../config.ts";
36import { ServerSettingsService } from "../../serverSettings.ts";
37import { ProviderDriverError } from "../Errors.ts";37import { ProviderDriverError } from "../Errors.ts";
38import { makeCodexAdapter } from "../Layers/CodexAdapter.ts";38import { makeCodexAdapter } from "../Layers/CodexAdapter.ts";
39import { checkCodexProviderStatus, makePendingCodexProvider } from "../Layers/CodexProvider.ts";39import { checkCodexProviderStatus, makePendingCodexProvider } from "../Layers/CodexProvider.ts";
...@@ -47,6 +47,11 @@ import {...@@ -47,6 +47,11 @@ import {
47 makePackageManagedProviderMaintenanceResolver,47 makePackageManagedProviderMaintenanceResolver,
48 resolveProviderMaintenanceCapabilitiesEffect,48 resolveProviderMaintenanceCapabilitiesEffect,
49} from "../providerMaintenance.ts";49} from "../providerMaintenance.ts";
50import {
51 haveProviderSnapshotSettingsChanged,
52 makeProviderSnapshotSettingsSource,
53 type ProviderSnapshotSettings,
54} from "../providerUpdateSettings.ts";
50import {55import {
51 codexContinuationIdentity,56 codexContinuationIdentity,
52 materializeCodexShadowHome,57 materializeCodexShadowHome,
...@@ -75,7 +80,8 @@ export type CodexDriverEnv =...@@ -75,7 +80,8 @@ export type CodexDriverEnv =
75 | HttpClient.HttpClient80 | HttpClient.HttpClient
76 | Path.Path81 | Path.Path
77 | ProviderEventLoggers82 | ProviderEventLoggers
78 | ServerConfig;83 | ServerConfig
84 | ServerSettingsService;
7985
80/**86/**
81 * Stamp instance identity onto a `ServerProvider` snapshot produced by the87 * Stamp instance identity onto a `ServerProvider` snapshot produced by the
...@@ -111,6 +117,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {...@@ -111,6 +117,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
111 Effect.gen(function* () {117 Effect.gen(function* () {
112 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;118 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
113 const httpClient = yield* HttpClient.HttpClient;119 const httpClient = yield* HttpClient.HttpClient;
120 const serverSettings = yield* ServerSettingsService;
114 const eventLoggers = yield* ProviderEventLoggers;121 const eventLoggers = yield* ProviderEventLoggers;
115 const processEnv = mergeProviderInstanceEnvironment(environment);122 const processEnv = mergeProviderInstanceEnvironment(environment);
116 const homeLayout = yield* resolveCodexHomeLayout(config);123 const homeLayout = yield* resolveCodexHomeLayout(config);
...@@ -163,16 +170,19 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {...@@ -163,16 +170,19 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
163 Effect.map(stampIdentity),170 Effect.map(stampIdentity),
164 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),171 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
165 );172 );
166 const snapshot = yield* makeManagedServerProvider<CodexSettings>({173 const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
174 const snapshot = yield* makeManagedServerProvider<ProviderSnapshotSettings<CodexSettings>>({
167 maintenanceCapabilities,175 maintenanceCapabilities,
168 getSettings: Effect.succeed(effectiveConfig),176 getSettings: snapshotSettings.getSettings,
169 streamSettings: Stream.never,177 streamSettings: snapshotSettings.streamSettings,
170 haveSettingsChanged: () => false,178 haveSettingsChanged: haveProviderSnapshotSettingsChanged,
171 initialSnapshot: (settings) =>179 initialSnapshot: (settings) =>
172 makePendingCodexProvider(settings).pipe(Effect.map(stampIdentity)),180 makePendingCodexProvider(settings.provider).pipe(Effect.map(stampIdentity)),
173 checkProvider,181 checkProvider,
174 enrichSnapshot: ({ snapshot, publishSnapshot }) =>182 enrichSnapshot: ({ settings, snapshot, publishSnapshot }) =>
175 enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities).pipe(183 enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities, {
184 enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
185 }).pipe(
176 Effect.provideService(HttpClient.HttpClient, httpClient),186 Effect.provideService(HttpClient.HttpClient, httpClient),
177 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),187 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),
178 ),188 ),
apps/server/src/provider/Drivers/CursorDriver.ts+17-8
...@@ -18,11 +18,11 @@ import * as Effect from "effect/Effect";...@@ -18,11 +18,11 @@ import * as Effect from "effect/Effect";
18import * as FileSystem from "effect/FileSystem";18import * as FileSystem from "effect/FileSystem";
19import * as Path from "effect/Path";19import * as Path from "effect/Path";
20import * as Schema from "effect/Schema";20import * as Schema from "effect/Schema";
21import * as Stream from "effect/Stream";
22import { HttpClient } from "effect/unstable/http";21import { HttpClient } from "effect/unstable/http";
23import { ChildProcessSpawner } from "effect/unstable/process";22import { ChildProcessSpawner } from "effect/unstable/process";
2423
25import { ServerConfig } from "../../config.ts";24import { ServerConfig } from "../../config.ts";
25import { ServerSettingsService } from "../../serverSettings.ts";
26import { makeCursorTextGeneration } from "../../textGeneration/CursorTextGeneration.ts";26import { makeCursorTextGeneration } from "../../textGeneration/CursorTextGeneration.ts";
27import { ProviderDriverError } from "../Errors.ts";27import { ProviderDriverError } from "../Errors.ts";
28import { makeCursorAdapter } from "../Layers/CursorAdapter.ts";28import { makeCursorAdapter } from "../Layers/CursorAdapter.ts";
...@@ -45,6 +45,11 @@ import {...@@ -45,6 +45,11 @@ import {
45 makeStaticProviderMaintenanceResolver,45 makeStaticProviderMaintenanceResolver,
46 resolveProviderMaintenanceCapabilitiesEffect,46 resolveProviderMaintenanceCapabilitiesEffect,
47} from "../providerMaintenance.ts";47} from "../providerMaintenance.ts";
48import {
49 haveProviderSnapshotSettingsChanged,
50 makeProviderSnapshotSettingsSource,
51 type ProviderSnapshotSettings,
52} from "../providerUpdateSettings.ts";
48const decodeCursorSettings = Schema.decodeSync(CursorSettings);53const decodeCursorSettings = Schema.decodeSync(CursorSettings);
4954
50const DRIVER_KIND = ProviderDriverKind.make("cursor");55const DRIVER_KIND = ProviderDriverKind.make("cursor");
...@@ -66,7 +71,8 @@ export type CursorDriverEnv =...@@ -66,7 +71,8 @@ export type CursorDriverEnv =
66 | HttpClient.HttpClient71 | HttpClient.HttpClient
67 | Path.Path72 | Path.Path
68 | ProviderEventLoggers73 | ProviderEventLoggers
69 | ServerConfig;74 | ServerConfig
75 | ServerSettingsService;
7076
71const withInstanceIdentity =77const withInstanceIdentity =
72 (input: {78 (input: {
...@@ -98,6 +104,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {...@@ -98,6 +104,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
98 const fileSystem = yield* FileSystem.FileSystem;104 const fileSystem = yield* FileSystem.FileSystem;
99 const path = yield* Path.Path;105 const path = yield* Path.Path;
100 const httpClient = yield* HttpClient.HttpClient;106 const httpClient = yield* HttpClient.HttpClient;
107 const serverSettings = yield* ServerSettingsService;
101 const eventLoggers = yield* ProviderEventLoggers;108 const eventLoggers = yield* ProviderEventLoggers;
102 const processEnv = mergeProviderInstanceEnvironment(environment);109 const processEnv = mergeProviderInstanceEnvironment(environment);
103 const continuationIdentity = defaultProviderContinuationIdentity({110 const continuationIdentity = defaultProviderContinuationIdentity({
...@@ -130,21 +137,23 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {...@@ -130,21 +137,23 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
130 Effect.provideService(Path.Path, path),137 Effect.provideService(Path.Path, path),
131 );138 );
132139
133 const snapshot = yield* makeManagedServerProvider<CursorSettings>({140 const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
141 const snapshot = yield* makeManagedServerProvider<ProviderSnapshotSettings<CursorSettings>>({
134 maintenanceCapabilities,142 maintenanceCapabilities,
135 getSettings: Effect.succeed(effectiveConfig),143 getSettings: snapshotSettings.getSettings,
136 streamSettings: Stream.never,144 streamSettings: snapshotSettings.streamSettings,
137 haveSettingsChanged: () => false,145 haveSettingsChanged: haveProviderSnapshotSettingsChanged,
138 initialSnapshot: (settings) =>146 initialSnapshot: (settings) =>
139 buildInitialCursorProviderSnapshot(settings).pipe(Effect.map(stampIdentity)),147 buildInitialCursorProviderSnapshot(settings.provider).pipe(Effect.map(stampIdentity)),
140 checkProvider,148 checkProvider,
141 // Model catalog and capabilities come exclusively from Cursor's149 // Model catalog and capabilities come exclusively from Cursor's
142 // list_available_models extension method during provider checks.150 // list_available_models extension method during provider checks.
143 enrichSnapshot: ({ settings, snapshot: currentSnapshot, publishSnapshot }) =>151 enrichSnapshot: ({ settings, snapshot: currentSnapshot, publishSnapshot }) =>
144 enrichCursorSnapshot({152 enrichCursorSnapshot({
145 settings,153 settings: settings.provider,
146 snapshot: currentSnapshot,154 snapshot: currentSnapshot,
147 maintenanceCapabilities,155 maintenanceCapabilities,
156 enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
148 publishSnapshot,157 publishSnapshot,
149 stampIdentity,158 stampIdentity,
150 httpClient,159 httpClient,
apps/server/src/provider/Drivers/GrokDriver.ts+17-8
...@@ -5,11 +5,11 @@ import * as Effect from "effect/Effect";...@@ -5,11 +5,11 @@ import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";5import * as FileSystem from "effect/FileSystem";
6import * as Path from "effect/Path";6import * as Path from "effect/Path";
7import * as Schema from "effect/Schema";7import * as Schema from "effect/Schema";
8import * as Stream from "effect/Stream";
9import { HttpClient } from "effect/unstable/http";8import { HttpClient } from "effect/unstable/http";
10import { ChildProcessSpawner } from "effect/unstable/process";9import { ChildProcessSpawner } from "effect/unstable/process";
1110
12import { ServerConfig } from "../../config.ts";11import { ServerConfig } from "../../config.ts";
12import { ServerSettingsService } from "../../serverSettings.ts";
13import { makeGrokTextGeneration } from "../../textGeneration/GrokTextGeneration.ts";13import { makeGrokTextGeneration } from "../../textGeneration/GrokTextGeneration.ts";
14import { ProviderDriverError } from "../Errors.ts";14import { ProviderDriverError } from "../Errors.ts";
15import { makeGrokAdapter } from "../Layers/GrokAdapter.ts";15import { makeGrokAdapter } from "../Layers/GrokAdapter.ts";
...@@ -32,6 +32,11 @@ import {...@@ -32,6 +32,11 @@ import {
32 makeStaticProviderMaintenanceResolver,32 makeStaticProviderMaintenanceResolver,
33 resolveProviderMaintenanceCapabilitiesEffect,33 resolveProviderMaintenanceCapabilitiesEffect,
34} from "../providerMaintenance.ts";34} from "../providerMaintenance.ts";
35import {
36 haveProviderSnapshotSettingsChanged,
37 makeProviderSnapshotSettingsSource,
38 type ProviderSnapshotSettings,
39} from "../providerUpdateSettings.ts";
35const decodeGrokSettings = Schema.decodeSync(GrokSettings);40const decodeGrokSettings = Schema.decodeSync(GrokSettings);
3641
37const DRIVER_KIND = ProviderDriverKind.make("grok");42const DRIVER_KIND = ProviderDriverKind.make("grok");
...@@ -50,7 +55,8 @@ export type GrokDriverEnv =...@@ -50,7 +55,8 @@ export type GrokDriverEnv =
50 | HttpClient.HttpClient55 | HttpClient.HttpClient
51 | Path.Path56 | Path.Path
52 | ProviderEventLoggers57 | ProviderEventLoggers
53 | ServerConfig;58 | ServerConfig
59 | ServerSettingsService;
5460
55const withInstanceIdentity =61const withInstanceIdentity =
56 (input: {62 (input: {
...@@ -80,6 +86,7 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {...@@ -80,6 +86,7 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
80 Effect.gen(function* () {86 Effect.gen(function* () {
81 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;87 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
82 const httpClient = yield* HttpClient.HttpClient;88 const httpClient = yield* HttpClient.HttpClient;
89 const serverSettings = yield* ServerSettingsService;
83 const eventLoggers = yield* ProviderEventLoggers;90 const eventLoggers = yield* ProviderEventLoggers;
84 const processEnv = mergeProviderInstanceEnvironment(environment);91 const processEnv = mergeProviderInstanceEnvironment(environment);
85 const continuationIdentity = defaultProviderContinuationIdentity({92 const continuationIdentity = defaultProviderContinuationIdentity({
...@@ -110,18 +117,20 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {...@@ -110,18 +117,20 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
110 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),117 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
111 );118 );
112119
113 const snapshot = yield* makeManagedServerProvider<GrokSettings>({120 const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
121 const snapshot = yield* makeManagedServerProvider<ProviderSnapshotSettings<GrokSettings>>({
114 maintenanceCapabilities,122 maintenanceCapabilities,
115 getSettings: Effect.succeed(effectiveConfig),123 getSettings: snapshotSettings.getSettings,
116 streamSettings: Stream.never,124 streamSettings: snapshotSettings.streamSettings,
117 haveSettingsChanged: () => false,125 haveSettingsChanged: haveProviderSnapshotSettingsChanged,
118 initialSnapshot: (settings) =>126 initialSnapshot: (settings) =>
119 buildInitialGrokProviderSnapshot(settings).pipe(Effect.map(stampIdentity)),127 buildInitialGrokProviderSnapshot(settings.provider).pipe(Effect.map(stampIdentity)),
120 checkProvider,128 checkProvider,
121 enrichSnapshot: ({ snapshot: currentSnapshot, publishSnapshot }) =>129 enrichSnapshot: ({ settings, snapshot: currentSnapshot, publishSnapshot }) =>
122 enrichGrokSnapshot({130 enrichGrokSnapshot({
123 snapshot: currentSnapshot,131 snapshot: currentSnapshot,
124 maintenanceCapabilities,132 maintenanceCapabilities,
133 enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
125 publishSnapshot,134 publishSnapshot,
126 httpClient,135 httpClient,
127 }),136 }),
apps/server/src/provider/Drivers/OpenCodeDriver.ts+29-17
...@@ -19,12 +19,12 @@ import * as Effect from "effect/Effect";...@@ -19,12 +19,12 @@ import * as Effect from "effect/Effect";
19import * as FileSystem from "effect/FileSystem";19import * as FileSystem from "effect/FileSystem";
20import * as Path from "effect/Path";20import * as Path from "effect/Path";
21import * as Schema from "effect/Schema";21import * as Schema from "effect/Schema";
22import * as Stream from "effect/Stream";
23import { HttpClient } from "effect/unstable/http";22import { HttpClient } from "effect/unstable/http";
24import { ChildProcessSpawner } from "effect/unstable/process";23import { ChildProcessSpawner } from "effect/unstable/process";
2524
26import { makeOpenCodeTextGeneration } from "../../textGeneration/OpenCodeTextGeneration.ts";25import { makeOpenCodeTextGeneration } from "../../textGeneration/OpenCodeTextGeneration.ts";
27import { ServerConfig } from "../../config.ts";26import { ServerConfig } from "../../config.ts";
27import { ServerSettingsService } from "../../serverSettings.ts";
28import { ProviderDriverError } from "../Errors.ts";28import { ProviderDriverError } from "../Errors.ts";
29import { makeOpenCodeAdapter } from "../Layers/OpenCodeAdapter.ts";29import { makeOpenCodeAdapter } from "../Layers/OpenCodeAdapter.ts";
30import {30import {
...@@ -47,6 +47,11 @@ import {...@@ -47,6 +47,11 @@ import {
47 normalizeCommandPath,47 normalizeCommandPath,
48 resolveProviderMaintenanceCapabilitiesEffect,48 resolveProviderMaintenanceCapabilitiesEffect,
49} from "../providerMaintenance.ts";49} from "../providerMaintenance.ts";
50import {
51 haveProviderSnapshotSettingsChanged,
52 makeProviderSnapshotSettingsSource,
53 type ProviderSnapshotSettings,
54} from "../providerUpdateSettings.ts";
50const decodeOpenCodeSettings = Schema.decodeSync(OpenCodeSettings);55const decodeOpenCodeSettings = Schema.decodeSync(OpenCodeSettings);
5156
52const DRIVER_KIND = ProviderDriverKind.make("opencode");57const DRIVER_KIND = ProviderDriverKind.make("opencode");
...@@ -80,7 +85,8 @@ export type OpenCodeDriverEnv =...@@ -80,7 +85,8 @@ export type OpenCodeDriverEnv =
80 | OpenCodeRuntime85 | OpenCodeRuntime
81 | Path.Path86 | Path.Path
82 | ProviderEventLoggers87 | ProviderEventLoggers
83 | ServerConfig;88 | ServerConfig
89 | ServerSettingsService;
8490
85const withInstanceIdentity =91const withInstanceIdentity =
86 (input: {92 (input: {
...@@ -111,6 +117,7 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>...@@ -111,6 +117,7 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>
111 const openCodeRuntime = yield* OpenCodeRuntime;117 const openCodeRuntime = yield* OpenCodeRuntime;
112 const serverConfig = yield* ServerConfig;118 const serverConfig = yield* ServerConfig;
113 const httpClient = yield* HttpClient.HttpClient;119 const httpClient = yield* HttpClient.HttpClient;
120 const serverSettings = yield* ServerSettingsService;
114 const eventLoggers = yield* ProviderEventLoggers;121 const eventLoggers = yield* ProviderEventLoggers;
115 const processEnv = mergeProviderInstanceEnvironment(environment);122 const processEnv = mergeProviderInstanceEnvironment(environment);
116 const continuationIdentity = defaultProviderContinuationIdentity({123 const continuationIdentity = defaultProviderContinuationIdentity({
...@@ -142,21 +149,26 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>...@@ -142,21 +149,26 @@ export const OpenCodeDriver: ProviderDriver<OpenCodeSettings, OpenCodeDriverEnv>
142 processEnv,149 processEnv,
143 ).pipe(Effect.map(stampIdentity), Effect.provideService(OpenCodeRuntime, openCodeRuntime));150 ).pipe(Effect.map(stampIdentity), Effect.provideService(OpenCodeRuntime, openCodeRuntime));
144151
145 const snapshot = yield* makeManagedServerProvider<OpenCodeSettings>({152 const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
146 maintenanceCapabilities,153 const snapshot = yield* makeManagedServerProvider<ProviderSnapshotSettings<OpenCodeSettings>>(
147 getSettings: Effect.succeed(effectiveConfig),154 {
148 streamSettings: Stream.never,155 maintenanceCapabilities,
149 haveSettingsChanged: () => false,156 getSettings: snapshotSettings.getSettings,
150 initialSnapshot: (settings) =>157 streamSettings: snapshotSettings.streamSettings,
151 makePendingOpenCodeProvider(settings).pipe(Effect.map(stampIdentity)),158 haveSettingsChanged: haveProviderSnapshotSettingsChanged,
152 checkProvider,159 initialSnapshot: (settings) =>
153 enrichSnapshot: ({ snapshot, publishSnapshot }) =>160 makePendingOpenCodeProvider(settings.provider).pipe(Effect.map(stampIdentity)),
154 enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities).pipe(161 checkProvider,
155 Effect.provideService(HttpClient.HttpClient, httpClient),162 enrichSnapshot: ({ settings, snapshot, publishSnapshot }) =>
156 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),163 enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities, {
157 ),164 enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
158 refreshInterval: SNAPSHOT_REFRESH_INTERVAL,165 }).pipe(
159 }).pipe(166 Effect.provideService(HttpClient.HttpClient, httpClient),
167 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),
168 ),
169 refreshInterval: SNAPSHOT_REFRESH_INTERVAL,
170 },
171 ).pipe(
160 Effect.mapError(172 Effect.mapError(
161 (cause) =>173 (cause) =>
162 new ProviderDriverError({174 new ProviderDriverError({
apps/server/src/provider/Layers/CursorProvider.ts+4-1
...@@ -1106,6 +1106,7 @@ export const enrichCursorSnapshot = (input: {...@@ -1106,6 +1106,7 @@ export const enrichCursorSnapshot = (input: {
1106 readonly settings: CursorSettings;1106 readonly settings: CursorSettings;
1107 readonly snapshot: ServerProvider;1107 readonly snapshot: ServerProvider;
1108 readonly maintenanceCapabilities: ProviderMaintenanceCapabilities;1108 readonly maintenanceCapabilities: ProviderMaintenanceCapabilities;
1109 readonly enableProviderUpdateChecks?: boolean;
1109 readonly publishSnapshot: (snapshot: ServerProvider) => Effect.Effect<void>;1110 readonly publishSnapshot: (snapshot: ServerProvider) => Effect.Effect<void>;
1110 readonly stampIdentity?: (snapshot: ServerProvider) => ServerProvider;1111 readonly stampIdentity?: (snapshot: ServerProvider) => ServerProvider;
1111 readonly httpClient: HttpClient.HttpClient;1112 readonly httpClient: HttpClient.HttpClient;
...@@ -1117,7 +1118,9 @@ export const enrichCursorSnapshot = (input: {...@@ -1117,7 +1118,9 @@ export const enrichCursorSnapshot = (input: {
1117 return Effect.void;1118 return Effect.void;
1118 }1119 }
11191120
1120 return enrichProviderSnapshotWithVersionAdvisory(snapshot, input.maintenanceCapabilities).pipe(1121 return enrichProviderSnapshotWithVersionAdvisory(snapshot, input.maintenanceCapabilities, {
1122 enableProviderUpdateChecks: input.enableProviderUpdateChecks,
1123 }).pipe(
1121 Effect.provideService(HttpClient.HttpClient, input.httpClient),1124 Effect.provideService(HttpClient.HttpClient, input.httpClient),
1122 Effect.flatMap((enrichedSnapshot) =>1125 Effect.flatMap((enrichedSnapshot) =>
1123 publishSnapshot(stampIdentity(enrichedSnapshot)).pipe(Effect.as(enrichedSnapshot)),1126 publishSnapshot(stampIdentity(enrichedSnapshot)).pipe(Effect.as(enrichedSnapshot)),
apps/server/src/provider/Layers/GrokProvider.ts+4-1
...@@ -311,12 +311,15 @@ export const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(func...@@ -311,12 +311,15 @@ export const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(func
311export const enrichGrokSnapshot = (input: {311export const enrichGrokSnapshot = (input: {
312 readonly snapshot: ServerProvider;312 readonly snapshot: ServerProvider;
313 readonly maintenanceCapabilities: ProviderMaintenanceCapabilities;313 readonly maintenanceCapabilities: ProviderMaintenanceCapabilities;
314 readonly enableProviderUpdateChecks?: boolean;
314 readonly publishSnapshot: (snapshot: ServerProvider) => Effect.Effect<void>;315 readonly publishSnapshot: (snapshot: ServerProvider) => Effect.Effect<void>;
315 readonly httpClient: HttpClient.HttpClient;316 readonly httpClient: HttpClient.HttpClient;
316}): Effect.Effect<void> => {317}): Effect.Effect<void> => {
317 const { snapshot, publishSnapshot } = input;318 const { snapshot, publishSnapshot } = input;
318319
319 return enrichProviderSnapshotWithVersionAdvisory(snapshot, input.maintenanceCapabilities).pipe(320 return enrichProviderSnapshotWithVersionAdvisory(snapshot, input.maintenanceCapabilities, {
321 enableProviderUpdateChecks: input.enableProviderUpdateChecks,
322 }).pipe(
320 Effect.provideService(HttpClient.HttpClient, input.httpClient),323 Effect.provideService(HttpClient.HttpClient, input.httpClient),
321 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),324 Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot)),
322 Effect.catchCause((cause) =>325 Effect.catchCause((cause) =>
apps/server/src/provider/Layers/ProviderInstanceRegistryLive.test.ts+3
...@@ -39,6 +39,7 @@ import * as Layer from "effect/Layer";...@@ -39,6 +39,7 @@ import * as Layer from "effect/Layer";
39import { HttpClient, HttpClientResponse } from "effect/unstable/http";39import { HttpClient, HttpClientResponse } from "effect/unstable/http";
4040
41import { ServerConfig } from "../../config.ts";41import { ServerConfig } from "../../config.ts";
42import { ServerSettingsService } from "../../serverSettings.ts";
42import { ClaudeDriver } from "../Drivers/ClaudeDriver.ts";43import { ClaudeDriver } from "../Drivers/ClaudeDriver.ts";
43import { CodexDriver } from "../Drivers/CodexDriver.ts";44import { CodexDriver } from "../Drivers/CodexDriver.ts";
44import { CursorDriver } from "../Drivers/CursorDriver.ts";45import { CursorDriver } from "../Drivers/CursorDriver.ts";
...@@ -107,6 +108,7 @@ describe("ProviderInstanceRegistryLive — multi-instance codex slice", () => {...@@ -107,6 +108,7 @@ describe("ProviderInstanceRegistryLive — multi-instance codex slice", () => {
107 prefix: "provider-instance-registry-test",108 prefix: "provider-instance-registry-test",
108 }).pipe(109 }).pipe(
109 Layer.provideMerge(NodeServices.layer),110 Layer.provideMerge(NodeServices.layer),
111 Layer.provideMerge(ServerSettingsService.layerTest()),
110 Layer.provideMerge(TestHttpClientLive),112 Layer.provideMerge(TestHttpClientLive),
111 Layer.provideMerge(Layer.succeed(ProviderEventLoggers, NoOpProviderEventLoggers)),113 Layer.provideMerge(Layer.succeed(ProviderEventLoggers, NoOpProviderEventLoggers)),
112 );114 );
...@@ -244,6 +246,7 @@ describe("ProviderInstanceRegistryLive — all drivers slice", () => {...@@ -244,6 +246,7 @@ describe("ProviderInstanceRegistryLive — all drivers slice", () => {
244 prefix: "provider-instance-registry-all-drivers-test",246 prefix: "provider-instance-registry-all-drivers-test",
245 }).pipe(247 }).pipe(
246 Layer.provideMerge(infraLayer),248 Layer.provideMerge(infraLayer),
249 Layer.provideMerge(ServerSettingsService.layerTest()),
247 Layer.provideMerge(TestHttpClientLive),250 Layer.provideMerge(TestHttpClientLive),
248 Layer.provideMerge(Layer.succeed(ProviderEventLoggers, NoOpProviderEventLoggers)),251 Layer.provideMerge(Layer.succeed(ProviderEventLoggers, NoOpProviderEventLoggers)),
249 );252 );
apps/server/src/provider/makeManagedServerProvider.ts+1-1
...@@ -21,7 +21,7 @@ export const makeManagedServerProvider = Effect.fn("makeManagedServerProvider")(...@@ -21,7 +21,7 @@ export const makeManagedServerProvider = Effect.fn("makeManagedServerProvider")(
21 Settings,21 Settings,
22>(input: {22>(input: {
23 readonly maintenanceCapabilities: ServerProviderShape["maintenanceCapabilities"];23 readonly maintenanceCapabilities: ServerProviderShape["maintenanceCapabilities"];
24 readonly getSettings: Effect.Effect<Settings>;24 readonly getSettings: Effect.Effect<Settings, ServerSettingsError>;
25 readonly streamSettings: Stream.Stream<Settings>;25 readonly streamSettings: Stream.Stream<Settings>;
26 readonly haveSettingsChanged: (previous: Settings, next: Settings) => boolean;26 readonly haveSettingsChanged: (previous: Settings, next: Settings) => boolean;
27 readonly initialSnapshot: (settings: Settings) => Effect.Effect<ServerProvider>;27 readonly initialSnapshot: (settings: Settings) => Effect.Effect<ServerProvider>;
apps/server/src/provider/providerMaintenance.test.ts+41-1
...@@ -4,13 +4,14 @@ import { chmodSync, mkdirSync, symlinkSync, writeFileSync } from "node:fs";...@@ -4,13 +4,14 @@ import { chmodSync, mkdirSync, symlinkSync, writeFileSync } from "node:fs";
4import * as NodeServices from "@effect/platform-node/NodeServices";4import * as NodeServices from "@effect/platform-node/NodeServices";
5import * as NodeOS from "node:os";5import * as NodeOS from "node:os";
6import path from "node:path";6import path from "node:path";
7import { ProviderDriverKind } from "@t3tools/contracts";7import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";
8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";8import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
9import * as Crypto from "effect/Crypto";9import * as Crypto from "effect/Crypto";
10import * as Effect from "effect/Effect";10import * as Effect from "effect/Effect";
11import { HttpClient } from "effect/unstable/http";11import { HttpClient } from "effect/unstable/http";
12import {12import {
13 createProviderVersionAdvisory,13 createProviderVersionAdvisory,
14 enrichProviderSnapshotWithVersionAdvisory,
14 makePackageManagedProviderMaintenanceResolver,15 makePackageManagedProviderMaintenanceResolver,
15 makeProviderMaintenanceCapabilities,16 makeProviderMaintenanceCapabilities,
16 makeStaticProviderMaintenanceResolver,17 makeStaticProviderMaintenanceResolver,
...@@ -67,6 +68,19 @@ const staticToolUpdate = makeStaticProviderMaintenanceResolver(...@@ -67,6 +68,19 @@ const staticToolUpdate = makeStaticProviderMaintenanceResolver(
67 updateLockKey: "static-tool",68 updateLockKey: "static-tool",
68 }),69 }),
69);70);
71const installedPackageToolProvider: ServerProvider = {
72 instanceId: ProviderInstanceId.make("packageTool"),
73 driver: driver("packageTool"),
74 enabled: true,
75 installed: true,
76 version: "1.0.0",
77 status: "ready",
78 auth: { status: "authenticated" },
79 checkedAt: "2026-04-10T00:00:00.000Z",
80 models: [],
81 slashCommands: [],
82 skills: [],
83};
7084
71it.layer(NodeServices.layer)("providerMaintenance", (it) => {85it.layer(NodeServices.layer)("providerMaintenance", (it) => {
72 it.effect("reads cached versions through the injectable cache reference", () =>86 it.effect("reads cached versions through the injectable cache reference", () =>
...@@ -95,6 +109,32 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -95,6 +109,32 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
95 ),109 ),
96 );110 );
97111
112 it.effect("does not fetch latest provider versions when update checks are disabled", () =>
113 enrichProviderSnapshotWithVersionAdvisory(
114 installedPackageToolProvider,
115 packageToolUpdate.resolve(),
116 {
117 enableProviderUpdateChecks: false,
118 },
119 ).pipe(
120 Effect.provideService(ProviderVersionCache, new Map()),
121 Effect.provideService(
122 HttpClient.HttpClient,
123 HttpClient.make(() =>
124 Effect.die("disabled provider update checks should not make an HTTP request"),
125 ),
126 ),
127 Effect.map((provider) => {
128 expect(provider.versionAdvisory).toMatchObject({
129 status: "unknown",
130 currentVersion: "1.0.0",
131 latestVersion: null,
132 checkedAt: "2026-04-10T00:00:00.000Z",
133 });
134 }),
135 ),
136 );
137
98 it("marks providers with unknown current versions as unknown", () => {138 it("marks providers with unknown current versions as unknown", () => {
99 expect(139 expect(
100 createProviderVersionAdvisory({140 createProviderVersionAdvisory({
apps/server/src/provider/providerMaintenance.ts+13-2
...@@ -468,10 +468,21 @@ export const resolveLatestProviderVersion = Effect.fn("resolveLatestProviderVers...@@ -468,10 +468,21 @@ export const resolveLatestProviderVersion = Effect.fn("resolveLatestProviderVers
468468
469export const enrichProviderSnapshotWithVersionAdvisory = Effect.fn(469export const enrichProviderSnapshotWithVersionAdvisory = Effect.fn(
470 "enrichProviderSnapshotWithVersionAdvisory",470 "enrichProviderSnapshotWithVersionAdvisory",
471)(function* (snapshot: ServerProvider, maintenanceCapabilities?: ProviderMaintenanceCapabilities) {471)(function* (
472 snapshot: ServerProvider,
473 maintenanceCapabilities?: ProviderMaintenanceCapabilities,
474 options?: {
475 readonly enableProviderUpdateChecks: boolean | undefined;
476 },
477) {
472 const capabilities =478 const capabilities =
473 maintenanceCapabilities ?? makeManualProviderMaintenanceCapabilities(snapshot.driver);479 maintenanceCapabilities ?? makeManualProviderMaintenanceCapabilities(snapshot.driver);
474 if (!snapshot.enabled || !snapshot.installed || !snapshot.version) {480 const shouldResolveLatestVersion =
481 options?.enableProviderUpdateChecks !== false &&
482 snapshot.enabled &&
483 snapshot.installed &&
484 Boolean(snapshot.version);
485 if (!shouldResolveLatestVersion) {
475 return {486 return {
476 ...snapshot,487 ...snapshot,
477 versionAdvisory: createProviderVersionAdvisory({488 versionAdvisory: createProviderVersionAdvisory({
apps/server/src/provider/providerUpdateSettings.ts created+43
...@@ -0,0 +1,43 @@
1import type { ServerSettings, ServerSettingsError } from "@t3tools/contracts";
2import * as Effect from "effect/Effect";
3import * as Equal from "effect/Equal";
4import * as Stream from "effect/Stream";
5
6import type { ServerSettingsShape } from "../serverSettings.ts";
7
8export interface ProviderSnapshotSettings<Settings> {
9 readonly provider: Settings;
10 readonly enableProviderUpdateChecks: boolean;
11}
12
13export function makeProviderSnapshotSettings<Settings>(
14 provider: Settings,
15 settings: ServerSettings,
16): ProviderSnapshotSettings<Settings> {
17 return {
18 provider,
19 enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
20 };
21}
22
23export function haveProviderSnapshotSettingsChanged<Settings>(
24 previous: ProviderSnapshotSettings<Settings>,
25 next: ProviderSnapshotSettings<Settings>,
26): boolean {
27 return !Equal.equals(previous, next);
28}
29
30export function makeProviderSnapshotSettingsSource<Settings>(
31 provider: Settings,
32 serverSettings: ServerSettingsShape,
33): {
34 readonly getSettings: Effect.Effect<ProviderSnapshotSettings<Settings>, ServerSettingsError>;
35 readonly streamSettings: Stream.Stream<ProviderSnapshotSettings<Settings>>;
36} {
37 const mapSettings = (settings: ServerSettings) =>
38 makeProviderSnapshotSettings(provider, settings);
39 return {
40 getSettings: serverSettings.getSettings.pipe(Effect.map(mapSettings)),
41 streamSettings: serverSettings.streamChanges.pipe(Stream.map(mapSettings)),
42 };
43}
apps/web/src/components/settings/SettingsPanels.tsx+27
...@@ -668,6 +668,33 @@ export function GeneralSettingsPanel() {...@@ -668,6 +668,33 @@ export function GeneralSettingsPanel() {
668 }668 }
669 />669 />
670670
671 <SettingsRow
672 title="Provider update checks"
673 description="Check installed provider CLIs for newer available versions."
674 resetAction={
675 settings.enableProviderUpdateChecks !==
676 DEFAULT_UNIFIED_SETTINGS.enableProviderUpdateChecks ? (
677 <SettingResetButton
678 label="provider update checks"
679 onClick={() =>
680 updateSettings({
681 enableProviderUpdateChecks: DEFAULT_UNIFIED_SETTINGS.enableProviderUpdateChecks,
682 })
683 }
684 />
685 ) : null
686 }
687 control={
688 <Switch
689 checked={settings.enableProviderUpdateChecks}
690 onCheckedChange={(checked) =>
691 updateSettings({ enableProviderUpdateChecks: Boolean(checked) })
692 }
693 aria-label="Check provider versions"
694 />
695 }
696 />
697
671 <SettingsRow698 <SettingsRow
672 title="Auto-open task panel"699 title="Auto-open task panel"
673 description="Open the right-side plan and task panel automatically when steps appear."700 description="Open the right-side plan and task panel automatically when steps appear."
packages/contracts/src/settings.ts+2
...@@ -365,6 +365,7 @@ export const DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL = Duration.seconds(30);...@@ -365,6 +365,7 @@ export const DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL = Duration.seconds(30);
365365
366export const ServerSettings = Schema.Struct({366export const ServerSettings = Schema.Struct({
367 enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),367 enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
368 enableProviderUpdateChecks: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))),
368 automaticGitFetchInterval: Schema.DurationFromMillis.pipe(369 automaticGitFetchInterval: Schema.DurationFromMillis.pipe(
369 Schema.withDecodingDefault(370 Schema.withDecodingDefault(
370 Effect.succeed(Duration.toMillis(DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL)),371 Effect.succeed(Duration.toMillis(DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL)),
...@@ -482,6 +483,7 @@ const OpenCodeSettingsPatch = Schema.Struct({...@@ -482,6 +483,7 @@ const OpenCodeSettingsPatch = Schema.Struct({
482export const ServerSettingsPatch = Schema.Struct({483export const ServerSettingsPatch = Schema.Struct({
483 // Server settings484 // Server settings
484 enableAssistantStreaming: Schema.optionalKey(Schema.Boolean),485 enableAssistantStreaming: Schema.optionalKey(Schema.Boolean),
486 enableProviderUpdateChecks: Schema.optionalKey(Schema.Boolean),
485 automaticGitFetchInterval: Schema.optionalKey(Schema.DurationFromMillis),487 automaticGitFetchInterval: Schema.optionalKey(Schema.DurationFromMillis),
486 defaultThreadEnvMode: Schema.optionalKey(ThreadEnvMode),488 defaultThreadEnvMode: Schema.optionalKey(ThreadEnvMode),
487 newWorktreesStartFromOrigin: Schema.optionalKey(Schema.Boolean),489 newWorktreesStartFromOrigin: Schema.optionalKey(Schema.Boolean),