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
//! Session-related output formatters.
//!
//! Why: session list and event display share compact-output helpers that should
//! live outside the handler file to keep it below the 500-line cap.
//! What: `short_id` for UUID truncation, `event_summary` for payload one-liners,
//! `print_compression_stats` for optimizer feedback, `deploy_summary_line` for
//! the agent/skill deploy-count summaries `session start` prints.
//! Test: `short_id_*` and `event_summary_*` unit tests in `tests.rs`; the
//! compression stats helper is exercised by `compression_stats_line_*` tests;
//! `deploy_summary_line` by `deploy_summary_line_formats_counts`.
/// Render a `SessionId` JSON value into a short, human id.
///
/// Why (#7805): `SessionId` is a plain `#[derive(Serialize)]` newtype over
/// `Uuid`, and serde writes a newtype struct TRANSPARENTLY — the daemon's wire
/// value is the bare string `"<uuid>"`, never the `{"0": "<uuid>"}` tuple shape
/// this helper used to be the only reader of. Every row therefore rendered the
/// `--------` placeholder, and `tm sessions list` (and its `tm session` alias)
/// printed `-------- Starting <path>`, which reads as a start-progress line
/// rather than an id/status/workdir row — the misreading #7805 was filed on.
/// What: reads the bare-string wire form first, then the `{"0": …}` object form
/// any older producer may still emit, and truncates the uuid to its first 8
/// characters. A value that is neither still falls back to the placeholder.
/// Test: `short_id_reads_the_daemon_string_wire_form`,
/// `short_id_extracts_uuid_prefix`, `short_id_truncates_to_eight_chars`,
/// `short_id_falls_back_when_field_missing`,
/// `short_id_falls_back_when_value_not_str`.
pub
/// Summarize an opaque hook-event payload into a single short line.
///
/// Why: `session events` prints one row per event; a full JSON payload would
/// wrap the terminal, so a compact summary keeps rows readable.
/// What: shows the `tool` field when present, otherwise a truncated JSON dump.
/// Test: covered by `event_summary_*` unit tests.
pub
/// Print a one-line compression-savings note when an output was summarized.
///
/// Why: `session run --summarize` and `session output --summarize` should tell
/// the operator how much the summary saved, completing the visible feedback for
/// the "summarize output" step of the user cycle.
/// What: when the response body carries a non-null `compress_level`, prints
/// `[summarized: A → B bytes (N% reduction)]` to a fresh line; does nothing when
/// the output was returned raw (no compression applied).
/// Test: `compression_stats_line_*` unit tests.
pub
/// The `[input box: …]` note for a `GET /sessions/{id}/output` body (#8407).
///
/// Why: a plain pane capture shows Claude Code's dim next-prompt suggestion
/// exactly like a typed draft; the daemon classifies the box so a reader never
/// has to parse escape codes.
/// What: `[input box: empty|suggestion|typed]` from the body's `input_box`, or
/// `[input box: unknown]` when it is `null` or absent (an older daemon).
/// Test: `input_box_note_names_the_state`.
pub
/// Render a "`<Label>: N deployed, M skipped, K unchanged`" summary line.
///
/// Why (#1917): `session start` prints matching three-way deploy summaries
/// for both agents and skills; a shared formatter keeps the two counts in
/// lockstep instead of two near-identical `println!` calls drifting apart —
/// before this fix, only the agent line existed, and `report.skill_deploy`
/// was silently never surfaced anywhere.
/// What: formats `"{label}: {deployed} deployed, {skipped} skipped, {unchanged} unchanged"`.
/// Test: `deploy_summary_line_formats_counts`.
pub
/// Render the `session start` delegation-roster line, declaring the count
/// incomplete when a roster read failed.
///
/// Why (#5544): this line is where `tm session start` publishes
/// [`trusty_mpm::core::instruction_pipeline::PipelineOutput::agent_count`], and
/// an unreadable agent file lowers that number with nothing to distinguish it
/// from a genuinely smaller roster. Printing the bare count was the same
/// incomplete-result-reported-as-complete shape the composed prompt's
/// `ROSTER INCOMPLETE` banner exists to remove, surviving one layer up.
/// What: the plain `"Instructions: N agents in delegation authority"` when
/// nothing was lost; otherwise `N` is qualified as `at least N` and the line
/// carries `ROSTER INCOMPLETE` with the unreadable paths named.
/// Test: `session_start_roster_line_is_plain_when_the_roster_is_whole`,
/// `session_start_roster_line_declares_an_incomplete_roster`.
pub