Feat: run sed
This commit is contained in:
591
tools.go
591
tools.go
@@ -537,6 +537,7 @@ func getHelp(args []string) string {
|
|||||||
mkdir <dir> - create directory
|
mkdir <dir> - create directory
|
||||||
pwd - print working directory
|
pwd - print working directory
|
||||||
cd <dir> - change directory
|
cd <dir> - change directory
|
||||||
|
sed 's/old/new/[g]' [file] - text replacement
|
||||||
|
|
||||||
# Text processing
|
# Text processing
|
||||||
echo <args> - echo back input
|
echo <args> - echo back input
|
||||||
@@ -551,6 +552,9 @@ func getHelp(args []string) string {
|
|||||||
# Git (read-only)
|
# Git (read-only)
|
||||||
git <cmd> - git commands (status, log, diff, show, branch, etc.)
|
git <cmd> - git commands (status, log, diff, show, branch, etc.)
|
||||||
|
|
||||||
|
# Go
|
||||||
|
go <cmd> - go commands (run, build, test, mod, etc.)
|
||||||
|
|
||||||
# Memory
|
# Memory
|
||||||
memory store <topic> <data> - save to memory
|
memory store <topic> <data> - save to memory
|
||||||
memory get <topic> - retrieve from memory
|
memory get <topic> - retrieve from memory
|
||||||
@@ -650,6 +654,27 @@ Use: run "command" to execute.`
|
|||||||
Print working directory.
|
Print working directory.
|
||||||
Example:
|
Example:
|
||||||
run "pwd"`
|
run "pwd"`
|
||||||
|
case "sed":
|
||||||
|
return `sed 's/old/new/[g]' [file]
|
||||||
|
Stream editor for text replacement.
|
||||||
|
Options:
|
||||||
|
-i in-place editing
|
||||||
|
-g global replacement (replace all)
|
||||||
|
Examples:
|
||||||
|
run "sed 's/foo/bar/' file.txt"
|
||||||
|
run "sed 's/foo/bar/g' file.txt" (global)
|
||||||
|
run "sed -i 's/foo/bar/' file.txt" (in-place)
|
||||||
|
run "cat file.txt | sed 's/foo/bar/'" (pipe from stdin)`
|
||||||
|
case "go":
|
||||||
|
return `go <command>
|
||||||
|
Go toolchain commands.
|
||||||
|
Allowed: run, build, test, mod, get, install, clean, fmt, vet, etc.
|
||||||
|
Examples:
|
||||||
|
run "go run main.go"
|
||||||
|
run "go build ./..."
|
||||||
|
run "go test ./..."
|
||||||
|
run "go mod tidy"
|
||||||
|
run "go get github.com/package"`
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("No help available for: %s. Use: run \"help\" for all commands.", cmd)
|
return fmt.Sprintf("No help available for: %s. Use: run \"help\" for all commands.", cmd)
|
||||||
}
|
}
|
||||||
@@ -931,65 +956,6 @@ func todoDelete(args map[string]string) []byte {
|
|||||||
return jsonResult
|
return jsonResult
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitReadSubcommands = map[string]bool{
|
|
||||||
"status": true,
|
|
||||||
"log": true,
|
|
||||||
"diff": true,
|
|
||||||
"show": true,
|
|
||||||
"branch": true,
|
|
||||||
"reflog": true,
|
|
||||||
"rev-parse": true,
|
|
||||||
"shortlog": true,
|
|
||||||
"describe": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
func isCommandAllowed(command string, args ...string) bool {
|
|
||||||
allowedCommands := map[string]bool{
|
|
||||||
"cd": true,
|
|
||||||
"grep": true,
|
|
||||||
"sed": true,
|
|
||||||
"awk": true,
|
|
||||||
"find": true,
|
|
||||||
"cat": true,
|
|
||||||
"head": true,
|
|
||||||
"tail": true,
|
|
||||||
"sort": true,
|
|
||||||
"uniq": true,
|
|
||||||
"wc": true,
|
|
||||||
"ls": true,
|
|
||||||
"echo": true,
|
|
||||||
"cut": true,
|
|
||||||
"tr": true,
|
|
||||||
"cp": true,
|
|
||||||
"mv": true,
|
|
||||||
"rm": true,
|
|
||||||
"mkdir": true,
|
|
||||||
"rmdir": true,
|
|
||||||
"pwd": true,
|
|
||||||
"df": true,
|
|
||||||
"free": true,
|
|
||||||
"ps": true,
|
|
||||||
"top": true,
|
|
||||||
"du": true,
|
|
||||||
"whoami": true,
|
|
||||||
"date": true,
|
|
||||||
"uname": true,
|
|
||||||
"git": true,
|
|
||||||
"go": true,
|
|
||||||
}
|
|
||||||
// Allow all go subcommands (go run, go mod tidy, go test, etc.)
|
|
||||||
if strings.HasPrefix(command, "go ") && allowedCommands["go"] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if command == "git" && len(args) > 0 {
|
|
||||||
return gitReadSubcommands[args[0]]
|
|
||||||
}
|
|
||||||
if !allowedCommands[command] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func summarizeChat(args map[string]string) []byte {
|
func summarizeChat(args map[string]string) []byte {
|
||||||
if len(chatBody.Messages) == 0 {
|
if len(chatBody.Messages) == 0 {
|
||||||
return []byte("No chat history to summarize.")
|
return []byte("No chat history to summarize.")
|
||||||
@@ -1150,108 +1116,6 @@ func argsToSlice(args map[string]string) []string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdLs(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsLs(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCat(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsCat(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdSee(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsSee(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdWrite(args map[string]string) []byte {
|
|
||||||
// write needs special handling - content might be in args or stdin
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
// If there's a "content" key, append it
|
|
||||||
if content, ok := args["content"]; ok && content != "" {
|
|
||||||
slice = append(slice, content)
|
|
||||||
}
|
|
||||||
return []byte(tools.FsWrite(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdStat(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsStat(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdRm(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsRm(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCp(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsCp(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdMv(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsMv(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdMkdir(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsMkdir(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdEcho(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsEcho(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTime(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsTime(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdGrep(args map[string]string) []byte {
|
|
||||||
// grep needs special handling - pattern and flags
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
// Check for pattern key
|
|
||||||
if pattern, ok := args["pattern"]; ok && pattern != "" {
|
|
||||||
slice = append([]string{pattern}, slice...)
|
|
||||||
}
|
|
||||||
return []byte(tools.FsGrep(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdHead(args map[string]string) []byte {
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
return []byte(tools.FsHead(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdTail(args map[string]string) []byte {
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
return []byte(tools.FsTail(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdWc(args map[string]string) []byte {
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
return []byte(tools.FsWc(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdSort(args map[string]string) []byte {
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
return []byte(tools.FsSort(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdUniq(args map[string]string) []byte {
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
return []byte(tools.FsUniq(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdGit(args map[string]string) []byte {
|
|
||||||
slice := argsToSlice(args)
|
|
||||||
// Check for subcommand key
|
|
||||||
if subcmd, ok := args["subcommand"]; ok && subcmd != "" {
|
|
||||||
slice = append([]string{subcmd}, slice...)
|
|
||||||
}
|
|
||||||
return []byte(tools.FsGit(slice, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdPwd(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsPwd(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCd(args map[string]string) []byte {
|
|
||||||
return []byte(tools.FsCd(argsToSlice(args), ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdMemory(args map[string]string) []byte {
|
func cmdMemory(args map[string]string) []byte {
|
||||||
return []byte(tools.FsMemory(argsToSlice(args), ""))
|
return []byte(tools.FsMemory(argsToSlice(args), ""))
|
||||||
}
|
}
|
||||||
@@ -1295,18 +1159,6 @@ var fnMap = map[string]fnSig{
|
|||||||
"websearch_raw": websearchRaw,
|
"websearch_raw": websearchRaw,
|
||||||
"read_url": readURL,
|
"read_url": readURL,
|
||||||
"read_url_raw": readURLRaw,
|
"read_url_raw": readURLRaw,
|
||||||
// Unix-style file commands (replacing file_* tools)
|
|
||||||
"ls": cmdLs,
|
|
||||||
"cat": cmdCat,
|
|
||||||
"see": cmdSee,
|
|
||||||
"write": cmdWrite,
|
|
||||||
"stat": cmdStat,
|
|
||||||
"rm": cmdRm,
|
|
||||||
"cp": cmdCp,
|
|
||||||
"mv": cmdMv,
|
|
||||||
"mkdir": cmdMkdir,
|
|
||||||
"pwd": cmdPwd,
|
|
||||||
"cd": cmdCd,
|
|
||||||
// Unified run command
|
// Unified run command
|
||||||
"run": runCmd,
|
"run": runCmd,
|
||||||
"summarize_chat": summarizeChat,
|
"summarize_chat": summarizeChat,
|
||||||
@@ -1909,238 +1761,6 @@ var baseTools = []models.Tool{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
// run - unified command
|
// run - unified command
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "memory",
|
|
||||||
Description: "Memory management. Usage: memory store <topic> <data> | memory get <topic> | memory list | memory forget <topic>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"subcommand"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"subcommand": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "subcommand: store, get, list, topics, forget, delete",
|
|
||||||
},
|
|
||||||
"topic": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "topic/key for memory",
|
|
||||||
},
|
|
||||||
"data": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "data to store",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Unix-style file commands
|
|
||||||
// ls
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "ls",
|
|
||||||
Description: "List files in a directory. Usage: ls [dir]",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"path": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "directory to list (optional, defaults to current directory)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// cat
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "cat",
|
|
||||||
Description: "Read file content. Usage: cat <path>. Use -b flag for base64 output (for binary files).",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"path"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"path": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "path of the file to read",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// see
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "see",
|
|
||||||
Description: "View an image file and return it for multimodal LLM viewing. Supports png, jpg, jpeg, gif, webp, svg.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"path"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"path": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "path of the image file to view",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// write
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "write",
|
|
||||||
Description: "Write content to a file. Will overwrite any content present. Usage: write <path> [content]. Use -b flag for base64 input (for binary files).",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"path"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"path": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "path of the file to write to",
|
|
||||||
},
|
|
||||||
"content": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "content to write to the file",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// stat
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "stat",
|
|
||||||
Description: "Get file information (size, type, modified time). Usage: stat <path>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"path"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"path": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "path of the file to get info for",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// rm
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "rm",
|
|
||||||
Description: "Delete a file. Usage: rm <path>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"path"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"path": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "path of the file to delete",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// cp
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "cp",
|
|
||||||
Description: "Copy a file. Usage: cp <src> <dst>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"src", "dst"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"src": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "source file path",
|
|
||||||
},
|
|
||||||
"dst": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "destination file path",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// mv
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "mv",
|
|
||||||
Description: "Move/rename a file. Usage: mv <src> <dst>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"src", "dst"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"src": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "source file path",
|
|
||||||
},
|
|
||||||
"dst": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "destination file path",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// mkdir
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "mkdir",
|
|
||||||
Description: "Create a directory. Usage: mkdir <dir>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"dir"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"dir": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "directory path to create",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// pwd
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "pwd",
|
|
||||||
Description: "Print working directory. Returns the current directory path.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// cd
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "cd",
|
|
||||||
Description: "Change working directory. Usage: cd <dir>",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"dir"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"dir": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "directory to change to",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// run - unified command
|
|
||||||
models.Tool{
|
models.Tool{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: models.ToolFunc{
|
Function: models.ToolFunc{
|
||||||
@@ -2158,165 +1778,4 @@ var baseTools = []models.Tool{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// echo
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "echo",
|
|
||||||
Description: "Echo back the input. Usage: echo [args] or pipe stdin",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"args": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "arguments to echo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// time
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "time",
|
|
||||||
Description: "Return the current time.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// grep
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "grep",
|
|
||||||
Description: "Filter lines matching a pattern. Usage: grep [-i] [-v] [-c] <pattern>. -i: ignore case, -v: invert match, -c: count matches.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"pattern"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"pattern": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "pattern to search for",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// head
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "head",
|
|
||||||
Description: "Show first N lines. Usage: head [n] or head -n <n>. Default: 10",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"n": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "number of lines (optional, default 10)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// tail
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "tail",
|
|
||||||
Description: "Show last N lines. Usage: tail [n] or tail -n <n>. Default: 10",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"n": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "number of lines (optional, default 10)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// wc
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "wc",
|
|
||||||
Description: "Count lines, words, chars. Usage: wc [-l] [-w] [-c]. -l: lines, -w: words, -c: chars.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"flag": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "optional flag: -l, -w, or -c",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// sort
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "sort",
|
|
||||||
Description: "Sort lines. Usage: sort [-r] [-n]. -r: reverse, -n: numeric sort.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"reverse": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "use -r for reverse sort",
|
|
||||||
},
|
|
||||||
"numeric": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "use -n for numeric sort",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// uniq
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "uniq",
|
|
||||||
Description: "Remove duplicate lines. Usage: uniq [-c] to show count.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"count": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "use -c to show count of occurrences",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// git (read-only)
|
|
||||||
models.Tool{
|
|
||||||
Type: "function",
|
|
||||||
Function: models.ToolFunc{
|
|
||||||
Name: "git",
|
|
||||||
Description: "Execute read-only git commands. Allowed: status, log, diff, show, branch, reflog, rev-parse, shortlog, describe.",
|
|
||||||
Parameters: models.ToolFuncParams{
|
|
||||||
Type: "object",
|
|
||||||
Required: []string{"subcommand"},
|
|
||||||
Properties: map[string]models.ToolArgProps{
|
|
||||||
"subcommand": models.ToolArgProps{
|
|
||||||
Type: "string",
|
|
||||||
Description: "git subcommand (status, log, diff, show, branch, reflog, rev-parse, shortlog, describe)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,6 +266,18 @@ func execBuiltin(name string, args []string, stdin string) string {
|
|||||||
}
|
}
|
||||||
fsRootDir = abs
|
fsRootDir = abs
|
||||||
return fmt.Sprintf("Changed directory to: %s", fsRootDir)
|
return fmt.Sprintf("Changed directory to: %s", fsRootDir)
|
||||||
|
case "go":
|
||||||
|
// Allow all go subcommands
|
||||||
|
if len(args) == 0 {
|
||||||
|
return "[error] usage: go <subcommand> [options]"
|
||||||
|
}
|
||||||
|
cmd := exec.Command("go", args...)
|
||||||
|
cmd.Dir = fsRootDir
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output))
|
||||||
|
}
|
||||||
|
return string(output)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
74
tools/fs.go
74
tools/fs.go
@@ -614,6 +614,80 @@ func FsCd(args []string, stdin string) string {
|
|||||||
return fmt.Sprintf("Changed directory to: %s", fsRootDir)
|
return fmt.Sprintf("Changed directory to: %s", fsRootDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FsSed(args []string, stdin string) string {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return "[error] usage: sed 's/old/new/[g]' [file]"
|
||||||
|
}
|
||||||
|
|
||||||
|
inPlace := false
|
||||||
|
var filePath string
|
||||||
|
var pattern string
|
||||||
|
|
||||||
|
for _, a := range args {
|
||||||
|
if a == "-i" || a == "--in-place" {
|
||||||
|
inPlace = true
|
||||||
|
} else if strings.HasPrefix(a, "s") && len(a) > 1 {
|
||||||
|
// This looks like a sed pattern
|
||||||
|
pattern = a
|
||||||
|
} else if filePath == "" && !strings.HasPrefix(a, "-") {
|
||||||
|
filePath = a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pattern == "" {
|
||||||
|
return "[error] usage: sed 's/old/new/[g]' [file]"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse pattern: s/old/new/flags
|
||||||
|
parts := strings.Split(pattern[1:], "/")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return "[error] invalid sed pattern. Use: s/old/new/[g]"
|
||||||
|
}
|
||||||
|
|
||||||
|
oldStr := parts[0]
|
||||||
|
newStr := parts[1]
|
||||||
|
global := len(parts) >= 3 && strings.Contains(parts[2], "g")
|
||||||
|
|
||||||
|
var content string
|
||||||
|
if filePath != "" && stdin == "" {
|
||||||
|
// Read from file
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] sed: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] sed: %v", err)
|
||||||
|
}
|
||||||
|
content = string(data)
|
||||||
|
} else if stdin != "" {
|
||||||
|
// Use stdin
|
||||||
|
content = stdin
|
||||||
|
} else {
|
||||||
|
return "[error] sed: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply sed replacement
|
||||||
|
if global {
|
||||||
|
content = strings.ReplaceAll(content, oldStr, newStr)
|
||||||
|
} else {
|
||||||
|
content = strings.Replace(content, oldStr, newStr, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inPlace && filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] sed: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(abs, []byte(content), 0644); err != nil {
|
||||||
|
return fmt.Sprintf("[error] sed: %v", err)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Modified %s", filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
func FsMemory(args []string, stdin string) string {
|
func FsMemory(args []string, stdin string) string {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return "[error] usage: memory store <topic> <data> | memory get <topic> | memory list | memory forget <topic>"
|
return "[error] usage: memory store <topic> <data> | memory get <topic> | memory list | memory forget <topic>"
|
||||||
|
|||||||
Reference in New Issue
Block a user