elelem 0.5.0 → 0.6.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: 5358e2fd855f1b8848a191c4db7160cc7eb296a73451d56f69da7e67b1b83313
4
- data.tar.gz: 728dcd83f11d131af93a99cc08b68c3141b57c7ee36d69fb038736220e628eb1
3
+ metadata.gz: 9a97a3be43a2528518770e2881fef86138b19ce9394601de922822f9748fe9c8
4
+ data.tar.gz: e87dc58d17f701d9b2fa0a15b05b7f2fbad24a7f71b5836a47f01fe6b216df55
5
5
  SHA512:
6
- metadata.gz: 2bcc2bb0271cb1188a68d390922b59a0c1007aaf8f8980c0981c26d60b75d6cb666c481702d72db92d61db4824402d88a9bbfffce0623b73ba133ca8557270df
7
- data.tar.gz: 1b36b16c23223f574942de9bf72ea46f34d5e090eae8523c53baeccbd64ce26239de21938f80adf673f76326e87c9344e011723cb53407ed5f3df7d9647a1c3c
6
+ metadata.gz: e7b58a5575c8065b1dd9bd020615dc6ec85660b8f5df431f01d28fca90d199608a845aae8e915fd6508c23817f98b2f8c5396e79595d293c1eedbe7f4e9146a7
7
+ data.tar.gz: 6556959f36182acd496d99bc64001bb1ccdff79a95d14ec3116dec1f86a4da928fc35e5f8bc32e84b93161d3013f98f374c2f4188efe9374121e80829e2ca157
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.0] - 2026-01-12
4
+
5
+ ### Added
6
+ - `/env` slash command to capture environment variables for provider connections
7
+ - `/shell` slash command
8
+ - `/provider` and `/model` slash commands
9
+ - Tab completion for commands
10
+ - Help output for `/mode` and `/env` commands
11
+
12
+ ### Changed
13
+ - Renamed `bash` tool to `exec`
14
+ - Tuned system prompt
15
+ - Changed thinking prompt to ellipsis
16
+ - Removed username from system prompt
17
+ - Use pessimistic constraint on net-llm dependency
18
+ - Extracted Terminal class for IO abstraction (enables E2E testing)
19
+
20
+ ### Fixed
21
+ - Prevent infinite looping errors
22
+ - Provide function schema when tool is called with invalid arguments
23
+ - Tab completion for `pass` entries without requiring `show` subcommand
24
+ - Password store symlink support in tab completion
25
+
3
26
  ## [0.5.0] - 2025-01-07
4
27
 
5
28
  ### Added
data/README.md CHANGED
@@ -141,7 +141,7 @@ seven tools, each represented by a JSON schema that the LLM can call.
141
141
 
142
142
  | Tool | Purpose | Parameters |
143
143
  | ---- | ------- | ---------- |
144
- | `bash` | Run shell commands | `cmd`, `args`, `env`, `cwd`, `stdin` |
144
+ | `exec` | Run shell commands | `cmd`, `args`, `env`, `cwd`, `stdin` |
145
145
  | `eval` | Dynamically create new tools | `code` |
146
146
  | `grep` | Search Git‑tracked files | `query` |
147
147
  | `list` | List tracked files | `path` (optional) |
data/lib/elelem/agent.rb CHANGED
@@ -2,45 +2,36 @@
2
2
 
3
3
  module Elelem
4
4
  class Agent
5
- attr_reader :conversation, :client, :toolbox
5
+ PROVIDERS = %w[ollama anthropic openai vertex-ai].freeze
6
+ ANTHROPIC_MODELS = %w[claude-sonnet-4-20250514 claude-opus-4-20250514 claude-haiku-3-5-20241022].freeze
7
+ VERTEX_MODELS = %w[claude-sonnet-4@20250514 claude-opus-4-5@20251101].freeze
8
+ COMMANDS = %w[/env /mode /provider /model /shell /clear /context /exit /help].freeze
9
+ MODES = %w[auto build plan verify].freeze
10
+ ENV_VARS = %w[ANTHROPIC_API_KEY OPENAI_API_KEY OPENAI_BASE_URL OLLAMA_HOST GOOGLE_CLOUD_PROJECT GOOGLE_CLOUD_REGION].freeze
6
11
 
