2025-10-26 19:50:41 +00:00
import z from "zod"
2025-06-04 17:12:13 +00:00
import path from "path"
2025-05-31 18:41:00 +00:00
import { Tool } from "./tool"
2025-06-04 17:12:13 +00:00
import DESCRIPTION from "./glob.txt"
2025-06-30 18:46:18 +00:00
import { Ripgrep } from "../file/ripgrep"
2025-09-01 21:15:49 +00:00
import { Instance } from "../project/instance"
2025-05-21 14:30:39 +00:00
2025-07-25 17:29:29 +00:00
export const GlobTool = Tool . define ( "glob" , {
2025-05-21 14:30:39 +00:00
description : DESCRIPTION ,
parameters : z.object ( {
pattern : z.string ( ) . describe ( "The glob pattern to match files against" ) ,
path : z
. string ( )
2025-06-17 15:27:07 +00:00
. optional ( )
2025-05-21 14:30:39 +00:00
. describe (
2025-06-04 17:12:13 +00:00
` The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided. ` ,
2025-06-10 00:24:18 +00:00
) ,
2025-05-21 14:30:39 +00:00
} ) ,
2026-01-01 22:54:11 +00:00
async execute ( params , ctx ) {
await ctx . ask ( {
permission : "glob" ,
patterns : [ params . pattern ] ,
always : [ "*" ] ,
metadata : {
pattern : params.pattern ,
path : params.path ,
} ,
} )
2025-09-01 21:15:49 +00:00
let search = params . path ? ? Instance . directory
search = path . isAbsolute ( search ) ? search : path.resolve ( Instance . directory , search )
2025-06-04 17:12:13 +00:00
2025-05-31 18:41:00 +00:00
const limit = 100
const files = [ ]
let truncated = false
2025-10-01 07:37:01 +00:00
for await ( const file of Ripgrep . files ( {
2025-06-23 21:37:32 +00:00
cwd : search ,
2025-07-08 22:14:24 +00:00
glob : [ params . pattern ] ,
2025-06-23 21:37:32 +00:00
} ) ) {
2025-05-21 14:30:39 +00:00
if ( files . length >= limit ) {
2025-05-31 18:41:00 +00:00
truncated = true
break
2025-05-21 14:30:39 +00:00
}
2025-06-04 17:12:13 +00:00
const full = path . resolve ( search , file )
const stats = await Bun . file ( full )
2025-05-21 14:30:39 +00:00
. stat ( )
. then ( ( x ) = > x . mtime . getTime ( ) )
2025-05-31 18:41:00 +00:00
. catch ( ( ) = > 0 )
2025-05-21 14:30:39 +00:00
files . push ( {
2025-06-04 17:12:13 +00:00
path : full ,
2025-05-21 14:30:39 +00:00
mtime : stats ,
2025-05-31 18:41:00 +00:00
} )
2025-05-21 14:30:39 +00:00
}
2025-05-31 18:41:00 +00:00
files . sort ( ( a , b ) = > b . mtime - a . mtime )
2025-05-21 14:30:39 +00:00
2025-05-31 18:41:00 +00:00
const output = [ ]
if ( files . length === 0 ) output . push ( "No files found" )
2025-05-21 14:30:39 +00:00
if ( files . length > 0 ) {
2025-05-31 18:41:00 +00:00
output . push ( . . . files . map ( ( f ) = > f . path ) )
2025-05-21 14:30:39 +00:00
if ( truncated ) {
2025-05-31 18:41:00 +00:00
output . push ( "" )
2025-07-07 19:53:43 +00:00
output . push ( "(Results are truncated. Consider using a more specific path or pattern.)" )
2025-05-21 14:30:39 +00:00
}
}
return {
2025-09-01 21:15:49 +00:00
title : path.relative ( Instance . worktree , search ) ,
2025-05-21 14:30:39 +00:00
metadata : {
count : files.length ,
truncated ,
} ,
output : output.join ( "\n" ) ,
2025-05-31 18:41:00 +00:00
}
2025-05-21 14:30:39 +00:00
} ,
2025-05-31 18:41:00 +00:00
} )