Icod.Terminal 1.9.0
Icod.Terminal 1.9.0
Icod.Terminal 1.9.0 extends the stable 1.x event architecture with unsolicited semantic terminal events and completes the interactive Kitty OSC 99 notification work deliberately deferred from 1.4.
The release keeps one authoritative terminal input conversation. Active query responses retain first ownership of matching traffic; recognized unsolicited semantic reports are routed next; ordinary application input remains the final path. No second raw reader, notification listener, callback channel, or vendor-event dispatcher is introduced.
What changed
Protocol-neutral semantic events
TerminalEventKind gains one additive value:
Semantic = 4
The existing numeric values remain unchanged:
Input = 0
Lifecycle = 1
Timeout = 2
Cancelled = 3
TerminalEvent.Semantic carries a TerminalSemanticEvent. The first reviewed semantic family is notifications, represented by TerminalNotificationEvent with these event kinds:
Activated
ButtonActivated
Closed
CloseTrackingUnavailable
ButtonActivated carries a one-based button number. CloseTrackingUnavailable is deliberately distinct from Closed: it reports that the terminal/host cannot reliably track a future close rather than fabricating a close observation.
Semantic events are delivered only through the existing TerminalSession.ReadEventAsync(...) stream. There is no ReadSemanticEventAsync(...) API.
Interactive Kitty OSC 99 notifications
KittyNotificationOptions gains three opt-in properties:
public bool ReportActivation { get; init; }
public bool ReportClose { get; init; }
public IReadOnlyList<string> Buttons { get; init; }When these options are unused, existing Kitty notification behavior and bytes remain unchanged.
Interactive reporting requires an explicit caller-supplied notification identifier. Button labels are encoded as strict UTF-8 using Kitty's U+2028 separator and are bounded to 16 buttons, 512 UTF-8 bytes per label, and 2,048 UTF-8 bytes for the combined button payload including separators.
FocusOnActivation remains independent from report generation.
Authoritative routing and recovery
Incoming terminal traffic is assigned in this order:
1. active query/response ownership
2. recognized unsolicited semantic-report ownership
3. ordinary application-input decoding
A query response is never double-delivered as a semantic event. Unrelated notification events do not satisfy an active query merely because both use OSC 99.
Malformed and oversized OSC 99 candidates that have entered semantic ownership are consumed/recovered boundedly rather than leaking hostile bytes into ordinary text. After semantic recovery, routing restarts at active-query precedence so a following correlated response cannot be skipped.
Ordering, cancellation, lifecycle, and backpressure
Ordinary input and semantic events share the existing bounded application-event coordinator and preserve same-byte-stream order. No unbounded semantic side queue is added.
Caller cancellation or timeout of one ReadEventAsync(...) wait does not discard an already-started fragmented report or an already-decoded queued event. Session disposal retains its existing authority to stop the session-owned input machinery.
Notifications are observations/output, not reversible terminal state. They are not replayed on resume and are not automatically closed on session disposal. Already-decoded semantic observations survive lifecycle transitions according to the existing event contract.
Applications should choose one lifecycle-consumption pattern: ReadEventAsync(...) and ReadLifecycleEventAsync(...) consume the same lifecycle queue and are not independent duplicated event streams.
Security and trust boundary
Unsolicited notification reports are validated but unauthenticated terminal-controlled input. A terminal, multiplexer, remote endpoint, or hostile transport can fabricate notification identifiers, activation reports, button numbers, close reports, and untracked results.
An identifier is correlation data, not authentication. Applications must not use a TerminalNotificationEvent as an authorization boundary or proof that the operating system displayed a notification or that a trusted desktop user performed the reported action.
Malformed/oversized owned reports remain bounded. The public semantic model does not expose raw OSC payloads, selector dictionaries, arbitrary vendor metadata, or protocol backend identifiers.
Public API and compatibility
The final 1.9 public API fingerprint is:
e652e6fd65cd43422ca84b7c4c2a1815ee7ead9b2a64285e0e17cf39614b0315
The authoritative files are:
docs/Public-API-Baseline-1.9.md
docs/Public-API-Baseline-1.9.sha256
Version 1.9 is an additive minor release. Stable 1.0.0 remains the compatibility floor, existing public members remain present, existing enum numeric values are unchanged, and historical API baselines remain preserved.
Consumers with exhaustive switches over TerminalEventKind should handle the new Semantic value when moving to 1.9.
See Compatibility-and-Versioning.md for the permanent compatibility authority.
Platforms and dependencies
The package continues to target:
net8.0
net9.0
net10.0
The dependency floor remains:
Icod.TermInfo 1.10.0
Icod.Timing 1.0.0
No package dependency is added for semantic-event or OSC 99 interaction support.
Samples and package acceptance
Icod.Terminal.Notification.Sample includes --kitty-interactive, demonstrating an explicit notification identifier, activation/button and close reporting, two bounded sample buttons, and typed event consumption through ReadEventAsync(...).
Fresh NuGet-only package validation compiles and runs the 1.9 semantic-event and interactive-notification surface independently on net8.0, net9.0, and net10.0. Existing package shards and Icod.DCurses compatibility/soak witnesses remain part of release qualification.
Deliberate exclusions
Version 1.9 does not add:
- a raw OSC event stream;
- a generic vendor-event dispatcher;
- a second semantic reader or callback delivery path;
- host-native desktop notifications;
- terminal-brand-driven activation;
- a persistent notification database;
- authentication of notification reports;
- notification replay or automatic close-on-dispose;
- unrelated future OSC 99 report forms;
- persistent raster image/placement ownership;
- image codecs;
- PTY/ConPTY hosting;
- DCurses window/widget/layout policy.
Development evidence
The 1.9 program is organized as E190–E199. E198's final adversarial/package checkpoint is 0f9eaa169922fa8679df682239c5d7e2fb6afa8f, workflow #1444 / 34526210297, which passed Windows, Linux, macOS, the package/API candidate, all four package shards, and the validated artifact with 1,788 tests passing on every supported TFM on Linux and Windows.
E199 performs the final package/documentation/version closure and exact-head Staging qualification before the PR is handed back for maintainer merge. Merge, Release validation on the resulting main commit, tagging, and publication remain separate maintainer actions.