|
|
@@ -4,6 +4,7 @@ import { RooIgnoreController } from "../../../core/ignore/RooIgnoreController"
|
|
|
import { stat } from "fs/promises"
|
|
|
import * as path from "path"
|
|
|
import { generateNormalizedAbsolutePath, generateRelativeFilePath } from "../shared/get-relative-path"
|
|
|
+import { getWorkspacePathForContext } from "../../../utils/path"
|
|
|
import { scannerExtensions } from "../shared/supported-extensions"
|
|
|
import * as vscode from "vscode"
|
|
|
import { CodeBlock, ICodeParser, IEmbedder, IVectorStore, IDirectoryScanner } from "../interfaces"
|
|
|
@@ -49,6 +50,9 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
onFileParsed?: (fileBlockCount: number) => void,
|
|
|
): Promise<{ codeBlocks: CodeBlock[]; stats: { processed: number; skipped: number }; totalBlockCount: number }> {
|
|
|
const directoryPath = directory
|
|
|
+ // Capture workspace context at scan start
|
|
|
+ const scanWorkspace = getWorkspacePathForContext(directoryPath)
|
|
|
+
|
|
|
// Get all files recursively (handles .gitignore automatically)
|
|
|
const [allPaths, _] = await listFiles(directoryPath, true, MAX_LIST_FILES_LIMIT)
|
|
|
|
|
|
@@ -66,7 +70,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
// Filter by supported extensions, ignore patterns, and excluded directories
|
|
|
const supportedPaths = allowedPaths.filter((filePath) => {
|
|
|
const ext = path.extname(filePath).toLowerCase()
|
|
|
- const relativeFilePath = generateRelativeFilePath(filePath)
|
|
|
+ const relativeFilePath = generateRelativeFilePath(filePath, scanWorkspace)
|
|
|
|
|
|
// Check if file is in an ignored directory using the shared helper
|
|
|
if (isPathInIgnoredDirectory(filePath)) {
|
|
|
@@ -169,6 +173,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
batchBlocks,
|
|
|
batchTexts,
|
|
|
batchFileInfos,
|
|
|
+ scanWorkspace,
|
|
|
onError,
|
|
|
onBlocksIndexed,
|
|
|
),
|
|
|
@@ -185,12 +190,15 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
await this.cacheManager.updateHash(filePath, currentFileHash)
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- console.error(`Error processing file ${filePath}:`, error)
|
|
|
+ console.error(`Error processing file ${filePath} in workspace ${scanWorkspace}:`, error)
|
|
|
if (onError) {
|
|
|
onError(
|
|
|
error instanceof Error
|
|
|
- ? error
|
|
|
- : new Error(t("embeddings:scanner.unknownErrorProcessingFile", { filePath })),
|
|
|
+ ? new Error(`${error.message} (Workspace: ${scanWorkspace}, File: ${filePath})`)
|
|
|
+ : new Error(
|
|
|
+ t("embeddings:scanner.unknownErrorProcessingFile", { filePath }) +
|
|
|
+ ` (Workspace: ${scanWorkspace})`,
|
|
|
+ ),
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
@@ -214,7 +222,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
|
|
|
// Queue final batch processing
|
|
|
const batchPromise = batchLimiter(() =>
|
|
|
- this.processBatch(batchBlocks, batchTexts, batchFileInfos, onError, onBlocksIndexed),
|
|
|
+ this.processBatch(batchBlocks, batchTexts, batchFileInfos, scanWorkspace, onError, onBlocksIndexed),
|
|
|
)
|
|
|
activeBatchPromises.push(batchPromise)
|
|
|
} finally {
|
|
|
@@ -235,15 +243,20 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
await this.qdrantClient.deletePointsByFilePath(cachedFilePath)
|
|
|
await this.cacheManager.deleteHash(cachedFilePath)
|
|
|
} catch (error) {
|
|
|
- console.error(`[DirectoryScanner] Failed to delete points for ${cachedFilePath}:`, error)
|
|
|
+ console.error(
|
|
|
+ `[DirectoryScanner] Failed to delete points for ${cachedFilePath} in workspace ${scanWorkspace}:`,
|
|
|
+ error,
|
|
|
+ )
|
|
|
if (onError) {
|
|
|
onError(
|
|
|
error instanceof Error
|
|
|
- ? error
|
|
|
+ ? new Error(
|
|
|
+ `${error.message} (Workspace: ${scanWorkspace}, File: ${cachedFilePath})`,
|
|
|
+ )
|
|
|
: new Error(
|
|
|
t("embeddings:scanner.unknownErrorDeletingPoints", {
|
|
|
filePath: cachedFilePath,
|
|
|
- }),
|
|
|
+ }) + ` (Workspace: ${scanWorkspace})`,
|
|
|
),
|
|
|
)
|
|
|
}
|
|
|
@@ -267,6 +280,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
batchBlocks: CodeBlock[],
|
|
|
batchTexts: string[],
|
|
|
batchFileInfos: { filePath: string; fileHash: string; isNew: boolean }[],
|
|
|
+ scanWorkspace: string,
|
|
|
onError?: (error: Error) => void,
|
|
|
onBlocksIndexed?: (indexedCount: number) => void,
|
|
|
): Promise<void> {
|
|
|
@@ -292,11 +306,14 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
await this.qdrantClient.deletePointsByMultipleFilePaths(uniqueFilePaths)
|
|
|
} catch (deleteError) {
|
|
|
console.error(
|
|
|
- `[DirectoryScanner] Failed to delete points for ${uniqueFilePaths.length} files before upsert:`,
|
|
|
+ `[DirectoryScanner] Failed to delete points for ${uniqueFilePaths.length} files before upsert in workspace ${scanWorkspace}:`,
|
|
|
deleteError,
|
|
|
)
|
|
|
- // Re-throw the error to stop processing this batch attempt
|
|
|
- throw deleteError
|
|
|
+ // Re-throw the error with workspace context
|
|
|
+ throw new Error(
|
|
|
+ `Failed to delete points for ${uniqueFilePaths.length} files. Workspace: ${scanWorkspace}. ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`,
|
|
|
+ { cause: deleteError },
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
// --- End Deletion Step ---
|
|
|
@@ -306,7 +323,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
|
|
|
// Prepare points for Qdrant
|
|
|
const points = batchBlocks.map((block, index) => {
|
|
|
- const normalizedAbsolutePath = generateNormalizedAbsolutePath(block.file_path)
|
|
|
+ const normalizedAbsolutePath = generateNormalizedAbsolutePath(block.file_path, scanWorkspace)
|
|
|
|
|
|
// Use segmentHash for unique ID generation to handle multiple segments from same line
|
|
|
const pointId = uuidv5(block.segmentHash, QDRANT_CODE_BLOCK_NAMESPACE)
|
|
|
@@ -315,7 +332,7 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
id: pointId,
|
|
|
vector: embeddings[index],
|
|
|
payload: {
|
|
|
- filePath: generateRelativeFilePath(normalizedAbsolutePath),
|
|
|
+ filePath: generateRelativeFilePath(normalizedAbsolutePath, scanWorkspace),
|
|
|
codeChunk: block.content,
|
|
|
startLine: block.start_line,
|
|
|
endLine: block.end_line,
|
|
|
@@ -335,7 +352,10 @@ export class DirectoryScanner implements IDirectoryScanner {
|
|
|
success = true
|
|
|
} catch (error) {
|
|
|
lastError = error as Error
|
|
|
- console.error(`[DirectoryScanner] Error processing batch (attempt ${attempts}):`, error)
|
|
|
+ console.error(
|
|
|
+ `[DirectoryScanner] Error processing batch (attempt ${attempts}) in workspace ${scanWorkspace}:`,
|
|
|
+ error,
|
|
|
+ )
|
|
|
|
|
|
if (attempts < MAX_BATCH_RETRIES) {
|
|
|
const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempts - 1)
|