Skip to content

feat(terminal-progress): add kitty support (0.47+) - #84

Merged
pedropombeiro merged 4 commits into
pedropombeiro:mainfrom
daropotter:feat/kitty-terminal-detection
Oct 10, 2026
Merged

pedropombeiro merged 4 commits into
pedropombeiro:mainfrom
daropotter:feat/kitty-terminal-detection

Conversation

@daropotter

@daropotter daropotter commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds kitty support to opencode-terminal-progress, gated on kitty 0.47+ — the version that
draws an in-window progress bar (progress_bar option in kitty.conf) and shows the state
indicator in the tab title.

Detection & version gate

if (env['KITTY_WINDOW_ID'] || env['TERM_PROGRAM'] === 'kitty') {
  const version = await detectKittyVersion();
  if (version && isSupportedKitty(version)) return 'kitty';
  return undefined;
}
  • KITTY_WINDOW_ID is set by kitty itself for every process it launches (also without shell
    integration / when TERM_PROGRAM is missing) — the kitty equivalent of ITERM_SESSION_ID /
    WEZTERM_EXECUTABLE.
  • The version is read from TERM_PROGRAM_VERSION (shell integration) or, on Linux, by resolving the
    running emulator binary via /proc/<KITTY_PID>/exe and running --version. If the version cannot
    be confirmed as ≥ 0.47, the plugin stays a no-op.

setup is async (await detectTerminal()) — allowed by Plugin.Definition.

Keeping the kitty indicator alive

kitty auto-clears any OSC 9;4 progress ~60 s after the last report (clear_timeout in
kitty/kitty/progress.py), so a single report per state change made the indicator vanish during
longer runs. While a state is active the plugin now re-reports it every 30 s — only on kitty, and
with the same canonical payload: busy 9;4;3 (indeterminate), waiting 9;4;4;50, error 9;4;2,
idle 9;4;0. No determinate 9;4;1;N sequences are emitted; busy stays indeterminate, matching
the canonical ConEmu/OSC 9;4 semantics and the visuals of the other supported terminals
(Windows Terminal, Ghostty, WezTerm, VTE, iTerm2 render indeterminate as a spinner/pulse).

Checks

  • tsc --noEmit ✅ · ESLint ✅ · bun build ✅
  • e2e (mock context, OSC captured via pty): a 31 s busy emits 9;4;3 per heartbeat with no
    9;4;1;N; waiting emits 4;50, error 2, idle 0.
  • Live on kitty 0.49.2 (Linux): the tab-state indicator stays visible for over 60 s, pauses at
    50 % on questions, clears on idle.

Detect kitty via KITTY_WINDOW_ID (set by kitty itself for every process it
launches, so it works even without shell integration / TERM_PROGRAM) or
TERM_PROGRAM=kitty. kitty has reported OSC 9;4 progress since 0.39
(percentage in tab title) and draws an in-window progress bar since 0.47.
kitty only renders an in-window progress bar since 0.47 (progress_bar option).
Older versions show at most a percentage in the tab title (0.39-0.46), and
before 0.38 OSC 9;4 was misread as a notification. Keep the plugin a no-op
unless the running kitty is confirmed to be at least 0.47.

Version is read from TERM_PROGRAM_VERSION when the shell integration exported
it, otherwise on Linux by querying the running emulator binary via
/proc/<KITTY_PID>/exe.
@daropotter daropotter changed the title feat(terminal-progress): add kitty support feat(terminal-progress): add kitty support (0.47+) Oct 2, 2026
daropotter and others added 2 commits October 2, 2026 18:21
…ging visuals

kitty clears any OSC 9;4 progress ~60 s after the last report, so a single
report per state change made the indicator disappear during longer runs.

Re-report the active state every 30 s while it lasts, but only on kitty and
without changing what is reported: busy stays indeterminate (9;4;3), matching
the canonical ConEmu/OSC 9;4 behaviour and the visuals of the other supported
terminals (spinner/pulse on Windows Terminal, Ghostty, WezTerm, VTE, iTerm2).
… its real version

kitty never sets TERM_PROGRAM or TERM_PROGRAM_VERSION, so the version was
often read from whatever else set them (e.g. tmux 3.4 passing the 0.47 gate
on an older kitty), and a KITTY_WINDOW_ID leaked into a nested Ghostty or
WezTerm hijacked their detection.

- Treat the host as kitty only when TERM_PROGRAM is unset, tmux or kitty.
- Trust TERM_PROGRAM_VERSION only alongside TERM_PROGRAM=kitty.
- Run /proc/<KITTY_PID>/exe directly (works after upgrades), only if it
  resolves to a kitty binary, with a 2 s timeout.
- Fall back to the binary in KITTY_INSTALLATION_DIR (Linux and macOS).
- Move detection into kitty.ts with unit tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@pedropombeiro
pedropombeiro merged commit 3a410b8 into pedropombeiro:main Oct 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants