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
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,39 @@ jobs:
dotnet-version: '10.0.x'

- name: Restore
run: dotnet restore MuGlyph.slnx
run: dotnet restore SharpMUTerm.slnx

- name: Build
run: dotnet build MuGlyph.slnx -c Release --no-restore
run: dotnet build SharpMUTerm.slnx -c Release --no-restore

# TUnit runs on Microsoft.Testing.Platform; execute each test project directly
# (the classic `dotnet test`/VSTest path is not used by MTP on .NET 10).
- name: Test — Core
shell: bash
run: dotnet run -c Release --no-build --project tests/MuClient.Core.Tests/MuClient.Core.Tests.csproj
run: dotnet run -c Release --no-build --project tests/SharpMUTerm.Core.Tests/SharpMUTerm.Core.Tests.csproj

- name: Test — Graphics
shell: bash
run: dotnet run -c Release --no-build --project tests/MuClient.Graphics.Tests/MuClient.Graphics.Tests.csproj
run: dotnet run -c Release --no-build --project tests/SharpMUTerm.Graphics.Tests/SharpMUTerm.Graphics.Tests.csproj

- name: Test — Scripting
shell: bash
run: dotnet run -c Release --no-build --project tests/MuClient.Scripting.Tests/MuClient.Scripting.Tests.csproj
run: dotnet run -c Release --no-build --project tests/SharpMUTerm.Scripting.Tests/SharpMUTerm.Scripting.Tests.csproj

- name: Test — Web
shell: bash
run: dotnet run -c Release --no-build --project tests/MuClient.Web.Tests/MuClient.Web.Tests.csproj
run: dotnet run -c Release --no-build --project tests/SharpMUTerm.Web.Tests/SharpMUTerm.Web.Tests.csproj

- name: Test — Tui
shell: bash
run: dotnet run -c Release --no-build --project tests/MuClient.Tui.Tests/MuClient.Tui.Tests.csproj
run: dotnet run -c Release --no-build --project tests/SharpMUTerm.Tui.Tests/SharpMUTerm.Tui.Tests.csproj

# End-to-end guard: the headless snapshot must render the workspace (rail, worlds, command
# surface) and exit — catches both UI-render regressions and any return of the stdin-block hang.
- name: Smoke — headless snapshot
shell: bash
run: |
dotnet run -c Release --no-build --project src/MuClient.Tui/MuClient.Tui.csproj -- \
dotnet run -c Release --no-build --project src/SharpMUTerm.Tui/SharpMUTerm.Tui.csproj -- \
--snapshot --size 120x30 --out snapshot.ans </dev/null
test -s snapshot.ans || { echo "snapshot produced no output"; exit 1; }
for token in CONNECTIONS Aetherfall Corvid palette; do
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Publish single-file
shell: bash
run: >
dotnet publish src/MuClient.Tui/MuClient.Tui.csproj
dotnet publish src/SharpMUTerm.Tui/SharpMUTerm.Tui.csproj
-p:PublishProfile=${{ matrix.profile }}
-o publish/${{ matrix.rid }}

Expand All @@ -42,20 +42,20 @@ jobs:
shell: bash
run: |
cd publish/${{ matrix.rid }}
tar -czf ../../muglyph-${{ matrix.rid }}.tar.gz muglyph
tar -czf ../../sharpmuterm-${{ matrix.rid }}.tar.gz sharpmuterm

- name: Package (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
cd publish/${{ matrix.rid }}
7z a ../../muglyph-${{ matrix.rid }}.zip muglyph.exe
7z a ../../sharpmuterm-${{ matrix.rid }}.zip sharpmuterm.exe

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: muglyph-${{ matrix.rid }}
path: muglyph-${{ matrix.rid }}.*
name: sharpmuterm-${{ matrix.rid }}
path: sharpmuterm-${{ matrix.rid }}.*

# Serialize release creation in a single downstream job so the two matrix jobs don't race
# softprops/action-gh-release on the same tag.
Expand Down
29 changes: 15 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# CLAUDE.md — MuGlyph agent brief
# CLAUDE.md — SharpMUTerm agent brief

Guidance for any Claude agent working in this repository. Read this first, then read
[`docs/PLAN.md`](docs/PLAN.md) — the plan is the authoritative architecture + roadmap.

## What this project is

**MuGlyph** is a cross-platform TUI **MU\*** (MUSH / MUCK / MUD) client in **C# / .NET 10**,
**SharpMUTerm** is a cross-platform TUI **MU\*** (MUSH / MUCK / MUD) client in **C# / .NET 10**,
targeting feature parity with [BeipMU](https://beipdev.github.io/BeipMU/), running inside
GPU-accelerated terminals (Kitty, WezTerm, Ghostty) on **Windows and Linux**.

Expand All @@ -20,7 +20,7 @@ fallbacks) for inline images/maps.
framework with split layouts, tabs, resizable/mouse-draggable windows, Spectre-style markup, and
a **native Kitty graphics protocol** (+ Sixel/half-block) for inline images. Replaced Terminal.Gui
v2 (which was prerelease with an `[Obsolete]` mid-migration API); the switch is contained to
`MuClient.Tui` because `MuClient.Core` is UI-agnostic.
`SharpMUTerm.Tui` because `SharpMUTerm.Core` is UI-agnostic.
- **Scripting:** Lua via **MoonSharp** (pure-managed, sandboxed).
- **Inline graphics:** in scope from day one (Kitty Unicode placeholders → Sixel → half-block).
- **Protocols:** aim for all common MU\* protocols. GMCP/MSSP/CHARSET/NAWS/MTTS/EOR via
Expand All @@ -31,8 +31,8 @@ fallbacks) for inline images/maps.

