nub/internal/tool/builtin/glob.go
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

83 lines
1.8 KiB
Go

package builtin
import (
"context"
"encoding/json"
"fmt"
"io/fs"
"os"
"sort"
"github.com/bmatcuk/doublestar/v4"
"nub/internal/tool"
)
type GlobTool struct{}
func (GlobTool) Name() string { return "glob" }
func (GlobTool) Description() string {
return "Findet Dateien per Glob-Pattern, .gitignore respektiert, nach mtime absteigend sortiert."
}
func (GlobTool) Schema() json.RawMessage {
return json.RawMessage(`{
"type": "object",
"properties": {
"pattern": {"type": "string", "description": "doublestar-Pattern, z.B. **/*.go"}
},
"required": ["pattern"]
}`)
}
type globInput struct {
Pattern string `json:"pattern"`
}
func (GlobTool) Run(ctx context.Context, input json.RawMessage, env tool.Env) (tool.Result, error) {
var in globInput
if err := json.Unmarshal(input, &in); err != nil {
return tool.Result{ForModel: "invalid input: " + err.Error(), IsError: true}, nil
}
ignore := loadGitignore(env.RepoRoot)
type match struct {
path string
mtime int64
}
var matches []match
err := doublestar.GlobWalk(os.DirFS(env.RepoRoot), in.Pattern, func(path string, d fs.DirEntry) error {
if d.IsDir() || ignore.match(path) {
return nil
}
info, err := d.Info()
if err != nil {
return nil
}
matches = append(matches, match{path: path, mtime: info.ModTime().Unix()})
return nil
})
if err != nil {
return tool.Result{ForModel: fmt.Sprintf("glob %s: %v", in.Pattern, err), IsError: true}, nil
}
sort.Slice(matches, func(i, j int) bool { return matches[i].mtime > matches[j].mtime })
paths := make([]string, len(matches))
out := ""
for i, m := range matches {
paths[i] = m.path
out += m.path + "\n"
}
if len(matches) == 0 {
out = fmt.Sprintf("no matches for %s", in.Pattern)
}
return tool.Result{ForModel: out, ForUI: GlobResult{Paths: paths}}, nil
}
type GlobResult struct {
Paths []string
}