elelem 0.10.0 → 0.12.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -195
  3. data/exe/elelem +7 -1
  4. data/lib/elelem/agent.rb +68 -62
  5. data/lib/elelem/cli.rb +116 -0
  6. data/lib/elelem/commands.rb +26 -10
  7. data/lib/elelem/config.rb +17 -0
  8. data/lib/elelem/conversation.rb +1 -0
  9. data/lib/elelem/input.rb +51 -0
  10. data/lib/elelem/null_input.rb +8 -0
  11. data/lib/elelem/null_output.rb +7 -0
  12. data/lib/elelem/null_tool.rb +18 -0
  13. data/lib/elelem/output.rb +55 -0
  14. data/lib/elelem/plugins.rb +20 -27
  15. data/lib/elelem/prompts/default.erb +3 -0
  16. data/lib/elelem/registration.rb +37 -0
  17. data/lib/elelem/registry.rb +68 -0
  18. data/lib/elelem/repl.rb +34 -0
  19. data/lib/elelem/result.rb +27 -0
  20. data/lib/elelem/schema.rb +20 -0
  21. data/lib/elelem/session.rb +17 -0
  22. data/lib/elelem/slash_command.rb +18 -0
  23. data/lib/elelem/stub_provider.rb +15 -0
  24. data/lib/elelem/system_prompt.rb +12 -135
  25. data/lib/elelem/tool.rb +7 -12
  26. data/lib/elelem/toolbox.rb +40 -31
  27. data/lib/elelem/transcript.rb +26 -0
  28. data/lib/elelem/version.rb +2 -2
  29. data/lib/elelem.rb +28 -113
  30. metadata +48 -155
  31. data/CHANGELOG.md +0 -309
  32. data/lib/elelem/mcp/oauth.rb +0 -217
  33. data/lib/elelem/mcp/token_storage.rb +0 -60
  34. data/lib/elelem/mcp.rb +0 -243
  35. data/lib/elelem/net/claude.rb +0 -202
  36. data/lib/elelem/net/ollama.rb +0 -81
  37. data/lib/elelem/net/openai.rb +0 -88
  38. data/lib/elelem/net.rb +0 -13
  39. data/lib/elelem/permissions.rb +0 -45
  40. data/lib/elelem/plugins/builtins.rb +0 -96
  41. data/lib/elelem/plugins/edit.rb +0 -15
  42. data/lib/elelem/plugins/eval.rb +0 -20
  43. data/lib/elelem/plugins/execute.rb +0 -18
  44. data/lib/elelem/plugins/git.rb +0 -20
  45. data/lib/elelem/plugins/glob.rb +0 -13
  46. data/lib/elelem/plugins/grep.rb +0 -21
  47. data/lib/elelem/plugins/list.rb +0 -14
  48. data/lib/elelem/plugins/mcp.rb +0 -20
  49. data/lib/elelem/plugins/permissions.json +0 -6
  50. data/lib/elelem/plugins/read.rb +0 -21
  51. data/lib/elelem/plugins/task.rb +0 -14
  52. data/lib/elelem/plugins/tools.rb +0 -13
  53. data/lib/elelem/plugins/verify.rb +0 -47
  54. data/lib/elelem/plugins/write.rb +0 -34
  55. data/lib/elelem/plugins/zz_confirm.rb +0 -9
  56. data/lib/elelem/terminal.rb +0 -103
@@ -10,8 +10,16 @@ module Elelem
10
10
  @hooks = { before: Hash.new { |h, k| h[k] = [] }, after: Hash.new { |h, k| h[k] = [] } }
11
11
  end
12
12
 
13
- def add(name, description:, params: {}, required: [], aliases: [], &fn)
14
- tool = Tool.new(name, description: description, params: params, required: required, aliases: aliases, &fn)
13
+ def clear!
14
+ @tools.clear
15
+ @aliases.clear
16
+ @hooks[:before].clear
17
+ @hooks[:after].clear
18
+ end
19
+
20
+ def add(name, description:, params: {}, required: [], aliases: [], &handler)
21
+ schema = Schema.new(params: params, required: required)
22
+ tool = Tool.new(name, description: description, schema: schema, aliases: aliases, &handler)
15
23
  @tools[name] = tool
