From d731643fb8f8e022a196f0d2e0005807128f0ca9 Mon Sep 17 00:00:00 2001 From: Patrick szymkowiak Date: Mon, 16 Mar 2026 17:26:50 +0100 Subject: [PATCH 1/2] feat: add 5 new TOML built-in filters (ollama, nx, gradle, spring-boot, jira) New filters for commands not covered by Rust modules: - ollama: strip ANSI spinners, keep final text response (#624) - nx: strip Nx monorepo noise, keep build results (#444) - gradle/gradlew: strip UP-TO-DATE tasks, keep build summary (#147) - spring-boot: strip banner and verbose logs, keep startup/errors (#147) - jira: strip blanks, truncate wide columns (#524) All 5 filters pass inline tests via rtk verify (123/123). Updated builtin filter count: 47 -> 52. Signed-off-by: Patrick szymkowiak --- src/filters/gradle.toml | 35 +++++++++++++++++++++++++++++++++++ src/filters/jira.toml | 20 ++++++++++++++++++++ src/filters/nx.toml | 25 +++++++++++++++++++++++++ src/filters/ollama.toml | 23 +++++++++++++++++++++++ src/filters/spring-boot.toml | 28 ++++++++++++++++++++++++++++ src/toml_filter.rs | 10 +++++----- 6 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 src/filters/gradle.toml create mode 100644 src/filters/jira.toml create mode 100644 src/filters/nx.toml create mode 100644 src/filters/ollama.toml create mode 100644 src/filters/spring-boot.toml diff --git a/src/filters/gradle.toml b/src/filters/gradle.toml new file mode 100644 index 000000000..e6ad28a3e --- /dev/null +++ b/src/filters/gradle.toml @@ -0,0 +1,35 @@ +[filters.gradle] +description = "Compact Gradle build output — strip progress, keep tasks and errors" +match_command = "^(gradle|gradlew|\\./)gradlew?\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^> Configuring project", + "^> Resolving dependencies", + "^> Transform ", + "^Download(ing)?\\s+http", + "^\\s*<-+>\\s*$", + "^> Task :.*UP-TO-DATE$", + "^> Task :.*NO-SOURCE$", + "^> Task :.*FROM-CACHE$", + "^Starting a Gradle Daemon", + "^Daemon will be stopped", +] +truncate_lines_at = 150 +max_lines = 50 +on_empty = "gradle: ok" + +[[tests.gradle]] +name = "strips UP-TO-DATE tasks, keeps build result" +input = "> Configuring project :app\n> Task :app:compileJava UP-TO-DATE\n> Task :app:compileKotlin UP-TO-DATE\n> Task :app:test\n\n3 tests completed, 1 failed\n\nBUILD FAILED in 12s" +expected = "> Task :app:test\n3 tests completed, 1 failed\nBUILD FAILED in 12s" + +[[tests.gradle]] +name = "clean build preserved" +input = "BUILD SUCCESSFUL in 8s\n7 actionable tasks: 7 executed" +expected = "BUILD SUCCESSFUL in 8s\n7 actionable tasks: 7 executed" + +[[tests.gradle]] +name = "empty after stripping" +input = "> Configuring project :app\n" +expected = "gradle: ok" diff --git a/src/filters/jira.toml b/src/filters/jira.toml new file mode 100644 index 000000000..9de5ad3ba --- /dev/null +++ b/src/filters/jira.toml @@ -0,0 +1,20 @@ +[filters.jira] +description = "Compact Jira CLI output — strip verbose metadata, keep essentials" +match_command = "^jira\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^\\s*--", +] +truncate_lines_at = 120 +max_lines = 40 + +[[tests.jira]] +name = "strips blank lines from issue list" +input = "TYPE\tKEY\tSUMMARY\tSTATUS\n\nStory\tPROJ-123\tAdd login feature\tIn Progress\n\nBug\tPROJ-456\tFix crash on startup\tOpen" +expected = "TYPE\tKEY\tSUMMARY\tSTATUS\nStory\tPROJ-123\tAdd login feature\tIn Progress\nBug\tPROJ-456\tFix crash on startup\tOpen" + +[[tests.jira]] +name = "single issue view" +input = "KEY: PROJ-123\nSummary: Add login feature\nStatus: In Progress\nAssignee: john@example.com" +expected = "KEY: PROJ-123\nSummary: Add login feature\nStatus: In Progress\nAssignee: john@example.com" diff --git a/src/filters/nx.toml b/src/filters/nx.toml new file mode 100644 index 000000000..d42dfb76e --- /dev/null +++ b/src/filters/nx.toml @@ -0,0 +1,25 @@ +[filters.nx] +description = "Compact Nx monorepo output — strip task graph noise, keep results" +match_command = "^(pnpm\\s+)?nx\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^\\s*>\\s*NX\\s+Running target", + "^\\s*>\\s*NX\\s+Nx read the output", + "^\\s*>\\s*NX\\s+View logs", + "^———————", + "^—————————", + "^\\s+Nx \\(powered by", +] +truncate_lines_at = 150 +max_lines = 60 + +[[tests.nx]] +name = "strips Nx noise, keeps build output" +input = "\n > NX Running target build for project myapp\n\n———————————————————————————————————————\nCompiled successfully.\nOutput: dist/apps/myapp\n\n > NX View logs at /tmp/.nx/runs/abc123\n\n Nx (powered by computation caching)\n" +expected = "Compiled successfully.\nOutput: dist/apps/myapp" + +[[tests.nx]] +name = "preserves error output" +input = "ERROR: Cannot find module '@myapp/shared'\n\n > NX Running target build for project myapp\n\nFailed at step: build" +expected = "ERROR: Cannot find module '@myapp/shared'\nFailed at step: build" diff --git a/src/filters/ollama.toml b/src/filters/ollama.toml new file mode 100644 index 000000000..e325ec948 --- /dev/null +++ b/src/filters/ollama.toml @@ -0,0 +1,23 @@ +[filters.ollama] +description = "Strip ANSI spinners and cursor control from ollama output, keep final text" +match_command = "^ollama\\s+run\\b" +strip_ansi = true +strip_lines_matching = [ + "^[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏\\s]*$", + "^\\s*$", +] + +[[tests.ollama]] +name = "strips spinner lines, keeps response" +input = "⠋ \n⠙ \n⠹ \nHello! How can I help you today?" +expected = "Hello! How can I help you today?" + +[[tests.ollama]] +name = "preserves multi-line response" +input = "⠋ \n⠙ \nLine one of the response.\nLine two of the response." +expected = "Line one of the response.\nLine two of the response." + +[[tests.ollama]] +name = "empty input" +input = "" +expected = "" diff --git a/src/filters/spring-boot.toml b/src/filters/spring-boot.toml new file mode 100644 index 000000000..5ec03e58c --- /dev/null +++ b/src/filters/spring-boot.toml @@ -0,0 +1,28 @@ +[filters.spring-boot] +description = "Compact Spring Boot output — strip banner and verbose startup logs, keep key events" +match_command = "^(mvn\\s+spring-boot:run|java\\s+-jar.*\\.jar|gradle\\s+.*bootRun)" +strip_ansi = true +keep_lines_matching = [ + "Started\\s.*\\sin\\s", + "Tomcat started on port", + "ERROR", + "WARN", + "Exception", + "Caused by:", + "Application run failed", + "BUILD\\s", + "Tests run:", + "FAILURE", + "listening on port", +] +max_lines = 30 + +[[tests.spring-boot]] +name = "keeps startup summary and errors" +input = " . ____ _ \n /\\\\ / ___'_ __ _ _(_)_ __ \n( ( )\\___ | '_ | '_| | '_ \\ \n \\/ ___)| |_)| | | | | || )\n ' |____| .__|_| |_|_| |_\\__|\n :: Spring Boot :: (v3.2.0)\n2024-01-01 INFO Initializing Spring\n2024-01-01 INFO Bean 'dataSource' created\n2024-01-01 INFO Tomcat started on port 8080\n2024-01-01 INFO Started MyApp in 3.2 seconds" +expected = "2024-01-01 INFO Tomcat started on port 8080\n2024-01-01 INFO Started MyApp in 3.2 seconds" + +[[tests.spring-boot]] +name = "preserves errors" +input = " :: Spring Boot :: (v3.2.0)\n2024-01-01 INFO Initializing Spring\n2024-01-01 ERROR Application run failed\nCaused by: java.lang.NullPointerException" +expected = "2024-01-01 ERROR Application run failed\nCaused by: java.lang.NullPointerException" diff --git a/src/toml_filter.rs b/src/toml_filter.rs index f72f3c870..a7761a910 100644 --- a/src/toml_filter.rs +++ b/src/toml_filter.rs @@ -1610,8 +1610,8 @@ match_command = "^make\\b" let filters = make_filters(BUILTIN_TOML); assert_eq!( filters.len(), - 47, - "Expected exactly 47 built-in filters, got {}. \ + 52, + "Expected exactly 52 built-in filters, got {}. \ Update this count when adding/removing filters in src/filters/.", filters.len() ); @@ -1668,11 +1668,11 @@ expected = "output line 1\noutput line 2" let combined = format!("{}\n\n{}", BUILTIN_TOML, new_filter); let filters = make_filters(&combined); - // All 47 existing filters still present + 1 new = 48 + // All 52 existing filters still present + 1 new = 53 assert_eq!( filters.len(), - 48, - "Expected 48 filters after concat (47 built-in + 1 new)" + 53, + "Expected 53 filters after concat (52 built-in + 1 new)" ); // New filter is discoverable From 41b49113c24915cb16ce98793036319c379f818a Mon Sep 17 00:00:00 2001 From: Patrick szymkowiak Date: Mon, 16 Mar 2026 17:37:28 +0100 Subject: [PATCH 2/2] feat: add 5 more TOML filters (turbo, mise, just, task, yadm) New filters for task runners and git wrapper: - turbo: strip cache/Tasks/Duration noise, keep task output (#531) - mise: strip install/download progress, keep task results (#607) - just: strip blanks and recipe headers, keep output (#607) - task: strip task headers and up-to-date lines, keep results (#607) - yadm: strip hint lines, compact git-like output (#567) All verified with fake binaries through catch-all TOML engine. 137/137 TOML tests pass, 934 Rust tests pass. Updated builtin filter count: 52 -> 57. Signed-off-by: Patrick szymkowiak --- src/filters/just.toml | 26 ++++++++++++++++++++++++++ src/filters/mise.toml | 30 ++++++++++++++++++++++++++++++ src/filters/task.toml | 27 +++++++++++++++++++++++++++ src/filters/turbo.toml | 30 ++++++++++++++++++++++++++++++ src/filters/yadm.toml | 21 +++++++++++++++++++++ src/toml_filter.rs | 10 +++++----- 6 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 src/filters/just.toml create mode 100644 src/filters/mise.toml create mode 100644 src/filters/task.toml create mode 100644 src/filters/turbo.toml create mode 100644 src/filters/yadm.toml diff --git a/src/filters/just.toml b/src/filters/just.toml new file mode 100644 index 000000000..31e58a542 --- /dev/null +++ b/src/filters/just.toml @@ -0,0 +1,26 @@ +[filters.just] +description = "Compact just task runner output — strip recipe headers, keep command output" +match_command = "^just\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^\\s*Available recipes:", + "^\\s*just --list", +] +truncate_lines_at = 150 +max_lines = 50 + +[[tests.just]] +name = "preserves command output" +input = "cargo test\n\ntest result: ok. 42 passed; 0 failed\n" +expected = "cargo test\ntest result: ok. 42 passed; 0 failed" + +[[tests.just]] +name = "preserves error output" +input = "error: Compilation failed\nsrc/main.rs:10: expected `;`" +expected = "error: Compilation failed\nsrc/main.rs:10: expected `;`" + +[[tests.just]] +name = "empty input" +input = "" +expected = "" diff --git a/src/filters/mise.toml b/src/filters/mise.toml new file mode 100644 index 000000000..7223d12b3 --- /dev/null +++ b/src/filters/mise.toml @@ -0,0 +1,30 @@ +[filters.mise] +description = "Compact mise task runner output — strip status lines, keep task results" +match_command = "^mise\\s+(run|exec|install|upgrade)\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^mise\\s+(trust|install|upgrade).*✓", + "^mise\\s+Installing\\s", + "^mise\\s+Downloading\\s", + "^mise\\s+Extracting\\s", + "^mise\\s+\\w+@[\\d.]+ installed", +] +truncate_lines_at = 150 +max_lines = 50 +on_empty = "mise: ok" + +[[tests.mise]] +name = "strips install noise, keeps task output" +input = "mise Installing node@20.0.0\nmise Downloading node@20.0.0\nmise Extracting node@20.0.0\nmise node@20.0.0 installed\n\nlint check passed\n2 warnings found" +expected = "lint check passed\n2 warnings found" + +[[tests.mise]] +name = "preserves error output" +input = "mise run lint\nError: biome check failed\nsrc/index.ts:5 — unused variable" +expected = "mise run lint\nError: biome check failed\nsrc/index.ts:5 — unused variable" + +[[tests.mise]] +name = "empty after stripping" +input = "mise trust ~/dev/.mise.toml ✓\nmise install node@20 ✓\n" +expected = "mise: ok" diff --git a/src/filters/task.toml b/src/filters/task.toml new file mode 100644 index 000000000..31868fc06 --- /dev/null +++ b/src/filters/task.toml @@ -0,0 +1,27 @@ +[filters.task] +description = "Compact go-task output — strip task headers, keep command results" +match_command = "^task\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^task: \\[.*\\] ", + "^task: Task .* is up to date", +] +truncate_lines_at = 150 +max_lines = 50 +on_empty = "task: ok" + +[[tests.task]] +name = "strips task headers, keeps output" +input = "task: [build] go build ./...\n\ntask: [test] go test ./...\nok myapp 0.5s\n\ntask: Task \"lint\" is up to date" +expected = "ok myapp 0.5s" + +[[tests.task]] +name = "preserves error output" +input = "task: [build] go build ./...\n./main.go:10: undefined: foo\ntask: Failed to run task \"build\": exit status 1" +expected = "./main.go:10: undefined: foo\ntask: Failed to run task \"build\": exit status 1" + +[[tests.task]] +name = "all up to date" +input = "task: Task \"build\" is up to date\ntask: Task \"lint\" is up to date\n" +expected = "task: ok" diff --git a/src/filters/turbo.toml b/src/filters/turbo.toml new file mode 100644 index 000000000..c5a09acf0 --- /dev/null +++ b/src/filters/turbo.toml @@ -0,0 +1,30 @@ +[filters.turbo] +description = "Compact Turborepo output — strip cache status noise, keep task results" +match_command = "^turbo\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^\\s*cache (hit|miss|bypass)", + "^\\s*\\d+ packages in scope", + "^\\s*Tasks:\\s+\\d+", + "^\\s*Duration:\\s+", + "^\\s*Remote caching (enabled|disabled)", +] +truncate_lines_at = 150 +max_lines = 50 +on_empty = "turbo: ok" + +[[tests.turbo]] +name = "strips cache noise, keeps task output" +input = " cache hit, replaying logs abc123\n cache miss, executing abc456\n\n3 packages in scope\n\n> myapp:build\n\nCompiled successfully.\n\nTasks: 2 successful, 2 total (1 cached)\nDuration: 3.2s" +expected = "> myapp:build\nCompiled successfully." + +[[tests.turbo]] +name = "preserves error output" +input = "> myapp:lint\n\nError: src/index.ts(5,1): error TS2304\n\nTasks: 0 successful, 1 total\nDuration: 1.1s" +expected = "> myapp:lint\nError: src/index.ts(5,1): error TS2304" + +[[tests.turbo]] +name = "empty after stripping" +input = " cache hit, replaying logs abc\n\n" +expected = "turbo: ok" diff --git a/src/filters/yadm.toml b/src/filters/yadm.toml new file mode 100644 index 000000000..f2cd3d1a2 --- /dev/null +++ b/src/filters/yadm.toml @@ -0,0 +1,21 @@ +[filters.yadm] +description = "Compact yadm (git wrapper) output — same filtering as git" +match_command = "^yadm\\b" +strip_ansi = true +strip_lines_matching = [ + "^\\s*$", + "^\\s*\\(use \"git ", + "^\\s*\\(use \"yadm ", +] +truncate_lines_at = 120 +max_lines = 40 + +[[tests.yadm]] +name = "strips hint lines" +input = "On branch main\nYour branch is up to date with 'origin/main'.\n\n (use \"yadm add\" to update what will be committed)\n\nChanges not staged for commit:\n modified: .bashrc" +expected = "On branch main\nYour branch is up to date with 'origin/main'.\nChanges not staged for commit:\n modified: .bashrc" + +[[tests.yadm]] +name = "short output preserved" +input = "Already up to date." +expected = "Already up to date." diff --git a/src/toml_filter.rs b/src/toml_filter.rs index a7761a910..b06bc051f 100644 --- a/src/toml_filter.rs +++ b/src/toml_filter.rs @@ -1610,8 +1610,8 @@ match_command = "^make\\b" let filters = make_filters(BUILTIN_TOML); assert_eq!( filters.len(), - 52, - "Expected exactly 52 built-in filters, got {}. \ + 57, + "Expected exactly 57 built-in filters, got {}. \ Update this count when adding/removing filters in src/filters/.", filters.len() ); @@ -1668,11 +1668,11 @@ expected = "output line 1\noutput line 2" let combined = format!("{}\n\n{}", BUILTIN_TOML, new_filter); let filters = make_filters(&combined); - // All 52 existing filters still present + 1 new = 53 + // All 57 existing filters still present + 1 new = 58 assert_eq!( filters.len(), - 53, - "Expected 53 filters after concat (52 built-in + 1 new)" + 58, + "Expected 58 filters after concat (57 built-in + 1 new)" ); // New filter is discoverable