Turns running at or past 3600s now read 1小时05分03秒 / 1h 05m 03s in the
running clock, the settled Ran-for footer, and the turn-time dialog, which
share formatRunDuration. Below an hour the second and minute branches are
unchanged, and the hour rolls at the unit boundary so 60分00秒 never appears.
The guide tab gains a compass hero, per-entry descriptions (shown while
at most four entries are listed), and a quieter cube placeholder for
entries that registered no glyph; the files entry registers its
description and folder glyph. Bundled stat fixes: the session usage
dialog drops the zero cache-write row, and the turn-time pill renders as
plain text when its dialog would only repeat the pill's own duration.
StatsPills buttons carry explicit aria-labels separating segments with
' · '; a log with no timed figure renders the counts pill as a static
reading instead of a button opening an empty dialog; the pills row owns
one exclusive open slot so sibling dialogs never stack. ContextMeter
restores the '~' approximation prefix (usedTokens prefers heuristic
projectedTokens). ModelSelect's jscpd:ignore now names the real gap
(useAnchoredPosition places from the left edge only). The pills Agent
Note's stale facts (locale keys, context occupancy, golden ownership)
are rewritten in place, en+zh. plan-review.e2e.ts parks the pointer
after Approve so the ContextMeter tooltip cannot leak into the aria
captures; affected goldens refreshed.
Master archived three Agent Notes this branch had fact-updated (archived
copies restored to their frozen master content; the pills note now links
the archived path), extended the steer-all placeholder to continuable
children (spec and subagent e2e take master's behavior with this branch's
reworded copy), and dropped the session-sharing sentence from feedback
acks (goldens re-refreshed with the new placeholder).
The A/B winner over the single-line StatsLine: a gauge pill (counts + TPS,
opening the session-stats dialog) and a database pill (billed total +
cache-hit share, opening the exact token-usage dialog), sharing a new
stat-dialog module. StatsLine and its dead locale keys are deleted, the
gauge icon is optically centered, and the composer keeps its 4px clearance
through the data-composer-stats contract. Agent Note added; stale
StatsLine references across implemented notes updated in place.
A single-consumer pure helper does not earn its own file: the mapping
now lives beside the prose vocabulary it serves (same shape as the
deliverables file-mention logic), and its unit cases merged into the
component spec.
Assistant prose that references a workspace-contained local media path
(e.g. ``) now renders through a same-origin
`GET|HEAD /api/file?path=` route instead of inert alt text.
- ui-primitives: MarkdownText gains a settled-only MarkdownPathImages
vocabulary gate (same posture as file mentions); no vocabulary means
byte-identical output.
- ui-chat: AssistantMarkdown supplies a page-stable rewrite vocabulary
for absolute POSIX paths (local-path-media.ts).
- session-controller: SessionMediaReferences plugin contribution mounts
the route on the authenticated connection.fetch channel; per-request
policy = workspace-root containment after realpath, regular file,
allowlisted media extension (images additionally signature-checked),
range/HEAD streaming, private no-store + nosniff, fail-closed statuses.
- Agent Note added (feature/2026-09-07-session-prose-local-media-display).
Closes#3662.