summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrail Finder <wohilas@gmail.com>2026-03-16 09:44:28 +0300
committerGrail Finder <wohilas@gmail.com>2026-03-16 09:44:28 +0300
commit3d44686a517f65c6f5a985cfa864240b996fdb99 (patch)
tree08263e3b97522bd04bb19f7a822d8894064c1930
parentdf04d8c21c4d256ade69f53bfe171f066db943cc (diff)
Feat (cli): test run and teardown
-rw-r--r--.gitignore1
-rwxr-xr-xcli-tests/sort-text/check.sh91
-rwxr-xr-xcli-tests/sort-text/run.sh25
-rwxr-xr-xcli-tests/sort-text/teardown.sh4
-rw-r--r--tools/chain.go131
-rw-r--r--tools/tools.go8
6 files changed, 230 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore
index 6811189..0ce290e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@ chat_exports/*.json
ragimport
.env
onnx/
+*.log
diff --git a/cli-tests/sort-text/check.sh b/cli-tests/sort-text/check.sh
new file mode 100755
index 0000000..7beb2f5
--- /dev/null
+++ b/cli-tests/sort-text/check.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+LOG_FILE="$SCRIPT_DIR/run.log"
+
+PASS=0
+FAIL=0
+
+log_pass() {
+ echo "[PASS] $1"
+ PASS=$((PASS + 1))
+}
+
+log_fail() {
+ echo "[FAIL] $1"
+ FAIL=$((FAIL + 1))
+}
+
+echo "=== Checking results ==="
+echo ""
+
+# Check animals directory exists
+if [ -d "/tmp/sort-text/animals" ]; then
+ log_pass "animals directory exists"
+else
+ log_fail "animals directory missing"
+fi
+
+# Check colors directory exists
+if [ -d "/tmp/sort-text/colors" ]; then
+ log_pass "colors directory exists"
+else
+ log_fail "colors directory missing"
+fi
+
+# Check animals contain cat/dog
+ANIMALS_FILES=$(ls -1 /tmp/sort-text/animals 2>/dev/null | tr '\n' ' ')
+if echo "$ANIMALS_FILES" | grep -q "file1.txt" && echo "$ANIMALS_FILES" | grep -q "file3.txt"; then
+ log_pass "animals contains animal files"
+else
+ log_fail "animals missing animal files (got: $ANIMALS_FILES)"
+fi
+
+# Check colors contain red/blue
+COLORS_FILES=$(ls -1 /tmp/sort-text/colors 2>/dev/null | tr '\n' ' ')
+if echo "$COLORS_FILES" | grep -q "file2.txt" && echo "$COLORS_FILES" | grep -q "file4.txt"; then
+ log_pass "colors contains color files"
+else
+ log_fail "colors missing color files (got: $COLORS_FILES)"
+fi
+
+# Verify content
+if grep -q "cat" /tmp/sort-text/animals/file1.txt 2>/dev/null; then
+ log_pass "file1.txt contains 'cat'"
+else
+ log_fail "file1.txt missing 'cat'"
+fi
+
+if grep -q "dog" /tmp/sort-text/animals/file3.txt 2>/dev/null; then
+ log_pass "file3.txt contains 'dog'"
+else
+ log_fail "file3.txt missing 'dog'"
+fi
+
+if grep -q "red" /tmp/sort-text/colors/file2.txt 2>/dev/null; then
+ log_pass "file2.txt contains 'red'"
+else
+ log_fail "file2.txt missing 'red'"
+fi
+
+if grep -q "blue" /tmp/sort-text/colors/file4.txt 2>/dev/null; then
+ log_pass "file4.txt contains 'blue'"
+else
+ log_fail "file4.txt missing 'blue'"
+fi
+
+echo ""
+echo "=== Summary ==="
+echo "PASSED: $PASS"
+echo "FAILED: $FAIL"
+
+if [ $FAIL -gt 0 ]; then
+ echo ""
+ echo "Log file: $LOG_FILE"
+ exit 1
+fi
+
+echo ""
+echo "All tests passed!"
+exit 0
diff --git a/cli-tests/sort-text/run.sh b/cli-tests/sort-text/run.sh
new file mode 100755
index 0000000..5cd5d3e
--- /dev/null
+++ b/cli-tests/sort-text/run.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+TIMESTAMP=$(date +%Y%m%d_%H%M%S)
+LOG_FILE="$SCRIPT_DIR/${TIMESTAMP}_run.log"
+
+exec > "$LOG_FILE" 2>&1
+
+echo "=== Running teardown ==="
+"$SCRIPT_DIR/teardown.sh"
+
+echo ""
+echo "=== Running setup ==="
+"$SCRIPT_DIR/setup.sh"
+
+echo ""
+echo "=== Running task ==="
+TASK=$(cat "$SCRIPT_DIR/task.txt")
+cd /home/grail/projects/plays/goplays/gf-lt
+go run . -cli -msg "$TASK"
+
+echo ""
+echo "=== Done ==="
+echo "Log file: $LOG_FILE"
diff --git a/cli-tests/sort-text/teardown.sh b/cli-tests/sort-text/teardown.sh
new file mode 100755
index 0000000..5a833ce
--- /dev/null
+++ b/cli-tests/sort-text/teardown.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+set -e
+
+rm -rf /tmp/sort-text
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 {