Commit Graph
100 Commits
Author SHA1 Message Date
JonKazama-Hellion 6d49dbad3e fix(ui): bounds-guard out-of-range list access in pop-out and tabs UI
Two pre-existing upstream defects fixed in v1.0.0:

- Ui/Popout.cs PopOutDocked[Idx] now bounds-checks Idx against
  ChatLogWindow.PopOutDocked.Count before reading or writing. A
  popout instance can outlive a list resize when AddPopOutsToDraw()
  rebuilds the docked-state list while a draw frame is in flight,
  which previously produced an out-of-range crash on tab drop
- Ui/SettingsTabs/Tabs.cs guards against an empty worlds list before
  indexing worlds[selectedWorld]. Empty lists can occur briefly when
  switching characters or before the datacenter sheet finishes
  loading — the previous code would crash with an
  ArgumentOutOfRangeException
2026-05-03 22:04:45 +02:00
JonKazama-Hellion a651b3b9ad fix: correctness bugs flagged by CodeRabbit
Four pre-existing upstream defects fixed in v1.0.0:

- Util/GlobalParametersCache.cs GetValue captures Cache into a local
  before the bounds check, so the check and the indexed read operate
  on the same array reference even when Refresh reassigns Cache from
  the main thread between the two operations
- Util/IconUtil.cs binary search bounds: hi initialized to
  entries.Length-1 (was Length), and reset on redirect-restart;
  added entries.Length==0 short-circuit to prevent indexing into
  empty arrays
- Sheets.cs WorldsOnDatacenter compared Region.RowId, which groups
  by region instead of datacenter — now compares DataCenter.RowId
  directly so the result actually reflects same-DC worlds
- Message.cs back-reference loop iterates the processed Sender/Content
  properties rather than the raw constructor parameters, so chunks
  added or replaced by CheckMessageContent also get Message set
2026-05-03 22:03:47 +02:00
JonKazama-Hellion 3f2e56be67 fix: tighten resource-leak and null-deref hot spots
Three pre-existing upstream defects flagged by CodeRabbit, fixed in the
v1.0.0 standalone cut where we own the codebase:

- Ipc/ExtraChat.cs Dispose now unsubscribes all three IPC subscriptions
  (OverrideChannelGate, ChannelCommandColoursGate, ChannelNamesGate)
  instead of only the first; previously the latter two leaked their
  subscriptions on every plugin reload
- GameFunctions/Types/TellTarget.cs FromTarget guards against a zero
  IPlayerCharacter.Address before dereferencing the unsafe Character*
  cast; previously a missing/destroyed target object would crash the
  game on /tell construction
- GameFunctions/GameFunctions.cs ResolveTextCommandPlaceholderDetour
  null-checks the Hook reference before calling .Original instead of
  using the null-forgiving operator; defensive guard for teardown races
2026-05-03 22:02:46 +02:00
JonKazama-Hellion feb6e262e4 fix(ipc): match Unregister call to Register call type in Dispose
UnregisterGate is registered via RegisterAction(Unregister) on
construction (Unregister returns void), but Dispose was calling
UnregisterFunc() instead of UnregisterAction(). The mismatched
unregister call leaks the action subscription on plugin reload —
subsequent Dispose/Init cycles would accumulate orphan handlers
in the Dalamud IPC layer.

Pre-existing upstream issue (CodeRabbit critical finding); fixed in
v1.0.0 standalone cut where we own the codebase.
2026-05-03 21:57:35 +02:00
JonKazama-Hellion 1d557f1b0e fix(code): replace GetHashCode comparison in ChatCode.Equals with field equality
Equals(object?) was delegating to GetHashCode() comparison, which is
the textbook hash-collision anti-pattern: two distinct ChatCode values
could in principle share a hash and be wrongly reported as equal. The
current GetHashCode implementation packs Type/Source/Target into 24
bits and happens to be collision-free, but the contract is fragile —
any future change to GetHashCode silently breaks Equals.

Replaced with direct field-by-field comparison of Type, Source, Target.
GetHashCode is left unchanged so dictionary/HashSet behavior stays
identical.

Pre-existing upstream issue (CodeRabbit critical finding); fixed in
v1.0.0 standalone cut where we own the codebase.
2026-05-03 21:57:17 +02:00
JonKazama-Hellion fea4965889 fix(util): correct AABB overlap test in MathUtil.HasOverlap
The previous implementation nested a ValueInRange helper that used
strict inequalities at both ends. That dropped identical rectangles
and shared-edge cases as false negatives — two rectangles with
a.X == b.X would miss the overlap on the X axis even when they
clearly overlapped.

Replaced with the standard AABB test: rectangles overlap iff they
overlap on both axes (a.Min < b.Max && a.Max > b.Min per axis).

Pre-existing upstream issue (CodeRabbit critical finding); fixed in
v1.0.0 standalone cut where we own the codebase.
2026-05-03 21:56:39 +02:00
JonKazama-Hellion 91663832f0 release: sync repo.json with v1.0.0 manifest
AssemblyVersion and TestingAssemblyVersion bumped to 1.0.0.0,
DownloadLinks (Install/Update/Testing) all point to
releases/download/v1.0.0/latest.zip, Changelog block mirrors
HellionChat.yaml.
2026-05-03 21:40:19 +02:00
JonKazama-Hellion 9cf1b19801 release: bump version to 1.0.0
First standalone major release. csproj version and yaml changelog
synchronized; repo.json sync follows in next commit.
2026-05-03 21:31:06 +02:00
JonKazama-Hellion 1f7f0945c5 build: rename repository folder ChatTwo to HellionChat
Repository folder, csproj, solution and all CI/build paths now use
the consolidated HellionChat name.

