chore: bump version to 1.4.7, sync changelog and forge post

- csproj <Version> -> 1.4.7
- repo.json AssemblyVersion + TestingAssemblyVersion -> 1.4.7.0
- repo.json DownloadLink{Install,Update,Testing} URLs -> /v1.4.7/
- repo.json + HellionChat.yaml changelog: prepend v1.4.7 block, retire
  v1.4.3 (slim rule keeps the last 3-4 versions)
- docs/CHANGELOG.md + docs/ROADMAP.md: v1.4.7 section, next-cycle
  pointer flipped to v1.4.8 Hook-Layer-Cycle
- README.md release badge + version stamps + Project Status block
  rewritten for v1.4.7
- .github/forge-posts/v1.4.7.md (new): DE body with subtitle
  "Backlog Cleanup and Mid-Features" / versionsnatur "Mid-Feature-Patch"
- Pin diagnostic logs (RehydratePinnedTabs / TryPin / Unpin /
  PromoteToPermanent) downgraded from Info to Debug so non-debug
  console stays quiet on release builds
This commit is contained in:
2026-05-13 11:00:25 +02:00
parent d5735d8dcc
commit f4ea460644
8 changed files with 167 additions and 48 deletions
+29
View File
@@ -0,0 +1,29 @@
---
subtitle: Backlog Cleanup and Mid-Features
versionsnatur: Mid-Feature-Patch
---
Achter Sub-Patch der v1.4.x Polish-Sweep-Serie. Erstes User-sichtbares Feature-Bundle seit v1.4.5 — angepinnte Tell-Tabs
die Relog überleben, opt-in Honorific-Glow, plus eine konfigurierbare Sidebar.
- **TempTell anpinnen**: Rechtsklick auf einen TempTell-Tab in der Sidebar → „Tab anpinnen". Angepinnte Tabs überleben
Plugin-Reload und Char-Logout, behalten ihre Konversations-Historie (wird beim Rehydrate aus dem MessageStore
nachgeladen) und bleiben an die gleiche /tell-Person gebunden. Hard-Cap 5 angepinnte Tabs in einem separaten Pool —
die normalen Auto-Tell-Tabs (15er Cap) sind davon entkoppelt, Gesamt-Decke 20. Die Sidebar gruppiert angepinnte Tabs
in einer eigenen „Angepinnt"-Sektion mit eigenem Trenner.
- **Honorific Glow-Outline**: rendert jetzt eine 8-Richtungs-DrawList-Outline wenn der Honorific-Titel eine Glow-Farbe
trägt. Opt-in via **Settings → Integrationen → Glow-Outline rendern (Honorific)** (Default OFF). Gradient (Color3 /
GradientColourSet / Wave / Pulse) wird geparst und im DTO weitergereicht, rendert aktuell aber statisch als
Primärfarbe — der volle Gradient-Port (Animations-Algorithmus + Pride-Palette) kommt als eigener Cycle nach.
- **Sidebar-Breite konfigurierbar**: in **Theme & Layout** ein Slider 44160 px. Default bleibt 44 px (icon-only), aber
breiter machen damit Sektion-Header wie „Aktive Tells (3)" oder „Angepinnt (2)" nicht abgeschnitten werden.
- **Settings-Save Channel-Fix**: ein Save mit aktivem Party- oder Linkshell-Tab konnte den Chat-Input zurück auf
`/tell <angepinnte Person>` springen lassen. `Configuration.UpdateFrom` bewahrt jetzt den Runtime-`CurrentChannel`
über den persistent-Tab-Merge hinweg, und `TabSwitched` deep-cloned den Seed-Channel statt sich den `UsedChannel` mit
dem vorigen Tab zu teilen.
- **Internal**: `IPluginLogProxy`-Indirektion vor Dalamud's `IPluginLog` über alle ~91 `Plugin.Log`-Call-Sites. Damit
läuft `MessageStore.Migrate0` voll-isoliert in xUnit (F12.1-Lücke aus v1.4.6 geschlossen). Plus: TempTab-Counter als
abgeleitete Property statt gecachtes Interlocked-Feld — die neuen Pin/Unpin-Übergänge sind Cold-Path, kein
Lock-Free-Vorteil mehr. Migration v16 → v17 ist rein additiv (neues `Tab.IsPinned`-Bool, Default false).
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
+6 -6
View File
@@ -67,7 +67,7 @@ internal sealed class AutoTellTabsService : IDisposable
private void RehydratePinnedTabs()
{
var pinned = Plugin.Config.Tabs.Count(TabLifecycleHelpers.IsInPinnedPool);
Plugin.LogProxy.Info($"[Pin] Rehydrate scan: {pinned} pinned tab(s) found");
Plugin.LogProxy.Debug($"[Pin] Rehydrate scan: {pinned} pinned tab(s) found");
foreach (var tab in Plugin.Config.Tabs)
{
@@ -93,7 +93,7 @@ internal sealed class AutoTellTabsService : IDisposable
// sees the recent conversation, not a blank tab.
PreloadHistory(tab, tab.TellTarget.Name, tab.TellTarget.World, Guid.Empty);
Plugin.LogProxy.Info(
Plugin.LogProxy.Debug(
$"[Pin] Rehydrated '{tab.Name}' -> Tell target {tab.TellTarget.Name}@{tab.TellTarget.World}"
);
}
@@ -456,7 +456,7 @@ internal sealed class AutoTellTabsService : IDisposable
{
if (!tab.IsTempTab || tab.IsPinned)
{
Plugin.LogProxy.Info(
Plugin.LogProxy.Debug(
$"[Pin] TryPin skipped: IsTempTab={tab.IsTempTab} IsPinned={tab.IsPinned}"
);
return false;
@@ -472,7 +472,7 @@ internal sealed class AutoTellTabsService : IDisposable
}
tab.IsPinned = true;
Plugin.LogProxy.Info(
Plugin.LogProxy.Debug(
$"[Pin] Pinned tab '{tab.Name}' target={tab.TellTarget?.Name}@{tab.TellTarget?.World}"
);
_plugin.SaveConfig();
@@ -495,7 +495,7 @@ internal sealed class AutoTellTabsService : IDisposable
}
tab.IsPinned = false;
Plugin.LogProxy.Info($"[Pin] Unpinned tab '{tab.Name}'");
Plugin.LogProxy.Debug("[Pin] Unpinned tab '{tab.Name}'");
_plugin.SaveConfig();
}
@@ -509,7 +509,7 @@ internal sealed class AutoTellTabsService : IDisposable
tab.IsTempTab = false;
tab.IsPinned = false;
tab.TellTarget = TellTarget.Empty();
Plugin.LogProxy.Info(
Plugin.LogProxy.Debug(
$"[Pin] Promoted tab '{tab.Name}' to permanent (tell-binding dropped)"
);
_plugin.SaveConfig();
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
<PropertyGroup>
<!-- Independent versioning; see yaml changelog for upstream Chat 2 base -->
<Version>1.4.6</Version>
<Version>1.4.7</Version>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Use lock file to pin exact versions -->
+43 -15
View File
@@ -35,6 +35,49 @@ tags:
- Replacement
- Privacy
changelog: |-
**v1.4.7 — Backlog Cleanup and Mid-Features (2026-05-13)**
Eighth sub-patch of the v1.4.x polish-sweep series. First
user-visible feature bundle since v1.4.5 — pinned tell tabs that
survive relog, opt-in Honorific glow rendering, and a configurable
sidebar.
- TempTell Pin: right-click a TempTell tab in the sidebar to pin
it. Pinned tabs survive relog, keep their conversation history
(loaded on demand from the message store), and stay bound to
the same /tell partner. Hard cap of 5 pinned tabs in a pool
separate from the 15-tab auto-tell pool — total ceiling is 20
tabs. New 'Pinned' section in the sidebar with its own divider
header
- Honorific Glow outline now renders when the title carries a
Glow colour. Opt-in via Settings → Integrations → 'Render glow
outlines (Honorific)' (default off, dodges the per-frame
DrawList overhead on low-end hardware). Gradient (Color3 /
GradientColourSet / Wave / Pulse) is parsed but rendered
statically — a later cycle will port the full animation
- Sidebar width is now configurable in Theme & Layout (range
44160 px). Default stays icon-only; widen to fit section
headers like 'Active Tells (3)' without truncation
- Settings Save no longer pops the chat input back to /tell with
a pinned partner — Configuration.UpdateFrom now preserves the
runtime CurrentChannel across the persistent-tab merge, and
TabSwitched deep-clones the seeded channel instead of sharing
the previous tab's UsedChannel
- Util/ImGuiUtil.cs DrawArrows IconButton id now uses
(id + 1).ToString() instead of the operator-precedence quirk
id + 1.ToString() — generated IDs stay numerically stable
- Internal: IPluginLogProxy indirection over Dalamud's IPluginLog
routes all ~91 Plugin.Log call sites through a testable proxy.
MessageStore.Migrate0 can now run in xUnit without loading
Dalamud.dll, closing the gap F12.1 left in v1.4.6
- Internal: TempTab counter switched from an Interlocked cached
field to a derived Tabs.Count(predicate) — pin-state transitions
are cold-path and don't need lock-free reads
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
---
**v1.4.6 — Code Hygiene and Refactor (2026-05-12)**
Maintenance patch. No user-visible behaviour changes; tightens the
@@ -117,19 +160,4 @@ changelog: |-
---
**v1.4.3 — Faster plugin load + new repo (2026-05-08)**
Heavy startup work (migrations, hooks, windows) now runs async so
Dalamud's UI stays responsive during load. Load time is comparable
to v1.4.2 — this is the foundation for v1.4.4 optimisations.
- Two-phase async load via IAsyncDalamudPlugin
- Schema-gate replaces the v9→v16 migration chain; old configs
require a v1.4.2 install first
- AutoTranslate cache loads on first use instead of every startup
- Custom font (Hellion-Exo2) appears with a brief pop after load
- Repo moved to gitea.hellion-forge.cloud — update your custom-repo URL
---
Full history: https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases
+19 -16
View File
@@ -2,7 +2,7 @@
[![Build](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/actions/workflows/build.yml/badge.svg?branch=main)](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/actions/workflows/build.yml)
[![License: EUPL-1.2](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](LICENSE)
[![Latest release](https://img.shields.io/badge/release-v1.4.6-brightgreen)](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/latest)
[![Latest release](https://img.shields.io/badge/release-v1.4.7-brightgreen)](https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/releases/latest)
[![Dalamud API](https://img.shields.io/badge/Dalamud-API_15-purple)](https://github.com/goatcorp/Dalamud)
[![.NET](https://img.shields.io/badge/.NET-10.0-512BD4)](https://dotnet.microsoft.com/)
[![FFXIV](https://img.shields.io/badge/FFXIV-Dawntrail-c3a37f)](https://www.finalfantasyxiv.com/)
@@ -11,7 +11,7 @@
<img src="docs/images/hellion-forge.png" alt="Hellion Forge" width="180" />
</p>
**Version 1.4.6** — Privacy-first chat plugin for FINAL FANTASY XIV / Dalamud, built on
**Version 1.4.7** — Privacy-first chat plugin for FINAL FANTASY XIV / Dalamud, built on
[Chat 2](https://github.com/Infiziert90/ChatTwo) (EUPL-1.2).
Hellion Chat is a privacy-first plugin built on the Chat 2 foundation. The majority of the engine comes from Chat 2
@@ -286,20 +286,23 @@ An optional submission to the Dalamud main plugin repo (in addition to the custo
## Project Status
**Version 1.4.6**Maintenance patch. No user-visible behaviour changes; tightens the development feedback loop and
pulls in two ChatTwo upstream bugfixes. `scripts/preflight.sh` gains a csharpier reflow check and a markdownlint pass at
the pre-push gate. `FontManager`'s font-fallback catch-filter now covers `InvalidOperationException` and
`ArgumentException` on top of the IO triad, so a corrupted font config no longer takes down the atlas build.
`BrandingLinks` and `IntegrationLinks` URLs validate themselves on plugin load — a typo in a future URL rotation throws
at startup instead of failing silently when a user clicks the broken button. Cherry-picked from ChatTwo upstream
`f35b7d3`: `Chat.SetChannel` no longer leaks the native `Utf8String` when the linkshell check rejects the channel, and
`Tab.Clone` now deep-clones `UsedChannel` and `TellTarget` (the previous reference copy let PopOut and Temp tabs mutate
each other's channel state). The active-tab underline pill scales with DPI and rounds to physical pixels for crisp
rendering above 100 % DPI. Internal items: `HellionStyle` ChildBgAlpha extracted to a testable helper,
`Plugin.SaveConfig` clones only the temp-tab subset, `SettingsOverview` caches the draw-list per frame,
`Dalamud.Utility.Util` static surface routed through an `IPlatformUtil` indirection (`MessageStore`'s `IsWine` probe is
now testable in isolation). No schema bump, no migration. Seventh sub-patch of the v1.4.x polish sweep series (as of
2026-05-12).
**Version 1.4.7**Backlog cleanup and the first user-visible feature bundle since v1.4.5. TempTell tabs can now be
pinned via right-click; pinned tabs survive relog, keep their conversation history (loaded on demand from the message
store), and stay bound to the same `/tell` partner. A hard cap of 5 pinned tabs lives in a pool separate from the 15-tab
auto-tell pool, so the total ceiling is 20 tabs. The sidebar groups pinned tabs into their own section with its own
divider header. Honorific glow outlines now render when the title carries a Glow colour — opt-in via **Settings →
Integrations → Render glow outlines (Honorific)**, default off, so v1.4.6 visuals stay untouched for users who don't
care and the per-frame DrawList overhead is skipped on low-end hardware. Honorific gradient (Color3 / GradientColourSet
/ Wave / Pulse) is parsed and stashed for a later cycle, but currently renders as the primary colour. Sidebar width is
configurable in **Theme & Layout** between 44 and 160 px; default stays icon-only so existing users see no layout
change. `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the persistent-tab merge, and
`TabSwitched` deep-clones the seeded channel — together they fix a Settings-Save regression where the chat input could
pop back to `/tell <pinned-partner>` after touching settings while on a Party or Linkshell tab. Internal items:
`IPluginLogProxy` indirection over Dalamud's `IPluginLog` routes all ~91 `Plugin.Log` call sites through a testable
proxy, closing the test-isolation gap F12.1 left in v1.4.6 (`MessageStore.Migrate0` now runs in xUnit without loading
`Dalamud.dll`). `Util/ImGuiUtil.cs`'s `DrawArrows` IconButton id gets explicit parentheses on the increment. Migration
v16 → v17 is additive (new `Tab.IsPinned` flag, default false). Eighth sub-patch of the v1.4.x polish sweep series (as
of 2026-05-13).
Hellion Chat is a standalone plugin, no longer a fork in the repository sense. Fully completed:
+39
View File
@@ -10,6 +10,45 @@ to the release pages for details.
---
## Hellion Chat 1.4.7 — Backlog Cleanup and Mid-Features (2026-05-13)
Eighth sub-patch of the v1.4.x polish-sweep series. First user-visible feature bundle since v1.4.5 — pinned tell tabs
that survive relog, opt-in Honorific glow rendering, a configurable sidebar, plus a Settings-Save channel-preservation
fix surfaced during smoke testing.
- TempTell Pin: right-click a TempTell tab in the sidebar and choose "Pin Tab" / "Tab anpinnen". Pinned tabs survive
plugin reload and character logout, keep their conversation history (loaded on demand from the message store on
rehydrate), and stay bound to the same `/tell` partner. Hard cap of 5 pinned tabs in a pool separate from the 15-tab
auto-tell pool — total ceiling is 20 tabs. The sidebar groups pinned tabs into their own section with a divider header
- Honorific glow outlines now render via an 8-direction DrawList pre-pass when the title carries a Glow colour. Opt-in
via **Settings → Integrations → Render glow outlines (Honorific)** (default off). Honorific's gradient surface
(`Color3`, `GradientColourSet`, `GradientAnimationStyle`) is parsed and stashed for a later cycle but renders as the
primary colour until then — the v1.4.7 DTO already mirrors all four extra fields so the JSON roundtrip doesn't
silent-drop them
- Sidebar width configurable in **Theme & Layout** (44160 px, default 44 stays icon-only). The icon button stretches
with the configured width so a widened sidebar looks intentional, not a 36 px icon floating in empty space
- `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the persistent-tab merge alongside
`Messages` and `LastSendUnread`. `TabSwitched` deep-clones the seeded channel from the previous tab instead of sharing
the same `UsedChannel` instance. Together these fix a regression where Settings-Save on a Party or Linkshell tab
popped the chat input back to `/tell <pinned-partner>` on the next interaction
- `Util/ImGuiUtil.cs` `DrawArrows` IconButton id uses `(id + 1).ToString()` with explicit parentheses instead of the
operator-precedence quirk `id + 1.ToString()` (which resolved to `id.ToString() + "1"`). Single live caller is
`Ui/DbViewer.cs:227` page-navigation
- Internal: `IPluginLogProxy` indirection over Dalamud's `IPluginLog` routes all ~91 `Plugin.Log` call sites through a
testable proxy. `MessageStore.Migrate0` can now run in xUnit without loading `Dalamud.dll`, closing the gap F12.1 left
in v1.4.6. Production wrapper `DalamudPluginLogProxy` and Build-Suite `FakePluginLogProxy` mirror the full
`IPluginLog` surface (`Verbose`/`Debug`/`Information`/`Info`/`Warning`/`Error`/`Fatal`) with single-string,
`Exception+string`, and `params object[]` overloads
- Internal: TempTab counter switched from an `Interlocked` cached field to a derived `Tabs.Count(predicate)`. Pin-state
transitions (TryPin / Unpin / Promote) are cold-path and don't need lock-free reads; counter mutation surface dropped
from 5 to 0 sites. Build-Suite floor 688 → 710 (+22)
- Schema bump v16 → v17 is additive: new `Tab.IsPinned` bool, default false. Existing v16 configs load cleanly and get
their `Version` stamp bumped after the gate check
Based on Chat 2 1.35.3 (upstream Infiziert90/ChatTwo, EUPL-1.2).
---
## Hellion Chat 1.4.6 — Code Hygiene and Refactor (2026-05-12)
Maintenance patch. No user-visible behaviour changes; tightens the development feedback loop, fixes two
+24 -4
View File
@@ -10,14 +10,34 @@ the plugin's privacy-first scope during brainstorming.
---
## Next Cycle (v1.4.7)
## Next Cycle (v1.4.8)
**Backlog Cleanup.** Roll up the remaining audit items deferred from v1.4.0v1.4.6 and the new entries surfaced during
v1.4.6 (notably the `Plugin.Log` indirection that would unlock fully isolated `MessageStore` construction tests, plus
follow-up scope hinted at in the ChatTwo upstream f35b7d3 cherry-picks). Scope is consolidated during brainstorm.
**Hook-Layer Cycle.** Receive-suppressed-tells toggle (cross-reference XIVIM #73 bubble-layer sub-task), Database Viewer
full-text search via SQLite FTS5, plus preparation for the later Ad-Block cycle. Hook-layer investigation is shared
across these items so they cluster naturally in one sub-patch.
---
## v1.4.7 — Backlog Cleanup and Mid-Features (released 2026-05-13)
Eighth sub-patch of the v1.4.x Polish Sweep series. First user-visible feature bundle since v1.4.5. TempTell tabs can
now be pinned via right-click; pinned tabs survive plugin reload and character logout, keep their conversation history
(loaded on demand from the message store on rehydrate), and stay bound to the same `/tell` partner. A hard cap of 5
pinned tabs lives in a pool separate from the 15-tab auto-tell pool, total ceiling 20. The sidebar groups pinned tabs
into their own section with a divider header, and the sidebar width itself is now configurable in **Theme & Layout**
between 44 and 160 px. Honorific glow outlines render when the title carries a Glow colour, opt-in via **Settings →
Integrations → Render glow outlines (Honorific)** (default off). Honorific's gradient (Color3 / GradientColourSet / Wave
/ Pulse) is parsed but rendered statically — a later cycle will port the full animation algorithm or land an upstream
IPC PR for the resolved frame colour. `Configuration.UpdateFrom` now preserves the runtime `CurrentChannel` across the
persistent-tab merge, and `TabSwitched` deep-clones the seeded channel instead of sharing the previous tab's
`UsedChannel` — together they fix a Settings-Save regression where the chat input could pop back to
`/tell <pinned-partner>` after touching settings on a Party or Linkshell tab. Internal items: `IPluginLogProxy`
indirection over Dalamud's `IPluginLog` routes all ~91 `Plugin.Log` call sites through a testable proxy, closing the
F12.1 test-isolation gap (`MessageStore.Migrate0` runs in xUnit now). TempTab counter switched from `Interlocked` cached
field to derived `Tabs.Count(predicate)`. Migration v16 → v17 is additive (new `Tab.IsPinned` flag). Build-Suite floor
688 → 710 (+22 tests across Pin-lifecycle predicates, pool limits, Tab.Clone roundtrip, MessageStore Migrate0
construction, and Honorific TitleData JSON roundtrip).
## v1.4.6 — Code Hygiene and Refactor (released 2026-05-12)
Seventh sub-patch of the v1.4.x Polish Sweep series. Maintenance patch — no user-visible behaviour changes; tightens the
+6 -6
View File
File diff suppressed because one or more lines are too long