Repository navigation
Upgrade TelnetNegotiationCore to 4.6.1; truecolour, inline images, Pueblo via TNC - #29
Merged
Merged
Conversation
- SendNAWS was removed in TNC 2.8.0; report the window size through
NAWSProtocol.SendWindowSizeAsync, clamped to RFC 1073's 0..65535
(TNC now throws outside it instead of wrapping).
- TNC 2.8.0 stopped naming the client: TTYPE would answer UNKNOWN.
Set WithClientIdentity("SharpClient") with TERMINAL_TYPE XTERM and
MTTS ANSI|UTF-8|256 colours (truecolour is not rendered, so not claimed).
- Bump directly referenced Microsoft.Extensions.* to 10.0.14, the floor
TNC 4.6.1 depends on, so restore does not report a downgrade (NU1605).
- TNC 4.0 dropped FSharp.Core, so Android Release AOT is re-enabled.
Trimming stays off until a trimmed APK is checked on a device.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rqqt7TbSP3xxcS6oaZwo3C
…ects TNC drops a NAWS report made before the server's DO NAWS, as RFC 1073 requires, and nothing reported it again: the size the UI measured at connect and the size carried over an auto-reconnect never reached the server until the next resize. WindowSizeProtocol keeps the last size and reports it when NAWS is agreed, the way SharpMUTerm does. The default protocol set is spelled out because AddDefaultMUDProtocols always registers the base NAWSProtocol. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rqqt7TbSP3xxcS6oaZwo3C
…for AOT (XA1030) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rqqt7TbSP3xxcS6oaZwo3C
- SGR 38;2 / 48;2 now render as the given colour (AnsiColorKind.Rgb) instead of the default, and MTTS claims truecolour. - MXP <IMAGE> on a Secure line and Pueblo <img src> render as <img> in the output, inside a <SEND>/<a> link when one is open. Only http(s) and data:image URLs are accepted; images load with no-referrer. - Pueblo is detected by TNC's PuebloProtocol (the server's hello and its start sequence, both consumed) instead of a substring match on any line, which let a player's pose switch the client into HTML mode and sent PUEBLOCLIENT as a game command. A server that agreed MXP stays on MXP, as SharpMUTerm does. MXP/Pueblo state resets when the connection drops, so a reconnect negotiates it again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rqqt7TbSP3xxcS6oaZwo3C
HarryCordewener
marked this pull request as ready for review
November 6, 2026 17:43
There was a problem hiding this comment.
🟡 Changes recommended
An unresolved critical flaw allows unsolicited Pueblo activation to enable command links without a client announcement, even when Pueblo was declined in favor of MXP.
5 open issues
Reject Pueblo activation without a matching announcement · New Replay cached window size after interpreter setup · New Preserve shorthand commands across SEND text and image segments · New Parse spaced assignments without truncating positional URLs · New Keep sticky scrolling pinned when images load · New
What changed in this PR
Upgrades SharpClient to TelnetNegotiationCore 4.6.1 and extends its MUD/MUSH output rendering with truecolour and inline images.
Changes:
- Updates dependencies, declares client identity, and adapts window-size reporting to the new negotiation API.
- Adds RGB colour rendering and filtered MXP/Pueblo images, including command-linked images.
- Moves Pueblo detection into the connection layer, resets markup state on disconnect, and adds regression tests.
| File | Description |
|---|---|
| tests/SharpClient.UI.Tests/OutputViewLinkTests.cs | Tests image attributes and clickable images. |
| tests/SharpClient.Tests/SharpClient.Tests.csproj | Updates test dependency versions. |
| tests/SharpClient.Tests/Sessions/SessionMxpTests.cs | Tests Pueblo events and markup-state reset. |
| tests/SharpClient.Tests/Sessions/FakeTelnetConnection.cs | Adds simulated Pueblo activation. |
| tests/SharpClient.Tests/Rendering/SegmentStyleTests.cs | Tests RGB-to-CSS conversion. |
| tests/SharpClient.Tests/Rendering/InlineImageTests.cs | Tests image parsing, URL filtering, and links. |
| tests/SharpClient.Tests/Rendering/AnsiParserTests.cs | Tests truecolour parsing and edge cases. |
| tests/SharpClient.Tests/Connection/ClientIdentityAndNawsTests.cs | Tests terminal identity and window-size negotiation. |
| src/SharpClient.Web/SharpClient.Web.csproj | Upgrades the web host’s TNC dependency. |
| src/SharpClient.UI/wwwroot/app.css | Adds image sizing and image-button styles. |
| src/SharpClient.UI/SharpClient.UI.csproj | Updates dependency injection abstractions. |
| src/SharpClient.UI/Components/OutputView.razor | Renders images and command-linked image buttons. |
| src/SharpClient.Core/SharpClient.Core.csproj | Upgrades TNC and logging abstractions. |
| src/SharpClient.Core/Sessions/Session.cs | Uses Pueblo events and clears connection-specific markup state. |
| src/SharpClient.Core/Rendering/StyledSegment.cs | Adds inline-image URL metadata. |
| src/SharpClient.Core/Rendering/SegmentStyle.cs | Converts RGB colours to CSS hex values. |
| src/SharpClient.Core/Rendering/MxpParserState.cs | Clarifies the Pueblo-state documentation. |
| src/SharpClient.Core/Rendering/ImageSource.cs | Resolves and filters image URLs. |
| src/SharpClient.Core/Rendering/AnsiParser.cs | Parses truecolour sequences and image tags. |
| src/SharpClient.Core/Rendering/AnsiColor.cs | Adds clamped RGB colour representation. |
| src/SharpClient.Core/Connection/WindowSizeProtocol.cs | Caches window dimensions until negotiation permits reporting. |
| src/SharpClient.Core/Connection/TelnetConnection.cs | Configures identity, protocols, and Pueblo callbacks. |
| src/SharpClient.Core/Connection/ITelnetConnection.cs | Exposes Pueblo activation notifications. |
| src/SharpClient.App/SharpClient.App.csproj | Upgrades TNC and revises AOT/trimming comments; settings remain unchanged. |
Review effort: Balanced
|
|
||
| private ValueTask OnPuebloEnabledAsync(PuebloClient client) | ||
| { | ||
| PuebloEnabled?.Invoke(); |
| onMXPEnabled: OnMxpEnabledAsync, | ||
| charsetOrder: CharsetPreference) | ||
| .WithClientIdentity(Identity) | ||
| .AddPlugin(new WindowSizeProtocol(_windowSize)) |
Comment on lines
+46
to
+50
| Flush(); | ||
| segments.Add(new StyledSegment(label, style) | ||
| { | ||
| ImageUrl = url, | ||
| Command = pendingCommand, |
Comment on lines
+315
to
+337
| var isNamed = false; | ||
| while (i < body.Length && body[i] is not (' ' or '\t')) | ||
| { | ||
| if (body[i] == '=') | ||
| { | ||
| isNamed = true; | ||
| i++; | ||
| if (i < body.Length && body[i] is '"' or '\'') | ||
| { | ||
| var quote = body[i++]; | ||
| while (i < body.Length && body[i] != quote) | ||
| { | ||
| i++; | ||
| } | ||
|
|
||
| i++; | ||
| } | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| i++; | ||
| } |
| @foreach (var segment in line.Segments) | ||
| { | ||
| @if (segment.Command is not null && OnSendCommand is not null) | ||
| @if (segment.ImageUrl is not null) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Requested by Grave · project thread
Why
SharpClient is on TNC 2.5.3, and the current release is 4.6.1. This PR upgrades it and adds the MUSH features asked for in the same thread (24-bit colour and inline images). Pueblo images are only safe once Pueblo detection is fixed, so that fix is included too.
Changes
TNC upgrade
NAWS.
SendNAWSwas removed in 2.8.0. The window size now goes throughWindowSizeProtocol, aNAWSProtocolsubclass (SharpMUTerm does the same):DO NAWS. TNC drops a report sent before that, so on 2.5.3 the size measured at connect, and the size carried over an auto-reconnect, never reached the server.Because
AddDefaultMUDProtocolsalways registers the baseNAWSProtocol, the protocol list is now written out in full.Client identity. Since 2.8.0, TTYPE answers
UNKNOWNunless the client names itself. It now sendsSharpClient, thenXTERM, then MTTSANSI | UTF-8 | 256 colours | truecolour.Package floor.
Microsoft.Extensions.*packages that are referenced directly move from 10.0.9 to 10.0.14, the version TNC 4.6.1 depends on. Without that, restore fails with NU1605.Android AOT and trimming stay off. The original reason (FSharp.Core) is gone, but .NET for Android allows AOT only together with trimming (XA1030). Trimming needs a device check first, because EF Core and the Blazor WebView use reflection. The csproj comment now explains this.
Rendering
38;2;r;g;band48;2;r;g;bused to be drawn in the default colour. They now produceAnsiColorKind.Rgb, whichSegmentStylewrites out as#rrggbb. Components outside 0..255 are clamped. A truncated sequence is still consumed and leaves no colour.<IMAGE>is honoured only on a Secure line, the same as<SEND>. The URL isURL+T+FNAME(or the first positional argument), as the spec describes.<img src alt>is honoured in Pueblo mode.<img xch_mode=…>is ignored, since it is Pueblo's mode switch and not a picture.http,httpsanddata:image/URLs are allowed.javascript:,file:,content:and local paths are refused.OutputViewrenders an<img loading=lazy referrerpolicy=no-referrer>, capped at the column width and 40vh. Inside a<SEND>/<a>the image is a clickable button.PuebloProtocol. Before,Sessionswitched Pueblo on for any line containing "This world is Pueblo", including another player's pose. It then sentPUEBLOCLIENT 2.01as a game command, and after that every<a xch_cmd>in the output was clickable. Now:PUEBLOCLIENT 2.50only if the server has not agreed MXP. SharpMUSH offers both, and answering Pueblo makes it stop sending MXP; SharpMUTerm learned the same thing.Tests
DO NAWS; NAWS clamping and IAC doubling.<img>attributes, and an image inside a command button.Verification
http:images are likely blocked as mixed content in the WebView (it serves from https://0.0.0.1), so expect onlyhttps:images to show there.Out of scope / follow-ups
<SUPPORT>/<VERSION>, TLS, MCCP and NEW-ENVIRON, from the SharpMUTerm gap list.🤖 Generated with Claude Code
https://claude.ai/code/session_01Rqqt7TbSP3xxcS6oaZwo3C