16
24
  tool.aliases.each { |a| @aliases[a] = name }
17
25
  end
@@ -24,33 +32,15 @@ module Elelem
24
32
  @hooks[:after][tool_name] << block
25
33
  end
26
34
 
27
- def header(name, args, state: "+")
28
- tool = tool_for(name)
29
- color = tool ? "36" : "33"
30
- name = tool&.name || "#{name}?"
31
- "\n#{state} \e[#{color}m#{name}\e[0m(#{args})"
35
+ def tool_for(name)
36
+ tools.fetch(@aliases.fetch(name, name)) { NullTool.new(name, available: tools.keys) }
32
37
  end
33
38
 
34
39
  def run(name, args)
35
40
  tool = tool_for(name)
36
- return failure(error: "unknown tool: #{name}. Use 'execute' to run shell commands like rg, fd, git.", tools: to_a) unless tool
37
-
38
- errors = tool.validate(args)
39
- return failure(error: errors.join(", ")) if errors.any?
40
-
41
- @hooks[:before][:*].each { |h| h.call(args, tool_name: tool.name) }
42
- @hooks[:before][tool.name].each { |h| h.call(args) }
43
- result = tool.call(args)
44
- @hooks[:after][:*].each { |h| h.call(args, result, tool_name: tool.name) }
45
- @hooks[:after][tool.name].each { |h| h.call(args, result) }
46
- result[:error] ? failure(result) : success(result)
47
- rescue => e
48
- failure(error: e.message, name: name, args: args)
49
- end
50
-
51
- def exec(*args)
52
- command = args.flatten.map { |a| Shellwords.escape(a.to_s) }.join(" ")
53
- run("execute", { "command" => command })
41
+ invalid(tool, args) || to_result(dispatch(tool, args))
42
+ rescue StandardError, ScriptError => e
43
+ failure(name, args, e)
54
44
  end
55
45
 
56
46
  def to_a
@@ -59,16 +49,35 @@ module Elelem
59
49
 
60
50
  private
61
51
 
62
- def tool_for(name)
63
- tools[@aliases.fetch(name, name)]
52
+ def invalid(tool, args)
53
+ errors = tool.validate(args)
54
+ Result.failure(error: errors.join(", ")) if errors.any?
55
+ end
56
+
57
+ def to_result(result)
58
+ result[:error] ? Result.failure(result) : Result.success(result)
64
59
  end
65
60
 
66
- def success(payload)
67
- payload.merge(ok: true)
61
+ def failure(name, args, error)
62
+ Elelem.logger.warn("toolbox: #{error.message}\n#{error.backtrace.join("\n")}")
63
+ Result.failure(error: error.message, name: name, args: args)
64
+ end
65
+
66
+ def dispatch(tool, args)
67
+ run_before_hooks(tool, args)
68
+ result = tool.call(args)
69
+ run_after_hooks(tool, args, result)
70
+ result
68
71
  end
69
72
 
70
- def failure(payload)
71
- payload.merge(ok: false)
73
+ def run_before_hooks(tool, args)
74
+ @hooks[:before][:*].each { |h| h.call(args, tool_name: tool.name) }
75
+ @hooks[:before][tool.name].each { |h| h.call(args) }
76
+ end
77
+
78
+ def run_after_hooks(tool, args, result)
79
+ @hooks[:after][:*].each { |h| h.call(args, result, tool_name: tool.name) }
80
+ @hooks[:after][tool.name].each { |h| h.call(args, result) }
72
81
  end
73
82
  end
74
83
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Elelem
4
+ class Transcript
5
+ def initialize(system_prompt: nil)
6
+ @conversation = Conversation.new
7
+ @system_prompt = SystemPrompt.new(system_prompt)
8
+ end
9
+
10
+ def add(role:, content:, **extra)
11
+ @conversation.add(role: role, content: content, **extra)
12
+ end
13
+
14
+ def clear!
15
+ @conversation.clear!
16
+ end
17
+
18
+ def last
19
+ @conversation.last
20
+ end
21
+
22
+ def to_a(extra = [])
23
+ @conversation.to_a(system_prompt: @system_prompt.render) + extra
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Elelem
4
- VERSION = "0.10.0"
5
- end
4
+ VERSION = "0.12.0"
5
+ end
data/lib/elelem.rb CHANGED
@@ -1,141 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "base64"
4
- require "date"
5
- require "digest"
6
3
  require "erb"
