elelem 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a284087a47f32b75927bb0fc593aee12c376952f89af2ae61faa96b66810ae87
4
- data.tar.gz: 138d5d8a0c110a1631c1a3b64024d2f82b5a80bfa1339244ef0d5bb932c2c626
3
+ metadata.gz: c88aa14330442939c8d62db38adcb229c860059888567b21fb309b760da18b7e
4
+ data.tar.gz: 7829340c692a3b025d95f47be9908c8d5ca0ab7988454b29e73af783d0e7d3ab
5
5
  SHA512:
6
- metadata.gz: b3baefa781ccfef8e2a4882a1b8f65779b672f45918a9e0a9926741dbb80ecfb57c4c182f9074ae71e73b29010d3c349a893f3bde388d7e5340d04a158ae3cde
7
- data.tar.gz: d4d6d0609f1ef0fa9bc5e9bb67aec6085944706db8a31025a63299f3ea0519f202a4a3f4a2ea4dad647bcb1390a98eb3ea7b1f0ab2f6b16c87ec18f6f1c355e3
6
+ metadata.gz: a3254b0655057dbaf8871ef6e6782bb962b588525a69a6d9f0746368f4c38d92c3ad41790104bb2cedfb25c16df2d77d07f236cfdde23805bee3be21d515cf99
7
+ data.tar.gz: f6d43cbe0659d37b6c6249bad2dc5c3dd04b6e4e2bb0a2a7201b4a479a9c1c52cc8e0516ffeb6b050098537e5c10b4d7887c80c8870ac01334599ab49100dc06
data/CHANGELOG.md CHANGED
@@ -1,4 +1,73 @@
1
- ## [Unreleased]
1
+ ## [0.9.0] - 2026-01-21
2
+
3
+ ### Added
4
+ - **Plugin system** with support for custom tool definitions
5
+ - Load plugins from `lib/elelem/plugins/`, `~/.elelem/plugins/`, and `.elelem/plugins/`
6
+ - `Elelem::Plugins.register(name) { |toolbox| ... }` API
7
+ - Built-in plugins: `read`, `write`, `edit`, `execute`, `eval`, `verify`, `confirm`, `mcp`
8
+ - **MCP (Model Context Protocol)** server support via `.mcp.json` configuration
9
+ - **AGENTS.md** file support - searches up directory tree for project instructions
10
+ - **`/init` command** to generate an AGENTS.md file for the current project
11
+ - **`/shell` command** to drop into a shell session and capture the transcript to context
12
+ - **`/reload` command** to hot-reload source code without restarting the process
13
+ - **`task` tool** for delegating subtasks to focused sub-agents
14
+ - **`edit` tool** for replacing first occurrence of text in a file
15
+ - **`eval` tool** for executing Ruby code and dynamically registering new tools
16
+ - **`verify` tool** for syntax checking and running project tests
17
+ - **Pre/post tool hooks** (`toolbox.before`/`toolbox.after`) for extensibility
18
+ - **Confirmation prompt** before executing shell commands (when TTY)
19
+ - **Context compaction** for long conversations (summarizes old messages)
20
+ - **Repo map** via ctags included in system prompt
21
+ - **Markdown rendering** with [glow](https://github.com/charmbracelet/glow) for LLM responses
22
+ - **CLI improvements**: optparse-based interface with `-p`/`-m` flags
23
+ - `elelem chat` - Interactive REPL (default)
24
+ - `elelem ask <prompt>` - One-shot query (reads stdin if piped)
25
+ - `elelem files` - Output files as XML
26
+ - JSON Schema validation for tool call arguments (via `json_schemer`)
27
+ - Tool aliases support (e.g., `bash`, `sh`, `exec` → `execute`)
28
+ - **Dependencies documentation** in README with installation links
29
+
30
+ ### Changed
31
+ - **Breaking**: Requires Ruby >= 4.0.0 (was 3.4.0)
32
+ - **Breaking**: Removed `net-llm` dependency - LLM clients now inline in `lib/elelem/net/`
33
+ - `Elelem::Net::Claude` (Anthropic and Vertex AI)
34
+ - `Elelem::Net::OpenAI`
35
+ - `Elelem::Net::Ollama`
36
+ - **Breaking**: Simplified LLM client `fetch` contract
37
+ - Yields `{content:, thinking:}` deltas
38
+ - Returns `tool_calls` array directly
39
+ - **Breaking**: Tool schema uses OpenAI format (`{type: "function", function: {...}}`)
40
+ - **Breaking**: Tool definitions use `description:` key (was `desc:`)
41
+ - **Breaking**: Removed modes and permissions system entirely
42
+ - **Breaking**: Removed slash commands (`/mode`, `/env`, `/provider`, `/model`)
43
+ - Remaining: `/clear`, `/context`, `/init`, `/reload`, `/shell`, `/exit`, `/help`
44
+ - **Breaking**: Removed many dependencies
45
+ - Removed: `thor`, `cli-ui`, `erb`, `cgi`, `set`, `timeout`, `logger`, `net-llm`, `json-schema`
46
+ - Added: `json_schemer`, `optparse`, `tempfile`, `stringio`, `uri`
47
+ - Consolidated multiple exe files into single `exe/elelem` entry point
48
+ - Tools are now defined via plugins instead of hardcoded in Toolbox
49
+ - System prompt includes hints for `rg`, `fd`, `sg` (ast-grep), `sed`, `patch`
50
+ - System prompt regenerated on each fetch (includes dynamic repo map)
51
+ - Default tool set: `read`, `write`, `edit`, `execute`, `eval`, `verify`, `task`
52
+ - System prompt encourages using `eval` to create tools for repetitive tasks
53
+
54
+ ### Removed
55
+ - `lib/elelem/application.rb` - CLI now in `exe/elelem`
56
+ - `lib/elelem/conversation.rb` - simplified into Agent
57
+ - `lib/elelem/git_context.rb` - inlined into Agent
58
+ - `lib/elelem/system_prompt.erb` - now generated in Agent
59
+ - `web_fetch`, `web_search`, `fetch`, `search_engine` tools
60
+ - `patch` tool (use `edit` or `execute` with `sed`/`patch`)
61
+ - `grep`, `list` tools (use `execute` with `rg`, `fd`)
62
+ - Modes and permissions system
63
+ - Events module
64
+ - GitHub Actions CI workflow
65
+
66
+ ### Fixed
67
+ - Handle missing args in Claude provider
68
+ - Tool alias resolution (use canonical tool name, not alias)
69
+ - Unknown tool error now suggests using `execute` and lists available tools
70
+ - Duplicate write operations in edit flow
2
71
 
3
72
  ## [0.8.0] - 2026-01-14
4
73
 
@@ -48,7 +117,7 @@
48
117
  - Tab completion for `pass` entries without requiring `show` subcommand
49
118
  - Password store symlink support in tab completion
50
119
 
51
- ## [0.5.0] - 2025-01-07
120
+ ## [0.5.0] - 2026-01-07
52
121
 
53
122
  ### Added
54
123
  - Multi-provider support: Ollama, Anthropic, OpenAI, and VertexAI
@@ -198,4 +267,3 @@
198
267
  ## [0.1.0] - 2025-08-08
199
268
 
200
269
  - Initial release
201
-
data/README.md CHANGED
@@ -7,8 +7,7 @@ Fast, correct, autonomous – pick two.
7
7
  Elelem is a minimal coding agent written in Ruby. It is designed to help
8
8
  you write, edit, and manage code and plain-text files from the command line
9
9
  by delegating work to an LLM. The agent exposes a simple text-based UI and a
10
- set of built-in tools that give the LLM access to the local file system
11
- and Git.
10
+ set of built-in tools that give the LLM access to the local file system.
12
11
 
13
12
  ## Design Principles
14
13
 
@@ -26,6 +25,26 @@ and Git.
26
25
  * Runs inside a Git repository.
27
26
  * Git is available and functional.
28
27
 
28
+ ## Dependencies
29
+
30
+ Elelem relies on several external tools. Install the ones you need:
31
+
32
+ | Tool | Purpose | Install |
33
+ |------|---------|---------|
34
+ | [Ollama](https://ollama.ai/) | Default LLM provider | https://ollama.ai/download |
35
+ | [glow](https://github.com/charmbracelet/glow) | Markdown rendering | `brew install glow` / `go install github.com/charmbracelet/glow@latest` |
36
+ | [ctags](https://ctags.io/) | Repo map generation | `brew install universal-ctags` / `apt install universal-ctags` |
37
+ | [ripgrep](https://github.com/BurntSushi/ripgrep) | Text search (`rg`) | `brew install ripgrep` / `apt install ripgrep` |
38
+ | [fd](https://github.com/sharkdp/fd) | File discovery | `brew install fd` / `apt install fd-find` |
39
+ | [ast-grep](https://ast-grep.github.io/) | Structural search (`sg`) | `brew install ast-grep` / `cargo install ast-grep` |
40
+ | [Git](https://git-scm.com/) | Version control | `brew install git` / `apt install git` |
41
+
42
+ **Required:** Git, Ollama (or another LLM provider)
43
+
44
+ **Recommended:** glow, ctags, ripgrep, fd
45
+
46
+ **Optional:** ast-grep (for structural code search)
47
+
29
48
  ## Scope
30
49
 
31
50
  Only plain-text and source-code files are supported. No binary handling,
@@ -101,35 +120,10 @@ Each provider reads its configuration from environment variables:
101
120
  | openai | `OPENAI_API_KEY`, `OPENAI_BASE_URL` |
102
121
  | vertex-ai | `GOOGLE_CLOUD_PROJECT`, `GOOGLE_CLOUD_REGION` |
103
122
 
104
- ## Mode System
105
-
106
- The agent exposes seven built‑in tools. You can switch which ones are
107
- available by changing the *mode*:
108
-
109
- | Mode | Enabled Tools |
110
- |---------|------------------------------------------|
111
- | plan | `grep`, `list`, `read` |
112
- | build | `grep`, `list`, `read`, `patch`, `write` |
113
- | verify | `grep`, `list`, `read`, `execute` |
114
- | auto | All tools |
115
-
116
- Use the following commands inside the REPL:
117
-
118
- ```text
119
- /mode plan # Read‑only
120
- /mode build # Read + Write
121
- /mode verify # Read + Execute
122
- /mode auto # All tools
123
- /mode # Show current mode
124
- ```
125
-
126
- The system prompt is adjusted per mode so the LLM knows which actions
127
- are permissible.
128
-
129
123
  ## Features
130
124
 
131
125
  * **Interactive REPL** – clean, streaming chat.
132
- * **Toolbox** – file I/O, Git, shell execution.
126
+ * **Toolbox** – file I/O and shell execution.
133
127
  * **Streaming Responses** – output appears in real time.
134
128
  * **Conversation History** – persists across turns; can be cleared.
135
129
  * **Context Dump** – `/context` shows the current conversation state.
@@ -137,24 +131,15 @@ are permissible.
137
131
  ## Toolbox Overview
138
132
 
139
133
  The `Toolbox` class is defined in `lib/elelem/toolbox.rb`. It supplies
140
- seven tools, each represented by a JSON schema that the LLM can call.
141
-
142
- | Tool | Purpose | Parameters |
143
- | ---- | ------- | ---------- |
144
- | `exec` | Run shell commands | `cmd`, `args`, `env`, `cwd`, `stdin` |
145
- | `eval` | Dynamically create new tools | `code` |
146
- | `grep` | Search Git‑tracked files | `query` |
147
- | `list` | List tracked files | `path` (optional) |
148
- | `patch` | Apply a unified diff via `git apply` | `diff` |
149
- | `read` | Read file contents | `path` |
150
- | `write` | Overwrite a file | `path`, `content` |
151
-
152
- ## Tool Definition
153
-
154
- The core `Tool` wrapper is defined in `lib/elelem/tool.rb`. Each tool is
155
- created with a name, description, JSON schema for arguments, and a block
156
- that performs the operation. The LLM calls a tool by name and passes the
157
- arguments as a hash.
134
+ three tools, each represented by a JSON schema that the LLM can call.
135
+
136
+ | Tool | Purpose | Parameters |
137
+ | --------- | ------------------ | ------------------ |
138
+ | `read` | Read file contents | `path` |
139
+ | `write` | Write file | `path`, `content` |
140
+ | `execute` | Run shell command | `command` |
141
+
142
+ Aliases: `bash`, `sh`, `exec` `execute`; `open` `read`
158
143
 
159
144
  ## Known Limitations
160
145
 
data/exe/elelem CHANGED
@@ -2,9 +2,84 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "elelem"
5
+ require "optparse"
5
6
 
6
- Signal.trap("INT") do
7
- exit(1)
7
+ Signal.trap("INT") { exit 1 }
8
+
9
+ class App
10
+ MODELS = {
11
+ "ollama" => "gpt-oss:latest",
12
+ "anthropic" => "claude-opus-4-5-20250514",
13
+ "vertex" => "claude-opus-4-5@20251101",
14
+ "openai" => "gpt-4o"
15
+ }.freeze
16
+
17
+ PROVIDERS = {
18
+ "ollama" => ->(model) { Elelem::Net::Ollama.new(model: model, host: ENV.fetch("OLLAMA_HOST", "localhost:11434")) },
19
+ "anthropic" => ->(model) { Elelem::Net::Claude.anthropic(model: model, api_key: ENV.fetch("ANTHROPIC_API_KEY")) },
20
+ "vertex" => ->(model) { Elelem::Net::Claude.vertex(model: model, project: ENV.fetch("GOOGLE_CLOUD_PROJECT"), region: ENV.fetch("GOOGLE_CLOUD_REGION", "us-east5")) },
21
+ "openai" => ->(model) { Elelem::Net::OpenAI.new(model: model, api_key: ENV.fetch("OPENAI_API_KEY")) }
22
+ }.freeze
23
+
24
+ def initialize(args)
25
+ @provider = "ollama"
26
+ @model = nil
27
+ @args = parse(args)
28
+ end
29
+
30
+ def run
31
+ command = @args.shift || "chat"
32
+ send(command.tr("-", "_"))
33
+ rescue NoMethodError
34
+ abort "Unknown command: #{command}"
35
+ end
36
+
37
+ private
38
+
39
+ def parse(args)
40
+ @parser = OptionParser.new do |o|
41
+ o.banner = "Usage: elelem [command] [options] [args]"
42
+ o.separator "\nCommands:"
43
+ o.separator " chat Interactive REPL (default)"
44
+ o.separator " ask <prompt> One-shot query (reads stdin if piped)"
45
+ o.separator " files Output files as XML (no options)"
46
+ o.separator " help Show this help"
47
+ o.separator "\nOptions:"
48
+ o.on("-p", "--provider NAME", "ollama, anthropic, vertex, openai") { |p| @provider = p }
49
+ o.on("-m", "--model NAME", "Override default model") { |m| @model = m }
50
+ o.on("-h", "--help") { puts o; exit }
51
+ end
52
+ @parser.parse!(args)
53
+ end
54
+
55
+ def help
56
+ puts @parser
57
+ end
58
+
59
+ def client
60
+ model = @model || MODELS.fetch(@provider)
61
+ PROVIDERS.fetch(@provider).call(model)
62
+ end
63
+
64
+ def chat = Elelem.start(client)
65
+
66
+ def ask
67
+ abort "Usage: elelem ask <prompt>" if @args.empty?
68
+ prompt = @args.join(" ")
69
+ prompt = "#{prompt}\n\n```\n#{$stdin.read}\n```" if $stdin.stat.pipe?
70
+ Elelem::Terminal.new.markdown Elelem.ask(client, prompt)
71
+ end
72
+
73
+ def files
74
+ files = $stdin.stat.pipe? ? $stdin.readlines : `git ls-files`.lines
75
+ puts "<documents>"
76
+ files.each_with_index do |line, i|
77
+ path = line.strip
78
+ next if path.empty? || !File.file?(path)
79
+ puts %Q{<document index="#{i + 1}"><source>#{path}</source><content><![CDATA[#{File.read(path)}]]></content></document>}
80
+ end
81
+ puts "</documents>"
82
+ end
8
83
  end
9
84
 
10
- Elelem::Application.start
85
+ App.new(ARGV).run