Commit Graph

352 Commits

Author SHA1 Message Date
GitHub Copilot 674e62d983 refactor: upgrade go-te to v0.1.0, remove C1 normalization
go-te v0.1.0 fixes the ByteStream C1 bug (Latin-1 fallback for
invalid UTF-8 bytes), so NormalizeC1Controls is no longer needed.

Removed:
- NormalizeC1Controls function and its tests/fuzz target
- utf8Buffer field from TerminalSession and DockerExecSession
- C1BUG.md (fix shipped upstream)

The handleOutput pipeline now does: FilterDA → replay → tracker → connector
(was: FilterDA → NormalizeC1 → replay → tracker → connector)

All tests pass with -race. 13 fuzz targets remain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-14 16:40:28 +00:00
GitHub Copilot 307a8cc312 docs: add go-te C1 ByteStream bug report (C1BUG.md)
ByteStream.Feed() in UTF-8 mode permanently stalls on raw C1
control bytes (0x80-0x9F). DecodeRune returns RuneError, the loop
breaks, and the bad byte stays in the buffer forever — blocking
all subsequent input and leaking memory.

Stream.handleGround() has correct C1 handlers but they are
unreachable through ByteStream. Includes reproduction case and
suggested fix (Latin-1 fallback for invalid UTF-8 bytes).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-14 16:32:50 +00:00
GitHub Copilot 52a96915f0 test: add 14 fuzz tests across Go packages
Fuzz targets covering all input-processing functions:
- terminalstate: FuzzTrackerFeed, FuzzTrackerFeedIncremental
- normalize: FuzzNormalizeC1Controls, FuzzFilterDASequences
- slugify: FuzzSlugify (with unit tests)
- identity: FuzzGenerateID (with unit tests)
- replay: FuzzReplayBuffer, FuzzReplayBufferRapid
- svg_exporter: FuzzColorToHex, FuzzIsHex, FuzzRenderTerminalSVG
- shellsplit: FuzzShlexSplit (with unit test)
- twoway: FuzzTwoWayMap (with unit test)
- config: FuzzExtractLabel

All 14 targets validated with -fuzztime=3s, no panics found.
All unit tests pass with -race.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-14 16:25:55 +00:00
GitHub Copilot fd6c1c4e0d feat: complete Go port with go-te terminal emulator
Full Go implementation under go/ replacing Python pyte with go-te:
- HTTP server with WebSocket protocol, SSE, screenshot SVG rendering
- PTY terminal sessions and Docker exec sessions
- Docker watcher (label-based container discovery + event stream)
- CPU stats collection with sparkline SVG rendering
- Session manager with TwoWayMap routing and replay buffers
- C1 normalization, DA filtering, identity generation, theme palettes

Audit fixes for 9 concurrency/correctness issues:
- HTTP transport leak: shared client pool for Docker socket calls
- WebSocket concurrent writes: all writes routed through send channel
- Closed channel panic: atomic.Bool guard on enqueueWSData
- GetFirstRunningSession: use UnsafeForward under SessionManager lock
- NewSession TOCTOU: re-check routeKey after re-acquiring lock
- waitErr data race: protect with mutex in both session types
- Replay buffer fragmentation: copy to new slice on eviction
- go-te dirty tracking: check screen.Dirty before incrementing counter
- Identity modulo bias: rejection sampling for uniform distribution

All Go tests pass (including -race). Python baseline unchanged (397 tests).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-14 16:18:23 +00:00
GitHub Copilot 7cb3799c3b Bump version to 1.2.18 2026-02-11 09:21:48 +00:00
GitHub Copilot 57a93a7cc6 Fix stdin stalls and test warnings 2026-02-11 09:21:29 +00:00
GitHub Copilot 3eeba0c1ec typo 2026-02-09 16:36:26 +00:00
GitHub Copilot b412d96653 Bump version to 1.2.17 2026-02-06 21:26:48 +00:00
GitHub Copilot 10ffb9d8cc docs: consolidate pyte patches documentation
Rename ink-clear-fix.md → pyte-patches.md and rewrite as a
comprehensive reference for all pyte monkeypatches:
- Patch 1: CSI S/T (SU/SD scroll) — primary ghost content fix
- Patch 2: Alternate screen buffer (DECSET 1049)
- Patch 3: Ink partial clear expansion (secondary defense)

