feat(rtk): add JS-native git-log filter (#2423)

Compress git log output via dedicated RTK filter: keep commit headers,
Author/Date, subject; drop body padding, decoration, embedded diff lines.
Wire into autodetect (git-log prioritized before git-diff) and registry.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
KunN-21
2026-07-07 12:02:56 +07:00
committed by decolua
co-authored by Cursor
parent bbae990b92
commit 19281b5524
6 changed files with 329 additions and 21 deletions
+5 -2
View File
@@ -1,9 +1,10 @@
// Port of auto_detect_filter (rtk/src/cmds/system/pipe_cmd.rs:132-188) + JS extras
// Order: git-diff → git-status → build-output → grep → find → tree → ls → search-list
// → read-numbered → dedup-log → smart-truncate → null
// Detection order: git-log → git-diff → git-status → build-output → grep → find → tree → ls → search-list
// → read-numbered → dedup-log → smart-truncate → null
import { DETECT_WINDOW, READ_NUMBERED_MIN_HIT_RATIO, SMART_TRUNCATE_MIN_LINES } from "./constants.js";
import { gitDiff } from "./filters/gitDiff.js";
import { gitStatus } from "./filters/gitStatus.js";
import { gitLog } from "./filters/gitLog.js";
import { buildOutput } from "./filters/buildOutput.js";
import { grep } from "./filters/grep.js";
import { find } from "./filters/find.js";
@@ -17,6 +18,7 @@ import { searchList, SEARCH_LIST_HEADER_RE } from "./filters/searchList.js";
const RE_GIT_DIFF = /^diff --git /m;
const RE_GIT_DIFF_HUNK = /^@@ /m;
const RE_GIT_STATUS = /^On branch |^nothing to commit|^Changes (not |to be )|^Untracked files:/m;
const RE_GIT_LOG = /^[*|/\\ ]*commit [0-9a-f]{7,40}$/m;
const RE_PORCELAIN = /^[ MADRCU?!][ MADRCU?!] \S/m;
const RE_BUILD_OUTPUT = /^(npm (warn|error|ERR!)|yarn (warn|error)|\s*Compiling\s+\S+|\s*Downloading\s+\S+|added \d+ package|\[ERROR\]|BUILD (SUCCESS|FAILED)|\s*Finished\s+|Successfully (installed|built)|ERROR:)/im;
const RE_TREE_GLYPH = /[├└]──|│ /;
@@ -27,6 +29,7 @@ export function autoDetectFilter(text) {
// Rust: floor_char_boundary to avoid UTF-8 split — JS .slice() by char is safe
const head = text.length > DETECT_WINDOW ? text.slice(0, DETECT_WINDOW) : text;
if (RE_GIT_LOG.test(head)) return gitLog;
if (RE_GIT_DIFF.test(head) || RE_GIT_DIFF_HUNK.test(head)) return gitDiff;
if (RE_GIT_STATUS.test(head)) return gitStatus;
+1
View File
@@ -4,6 +4,7 @@ export const MIN_COMPRESS_SIZE = 500; // bytes; skip tiny blobs
export const DETECT_WINDOW = 1024; // autodetect peeks first N chars
export const GIT_DIFF_HUNK_MAX_LINES = 100; // per-hunk line cap
export const GIT_DIFF_CONTEXT_KEEP = 3; // context lines around changes
export const GIT_LOG_MAX_LINES = 200; // gitLog line cap
export const DEDUP_LINE_MAX = 2000; // dedupLog truncation cap
// Rust pipe_cmd.rs parity caps
+99
View File
@@ -0,0 +1,99 @@
// JS-native git-log filter
// Compresses `git log` output: keeps commit headers, subjects, Author/Date;
// drops body padding, decoration, embedded diff lines.
import { GIT_LOG_MAX_LINES } from "../constants.js";
export function gitLog(text, maxLines = GIT_LOG_MAX_LINES) {
if (!text) return "";
const input = String(text);
const lines = input.split("\n");
const out = [];
let skipped = 0;
let inCommit = false;
let subjectSeen = false;
function pushLine(l) {
if (out.length < maxLines) {
out.push(l);
return true;
}
skipped++;
return false;
}
for (let i = 0; i < lines.length; i++) {
const raw = lines[i];
const line = raw.trimEnd();
const trimmed = line.trim();
// commit <sha> header — starts new commit entry
// Also matched with leading graph decoration (`* commit abc1234...` — --graph without --oneline)
if (/^commit [0-9a-f]{7,40}$/i.test(trimmed) || /^[*|/\\ ]+commit [0-9a-f]{7,40}/i.test(trimmed)) {
inCommit = true;
subjectSeen = false;
pushLine(line);
continue;
}
if (inCommit) {
// Author / Date — keep as-is (already column 0 in raw, or graph-prefix stripped by commit-header match)
if (/^[*|/\\ ]*(Author|Date):/i.test(trimmed)) {
pushLine(trimmed);
continue;
}
// blank — skip
if (trimmed === "") continue;
// indented subject (4 spaces, optionally preceded by graph decoration) — first one is subject
if (!subjectSeen && /^[*|/\\ ]* \S/.test(line)) {
pushLine(" Subject: " + trimmed);
subjectSeen = true;
continue;
}
// stat summary: "N file(s) changed, N insertions(+), N deletions(-)"
if (/^\d+ file\w* changed/.test(trimmed)) {
pushLine(" " + trimmed);
continue;
}
// embedded diff header — one-line marker
if (/^diff --git /.test(trimmed)) {
pushLine(" ... diff body omitted");
continue;
}
// everything else in commit body — drop
continue;
}
// Not in a commit block (--oneline / --graph modes):
// Graph decoration + sha + subject: "*|/\\ <sha7> <subject>"
const graphMatch = trimmed.match(/^[*|/\\ ]+([0-9a-f]{7,40}\s+.+)/i);
if (graphMatch) {
pushLine(graphMatch[1]);
continue;
}
// Plain oneline: "<sha7> <subject>"
if (/^[0-9a-f]{7,40}\s+/.test(trimmed)) {
pushLine(trimmed);
continue;
}
// Pure graph decoration (no sha) — drop
if (/^[*|/\\ ]+$/.test(trimmed) && /[*|/\\]/.test(trimmed)) {
continue;
}
// catch-all pass-through
pushLine(trimmed);
}
if (skipped > 0) out.push(`... (${skipped} more lines)`);
const result = out.join("\n");
if (!result && input) return input;
if (result.length > input.length) return input;
return result;
}
gitLog.filterName = "git-log";
+2
View File
@@ -1,6 +1,7 @@
import { FILTERS } from "./constants.js";
import { gitDiff } from "./filters/gitDiff.js";
import { gitStatus } from "./filters/gitStatus.js";
import { gitLog } from "./filters/gitLog.js";
import { grep } from "./filters/grep.js";
import { find } from "./filters/find.js";
import { dedupLog } from "./filters/dedupLog.js";
@@ -13,6 +14,7 @@ import { searchList } from "./filters/searchList.js";
const REGISTRY = {
[FILTERS.GIT_DIFF]: gitDiff,
[FILTERS.GIT_STATUS]: gitStatus,
[FILTERS.GIT_LOG]: gitLog,
[FILTERS.GREP]: grep,
[FILTERS.FIND]: find,
[FILTERS.DEDUP_LOG]: dedupLog,