diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ecbd4b8..d776c2a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -80,23 +80,23 @@ jobs:
- name: Publish Client win-x64
if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
- run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r win-x64 --self-contained true -o publish/client-win-x64
+ run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-win-x64
- name: Publish Client linux-x64
if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
- run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r linux-x64 --self-contained true -o publish/client-linux-x64
+ run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-linux-x64
- name: Publish Client osx-x64
if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
- run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r osx-x64 --self-contained true -o publish/client-osx-x64
+ run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-osx-x64
- name: Publish Client osx-arm64
if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
- run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r osx-arm64 --self-contained true -o publish/client-osx-arm64
+ run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r osx-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-osx-arm64
- name: Publish Client linux-arm64
if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
- run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r linux-arm64 --self-contained true -o publish/client-linux-arm64
+ run: dotnet publish src/EchoHub.Client/EchoHub.Client.csproj -c Release -r linux-arm64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/client-linux-arm64
- name: Zip artifacts
if: steps.changes.outputs.src_changed == 'true' && steps.check_release.outputs.exists == 'false'
diff --git a/docs/changelog/v0.2.9.md b/docs/changelog/v0.2.9.md
new file mode 100644
index 0000000..3fc6db7
--- /dev/null
+++ b/docs/changelog/v0.2.9.md
@@ -0,0 +1,5 @@
+# v0.2.9
+
+## Bug Fixes
+
+- Fix Linux/macOS client install — enable single-file publish so the install script copies one self-contained binary instead of just the native host (which failed with "does not exist: EchoHub.Client.dll")
diff --git a/docs/todo.md b/docs/todo.md
index 07726db..eb04e7d 100644
--- a/docs/todo.md
+++ b/docs/todo.md
@@ -15,10 +15,11 @@
- [x] unmute timer does not seem to work
- [ ] add IRC network like support
- that means basically multiple servers linked, so users can chat cross-server in this network
-- [ ] when users clicks public -> private -> public checkbox in the channel creation, it ends up creating the channel on 3rd check switch
+- [x] when users clicks public -> private -> public checkbox in the channel creation, it ends up creating the channel on 3rd check switch
- [ ] add keyboard only controls | at least for most important parts and the rest might be accessible with: (down)
- [ ] add search bar / search modal – that will allow users to instantly navigate to room / focus on app element & etc
- [ ] Actually smart data management – cache messages, lazy load messages on scroll (currently hardcoded 100msgs fetched + new ones)
- [x] Another thing would be stateful userlist – basically fetch once and listen for userlist updates
- [x] Send to EchohubSpace only state changes, currently we send user count periodically, instead of updating it on update
- [x] space between mod|admin "icon" and username
+- [ ] Embeds still incorrectly display colors
diff --git a/packaging/choco/echohub.nuspec b/packaging/choco/echohub.nuspec
index e908659..a3137e1 100644
--- a/packaging/choco/echohub.nuspec
+++ b/packaging/choco/echohub.nuspec
@@ -7,17 +7,17 @@
HueByte
HueByte
false
- https://github.com/HueByteByte/EchoHub/blob/master/LICENSE
- https://github.com/HueByteByte/EchoHub
- https://github.com/HueByteByte/EchoHub
- https://HueBytebyte.github.io/EchoHub
- https://github.com/HueByteByte/EchoHub/issues
- https://github.com/HueByteByte/EchoHub/tree/master/packaging/choco
- https://raw.githubusercontent.com/HueByteByte/EchoHub/master/assets/HueByte_icon.png
+ https://github.com/HueByte/EchoHub/blob/master/LICENSE
+ https://github.com/HueByte/EchoHub
+ https://github.com/HueByte/EchoHub
+ https://huebyte.github.io/EchoHub
+ https://github.com/HueByte/EchoHub/issues
+ https://github.com/HueByte/EchoHub/tree/master/packaging/choco
+ https://raw.githubusercontent.com/HueByte/EchoHub/refs/heads/master/assets/hue_icon.png
EchoHub is a decentralized IRC-style chat application with a terminal user interface (TUI). Connect to any EchoHub server, join channels, and chat — all from your terminal. Features include SignalR real-time messaging, file sharing, custom themes, and IRC gateway compatibility.
Decentralized terminal chat client with IRC gateway support
chat irc decentralized tui terminal signalr echohub
- https://HueBytebyte.github.io/EchoHub/changelog/v__VERSION__.html
+ https://huebyte.github.io/EchoHub/changelog/v__VERSION__.html
Copyright (c) 2026 HueByte
diff --git a/packaging/choco/tools/chocolateyInstall.ps1 b/packaging/choco/tools/chocolateyInstall.ps1
index a483c19..af14c59 100644
--- a/packaging/choco/tools/chocolateyInstall.ps1
+++ b/packaging/choco/tools/chocolateyInstall.ps1
@@ -14,5 +14,6 @@ $packageArgs = @{
Install-ChocolateyZipPackage @packageArgs
# Create a shim so 'echohub' is available on PATH
-$exePath = Join-Path $toolsDir 'client-win-x64' 'EchoHub.Client.exe'
+$exeDir = Join-Path $toolsDir 'client-win-x64'
+$exePath = Join-Path $exeDir 'EchoHub.Client.exe'
Install-BinFile -Name 'echohub' -Path $exePath
diff --git a/scripts/install.sh b/scripts/install.sh
index 576c30e..238604d 100644
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -199,10 +199,17 @@ main() {
fi
fi
- # Install the binary
+ # Install full directory to ~/.local/share/echohub and symlink the binary.
+ # Even single-file publishes may have content files (appsettings, assets)
+ # that the app expects next to the binary via AppContext.BaseDirectory.
+ app_dir="$HOME/.local/share/echohub"
+ rm -rf "$app_dir"
+ mkdir -p "$app_dir"
+ cp -r "$src_dir"/. "$app_dir/"
+ chmod +x "$app_dir/EchoHub.Client"
+
mkdir -p "$install_dir"
- cp "$src_dir/EchoHub.Client" "$install_dir/$BINARY_NAME"
- chmod +x "$install_dir/$BINARY_NAME"
+ ln -sf "$app_dir/EchoHub.Client" "$install_dir/$BINARY_NAME"
echo ""
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 744d01d..24de7d9 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,6 +1,6 @@
- 0.2.8
+ 0.2.9
true
$(NoWarn);CS1591
diff --git a/src/EchoHub.Client/EchoHub.Client.csproj b/src/EchoHub.Client/EchoHub.Client.csproj
index 70753d0..a4ab665 100644
--- a/src/EchoHub.Client/EchoHub.Client.csproj
+++ b/src/EchoHub.Client/EchoHub.Client.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/src/EchoHub.Client/UI/Dialogs/CreateChannelDialog.cs b/src/EchoHub.Client/UI/Dialogs/CreateChannelDialog.cs
index a00dd5b..076b2ad 100644
--- a/src/EchoHub.Client/UI/Dialogs/CreateChannelDialog.cs
+++ b/src/EchoHub.Client/UI/Dialogs/CreateChannelDialog.cs
@@ -12,7 +12,7 @@ public sealed class CreateChannelDialog
{
CreateChannelResult? result = null;
- var dialog = new Dialog { Title = "Create Channel", Width = 50, Height = 14 };
+ var dialog = new Dialog { Title = "Create Channel", Width = 50, Height = 14, CommandsToBubbleUp = [] };
var nameLabel = new Label { Text = "Name:", X = 1, Y = 1 };
var nameField = new TextField { X = 10, Y = 1, Width = Dim.Fill(2) };