diff --git a/CHANGELOG.md b/CHANGELOG.md index e60c6cc065..6bf4bed769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ - **compression (caveman):** add a **Chinese (zh / wenyan 文言) input-side rule pack** — the counterpart of the existing output-side `terse-cjk` style. New `rules/zh/{dedup,filler,ultra}.json` collapse repeated context ("如前所述" → "见上。"), drop pleasantries/hedging ("请帮我…/谢谢/我觉得"), strip sentence-final modal particles ("吗/呢/吧"), and abbreviate dense technical terms ("数据库"→"DB", "应用程序"→"app"). Chinese is now auto-detected: `detectCompressionLanguage` distinguishes zh from ja by Han-without-kana (kana is Japanese-exclusive, so a Han-heavy Japanese sentence still resolves to `ja`), and `zh` is listed in `listSupportedCompressionLanguages`. Patterns are ReDoS-safe (bounded literal alternations, no `\b` since CJK has no word boundaries). Regression guard: `tests/unit/caveman-packs-zh-wenyan.test.ts` (packs load + validate + shrink; zh/ja/non-CJK detection). gaps v3.8.42 — T05/C6. +### ✨ New Features + +- **compression (RTK):** add **Gradle** and **.NET CLI (`dotnet`)** to the RTK tool-output filter catalog. Tool output for `gradle`/`gradlew` and `dotnet build|test|restore|publish` is now recognized (both by command and by output content) and compressed: Gradle daemon/welcome banners and no-op `> Task … UP-TO-DATE/SKIPPED/FROM-CACHE` lines are dropped while `BUILD SUCCESSFUL/FAILED`, "What went wrong", and stack traces are preserved; the .NET build banner, copyright, and `Determining projects to restore`/`Restored …` chatter are dropped while `Build succeeded/FAILED`, `error CS####`/`warning CS####`, and test summaries are preserved. New builtin filters `engines/rtk/filters/{gradle,dotnet}.json` (with inline tests run by the catalog gate) plus `gradle`/`dotnet` entries in the command detector. Regression guard: `tests/unit/rtk-gradle-dotnet-filters.test.ts`. gaps v3.8.42 — T07/R9. + --- ## [3.8.41] — 2026-06-29 diff --git a/open-sse/services/compression/engines/rtk/commandDetector.ts b/open-sse/services/compression/engines/rtk/commandDetector.ts index 6f58a87b6a..8b932bb583 100644 --- a/open-sse/services/compression/engines/rtk/commandDetector.ts +++ b/open-sse/services/compression/engines/rtk/commandDetector.ts @@ -27,6 +27,9 @@ type Detector = { const COMMAND_PREFIXES = [ "git", "make", + "gradle", + "gradlew", + "dotnet", "terraform", "tofu", "opentofu", @@ -114,6 +117,18 @@ const DETECTORS: Detector[] = [ commandPatterns: [/^make\b/i], contentPatterns: [/^make\[\d+\]: (?:Entering|Leaving) directory/m, /make: \*\*\* /], }, + { + type: "gradle", + category: "build", + commandPatterns: [/^(?:gradle|gradlew|\.\/gradlew)\b/i], + contentPatterns: [/^> Task :/m, /^BUILD (?:SUCCESSFUL|FAILED)\b/m], + }, + { + type: "dotnet", + category: "build", + commandPatterns: [/^dotnet\s+(?:build|test|run|restore|publish|pack|msbuild)\b/i, /^dotnet\b/i], + contentPatterns: [/^Build (?:succeeded|FAILED)\b/m, /\b(?:error|warning) CS\d+\b/m], + }, { type: "terraform-plan", category: "infra", diff --git a/open-sse/services/compression/engines/rtk/filters/dotnet.json b/open-sse/services/compression/engines/rtk/filters/dotnet.json new file mode 100644 index 0000000000..532f4575c8 --- /dev/null +++ b/open-sse/services/compression/engines/rtk/filters/dotnet.json @@ -0,0 +1,47 @@ +{ + "id": "dotnet", + "label": ".NET CLI", + "description": "Strip the .NET build banner and restore chatter; keep build/test status, warnings (CS####), and errors.", + "category": "build", + "priority": 78, + "match": { + "outputTypes": ["dotnet"], + "commands": ["^dotnet\\b"], + "patterns": ["^Build (?:succeeded|FAILED)\\b", "\\b(?:error|warning) CS\\d+\\b"] + }, + "rules": { + "stripAnsi": true, + "dropPatterns": [ + "^Microsoft \\(R\\)", + "^Copyright \\(C\\) Microsoft", + "Determining projects to restore", + "^\\s*Restored ", + "^\\s*$", + "^Time Elapsed " + ], + "collapsePatterns": ["^\\s*Restored "], + "deduplicate": true, + "maxLines": 160, + "headLines": 40, + "tailLines": 60, + "onEmpty": "dotnet: ok" + }, + "preserve": { + "errorPatterns": [ + "Build FAILED", + "FAILED", + "\\berror CS\\d+\\b", + "\\bwarning CS\\d+\\b", + "Failed!" + ], + "summaryPatterns": ["Build succeeded", "Passed!", "Total tests:"] + }, + "tests": [ + { + "name": "drops build banner + restore chatter, keeps status", + "command": "dotnet build", + "input": "Microsoft (R) Build Engine version 17.8\n Determining projects to restore...\nBuild succeeded.\n", + "expected": "Build succeeded." + } + ] +} diff --git a/open-sse/services/compression/engines/rtk/filters/gradle.json b/open-sse/services/compression/engines/rtk/filters/gradle.json new file mode 100644 index 0000000000..e01096bb4d --- /dev/null +++ b/open-sse/services/compression/engines/rtk/filters/gradle.json @@ -0,0 +1,47 @@ +{ + "id": "gradle", + "label": "Gradle", + "description": "Strip Gradle daemon/welcome chatter and no-op tasks; keep build status, failures, and warnings.", + "category": "build", + "priority": 78, + "match": { + "outputTypes": ["gradle"], + "commands": ["^(?:gradle|gradlew|\\./gradlew)\\b"], + "patterns": ["^> Task :", "^BUILD (?:SUCCESSFUL|FAILED)\\b"] + }, + "rules": { + "stripAnsi": true, + "dropPatterns": [ + "^Welcome to Gradle", + "^Starting a Gradle Daemon", + "^> Task :\\S+ (?:UP-TO-DATE|SKIPPED|NO-SOURCE|FROM-CACHE)$", + "^Download https?://", + "^\\s*$" + ], + "collapsePatterns": ["^> Task :\\S+$"], + "deduplicate": true, + "maxLines": 160, + "headLines": 40, + "tailLines": 60, + "onEmpty": "gradle: ok" + }, + "preserve": { + "errorPatterns": [ + "BUILD FAILED", + "FAILED", + "What went wrong", + "Caused by:", + "error:", + "> Task :\\S+ FAILED" + ], + "summaryPatterns": ["BUILD SUCCESSFUL", "actionable task"] + }, + "tests": [ + { + "name": "drops welcome + up-to-date tasks, keeps build status", + "command": "gradle build", + "input": "Welcome to Gradle 8.5!\n> Task :app:compileJava UP-TO-DATE\nBUILD SUCCESSFUL in 3s\n", + "expected": "BUILD SUCCESSFUL in 3s" + } + ] +} diff --git a/tests/unit/rtk-gradle-dotnet-filters.test.ts b/tests/unit/rtk-gradle-dotnet-filters.test.ts new file mode 100644 index 0000000000..ead554a589 --- /dev/null +++ b/tests/unit/rtk-gradle-dotnet-filters.test.ts @@ -0,0 +1,37 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { detectCommandType } from "../../open-sse/services/compression/engines/rtk/commandDetector.ts"; +import { matchRtkFilter } from "../../open-sse/services/compression/engines/rtk/filterLoader.ts"; + +// T07 / R9 — gradle + dotnet RTK catalog filters (the catalog gap behind kubectl, etc.). + +const GRADLE_OUTPUT = + "Welcome to Gradle 8.5!\n> Task :app:compileJava UP-TO-DATE\n> Task :app:test\nBUILD SUCCESSFUL in 12s\n"; +const DOTNET_OUTPUT = + "Microsoft (R) Build Engine version 17.8\n Determining projects to restore...\n Restored /repo/App.csproj\nBuild succeeded.\n 0 Warning(s)\n"; + +test("detectCommandType recognizes gradle and dotnet by command", () => { + assert.equal(detectCommandType("", "gradle build").type, "gradle"); + assert.equal(detectCommandType("", "./gradlew test").type, "gradle"); + assert.equal(detectCommandType("", "dotnet build").type, "dotnet"); + assert.equal(detectCommandType("", "dotnet test").type, "dotnet"); +}); + +test("detectCommandType recognizes gradle/dotnet by output content alone", () => { + assert.equal(detectCommandType(GRADLE_OUTPUT).type, "gradle"); + assert.equal(detectCommandType(DOTNET_OUTPUT).type, "dotnet"); +}); + +test("matchRtkFilter selects the gradle / dotnet builtin filter", () => { + const cases: Array<[string, string, string]> = [ + ["gradle", GRADLE_OUTPUT, "gradle build"], + ["gradle", GRADLE_OUTPUT, "./gradlew test"], + ["dotnet", DOTNET_OUTPUT, "dotnet build"], + ["dotnet", DOTNET_OUTPUT, "dotnet test"], + ]; + for (const [id, output, command] of cases) { + const filter = matchRtkFilter(output, command, { customFiltersEnabled: false }); + assert.equal(filter?.id, id, `${command} should match the ${id} filter`); + assert.equal(filter?.category, "build"); + } +});