Update README.md Known Issues to reflect the actual fix approach.
Update ARCHITECTURE.md to document alt_screen.py and pyte patching.
2026-02-06 21:24:52 +00:00
GitHub Copilot d538cae2fa Bump version to 1.2.16 2026-02-06 21:22:00 +00:00
GitHub Copilot 207eddc922 fix: implement CSI S/T (scroll up/down) to fix ghost content in screenshots
pyte 0.8.2 does not handle CSI S (SU — Scroll Up) or CSI T (SD —
Scroll Down). When TERM=xterm-256color, tmux sends CSI n S for bulk
scrolling instead of DECSTBM+index. pyte silently ignored these
sequences, leaving old content in the screen buffer — visible as
ghost content in SVG screenshots.

Fix: monkeypatch pyte's CSI dispatch tables to map S→scroll_up and
T→scroll_down, and implement both methods on AltScreen with proper
scroll-region (DECSTBM) support.

Adds 6 tests for SU/SD functionality.
2026-02-06 21:21:57 +00:00
GitHub Copilot c98cee4cd6 Bump version to 1.2.15 2026-02-06 20:01:52 +00:00
GitHub Copilot d74c2726bf docs: add Ink partial clear fix to README known issues and notes 2026-02-06 20:01:09 +00:00
GitHub Copilot 3ba8c7f352 fix: expand Ink partial clears to prevent ghost content in screenshots
Ink (React CLI framework) clears its output using repeated EL2+CUU1
sequences, one per previously-drawn line. When /clear resets Ink's
internal line counter, the next frame only erases a few lines instead
of the full previous output. In a real terminal the old content is in
scrollback and invisible, but pyte's fixed-size screen retains it,
producing ghost content (e.g. duplicated prompts) in SVG screenshots.

Added AltScreen.expand_clear_sequences() which detects runs of 3+
EL2+CUU1 pairs that don't reach row 0 and extends them to erase all
lines up to the top of the screen. Both DockerExecSession and
TerminalSession call this before feeding data to pyte.

Also made on_session_end() idempotent (contextlib.suppress KeyError)
to prevent a race when close_session() and natural session exit both
call it.

Added docs/ink-clear-fix.md with root cause analysis, byte-level
explanation, and reproduction script.
2026-02-06 20:00:09 +00:00
GitHub Copilot b87a698438 fix: properly clean up sessions when Docker containers are destroyed
- close_session() now calls on_session_end() to remove the session from
  sessions dict and routes, preventing zombie entries that persist after
  the container is gone
- _remove_container() now closes the active session before removing the
  app from apps_by_slug/apps, so session cleanup can still reference the
  app during teardown
- Updated and added tests to verify session tracking cleanup
2026-02-06 17:27:49 +00:00
GitHub Copilot 8513283eae Known issues 2026-02-04 21:49:09 +00:00
GitHub Copilot 70c0870bcc Bump version to 1.2.14 2026-02-04 07:14:20 +00:00
GitHub Copilot f5c2a80644 Fix tmux alt-screen handling
- handle DECSET ?47 as an alternate screen mode so tmux clear redraws don't overlay stale content in screenshots

- keep AltScreen mode checks aligned with 47/1047/1048/1049 variants used by full-screen TUIs

