Skip to content
This repository was archived by the owner on Sep 28, 2026. It is now read-only.
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
26 changes: 21 additions & 5 deletions plugins/token-diet/ctx-wire/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ prose. That set is small:
| **dotnet restore** | Yes (NuGet) | Yes (`All projects are up-to-date`, `Restored …`, `NU####`) | ✅ EN+FR |
| **dotnet run** | Yes (build + app) | Strips build preamble; collapses all-passed MTP test runs | ✅ EN+FR |
| **dotnet tool** | Yes (SDK) | Yes (`was successfully installed/updated`) | ✅ EN+FR |
| **dotnet publish** | Yes (build + NuGet) | Strips restore/build preamble, keeps the `-> …/publish/` artifact + errors/warnings (no `Build succeeded` line in .NET 10) | ✅ EN+FR |
| **dotnet pack** | Yes (NuGet) | Yes (`Successfully created package` / `Création réussie du package`) | ✅ EN+FR |
| **dotnet format** | Yes | **No** — silent on success; its diagnostics (`error WHITESPACE:`, analyzer IDs) must reach context. Nothing to collapse | n/a |
| **dotnet list package** | keys are English | **No** — `--outdated` / `--vulnerable` tables are the payload you *want* to keep; structural at most | n/a |
| git log / diff / blame / list | Yes | **No** — purely structural (blank-strip, truncate, caps) | n/a |
| grep / rg | Diagnostics only | **No** — `group_by` on `file:line:`, structural | n/a |
| jira (CLI) | No (Go, English-only) | structural (strip blanks/`--`) | n/a |
Expand All @@ -33,6 +37,14 @@ So localizing "all tools" would be almost entirely dead regex: the long tail
emits English in any locale, and the structural filters (grep, git-log, ls, …)
are already locale-agnostic by construction.

> **`dotnet build` vs `publish`/`pack` output in .NET 10** — verified against
> SDK 10.0.301: `dotnet build` still prints the classic `Build succeeded.` /
> `0 Error(s)` summary (piped, under a PTY, and with `--tl:off`), so the
> `dotnet-build` filter keys on it safely. `publish` and `pack` do **not** print
> that summary — their success markers are the `-> …/publish/` artifact line and
> `Successfully created package` respectively, which is why they get their own
> filters rather than reusing the build one.

## Why no Romanian

The two tools worth localizing **do not ship Romanian translations**:
Expand Down Expand Up @@ -73,11 +85,15 @@ and secret-ish `key=value` / `--secret-flag value` pairs.

So **GitHub tokens** and **Azure DevOps PATs / Atlassian tokens in the usual auth
forms** (Basic header, `https://user:pat@…` URL, `token=…` assignment) are
already scrubbed. The one shape it doesn't know is a **bare `ATATT…` Atlassian
API token** (no matching prefix). Since the scrub rules aren't user-extensible,
`acli.toml` adds a filter `replace` that redacts `ATATT…` from acli output. To
scrub bare ATATT tokens everywhere (not just acli output), upstream an `ATATT`
entry to ctx-wire's `internal/scrub/scrub.go` token alternation + literal anchors.
already scrubbed. The shapes it doesn't know are the **bare `AT?…` Atlassian
tokens** — `ATATT…` (API), `ATCTT…` (Confluence/Bitbucket scoped) and `ATOAT…`
(OAuth) — none of which carry a prefix the built-in scrub matches. Since the
scrub rules aren't user-extensible, `acli.toml` adds a filter `replace` that
redacts all three (`AT(?:ATT|CTT|OAT)…`) from acli output to a single generic
`AT***REDACTED***` marker (the label deliberately doesn't echo which prefix — and
thus which token class — was present). To scrub these everywhere (not just acli
output), upstream an `AT(?:ATT|CTT|OAT)` entry to ctx-wire's
`internal/scrub/scrub.go` token alternation + literal anchors.

## Compressing MCP output

