Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
- **dashboard:** fix the **Add Provider / onboarding wizard** button silently doing nothing. The `/dashboard/providers/new` route was a redirect stub (it bounced straight back to `/dashboard/providers`), so every "Add Provider" button and dashboard widget link opened nothing, and the fully-built `ProviderOnboardingWizard` component stayed orphaned (never rendered by any route). The route now renders the wizard directly; auth is enforced centrally by the `(dashboard)` layout, same as the sibling provider routes. Regression guard in `tests/unit/onboarding-wizard-route-5427.test.ts`. ([#5427](https://github.com/diegosouzapw/OmniRoute/issues/5427))
- **db (import):** fix `EBUSY: resource busy or locked` when importing a database on **Windows**. The import route deleted the live `storage.sqlite` + WAL/`-shm`/`-journal` sidecars with a plain `fs.unlinkSync` immediately after `resetDbInstance()`, but Windows releases the SQLite file handle asynchronously after `close()` (mmap / antivirus), so the unlink raced and threw `EBUSY`. The route now deletes via `unlinkFileWithRetry` (EBUSY/EPERM backoff) — the same helper the restore path already uses. Regression guard in `tests/unit/db-import-ebusy-5406.test.ts`. ([#5406](https://github.com/diegosouzapw/OmniRoute/issues/5406), consolidated under [#5161](https://github.com/diegosouzapw/OmniRoute/issues/5161))

### ✨ 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
Expand Down
15 changes: 15 additions & 0 deletions open-sse/services/compression/engines/rtk/commandDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type Detector = {
const COMMAND_PREFIXES = [
"git",
"make",
"gradle",
"gradlew",
"dotnet",
"terraform",
"tofu",
"opentofu",
Expand Down Expand Up @@ -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",
Expand Down
47 changes: 47 additions & 0 deletions open-sse/services/compression/engines/rtk/filters/dotnet.json
Original file line number Diff line number Diff line change
@@ -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."
}
]
}
47 changes: 47 additions & 0 deletions open-sse/services/compression/engines/rtk/filters/gradle.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
37 changes: 37 additions & 0 deletions tests/unit/rtk-gradle-dotnet-filters.test.ts
Original file line number Diff line number Diff line change
@@ -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");
}
});
Loading