7
- require "fileutils"
4
+ require "forwardable"
8
5
  require "json"
9
6
  require "json_schemer"
10
7
  require "logger"
11
- require "net/hippie"
12
8
  require "open3"
13
- require "optparse"
14
9
  require "pathname"
15
- require "reline"
16
- require "securerandom"
17
- require "stringio"
18
- require "tempfile"
19
- require "uri"
20
- require "webrick"
10
+ require "shellwords"
21
11
 
22
12
  require_relative "elelem/agent"
13
+ require_relative "elelem/slash_command"
23
14
  require_relative "elelem/commands"
24
15
  require_relative "elelem/conversation"
25
- require_relative "elelem/mcp"
26
- require_relative "elelem/net"
27
- require_relative "elelem/permissions"
16
+ require_relative "elelem/input"
17
+ require_relative "elelem/null_input"
18
+ require_relative "elelem/output"
19
+ require_relative "elelem/null_output"
28
20
  require_relative "elelem/plugins"
21
+ require_relative "elelem/registration"
22
+ require_relative "elelem/registry"
23
+ require_relative "elelem/repl"
24
+ require_relative "elelem/config"
25
+ require_relative "elelem/result"
26
+ require_relative "elelem/schema"
27
+ require_relative "elelem/session"
28
+ require_relative "elelem/stub_provider"
29
29
  require_relative "elelem/system_prompt"
30
- require_relative "elelem/terminal"
31
30
  require_relative "elelem/tool"
31
+ require_relative "elelem/transcript"
32
+ require_relative "elelem/null_tool"
32
33
  require_relative "elelem/toolbox"
33
34
  require_relative "elelem/version"
34
35
 
35
36
  module Elelem
36
- def self.sh(cmd, args: [], cwd: Dir.pwd, env: {})
37
- output = StringIO.new
38
-
39
- Open3.popen2e(env, cmd, *args, chdir: cwd) do |stdin, out, wait_thr|
40
- stdin.close
41
- out.each_line do |line|
42
- yield line if block_given?
43
- output.write(line)
44
- end
45
-
46
- { exit_status: wait_thr.value.exitstatus, content: output.string }
47
- end
37
+ def self.start(provider: "stub", toolbox: Toolbox.new)
38
+ Repl.new(build(provider: provider, toolbox: toolbox)).run
48
39
  end
49
40
 
50
- def self.start(client, toolbox: Toolbox.new)
51
- agent = Agent.new(client, toolbox: toolbox)
52
- Plugins.setup!(agent)
53
- agent.terminal = Terminal.new(commands: agent.commands.names)
54
- agent.repl
41
+ def self.ask(prompt, provider: "stub", toolbox: Toolbox.new, output: NullOutput.new)
42
+ build(provider: provider, toolbox: toolbox, input: NullInput.new, output: output).turn(prompt)
55
43
  end
56
44
 
57
- def self.ask(client, prompt, toolbox: Toolbox.new)
58
- agent = Agent.new(client, toolbox: toolbox, terminal: Terminal.new(quiet: true))
59
- Plugins.setup!(agent)
60
- agent.turn(prompt)
61
- agent.conversation.last[:content]
45
+ def self.build(provider: "stub", toolbox: Toolbox.new, input: nil, output: nil)
46
+ Config.build_session(provider, toolbox: toolbox, input: input, output: output)
62
47
  end
63
48
 
