own /effort: respawn-with-resume carrying --effort, picker UX (T-412)

Spike result (probed claude 2.1.175 over stream-json): there is NO
set_effort/set_thinking_effort control subtype — both are rejected. The
lever is the `--effort <level>` spawn flag (low/medium/high/xhigh/max;
settings.json effortLevel is the persisted default). So changing effort
restarts the process: respawn-with-resume keeps the conversation and
carries the flag — the same continuity /clear and /resume already rely on.

- SpawnSpec.effort → orchestrator appends `--effort <level>`.
- claude_pane: /effort <level> validates and respawns (toast explains the
  restart); bare /effort opens a picker; the pane re-applies its effort on
  every later respawn. Invalid level → local notice listing levels.
- ModelPickerCard generalised minimally (title + isCurrent predicate) so
  the effort picker reuses it; effort needs exact matching because `high`
  is a substring of `xhigh` and alias-containment would mis-mark it.
- SessionStatus.effort + StreamJsonSession.noteEffort: the wire never
  reports effort, so the spawner records what it set; status/sidebar read
  it from the normal status stream.
- Routing: effort moves from the TUI-only catalog to kClideOwnedCommands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 12:56:09 +02:00
co-authored by Claude Fable 5
parent 02c6dd4cf0
commit 1bdd88f4ab
14 changed files with 208 additions and 16 deletions
@@ -522,6 +522,16 @@ void main() {
expect(const SessionStatus(contextWindow: 0).isEmpty, isFalse);
expect(const SessionStatus(rateLimitInfo: 'rate limited').isEmpty, isFalse);
});
test('effort merges, compares, and flips isEmpty (T-412)', () {
const a = SessionStatus(model: 'm1');
final m = a.merge(const SessionStatus(effort: 'high'));
expect(m.effort, 'high');
expect(m.model, 'm1');
expect(const SessionStatus(effort: 'high'), const SessionStatus(effort: 'high'));
expect(const SessionStatus(effort: 'high'), isNot(const SessionStatus(effort: 'max')));
expect(const SessionStatus(effort: 'low').isEmpty, isFalse);
});
});
group('synthetic CLI-local output (T-411)', () {