Expand Down
16 changes: 13 additions & 3 deletions plugins/token-diet/ctx-wire/filters.d/acli.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ description = "Compact Atlassian CLI (acli) output; redact bare AT?TT tokens (AT
match_command = "^acli\\b"
strip_ansi = true
replace = [
{ pattern = "AT[A-Z]TT[A-Za-z0-9_=.\\-]{20,}", replacement = "ATATT***REDACTED***" },
# Match all three bare Atlassian token prefixes: ATATT (API), ATCTT
# (Confluence/Bitbucket scoped), ATOAT (OAuth). The old `AT[A-Z]TT` shape
# required a literal `TT` in positions 4-5, so it silently missed ATOAT
# (…OAT) and leaked OAuth tokens into context. Generic replacement label —
# don't leak which prefix (and thus token class) was present.
{ pattern = "AT(?:ATT|CTT|OAT)[A-Za-z0-9_=.\\-]{20,}", replacement = "AT***REDACTED***" },
]
strip_lines_matching = [
"^\\s*$",
Expand All @@ -41,12 +46,17 @@ expected = "TYPE\tKEY\tSUMMARY\tSTATUS\nStory\tPROJ-123\tAdd login\tIn Progress\
[[tests.acli]]
name = "redacts bare ATATT Atlassian API token"
input = "Authenticated. Your API token ATATT3xFfGF0abcDEF123ghiJKL456mnoPQR789stu=A1B2 is stored."
expected = "Authenticated. Your API token ATATT***REDACTED*** is stored."
expected = "Authenticated. Your API token AT***REDACTED*** is stored."

[[tests.acli]]
name = "redacts bare ATCTT scoped (Confluence/Bitbucket) token"
input = "Authenticated. Your API token ATCTT3xFfGF0abcDEF123ghiJKL456mnoPQR789stu=A1B2 is stored."
expected = "Authenticated. Your API token ATATT***REDACTED*** is stored."
expected = "Authenticated. Your API token AT***REDACTED*** is stored."

[[tests.acli]]
name = "redacts bare ATOAT Atlassian OAuth token"
input = "Authenticated. Your API token ATOAT3xFfGF0abcDEF123ghiJKL456mnoPQR789stu=A1B2 is stored."
expected = "Authenticated. Your API token AT***REDACTED*** is stored."

[[tests.acli]]
name = "single workitem view preserved"
Expand Down
79 changes: 79 additions & 0 deletions plugins/token-diet/ctx-wire/filters.d/dotnet-pack.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# dotnet-pack (EN + FR) — token-diet multilingual filter for ctx-wire.
# `dotnet pack` runs a build then emits a NuGet packaging summary. On success
# it prints `Successfully created package '<path>.nupkg'.` (often preceded by a
# benign "missing a readme" NOTE). Like `dotnet publish` it does NOT print a
# "Build succeeded." summary in .NET 10. Collapse a clean pack to a short ok;
# keep build/NuGet errors. Success + FR strings verified verbatim against .NET
# 10.0.301 (DOTNET_CLI_UI_LANGUAGE=fr):
# "Successfully created package '{0}'." -> "Création réussie du package '{0}'."
# No Romanian (.NET / NuGet ship none).
schema_version = 1

[filters.dotnet-pack]
description = "Compact dotnet pack output (EN+FR) - collapse a clean pack to ok, keep errors"
match_command = "^dotnet\\s+pack\\b"
strip_ansi = true
match_output = [
{ pattern = "(?mi)(Successfully created package|Création réussie du package)", message = "dotnet pack: ok", unless = "(?i)(:\\s*error|\\berror\\b|\\bNU[0-9]{3,4}\\b|Build FAILED|La génération a échoué|ÉCHEC de la build|\\bfailed\\b|\\béchec\\b)" },
]
strip_lines_matching = [
"^\\s*$",
"^Microsoft \\(R\\)",
"^Copyright \\(C\\)",
"^\\s*(Determining projects to restore|Identification des projets à restaurer)",
"^\\s*(Restoring packages for|Restauration des packages pour)",
"^\\s*(Restored |Restauration effectuée de )",
"^\\s*(All projects are up-to-date for restore|Tous les projets sont à jour pour la restauration)",
"^\\s*\\S+ -> .*\\.(dll|exe)$",
"^(Build succeeded|La génération a réussi)\\.?\\s*$",
"^(Time Elapsed|Temps écoulé) ",
]
max_lines = 60

# --- English ---
[[tests.dotnet-pack]]
name = "EN: success collapses (readme NOTE does not block)"
input = """
Determining projects to restore...
All projects are up-to-date for restore.
MyApp -> /home/user/MyApp/bin/Release/net10.0/MyApp.dll
The package MyApp.1.0.0 is missing a readme. Go to https://aka.ms/nuget/authoring-best-practices/readme to learn why package readmes are important.
Successfully created package '/home/user/MyApp/bin/Release/MyApp.1.0.0.nupkg'.
"""
expected = "dotnet pack: ok"

[[tests.dotnet-pack]]
name = "EN: build error preserved"
input = """
Determining projects to restore...
/home/user/MyApp/Program.cs(1,24): error CS1002: ; expected [/home/user/MyApp/MyApp.csproj]
"""
expected = "/home/user/MyApp/Program.cs(1,24): error CS1002: ; expected [/home/user/MyApp/MyApp.csproj]"

# --- French ---
[[tests.dotnet-pack]]
name = "FR: success collapses"
input = """
Identification des projets à restaurer...
Tous les projets sont à jour pour la restauration.
MyApp -> /home/user/MyApp/bin/Release/net10.0/MyApp.dll
Il manque un fichier Lisez-moi au MyApp.1.0.0 du package. Accédez à https://aka.ms/nuget/authoring-best-practices/readme pour savoir pourquoi les lisez-moi de package sont importants.
Création réussie du package '/home/user/MyApp/bin/Release/MyApp.1.0.0.nupkg'.
"""
expected = "dotnet pack: ok"

[[tests.dotnet-pack]]
name = "FR: build error preserved"
input = """
Identification des projets à restaurer...
/home/user/MyApp/Program.cs(1,24): error CS1002: ; attendu [/home/user/MyApp/MyApp.csproj]
"""
expected = "/home/user/MyApp/Program.cs(1,24): error CS1002: ; attendu [/home/user/MyApp/MyApp.csproj]"

[[tests.dotnet-pack]]
name = "NU packaging error not collapsed to ok"
input = """
MyApp -> /home/user/MyApp/bin/Release/net10.0/MyApp.dll
error NU5017: Cannot create a package that has no dependencies nor content.
"""
expected = "error NU5017: Cannot create a package that has no dependencies nor content."
82 changes: 82 additions & 0 deletions plugins/token-diet/ctx-wire/filters.d/dotnet-publish.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# dotnet-publish (EN + FR) — token-diet multilingual filter for ctx-wire.
# `dotnet publish` shares `dotnet build`'s restore/build preamble but — unlike
# build — does NOT print a "Build succeeded." / "0 Error(s)" summary in .NET 10
# (verified against 10.0.301, piped and under a PTY). Its success signal is the
# publish artifact line `<Proj> -> <path>/publish/`. So this is a STRIP filter,
# not a success-collapse: drop the restore banner + the intermediate `-> …dll`
# build arrow, and KEEP the `-> …/publish/` line plus any errors/warnings.
#
# Trim / AOT / self-contained publishes emit actionable `warning IL####` /
# `warning TrimmerXXXX` lines — those must survive, so we deliberately do NOT
# collapse to a bare "ok". FR strings verbatim from MSBuild/NuGet localization.
# No Romanian (.NET ships none).
schema_version = 1

[filters.dotnet-publish]
description = "Compact dotnet publish output (EN+FR) - strip restore/build preamble, keep the publish artifact line + errors/warnings"
match_command = "^dotnet\\s+publish\\b"
strip_ansi = true
strip_lines_matching = [
"^\\s*$",
"^Microsoft \\(R\\)",
"^Copyright \\(C\\)",
"^\\s*(Determining projects to restore|Identification des projets à restaurer)",
"^\\s*(Restoring packages for|Restauration des packages pour)",
"^\\s*(Restored |Restauration effectuée de )",
"^\\s*(All projects are up-to-date for restore|Tous les projets sont à jour pour la restauration)",
# intermediate build arrow (`Proj -> …/MyApp.dll`); the publish arrow ends in
# `publish/` and is intentionally NOT matched here, so it survives.
"^\\s*\\S+ -> .*\\.(dll|exe)$",
"^(Build succeeded|La génération a réussi)\\.?\\s*$",
"^(Time Elapsed|Temps écoulé) ",
]
truncate_lines_at = 240
max_lines = 200

# --- English ---
[[tests.dotnet-publish]]
name = "EN: preamble stripped, publish artifact kept"
input = """
Determining projects to restore...
All projects are up-to-date for restore.
MyApp -> /home/user/MyApp/bin/Release/net10.0/MyApp.dll
MyApp -> /home/user/MyApp/bin/Release/net10.0/publish/
"""
expected = " MyApp -> /home/user/MyApp/bin/Release/net10.0/publish/"

[[tests.dotnet-publish]]
name = "EN: build error passes through"
input = """
Determining projects to restore...
All projects are up-to-date for restore.
/home/user/MyApp/Program.cs(1,24): error CS1002: ; expected [/home/user/MyApp/MyApp.csproj]
"""
expected = "/home/user/MyApp/Program.cs(1,24): error CS1002: ; expected [/home/user/MyApp/MyApp.csproj]"

[[tests.dotnet-publish]]
name = "EN: trim warnings preserved"
input = """
MyApp -> /home/user/MyApp/bin/Release/net10.0/MyApp.dll
/home/user/MyApp/Program.cs(3,1): warning IL2026: Using member 'X' which has 'RequiresUnreferencedCodeAttribute' [/home/user/MyApp/MyApp.csproj]
MyApp -> /home/user/MyApp/bin/Release/net10.0/linux-x64/publish/
"""
expected = "/home/user/MyApp/Program.cs(3,1): warning IL2026: Using member 'X' which has 'RequiresUnreferencedCodeAttribute' [/home/user/MyApp/MyApp.csproj]\n MyApp -> /home/user/MyApp/bin/Release/net10.0/linux-x64/publish/"

# --- French ---
[[tests.dotnet-publish]]
name = "FR: preamble stripped, publish artifact kept"
input = """
Identification des projets à restaurer...
Tous les projets sont à jour pour la restauration.
MyApp -> /home/user/MyApp/bin/Release/net10.0/MyApp.dll
MyApp -> /home/user/MyApp/bin/Release/net10.0/publish/
"""
expected = " MyApp -> /home/user/MyApp/bin/Release/net10.0/publish/"

[[tests.dotnet-publish]]
name = "FR: build error passes through"
input = """
Identification des projets à restaurer...
/home/user/MyApp/Program.cs(1,24): error CS1002: ; attendu [/home/user/MyApp/MyApp.csproj]
"""
expected = "/home/user/MyApp/Program.cs(1,24): error CS1002: ; attendu [/home/user/MyApp/MyApp.csproj]"
12 changes: 7 additions & 5 deletions plugins/token-diet/ctx-wire/filters.d/dotnet-run.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ input = """
Test run summary: Passed!
total: 42
failed: 0
passed: 42
succeeded: 42
skipped: 0
duration: 1s
"""
Expand All @@ -77,11 +77,11 @@ failed MyNamespace.MyTests.Test1
Test run summary: Failed!
total: 42
failed: 2
passed: 40
succeeded: 40
skipped: 0
duration: 1s
"""
expected = "failed MyNamespace.MyTests.Test1\nTest run summary: Failed!\n total: 42\n failed: 2\n passed: 40\n skipped: 0\n duration: 1s"
expected = "failed MyNamespace.MyTests.Test1\nTest run summary: Failed!\n total: 42\n failed: 2\n succeeded: 40\n skipped: 0\n duration: 1s"

# --- French (plain app) ---
[[tests.dotnet-run]]
Expand All @@ -104,14 +104,16 @@ src/Program.cs(10,5): error CS1002: ; attendu
expected = "src/Program.cs(10,5): error CS1002: ; attendu\nÉCHEC de la build."

# --- French (MTP test project run via dotnet run) ---
# FR MTP block label is `réussie :` (past participle), header `… : Réussite!`
# — verified against .NET 10.0.301 (DOTNET_CLI_UI_LANGUAGE=fr).
[[tests.dotnet-run]]
name = "FR MTP: all-passed test run collapses"
input = """
MyTests -> /home/user/MyTests/bin/Debug/net8.0/MyTests.dll
Résumé de série de tests : Réussite !
Résumé de série de tests : Réussite!
total : 42
échec : 0
réussite : 42
réussie : 42
ignoré : 0
durée : 1s
"""
Expand Down
61 changes: 52 additions & 9 deletions plugins/token-diet/ctx-wire/filters.d/dotnet-test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
# "{0} - échec : {1}, réussite : {2}, ignorée(s) : {3}, total : {4}, durée : {5}"
# "Error Message:" -> "Message d'erreur :"
# MTP: "Test run summary:" -> "Résumé de série de tests :"
# total/failed/passed/skipped/duration -> total/échec/réussite/ignoré/durée
# total/failed/succeeded/skipped/duration -> total/échec/réussie/ignoré/durée
# (EN field label is `succeeded:`, FR is `réussie :` — verified against
# .NET 10.0.301; NOT `passed:` / `réussite :`)
# "Zero tests ran" -> "Zéro tests exécutés"
# .NET ships no Romanian satellite resources, so EN+FR covers every locale.
schema_version = 1
Expand Down Expand Up @@ -71,13 +73,19 @@ Message d'erreur :
expected = "Échec ! - échec : 1, réussite : 41, ignorée(s) : 0, total : 42, durée : 1 s\nMessage d'erreur :\n Attendu true mais a obtenu false"

# --- English (MTP, Microsoft.Testing.Platform) ---
# Field label is `succeeded:` (verified against .NET 10.0.301 `dotnet test`
# with the MTP runner, global.json `test.runner = Microsoft.Testing.Platform`),
# NOT `passed:`. The header is `Test run summary:` (with "run") in every path
# checked — single project, solution, and multi-project solution roll-up — so
# the trigger needs no `Test summary:` (no-"run") variant; that string does not
# occur in the .NET 10 SDK or Microsoft.Testing.Platform assemblies.
[[tests.dotnet-test]]
name = "EN MTP: summary block collapses"
input = """
Test run summary: Passed!
total: 42
failed: 0
passed: 42
succeeded: 42
skipped: 0
duration: 1s
"""
Expand All @@ -91,20 +99,55 @@ failed MyNamespace.MyTests.Test1
Test run summary: Failed!
total: 42
failed: 2
passed: 40
succeeded: 40
skipped: 0
duration: 1s
"""
expected = "failed MyNamespace.MyTests.Test1\n Assert.True failed\nTest run summary: Failed!\n total: 42\n failed: 2\n passed: 40\n skipped: 0\n duration: 1s"
expected = "failed MyNamespace.MyTests.Test1\n Assert.True failed\nTest run summary: Failed!\n total: 42\n failed: 2\n succeeded: 40\n skipped: 0\n duration: 1s"

# --- English (MTP native `dotnet test` integration, .NET 10 SDK) ---
# The SDK-integrated runner prints a per-app status line followed by the same
# `Test run summary:` block. Verified verbatim against .NET 10.0.301.
[[tests.dotnet-test]]
name = "EN MTP native (dotnet test): per-app line + summary collapses"
input = """
App.Tests.dll (net10.0|x64) passed (269ms)
Test run summary: Passed!
total: 42
failed: 0
succeeded: 42
skipped: 0
duration: 500ms
"""
expected = "dotnet test: ok"

[[tests.dotnet-test]]
name = "EN MTP native (dotnet test): failures preserved"
input = """
App.Tests.dll (net10.0|x64) failed with 1 error(s) (269ms)
Test run summary: Failed!
total: 5
failed: 1
succeeded: 3
skipped: 1
duration: 471ms
"""
expected = "App.Tests.dll (net10.0|x64) failed with 1 error(s) (269ms)\nTest run summary: Failed!\n total: 5\n failed: 1\n succeeded: 3\n skipped: 1\n duration: 471ms"

# --- French (MTP) ---
# The MTP block's success label is `réussie :` (past participle), NOT the VSTest
# noun `réussite :`. Header renders as `Résumé de série de tests : Réussite!` /
# `… : Échec!` (space before the colon, none before the bang). Verified verbatim
# against .NET 10.0.301 with DOTNET_CLI_UI_LANGUAGE=fr. Collapse keys on the
# `Résumé de série de tests` header, so the label discrepancy never broke the
# match — but the fixtures now assert the real wording.
[[tests.dotnet-test]]
name = "FR MTP: summary block collapses"
input = """
Résumé de série de tests : Réussite !
Résumé de série de tests : Réussite!
total : 42
échec : 0
réussite : 42
réussie : 42
ignoré : 0
durée : 1s
"""
Expand All @@ -115,14 +158,14 @@ name = "FR MTP: failures preserved"
input = """
échec MyNamespace.MyTests.Test1
Échec de Assert.True
Résumé de série de tests : Échec !
Résumé de série de tests : Échec!
total : 42
échec : 2
réussite : 40
réussie : 40
ignoré : 0
durée : 1s
"""
expected = "échec MyNamespace.MyTests.Test1\n Échec de Assert.True\nRésumé de série de tests : Échec !\n total : 42\n échec : 2\n réussite : 40\n ignoré : 0\n durée : 1s"
expected = "échec MyNamespace.MyTests.Test1\n Échec de Assert.True\nRésumé de série de tests : Échec!\n total : 42\n échec : 2\n réussie : 40\n ignoré : 0\n durée : 1s"

[[tests.dotnet-test]]
name = "MTP: zero tests not collapsed to ok"
Expand Down
Loading