Commit 1f9e459

mo khan <mo@mokhan.ca>
2026-01-12 20:45:43
feat: add git status section to system prompt
1 parent cb5b001
lib/elelem/git_context.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+module Elelem
+  class GitContext
+    MAX_DIFF_LINES = 100
+
+    def initialize(shell = Elelem.shell)
+      @shell = shell
+    end
+
+    def to_s
+      return "" unless git_repo?
+
+      parts = []
+      parts << "Branch: #{branch}" if branch
+      parts << status_section if status.any?
+      parts << diff_section if staged_diff.any? || unstaged_diff.any?
+      parts << recent_commits_section if recent_commits.any?
+      parts.join("\n\n")
+    end
+
+    private
+
+    def git_repo?
+      @shell.execute("git", args: ["rev-parse", "--git-dir"])["exit_status"].zero?
+    end
+
+    def branch
+      @branch ||= @shell.execute("git", args: ["branch", "--show-current"])["stdout"].strip
+    end
+
+    def status
+      @status ||= @shell.execute("git", args: ["status", "--porcelain"])["stdout"].lines.map(&:strip)
+    end
+
+    def staged_diff
+      @staged_diff ||= @shell.execute("git", args: ["diff", "--cached", "--stat"])["stdout"].lines
+    end
+
+    def unstaged_diff
+      @unstaged_diff ||= @shell.execute("git", args: ["diff", "--stat"])["stdout"].lines
+    end
+
+    def recent_commits
+      @recent_commits ||= @shell.execute("git", args: ["log", "--oneline", "-5"])["stdout"].lines.map(&:strip)
+    end
+
+    def status_section
+      modified = status.select { |l| l.start_with?(" M", "M ") }.map { |l| l[3..] }
+      added = status.select { |l| l.start_with?("A ", "??") }.map { |l| l[3..] }
+      deleted = status.select { |l| l.start_with?(" D", "D ") }.map { |l| l[3..] }
+
+      lines = []
+      lines << "Modified: #{modified.join(', ')}" if modified.any?
+      lines << "Added: #{added.join(', ')}" if added.any?
+      lines << "Deleted: #{deleted.join(', ')}" if deleted.any?
+      lines.any? ? "Working tree:\n#{lines.join("\n")}" : nil
+    end
+
+    def diff_section
+      lines = []
+      lines << "Staged:\n#{truncate(staged_diff)}" if staged_diff.any?
+      lines << "Unstaged:\n#{truncate(unstaged_diff)}" if unstaged_diff.any?
+      lines.join("\n\n")
+    end
+
+    def recent_commits_section
+      "Recent commits:\n#{recent_commits.join("\n")}"
+    end
+
+    def truncate(lines)
+      if lines.size > MAX_DIFF_LINES
+        lines.first(MAX_DIFF_LINES).join + "\n... (#{lines.size - MAX_DIFF_LINES} more lines)"
+      else
+        lines.join
+      end
+    end
+  end
+end
lib/elelem/system_prompt.erb
@@ -10,3 +10,7 @@ You are a trusted terminal agent. You act on behalf of the user - executing task
 ## System
 
 <%= `uname -s`.strip %> · <%= ENV['PWD'] %>
+
+## Git State
+
+<%= Elelem::GitContext.new.to_s %>
lib/elelem.rb
@@ -17,6 +17,7 @@ require "timeout"
 require_relative "elelem/agent"
 require_relative "elelem/application"
 require_relative "elelem/conversation"
+require_relative "elelem/git_context"
 require_relative "elelem/terminal"
 require_relative "elelem/tool"
 require_relative "elelem/toolbox"
elelem.gemspec
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
     "lib/elelem/agent.rb",
     "lib/elelem/application.rb",
     "lib/elelem/conversation.rb",
+    "lib/elelem/git_context.rb",
     "lib/elelem/system_prompt.erb",
     "lib/elelem/terminal.rb",
     "lib/elelem/tool.rb",