From edfa239c3e0aa006ae9f3891c9d04f18aeb400df Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Tue, 17 Feb 2026 20:38:55 +0000 Subject: [PATCH] Filter unsupported DEC private mode 7727 from terminal output Shells (e.g. via Tera Term conventions) emit CSI ?7727h/l to toggle Application Escape Key mode, which ghostty-web does not implement. This produces noisy console warnings in the browser. Strip these sequences server-side in the output pipeline (both TerminalSession and DockerExecSession) before they reach the client, using the same pattern as the existing DA response filter. --- webterm/docker_exec_session.go | 1 + webterm/normalize.go | 14 ++++++++++++-- webterm/terminal_session.go | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/webterm/docker_exec_session.go b/webterm/docker_exec_session.go index 6d346c9..045dc80 100644 --- a/webterm/docker_exec_session.go +++ b/webterm/docker_exec_session.go @@ -147,6 +147,7 @@ func (s *DockerExecSession) handleOutput(data []byte) { tracker := s.tracker connector := s.connector s.mu.Unlock() + filtered = FilterUnsupportedModes(filtered) dispatchSessionOutput(filtered, tracker, s.replay, connector) } diff --git a/webterm/normalize.go b/webterm/normalize.go index 277c7e3..9804cc1 100644 --- a/webterm/normalize.go +++ b/webterm/normalize.go @@ -6,8 +6,9 @@ import ( ) var ( - daResponsePattern = regexp.MustCompile(`\x1b\[[?>=][\d;]*c`) - daPartialPattern = regexp.MustCompile(`\x1b(?:\[(?:[?>=][\d;]*)?)?$`) + daResponsePattern = regexp.MustCompile(`\x1b\[[?>=][\d;]*c`) + daPartialPattern = regexp.MustCompile(`\x1b(?:\[(?:[?>=][\d;]*)?)?$`) + unsupportedModePattern = regexp.MustCompile(`\x1b\[\?7727[hl]`) ) func FilterDASequences(data []byte, escapeBuffer []byte) ([]byte, []byte) { @@ -28,3 +29,12 @@ func FilterDASequences(data []byte, escapeBuffer []byte) ([]byte, []byte) { } return filtered, nil } + +// FilterUnsupportedModes strips DEC private mode sequences that ghostty-web +// does not implement, preventing noisy console warnings in the browser. +func FilterUnsupportedModes(data []byte) []byte { + if !bytes.Contains(data, []byte("\x1b[?7727")) { + return data + } + return unsupportedModePattern.ReplaceAll(data, nil) +} diff --git a/webterm/terminal_session.go b/webterm/terminal_session.go index 20e8c8d..54210c3 100644 --- a/webterm/terminal_session.go +++ b/webterm/terminal_session.go @@ -136,6 +136,7 @@ func (s *TerminalSession) handleOutput(data []byte) { tracker := s.tracker connector := s.connector s.mu.Unlock() + filtered = FilterUnsupportedModes(filtered) dispatchSessionOutput(filtered, tracker, s.replay, connector) }