A session header can only name the model a session runs if the server knows
it, so SessionState gains `displayModel: { model, source }`, resolved in a pure
module (src/session-display-model.ts), strongest first:
- custom-endpoint: a Custom Model Endpoint Profile's modelId answers the
session, whatever alias the CLI prints;
- statusline / screen: the newest report from the running CLI itself.
Claude's statusLine exporter already posts model.display_name on every
render; the status-telemetry route now records it (only for a CLI with
capabilities.statusLineTelemetry). A CLI whose registry entry declares the
new capabilities.modelDetect has its footer read off the pane capture the
idle/working probe already takes (no extra tmux call), so an in-session
/model switch is followed at the next transition;
- launch: the model the session was launched with (claude's --model or the
app-wide default, another CLI's <cli>Config.model), read where the registry
says the model param lives;
- nothing known: no field, never a placeholder.
modelDetect is registry data, measured on live panes: dsh-TUI's status line
on the row under its composer (qwen3.8-27b on the owner's route) and codex's
`<model> <effort> ·` footer on its last row. Both anchor on chrome only that
CLI draws, over the last rows of the screen only; a transcript line shaped like
the footer is never taken (fixture tests). The pattern goes through
compileVersionRegex() with exactly one capture group, checked at load time.
An unreadable or covered footer keeps the last model (unlike the watching
label: a model does not stop running when something covers its row). Model
text is untrusted: escape sequences and control characters are stripped and it
is capped at 64 characters. A change emits displayModelChanged, broadcast
(session:updated) and persisted; a restart restores a CLI-reported model until
the next report.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Ported from #416 (discussion #405): a statusline reading just `codeman`
is what a hand-run claude in a managed repo showed, and it reads as a
broken config rather than a footer. Three paths produced it and all
three now yield an empty footer: the exporter's `|| echo codeman`
fallback (now `curl -sfk ... || true`, with -f keeping an HTTP error
body off stdout), the unknown-session answer of POST /api/status-telemetry,
and formatSessionStatusText() with nothing to show. The exporter script
marker moves to V4 so live installs pick the new content up on the next
spawn.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Review of the plan-usage chip feature (commits since 1.0.0) surfaced several
issues; this fixes all confirmed findings:
- HIGH: applyStatusLineConfig clobbered a user's hand-authored statusLine on
the enable path (the isOurs guard only protected disable). Now bails out when
an existing statusLine isn't ours, on both the enable and disable paths.
- MED: StatusTelemetrySchema used z.optional() (rejects null) on Claude's
undocumented statusline fields — a single stray null 400'd the entire POST and
silently killed the chip's data feed. Switched the modeled fields to .nullish().
- MED: dropping the Token Count / Show Cost header toggles left their features
reading settings.showTokenCount/showCost, but saveAppSettings rebuilds settings
fresh from the DOM, dropping those keys and resetting them to defaults on every
save (re-enabling the token chip with no UI to turn it off). Preserve the prior
stored preference.
- telemetrySignature keyed on contextUsedPercentage (never displayed) and the raw
unrounded %, churning a redundant SSE broadcast + localStorage write + identical
chip re-render on every assistant message. Now keys on the rounded displayed
window values only.
- Plan-usage chip flashed hidden on load (no server-side reveal): renderIndexHtml
now strips header-plan-usage--hidden when enabled, matching btn-multimonitor;
fixes the FOUC and makes the "server renders initial state" comments accurate.
- Serialize all settings.local.json read-modify-write writers in hooks-config via
a shared per-path mutex (previously lock-free; concurrent session-create +
settings-toggle on the same repo could lose writes).
- Hardened the chip's innerHTML against any future string field; removed the dead
_latestPlanUsage field; clamped ctx% in the footer formatter; corrected the
session-create comment (the path is add-only by design — a per-repo settings
file is shared by sibling sessions).
- Tests: new test/routes/status-telemetry-routes.test.ts (route behavior, dedup,
null-tolerance) + NaN/Infinity/fractional and signature-churn unit tests; made
server-index-title.test.ts deterministic against the ambient settings.json.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>