Skip to content

feat(tui): show the running version in the dashboard header - #394

Merged
MagicalTux merged 6 commits into
KarpelesLab:masterfrom
lexfrei:feat/tui-header-version
Sep 15, 2026
Merged

MagicalTux merged 6 commits into
KarpelesLab:masterfrom
lexfrei:feat/tui-header-version

Conversation

@lexfrei

@lexfrei lexfrei commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

The header doesn't say which build is running. A release and a local tarball built from it both read 1.1.20, so telling them apart means running teamclaude --version in another terminal. The startup update notice is no help either: it's only printed when there is no TUI.

Header now carries the version in the middle of the line — the tag if HEAD sits on one, else the short sha, else the package.json version, and local when nothing is readable.

A green ▲ shows up beside it when a newer release is known. It reads the daily update cache the updater already writes, so nothing here touches the registry. In a git checkout there is no marker at all, since autoUpdate refuses to npm-install over one anyway.

An attached dashboard shows the server's build. The label comes over in /teamclaude/status and is sanitized like every other field off the wire, because it goes straight into the frame. A server too old to send it falls back to server.version.

Too narrow, and the label is dropped whole; the header falls back to what it was.

The header had no test before this. There is one now: the line has to be exactly the terminal width across a matrix of widths, session counts and update states. An off-by-one in either padding run pushes the liveness ▲ off the right edge, where fitLine eats it silently.

lexfrei and others added 6 commits September 14, 2026 14:47
…ache without fetching

The dashboard has no way to name the build it runs: currentVersion() reports
package.json, which is identical for a release and for a local tarball built
from it. resolveVersionLabel prefers the exact tag, falls back to the short
sha, and only then to package.json, so a checkout is distinguishable from an
install at a glance. It also reports whether the copy is a checkout, which
callers need because autoUpdate refuses to touch one.

The git calls are pinned to the package root. The server is started from the
operator's own project directory, and resolving against the process cwd would
report that repository's sha as this package's version.

updateAvailableFromCache answers the same question as checkForUpdate from the
daily cache alone, so a caller on a render or status path never reaches the
registry.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The dashboard never said which build it was: a release and a local tarball
built from it are indistinguishable on screen, and the update notice printed at
startup is skipped entirely under the TUI.

The label is centred on the line rather than in the gap between the title and
the port block, so it holds still as the session segment comes and goes. It is
dropped whole once either side is within two columns of it — a squeezed or
clipped version string is worse than none, and the fallback is the header
exactly as it was.

A second green triangle follows the label when a newer release is known. It
reuses the glyph of the liveness marker at the right edge deliberately: both
mean "there is something here worth looking at".

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
…status

Both consumers need the same answer: the in-process TUI draws it in the header,
and an attached dashboard reads it off /teamclaude/status so it names the
server's build rather than its own. Resolved once at startup, next to
serverVersion and for the same reason — it must report what is running.

The update flag is read from the daily cache, so nothing here touches the
network. A checkout is excluded: autoUpdate returns early on one, so a marker
there would advertise an action the tool declines.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The status payload is stored raw, and applyStatus exists because everything
drawn from it must not be able to put an escape sequence in the operator's
terminal. The version label is drawn straight into the header, so it goes
through the same sanitizer as every other field off the wire, and the renderer
reads the sanitized property rather than the raw payload.

Falling back to server.version keeps an older server readable: it shows the
plain semver and no update marker. A server older than both leaves the label
empty and the header omits it.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The header had no test at all, and it is now three pieces of arithmetic that
must sum to the terminal width — so the width invariant is asserted across a
matrix of widths, session counts and update states, not at one comfortable
size. An off-by-one in either padding run pushes the liveness marker off the
right edge, which is exactly what fitLine would hide.

The label resolution is driven through an injected exec: no real git runs, so
the tests hold on a shallow CI clone that has no tags to describe. Both paths
that reach a terminal — a tag name and a label off the wire — are pinned for
control characters.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
@MagicalTux
MagicalTux merged commit e9045da into KarpelesLab:master Sep 15, 2026
5 checks passed
rikbrown added a commit to rikbrown/teamclaude that referenced this pull request Sep 15, 2026
Local branding: the dashboard's top-left title becomes "RikClaude Harness".

The version display this commit used to carry is upstream's now (KarpelesLab#394,
e9045da). Upstream resolves an exact tag or short sha rather than
package.json, sanitizes the label on the attach-mode path, and marks an
available update beside it — and draws it centred on the header line, so
the title block keeps the brand on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
rikbrown added a commit to rikbrown/teamclaude that referenced this pull request Sep 19, 2026
Local branding: the dashboard's top-left title becomes "RikClaude Harness".