7
- def initialize(client, toolbox)
12
+ attr_reader :conversation, :client, :toolbox, :provider, :terminal
13
+
14
+ def initialize(provider, model, toolbox, terminal: nil)
8
15
  @conversation = Conversation.new
9
- @client = client
16
+ @provider = provider
10
17
  @toolbox = toolbox
18
+ @client = build_client(provider, model)
19
+ @terminal = terminal || Terminal.new(
20
+ commands: COMMANDS,
21
+ modes: MODES,
22
+ providers: PROVIDERS,
23
+ env_vars: ENV_VARS
24
+ )
11
25
  end
12
26
 
13
27
  def repl
14
28
  mode = Set.new([:read])
15
29
 
16
30
  loop do
17
- input = ask?("User> ")
31
+ input = terminal.ask("User> ")
18
32
  break if input.nil?
19
33
  if input.start_with?("/")
20
- case input
21
- when "/mode auto"
22
- mode = Set[:read, :write, :execute]
23
- puts " → Mode: auto (all tools enabled)"
24
- when "/mode build"
25
- mode = Set[:read, :write]
26
- puts " → Mode: build (read + write)"
27
- when "/mode plan"
28
- mode = Set[:read]
29
- puts " → Mode: plan (read-only)"
30
- when "/mode verify"
31
- mode = Set[:read, :execute]
32
- puts " → Mode: verify (read + execute)"
33
- when "/mode"
34
- puts " Mode: #{mode.to_a.inspect}"
35
- puts " Tools: #{toolbox.tools_for(mode).map { |t| t.dig(:function, :name) }}"
36
- when "/exit" then exit
37
- when "/clear"
38
- conversation.clear
39
- puts " → Conversation cleared"
40
- when "/context" then puts conversation.dump(mode)
41
- else
42
- puts help_banner
43
- end
34
+ handle_command(input, mode)
44
35
  else
45
36
  conversation.add(role: :user, content: input)
46
37
  result = execute_turn(conversation.history_for(mode), tools: toolbox.tools_for(mode))
@@ -51,13 +42,111 @@ module Elelem
51
42
 
52
43
  private
53
44
 
