From 71ebe3b9e3ffcc350754f827fcdeaf974f8b0c61 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Tue, 6 Oct 2026 16:08:23 +0000 Subject: [PATCH] 0.10.3: recognise hqterm (synchronized frames, iTerm2 images); LC_TERMINAL=iTerm2 TERM_PROGRAM=hqterm is detected first (panes launched from Konsole inherit KONSOLE_VERSION), gets DEC 2026 synchronized output (xterm.js 6 supports it, so each frame lands at once instead of being drawn as it streams in) and iTerm2 inline images. LC_TERMINAL=iTerm2 (what the desktop app sends over ssh) now reads as iTerm2. Co-Authored-By: Claude Opus 5.5 --- apps/benchmark/package.json | 2 +- apps/demo/package.json | 4 ++-- apps/demo/src/main.ts | 2 +- apps/web/app/page.tsx | 2 +- apps/web/package.json | 2 +- bun.lock | 10 +++++----- examples/package.json | 2 +- packages/hqtui/package.json | 2 +- packages/hqtui/src/capabilities.ts | 7 +++++-- packages/hqtui/src/cli.ts | 2 +- packages/hqtui/src/images.ts | 2 +- packages/hqtui/test/images.test.ts | 11 +++++++++++ ports/nim/hqtui.nimble | 2 +- ports/nim/src/hqtui.nim | 2 +- 14 files changed, 33 insertions(+), 19 deletions(-) diff --git a/apps/benchmark/package.json b/apps/benchmark/package.json index 72450ed..1735770 100644 --- a/apps/benchmark/package.json +++ b/apps/benchmark/package.json @@ -7,6 +7,6 @@ "start": "bun src/main.ts" }, "dependencies": { - "@profullstack/hqtui": "^0.10.2" + "@profullstack/hqtui": "^0.10.3" } } diff --git a/apps/demo/package.json b/apps/demo/package.json index e628bf5..0f5df99 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -1,6 +1,6 @@ { "name": "@profullstack/hqtui-demo", - "version": "0.10.2", + "version": "0.10.3", "description": "The HQTUI reference dashboard: a btop-grade terminal system monitor. Runs on real system metrics or a deterministic simulation.", "license": "MIT", "type": "module", @@ -27,7 +27,7 @@ "audit:scroll": "bun scripts/scrollaudit.ts" }, "dependencies": { - "@profullstack/hqtui": "^0.10.2" + "@profullstack/hqtui": "^0.10.3" }, "publishConfig": { "access": "public" diff --git a/apps/demo/src/main.ts b/apps/demo/src/main.ts index 17d127c..a3edd8c 100755 --- a/apps/demo/src/main.ts +++ b/apps/demo/src/main.ts @@ -52,7 +52,7 @@ function parseArgs(argv: string[]): Options { case "-h": case "--help": printHelp(); process.exit(0); case "-v": - case "--version": console.log("hqtui-demo 0.10.2"); process.exit(0); + case "--version": console.log("hqtui-demo 0.10.3"); process.exit(0); } } return options; diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 490fd13..6e1a13c 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -158,7 +158,7 @@ export default async function Home() { High Quality Terminal UI for TypeScript, Rust, Go, Python, Zig and C++

- v0.10.2 · {COUNT} language demos · MIT + v0.10.3 · {COUNT} language demos · MIT

Terminal dashboards that diff --git a/apps/web/package.json b/apps/web/package.json index 21e253e..5dc2c88 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@base-ui/react": "1.7.0", - "@profullstack/hqtui": "^0.10.2", + "@profullstack/hqtui": "^0.10.3", "@profullstack/libsql-pg": "^0.1.3", "class-variance-authority": "0.7.1", "clsx": "2.1.1", diff --git a/bun.lock b/bun.lock index c62fc2f..b962b1f 100644 --- a/bun.lock +++ b/bun.lock @@ -21,12 +21,12 @@ }, "apps/demo": { "name": "@profullstack/hqtui-demo", - "version": "0.10.2", + "version": "0.10.3", "bin": { "hqtui-demo": "./bin/hqtui-demo.mjs", }, "dependencies": { - "@profullstack/hqtui": "^0.10.2", + "@profullstack/hqtui": "^0.10.3", }, }, "apps/web": { @@ -34,7 +34,7 @@ "version": "0.1.0", "dependencies": { "@base-ui/react": "1.7.0", - "@profullstack/hqtui": "^0.10.2", + "@profullstack/hqtui": "^0.10.3", "@profullstack/libsql-pg": "^0.1.3", "class-variance-authority": "0.7.1", "clsx": "2.1.1", @@ -59,12 +59,12 @@ "name": "@profullstack/hqtui-examples", "version": "0.1.0", "dependencies": { - "@profullstack/hqtui": "^0.10.2", + "@profullstack/hqtui": "^0.10.3", }, }, "packages/hqtui": { "name": "@profullstack/hqtui", - "version": "0.10.2", + "version": "0.10.3", "bin": { "hqtui": "./bin/hqtui.mjs", }, diff --git a/examples/package.json b/examples/package.json index 4157205..34150e4 100644 --- a/examples/package.json +++ b/examples/package.json @@ -4,6 +4,6 @@ "version": "0.1.0", "type": "module", "dependencies": { - "@profullstack/hqtui": "^0.10.2" + "@profullstack/hqtui": "^0.10.3" } } diff --git a/packages/hqtui/package.json b/packages/hqtui/package.json index e47f9c3..67e5ad3 100644 --- a/packages/hqtui/package.json +++ b/packages/hqtui/package.json @@ -1,6 +1,6 @@ { "name": "@profullstack/hqtui", - "version": "0.10.2", + "version": "0.10.3", "description": "High Quality Terminal UI for TypeScript. btop-grade dashboards with a one-import API, dark by default, zero runtime dependencies.", "license": "MIT", "type": "module", diff --git a/packages/hqtui/src/capabilities.ts b/packages/hqtui/src/capabilities.ts index fdaaa43..098ced2 100644 --- a/packages/hqtui/src/capabilities.ts +++ b/packages/hqtui/src/capabilities.ts @@ -35,10 +35,13 @@ export interface CapabilityOverrides { } function detectProgram(env: NodeJS.ProcessEnv): string { + // First: launched from another terminal, hqterm's panes inherit its markers + // (KONSOLE_VERSION, KITTY_WINDOW_ID ...), but the pane is hqterm. + if (env.TERM_PROGRAM === "hqterm") return "hqterm"; if (env.KITTY_WINDOW_ID || env.TERM === "xterm-kitty") return "kitty"; if (env.WEZTERM_EXECUTABLE || env.TERM_PROGRAM === "WezTerm") return "wezterm"; if (env.GHOSTTY_RESOURCES_DIR || env.TERM === "xterm-ghostty") return "ghostty"; - if (env.TERM_PROGRAM === "iTerm.app") return "iterm"; + if (env.TERM_PROGRAM === "iTerm.app" || env.LC_TERMINAL === "iTerm2") return "iterm"; if (env.ALACRITTY_WINDOW_ID || env.TERM === "alacritty") return "alacritty"; if (env.TERM_PROGRAM === "vscode") return "vscode"; if (env.WT_SESSION) return "windows-terminal"; @@ -102,7 +105,7 @@ export function detectCapabilities( const unicode = overrides.unicode ?? detectUnicode(env); const syncCapable = - ["kitty", "wezterm", "ghostty", "iterm", "windows-terminal", "konsole", "alacritty"].includes(program) || tmux; + ["kitty", "wezterm", "ghostty", "iterm", "windows-terminal", "konsole", "alacritty", "hqterm"].includes(program) || tmux; return { tty, diff --git a/packages/hqtui/src/cli.ts b/packages/hqtui/src/cli.ts index 2689d2c..b799751 100644 --- a/packages/hqtui/src/cli.ts +++ b/packages/hqtui/src/cli.ts @@ -14,7 +14,7 @@ import { detectCapabilities } from "./capabilities.ts"; import { themeList, themes } from "./theme.ts"; import { BrailleCanvas } from "./graphics/braille.ts"; -const VERSION = "0.10.2"; +const VERSION = "0.10.3"; function help(): void { console.log(`hqtui ${VERSION} — High Quality Terminal UI for TypeScript diff --git a/packages/hqtui/src/images.ts b/packages/hqtui/src/images.ts index 14888dd..e910ecd 100644 --- a/packages/hqtui/src/images.ts +++ b/packages/hqtui/src/images.ts @@ -68,7 +68,7 @@ export function imageSupport(env: NodeJS.ProcessEnv = process.env): ImageSupport if (/^(ghostty|kitty)$/i.test(env.TERM_PROGRAM ?? "")) return "kitty"; if (/^xterm-(kitty|ghostty)$/.test(env.TERM ?? "")) return "kitty"; // WezTerm and iTerm2: inline images, not placeholders. - if (program === "wezterm" || program === "iterm") return "iterm"; + if (program === "wezterm" || program === "iterm" || program === "hqterm") return "iterm"; if (env.WEZTERM_PANE || env.WEZTERM_EXECUTABLE || /^(wezterm|iterm\.app)$/i.test(env.TERM_PROGRAM ?? "")) return "iterm"; if (env.LC_TERMINAL === "iTerm2") return "iterm"; return "none"; diff --git a/packages/hqtui/test/images.test.ts b/packages/hqtui/test/images.test.ts index 6b3ee58..7d39b04 100644 --- a/packages/hqtui/test/images.test.ts +++ b/packages/hqtui/test/images.test.ts @@ -9,6 +9,17 @@ import { createImageStore, drawRichText, imageSupport, inTmux, behindMosh, kittyVirtualImage, passthrough, placeholderCell, PLACEHOLDER, } from "../src/images.ts"; import { renderToScreen } from "../src/testing.ts"; +import { detectCapabilities } from "../src/capabilities.ts"; + +test("hqterm is recognised: synchronized frames and iTerm2 images, even when launched from Konsole", () => { + const env = { TERM: "xterm-256color", TERM_PROGRAM: "hqterm", KONSOLE_VERSION: "240802", HQTUI_MOSH: "0" }; + const caps = detectCapabilities({ tty: true }, env); + assert.equal(caps.program, "hqterm"); + assert.equal(caps.synchronizedOutput, true); + assert.equal(imageSupport(env), "iterm"); + // On a remote host the desktop app identifies itself the iTerm2 way. + assert.equal(detectCapabilities({ tty: true }, { TERM: "xterm-256color", LC_TERMINAL: "iTerm2" }).program, "iterm"); +}); import { cellText } from "../src/unicode.ts"; // These tests describe terminals, not the machine running them (which may be behind mosh). diff --git a/ports/nim/hqtui.nimble b/ports/nim/hqtui.nimble index 765ab21..63e175c 100644 --- a/ports/nim/hqtui.nimble +++ b/ports/nim/hqtui.nimble @@ -1,6 +1,6 @@ # Package -version = "0.10.2" +version = "0.10.3" author = "HQTUI contributors" description = "Terminal UI widgets and the ten-screen HQTUI dashboard for Nim, over HQTUI's shared native engine (compiled from source)" license = "MIT" diff --git a/ports/nim/src/hqtui.nim b/ports/nim/src/hqtui.nim index fd15904..8788057 100644 --- a/ports/nim/src/hqtui.nim +++ b/ports/nim/src/hqtui.nim @@ -6,7 +6,7 @@ import std/[json, os, strutils] export json -const version* = "0.10.2" +const version* = "0.10.3" const engine = currentSourcePath().parentDir / "hqtui" / "engine"