Skip to content

Commit 5cac18a

Browse files
committed
env: use alpine and ripgrep + update tool descriptions
Signed-off-by: Tibor Vass <teabee89@gmail.com>
1 parent 451c470 commit 5cac18a

File tree

3 files changed

+22
-18
lines changed

3 files changed

+22
-18
lines changed

cmd/cu/stdio.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var stdioCmd = &cobra.Command{
3939

4040
func warmCache(ctx context.Context, dag *dagger.Client) {
4141
environment.EditUtil(dag).Sync(ctx)
42+
environment.GrepUtil(dag).Sync(ctx)
4243
}
4344

4445
func init() {

environment/filesystem.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@ import (
77
"strings"
88

99
"dagger.io/dagger"
10-
"dagger.io/dagger/dag"
1110
"github.com/dagger/container-use/edit"
1211
)
1312

14-
// FIXME: See hack where it's used
15-
const fileUtilsBaseImage = "busybox"
16-
1713
func (env *Environment) FileRead(ctx context.Context, targetFile string, shouldReadEntireFile bool, startLineOneIndexed int, endLineOneIndexedInclusive int) (string, error) {
1814
file, err := env.container().File(targetFile).Contents(ctx)
1915
if err != nil {
@@ -81,42 +77,47 @@ func (env *Environment) ls(ctx context.Context, path string, filter dagger.Direc
8177

8278
func (env *Environment) FileGrep(ctx context.Context, path, pattern, include string) (string, error) {
8379
// Hack: use busybox to run `sed` since dagger doesn't have native file editing primitives.
84-
args := []string{"/bin/grep", "-E", "--", pattern, include}
80+
args := []string{"/usr/bin/rg", "--no-unicode", "-g", include, "--", pattern, path}
8581

8682
dir := env.container().Rootfs().Directory(path)
87-
out, err := dag.Container().From(fileUtilsBaseImage).WithMountedDirectory("/mnt", dir).WithWorkdir("/mnt").WithExec(args).Stdout(ctx)
83+
out, err := GrepUtil(env.dag).WithMountedDirectory("/mnt", dir).WithWorkdir("/mnt").WithExec(args).Stdout(ctx)
8884
if err != nil {
8985
return "", err
9086
}
9187
return out, nil
9288
}
9389

9490
type FileEdit struct {
95-
Old string
96-
New string
91+
OldString string
92+
NewString string
9793
ReplaceAll bool
9894
}
9995

10096
func EditUtil(dag *dagger.Client) *dagger.Container {
101-
editBin := dag.Container().From("golang:alpine").
97+
editBin := dag.Container().From(alpineImage).
98+
WithExec([]string{"apk", "add", "-U", "go"}).
10299
WithNewFile("/edit.go", edit.Src).
103100
WithEnvVariable("CGO_ENABLED", "0").
104101
WithExec([]string{"go", "build", "-o", "/edit", "-ldflags", "-w -s", "/edit.go"}).File("/edit")
105102
return dag.Container().From("scratch").WithFile("/edit", editBin).WithEntrypoint([]string{"/edit"})
106103
}
107104

108-
func (env *Environment) FileEdit(ctx context.Context, dag *dagger.Client, targetFile string, edits []FileEdit) error {
105+
func GrepUtil(dag *dagger.Client) *dagger.Container {
106+
return dag.Container().From(alpineImage).WithExec([]string{"apk", "add", "-U", "ripgrep"})
107+
}
108+
109+
func (env *Environment) FileEdit(ctx context.Context, targetFile string, edits []FileEdit) error {
109110
// Hack: use busybox to run `sed` since dagger doesn't have native file editing primitives.
110111
args := []string{"/edit", "/target", "/new"}
111112
for _, edit := range edits {
112113
replaceCount := "1"
113114
if edit.ReplaceAll {
114115
replaceCount = "-1"
115116
}
116-
args = append(args, edit.Old, edit.New, replaceCount)
117+
args = append(args, edit.OldString, edit.NewString, replaceCount)
117118
}
118119

119-
newFile := EditUtil(dag).WithMountedFile("/target", env.container().File(targetFile)).WithExec(args).File("/new")
120+
newFile := EditUtil(env.dag).WithMountedFile("/target", env.container().File(targetFile)).WithExec(args).File("/new")
120121
err := env.apply(ctx, env.container().WithFile(targetFile, newFile))
121122
if err != nil {
122123
return fmt.Errorf("failed applying file edit, skipping git propagation: %w", err)

mcpserver/tools.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ var EnvironmentFileGrepTool = &Tool{
732732

733733
var EnvironmentFileEditTool = &Tool{
734734
Definition: mcp.NewTool("environment_file_edit",
735-
mcp.WithDescription("Efficiently edit the contents of a file."),
735+
mcp.WithDescription("This is a tool for making single or multiple edits to a single file in one operation. It allows you to perform multiple find-and-replace operations efficiently.\n\nBefore using this tool:\n\n1. Use the Read tool to understand the file's contents and context\n2. Verify the directory path is correct\n\nTo make file edits, provide the following:\n1. file_path: The absolute path to the file to modify (must be absolute, not relative)\n2. edits: An array of edit operations to perform, where each edit contains:\n - old_string: The text to replace (must match the file contents exactly, including all whitespace and indentation)\n - new_string: The edited text to replace the old_string\n - replace_all: Replace all occurences of old_string. This parameter is optional and defaults to false.\n\nIMPORTANT:\n- All edits are applied in sequence, in the order they are provided\n- Each edit operates on the result of the previous edit\n- All edits must be valid for the operation to succeed - if any edit fails, none will be applied\n- This tool is ideal when you need to make several changes to different parts of the same file\n- For Jupyter notebooks (.ipynb files), use the NotebookEdit instead\n\nCRITICAL REQUIREMENTS:\n1. All edits follow the same requirements as the single Edit tool\n2. The edits are atomic - either all succeed or none are applied\n3. Plan your edits carefully to avoid conflicts between sequential operations\n\nWARNING:\n- The tool will fail if edits.old_string doesn't match the file contents exactly (including whitespace)\n- The tool will fail if edits.old_string and edits.new_string are the same\n- Since edits are applied in sequence, ensure that earlier edits don't affect the text that later edits are trying to find\n\nWhen making edits:\n- Ensure all edits result in idiomatic, correct code\n- Do not leave the code in a broken state\n- Always use absolute file paths (starting with /)\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.\n\nIf you want to create a new file, use:\n- A new file path, including dir name if needed\n- First edit: empty old_string and the new file's contents as new_string\n- Subsequent edits: normal edit operations on the created content"),
736736
mcp.WithString("explanation",
737737
mcp.Description("One sentence explanation for why this file is being edited."),
738738
),
@@ -749,8 +749,12 @@ var EnvironmentFileEditTool = &Tool{
749749
mcp.Required(),
750750
),
751751
mcp.WithArray("edits",
752-
mcp.Description("Array of sed search-replace operations to perform on the contents of target_file (e.g. \"s/old/new/g\").\nUses extended regex syntax."),
753-
mcp.Items(map[string]any{"type": "string"}),
752+
mcp.Description("An array of edit operations to perform on the contents of target_file."),
753+
mcp.Items(map[string]any{"type": "object", "properties": map[string]any{
754+
"old_string": map[string]any{"type": "string", "description": "The text to replace"},
755+
"new_string": map[string]any{"type": "string", "description": "The text to replace it with"},
756+
"replace_all": map[string]any{"type": "string", "description": "Replace all occurences of old_string (default false)", "default": false},
757+
}}),
754758
mcp.MinItems(1),
755759
mcp.Required(),
756760
),
@@ -761,8 +765,6 @@ var EnvironmentFileEditTool = &Tool{
761765
return mcp.NewToolResultErrorFromErr("unable to open the environment", err), nil
762766
}
763767

764-
dag, _ := ctx.Value(daggerClientKey{}).(*dagger.Client)
765-
766768
var args struct {
767769
TargetFile string
768770
Edits []environment.FileEdit
@@ -771,7 +773,7 @@ var EnvironmentFileEditTool = &Tool{
771773
return nil, fmt.Errorf("could not bind arguments")
772774
}
773775

774-
if err := env.FileEdit(ctx, dag, args.TargetFile, args.Edits); err != nil {
776+
if err := env.FileEdit(ctx, args.TargetFile, args.Edits); err != nil {
775777
return mcp.NewToolResultErrorFromErr("failed to edit file", err), nil
776778
}
777779

0 commit comments

Comments
 (0)