Commit fdabdd6

mo khan <mo@mokhan.ca>
2026-01-19 16:50:22
feat: add repo map to system prompt
1 parent 49fe061
lib/elelem/agent.rb
@@ -87,17 +87,64 @@ module Elelem
 
     def system_prompt
       prompt = <<~PROMPT
-        Terminal coding agent. Be concise. Act directly, Verify your work. Use markdown.
+        Terminal coding agent. Be concise. Verify your work.
 
-        # Editing files
-        Use sed for changes: `sed -i'' 's/search/replace/' file`
-        Escape special chars: / & \\ [ ] . *
-        For multi-line or complex edits, use write.
+        # Tools
+        - read: file contents
+        - write: create/overwrite file
+        - execute: shell command
 
+        # Editing
+        Use sed: `sed -i'' 's/old/new/' file`
+        Escape: / & \\ [ ] . *
+        Multi-line: use write
+
+        # Policy
+        - Explain before non-trivial commands
+        - Verify changes (read file, run tests)
+        - No interactive flags (-i, -p)
+
+        # Environment
         pwd: #{Dir.pwd}
+        platform: #{RUBY_PLATFORM.split("-").last}
+        date: #{Date.today}
+        #{git_branch}
+
+        # Codebase
+        #{repo_map}
       PROMPT
       prompt += "\n\n#{IO.read("AGENTS.md")}" if File.exist?("AGENTS.md")
       prompt
     end
+
+    def git_branch
+      return unless File.exist?(".git")
+      "branch: #{`git branch --show-current`.strip}"
+    rescue
+      nil
+    end
+
+    def repo_map
+      exts = %w[.rb .js .ts .py .go .rs]
+      patterns = {
+        ".rb" => /^\s*(class |module |def )/,
+        ".js" => /^\s*(function |class |const \w+ = (?:async )?\(|export )/,
+        ".ts" => /^\s*(function |class |const |export |interface )/,
+        ".py" => /^\s*(class |def |async def )/,
+        ".go" => /^\s*(func |type )/,
+        ".rs" => /^\s*(fn |struct |impl |pub fn )/
+      }
+
+      Dir.glob("**/*.{rb,js,ts,py,go,rs}").reject { |f| f.start_with?("vendor/", "node_modules/") }
+        .flat_map do |path|
+          pattern = patterns[File.extname(path)]
+          next [] unless pattern
+          File.readlines(path).filter_map.with_index do |line, i|
+            "#{path}:#{i + 1}: #{line.strip}" if line.match?(pattern)
+          end
+        rescue
+          []
+        end.first(100).join("\n")
+    end
   end
 end
lib/elelem.rb
@@ -1,12 +1,13 @@
 # frozen_string_literal: true
 
+require "date"
 require "fileutils"
 require "json"
 require "net/llm"
 require "open3"
 require "pathname"
-require "stringio"
 require "reline"
+require "stringio"
 
 require_relative "elelem/agent"
 require_relative "elelem/terminal"
elelem.gemspec
@@ -12,8 +12,8 @@ Gem::Specification.new do |spec|
   spec.description = "A minimal coding agent supporting Ollama, Anthropic, OpenAI, and VertexAI."
   spec.homepage = "https://src.mokhan.ca/xlgmokha/elelem"
   spec.license = "MIT"
-  spec.required_ruby_version = ">= 3.4.0"
-  spec.required_rubygems_version = ">= 3.3.11"
+  spec.required_ruby_version = ">= 4.0.0"
+  spec.required_rubygems_version = ">= 4.0.0"
   spec.metadata["allowed_push_host"] = "https://rubygems.org"
   spec.metadata["homepage_uri"] = spec.homepage
   spec.metadata["source_code_uri"] = "https://src.mokhan.ca/xlgmokha/elelem"
@@ -40,10 +40,12 @@ Gem::Specification.new do |spec|
   spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
   spec.require_paths = ["lib"]
 
+  spec.add_dependency "date", "~> 3.0"
   spec.add_dependency "fileutils", "~> 1.0"
   spec.add_dependency "json", "~> 2.0"
   spec.add_dependency "net-llm", "~> 0.5", ">= 0.5.0"
   spec.add_dependency "open3", "~> 0.1"
   spec.add_dependency "pathname", "~> 0.1"
   spec.add_dependency "reline", "~> 0.6"
+  spec.add_dependency "stringio", "~> 3.0"
 end
Gemfile.lock
@@ -2,6 +2,7 @@ PATH
   remote: .
   specs:
     elelem (0.8.0)
+      date (~> 3.0)
       fileutils (~> 1.0)
       json (~> 2.0)
       net-llm (~> 0.5, >= 0.5.0)