(
workspaceId: string,
query: string,
limit = 20
)
| 8468 | } |
| 8469 | |
| 8470 | async getFileCompletions( |
| 8471 | workspaceId: string, |
| 8472 | query: string, |
| 8473 | limit = 20 |
| 8474 | ): Promise<{ paths: string[] }> { |
| 8475 | assert(workspaceId, "workspaceId is required"); |
| 8476 | assert(typeof query === "string", "query must be a string"); |
| 8477 | |
| 8478 | const resolvedLimit = Math.min(Math.max(1, Math.trunc(limit)), 50); |
| 8479 | |
| 8480 | const metadata = await this.getInfo(workspaceId); |
| 8481 | if (!metadata) { |
| 8482 | return { paths: [] }; |
| 8483 | } |
| 8484 | |
| 8485 | const now = Date.now(); |
| 8486 | const CACHE_TTL_MS = 10_000; |
| 8487 | |
| 8488 | let cached = this.fileCompletionsCache.get(workspaceId); |
| 8489 | if (!cached) { |
| 8490 | cached = { index: EMPTY_FILE_COMPLETIONS_INDEX, fetchedAt: 0 }; |
| 8491 | this.fileCompletionsCache.set(workspaceId, cached); |
| 8492 | } |
| 8493 | |
| 8494 | const cacheEntry = cached; |
| 8495 | |
| 8496 | const isStale = cacheEntry.fetchedAt === 0 || now - cacheEntry.fetchedAt > CACHE_TTL_MS; |
| 8497 | if (isStale && !cacheEntry.refreshing) { |
| 8498 | cacheEntry.refreshing = (async () => { |
| 8499 | const previousIndex = cacheEntry.index; |
| 8500 | |
| 8501 | try { |
| 8502 | const workspace = this.config.findWorkspace(workspaceId); |
| 8503 | const files = await this.listWorkspacePathsForFileCompletions( |
| 8504 | metadata, |
| 8505 | workspace?.workspacePath |
| 8506 | ); |
| 8507 | cacheEntry.index = files === null ? previousIndex : buildFileCompletionsIndex(files); |
| 8508 | cacheEntry.fetchedAt = Date.now(); |
| 8509 | } catch (error) { |
| 8510 | log.debug("getFileCompletions: failed to list files", { |
| 8511 | workspaceId, |
| 8512 | error: getErrorMessage(error), |
| 8513 | }); |
| 8514 | |
| 8515 | // Keep any previously indexed data, but avoid retrying in a tight loop. |
| 8516 | cacheEntry.index = previousIndex; |
| 8517 | cacheEntry.fetchedAt = Date.now(); |
| 8518 | } |
| 8519 | })().finally(() => { |
| 8520 | cacheEntry.refreshing = undefined; |
| 8521 | }); |
| 8522 | } |
| 8523 | |
| 8524 | if (cacheEntry.fetchedAt === 0 && cacheEntry.refreshing) { |
| 8525 | await cacheEntry.refreshing; |
| 8526 | } |
| 8527 |
nothing calls this directly
no test coverage detected