1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! UX-21: OSC terminal-title updates — sets the terminal window/tab title to
//! reflect Volter Harness's current activity (`Volter Harness · <model>` while idle at
//! the prompt, `Volter Harness · <model> · thinking…` while a turn is in flight)
//! so a session is identifiable among other tabs, and restores whatever
//! title was there before on exit.
//!
//! Design goals (mirroring `spinner.rs`'s and `ui.rs`'s established shape —
//! see `spinner::should_show_spinner` / `ui::detect_color_level`):
//! - Zero-dependency: two escape-sequence writes, no crate.
//! - Byte-clean on any non-interactive path: piped/redirected stderr,
//! `--quiet`/`SUPERCODE_QUIET`, or a dumb terminal must never see a single
//! title byte. Achieved by never emitting anything when
//! [`should_set_title`] says no — the single choke point, same discipline
//! as `Spinner::enabled`.
//! - Never touches stdout: the OSC bytes go to stderr only, so `run
//! --output-format json` / piped answers are never at risk of an escape
//! sequence landing in machine-readable output.
//! - Restores on exit: [`TitleGuard::enter`] pushes the terminal's current
//! title onto its title stack (xterm window-ops `CSI 22 ; 0 t`) before
//! setting the first title; `Drop` pops it back (`CSI 23 ; 0 t`) on every
//! exit path (normal return, `?`, or panic-unwind) — the same
//! belt-and-suspenders teardown `Spinner`'s `Drop` uses.
use ;
/// Push the current title onto the terminal's title stack (xterm window
/// manipulation, `CSI 22 ; 0 t` with the `0` parameter meaning "both icon
/// and window title"). Widely supported (xterm, most VTE-based terminals,
/// iTerm2, Windows Terminal); on a terminal that doesn't understand it, it's
/// silently ignored like any unrecognized CSI sequence.
const PUSH_TITLE: &str = "\x1b[22;0t";
/// Pop the previously-pushed title back off the stack, restoring whatever
/// the terminal showed before supercode started touching it.
const POP_TITLE: &str = "\x1b[23;0t";
/// The activity supercode's title should reflect. Deliberately just two
/// states (idle / thinking) — the AC calls for "model / running / idle",
/// and "running" and "thinking" are the same state from the title's
/// perspective (a turn is in flight).
pub
/// Pure decision function for "should the title ever be touched?" — no I/O,
/// unit-testable without a real tty or mutated env vars, the same shape as
/// `spinner::should_show_spinner`.
///
/// Title emission is suppressed when:
/// - the caller is in `--quiet`/`SUPERCODE_QUIET` mode (`quiet`) — UX-21
/// dev/02;
/// - `TERM=dumb` (a terminal that declares no capabilities shouldn't be
/// sent window-manipulation escapes); or
/// - stderr isn't a terminal (piped/redirected/non-interactive — UX-21
/// dev/02's "non-tty/piped" case; this is also what makes `run
/// --output-format json` and any non-interactive path byte-clean, since
/// those never construct a `TitleGuard` enabled in the first place).
pub
/// Real-world gating: reads `TERM` and stderr's tty-ness. `quiet` is
/// threaded in by the caller, exactly like `spinner::should_show_spinner_now`
/// — every call site passes `main.rs`'s `effective_quiet(cli)`
/// (`cli.quiet || SUPERCODE_QUIET`), so the flag and the env var can never
/// give different answers.
/// Strip control characters (including ESC/BEL) from a title component
/// before it's interpolated into an OSC sequence. `model` ultimately comes
/// from `--model`/config — untrusted enough that a crafted value containing
/// an embedded `ESC`/`BEL` must not be able to break out of the title
/// sequence and inject arbitrary escapes into the user's terminal.
/// Build the title string for a given model/state, e.g.
/// `"Volter Harness · claude-opus-4-6 · thinking…"`.
/// Emit an OSC 0 (icon + window title) set sequence: `ESC ] 0 ; <title> BEL`.
/// Written to stderr only, never stdout, and flushed immediately so it lands
/// before whatever the caller prints next.
/// RAII scope for a title-managed interactive session (the REPL, `chat()`).
/// Construct once via [`TitleGuard::enter`] at the top of the session;
/// [`TitleGuard::set`] updates it on turn start/finish; `Drop` restores the
/// terminal's previous title on every exit path. A disabled guard (gating
/// says no) is a true no-op end to end — `enter`/`set`/`drop` never touch
/// stderr — so `--quiet`/non-tty/dumb-terminal sessions stay byte-clean.
pub