mirror of
https://github.com/cline/cline.git
synced 2026-09-04 11:44:01 +08:00
add interval to fetch and set remote config (#6813)
* add interval to fetch and set remote config * clear the remote config if the user goes from an org to a private account
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
GlobalFileNames,
|
||||
writeMcpMarketplaceCatalogToCache,
|
||||
} from "../storage/disk"
|
||||
import { fetchRemoteConfig } from "../storage/remote-config/fetch"
|
||||
import { PersistenceErrorEvent, StateManager } from "../storage/StateManager"
|
||||
import { Task } from "../task"
|
||||
import { sendMcpMarketplaceCatalogEvent } from "./mcp/subscribeToMcpMarketplaceCatalog"
|
||||
@@ -67,6 +68,9 @@ export class Controller {
|
||||
// NEW: Add workspace manager (optional initially)
|
||||
private workspaceManager?: WorkspaceRootManager
|
||||
|
||||
// Timer for periodic remote config fetching
|
||||
private remoteConfigTimer?: NodeJS.Timeout
|
||||
|
||||
// Public getter for workspace manager with lazy initialization - To get workspaces when task isn't initialized (Used by file mentions)
|
||||
async ensureWorkspaceManager(): Promise<WorkspaceRootManager | undefined> {
|
||||
if (!this.workspaceManager) {
|
||||
@@ -87,15 +91,28 @@ export class Controller {
|
||||
return this.workspaceManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the periodic remote config fetching timer
|
||||
* Fetches immediately and then every 30 seconds
|
||||
*/
|
||||
private startRemoteConfigTimer() {
|
||||
// Initial fetch
|
||||
fetchRemoteConfig(this).catch((error) => {
|
||||
console.error("Failed to fetch remote config:", error)
|
||||
})
|
||||
|
||||
// Set up 30-second interval
|
||||
this.remoteConfigTimer = setInterval(() => {
|
||||
fetchRemoteConfig(this).catch((error) => {
|
||||
console.error("Failed to fetch remote config:", error)
|
||||
})
|
||||
}, 30000) // 30 seconds
|
||||
}
|
||||
|
||||
constructor(readonly context: vscode.ExtensionContext) {
|
||||
PromptRegistry.getInstance() // Ensure prompts and tools are registered
|
||||
HostProvider.get().logToChannel("ClineProvider instantiated")
|
||||
this.stateManager = StateManager.get()
|
||||
this.authService = AuthService.getInstance(this)
|
||||
this.ocaAuthService = OcaAuthService.initialize(this)
|
||||
this.accountService = ClineAccountService.getInstance()
|
||||
this.authService.restoreRefreshTokenAndRetrieveAuthInfo()
|
||||
|
||||
StateManager.get().registerCallbacks({
|
||||
onPersistenceError: async ({ error }: PersistenceErrorEvent) => {
|
||||
console.error("[Controller] Cache persistence failed, recovering:", error)
|
||||
@@ -118,6 +135,13 @@ export class Controller {
|
||||
await this.postStateToWebview()
|
||||
},
|
||||
})
|
||||
this.authService = AuthService.getInstance(this)
|
||||
this.ocaAuthService = OcaAuthService.initialize(this)
|
||||
this.accountService = ClineAccountService.getInstance()
|
||||
|
||||
this.authService.restoreRefreshTokenAndRetrieveAuthInfo().then(() => {
|
||||
this.startRemoteConfigTimer()
|
||||
})
|
||||
|
||||
this.mcpHub = new McpHub(
|
||||
() => ensureMcpServersDirectoryExists(),
|
||||
@@ -138,6 +162,12 @@ export class Controller {
|
||||
- https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
|
||||
*/
|
||||
async dispose() {
|
||||
// Clear the remote config timer
|
||||
if (this.remoteConfigTimer) {
|
||||
clearInterval(this.remoteConfigTimer)
|
||||
this.remoteConfigTimer = undefined
|
||||
}
|
||||
|
||||
await this.clearTask()
|
||||
this.mcpHub.dispose()
|
||||
|
||||
|
||||
@@ -315,6 +315,18 @@ export async function writeRemoteConfigToCache(organizationId: string, config: R
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteRemoteConfigFromCache(organizationId: string): Promise<void> {
|
||||
try {
|
||||
const remoteConfigFilePath = path.join(await ensureCacheDirectoryExists(), GlobalFileNames.remoteConfig(organizationId))
|
||||
const fileExists = await fileExistsAtPath(remoteConfigFilePath)
|
||||
if (fileExists) {
|
||||
await fs.unlink(remoteConfigFilePath)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to delete remote config from cache:", error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paths to the workspace's .clinerules/hooks directories to search for
|
||||
* hooks. A workspace may not use hooks, and the resulting array will be empty. A
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import axios, { AxiosRequestConfig, AxiosResponse } from "axios"
|
||||
import { Controller } from "@/core/controller"
|
||||
import { clineEnvConfig } from "../../../config"
|
||||
import { AuthService } from "../../../services/auth/AuthService"
|
||||
import { CLINE_API_ENDPOINT } from "../../../shared/cline/api"
|
||||
import { RemoteConfig, RemoteConfigSchema } from "../../../shared/remote-config/schema"
|
||||
import { readRemoteConfigFromCache, writeRemoteConfigToCache } from "../disk"
|
||||
import { deleteRemoteConfigFromCache, readRemoteConfigFromCache, writeRemoteConfigToCache } from "../disk"
|
||||
import { StateManager } from "../StateManager"
|
||||
import { applyRemoteConfig } from "./utils"
|
||||
|
||||
/**
|
||||
@@ -13,12 +15,15 @@ import { applyRemoteConfig } from "./utils"
|
||||
* @returns Promise resolving to the RemoteConfig object, or undefined if no active organization exists
|
||||
* @throws Error if both API fetch and cache retrieval fail (when an organization exists)
|
||||
*/
|
||||
export async function fetchRemoteConfig(): Promise<RemoteConfig | undefined> {
|
||||
export async function fetchRemoteConfig(controller: Controller): Promise<RemoteConfig | undefined> {
|
||||
const authService = AuthService.getInstance()
|
||||
|
||||
// Get the active organization ID
|
||||
const organizationId = authService.getActiveOrganizationId()
|
||||
|
||||
if (!organizationId) {
|
||||
// Clear the in-memory cache of the remote config settings in case it was previously set with an organization that has remote config
|
||||
StateManager.get().clearRemoteConfig()
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -74,6 +79,12 @@ export async function fetchRemoteConfig(): Promise<RemoteConfig | undefined> {
|
||||
|
||||
// Check if config is enabled
|
||||
if (!configData.enabled) {
|
||||
// Clear the remote config from the on-disk cache if it exists
|
||||
await deleteRemoteConfigFromCache(organizationId)
|
||||
|
||||
// Clear the in-memory cache of the remote config settings in case it was previously set
|
||||
StateManager.get().clearRemoteConfig()
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -89,6 +100,8 @@ export async function fetchRemoteConfig(): Promise<RemoteConfig | undefined> {
|
||||
// Apply config to StateManager
|
||||
applyRemoteConfig(validatedConfig)
|
||||
|
||||
controller.postStateToWebview()
|
||||
|
||||
return validatedConfig
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch remote config from API:", error)
|
||||
@@ -96,16 +109,21 @@ export async function fetchRemoteConfig(): Promise<RemoteConfig | undefined> {
|
||||
// Try to fall back to cached config
|
||||
const cachedConfig = await readRemoteConfigFromCache(organizationId)
|
||||
if (cachedConfig) {
|
||||
// Validate cached config against schema
|
||||
const validatedCachedConfig = RemoteConfigSchema.parse(cachedConfig)
|
||||
// Apply config to StateManager
|
||||
applyRemoteConfig(validatedCachedConfig)
|
||||
return validatedCachedConfig
|
||||
try {
|
||||
// Validate cached config against schema
|
||||
const validatedCachedConfig = RemoteConfigSchema.parse(cachedConfig)
|
||||
// Apply config to StateManager
|
||||
applyRemoteConfig(validatedCachedConfig)
|
||||
return validatedCachedConfig
|
||||
} catch (validationError) {
|
||||
// Cache validation failed - log and fall through
|
||||
console.error("Cached config validation failed:", validationError)
|
||||
}
|
||||
}
|
||||
|
||||
// Both API and cache failed
|
||||
// Both API and cache failed (or cache was invalid)
|
||||
throw new Error(
|
||||
`Failed to fetch remote config: ${error instanceof Error ? error.message : "Unknown error"}. No cached config available.`,
|
||||
`Failed to fetch remote config: ${error instanceof Error ? error.message : "Unknown error"}. No valid cached config available.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user