Commit c38d23b

mo khan <mo@mokhan.ca>
2026-01-26 22:41:37
feat: add more tools
1 parent e99a023
lib/elelem/builtins/confirm.rb
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-Elelem::Plugins.register(:confirm) do |agent|
-  agent.toolbox.before("execute") do |args|
-    next unless $stdin.tty?
-
-    cmd = args["command"]
-    answer = agent.terminal.ask("  Allow? [Y/n] > ")&.downcase
-    raise "User denied permission to execute: #{cmd}" if answer == "n"
-  end
-end
lib/elelem/builtins/git.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+Elelem::Plugins.register(:git) do |agent|
+  allowed = %w[status diff log show branch checkout add reset stash].freeze
+
+  agent.toolbox.add("git",
+    description: "Run git command",
+    params: { command: { type: "string" }, args: { type: "array" } },
+    required: ["command"]
+  ) do |a|
+    cmd = a["command"]
+    next { error: "not allowed: #{cmd}" } unless allowed.include?(cmd)
+
+    agent.toolbox.exec("git", cmd, *(a["args"] || []))
+  end
+
+  agent.toolbox.after("git") do |_, result|
+    agent.terminal.say "  ! #{result[:error]}" if result[:error]
+  end
+end
lib/elelem/builtins/glob.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+Elelem::Plugins.register(:glob) do |agent|
+  agent.toolbox.add("glob",
+    description: "Find files matching pattern",
+    params: { pattern: { type: "string" }, path: { type: "string" } },
+    required: ["pattern"]
+  ) do |a|
+    path = a["path"] || "."
+    result = agent.toolbox.exec("fd", "--glob", a["pattern"], path)
+    result[:ok] ? result : agent.toolbox.exec("find", path, "-name", a["pattern"])
+  end
+end
lib/elelem/builtins/grep.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+Elelem::Plugins.register(:grep) do |agent|
+  agent.toolbox.add("grep",
+    description: "Search file contents",
+    params: { pattern: { type: "string" }, path: { type: "string" }, glob: { type: "string" } },
+    required: ["pattern"]
+  ) do |a|
+    path = a["path"] || "."
+    glob = a["glob"]
+    rg_args = ["rg", "-n", a["pattern"], path]
+    rg_args += ["-g", glob] if glob
+    result = agent.toolbox.exec(*rg_args)
+    next result if result[:ok]
+
+    grep_args = ["grep", "-rn"]
+    grep_args += ["--include", glob] if glob
+    grep_args += [a["pattern"], path]
+    agent.toolbox.exec(*grep_args)
+  end
+end
lib/elelem/builtins/list.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+Elelem::Plugins.register(:list) do |agent|
+  agent.toolbox.add("list",
+    description: "List directory contents",
+    params: { path: { type: "string" }, recursive: { type: "boolean" } },
+    required: [],
+    aliases: ["ls"]
+  ) do |a|
+    path = a["path"] || "."
+    flags = a["recursive"] ? "-laR" : "-la"
+    agent.toolbox.exec("ls", flags, path)
+  end
+end
lib/elelem/builtins/permissions.json
@@ -0,0 +1,6 @@
+{
+  "read": "allow",
+  "write": "ask",
+  "edit": "ask",
+  "execute": "ask"
+}
lib/elelem/builtins/write.rb
@@ -12,6 +12,17 @@ Elelem::Plugins.register(:write) do |agent|
     { bytes: path.write(a["content"]), path: a["path"] }
   end
 
+  agent.toolbox.before("write") do |args|
+    path = Pathname.new(args["path"]).expand_path
+    next unless path.exist? && $stdin.tty?
+
+    Tempfile.create(["elelem", File.extname(path)]) do |t|
+      t.write(args["content"])
+      t.flush
+      system("diff", "--color=always", "-u", path.to_s, t.path)
+    end
+  end
+
   agent.toolbox.after("write") do |_, result|
     if result[:error]
       agent.terminal.say "  ! #{result[:error]}"
lib/elelem/builtins/zz_confirm.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+Elelem::Plugins.register(:confirm) do |agent|
+  permissions = Elelem::Permissions.new
+
+  agent.toolbox.tools.each_key do |tool_name|
+    agent.toolbox.before(tool_name) do |args|
+      permissions.check(tool_name, args, terminal: agent.terminal)
+    end
+  end
+end