- ChatTwo/ → HellionChat/ (git mv preserves history with --follow)
- ChatTwo.csproj → HellionChat.csproj
- ChatTwo.sln → HellionChat.sln; obsolete Tests project entry removed
  (private/untracked sandbox)
- AssemblyInfo.cs InternalsVisibleTo for ChatTwo.Tests removed
  (file emptied; can be repopulated when actual tests land)
- repo.json and yaml image URLs updated (ChatTwo/images/ → HellionChat/images/)
- .github/workflows/{build,codeql,release}.yml csproj paths
- .github/dependabot.yml directory path

Functional behavior unchanged.
2026-05-03 21:30:07 +02:00
JonKazama-Hellion cd6afb32cb build: align RootNamespace with HellionChat post-rename
Updates the project root namespace and replaces the historical comment
about cherry-pick compatibility — that compatibility was the rationale
for keeping ChatTwo.* in source while AssemblyName was already
HellionChat. With v1.0.0 the standalone cut is complete and both
identifiers match.

Note: this commit also fixes the runtime MissingManifestResourceException
that the previous Task 6 commit caused — the embedded resource prefix
is derived from RootNamespace at build time, so Designer.cs string
arguments and the actual resource names only line up once both are set
to HellionChat.
2026-05-03 21:27:50 +02:00
JonKazama-Hellion 7d5496e959 refactor(namespace): rename ChatTwo.* to HellionChat.* across all source files
81 namespace declarations and 100 using directives converted via sed,
plus two FQN-aliases (ChatTwoPartyFinderPayload in PayloadHandler.cs and
ModifierFlag in KeybindManager.cs) updated. Critical: Language.Designer.cs
and HellionStrings.Designer.cs ResourceManager string arguments updated
synchronously — these are runtime reflection lookups not caught by the
C# compiler.

Two intentional ChatTwo references remain: the legacy migration path
'ChatTwo.json' in Plugin.cs (still points to upstream Chat 2's config
file by design) and the InternalsVisibleTo declaration in
AssemblyInfo.cs (handled in the upcoming repo-folder rename task).

The local alias names 'ChatTwoPartyFinderPayload' and 'ChatTwoConflictDetector'
are preserved as local symbols; only their target namespaces and references
changed.
2026-05-03 21:23:28 +02:00
JonKazama-Hellion ed426556e1 docs(branding): hellionize public-facing descriptions
README, repo.json and HellionChat.yaml describe the plugin as a
chat-replacement based on Chat 2 rather than as a Chat-2 fork. License
attribution (NOTICE.md, COPYRIGHT, THIRD_PARTY_NOTICES.md, README
credits section) is left untouched per EUPL-1.2 obligations.

