Skip to content

Commit b9be243

Browse files
committed
code_search: Include a few hidden dirs like .agents, .github
1 parent c91965e commit b9be243

File tree

1 file changed

+48
-12
lines changed

1 file changed

+48
-12
lines changed

sdk/src/tools/code-search.ts

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ import { getBundledRgPath } from '../native/ripgrep'
66

77
import type { CodebuffToolOutput } from '../../../common/src/tools/list'
88

9+
// Hidden directories to include in code search by default.
10+
// These are searched in addition to '.' to ensure important config/workflow files are discoverable.
11+
const INCLUDED_HIDDEN_DIRS = [
12+
'.agents', // Codebuff agent definitions
13+
'.claude', // Claude settings
14+
'.github', // GitHub Actions, workflows, issue templates
15+
'.gitlab', // GitLab CI configuration
16+
'.circleci', // CircleCI configuration
17+
'.husky', // Git hooks
18+
]
19+
920
export function codeSearch({
1021
projectPath,
1122
pattern,
@@ -31,9 +42,12 @@ export function codeSearch({
3142
// Guard paths robustly
3243
const projectRoot = path.resolve(projectPath)
3344
const searchCwd = cwd ? path.resolve(projectRoot, cwd) : projectRoot
34-
45+
3546
// Ensure the resolved path is within the project directory
36-
if (!searchCwd.startsWith(projectRoot + path.sep) && searchCwd !== projectRoot) {
47+
if (
48+
!searchCwd.startsWith(projectRoot + path.sep) &&
49+
searchCwd !== projectRoot
50+
) {
3751
return resolve([
3852
{
3953
type: 'json',
@@ -53,7 +67,17 @@ export function codeSearch({
5367
// -n shows line numbers
5468
// --json outputs in JSON format, which streams in and allows us to cut off the output if it grows too long
5569
// "--"" prevents pattern from being misparsed as a flag (e.g., pattern starting with '-')
56-
const args = ['--no-config', '-n', '--json', ...flagsArray, '--', pattern, '.']
70+
// Search paths: '.' plus blessed hidden directories (ripgrep ignores non-existent paths)
71+
const searchPaths = ['.', ...INCLUDED_HIDDEN_DIRS]
72+
const args = [
73+
'--no-config',
74+
'-n',
75+
'--json',
76+
...flagsArray,
77+
'--',
78+
pattern,
79+
...searchPaths,
80+
]
5781

5882
const rgPath = getBundledRgPath(import.meta.url)
5983
const childProcess = spawn(rgPath, args, {
@@ -126,7 +150,8 @@ export function codeSearch({
126150
// Parse ripgrep JSON for early stopping
127151
childProcess.stdout.on('data', (chunk: Buffer | string) => {
128152
if (isResolved) return
129-
const chunkStr = typeof chunk === 'string' ? chunk : chunk.toString('utf8')
153+
const chunkStr =
154+
typeof chunk === 'string' ? chunk : chunk.toString('utf8')
130155
jsonRemainder += chunkStr
131156

132157
// Split by lines; last line might be partial
@@ -181,7 +206,10 @@ export function codeSearch({
181206
matchesGlobal++
182207

183208
// Check global limit or output size limit
184-
if (matchesGlobal >= globalMaxResults || estimatedOutputLen >= maxOutputStringLength) {
209+
if (
210+
matchesGlobal >= globalMaxResults ||
211+
estimatedOutputLen >= maxOutputStringLength
212+
) {
185213
killedForLimit = true
186214
hardKill()
187215

@@ -199,9 +227,10 @@ export function codeSearch({
199227
'\n\n[Output truncated]'
200228
: formattedOutput
201229

202-
const limitReason = matchesGlobal >= globalMaxResults
203-
? `[Global limit of ${globalMaxResults} results reached.]`
204-
: '[Output size limit reached.]'
230+
const limitReason =
231+
matchesGlobal >= globalMaxResults
232+
? `[Global limit of ${globalMaxResults} results reached.]`
233+
: '[Output size limit reached.]'
205234

206235
return settle({
207236
stdout: finalOutput + '\n\n' + limitReason,
@@ -216,7 +245,8 @@ export function codeSearch({
216245

217246
childProcess.stderr.on('data', (chunk: Buffer | string) => {
218247
if (isResolved) return
219-
const chunkStr = typeof chunk === 'string' ? chunk : chunk.toString('utf8')
248+
const chunkStr =
249+
typeof chunk === 'string' ? chunk : chunk.toString('utf8')
220250
// Keep stderr bounded during streaming
221251
const limit = Math.floor(maxOutputStringLength / 5)
222252
if (stderrBuf.length < limit) {
@@ -232,13 +262,16 @@ export function codeSearch({
232262
try {
233263
if (jsonRemainder) {
234264
// Ensure we have a trailing newline for split to work correctly
235-
const maybeMany = jsonRemainder.endsWith('\n') ? jsonRemainder : jsonRemainder + '\n'
265+
const maybeMany = jsonRemainder.endsWith('\n')
266+
? jsonRemainder
267+
: jsonRemainder + '\n'
236268
for (const ln of maybeMany.split('\n')) {
237269
if (!ln) continue
238270
try {
239271
const evt = JSON.parse(ln)
240272
if (evt?.type === 'match' || evt?.type === 'context') {
241-
const filePath = evt.data.path?.text ?? evt.data.path?.bytes ?? ''
273+
const filePath =
274+
evt.data.path?.text ?? evt.data.path?.bytes ?? ''
242275
const lineNumber = evt.data.line_number ?? 0
243276
const rawText = evt.data.lines?.text ?? ''
244277
const lineText = rawText.replace(/\r?\n$/, '')
@@ -253,7 +286,10 @@ export function codeSearch({
253286
const isMatch = evt.type === 'match'
254287

255288
// Check if we should include this line
256-
const shouldInclude = !isMatch || (fileMatchCount < maxResults && matchesGlobal < globalMaxResults)
289+
const shouldInclude =
290+
!isMatch ||
291+
(fileMatchCount < maxResults &&
292+
matchesGlobal < globalMaxResults)
257293

258294
if (shouldInclude) {
259295
fileLines.push(formattedLine)

0 commit comments

Comments
 (0)