- document the screenshot debugging workflow in .github/skills/screenshot-debugging/SKILL.md for repeatable escape-sequence analysis
2026-02-04 07:13:26 +00:00
GitHub Copilot 4a4ab40917 Bump version to 1.2.13 2026-02-03 20:30:11 +00:00
GitHub Copilot 786cc4c80e Rebuild assets for mobile keybar updates 2026-02-03 20:21:00 +00:00
GitHub Copilot fa2255a06e Bump version to 1.2.12 2026-02-03 19:40:53 +00:00
GitHub Copilot 027c8931ed Add Alt/Fn modifiers to mobile keybar 2026-02-03 19:37:29 +00:00
GitHub Copilot 51984fd5d1 Bump version to 1.2.11 2026-02-01 09:46:47 +00:00
GitHub Copilot d644c3160e note 2026-02-01 09:46:44 +00:00
GitHub Copilot 381d844068 Make C1 handling UTF-8 safe 2026-02-01 09:45:23 +00:00
GitHub Copilot fadde71aa5 Teach helper Shift/Ctrl punctuation 2026-02-01 09:15:03 +00:00
GitHub Copilot 6e856f22b4 Let helper Ctrl guide physical letters 2026-02-01 09:10:31 +00:00
GitHub Copilot 5b52820b2c Bump version to 1.2.10 2026-02-01 08:58:37 +00:00
GitHub Copilot b71822b2be Prioritize Ctrl+Shift arrow sequences 2026-02-01 08:57:51 +00:00
GitHub Copilot 4c53c1509c Bump version to 1.2.9 2026-02-01 01:37:29 +00:00
GitHub Copilot 7849e53edd Fix iPad modifier handling for mobile keybar 2026-02-01 01:36:35 +00:00
GitHub Copilot e99ac51495 Bump version to 1.2.8 2026-01-31 19:24:05 +00:00
GitHub Copilot 704527c16c Invert selection colors for readability 2026-01-31 19:23:56 +00:00
GitHub Copilot dc60f78e59 Bump version to 1.2.7 2026-01-31 18:51:30 +00:00
GitHub Copilot 56574698ad Listen to the abyss: tame C1 control phantoms for clear screens 2026-01-31 18:50:58 +00:00
GitHub Copilot 64ee95b0f9 Bump version to 1.2.6 2026-01-31 16:50:02 +00:00
GitHub Copilot f12c9901d7 Handle alternate screen modes 2026-01-31 16:49:54 +00:00
GitHub Copilot 6d613f008d Rebuild terminal bundle 2026-01-31 16:28:33 +00:00
GitHub Copilot a530afce92 Improve selection contrast 2026-01-31 16:27:39 +00:00
GitHub Copilot 8408e7b679 Bump version to 1.2.5 2026-01-31 11:42:30 +00:00
GitHub Copilot 575eb236b2 Centralize env handling for screenshots 2026-01-31 11:42:12 +00:00
GitHub Copilot 38e7c0e489 Add alt screen buffer support 2026-01-31 11:37:34 +00:00
GitHub Copilot aba3460c40 Bump version to 1.2.4 2026-01-31 10:15:42 +00:00
GitHub Copilot 26e77a010b Document {container} placeholder in README 2026-01-31 10:15:05 +00:00
GitHub Copilot 9c5e3781c7 Support {container} placeholder in WEBTERM_DOCKER_AUTO_COMMAND
Allows per-container customization of the auto command. For example:
  WEBTERM_DOCKER_AUTO_COMMAND='tmux new-session -ADs {container}'

This creates a tmux session named after the container instead of using
a fixed session name for all containers.
2026-01-31 10:14:39 +00:00
GitHub Copilot 7556539b6f Bump version to 1.2.3 2026-01-31 08:41:06 +00:00
GitHub Copilot 84b4cee353 Fix TypeError when Docker returns null labels in container inspect
When a container has no labels, Docker returns {"Labels": null} in the
inspect response. The code was using .get("Labels", {}) which only
returns the default when the key is missing, not when it's null.

This caused _has_webterm_label() to raise TypeError, which was silently
caught by the event watcher's exception handler, causing it to reconnect
and miss the container start event.

Fixed by using .get("Labels") or {} pattern in:
- _handle_event() when processing start events
- _get_container_command() when extracting command label
- _get_container_theme() when extracting theme label

Added test for null labels case.
2026-01-31 08:40:39 +00:00
GitHub Copilot 924905eace Bump version to 1.2.2 2026-01-30 10:56:59 +00:00
GitHub Copilot d9c35ee95d Refresh docker watch tiles on new containers 2026-01-30 10:56:39 +00:00
GitHub Copilot 6eaeeb624e Bump version to 1.2.1 2026-01-30 09:37:17 +00:00