Architecture section in README updated to reflect that the
HellionChat namespace is now consolidated (post-v1.0.0).
2026-05-03 21:20:50 +02:00
JonKazama-Hellion 96c445356b refactor(strings): hellionize functional comparison wording
Three user-facing strings reworded from upstream-comparison framing to
neutral phrasing. License attribution and personal-story strings remain
unchanged (EUPL-1.2 attribution, author's voice).

- Privacy filter description (EN/DE)
- Full-history mode tooltip (EN/DE)
- Colour preset 'ChatTwo Default'/'ChatTwo Standard' becomes
  'Klassik (Chat 2 Default)' in both languages
2026-05-03 21:15:30 +02:00
JonKazama-Hellion 1c2d361b77 feat(safety): refuse to load when Chat 2 is also active
When the user has both Hellion Chat and upstream Chat 2 installed and
loaded, the parallel chat-window replacement and Hook collisions can
crash FFXIV at frame boundaries. The new detector inspects
IDalamudPluginInterface.InstalledPlugins and throws an
InvalidOperationException with a localized message if Chat 2 is loaded,
which Dalamud surfaces cleanly instead of letting the load proceed
into a runtime crash.

Bilingual messages (EN/DE) follow the existing HellionStrings pattern.
2026-05-03 21:08:55 +02:00
JonKazama-Hellion 581aae1735 refactor(ui): rename ImGui popup ID to hellionchat- prefix
Prevents ImGui ID-stack collision when both Hellion Chat and upstream
Chat 2 try to render their context popups in the same frame.
2026-05-03 21:07:21 +02:00
JonKazama-Hellion 70109e1896 refactor(ipc): rename IPC channels from ChatTwo.* to HellionChat.*
All 6 inter-plugin communication channels are renamed for the v1.0.0
standalone cut. Prevents Dalamud IPC registration conflicts when a user
has both Hellion Chat and upstream Chat 2 installed.

- IpcManager: Register, Available, Unregister, Invoke
- TypingIpc:  GetChatInputState, ChatInputStateChanged

Breaking change for third-party plugins that bound to ChatTwo.* — none
known at the time of this commit.
2026-05-03 21:07:05 +02:00
JonKazama-Hellion 0df5819a88 merge: v0.6.1 Pop-Out Discoverability & /tell Auto-Pop-Out
- Visible pop-out icon button in chat header toolbar (right-aligned)
- One-time hint banner introduces toolbar + right-click and the v0.6.1 default flip
- Settings → Chat → Auto-Tell-Tabs → "Open new /tell tabs directly as pop-out"
- PopOutInputEnabled hard-flipped to true via v11 → v12 migration
- Bugfix: pop-out windows of LRU-dropped or logout-stripped temp tabs are now properly torn down (no more ghost windows)
- Bugfix: dead zone below chat input bar when v0.6.0 hint banner was visible (also fixes Jin's report on the v0.6.0 in-pop-out banner)
- CI: fix release.yml YAML parse failure (heredoc footer extracted to .github/release-footer.md), add workflow_dispatch recovery trigger
- README + SUPPORT.md + repo.json + yaml: Hellion Forge Discord link
2026-05-03 17:15:52 +02:00
JonKazama-Hellion 3fbbe8543f ci(release): fix YAML parse failure (heredoc footer broke block-scalar) and add manual recovery trigger 2026-05-03 17:14:05 +02:00
JonKazama-Hellion 03dfb8e3da fix: restore toolbar height subtraction (banner is auto-handled by cursor advance) 2026-05-03 17:02:10 +02:00
JonKazama-Hellion a987e97610 fix: re-add banner height subtraction (lives outside tab container scope) 2026-05-03 17:00:11 +02:00
JonKazama-Hellion ecd46ed630 release: bump version to 0.6.1, add changelog and Hellion Forge Discord link 2026-05-03 16:56:28 +02:00
JonKazama-Hellion f2f7599f81 fix: remove double height subtraction for header toolbar and hint banner 2026-05-03 16:49:24 +02:00
JonKazama-Hellion ac158907ea docs: clarify _v061HintBannerHeight reset semantics 2026-05-03 16:43:12 +02:00
JonKazama-Hellion 9506af49db feat: one-time hint banner introduces v0.6.1 pop-out toolbar and default flip 2026-05-03 16:38:31 +02:00
JonKazama-Hellion c882eac1ca feat: visible pop-out icon button in chat header toolbar 2026-05-03 16:27:28 +02:00
JonKazama-Hellion 7a6b44048a settings: add 'Open new /tell tabs as pop-out' checkbox 2026-05-03 16:17:24 +02:00
JonKazama-Hellion 0d39d59a04 feat: opt-in auto-pop-out for new /tell tabs 2026-05-03 16:13:38 +02:00
JonKazama-Hellion f0e0db55e3 fix: also clean up pop-outs of temp tabs on logout (symmetric to LRU drop) 2026-05-03 16:11:00 +02:00
JonKazama-Hellion f207239d56 fix: clean up pop-out window when auto-tell tab is LRU-dropped 2026-05-03 16:04:57 +02:00
JonKazama-Hellion ccf2ec9f12 i18n: tighten v0.6.1 hint body wording (DE/EN tone consistency) 2026-05-03 16:03:05 +02:00
JonKazama-Hellion aff7a5e7ce i18n: add v0.6.1 strings for hint banner and auto-pop-out toggle (DE/EN) 2026-05-03 15:57:10 +02:00
JonKazama-Hellion cd84ca2b3f migration: clarify v11->v12 log message and trim rotting comment 2026-05-03 15:55:15 +02:00
JonKazama-Hellion 7c645afa1d migration: add v11 -> v12 hard-flip of PopOutInputEnabled to true 2026-05-03 15:51:13 +02:00
JonKazama-Hellion 24c1e0e754 config: bump LatestVersion to 12, flip PopOutInputEnabled default, add v0.6.1 fields 2026-05-03 15:47:05 +02:00
JonKazama-Hellion 9f6a0807d1 docs: update README for v0.6.0 release (Pop-Out Input + Colour Presets) 2026-05-03 13:26:58 +02:00
JonKazama-Hellion 15f83c8b0e merge: v0.6.0 UX Polish — Pop-Out Input + Colour Presets
Two opt-in UX features. Existing users see no change unless they
enable the new toggles.

- Pop-out input: global master switch in Settings → Window → Frame.
  When enabled, every pop-out window grows a compact input bar
  (channel-coloured icon + text input). Independent text buffer and
  history cursor per pop-out; channel changes apply globally.
- Chat colour presets: seven built-ins above the per-channel colour
  list — ChatTwo Default, High-Contrast, Pastell, Dark-Mode-Tuned,
  Hellion (brand), Night Blue (bonus), Indigo Violet (bonus).

Configuration migrates from v10 to v11 with a diagnostic log.
2026-05-03 13:22:11 +02:00
JonKazama-Hellion c7253bdf02 presets: add Night Blue and Indigo Violet bonus presets from KAZAMA themes 2026-05-03 13:19:01 +02:00
JonKazama-Hellion cf10c566dd release: bump version to 0.6.0 with changelog entry 2026-05-03 13:09:11 +02:00
JonKazama-Hellion acfe838bc6 i18n: add v0.6.0 strings for presets, pop-out input and hint banner 2026-05-03 13:06:26 +02:00
JonKazama-Hellion 9e1f559644 config: pivot pop-out input from per-tab to global master switch 2026-05-03 13:01:07 +02:00
JonKazama-Hellion 2c79a67dae settings: add PopOutInputEnabled toggle below PopOut option 2026-05-03 12:51:59 +02:00
JonKazama-Hellion 1687271bfd popout: show one-time hint banner about pop-out input feature 2026-05-03 12:51:35 +02:00
JonKazama-Hellion cb5457ba2e popout: opt-in ChatInputBar with focus-aware keybind routing 2026-05-03 12:50:42 +02:00
JonKazama-Hellion a701f6c103 keybinds: extract DispatchTabDelta helper for upcoming focus-aware routing 2026-05-03 12:49:30 +02:00
JonKazama-Hellion 8cad8651d2 ui: drop auto-translate from compact bar in v0.6.0 (out of scope) 2026-05-03 12:48:46 +02:00
JonKazama-Hellion 61b547606c ui: ChatInputBar compact input with submit and history callback 2026-05-03 12:46:20 +02:00
JonKazama-Hellion 059cfa6e28 ui: ChatInputBar compact channel-selector with ChatColours background 2026-05-03 12:44:35 +02:00
JonKazama-Hellion 71d84e4486 ui: scaffold ChatInputBar component with InputState 2026-05-03 12:43:48 +02:00
JonKazama-Hellion 92301869ed refactor: migrate input history from ChatLogWindow.InputBacklog to InputHistoryService 2026-05-03 12:36:36 +02:00
JonKazama-Hellion c3d06a9c94 services: add InputHistoryService for shared input history 2026-05-03 12:35:14 +02:00
JonKazama-Hellion 911c870e24 presets: rework Hellion preset with Arctic Cyan + Ember Glow brand palette 2026-05-03 12:32:32 +02:00
JonKazama-Hellion 8cda19d993 settings: add chat colour preset buttons with apply logic 2026-05-03 12:26:25 +02:00
JonKazama-Hellion 62621ba855 presets: add five built-in chat colour presets 2026-05-03 12:25:22 +02:00
JonKazama-Hellion 497c259031 config: add v10 to v11 migration with diagnostic log 2026-05-03 12:10:11 +02:00
JonKazama-Hellion 9ad9d2acd2 config: add PopOutInputEnabled and SeenPopOutInputHint, bump LatestVersion to 11 2026-05-03 12:09:51 +02:00
JonKazama-Hellion 1b63765caa docs: community standards, privacy notice and release-body automation
Closes the remaining gaps in GitHub's community-standards check, adds
explicit privacy and dependency documentation matching the plugin's
"DSGVO-by-design" claim, and removes the stale upstream Crowdin
artefact so the repo no longer suggests it ships its own translation
pipeline.

New community-health files:

- CODE_OF_CONDUCT.md: project-specific, short and direct, single
  reporting path to kontakt@hellion-media.de
- CONTRIBUTING.md: scope, accepted vs declined contributions, build
  and test instructions, EUPL-1.2 contribution terms, translation
  policy split between Hellion-specific (here) and upstream strings
  (Chat 2 repo)
- SUPPORT.md: routing for bugs, security, privacy and casual feedback
- .github/PULL_REQUEST_TEMPLATE.md: summary, change-type checklist,
  testing notes, compatibility notes for migrations and manifest
  fields, contribution checklist
- .github/FUNDING.yml: comments-only file, no platforms enabled,
  points donors at the upstream Chat 2 maintainers' Ko-fi pages

New privacy and compliance documentation:

- PRIVACY.md: what the plugin stores locally (config, SQLite,
  EmoteCacheV1), retention defaults, the two outbound network calls
  (BetterTTV API+CDN with ShowEmotes opt-out, Square Enix Lodestone
  font once-off), explicit no-telemetry statement, GDPR
  Art. 15/17/18/20/21 rights mapped to plugin features, third-party
  privacy-policy links
- THIRD_PARTY_NOTICES.md: direct NuGet dependencies with versions
  pinned to v0.5.4 (MessagePack, Microsoft.Data.Sqlite, morelinq,
  Pidgin, SixLabors.ImageSharp under Six Labors Split License 1.0),
  Dalamud SDK and .NET tooling, bundled Exo 2 font (OFL-1.1) and
  plugin icon, network-touch status per component, re-audit commands

Crowdin cleanup:

- crowdin.yml deleted (was upstream Chat 2's project_id 663694,
  pointed at /ChatTwo/Resources/Language.resx, never wired to
  HellionChat strings)
- README, CONTRIBUTING and CODE_OF_CONDUCT no longer suggest
  HellionChat operates a Crowdin project; remaining mentions are
  explicitly framed as upstream Chat 2's workflow

Contact and version consistency:

- Maintainer email switched from maintainer@hellion-media.de to
  kontakt@hellion-media.de in SECURITY.md and NOTICE.md
- README version references updated to 0.5.4 (header, project status
  block) and the update-tag pattern generalised from v0.1.x to v0.X.Y
- bug_report.yml version placeholder bumped to 0.5.4
- Project-documents table added to README footer linking all health
  and reference files in one place

Release-body automation:

- .github/workflows/release.yml now extracts the matching version
  block from ChatTwo/HellionChat.yaml's changelog and combines it
  with a static install / docs footer (custom-repo URL, project
  document links, licence) before passing the result to
  softprops/action-gh-release@v3 via body_path
- Workflow fails fast if no changelog block exists for the tagged
  version, automating the existing "yaml + repo.json + release body
  kept in sync" rule
- Tag value passed via env: TAG_NAME with strict ^v\d+\.\d+\.\d+$
  validation before any string concatenation, so the tag input cannot
  break out into shell evaluation
2026-05-03 10:42:07 +02:00
JonKazama-Hellion 61764459ed merge: WrapText span refactor and 0.5.4 release 2026-05-02 23:57:31 +02:00
JonKazama-Hellion 1b7f2c40e6 fix(security): rebuild WrapText on span and int offsets
The pointer-arithmetic CodeQL alert kept re-firing on each shape of
the previous shallow fix because Encoding.GetBytes is virtual and
every length value derived from its return inherited the taint.
Refactor the routine to thread int offsets through index-based
control flow and only compute pointers inside two small helpers
(CalcWordWrap and DrawText) that take an already-pinned base pointer
plus offsets sourced from local logic, not from any virtual return.

Buffer is now allocated against Encoding.UTF8.GetMaxByteCount via
ArrayPool with a real 16 KiB upper bound, and the encoded length
returned by GetBytes is validated against that ceiling before
anything touches the pointer. Behaviour is byte-identical to v0.5.3,
verified locally with the same input shapes the previous code path
handled.

Slim changelog: trimmed the per-version blocks down to v0.5.1-v0.5.4
plus a link to GitHub releases for older history. The previous block
ran ~9000 characters and was dragging the manifest payload down for
no benefit; users see the latest release block first anyway.
2026-05-02 23:57:26 +02:00
JonKazama-Hellion 93d52ae819 chore(release): bump version to 0.5.3
Single-fix patch to close the CodeQL pointer-arithmetic alert that
v0.5.2 left open. v0.5.2 already shipped, so we tag forward instead
of moving the published tag.
2026-05-02 23:46:26 +02:00
JonKazama-Hellion 48b3d5c6b1 fix(security): validate UTF8 byte buffer length before pointer arithmetic
CodeQL re-opened the unvalidated-pointer-arithmetic alert at the new
textEnd line because Encoding.GetBytes is a virtual method on
Encoding and the returned array's Length is therefore tracked as
untrusted input for pointer arithmetic.

Compute the expected byte count from the same encoder via
GetByteCount and bail out if the actual buffer length does not match.
That is a real consistency check that would catch a maliciously
swapped Encoding.UTF8 instance, not a dead defensive guard. The
empty-split early-out from the previous fix is folded into the same
condition.
2026-05-02 23:42:59 +02:00
JonKazama-Hellion e9a9d8a01c merge: icon packaging fix 2026-05-02 23:33:22 +02:00
JonKazama-Hellion a155a57f33 fix(packaging): icon and image urls now reach the built manifest
Three packaging defects rolled into one fix:

- The custom DalamudPackager.targets override forced HandleImages and
  ImagesPath through the legacy code path. SDK 15 handles images by
  default and the override produced an output manifest with neither
  IconUrl nor ImageUrls populated. Removed.
- The csproj only included images/icon.png explicitly via
  <None Include>, so chatWindow.png and withSimpleTweaks.png never
  reached the build output and never made it into the release ZIP
  either. Switched to a glob include.
- HellionChat.yaml carried no icon_url / image_urls, so even after
  the SDK started writing the manifest correctly, both fields stayed
  unset. Added them pointing at the public raw.githubusercontent
  URLs that already work for the repo.json IconUrl.

Net effect on a fresh release: Dalamud picks up the icon next to the
DLL on dev installs, the plugin-installer card shows the proper
HellionChat logo for users coming through the custom repo, and the
two screenshot images are listed alongside the description so the
plugin installer carousel works the way other Dalamud plugins look.
2026-05-02 23:33:15 +02:00
JonKazama-Hellion 90b83a0690 chore(release): bump version to 0.5.2
Patch release. History-order fix for Auto-Tell-Tabs, three default-
config alignments and two CodeQL security findings closed.
2026-05-02 23:28:35 +02:00
JonKazama-Hellion f10301c3e4 merge: codeql findings #1 and #2 2026-05-02 23:27:12 +02:00
JonKazama-Hellion 8571a936a4 merge: align config defaults with maintainer's live config 2026-05-02 23:27:12 +02:00
JonKazama-Hellion 3f6144836c merge: auto-tell history-order fix 2026-05-02 23:27:12 +02:00
JonKazama-Hellion 53c432a635 fix(security): close codeql findings #1 and #2
Two CodeQL alerts opened against the codeql-manual-build workflow's
first scan. Both real, both small fixes.

#1 Medium / Workflow does not contain permissions
   build.yml runs read-only against the repo (no push, no release
   creation, no API mutations) but never declared a permissions
   block, so the default GITHUB_TOKEN scope applied. Pin to
   contents: read at workflow level. Release and CodeQL workflows
   already have their explicit minimal scopes.

#2 Critical / Unvalidated local pointer arithmetic
   ImGuiUtil.WrappedTextWithPos splits its input on newlines and
   passes each part through Encoding.UTF8.GetBytes inside a fixed
   block. Empty splits (consecutive newlines, blank lines) produced
   a zero-length byte array, fixed gave us a valid pointer, and
   textEnd = text + bytes.Length collapsed onto text. The downstream
   ImGuiNative.CalcWordWrapPositionA calls received identical start
   and end pointers, which is undefined behaviour at the native
   boundary even if it happens to no-op on the current ImGui build.
   Bail before entering the fixed block when bytes.Length == 0 and
   render an empty line for the gap, which is what the original
   text == null guard was trying to do but could never reach inside
   a fixed block over a non-null array.
2026-05-02 23:25:41 +02:00
JonKazama-Hellion 340cadf3b9 chore(config): align defaults with maintainer's live config
Three real-world adjustments to the default config that ships with a
fresh install:

- HellionThemeWindowOpacity 0.92 -> 0.5 so a fresh install lands at
  the more glass-like default the maintainer uses daily
- Use24HourClock false -> true to match a German / European locale.
  Works correctly thanks to the v0.5.1 strict-format fix that uses
  CultureInfo.InvariantCulture instead of the host culture
- HellionParty preset Channel: InputChannel.Party -> null. Auto-
  routing /party into a tab that also collects /alliance and /pvpteam
  surprises the user when they wanted to type into the other ones;
  the tab stays as a read surface

LoadPreviousSession and FilterIncludePreviousSessions stay false to
keep the privacy-strict 'every session starts fresh' line. The
maintainer's personal settings flip them on, but that's an
opt-in choice, not a default we should ship to every fresh install.
RetentionEnabled also stays false for the same opt-in reason.
2026-05-02 23:24:22 +02:00
JonKazama-Hellion 8d6868aef6 chore(config): align defaults with maintainer's live config
Four defaults now match what a daily-driver Hellion install ends up at
anyway, so a fresh install does not feel like the wrong product:

- HellionThemeWindowOpacity 0.92 -> 0.5 (more glass-like)
- LoadPreviousSession + FilterIncludePreviousSessions false -> true
  (tabs pick up where they left off after a crash or restart). The
  privacy filter still gates what goes into the store; loading what
  is already in there is not an additional privacy cost.
- Use24HourClock false -> true (matches a German / European locale,
  works with the strict CultureInfo.InvariantCulture format from the
  v0.5.1 fix).

RetentionEnabled stays at false because that one is a documented
opt-in privacy line, not a UX default. The persistent retention sweep
should require an explicit user gesture even though my own install
has it on.
2026-05-02 23:21:20 +02:00
JonKazama-Hellion 6e8fcc8cc3 merge: codeql manual-build workflow 2026-05-02 23:17:39 +02:00
JonKazama-Hellion 57670ffc76 ci(codeql): replace default setup with manual-build workflow
The default GitHub-managed CodeQL setup builds C# without the Dalamud
assemblies (they live in user AppData, not in the repo or in NuGet),
so call-target resolution sits at 64% and the analysis tile reports
'Low C# analysis quality'. This workflow runs the same Dalamud staging
download we use for the regular build before the CodeQL build step,
which gives the analyser a fully-resolved compilation and pushes both
quality metrics above the 85% thresholds.

Two jobs:

- analyze-csharp on windows-latest with build-mode: manual and the
  security-extended query suite, so we get the full SQL-injection,
  path-traversal and crypto-misuse rule set on a clean compilation
- analyze-actions on ubuntu-latest with build-mode: none, scans the
  workflow files in .github for action-injection patterns

Schedule runs Mondays at 06:17 UTC (low-traffic window).

The repo's CodeQL default setup needs to be switched to advanced in
Settings -> Code security before this workflow takes over, otherwise
both run in parallel and we waste runner minutes.
2026-05-02 23:15:20 +02:00
JonKazama-Hellion 2144eedd76 fix(autotell): exclude live tell from history preload
The live tell that triggers an Auto-Tell-Tab spawn is already in the
message store by the time MessageProcessed fires, because
MessageManager calls Store.UpsertMessage on line 266 before invoking
the event on line 277. PreloadHistory therefore picked up the live
tell as the youngest historic message and the separator landed below
it instead of above.

Pass the live message id through SpawnTempTab into PreloadHistory and
filter it out of the result. Pull one extra row so a successful
exclude does not cost the user a preload-budget slot.
2026-05-02 23:11:20 +02:00
JonKazama-Hellion 43daef83de merge: readme status badges 2026-05-02 23:05:24 +02:00
JonKazama-Hellion 01b1a14511 docs(readme): add status badges above the title
Seven badges covering build status, CodeQL scanning, license, latest
release, Dalamud API level, .NET version and FFXIV expansion. Quick
visual indicator that the plugin is healthy and which tooling
generation it targets, plus shortcut links to the workflow runs and
security findings.
2026-05-02 23:00:13 +02:00
JonKazama-Hellion b6af8d559c merge: license detection fix and github workflows 2026-05-02 22:53:11 +02:00
JonKazama-Hellion 22dbfc2e24 chore(repo): fix license detection and add github workflows
LICENSE now starts with the EUPL-1.2 standard header so github-linguist
detects the licence correctly in the repo header. The dual-copyright
block (upstream ChatTwo authors plus Hellion Online Media) moves into a
new COPYRIGHT file referenced from the README. NOTICE.md and
UPSTREAM_SYNC.md stay as-is.

New files under .github:

- workflows/build.yml: validates every push to main and every PR
  against the current Dalamud staging branch on a Windows runner
- workflows/release.yml: builds Release on every v* tag, locates the
  DalamudPackager latest.zip and attaches it to the matching GitHub
  Release via softprops/action-gh-release
- dependabot.yml: weekly NuGet sweeps and monthly GitHub Actions
  sweeps with conventional-commit prefixes, grouped patch and minor
  PRs to cut review noise
- ISSUE_TEMPLATE/bug_report.yml + feature_request.yml + config.yml:
  structured intake that pushes security reports through the private
  advisory flow and routes upstream-only issues to ChatTwo
- SECURITY.md: documents the vulnerability reporting channels, scope,
  and target disclosure window

The release workflow replaces the previous manual upload step. Tag a
release and the ZIP shows up on the release page automatically.
2026-05-02 22:50:06 +02:00
JonKazama-Hellion 2f3b01732c merge: untrack test project from public repo 2026-05-02 22:09:34 +02:00
JonKazama-Hellion 88803382dd chore(repo): untrack ChatTwo.Tests, matches upstream layout
Drop the test project from version control. Upstream Chat 2 also
keeps ChatTwo.Tests outside the public repo, and the test sources
need a Dalamud assembly bundle that only resolves on a configured
Windows dev box anyway. The files stay on disk for local runs but
no longer ship with the source.
2026-05-02 22:08:47 +02:00
JonKazama-Hellion 74c51163c7 merge: license, notice and upstream sync docs 2026-05-02 22:06:53 +02:00
JonKazama-Hellion 877ff4ba18 chore(license): remove duplicate upstream LICENCE file
The LICENSE file added in ad2feb5 carries the dual-copyright block
(upstream ChatTwo authors plus Hellion Online Media) and is the one
the README now points at. The original Upstream-only LICENCE was a
verbatim copy of the EUPL text without our Hellion attribution and
became redundant the moment LICENSE landed. GitHub also prefers the
LICENSE filename for its license-detection in the repo header.
2026-05-02 21:53:06 +02:00
JonKazama-Hellion ad2feb5a27 chore(license): add LICENSE, NOTICE and upstream sync docs
Three new top-level files plus README update in preparation for
leaving the GitHub fork network:

- LICENSE: full EUPL-1.2 text plus dual copyright notice (upstream
  ChatTwo authors and Hellion Online Media). README previously
  pointed at a non-existent LICENCE file, fixing that compliance
  gap was overdue regardless of the fork-network decision.
- NOTICE.md: acknowledgements addressed directly to Infi and Anna,
  honest framing of why the fork exists alongside upstream rather
  than trying to displace it, plus maintainer contact channels for
  attribution or takedown questions.
- UPSTREAM_SYNC.md: documents the manual cherry-pick workflow with
  -x authorship preservation, the conflict-handling policy, and
  what we will and will not pull from upstream. Replaces the
  GitHub-Fork sync UI we will lose after detaching.
- README.md: version bump to 0.5.1, fork-network detach note, link
  to NOTICE.md and LICENSE, fixed the LICENCE / LICENSE typo.
2026-05-02 21:51:33 +02:00
JonKazama-Hellion 46b63ffdd1 merge: Hellion Chat 0.5.1 — Backlog Sweep 2026-05-02 21:34:50 +02:00
JonKazama-Hellion 4ba5004322 chore(release): bump version to 0.5.1
Hardening and polish patch. Eight backlog items from the v0.5.0
codebase review. No new features, no migration.
2026-05-02 21:27:10 +02:00
JonKazama-Hellion 3584c94523 docs(db): explain why pragma statements stay interpolated
Both PRAGMA call sites take values that SQLite does not accept as
bound parameters. ColumnExists takes a hardcoded table name, the
migration call takes a compile-time int from the version sequence.
Comments now state both facts so future readers don't try to wedge a
defensive whitelist into a path that cannot be reached from anywhere
user-controlled.
2026-05-02 21:25:40 +02:00
JonKazama-Hellion 303729f3d3 refactor(db): parameterise DeleteByRetentionPolicy SQL clauses
Per-channel WHERE tuples and the catch-all default-clause now bind
ChatType and cutoff via named parameters instead of being inlined as
literals. Combines BindIntList for the explicit-types exclusion with
explicit AddWithValue for each (type, cutoff) tuple. Behavioural diff
against v0.5.0: none — same retention windows, same cutoff math, just
parameterised.
2026-05-02 21:25:05 +02:00
JonKazama-Hellion 12085ff1e2 refactor(db): parameterise IN-clause SQL via BindIntList
Migrate CleanupRetainOnly, StreamForExport, CountDateRange, GetDateRange
and GetPagedDateRange from interpolated IN lists onto BindIntList.
Eliminates the string-interpolation pattern for SQL value lists in the
IN-clause sites. Behavioural diff against v0.5.0: none — same enum/byte
values, just bound under named parameters instead of inlined.
2026-05-02 21:24:36 +02:00
JonKazama-Hellion e4593a0fda refactor(db): add BindIntList helper for parameterised IN-clauses
Centralised builder for dynamic IN-clauses that binds each value as a
named parameter and returns the comma-joined placeholder string. Used
by the upcoming MessageStore migrations away from string-interpolated
SQL.
2026-05-02 21:23:17 +02:00
JonKazama-Hellion 3fc42963ae feat(autotell): dim selection background of greeted tabs
The text-disabled colour alone made greeted tabs visually weak in the
sidebar. Push dimmed Header and HeaderHovered values alongside the
existing Text push so the selected and hovered states match the
greeted state too. Idle state stays untouched because ImGui Selectable
has no idle background slot.
2026-05-02 21:22:36 +02:00
JonKazama-Hellion 7c52e890e6 feat(privacy): mark cleanup preview as stale when whitelist changes
The preview block caches the deletion estimate from the last refresh.
When the user toggles whitelist channels afterwards the cached number
no longer reflects the current selection. Snapshot the whitelist on
refresh and detect drift on every frame; on drift, grey out the counts
and surface a stale hint plus an emphasised refresh button. Sits
alongside the existing Cleanup_Help_SavedNote, which warns about a
different mismatch (mutable vs saved) and stays as-is.
2026-05-02 21:22:12 +02:00
JonKazama-Hellion 4d977d5118 fix(fonts): marshal font chooser results onto the framework thread
Three FontChooser ContinueWith handlers wrote Mutable.* directly from
the threadpool. Wrap the result-write in Plugin.Framework.Run so the
mutation lands on the same thread that owns the rest of the UI state.
Matches the marshalling pattern already used by Database.cs and
Privacy.cs background work.
2026-05-02 21:20:49 +02:00
JonKazama-Hellion ddd72a878e refactor(emotes): drop async void on LoadData
async void Task.Run() is a no-op for awaiting purposes since the void
returns immediately. Switch LoadData to async Task and have the two
callers fire-and-forget the task directly. Exceptions still go through
the existing try/catch inside LoadData.
2026-05-02 21:20:16 +02:00
JonKazama-Hellion 66450dd518 refactor(i18n): pull tabs and database tab names into hellionstrings
Both tab classes were the last two settings tabs still pulling their
display name from the upstream Language resource bundle. Move them
into HellionStrings so all eight settings tabs share one i18n source.
The unused Language.Options_*_Tab keys stay around for backwards
compat with cherry-picked upstream tabs.
2026-05-02 21:19:40 +02:00
JonKazama-Hellion 7de28ef9b2 refactor(settings): align performance section with helpmarker pattern
Drop the inline wall-of-text description in favour of the standard
HelpMarker tooltip used across the rest of the v0.5.0 settings UX.
Visual consistency for the General tab.
2026-05-02 21:18:30 +02:00
JonKazama-Hellion da3c1f6832 fix(emotes): mark required properties to silence CS8618
Mark Emote.Id, Top100.Id, Top100.Code and Top100.ImageType as required
so the JSON deserializer enforces the contract instead of relying on
default-null semantics. Removes the four CS8618 warnings the build has
been carrying since v0.4.0.
2026-05-02 21:17:57 +02:00
JonKazama-Hellion e66ae1f5b4 merge: Hellion Chat 0.5.0 — Settings UX Polish
Twelve organic settings tabs collapsed into eight themed ones (General,
Appearance, Window, Chat, Tabs, Privacy, Database, Information). Wipe
migration v9→v10 with HellionChat.json.pre-v10-backup safety net.
Default tab layout now spawns six themed tabs out of the box (General,
System, Free Company, Party, Beginner when Novice Network is on,
Linkshell, Tell Exclusive). HelpMarker pattern across every section,
disabled tooltips remain visible. Pre-release polish from full
codebase review covered race-conditions, EmoteCache retry, Allman
bracing, and dead i18n keys.
2026-05-02 18:42:50 +02:00
JonKazama-Hellion 281a1e172f feat(tabs): add dedicated System tab to default layout
Split the technical/notification streams (System, Error, Echo, Debug,
NPC announcements, login/logout, retainer sales, gathering system,
glamour notifications, sign messages, alarms, orchestrion, message
book, random number, progress) out of the General tab into their own
System tab. General now shows player conversation plus the active
gameplay events (loot rolls, crafting, gathering, NPC dialogue, party
finder pings) without burying chat under technical chatter.
2026-05-02 18:28:29 +02:00
JonKazama-Hellion 45a5035426 refactor(tabs): align General preset with maintainer's live config
Drop the channels that already live in dedicated themed tabs (Tells,
emotes, Novice Network, FC and PvP announcements, Sign and Glamour
notifications) so the General tab is the public-chat catch-all instead
of a duplicate of every themed tab. NpcDialogue moves in because the
maintainer reads it alongside system messages.
2026-05-02 18:25:59 +02:00
JonKazama-Hellion e1931fc7d2 feat(tabs): seed default tab layout on first run and v10 wipe
Spawn six themed tabs out of the box instead of one General catch-all:
General (everything), Free Company (FC chat plus FC announcements and
login/logout), Party (Party, CrossParty, Alliance, PvP team plus loot
rolls), Beginner (Novice Network only when ShowNoviceNetwork is on),
Linkshell (all eight regular and cross-world linkshells together) and
Tell Exclusive (TellIncoming/TellOutgoing as a safety-net catch-all in
case Auto-Tell-Tabs misses one).

Tab names live in HellionStrings (EN/DE). The Tabs settings tab gains a
help-text hint above the list recommending one tab per linkshell when
the user is in multiple, since a single combined Linkshell tab gets
noisy fast for active users.
2026-05-02 18:13:15 +02:00
JonKazama-Hellion 2201478a54 fix(v0.5.0): defaults and coupling issues from first walkthrough
- Configuration.cs: ShowTitleBar defaults to true so a fresh install
  shows the window header instead of leaving the user without a drag
  handle and hide button
- Configuration.cs: MaxLinesToRender default drops from 10000 to 5000
  to match the slider's intended ceiling and the previous user-tuned
  baseline
- ChatLogWindow.cs: 24h-clock checkbox now actually flips the format.
  The Bestand path passed null culture which on a German system
  locale always rendered 24h regardless of the toggle
- Appearance.cs + ChatLogWindow.cs + Popout.cs: when Hellion theme is
  enabled the global theme opacity drives the chat-window BgAlpha and
  the legacy WindowAlpha slider is disabled, so the two opacity
  controls no longer fight each other
- Appearance.cs: ticking UseHellionFont now flips FontsEnabled off so
  the two mutually-exclusive font stacks no longer appear active at
  the same time
2026-05-02 18:00:04 +02:00
JonKazama-Hellion 50963ccf1b fix(v0.5.0): pre-release polish from full-codebase review
- Plugin.cs: mark RetentionSweepRunning volatile so the ImGui thread
  reads the latest value without a stale register-cached copy
- EmoteCache.cs: reset State to Unloaded on exception so a later
  trigger can retry instead of being blocked by the early-out
- Settings.cs: switch the SaveAndClose / Discard buttons to Allman
  bracing for consistency with the rest of the file, and include the
  ItemSpacing in the Ko-fi-button right-edge calculation
- Privacy.cs: add a saved-policy hint above the manual retention
  Ctrl+Shift button so the existing Cleanup wording pattern is
  matched here too
- HellionStrings: drop seven unreferenced keys (Theme_Heading,
  Migration_Notification_*, Migration_Webinterface_Removed_*,
  AutoTellTabs_Migration_*) and their EN/DE values, add the new
  Retention_Help_SavedNote string
2026-05-02 17:50:32 +02:00