54
- def ask?(text)
55
- Reline.readline(text, true)&.strip
45
+ def handle_command(input, mode)
46
+ case input
47
+ when "/mode auto"
48
+ mode.replace([:read, :write, :execute])
49
+ terminal.say " → Mode: auto (all tools enabled)"
50
+ when "/mode build"
51
+ mode.replace([:read, :write])
52
+ terminal.say " → Mode: build (read + write)"
53
+ when "/mode plan"
54
+ mode.replace([:read])
55
+ terminal.say " → Mode: plan (read-only)"
56
+ when "/mode verify"
57
+ mode.replace([:read, :execute])
58
+ terminal.say " → Mode: verify (read + execute)"
59
+ when "/mode"
60
+ terminal.say " Usage: /mode [auto|build|plan|verify]"
61
+ terminal.say ""
62
+ terminal.say " Provider: #{provider}/#{client.model}"
63
+ terminal.say " Mode: #{mode.to_a.inspect}"
64
+ terminal.say " Tools: #{toolbox.tools_for(mode).map { |t| t.dig(:function, :name) }}"
65
+ when "/exit" then exit
66
+ when "/clear"
67
+ conversation.clear
68
+ terminal.say " → Conversation cleared"
69
+ when "/context"
70
+ terminal.say conversation.dump(mode)
71
+ when "/shell"
72
+ transcript = start_shell
73
+ conversation.add(role: :user, content: transcript) unless transcript.strip.empty?
74
+ terminal.say " → Shell session captured"
75
+ when "/provider"
76
+ terminal.select("Provider?", PROVIDERS) do |selected_provider|
77
+ models = models_for(selected_provider)
78
+ if models.empty?
79
+ terminal.say " ✗ No models available for #{selected_provider}"
80
+ else
81
+ terminal.select("Model?", models) do |m|
82
+ switch_client(selected_provider, m)
83
+ end
84
+ end
85
+ end
86
+ when "/model"
87
+ models = models_for(provider)
88
+ if models.empty?
89
+ terminal.say " ✗ No models available for #{provider}"
90
+ else
91
+ terminal.select("Model?", models) do |m|
92
+ switch_model(m)
93
+ end
94
+ end
95
+ when "/env"
96
+ terminal.say " Usage: /env VAR cmd..."
97
+ terminal.say ""
98
+ ENV_VARS.each do |var|
99
+ value = ENV[var]
100
+ if value
101
+ masked = value.length > 8 ? "#{value[0..3]}...#{value[-4..]}" : "****"
102
+ terminal.say " #{var}=#{masked}"
103
+ else
104
+ terminal.say " #{var}=(not set)"
105
+ end
106
+ end
107
+ when %r{^/env\s+(\w+)\s+(.+)$}
108
+ var_name = $1
109
+ command = $2
110
+ result = Elelem.shell.execute("sh", args: ["-c", command])
111
+ if result["exit_status"].zero?
112
+ value = result["stdout"].lines.first&.strip
113
+ if value && !value.empty?
114
+ ENV[var_name] = value
115
+ terminal.say " → Set #{var_name}"
116
+ else
117
+ terminal.say " ⚠ Command produced no output"
118
+ end
119
+ else
120
+ terminal.say " ⚠ Command failed: #{result['stderr']}"
121
+ end
122
+ else
123
+ terminal.say help_banner
124
+ end
125
+ end
126
+
127
+ def strip_ansi(text)
128
+ text.gsub(/^Script started.*?\n/, '')
129
+ .gsub(/\nScript done.*$/, '')
130
+ .gsub(/\e\[[0-9;]*[a-zA-Z]/, '')
131
+ .gsub(/\e\[\?[0-9]+[hl]/, '')
132
+ .gsub(/[\b]/, '')
133
+ .gsub(/\r/, '')
134
+ end
135
+
136
+ def start_shell
137
+ Tempfile.create do |file|
138
+ system("script -q #{file.path}", chdir: Dir.pwd)
139
+ strip_ansi(File.read(file.path))
140
+ end
56
141
  end
57
142
 
58
143
  def help_banner
59
144
  <<~HELP
145
+ /env VAR cmd...
60
146
  /mode auto build plan verify
147
+ /provider
148
+ /model
149
+ /shell
61
150
  /clear
62
151
  /context
63
152
  /exit
@@ -65,6 +154,53 @@ module Elelem
65
154
  HELP
66
155
  end
67
156
 
157
+ def build_client(provider_name, model = nil)
158
+ model_opts = model ? { model: model } : {}
159
+
160
+ case provider_name
161
+ when "ollama" then Net::Llm::Ollama.new(**model_opts)
162
+ when "anthropic" then Net::Llm::Anthropic.new(**model_opts)
163
+ when "openai" then Net::Llm::OpenAI.new(**model_opts)
164
+ when "vertex-ai" then Net::Llm::VertexAI.new(**model_opts)
165
+ else
166
+ raise Error, "Unknown provider: #{provider_name}"
167
+ end
168
+ end
169
+
170
+ def models_for(provider_name)
171
+ case provider_name
172
+ when "ollama"
173
+ client_for_models = provider_name == provider ? client : build_client(provider_name)
174
+ client_for_models.tags["models"]&.map { |m| m["name"] } || []
175
+ when "openai"
176
+ client_for_models = provider_name == provider ? client : build_client(provider_name)
177
+ client_for_models.models["data"]&.map { |m| m["id"] } || []
178
+ when "anthropic"
179
+ ANTHROPIC_MODELS
180
+ when "vertex-ai"
181
+ VERTEX_MODELS
182
+ else
183
+ []
184
+ end
185
+ rescue KeyError => e
186
+ terminal.say " ⚠ Missing credentials: #{e.message}"
187
+ []
188
+ rescue => e
189
+ terminal.say " ⚠ Could not fetch models: #{e.message}"
190
+ []
191
+ end
192
+
193
+ def switch_client(new_provider, model)
194
+ @provider = new_provider
195
+ @client = build_client(new_provider, model)
196
+ terminal.say " → Switched to #{new_provider}/#{client.model}"
197
+ end
198
+
199
+ def switch_model(model)
200
+ @client = build_client(provider, model)
201
+ terminal.say " → Switched to #{provider}/#{client.model}"
202
+ end
203
+
68
204
  def format_tool_call_result(result)
69
205
  return if result.nil?
70
206
  return result["stdout"] if result["stdout"]
@@ -74,6 +210,17 @@ module Elelem
74
210
  ""
75
211
  end
76
212
 
213
+ def truncate_output(text, max_lines: 30)
214
+ return text if text.nil? || text.empty?
215
+
216
+ lines = text.to_s.lines
217
+ if lines.size > max_lines
218
+ lines.first(max_lines).join + "\n... (#{lines.size - max_lines} more lines)"
219
+ else
220
+ text
221
+ end
222
+ end
223
+
77
224
  def format_tool_calls_for_api(tool_calls)
78
225
  tool_calls.map do |tc|
79
226
  args = openai_client? ? JSON.dump(tc[:arguments]) : tc[:arguments]
@@ -91,39 +238,43 @@ module Elelem
91
238
 
92
239
  def execute_turn(messages, tools:)
93
240
  turn_context = []
241
+ errors = 0
94
242
 
95
243
  loop do
96
244
  content = ""
97
245
  tool_calls = []
98
246
 
99
- print "Thinking> "
100
- client.fetch(messages + turn_context, tools) do |chunk|
101
- case chunk[:type]
102
- when :delta
103
- print chunk[:thinking] if chunk[:thinking]
104
- content += chunk[:content] if chunk[:content]
105
- when :complete
106
- content = chunk[:content] if chunk[:content]
107
- tool_calls = chunk[:tool_calls] || []
247
+ terminal.write "Thinking... "
248
+ begin
249
+ client.fetch(messages + turn_context, tools) do |chunk|
250
+ case chunk[:type]
251
+ when :delta
252
+ terminal.write chunk[:thinking] if chunk[:thinking]
253
+ content += chunk[:content] if chunk[:content]
254
+ when :complete
255
+ content = chunk[:content] if chunk[:content]
256
+ tool_calls = chunk[:tool_calls] || []
257
+ end
108
258
  end
259
+ rescue => e
260
+ terminal.say "\n ✗ API Error: #{e.message}"
261
+ return { role: "assistant", content: "[Error: #{e.message}]" }
109
262
  end
110
263
 
111
- puts "\nAssistant> #{content}" unless content.to_s.empty?
264
+ terminal.say "\nAssistant> #{content}" unless content.to_s.empty?
112
265
  api_tool_calls = tool_calls.any? ? format_tool_calls_for_api(tool_calls) : nil
113
266
  turn_context << { role: "assistant", content: content, tool_calls: api_tool_calls }.compact
114
267
 
115
268
  if tool_calls.any?
116
269
  tool_calls.each do |call|
117
- name = call[:name]
118
- args = call[:arguments]
119
-
120
- puts "\nTool> #{name}(#{args})"
270
+ name, args = call[:name], call[:arguments]
271
+ terminal.say "\nTool> #{name}(#{args})"
121
272
  result = toolbox.run_tool(name, args)
122
- puts format_tool_call_result(result)
273
+ terminal.say truncate_output(format_tool_call_result(result))
123
274
  turn_context << { role: "tool", tool_call_id: call[:id], content: JSON.dump(result) }
275
+ errors += 1 if result[:error]
124
276
  end
125
-
126
- tool_calls = []
277
+ return { role: "assistant", content: "[Stopped: too many errors]" } if errors >= 3
127
278
  next
128
279
  end
129
280
 
@@ -15,27 +15,13 @@ module Elelem
15
15
  type: :string,
16
16
  desc: "Model name (uses provider default if not specified)"
17
17
  def chat(*)
18
- client = build_client
19
- say "Agent (#{options[:provider]}/#{client.model})", :green
20
- agent = Agent.new(client, Toolbox.new)
18
+ provider = options[:provider]
19
+ model = options[:model]
20
+ say "Agent (#{provider})", :green
21
+ agent = Agent.new(provider, model, Toolbox.new)
21
22
  agent.repl
22
23
  end
23
24
 
24
- private
25
-
26
- def build_client
27
- model_opts = options[:model] ? { model: options[:model] } : {}
28
-
29
- case options[:provider]
30
- when "ollama" then Net::Llm::Ollama.new(**model_opts)
31
- when "anthropic" then Net::Llm::Anthropic.new(**model_opts)
32
- when "openai" then Net::Llm::OpenAI.new(**model_opts)
33
- when "vertex-ai" then Net::Llm::VertexAI.new(**model_opts)
34
- else
35
- raise Error, "Unknown provider: #{options[:provider]}. Use: #{PROVIDERS.join(', ')}"
36
- end
37
- end
38
-
39
25
  desc "files", "Generate CXML of the files"
40
26
  def files
41
27
  puts '<documents>'
@@ -1,15 +1,12 @@
1
- You are a reasoning coding and system agent.
1
+ You are a trusted terminal agent. You act on behalf of the user - executing tasks directly through bash, files, and git. Be capable, be direct, be done.
2
+
3
+ ## Principles
4
+
5
+ - Act, don't explain. Execute the task.
6
+ - Read before write. Understand existing code first.
7
+ - Small focused changes. One thing at a time.
8
+ - Verify your work. Run tests, check output.
2
9
 
3
10
  ## System
4
11
 
5
- Operating System: <%= `uname -a` %>
6
- USER: <%= ENV['USER'] %>
7
- HOME: <%= ENV['HOME'] %>
8
- SHELL: <%= ENV['SHELL'] %>
9
- PATH: <%= ENV['PATH'] %>
10
- PWD: <%= ENV['PWD'] %>
11
- LANG: <%= ENV['LANG'] %>
12
- EDITOR: <%= ENV['EDITOR'] %>
13
- LOGNAME: <%= ENV['LOGNAME'] %>
14
- TERM: <%= ENV['TERM'] %>
15
- MAIL: <%= ENV['MAIL'] %>
12
+ <%= `uname -s`.strip %> · <%= ENV['PWD'] %>
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Elelem
4
+ class Terminal
5
+ def initialize(commands: [], modes: [], providers: [], env_vars: [])
6
+ @commands = commands
7
+ @modes = modes
8
+ @providers = providers
9
+ @env_vars = env_vars
10
+ setup_completion
11
+ end
12
+
13
+ def ask(prompt)
14
+ Reline.readline(prompt, true)&.strip
15
+ end
16
+
17
+ def say(message)
18
+ $stdout.puts message
19
+ end
20
+
21
+ def write(message)
22
+ $stdout.print message
23
+ end
24
+
25
+ def select(question, options, &block)
26
+ CLI::UI::Prompt.ask(question) do |handler|
27
+ options.each do |option|
28
+ handler.option(option) { |selected| block.call(selected) }
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def setup_completion
36
+ Reline.autocompletion = true
37
+ Reline.completion_proc = ->(target, preposing) { complete(target, preposing) }
38
+ end
39
+
40
+ def complete(target, preposing)
41
+ line = "#{preposing}#{target}"
42
+
43
+ if line.start_with?('/') && !preposing.include?(' ')
44
+ return @commands.select { |c| c.start_with?(line) }
45
+ end
46
+
47
+ case preposing.strip
48
+ when '/mode'
49
+ @modes.select { |m| m.start_with?(target) }
50
+ when '/provider'
51
+ @providers.select { |p| p.start_with?(target) }
52
+ when '/env'
53
+ @env_vars.select { |v| v.start_with?(target) }
54
+ when %r{^/env\s+\w+\s+pass(\s+show)?\s*$}
55
+ subcommands = %w[show ls insert generate edit rm]
56
+ matches = subcommands.select { |c| c.start_with?(target) }
57
+ matches.any? ? matches : complete_pass_entries(target)
58
+ when %r{^/env\s+\w+$}
59
+ complete_commands(target)
60
+ else
61
+ complete_files(target)
62
+ end
63
+ end
64
+
65
+ def complete_commands(target)
66
+ result = Elelem.shell.execute("bash", args: ["-c", "compgen -c #{target}"])
67
+ result["stdout"].lines.map(&:strip).first(20)
68
+ end
69
+
70
+ def complete_files(target)
71
+ result = Elelem.shell.execute("bash", args: ["-c", "compgen -f #{target}"])
72
+ result["stdout"].lines.map(&:strip).first(20)
73
+ end
74
+
75
+ def complete_pass_entries(target)
76
+ store = ENV.fetch("PASSWORD_STORE_DIR", File.expand_path("~/.password-store"))
77
+ result = Elelem.shell.execute("find", args: ["-L", store, "-name", "*.gpg"])
78
+ result["stdout"].lines.map { |l|
79
+ l.strip.sub("#{store}/", "").sub(/\.gpg$/, "")
80
+ }.select { |e| e.start_with?(target) }.first(20)
81
+ end
82
+ end
83
+ end
data/lib/elelem/tool.rb CHANGED
@@ -12,7 +12,9 @@ module Elelem
12
12
 
13
13
  def call(args)
14
14
  unless valid?(args)
15
- return { error: "Invalid args for #{@name}", received: args.keys, expected: @schema.dig(:function, :parameters, :required) }
15
+ actual = args.keys
16
+ expected = @schema.dig(:function, :parameters)
17
+ return { error: "Invalid args for #{@name}.", actual: actual, expected: expected }
16
18
  end
17
19
 
18
20
  @block.call(args)
@@ -9,7 +9,7 @@ module Elelem
9
9
  full_path.exist? ? { content: full_path.read } : { error: "File not found: #{path}" }
10
10
  end
11
11
 
12
- BASH_TOOL = Tool.build("bash", "Run shell commands. For git: bash({\"cmd\": \"git\", \"args\": [\"log\", \"--oneline\"]}). Returns stdout/stderr/exit_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|
12
+ EXEC_TOOL = Tool.build("exec", "Run shell commands. Returns stdout/stderr/exit_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|
13
13
  Elelem.shell.execute(
14
14
  args["cmd"],
15
15
  args: args["args"] || [],
@@ -38,10 +38,11 @@ module Elelem
38
38
  end
39
39
 
40
40
  TOOL_ALIASES = {
41
- "exec" => "bash",
42
- "execute" => "bash",
41
+ "bash" => "exec",
42
+ "execute" => "exec",
43
43
  "open" => "read",
44
44
  "search" => "grep",
45
+ "sh" => "exec",
45
46
  }
46
47
 
47
48
  attr_reader :tools
@@ -50,7 +51,7 @@ module Elelem
50
51
  @tools_by_name = {}
51
52
  @tools = { read: [], write: [], execute: [] }
52
53
  add_tool(eval_tool(binding), :execute)
53
- add_tool(BASH_TOOL, :execute)
54
+ add_tool(EXEC_TOOL, :execute)
54
55
  add_tool(GREP_TOOL, :read)
55
56
  add_tool(LIST_TOOL, :read)
56
57
  add_tool(PATCH_TOOL, :write)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Elelem
4
- VERSION = "0.5.0"
5
- end
4
+ VERSION = "0.6.0"
5
+ end
data/lib/elelem.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cli/ui"
3
4
  require "erb"
4
5
  require "fileutils"
5
6
  require "json"
@@ -16,6 +17,7 @@ require "timeout"
16
17
  require_relative "elelem/agent"
17
18
  require_relative "elelem/application"
18
19
  require_relative "elelem/conversation"
20
+ require_relative "elelem/terminal"
19
21
  require_relative "elelem/tool"
20
22
  require_relative "elelem/toolbox"
21
23
  require_relative "elelem/version"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elelem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
@@ -9,6 +9,20 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: cli-ui
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: erb
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -201,6 +215,7 @@ files:
201
215
  - lib/elelem/application.rb
202
216
  - lib/elelem/conversation.rb
203
217
  - lib/elelem/system_prompt.erb
218
+ - lib/elelem/terminal.rb
204
219
  - lib/elelem/tool.rb
205
220
  - lib/elelem/toolbox.rb
206
221
  - lib/elelem/version.rb
@@ -226,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
241
  - !ruby/object:Gem::Version
227
242
  version: 3.3.11
228
243
  requirements: []
229
- rubygems_version: 3.7.2
244
+ rubygems_version: 3.6.9
230
245
  specification_version: 4
231
246
  summary: A minimal coding agent for LLMs.
232
247
  test_files: []