Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ jobs:
NODE_OPTIONS: '--max-old-space-size=8192'
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Copy link
Contributor

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?

Copy link
Contributor Author

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

You can produce an API key, set the GITHUB_TOKEN environment var to it, and vscode-ripgrep will use it when downloading from GitHub. This increases your API limit.
  1. Without this the most CI test will fail during download ripegrep binary.

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
Expand Down Expand Up @@ -169,6 +170,7 @@ jobs:
NODE_OPTIONS: '--max-old-space-size=8192'
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
1 change: 1 addition & 0 deletions buildspec/linuxTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ env:
# followed by Error: Could not delete obsolete instance handle Error: ENOENT: no such file or directory, unlink <path>
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
VSCODE_RIPGREP_TOKEN: ${GITHUB_READONLY_TOKEN}

phases:
install:
Expand Down
4 changes: 4 additions & 0 deletions buildspec/packageTestVsix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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"
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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:
Expand Down
41 changes: 35 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the right place to add it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

}
}
5 changes: 5 additions & 0 deletions packages/amazonq/scripts/build/copyFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ const tasks: CopyTask[] = [
target: path.join('../../node_modules', 'web-tree-sitter', 'tree-sitter.wasm'),
destination: path.join('src', 'tree-sitter.wasm'),
},
// ripgrep binary
{
target: path.join('../../node_modules', '@vscode/ripgrep', 'bin'),
destination: 'bin/',
},
]

function copy(task: CopyTask): void {
Expand Down
111 changes: 111 additions & 0 deletions packages/core/src/codewhispererChat/tools/fileSearch.ts
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter to only keep [F] prefix?


// 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,
},
}
}
}
Loading
Loading