Skip to content

Commit 61d0234

Browse files
committed
Adding the grep search tool and file search tool.
1. Implemented the grep search tool using https://github.com/microsoft/vscode-ripgrep. 2. The grepped result show as clickable file path. 3. Implemented the file search tool. 3. The tool currently is disable in current pr, once grepSearch tool tested, will update the tool_index.json to enable this tool.
1 parent 5825d42 commit 61d0234

File tree

15 files changed

+1188
-9
lines changed

15 files changed

+1188
-9
lines changed

.github/workflows/node.js.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ jobs:
132132
NODE_OPTIONS: '--max-old-space-size=8192'
133133
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
134134
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
135+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
135136
steps:
136137
- uses: actions/checkout@v4
137138
- name: Use Node.js ${{ matrix.node-version }}
@@ -169,6 +170,7 @@ jobs:
169170
NODE_OPTIONS: '--max-old-space-size=8192'
170171
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
171172
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
173+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
172174
steps:
173175
- uses: actions/checkout@v4
174176
- name: Use Node.js ${{ matrix.node-version }}

buildspec/linuxTests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ phases:
2525
pre_build:
2626
commands:
2727
- export HOME=/home/codebuild-user
28+
# produce an API key, set the GITHUB_TOKEN environment var, and vscode-ripgrep will pick it up
29+
- export GITHUB_TOKEN=${GITHUB_READONLY_TOKEN}
2830
- bash buildspec/shared/linux-pre_build.sh
2931

3032
build:

buildspec/packageTestVsix.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ phases:
2020
pre_build:
2121
commands:
2222
- export HOME=/home/codebuild-user
23+
- export GITHUB_TOKEN=${GITHUB_READONLY_TOKEN}
2324
- bash buildspec/shared/linux-pre_build.sh
2425

2526
build:

buildspec/shared/linux-pre_build.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ _SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
1111
# Include common functions.
1212
. "${_SCRIPT_DIR}/common.sh"
1313

14+
# Set up GitHub token for vscode-ripgrep to avoid rate limiting
15+
if [ -n "$GITHUB_TOKEN" ]; then
16+
echo "GITHUB_TOKEN is set. vscode-ripgrep will use this for GitHub API authentication."
17+
else
18+
echo "WARNING: GITHUB_TOKEN is not set. GitHub API requests may be rate-limited."
19+
fi
20+
1421
# If present, log into CodeArtifact. Provides a fallback in case NPM is down.
1522
# Should only affect tests run through Toolkits-hosted CodeBuild.
1623
if [ "$TOOLKITS_CODEARTIFACT_DOMAIN" ] && [ "$TOOLKITS_CODEARTIFACT_REPO" ] && [ "$TOOLKITS_ACCOUNT_ID" ]; then

package-lock.json

Lines changed: 35 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
"dependencies": {
7676
"@types/node": "^22.7.5",
7777
"vscode-nls": "^5.2.0",
78-
"vscode-nls-dev": "^4.0.4"
78+
"vscode-nls-dev": "^4.0.4",
79+
"@vscode/ripgrep": "1.15.11"
7980
}
8081
}

packages/amazonq/scripts/build/copyFiles.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ const tasks: CopyTask[] = [
6060
target: path.join('../../node_modules', 'web-tree-sitter', 'tree-sitter.wasm'),
6161
destination: path.join('src', 'tree-sitter.wasm'),
6262
},
63+
// ripgrep binary
64+
{
65+
target: path.join('../../node_modules', '@vscode/ripgrep', 'bin'),
66+
destination: 'bin/',
67+
},
6368
]
6469