## Repository state

**M1 delivered, plus substantial M2–M4 work.** `MuGlyph.slnx` builds all ten projects on
`net10.0`; the solution has **391 passing tests**. In place:
**M1 delivered, plus substantial M2–M4 work.** `SharpMUTerm.slnx` builds all ten projects on
`net10.0`; the solution has **514 passing tests**. In place:

- **Core** — `AnsiParser` (SGR 16/256/truecolor), styled-line + `ScrollbackBuffer` model,
`TcpTransport` (TLS + IPv6), `TelnetSession` (wraps TelnetNegotiationCore **2.5.3**),
Expand Down Expand Up @@ -70,30 +70,30 @@ fallbacks) for inline images/maps.

## Architecture rule (non-negotiable)

`MuClient.Core` stays **UI-agnostic and fully unit-testable**. All transport, telnet, parsing
`SharpMUTerm.Core` stays **UI-agnostic and fully unit-testable**. All transport, telnet, parsing
(ANSI/MXP/Pueblo), GMCP/MSDP routing, scrollback, and trigger/alias/macro engines live there.
SharpConsoleUI is referenced **only** from `MuClient.Tui`.
SharpConsoleUI is referenced **only** from `SharpMUTerm.Tui`.

Planned solution layout:

| Project | Responsibility |
|---|---|
| `MuClient.Core` | Transport, telnet, ANSI/MXP/Pueblo parsers, GMCP/MSDP routing, scrollback, engines, logging (no UI deps) |
| `MuClient.Graphics` | Kitty graphics protocol, capability probe, Sixel + half-block fallbacks, `GraphicsView` |
| `MuClient.Scripting` | MoonSharp host + scripting API |
| `MuClient.Tui` | SharpConsoleUI application |
| `SharpMUTerm.Core` | Transport, telnet, ANSI/MXP/Pueblo parsers, GMCP/MSDP routing, scrollback, engines, logging (no UI deps) |
| `SharpMUTerm.Graphics` | Kitty graphics protocol, capability probe, Sixel + half-block fallbacks, `GraphicsView` |
| `SharpMUTerm.Scripting` | MoonSharp host + scripting API |
| `SharpMUTerm.Tui` | SharpConsoleUI application |
| `*.Tests` (Core, Graphics, Scripting, Web, Tui) | TUnit |

## Milestone M1 — first task (delivered)

Kept for context; **M1 is done** (see *Repository state* above). As originally scoped:

1. Create `MuGlyph.slnx` with the projects above targeting `net10.0`, plus the TUnit test projects.
1. Create `SharpMUTerm.slnx` with the projects above targeting `net10.0`, plus the TUnit test projects.
2. Add NuGet references (see version notes below).
3. Runnable stub: connect over TCP (+ optional TLS via `SslStream`, IPv6-capable), pipe received
bytes through a first-pass `AnsiParser` (SGR: 16 / 256 / 24-bit color), render colored output
in a SharpConsoleUI window with an input line + history.
4. Unit-test `AnsiParser` and the telnet-session wrapper in `MuClient.Core.Tests`.
4. Unit-test `AnsiParser` and the telnet-session wrapper in `SharpMUTerm.Core.Tests`.

## Dependency notes / traps

Expand All @@ -112,7 +112,8 @@ Kept for context; **M1 is done** (see *Repository state* above). As originally s

## Verification

- Primary signal: `dotnet build` + `dotnet test`. Keep coverage in `MuClient.Core.Tests`
- Primary signal: `dotnet build` + `dotnet run --project <testproj>` for each test project
(see the TUnit/MTP note above — `dotnet test` does **not** work here). Keep coverage in `SharpMUTerm.Core.Tests`
(ANSI/SGR parser, telnet round-trips, engines).
- A headless sandbox **cannot** visually verify a TUI and **cannot** render Kitty graphics.
Treat the graphics layer as build-verified + capability-probed, never visually confirmed;
Expand Down
6 changes: 3 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>

