dirge-agent 0.9.0

Minimalistic coding agent written in Rust, optimized for memory footprint and performance
# Compression plugin — init.janet
# Ported from lean-ctx
#
# Loaded AFTER 00-regex.janet (alphabetical sort). The regex functions
# (find, find-all, replace, replace-all, match, compile) are already
# available in the shared Janet environment — no import needed.
#
# Hook: on-tool-end
#   Receives ctx with :tool (string) and :output (string).
#   Returns nil (no change) or calls harness/replace-result with
#   compressed output.
#
# Pipeline:
#   1. strip-ansi       — remove CSI escape sequences
#   2. compress-generic — remove progress bars, spinners, blank-line runs
#   3. tool-specific    — per-command pattern compressors (git, cargo, etc.)

# ---------------------------------------------------------------------------
# ANSI escape stripping
# ---------------------------------------------------------------------------

(def ANSI_CSI_PATTERN '(sequence "\x1b[" (any (set "0-9;")) (set "A-Za-z")))

(defn strip-ansi
  "Remove ANSI CSI escape sequences from text."
  [text]
  (peg/replace-all ANSI_CSI_PATTERN "" text))

# ---------------------------------------------------------------------------
# Generic noise removal
# Pattern inspired by headroom's output sanitization.
# ---------------------------------------------------------------------------

(defn- progress-bar-line?
  "True if the line uses carriage-return overwrite (progress/status bar)."
  [line]
  (not (nil? (find "\r" line))))

(defn- spinner-line?
  "True if the line is a download/spinner noise line."
  [line]
  (or (not (nil? (find "Downloading " line)))
      (not (nil? (find "Downloaded " line)))
      (not (nil? (find "Collecting " line)))))

(defn- noise-line?
  "True if the line is cosmetic noise to be removed."
  [line]
  (or (progress-bar-line? line)
      (spinner-line? line)))

(defn compress-generic
  "Remove progress bars, download spinners, and collapse runs of >3 blank
  lines to a single blank line. Non-matching text passes through unchanged."
  [text]
  (let [lines (string/split "\n" text)
        kept @[]]
    (var blank-run 0)
    (each line lines
      (if (noise-line? line)
        nil  # skip noise lines
        (if (= "" line)
          (++ blank-run)
          (do
            # Flush blank run first
            (when (> blank-run 0)
              (if (<= blank-run 3)
                (repeat blank-run (array/push kept ""))
                (array/push kept ""))
              (set blank-run 0))
            (array/push kept line)))))
    # Flush trailing blank run
    (when (> blank-run 0)
      (if (<= blank-run 3)
        (repeat blank-run (array/push kept ""))
        (array/push kept "")))
    (string/join kept "\n")))

(defn compress-shell
  "Apply generic compression to shell output. Called by tool-specific
  compressors after their own transformations, or directly for
  unrecognized commands."
  [text]
  (-> text
      strip-ansi
      compress-generic))

# ---------------------------------------------------------------------------
# Hook: on-tool-end
# ---------------------------------------------------------------------------

(defn on-tool-end [ctx]
  # Only compress shell tool output — read, grep, etc. don't need it.
  (let [tool (ctx :tool)
        output (ctx :output)
        command (ctx :command)]
    (if (not (or (= tool "bash") (= tool "bash_output")))
      (break nil))
    (if (or (nil? output) (empty? output))
      nil
      (do
        # Try tool-specific compressors in priority order.
        # Each compressor returns nil if it doesn't handle the
        # command; the first non-nil result wins. Falls back to
        # generic compression (ANSI strip, noise removal).
        (def compressed
          (if (and (not (nil? command)) (not (empty? command)))
            (or (git-compress command output)
                (cargo-compress command output)
                (docker-compress command output)
                (kubectl-compress command output)
                (npm-compress command output)
                (pip-compress command output)
                (grep-compress command output)
                (find-compress command output)
                (ls-compress command output)
                (curl-compress command output)
                (compress-shell output))
            (compress-shell output)))
        (when (not= compressed output)
          (harness/replace-result compressed))))))

nil