The version display this commit used to carry is upstream's now (KarpelesLab#394,
e9045da). Upstream resolves an exact tag or short sha rather than
package.json, sanitizes the label on the attach-mode path, and marks an
available update beside it — and draws it centred on the header line, so
the title block keeps the brand on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@MagicalTux MagicalTux mentioned this pull request Sep 20, 2026
MagicalTux added a commit that referenced this pull request Sep 20, 2026
Thirty-six commits since 1.1.20. Several change what a client sees on a
failure, so read the first section before upgrading a shared deployment.

Behaviour changes
  #439 a 401 from upstream is no longer relayed to the client: the request
       fails over like a 403, and an API-key account or an OAuth account with
       no refresh token leaves rotation (it used to be picked again on every
       request). With nothing left the client gets the proxy's own error
  #439 a path under /teamclaude/ that no control route claims — a typo, or the
       wrong verb — answers 404 locally instead of being forwarded upstream
       under a fleet credential
  #429 the synthetic 429's retry-after is the real reset of the windows
       blocking the request's candidate accounts, not a flat 60s, and the
       message counts only those candidates; #408 names accounts that need a
       re-login instead of calling them "at quota"
  #438 session pins are per conversation (session id plus a digest of the
       first message), so a session's subagents spread across accounts.
       `sessions.items[].id` in status is the composite key, load is counted
       per conversation, and a persisted concurrency cap re-learns
  #378 a `thread: continue` bound for a per-account third-party upstream is
       refused with the 400 Anthropic gives, so the client resends the whole
       conversation; `messageThreads: true` opts a relay out
  #434 a 429 whose x-codex-* headers show a spent account-wide window holds
       the account like an Anthropic rejection; a spent model-scoped bucket
       only moves the request
  #437 a Codex response head is awaited for five minutes (Anthropic unchanged)
  #411 idle keep-alive connections are held 120s on both listeners
  #389 with session distribution on, requests carrying no session id rotate on
       a cursor of their own instead of all resting on the current account
  #405 `defaultClientMode` ("mitm" | "base-url") sets what `run` and `env` do
       without a flag; `--mitm` / `--no-mitm` decide per launch, and in
       base-URL mode `env` unsets a stale proxy export naming this proxy
  #439 route `--bucket` is validated; an array `switchThreshold` reads as the
       default with one line saying so

Features
  #419 an MCP management endpoint at POST /teamclaude/mcp, off unless
       `proxy.mcp` is "read" or "full"; a named client key is read-only even
       in full mode, and with no proxy key it serves only this machine
  #428 per-account `switchThreshold`, a number or a per-bucket table
  #406 a Claude+Codex pool is drawn as two panes on a wide terminal, each with
       its own current marker; #392 names the provider in a mixed list; #418
       lets the operator arrange the list (`displayOrder`); #376 draws
       loopback-served accounts last; #435 shows the percentage beside a bar's
       countdown; #394 shows the running version in the header
  #430 free Codex rate-limit reset credits in status, the TUI and the dashboard
  #385 `proxy.terminalOnly` tunnels chatgpt.com so ChatGPT Desktop stays out

Fixes
  #404 a TUI paint can no longer block the proxy (stdout non-blocking, frames
       dropped while the terminal is behind); #410 a dead terminal no longer
       takes the proxy with it, and SIGHUP shuts down cleanly
  #433 token usage is booked from Codex Responses streams
  #386 #387 #388 the Codex five-hour window is read from the model-scoped
       family and the usage probe, and extra limits are named from their entries
  #431 a headerless 429 that follows the request is retried once
  #432 #439 startup and collaborator log lines reach the TUI's activity pane
       and log file instead of the covered terminal
  #415 #403 #439 reload mirrors `priority`, `disabled`, `stripRequestFields`
       onto the config entry, and a reload during a removal does not re-add it
  #439 the Host check uses the address actually bound; sx.org calls time out
  #381 the dashboard polls status before asking for a key
  #403 session outcome accounting classifies the decoded path; account names in
       daemon log lines are sanitised

Tooling
  #371 #372 #373 `npm run typecheck` (tsc over the JS sources) in CI, with a
       strict-mode ratchet: per-file strict diagnostics may not grow past the
       pre-merge commit (2006 at introduction, 1735 now)
  #401 docker workflow actions bumped

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
rikbrown added a commit to rikbrown/teamclaude that referenced this pull request Oct 7, 2026
Local branding: the dashboard's top-left title becomes "RikClaude Harness".

The version display this commit used to carry is upstream's now (KarpelesLab#394,
e9045da). Upstream resolves an exact tag or short sha rather than
package.json, sanitizes the label on the attach-mode path, and marks an
available update beside it — and draws it centred on the header line, so
the title block keeps the brand on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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