Skip to content

Commit f6d114d

Browse files
chezsmithySmith
authored and
Smith
committed
refactor: ♻️ Refactor CodeBaseIndexer out of core
1 parent f14824c commit f6d114d

File tree

5 files changed

+337
-165
lines changed

5 files changed

+337
-165
lines changed

core/config/yaml/loadYaml.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function convertYamlMcpToContinueMcp(
6868
return {
6969
transport: {
7070
type: "stdio",
71-
command: server.command,
71+
command: server.command || "", // Add default empty string to handle undefined
7272
args: server.args ?? [],
7373
env: server.env,
7474
} as any, // TODO: Fix the mcpServers types in config-yaml (discriminated union)
@@ -452,16 +452,28 @@ async function configYamlToContinueConfig(options: {
452452
// Trigger MCP server refreshes (Config is reloaded again once connected!)
453453
const mcpManager = MCPManagerSingleton.getInstance();
454454
mcpManager.setConnections(
455-
(config.mcpServers ?? []).map((server) => ({
456-
id: server.name,
457-
name: server.name,
458-
transport: {
459-
type: "stdio",
460-
args: [],
461-
...(server as any), // TODO: fix the types on mcpServers in config-yaml
462-
},
463-
timeout: server.connectionTimeout,
464-
})),
455+
(config.mcpServers ?? []).map((server) => {
456+
// Create proper transport object based on type
457+
const transport = server.type === "sse"
458+
? {
459+
type: "sse" as const,
460+
url: server.url || "",
461+
faviconUrl: server.faviconUrl
462+
}
463+
: {
464+
type: "stdio" as const,
465+
command: server.command || "",
466+
args: server.args || [],
467+
env: server.env,
468+
faviconUrl: server.faviconUrl
469+
};
470+
return {
471+
id: server.name,
472+
name: server.name,
473+
transport,
474+
timeout: server.connectionTimeout
475+
};
476+
}),
465477
false,
466478
);
467479

@@ -507,8 +519,8 @@ export async function loadContinueConfigFromYaml(options: {
507519
errors: configYamlResult.errors,
508520
config: undefined,
509521
configLoadInterrupted: true,
510-
};
511-
}
522+
};
523+
}
512524

513525
const { config: continueConfig, errors: localErrors } =
514526
await configYamlToContinueConfig({

core/core.ts

Lines changed: 25 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { getAuthUrlForTokenPage } from "./control-plane/auth/index";
1414
import { getControlPlaneEnv } from "./control-plane/env";
1515
import { DevDataSqliteDb } from "./data/devdataSqlite";
1616
import { DataLogger } from "./data/log";
17-
import { CodebaseIndexer, PauseToken } from "./indexing/CodebaseIndexer";
17+
import { CodebaseIndexer } from "./indexing/CodebaseIndexer";
1818
import DocsService from "./indexing/docs/DocsService";
1919
import { countTokens } from "./llm/countTokens";
2020
import Ollama from "./llm/llms/Ollama";
@@ -40,8 +40,7 @@ import {
4040
RangeInFile,
4141
type ContextItem,
4242
type ContextItemId,
43-
type IDE,
44-
type IndexingProgressUpdate,
43+
type IDE
4544
} from ".";
4645

4746
import { ConfigYaml } from "@continuedev/config-yaml";
@@ -56,7 +55,6 @@ import { MCPManagerSingleton } from "./context/mcp/MCPManagerSingleton";
5655
import { streamDiffLines } from "./edit/streamDiffLines";
5756
import { shouldIgnore } from "./indexing/shouldIgnore";
5857
import { walkDirCache } from "./indexing/walkDir";
59-
import { LLMError } from "./llm";
6058
import { LLMLogger } from "./llm/logger";
6159
import { llmStreamChat } from "./llm/streamChat";
6260
import type { FromCoreProtocol, ToCoreProtocol } from "./protocol";
@@ -65,18 +63,13 @@ import { StreamAbortManager } from "./util/abortManager";
6563

6664
export class Core {
6765
configHandler: ConfigHandler;
68-
codebaseIndexerPromise: Promise<CodebaseIndexer>;
66+
codeBaseIndexer: CodebaseIndexer;
6967
completionProvider: CompletionProvider;
70-
continueServerClientPromise: Promise<ContinueServerClient>;
71-
codebaseIndexingState: IndexingProgressUpdate;
68+
continueServerClientPromise: Promise<ContinueServerClient>;
7269
private docsService: DocsService;
7370
private globalContext = new GlobalContext();
7471
llmLogger = new LLMLogger();
7572

76-
private readonly indexingPauseToken = new PauseToken(
77-
this.globalContext.get("indexingPaused") === true,
78-
);
79-
8073
private messageAbortControllers = new Map<string, AbortController>();
8174
private addMessageAbortController(id: string): AbortController {
8275
const controller = new AbortController();
@@ -114,12 +107,6 @@ export class Core {
114107
// Ensure .continue directory is created
115108
migrateV1DevDataFiles();
116109

117-
this.codebaseIndexingState = {
118-
status: "loading",
119-
desc: "loading",
120-
progress: 0,
121-
};
122-
123110
const ideInfoPromise = messenger.request("getIdeInfo", undefined);
124111
const ideSettingsPromise = messenger.request("getIdeSettings", undefined);
125112
const sessionInfoPromise = messenger.request("getControlPlaneSessionInfo", {
@@ -144,6 +131,13 @@ export class Core {
144131
await this.configHandler.reloadConfig();
145132
};
146133

134+
this.codeBaseIndexer = new CodebaseIndexer(
135+
this.configHandler,
136+
this.ide,
137+
this.messenger,
138+
this.globalContext.get("indexingPaused"),
139+
);
140+
147141
this.configHandler.onConfigUpdate(async (result) => {
148142
const serializedResult = await this.configHandler.getSerializedConfig();
149143
this.messenger.send("configUpdate", {
@@ -170,38 +164,24 @@ export class Core {
170164
dataLogger.ideInfoPromise = ideInfoPromise;
171165
dataLogger.ideSettingsPromise = ideSettingsPromise;
172166

173-
// Codebase Indexer and ContinueServerClient depend on IdeSettings
174-
let codebaseIndexerResolve: (_: any) => void | undefined;
175-
this.codebaseIndexerPromise = new Promise(
176-
async (resolve) => (codebaseIndexerResolve = resolve),
177-
);
178-
179167
let continueServerClientResolve: (_: any) => void | undefined;
180168
this.continueServerClientPromise = new Promise(
181169
(resolve) => (continueServerClientResolve = resolve),
182170
);
183171

172+
184173
void ideSettingsPromise.then((ideSettings) => {
185-
const continueServerClient = new ContinueServerClient(
174+
const continueServerClient = new ContinueServerClient(
186175
ideSettings.remoteConfigServerUrl,
187176
ideSettings.userToken,
188177
);
189178
continueServerClientResolve(continueServerClient);
190179

191-
codebaseIndexerResolve(
192-
new CodebaseIndexer(
193-
this.configHandler,
194-
this.ide,
195-
this.indexingPauseToken,
196-
continueServerClient,
197-
),
198-
);
199-
200180
// Index on initialization
201181
void this.ide.getWorkspaceDirs().then(async (dirs) => {
202182
// Respect pauseCodebaseIndexOnStart user settings
203183
if (ideSettings.pauseCodebaseIndexOnStart) {
204-
this.indexingPauseToken.paused = true;
184+
this.codeBaseIndexer.paused = true;
205185
void this.messenger.request("indexProgress", {
206186
progress: 0,
207187
desc: "Initial Indexing Skipped",
@@ -210,7 +190,7 @@ export class Core {
210190
return;
211191
}
212192

213-
void this.refreshCodebaseIndex(dirs);
193+
await this.codeBaseIndexer.refreshCodebaseIndex(dirs);
214194
});
215195
});
216196

@@ -551,25 +531,24 @@ export class Core {
551531
}
552532
walkDirCache.invalidate();
553533
if (data?.shouldClearIndexes) {
554-
const codebaseIndexer = await this.codebaseIndexerPromise;
555-
await codebaseIndexer.clearIndexes();
534+
await this.codeBaseIndexer.clearIndexes();
556535
}
557536

558537
const dirs = data?.dirs ?? (await this.ide.getWorkspaceDirs());
559-
await this.refreshCodebaseIndex(dirs);
538+
await this.codeBaseIndexer.refreshCodebaseIndex(dirs);
560539
});
561540
on("index/setPaused", (msg) => {
562541
this.globalContext.update("indexingPaused", msg.data);
563-
this.indexingPauseToken.paused = msg.data;
542+
// Update using the new setter instead of token
543+
this.codeBaseIndexer.paused = msg.data;
564544
});
565545
on("index/indexingProgressBarInitialized", async (msg) => {
566546
// Triggered when progress bar is initialized.
567547
// If a non-default state has been stored, update the indexing display to that state
568-
if (this.codebaseIndexingState.status !== "loading") {
569-
void this.messenger.request(
570-
"indexProgress",
571-
this.codebaseIndexingState,
572-
);
548+
const currentState = this.codeBaseIndexer.currentIndexingState;
549+
550+
if (currentState.status !== "loading") {
551+
void this.messenger.request("indexProgress", currentState);
573552
}
574553
});
575554

@@ -589,7 +568,7 @@ export class Core {
589568
});
590569
const { config } = await this.configHandler.loadConfig();
591570
if (config && !config.disableIndexing) {
592-
await this.refreshCodebaseIndexFiles(toRefresh);
571+
await this.codeBaseIndexer.refreshCodebaseIndexFiles(toRefresh);
593572
}
594573
}
595574
};
@@ -853,7 +832,7 @@ export class Core {
853832
// Reindex the file
854833
const ignore = await shouldIgnore(uri, this.ide);
855834
if (!ignore) {
856-
await this.refreshCodebaseIndexFiles([uri]);
835+
await this.codeBaseIndexer.refreshCodebaseIndexFiles([uri]);
857836
}
858837
}
859838
}
@@ -1024,100 +1003,4 @@ export class Core {
10241003
return [];
10251004
}
10261005
};
1027-
1028-
private indexingCancellationController: AbortController | undefined;
1029-
private async sendIndexingErrorTelemetry(update: IndexingProgressUpdate) {
1030-
console.debug(
1031-
"Indexing failed with error: ",
1032-
update.desc,
1033-
update.debugInfo,
1034-
);
1035-
void Telemetry.capture(
1036-
"indexing_error",
1037-
{
1038-
error: update.desc,
1039-
stack: update.debugInfo,
1040-
},
1041-
false,
1042-
);
1043-
}
1044-
1045-
private async refreshCodebaseIndex(paths: string[]) {
1046-
if (this.indexingCancellationController) {
1047-
this.indexingCancellationController.abort();
1048-
}
1049-
this.indexingCancellationController = new AbortController();
1050-
try {
1051-
for await (const update of (
1052-
await this.codebaseIndexerPromise
1053-
).refreshDirs(paths, this.indexingCancellationController.signal)) {
1054-
let updateToSend = { ...update };
1055-
1056-
void this.messenger.request("indexProgress", updateToSend);
1057-
this.codebaseIndexingState = updateToSend;
1058-
1059-
if (update.status === "failed") {
1060-
void this.sendIndexingErrorTelemetry(update);
1061-
}
1062-
}
1063-
} catch (e: any) {
1064-
console.log(`Failed refreshing codebase index directories : ${e}`);
1065-
this.handleIndexingError(e);
1066-
}
1067-
1068-
this.messenger.send("refreshSubmenuItems", {
1069-
providers: "dependsOnIndexing",
1070-
});
1071-
this.indexingCancellationController = undefined;
1072-
}
1073-
1074-
private async refreshCodebaseIndexFiles(files: string[]) {
1075-
// Can be cancelled by codebase index but not vice versa
1076-
if (
1077-
this.indexingCancellationController &&
1078-
!this.indexingCancellationController.signal.aborted
1079-
) {
1080-
return;
1081-
}
1082-
this.indexingCancellationController = new AbortController();
1083-
try {
1084-
for await (const update of (
1085-
await this.codebaseIndexerPromise
1086-
).refreshFiles(files)) {
1087-
let updateToSend = { ...update };
1088-
1089-
void this.messenger.request("indexProgress", updateToSend);
1090-
this.codebaseIndexingState = updateToSend;
1091-
1092-
if (update.status === "failed") {
1093-
void this.sendIndexingErrorTelemetry(update);
1094-
}
1095-
}
1096-
} catch (e: any) {
1097-
console.log(`Failed refreshing codebase index files : ${e}`);
1098-
this.handleIndexingError(e);
1099-
}
1100-
1101-
this.messenger.send("refreshSubmenuItems", {
1102-
providers: "dependsOnIndexing",
1103-
});
1104-
this.indexingCancellationController = undefined;
1105-
}
1106-
1107-
// private
1108-
handleIndexingError(e: any) {
1109-
if (e instanceof LLMError) {
1110-
// Need to report this specific error to the IDE for special handling
1111-
void this.messenger.request("reportError", e);
1112-
}
1113-
// broadcast indexing error
1114-
let updateToSend: IndexingProgressUpdate = {
1115-
progress: 0,
1116-
status: "failed",
1117-
desc: e.message,
1118-
};
1119-
void this.messenger.request("indexProgress", updateToSend);
1120-
this.codebaseIndexingState = updateToSend;
1121-
void this.sendIndexingErrorTelemetry(updateToSend);
1122-
}
11231006
}

0 commit comments

Comments
 (0)