-
Notifications
You must be signed in to change notification settings - Fork 747
feat(chat): Adding the grep search tool and file search tool #7083
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ env: | |
| AWS_TOOLKIT_TEST_USER_DIR: '/tmp/' | ||
| # needed or else webpack will cause it to run out of memory | ||
| NODE_OPTIONS: '--max-old-space-size=8192' | ||
| # VSCODE_RIPGREP_TOKEN will be set in pre_build phase | ||
|
|
||
| phases: | ||
| install: | ||
|
|
@@ -20,6 +21,9 @@ phases: | |
| pre_build: | ||
| commands: | ||
| - export HOME=/home/codebuild-user | ||
| # Set up VSCODE_RIPGREP_TOKEN for GitHub API access | ||
| - export VSCODE_RIPGREP_TOKEN=${GITHUB_READONLY_TOKEN} | ||
| - echo "Setting up VSCODE_RIPGREP_TOKEN for GitHub API access" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similar as the GITHUB TOKEN env, set it setting this up to increase GitHub API Limit while download the ripgrep binary. otherwise, the ripgrep download failed. |
||
| - bash buildspec/shared/linux-pre_build.sh | ||
|
|
||
| build: | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,6 +75,7 @@ | |
| "dependencies": { | ||
| "@types/node": "^22.7.5", | ||
| "vscode-nls": "^5.2.0", | ||
| "vscode-nls-dev": "^4.0.4" | ||
| "vscode-nls-dev": "^4.0.4", | ||
| "@vscode/ripgrep": "1.15.11" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this the right place to add it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, based on the vscode ripgrep, it asked to add in the dependencies, not dev dependencies: https://github.com/microsoft/vscode-ripgrep. |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| /*! | ||
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| import * as vscode from 'vscode' | ||
| import { getLogger } from '../../shared/logger/logger' | ||
| import { readDirectoryRecursively } from '../../shared/utilities/workspaceUtils' | ||
| import fs from '../../shared/fs/fs' | ||
| import { Writable } from 'stream' | ||
| import path from 'path' | ||
| import { InvokeOutput, OutputKind, sanitizePath, CommandValidation } from './toolShared' | ||
| import { isInDirectory } from '../../shared/filesystemUtilities' | ||
|
|
||
| export interface FileSearchParams { | ||
| path: string | ||
| pattern: string | ||
| maxDepth?: number | ||
| caseSensitive?: boolean | ||
| } | ||
|
|
||
| export class FileSearch { | ||
| private fsPath: string | ||
| private pattern: RegExp | ||
| private maxDepth?: number | ||
| private readonly logger = getLogger('fileSearch') | ||
|
|
||
| constructor(params: FileSearchParams) { | ||
| this.fsPath = params.path | ||
| // Create RegExp with case sensitivity option | ||
| this.pattern = new RegExp(params.pattern, params.caseSensitive ? '' : 'i') | ||
| this.maxDepth = params.maxDepth | ||
| } | ||
|
|
||
| public async validate(): Promise<void> { | ||
| if (!this.fsPath || this.fsPath.trim().length === 0) { | ||
| throw new Error('Path cannot be empty.') | ||
| } | ||
| if (this.maxDepth !== undefined && this.maxDepth < 0) { | ||
| throw new Error('MaxDepth cannot be negative.') | ||
| } | ||
|
|
||
| const sanitized = sanitizePath(this.fsPath) | ||
| this.fsPath = sanitized | ||
|
|
||
| const pathUri = vscode.Uri.file(this.fsPath) | ||
| let pathExists: boolean | ||
| try { | ||
| pathExists = await fs.existsDir(pathUri) | ||
| if (!pathExists) { | ||
| throw new Error(`Path: "${this.fsPath}" does not exist or cannot be accessed.`) | ||
| } | ||
| } catch (err) { | ||
| throw new Error(`Path: "${this.fsPath}" does not exist or cannot be accessed. (${err})`) | ||
| } | ||
| } | ||
|
|
||
| public queueDescription(updates: Writable): void { | ||
| const fileName = path.basename(this.fsPath) | ||
| if (this.maxDepth === undefined) { | ||
| updates.write(`Searching for files matching pattern: ${this.pattern} in ${fileName} recursively`) | ||
| } else if (this.maxDepth === 0) { | ||
| updates.write(`Searching for files matching pattern: ${this.pattern} in ${fileName}`) | ||
| } else { | ||
| const level = this.maxDepth > 1 ? 'levels' : 'level' | ||
| updates.write( | ||
| `Searching for files matching pattern: ${this.pattern} in ${fileName} limited to ${this.maxDepth} subfolder ${level}` | ||
| ) | ||
| } | ||
| updates.end() | ||
| } | ||
|
|
||
| public requiresAcceptance(): CommandValidation { | ||
| const workspaceFolders = vscode.workspace.workspaceFolders | ||
| if (!workspaceFolders || workspaceFolders.length === 0) { | ||
| return { requiresAcceptance: true } | ||
| } | ||
| const isInWorkspace = workspaceFolders.some((folder) => isInDirectory(folder.uri.fsPath, this.fsPath)) | ||
| if (!isInWorkspace) { | ||
| return { requiresAcceptance: true } | ||
| } | ||
| return { requiresAcceptance: false } | ||
| } | ||
|
|
||
| public async invoke(updates?: Writable): Promise<InvokeOutput> { | ||
| try { | ||
| const fileUri = vscode.Uri.file(this.fsPath) | ||
| const allFiles = await readDirectoryRecursively(fileUri, this.maxDepth) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. filter to only keep |
||
|
|
||
| // Filter files by regex pattern | ||
| const matchedFiles = allFiles.filter((filePath) => { | ||
| // Extract just the filename from the path | ||
| const fileName = path.basename(filePath.split(' ').slice(1).join(' ')) | ||
| return this.pattern.test(fileName) | ||
| }) | ||
|
|
||
| return this.createOutput(matchedFiles.join('\n')) | ||
| } catch (error: any) { | ||
| this.logger.error(`Failed to search files in "${this.fsPath}": ${error.message || error}`) | ||
| throw new Error(`Failed to search files in "${this.fsPath}": ${error.message || error}`) | ||
| } | ||
| } | ||
|
|
||
| private createOutput(content: string): InvokeOutput { | ||
| return { | ||
| output: { | ||
| kind: OutputKind.Text, | ||
| content: content, | ||
| }, | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are setting this up to increase GitHub API Limit while download the ripgrep binary.
ref: https://github.com/microsoft/vscode-ripgrep