feat(sessions): a dsh session shows its route config's model while its screen names none

displayModel gains a `config` source, ranked below any report from the running
CLI and above the launch model: custom endpoint, then statusline or screen,
then config, then launch, then nothing. The screen still wins whenever it
names a model, since that is what the running TUI uses.

- Registry data: capabilities.modelDetect gains `configResolver`, a NAMED
  reader (src/model-config-resolvers.ts), like a launcher profile; dsh names
  'deepseek-route' (the reader from the previous commit). `screenLine` becomes
  optional; the schema refuses a modelDetect naming nothing, an unknown
  reader, or screenLines without a screenLine.
- Session: the reader runs from _withPaneLifecycle's finally, so at every pane
  start, attach and relaunch, with the session's own launch config
  (legacyConfigForMode) and env (its clamped overrides, then the server's), so
  a per-session DSH_HOME is the home read. Async; a read that lands after a
  newer one or after the session stopped is dropped; a remote or docker
  session reads nothing locally. A change emits displayModelChanged
  (broadcast and persist). Not restored after a restart: the next attach
  reads it again, and a restored screen value outranks it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-07 19:41:56 +02:00
parent 284f86b740
commit 661fe3dc13
9 changed files with 402 additions and 22 deletions
+5 -2
View File
@@ -646,9 +646,11 @@ export interface CustomModelSelection {
* - `custom-endpoint`: the Custom Model Endpoint Profile's model, which wins.
* - `statusline`: the CLI reported it (claude's statusLine exporter), follows a switch.
* - `screen`: read off the CLI's own footer (`capabilities.modelDetect`), follows a switch.
* - `config`: what the CLI's own config pins for this session
* (`capabilities.modelDetect.configResolver`), while its screen names none.
* - `launch`: what the session was launched with; nothing has reported since.
*/
export type DisplayModelSource = 'custom-endpoint' | 'statusline' | 'screen' | 'launch';
export type DisplayModelSource = 'custom-endpoint' | 'statusline' | 'screen' | 'config' | 'launch';
/** The model a session runs as far as the server knows, for a session header. */
export interface DisplayModel {
@@ -866,7 +868,8 @@ export interface SessionState {
/**
* The model this session runs, as far as the server knows it, and where that came from
* (src/session-display-model.ts): the custom endpoint's model, else the newest report
* from the CLI itself (statusline or its own footer), else the launch model. Absent when
* from the CLI itself (statusline or its own footer), else the model its config pins,
* else the launch model. Absent when
* none is known; a session header then shows the harness alone. Untrusted display text
* (pane-derived for `screen`): render it as text. Persisted, and a `statusline`/`screen`
* value is restored after a restart until the next report replaces it.