Commit 01a88f5
Changed files (2)
lib
elelem
lib/elelem/toolbox.rb
@@ -2,19 +2,17 @@
module Elelem
class Toolbox
- attr_reader :tools, :shell
+ attr_reader :tools
def initialize
@tools_by_name = {}
@tools = { read: [], write: [], execute: [] }
-
- @shell = Shell.new
- add_tool(exec_tool, :execute)
- add_tool(grep_tool, :read)
- add_tool(list_tool, :read)
- add_tool(patch_tool, :write)
- add_tool(read_tool, :read)
- add_tool(write_tool, :write)
+ add_tool(EXEC_TOOL, :execute)
+ add_tool(GREP_TOOL, :read)
+ add_tool(LIST_TOOL, :read)
+ add_tool(PATCH_TOOL, :write)
+ add_tool(READ_TOOL, :read)
+ add_tool(WRITE_TOOL, :write)
end
def add_tool(tool, mode)
@@ -29,89 +27,8 @@ module Elelem
def run_tool(name, args)
@tools_by_name[name]&.call(args) || { error: "Unknown tool", name: name, args: args }
rescue => error
+ puts error.inspect
{ error: error.message, name: name, args: args }
end
-
- private
-
- def exec_tool
- @exec_tools ||= Tool.build(
- "execute",
- "Execute shell commands directly. Commands run in a shell context. Examples: 'date', 'git status'.",
- {
- cmd: { type: "string" },
- args: { type: "array", items: { type: "string" } },
- env: { type: "object", additionalProperties: { type: "string" } },
- cwd: { type: "string", description: "Working directory (defaults to current)" },
- stdin: { type: "string" }
- },
- ["cmd"]
- ) do |args|
- shell.execute(
- args["cmd"],
- args: args["args"] || [],
- env: args["env"] || {},
- cwd: args["cwd"].to_s.empty? ? Dir.pwd : args["cwd"],
- stdin: args["stdin"]
- )
- end
- end
-
- def grep_tool
- @grep_tool ||= Tool.build(
- "grep",
- "Search all git-tracked files using git grep. Returns file paths with matching line numbers.",
- { query: { type: "string" } },
- ["query"]
- ) do |args|
- shell.execute("git", args: ["grep", "-nI", args["query"]])
- end
- end
-
- def list_tool
- @list_tool ||= Tool.build(
- "list",
- "List all git-tracked files in the repository, optionally filtered by path.",
- { path: { type: "string" } }
- ) do |args|
- shell.execute("git", args: args["path"] ? ["ls-files", "--", args["path"]] : ["ls-files"])
- end
- end
-
- def patch_tool
- @patch_tool ||= Tool.build(
- "patch",
- "Apply a unified diff patch via 'git apply'. Use for surgical edits to existing files.",
- { diff: { type: "string" } },
- ["diff"]
- ) do |args|
- shell.execute("git", args: ["apply", "--index", "--whitespace=nowarn", "-p1"], stdin: args["diff"])
- end
- end
-
- def read_tool
- @read_tool ||= Tool.build(
- "read",
- "Read complete contents of a file. Requires exact file path.",
- { path: { type: "string" } },
- ["path"]
- ) do |args|
- full_path = Pathname.new(args["path"]).expand_path
- full_path.exist? ? { content: full_path.read } : { error: "File not found: #{path}" }
- end
- end
-
- def write_tool
- @write_tool ||= Tool.build(
- "write",
- "Write complete file contents (overwrites existing files). Creates parent directories automatically.",
- { path: { type: "string" }, content: { type: "string" } },
- ["path", "content"]
- ) do |args|
- full_path = Pathname.new(args["path"]).expand_path
- FileUtils.mkdir_p(full_path.dirname)
- { bytes_written: full_path.write(args["content"]) }
- end
- end
end
end
lib/elelem.rb
@@ -26,6 +26,39 @@ Reline.output = $stdout
module Elelem
class Error < StandardError; end
+ READ_TOOL = Tool.build("read", "Read complete contents of a file. Requires exact file path.", { path: { type: "string" } }, ["path"]) do |args|
+ full_path = Pathname.new(args["path"]).expand_path
+ full_path.exist? ? { content: full_path.read } : { error: "File not found: #{path}" }
+ end
+
+ EXEC_TOOL = Tool.build("execute", "Execute shell commands directly. Commands run in a shell context. Examples: 'date', 'git status'.", { cmd: { type: "string" }, args: { type: "array", items: { type: "string" } }, env: { type: "object", additionalProperties: { type: "string" } }, cwd: { type: "string", description: "Working directory (defaults to current)" }, stdin: { type: "string" } }, ["cmd"]) do |args|
+ Elelem.shell.execute(
+ args["cmd"],
+ args: args["args"] || [],
+ env: args["env"] || {},
+ cwd: args["cwd"].to_s.empty? ? Dir.pwd : args["cwd"],
+ stdin: args["stdin"]
+ )
+ end
+
+ GREP_TOOL = Tool.build("grep", "Search all git-tracked files using git grep. Returns file paths with matching line numbers.", { query: { type: "string" } }, ["query"]) do |args|
+ Elelem.shell.execute("git", args: ["grep", "-nI", args["query"]])
+ end
+
+ LIST_TOOL = Tool.build("list", "List all git-tracked files in the repository, optionally filtered by path.", { path: { type: "string" } }) do |args|
+ Elelem.shell.execute("git", args: args["path"] ? ["ls-files", "--", args["path"]] : ["ls-files"])
+ end
+
+ PATCH_TOOL = Tool.build( "patch", "Apply a unified diff patch via 'git apply'. Use for surgical edits to existing files.", { diff: { type: "string" } }, ["diff"]) do |args|
+ Elelem.shell.execute("git", args: ["apply", "--index", "--whitespace=nowarn", "-p1"], stdin: args["diff"])
+ end
+
+ WRITE_TOOL = Tool.build("write", "Write complete file contents (overwrites existing files). Creates parent directories automatically.", { path: { type: "string" }, content: { type: "string" } }, ["path", "content"]) do |args|
+ full_path = Pathname.new(args["path"]).expand_path
+ FileUtils.mkdir_p(full_path.dirname)
+ { bytes_written: full_path.write(args["content"]) }
+ end
+
class Shell
def execute(command, args: [], env: {}, cwd: Dir.pwd, stdin: nil)
cmd = command.is_a?(Array) ? command.first : command
@@ -44,4 +77,10 @@ module Elelem
}
end
end
+
+ class << self
+ def shell
+ @shell ||= Shell.new
+ end
+ end
end