64
- class CLI
65
- MODELS = {
66
- "ollama" => "gpt-oss:latest",
67
- "anthropic" => "claude-opus-4-5-20250514",
68
- "vertex" => "claude-opus-4-5@20251101",
69
- "openai" => "gpt-4o"
70
- }.freeze
71
-
72
- PROVIDERS = {
73
- "ollama" => ->(model) { Elelem::Net::Ollama.new(model: model, host: ENV.fetch("OLLAMA_HOST", "localhost:11434")) },
74
- "anthropic" => ->(model) { Elelem::Net::Claude.anthropic(model: model, api_key: ENV.fetch("ANTHROPIC_API_KEY")) },
75
- "vertex" => ->(model) { Elelem::Net::Claude.vertex(model: model, project: ENV.fetch("GOOGLE_CLOUD_PROJECT"), region: ENV.fetch("GOOGLE_CLOUD_REGION", "us-east5")) },
76
- "openai" => ->(model) { Elelem::Net::OpenAI.new(model: model, api_key: ENV.fetch("OPENAI_API_KEY")) }
77
- }.freeze
78
-
79
- def initialize(args)
80
- @provider = "ollama"
81
- @model = nil
82
- @args = parse(args)
83
- end
84
-
85
- def run
86
- command = @args.shift || "chat"
87
- send(command.tr("-", "_"))
88
- rescue NoMethodError
89
- abort "Unknown command: #{command}"
90
- end
91
-
92
- private
93
-
94
- def parse(args)
95
- @parser = OptionParser.new do |o|
96
- o.banner = "Usage: elelem [command] [options] [args]"
97
- o.separator "\nCommands:"
98
- o.separator " chat Interactive REPL (default)"
99
- o.separator " ask <prompt> One-shot query (reads stdin if piped)"
100
- o.separator " files Output files as XML (no options)"
101
- o.separator " help Show this help"
102
- o.separator "\nOptions:"
103
- o.on("-p", "--provider NAME", "ollama, anthropic, vertex, openai") { |p| @provider = p }
104
- o.on("-m", "--model NAME", "Override default model") { |m| @model = m }
105
- o.on("-h", "--help") { puts o; exit }
106
- end
107
- @parser.parse!(args)
108
- end
109
-
110
- def help
111
- puts @parser
112
- end
113
-
114
- def client
115
- model = @model || MODELS.fetch(@provider)
116
- PROVIDERS.fetch(@provider).call(model)
117
- end
118
-
119
- def chat
120
- Elelem.start(client)
121
- end
122
-
123
- def ask
124
- abort "Usage: elelem ask <prompt>" if @args.empty?
125
- prompt = @args.join(" ")
126
- prompt = "#{prompt}\n\n```\n#{$stdin.read}\n```" if $stdin.stat.pipe?
127
- Elelem::Terminal.new.markdown Elelem.ask(client, prompt)
128
- end
129
-
130
- def files
131
- files = $stdin.stat.pipe? ? $stdin.readlines : `git ls-files`.lines
132
- puts "<documents>"
133
- files.each_with_index do |line, i|
134
- path = line.strip
135
- next if path.empty? || !File.file?(path)
136
- puts %Q{<document index="#{i + 1}"><source>#{path}</source><content><![CDATA[#{File.read(path)}]]></content></document>}
137
- end
138
- puts "</documents>"
49
+ def self.logger
50
+ @logger ||= Logger.new($stderr).tap do |log|
51
+ log.level = Logger.const_get(ENV.fetch("ELELEM_LOG_LEVEL", "warn").upcase)
139
52
  end
140
53
  end
141
54
  end
55
+
56
+ Elelem.configure { |config| config.provider(:stub) { Elelem::StubProvider.new } }
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.10.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
@@ -10,201 +10,145 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: base64
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '0.1'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '0.1'
26
- - !ruby/object:Gem::Dependency
27
- name: date
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: '3.0'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '3.0'
40
- - !ruby/object:Gem::Dependency
41
- name: digest
13
+ name: erb
42
14
  requirement: !ruby/object:Gem::Requirement
43
15
  requirements:
44
16
  - - "~>"
45
17
  - !ruby/object:Gem::Version
46
- version: '3.0'
18
+ version: '6.0'
47
19
  type: :runtime
48
20
  prerelease: false
49
21
  version_requirements: !ruby/object:Gem::Requirement
50
22
  requirements:
51
23
  - - "~>"
52
24
  - !ruby/object:Gem::Version
53
- version: '3.0'
25
+ version: '6.0'
54
26
  - !ruby/object:Gem::Dependency
55
- name: erb
27
+ name: forwardable
56
28
  requirement: !ruby/object:Gem::Requirement
57
29
  requirements:
58
30
  - - "~>"
59
31
  - !ruby/object:Gem::Version
60
- version: '6.0'
32
+ version: '1.4'
61
33
  type: :runtime
62
34
  prerelease: false
63
35
  version_requirements: !ruby/object:Gem::Requirement
64
36
  requirements:
65
37
  - - "~>"
66
38
  - !ruby/object:Gem::Version
67
- version: '6.0'
39
+ version: '1.4'
68
40
  - !ruby/object:Gem::Dependency
69
- name: fileutils
41
+ name: io-console
70
42
  requirement: !ruby/object:Gem::Requirement
71
43
  requirements:
72
44
  - - "~>"
73
45
  - !ruby/object:Gem::Version
74
- version: '1.0'
46
+ version: '0.9'
75
47
  type: :runtime
76
48
  prerelease: false
77
49
  version_requirements: !ruby/object:Gem::Requirement
78
50
  requirements:
79
51
  - - "~>"
80
52
  - !ruby/object:Gem::Version
81
- version: '1.0'
53
+ version: '0.9'
82
54
  - !ruby/object:Gem::Dependency
83
55
  name: json
84
56
  requirement: !ruby/object:Gem::Requirement
85
57
  requirements:
86
58
  - - "~>"
87
59
  - !ruby/object:Gem::Version
88
- version: '2.0'
60
+ version: '3.0'
89
61
  type: :runtime
90
62
  prerelease: false
91
63
  version_requirements: !ruby/object:Gem::Requirement
92
64
  requirements:
93
65
  - - "~>"
94
66
  - !ruby/object:Gem::Version
95
- version: '2.0'
67
+ version: '3.0'
96
68
  - !ruby/object:Gem::Dependency
97
69
  name: json_schemer
98
70
  requirement: !ruby/object:Gem::Requirement
99
71
  requirements:
100
72
  - - "~>"
101
73
  - !ruby/object:Gem::Version
102
- version: '2.0'
74
+ version: '2.5'
103
75
  type: :runtime
104
76
  prerelease: false
105
77
  version_requirements: !ruby/object:Gem::Requirement
106
78
  requirements:
107
79
  - - "~>"
108
80
  - !ruby/object:Gem::Version
109
- version: '2.0'
81
+ version: '2.5'
110
82
  - !ruby/object:Gem::Dependency
111
83
  name: logger
112
84
  requirement: !ruby/object:Gem::Requirement
113
85
  requirements:
114
86
  - - "~>"
115
87
  - !ruby/object:Gem::Version
116
- version: '1.0'
88
+ version: '1.7'
117
89
  type: :runtime
118
90
  prerelease: false
119
91
  version_requirements: !ruby/object:Gem::Requirement
120
92
  requirements:
121
93
  - - "~>"
122
94
  - !ruby/object:Gem::Version
123
- version: '1.0'
124
- - !ruby/object:Gem::Dependency
125
- name: net-hippie
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: '1.0'
131
- type: :runtime
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: '1.0'
95
+ version: '1.7'
138
96
  - !ruby/object:Gem::Dependency
139
97
  name: open3
140
98
  requirement: !ruby/object:Gem::Requirement
141
99
  requirements:
142
100
  - - "~>"
143
101
  - !ruby/object:Gem::Version
144
- version: '0.1'
102
+ version: '0.2'
145
103
  type: :runtime
146
104
  prerelease: false
147
105
  version_requirements: !ruby/object:Gem::Requirement
148
106
  requirements:
149
107
  - - "~>"
150
108
  - !ruby/object:Gem::Version
151
- version: '0.1'
109
+ version: '0.2'
152
110
  - !ruby/object:Gem::Dependency
153
111
  name: optparse
154
112
  requirement: !ruby/object:Gem::Requirement
155
113
  requirements:
156
114
  - - "~>"
157
115
  - !ruby/object:Gem::Version
158
- version: '0.1'
116
+ version: '0.8'
159
117
  type: :runtime
160
118
  prerelease: false
161
119
  version_requirements: !ruby/object:Gem::Requirement
162
120
  requirements:
163
121
  - - "~>"
164
122
  - !ruby/object:Gem::Version
165
- version: '0.1'
123
+ version: '0.8'
166
124
  - !ruby/object:Gem::Dependency
167
125
  name: pathname
168
126
  requirement: !ruby/object:Gem::Requirement
169
127
  requirements:
170
128
  - - "~>"
171
129
  - !ruby/object:Gem::Version
172
- version: '0.1'
130
+ version: '0.5'
173
131
  type: :runtime
174
132
  prerelease: false
175
133
  version_requirements: !ruby/object:Gem::Requirement
176
134
  requirements:
177
135
  - - "~>"
178
136
  - !ruby/object:Gem::Version
179
- version: '0.1'
137
+ version: '0.5'
180
138
  - !ruby/object:Gem::Dependency
181
139
  name: reline
182
140
  requirement: !ruby/object:Gem::Requirement
183
141
  requirements:
184
142
  - - "~>"
185
143
  - !ruby/object:Gem::Version
186
- version: '0.6'
144
+ version: '0.7'
187
145
  type: :runtime
188
146
  prerelease: false
189
147
  version_requirements: !ruby/object:Gem::Requirement
190
148
  requirements:
191
149
  - - "~>"
192
150
  - !ruby/object:Gem::Version
193
- version: '0.6'
194
- - !ruby/object:Gem::Dependency
195
- name: securerandom
196
- requirement: !ruby/object:Gem::Requirement
197
- requirements:
198
- - - "~>"
199
- - !ruby/object:Gem::Version
200
- version: '0.1'
201
- type: :runtime
202
- prerelease: false
203
- version_requirements: !ruby/object:Gem::Requirement
204
- requirements:
205
- - - "~>"
206
- - !ruby/object:Gem::Version
207
- version: '0.1'
151
+ version: '0.7'
208
152
  - !ruby/object:Gem::Dependency
209
153
  name: shellwords
210
154
  requirement: !ruby/object:Gem::Requirement
@@ -219,34 +163,6 @@ dependencies:
219
163
  - - "~>"
220
164
  - !ruby/object:Gem::Version
221
165
  version: '0.2'
222
- - !ruby/object:Gem::Dependency
223
- name: stringio
224
- requirement: !ruby/object:Gem::Requirement
225
- requirements:
226
- - - "~>"
227
- - !ruby/object:Gem::Version
228
- version: '3.0'
229
- type: :runtime
230
- prerelease: false
231
- version_requirements: !ruby/object:Gem::Requirement
232
- requirements:
233
- - - "~>"
234
- - !ruby/object:Gem::Version
235
- version: '3.0'
236
- - !ruby/object:Gem::Dependency
237
- name: tempfile
238
- requirement: !ruby/object:Gem::Requirement
239
- requirements:
240
- - - "~>"
241
- - !ruby/object:Gem::Version
242
- version: '0.3'
243
- type: :runtime
244
- prerelease: false
245
- version_requirements: !ruby/object:Gem::Requirement
246
- requirements:
247
- - - "~>"
248
- - !ruby/object:Gem::Version
249
- version: '0.3'
250
166
  - !ruby/object:Gem::Dependency
251
167
  name: uri
252
168
  requirement: !ruby/object:Gem::Requirement
@@ -261,21 +177,7 @@ dependencies:
261
177
  - - "~>"
262
178
  - !ruby/object:Gem::Version
263
179
  version: '1.0'
264
- - !ruby/object:Gem::Dependency
265
- name: webrick
266
- requirement: !ruby/object:Gem::Requirement
267
- requirements:
268
- - - "~>"
269
- - !ruby/object:Gem::Version
270
- version: '1.9'
271
- type: :runtime
272
- prerelease: false
273
- version_requirements: !ruby/object:Gem::Requirement
274
- requirements:
275
- - - "~>"
276
- - !ruby/object:Gem::Version
277
- version: '1.9'
278
- description: A minimal coding agent supporting Ollama, Anthropic, OpenAI, and VertexAI.
180
+ description: A minimal coding harness.
279
181
  email:
280
182
  - mo@mokhan.ca
281
183
  executables:
@@ -283,53 +185,44 @@ executables:
283
185
  extensions: []
284
186
  extra_rdoc_files: []
285
187
  files:
286
- - CHANGELOG.md
287
188
  - LICENSE.txt
288
189
  - README.md
289
190
  - Rakefile
290
191
  - exe/elelem
291
192
  - lib/elelem.rb
292
193
  - lib/elelem/agent.rb
194
+ - lib/elelem/cli.rb
293
195
  - lib/elelem/commands.rb
196
+ - lib/elelem/config.rb
294
197
  - lib/elelem/conversation.rb
295
- - lib/elelem/mcp.rb
296
- - lib/elelem/mcp/oauth.rb
297
- - lib/elelem/mcp/token_storage.rb
298
- - lib/elelem/net.rb
299
- - lib/elelem/net/claude.rb
300
- - lib/elelem/net/ollama.rb
301
- - lib/elelem/net/openai.rb
302
- - lib/elelem/permissions.rb
198
+ - lib/elelem/input.rb
199
+ - lib/elelem/null_input.rb
200
+ - lib/elelem/null_output.rb
201
+ - lib/elelem/null_tool.rb
202
+ - lib/elelem/output.rb
303
203
  - lib/elelem/plugins.rb
304
- - lib/elelem/plugins/builtins.rb
305
- - lib/elelem/plugins/edit.rb
306
- - lib/elelem/plugins/eval.rb
307
- - lib/elelem/plugins/execute.rb
308
- - lib/elelem/plugins/git.rb
309
- - lib/elelem/plugins/glob.rb
310
- - lib/elelem/plugins/grep.rb
311
- - lib/elelem/plugins/list.rb
312
- - lib/elelem/plugins/mcp.rb
313
- - lib/elelem/plugins/permissions.json
314
- - lib/elelem/plugins/read.rb
315
- - lib/elelem/plugins/task.rb
316
- - lib/elelem/plugins/tools.rb
317
- - lib/elelem/plugins/verify.rb
318
- - lib/elelem/plugins/write.rb
319
- - lib/elelem/plugins/zz_confirm.rb
204
+ - lib/elelem/prompts/default.erb
205
+ - lib/elelem/registration.rb
206
+ - lib/elelem/registry.rb
207
+ - lib/elelem/repl.rb
208
+ - lib/elelem/result.rb
209
+ - lib/elelem/schema.rb
210
+ - lib/elelem/session.rb
211
+ - lib/elelem/slash_command.rb
212
+ - lib/elelem/stub_provider.rb
320
213
  - lib/elelem/system_prompt.rb
321
- - lib/elelem/terminal.rb
322
214
  - lib/elelem/tool.rb
323
215
  - lib/elelem/toolbox.rb
216
+ - lib/elelem/transcript.rb
324
217
  - lib/elelem/version.rb
325
- homepage: https://src.mokhan.ca/xlgmokha/elelem
218
+ homepage: https://src.mokhan.ca/elelem/elelem
326
219
  licenses:
327
220
  - MIT
328
221
  metadata:
329
222
  allowed_push_host: https://rubygems.org
330
- homepage_uri: https://src.mokhan.ca/xlgmokha/elelem
331
- source_code_uri: https://src.mokhan.ca/xlgmokha/elelem
332
- changelog_uri: https://src.mokhan.ca/xlgmokha/elelem/blob/main/CHANGELOG.md.html
223
+ homepage_uri: https://src.mokhan.ca/elelem/elelem
224
+ source_code_uri: https://src.mokhan.ca/elelem/elelem
225
+ rubygems_mfa_required: 'true'
333
226
  rdoc_options: []
334
227
  require_paths:
335
228
  - lib
@@ -344,7 +237,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
344
237
  - !ruby/object:Gem::Version
345
238
  version: 4.0.0
346
239
  requirements: []
347
- rubygems_version: 4.0.4
240
+ rubygems_version: 4.0.20
348
241
  specification_version: 4
349
- summary: A minimal coding agent for LLMs.
242
+ summary: A minimal coding harness for LLMs.
350
243
  test_files: []