package builtin import ( "context" "encoding/json" "fmt" "os" "path/filepath" "nub/internal/tool" ) type WriteTool struct{} func (WriteTool) Name() string { return "write" } func (WriteTool) Description() string { return "Schreibt eine Datei vollständig (legt Parent-Dirs an)." } func (WriteTool) Schema() json.RawMessage { return json.RawMessage(`{ "type": "object", "properties": { "path": {"type": "string"}, "content": {"type": "string"} }, "required": ["path", "content"] }`) } type writeInput struct { Path string `json:"path"` Content string `json:"content"` } func (WriteTool) Run(ctx context.Context, input json.RawMessage, env tool.Env) (tool.Result, error) { var in writeInput if err := json.Unmarshal(input, &in); err != nil { return tool.Result{ForModel: "invalid input: " + err.Error(), IsError: true}, nil } path, err := resolvePath(env.RepoRoot, env.Cwd, in.Path) if err != nil { return tool.Result{ForModel: err.Error(), IsError: true}, nil } old, _ := os.ReadFile(path) // fehlt die Datei, ist old leer -> reiner Add-Diff if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return tool.Result{ForModel: fmt.Sprintf("write %s: %v", in.Path, err), IsError: true}, nil } if err := os.WriteFile(path, []byte(in.Content), 0o644); err != nil { return tool.Result{ForModel: fmt.Sprintf("write %s: %v", in.Path, err), IsError: true}, nil } return tool.Result{ ForModel: fmt.Sprintf("wrote %s (%d bytes)", in.Path, len(in.Content)), ForUI: DiffResult{Path: in.Path, Lines: lineDiff(string(old), in.Content)}, }, nil }