acpmux: publish a running turn's activity and plan step masked in the session summary

Merged
TE
7d ago
+59-52

Summary

acpmux's session summary now publishes a running turn's turn.activity (its latest tool call's title) and turn.planStep masked (secret_scan, masked before the 160-char cut), the same way the sub-session rows already do. A token in a tool call's title, such as curl -H 'x-key: …', no longer reaches any reader of the summary as raw text.

The finding (from the sidebar lane, on cmux#28095):

cmux#28095 (sidebar agent rows). Its opt-in Now line now shows turn.activity / turn.planStep from acpmux's watch summary, which carries them UNMASKED: hub/views.rs:398-399 copies t.doing.activity raw, and only the sub-session summaries get masked copies (hub/activity.rs:99, hub/subsessions.rs:821). The old source, lane.step, was masked (hq#2509), so a tool-call title holding a token could now show in the sidebar. Ask: publish masked copies of activity and planStep in the watch summary, using the existing Doing masker, as the sub-session summaries already do, so every app consumer gets the masked text.

What changed

  • hub/activity.rs: TurnActivity keeps only the masked line. activity_of masks, then cuts (session::masked_preview). The raw copy, the separate masked_* fields and mask_into are gone.
  • This one path feeds every reader of the summary: Hub::session_summary (hub/views.rs), which carries the app's sidebar row, _acpmux/watch / session_changed, _acpmux/sessions, acpmux ls --fields turn.activity, session info and the sub-session rows. It also feeds a turn an adopting daemon rebuilds from the log (hosts.rs, work.doing.note). A peer gets the masked text from the source, and server/peer_text.rs still masks those fields again on the way out.
  • subsessions.rs: drops the now-redundant mask_into call.
  • Protocol docs: TurnSummary.activity / planStep now say "masked". The Rust doc, spec/acpmux-protocol.json and the generated types.ts changed together; only the wording changed, no shape.

No reader needs the raw text. I grepped every reader of turn.activity / planStep / doing in cmux-tui, webviews and Packages: the webviews sessionList.ts doing line, subsession_send.rs doing_line, the CLI --fields examples and tests. All of them only display it.

Prior masking: hq#2509 (lane.step / peer text), cmux#23669 (the sub-session rows' masked activity).

Testing

Regression tests, committed before the fix (e66c53774d8):

  • hub::activity::tests::a_secret_in_a_tool_title_or_plan_step_is_masked: a tool title and a plan step carrying an AWS-key-shaped string are masked. A key straddling the 160-char cut leaves no head.
  • subsessions_delivery: a child's tool title carrying the key is masked in _acpmux/sessions over a local connection, which is what the app reads, as well as in the sub-session rows.

Command: cmux-ci test -- cargo test -p acpmux --lib hub::activity and --test subsessions_delivery, plus cargo clippy -p acpmux --all-targets -- -D warnings. Results are in a comment below: red at the test commit, green at the head.

Observed / Not run

  • Observed: rustfmt --check on the changed Rust files is clean.
  • Not run locally: cargo build/test/clippy (lane VM); they run through cmux-ci. The production code adds no panic sites; only code was removed.

No capture: no UI change. The daemon masks a text field it already sends; types.ts changed only a doc comment.

Changelog

Fixed: an agent's current tool call or plan step no longer shows a pasted secret in its session summary (sidebar, acpmux ls).

risk: normal (masking a display field; no shape change)

Agent session: agent session

šŸ¤– Generated with Claude Code