6570
function copy(task: CopyTask): void {
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import * as vscode from 'vscode'
6+
import { getLogger } from '../../shared/logger/logger'
7+
import { readDirectoryRecursively } from '../../shared/utilities/workspaceUtils'
8+
import fs from '../../shared/fs/fs'
9+
import { Writable } from 'stream'
10+
import path from 'path'
11+
import { InvokeOutput, OutputKind, sanitizePath, CommandValidation } from './toolShared'
12+
import { isInDirectory } from '../../shared/filesystemUtilities'
13+
14+
export interface FileSearchParams {
15+
path: string
16+
pattern: string
17+
maxDepth?: number
18+
caseSensitive?: boolean
19+
}
20+
21+
export class FileSearch {
22+
private fsPath: string
23+
private pattern: RegExp
24+
private maxDepth?: number
25+
private readonly logger = getLogger('fileSearch')
26+
27+
constructor(params: FileSearchParams) {
28+
this.fsPath = params.path
29+
// Create RegExp with case sensitivity option
30+
this.pattern = new RegExp(params.pattern, params.caseSensitive ? '' : 'i')
31+
this.maxDepth = params.maxDepth
32+
}
33+
34+
public async validate(): Promise<void> {
35+
if (!this.fsPath || this.fsPath.trim().length === 0) {
36+
throw new Error('Path cannot be empty.')
37+
}
38+
if (this.maxDepth !== undefined && this.maxDepth < 0) {
39+
throw new Error('MaxDepth cannot be negative.')
40+
}
41+
42+
const sanitized = sanitizePath(this.fsPath)
43+
this.fsPath = sanitized
44+
45+
const pathUri = vscode.Uri.file(this.fsPath)
46+
let pathExists: boolean
47+
try {
48+
pathExists = await fs.existsDir(pathUri)
49+
if (!pathExists) {
50+
throw new Error(`Path: "${this.fsPath}" does not exist or cannot be accessed.`)
51+
}
52+
} catch (err) {
53+
throw new Error(`Path: "${this.fsPath}" does not exist or cannot be accessed. (${err})`)
54+
}
55+
}
56+
57+
public queueDescription(updates: Writable): void {
58+
const fileName = path.basename(this.fsPath)
59+
if (this.maxDepth === undefined) {
60+
updates.write(`Searching for files matching pattern: ${this.pattern} in ${fileName} recursively`)
61+
} else if (this.maxDepth === 0) {
62+
updates.write(`Searching for files matching pattern: ${this.pattern} in ${fileName}`)
63+
} else {
64+
const level = this.maxDepth > 1 ? 'levels' : 'level'
65+
updates.write(
66+
`Searching for files matching pattern: ${this.pattern} in ${fileName} limited to ${this.maxDepth} subfolder ${level}`
67+
)
68+
}
69+
updates.end()
70+
}
71+
72+
public requiresAcceptance(): CommandValidation {
73+
const workspaceFolders = vscode.workspace.workspaceFolders
74+
if (!workspaceFolders || workspaceFolders.length === 0) {
75+
return { requiresAcceptance: true }
76+
}
77+
const isInWorkspace = workspaceFolders.some((folder) => isInDirectory(folder.uri.fsPath, this.fsPath))
78+
if (!isInWorkspace) {
79+
return { requiresAcceptance: true }
80+
}
81+
return { requiresAcceptance: false }
82+
}
83+
84+
public async invoke(updates?: Writable): Promise<InvokeOutput> {
85+
try {
86+
const fileUri = vscode.Uri.file(this.fsPath)
87+
const allFiles = await readDirectoryRecursively(fileUri, this.maxDepth)
88+
89+
// Filter files by regex pattern
90+
const matchedFiles = allFiles.filter((filePath) => {
91+
// Extract just the filename from the path
92+
const fileName = path.basename(filePath.split(' ').slice(1).join(' '))
93+
return this.pattern.test(fileName)
94+
})
95+
96+
return this.createOutput(matchedFiles.join('\n'))
97+
} catch (error: any) {
98+
this.logger.error(`Failed to search files in "${this.fsPath}": ${error.message || error}`)
99+
throw new Error(`Failed to search files in "${this.fsPath}": ${error.message || error}`)
100+
}
101+
}
102+
103+
private createOutput(content: string): InvokeOutput {
104+
return {
105+
output: {
106+
kind: OutputKind.Text,
107+
content: content,
108+
},
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)