<!-- Shared settings for every project in the MuGlyph solution. -->
<!-- Shared settings for every project in the SharpMUTerm solution. -->
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
Expand All @@ -11,10 +11,10 @@
<InvariantGlobalization>true</InvariantGlobalization>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<Authors>Harry Cordewener</Authors>
<Product>MuGlyph</Product>
<Product>SharpMUTerm</Product>
<Copyright>Copyright (c) 2026 Harry Cordewener</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/HarryCordewener/MuGlyph</RepositoryUrl>
<RepositoryUrl>https://github.com/SharpMUSH/SharpMUTerm</RepositoryUrl>
</PropertyGroup>

</Project>
16 changes: 0 additions & 16 deletions MuGlyph.slnx

This file was deleted.

37 changes: 21 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
# MuGlyph
# SharpMUTerm

A hyper-modern, cross-platform **TUI client for MU\*** (MUSH / MUCK / MUD) worlds, built for
GPU-accelerated terminals (Kitty, WezTerm, Ghostty) on **Windows and Linux**.

Part of the [SharpMUSH](https://github.com/SharpMUSH) family: **SharpMUSH** is the server,
[**SharpClient**](https://github.com/SharpMUSH/SharpClient) is the graphical client, and
**SharpMUTerm** is the terminal one. It speaks plain telnet, so it connects to any MU\* world —
not just SharpMUSH ones.

The goal is [BeipMU](https://beipdev.github.io/BeipMU/)-class feature parity in a terminal-native
client: rich truecolor text, inline graphics, powerful automation, and full MU\* protocol support.

> **Status:** milestone **M1 delivered** (usable text client foundation) with substantial work
> from M2–M4 in place — automation engines, inline-graphics subsystem, Lua scripting, and theming.
> `MuClient.Core` is fully unit-tested (391 tests across the solution). See
> `SharpMUTerm.Core` is fully unit-tested (514 tests across the solution). See
> [`docs/PLAN.md`](docs/PLAN.md) for the full architecture and roadmap.

## Why a TUI

"GPU acceleration" is a property of the terminal *emulator*, not the app. Any TUI running inside
Kitty / WezTerm / Ghostty gets GPU-accelerated glyph rendering for free. MuGlyph focuses on emitting
Kitty / WezTerm / Ghostty gets GPU-accelerated glyph rendering for free. SharpMUTerm focuses on emitting
rich truecolor/styled text and using the **Kitty graphics protocol** (with Sixel and half-block
fallbacks) for inline images and maps.

Expand All @@ -36,10 +41,10 @@ HTML logging · GMCP / MSDP / MSSP / MCCP · MXP + Pueblo · Unicode/emoji.

| Project | Responsibility |
|---|---|
| `MuClient.Core` | Transport, telnet, ANSI/MXP/Pueblo parsers, GMCP/MSDP routing, scrollback, trigger/alias/macro engines, logging (UI-agnostic) |
| `MuClient.Graphics` | Kitty graphics protocol, capability probe, Sixel + half-block fallbacks, `GraphicsView` |
| `MuClient.Scripting` | MoonSharp host + scripting API |
| `MuClient.Tui` | SharpConsoleUI application (windows, panes, settings, wiring) |
| `SharpMUTerm.Core` | Transport, telnet, ANSI/MXP/Pueblo parsers, GMCP/MSDP routing, scrollback, trigger/alias/macro engines, logging (UI-agnostic) |
| `SharpMUTerm.Graphics` | Kitty graphics protocol, capability probe, Sixel + half-block fallbacks, `GraphicsView` |
| `SharpMUTerm.Scripting` | MoonSharp host + scripting API |
| `SharpMUTerm.Tui` | SharpConsoleUI application (windows, panes, settings, wiring) |
| `*.Tests` | TUnit test projects |

## What works today
Expand Down Expand Up @@ -75,7 +80,7 @@ HTML logging · GMCP / MSDP / MSSP / MCCP · MXP + Pueblo · Unicode/emoji.
character-bound input prompt + destination/draft gutter. Output is truecolor markup with clickable
MXP/Pueblo/web spans; NAWS is re-advertised on resize. `Ctrl+N` next window · `Ctrl+O` next pane ·
`Ctrl+W` close · `Ctrl+Q` quit.
- **Web view** — an in-TUI text-mode browser (`MuClient.Web`, AngleSharp): fetch a URL or
- **Web view** — an in-TUI text-mode browser (`SharpMUTerm.Web`, AngleSharp): fetch a URL or
follow an MXP/Pueblo/HTML link and read the page as styled, word-wrapped text with clickable
links you can navigate in-pane. `<img>` shows as a labelled link (graphics-terminal image
rendering reuses the Kitty/Sixel/half-block pipeline).
Expand All @@ -87,14 +92,14 @@ HTML logging · GMCP / MSDP / MSSP / MCCP · MXP + Pueblo · Unicode/emoji.
Requires the **.NET 10 SDK**.

```bash
dotnet build MuGlyph.slnx -c Release
dotnet build SharpMUTerm.slnx -c Release
```

## Running

```bash
dotnet run --project src/MuClient.Tui -- <host> <port> [--tls] [--insecure] [--name NAME]
muglyph --help # once published
dotnet run --project src/SharpMUTerm.Tui -- <host> <port> [--tls] [--insecure] [--name NAME]
sharpmuterm --help # once published
```

In-app: **Up/Down** input history · **Ctrl+N** next window · **Ctrl+W** close window · **Ctrl+Q** quit. (Windows/panes are mouse-resizable; each window keeps its own input draft.)
Expand All @@ -105,11 +110,11 @@ The test projects use [TUnit], which runs on the Microsoft.Testing.Platform. Run
(the classic `dotnet test`/VSTest path is not used by MTP on .NET 10):

```bash
dotnet run --project tests/MuClient.Core.Tests
dotnet run --project tests/MuClient.Graphics.Tests
dotnet run --project tests/MuClient.Scripting.Tests
dotnet run --project tests/MuClient.Web.Tests
dotnet run --project tests/MuClient.Tui.Tests
dotnet run --project tests/SharpMUTerm.Core.Tests
dotnet run --project tests/SharpMUTerm.Graphics.Tests
dotnet run --project tests/SharpMUTerm.Scripting.Tests
dotnet run --project tests/SharpMUTerm.Web.Tests
dotnet run --project tests/SharpMUTerm.Tui.Tests
```

## License
Expand Down
16 changes: 16 additions & 0 deletions SharpMUTerm.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/SharpMUTerm.Core/SharpMUTerm.Core.csproj" />
<Project Path="src/SharpMUTerm.Graphics/SharpMUTerm.Graphics.csproj" />
<Project Path="src/SharpMUTerm.Scripting/SharpMUTerm.Scripting.csproj" />
<Project Path="src/SharpMUTerm.Tui/SharpMUTerm.Tui.csproj" />
<Project Path="src/SharpMUTerm.Web/SharpMUTerm.Web.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/SharpMUTerm.Core.Tests/SharpMUTerm.Core.Tests.csproj" />
<Project Path="tests/SharpMUTerm.Graphics.Tests/SharpMUTerm.Graphics.Tests.csproj" />
<Project Path="tests/SharpMUTerm.Scripting.Tests/SharpMUTerm.Scripting.Tests.csproj" />
<Project Path="tests/SharpMUTerm.Tui.Tests/SharpMUTerm.Tui.Tests.csproj" />
<Project Path="tests/SharpMUTerm.Web.Tests/SharpMUTerm.Web.Tests.csproj" />
</Folder>
</Solution>
18 changes: 9 additions & 9 deletions docs/PACKAGING.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
# Packaging MuGlyph
# Packaging SharpMUTerm

MuGlyph publishes as a **self-contained, single-file** executable — no .NET runtime required on
SharpMUTerm publishes as a **self-contained, single-file** executable — no .NET runtime required on
the target machine.

## Supported runtimes

`linux-x64`, `linux-arm64`, `win-x64`, `osx-x64`, `osx-arm64` (declared in
`src/MuClient.Tui/MuClient.Tui.csproj`).
`src/SharpMUTerm.Tui/SharpMUTerm.Tui.csproj`).

## Local publish

Publish profiles live in `src/MuClient.Tui/Properties/PublishProfiles/`:
Publish profiles live in `src/SharpMUTerm.Tui/Properties/PublishProfiles/`:

```bash
# Linux x64 → publish output contains a single `muglyph` binary
dotnet publish src/MuClient.Tui -p:PublishProfile=linux-x64 -o out/linux-x64
# Linux x64 → publish output contains a single `sharpmuterm` binary
dotnet publish src/SharpMUTerm.Tui -p:PublishProfile=linux-x64 -o out/linux-x64

# Windows x64 → `muglyph.exe`
dotnet publish src/MuClient.Tui -p:PublishProfile=win-x64 -o out/win-x64
# Windows x64 → `sharpmuterm.exe`
dotnet publish src/SharpMUTerm.Tui -p:PublishProfile=win-x64 -o out/win-x64
```

For a RID without a profile, pass the flags directly:

```bash
dotnet publish src/MuClient.Tui -c Release -r osx-arm64 \
dotnet publish src/SharpMUTerm.Tui -c Release -r osx-arm64 \
--self-contained -p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true -o out/osx-arm64
```
Expand Down
Loading
Loading