summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/chain.go131
-rw-r--r--tools/tools.go8
2 files changed, 109 insertions, 30 deletions
diff --git a/tools/chain.go b/tools/chain.go
index 8a79eda..381cc1a 100644
--- a/tools/chain.go
+++ b/tools/chain.go
@@ -150,7 +150,7 @@ func execSingle(command, stdin string) (string, error) {
name := parts[0]
args := parts[1:]
// Check if it's a built-in Go command
- if result := execBuiltin(name, args, stdin); result != "" {
+ if result, isBuiltin := execBuiltin(name, args, stdin); isBuiltin {
return result, nil
}
// Otherwise execute as system command
@@ -201,21 +201,23 @@ func tokenize(input string) []string {
}
// execBuiltin executes a built-in command if it exists.
-func execBuiltin(name string, args []string, stdin string) string {
+// Returns (result, true) if it was a built-in (even if result is empty).
+// Returns ("", false) if it's not a built-in command.
+func execBuiltin(name string, args []string, stdin string) (string, bool) {
switch name {
case "echo":
if stdin != "" {
- return stdin
+ return stdin, true
}
- return strings.Join(args, " ")
+ return strings.Join(args, " "), true
case "time":
- return "2006-01-02 15:04:05 MST"
+ return "2006-01-02 15:04:05 MST", true
case "cat":
if len(args) == 0 {
if stdin != "" {
- return stdin
+ return stdin, true
}
- return ""
+ return "", true
}
path := args[0]
abs := path
@@ -224,14 +226,14 @@ func execBuiltin(name string, args []string, stdin string) string {
}
data, err := os.ReadFile(abs)
if err != nil {
- return fmt.Sprintf("[error] cat: %v", err)
+ return fmt.Sprintf("[error] cat: %v", err), true
}
- return string(data)
+ return string(data), true
case "pwd":
- return cfg.FilePickerDir
+ return cfg.FilePickerDir, true
case "cd":
if len(args) == 0 {
- return "[error] usage: cd <dir>"
+ return "[error] usage: cd <dir>", true
}
dir := args[0]
// Resolve relative to cfg.FilePickerDir
@@ -242,16 +244,16 @@ func execBuiltin(name string, args []string, stdin string) string {
abs = filepath.Clean(abs)
info, err := os.Stat(abs)
if err != nil {
- return fmt.Sprintf("[error] cd: %v", err)
+ return fmt.Sprintf("[error] cd: %v", err), true
}
if !info.IsDir() {
- return "[error] cd: not a directory: " + dir
+ return "[error] cd: not a directory: " + dir, true
}
cfg.FilePickerDir = abs
- return "Changed directory to: " + cfg.FilePickerDir
+ return "Changed directory to: " + cfg.FilePickerDir, true
case "mkdir":
if len(args) == 0 {
- return "[error] usage: mkdir [-p] <dir>"
+ return "[error] usage: mkdir [-p] <dir>", true
}
createParents := false
var dirPath string
@@ -263,7 +265,7 @@ func execBuiltin(name string, args []string, stdin string) string {
}
}
if dirPath == "" {
- return "[error] usage: mkdir [-p] <dir>"
+ return "[error] usage: mkdir [-p] <dir>", true
}
abs := dirPath
if !filepath.IsAbs(dirPath) {
@@ -277,12 +279,12 @@ func execBuiltin(name string, args []string, stdin string) string {
mkdirFunc = os.Mkdir
}
if err := mkdirFunc(abs, 0o755); err != nil {
- return fmt.Sprintf("[error] mkdir: %v", err)
+ return fmt.Sprintf("[error] mkdir: %v", err), true
}
if createParents {
- return "Created " + dirPath + " (with parents)"
+ return "Created " + dirPath + " (with parents)", true
}
- return "Created " + dirPath
+ return "Created " + dirPath, true
case "ls":
dir := "."
for _, a := range args {
@@ -297,7 +299,7 @@ func execBuiltin(name string, args []string, stdin string) string {
}
entries, err := os.ReadDir(abs)
if err != nil {
- return fmt.Sprintf("[error] ls: %v", err)
+ return fmt.Sprintf("[error] ls: %v", err), true
}
var out strings.Builder
for _, e := range entries {
@@ -317,21 +319,98 @@ func execBuiltin(name string, args []string, stdin string) string {
}
}
if out.Len() == 0 {
- return "(empty directory)"
+ return "(empty directory)", true
}
- return strings.TrimRight(out.String(), "\n")
+ return strings.TrimRight(out.String(), "\n"), true
case "go":
// Allow all go subcommands
if len(args) == 0 {
- return "[error] usage: go <subcommand> [options]"
+ return "[error] usage: go <subcommand> [options]", true
}
cmd := exec.Command("go", args...)
cmd.Dir = cfg.FilePickerDir
output, err := cmd.CombinedOutput()
if err != nil {
- return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output))
+ return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output)), true
}
- return string(output)
+ return string(output), true
+ case "cp":
+ if len(args) < 2 {
+ return "[error] usage: cp <source> <dest>", true
+ }
+ src := args[0]
+ dst := args[1]
+ if !filepath.IsAbs(src) {
+ src = filepath.Join(cfg.FilePickerDir, src)
+ }
+ if !filepath.IsAbs(dst) {
+ dst = filepath.Join(cfg.FilePickerDir, dst)
+ }
+ data, err := os.ReadFile(src)
+ if err != nil {
+ return fmt.Sprintf("[error] cp: %v", err), true
+ }
+ err = os.WriteFile(dst, data, 0644)
+ if err != nil {
+ return fmt.Sprintf("[error] cp: %v", err), true
+ }
+ return "Copied " + src + " to " + dst, true
+ case "mv":
+ if len(args) < 2 {
+ return "[error] usage: mv <source> <dest>", true
+ }
+ src := args[0]
+ dst := args[1]
+ if !filepath.IsAbs(src) {
+ src = filepath.Join(cfg.FilePickerDir, src)
+ }
+ if !filepath.IsAbs(dst) {
+ dst = filepath.Join(cfg.FilePickerDir, dst)
+ }
+ err := os.Rename(src, dst)
+ if err != nil {
+ return fmt.Sprintf("[error] mv: %v", err), true
+ }
+ return "Moved " + src + " to " + dst, true
+ case "rm":
+ if len(args) == 0 {
+ return "[error] usage: rm [-r] <file>", true
+ }
+ recursive := false
+ var target string
+ for _, a := range args {
+ if a == "-r" || a == "-rf" || a == "-fr" || a == "-recursive" {
+ recursive = true
+ } else if target == "" {
+ target = a
+ }
+ }
+ if target == "" {
+ return "[error] usage: rm [-r] <file>", true
+ }
+ abs := target
+ if !filepath.IsAbs(target) {
+ abs = filepath.Join(cfg.FilePickerDir, target)
+ }
+ info, err := os.Stat(abs)
+ if err != nil {
+ return fmt.Sprintf("[error] rm: %v", err), true
+ }
+ if info.IsDir() {
+ if recursive {
+ err = os.RemoveAll(abs)
+ if err != nil {
+ return fmt.Sprintf("[error] rm: %v", err), true
+ }
+ return "Removed " + abs, true
+ }
+ return "[error] rm: is a directory (use -r)", true
+ }
+ err = os.Remove(abs)
+ if err != nil {
+ return fmt.Sprintf("[error] rm: %v", err), true
+ }
+ return "Removed " + abs, true
}
- return ""
+ return "", false
}
diff --git a/tools/tools.go b/tools/tools.go
index 9baafd3..ba0a5ce 100644
--- a/tools/tools.go
+++ b/tools/tools.go
@@ -134,10 +134,10 @@ func (t *Tools) initAgentsB() {
agent.RegisterB("summarize_chat", agent.NewWebAgentB(t.webAgentClient, summarySysPrompt))
}
-func InitTools(cfg *config.Config, logger *slog.Logger, store storage.FullRepo) *Tools {
- _ = logger
- _ = cfg
- if cfg.PlaywrightEnabled {
+func InitTools(initCfg *config.Config, logger *slog.Logger, store storage.FullRepo) *Tools {
+ logger = logger
+ cfg = initCfg
+ if initCfg.PlaywrightEnabled {
if err := CheckPlaywright(); err != nil {
// slow, need a faster check if playwright install
if err := InstallPW(); err != nil {