Adopt GET /api/hermes/update/receipt and append its summary to the
end of the hermes-update action progress popup after it finishes.
Additive only: existing checkHermesUpdate + connection-retry polling
is untouched. 404 (old backend) is handled gracefully.
- add UpdateReceiptResponse data model matching backend schema
- add getUpdateReceipt() to HermesApiService
- ActionProgressController gains trailingLines + pushTrailingLines
- ActionProgressDialog renders trailingLines after the log
- SystemViewModel fetches receipt on action finish and formats it
- extract pure formatUpdateReceiptLines for mockk-free testing
ORDERED_RE only captured item text and discarded the source number, and the
parse loop broke on the first blank line — so loose numbered lists (blank lines
between items) re-indexed every item to 1.
- capture the prefix number and emit it as MdBlock.Ordered.index
- treat a blank line as list-internal when the next non-blank line is another
ordered item, so loose lists stay one ordered list
- keep sequential numbering for tight lists (1,2,3) and honor custom starts
add regression tests in MarkdownTextFeatureTest (loose, custom-start, tight).
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
* fix(auth): await cookie scope hydration before ticket mint and request loading (#961)
* refactor(auth): scope latch activation to active store hydration
---------
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
The AnimatedContent gate on the composer's send button required
inputFieldValue.text.isNotBlank() in addition to canSend, so attaching an
image or file with an empty input hid the button entirely — the attachment
could never be sent on its own. ChatInputPolicy.canSend already allowed
attachment-only sends and ChatViewModel.sendMessage already accepted blank
text with pending attachments, but the button never rendered to trigger it.
Drop the stale text gate so the send affordance tracks canSend (non-empty
text OR pending attachments, plus connection). The backend handles
image-only turns natively: prompt.submit with empty text + queued images
routes through build_native_content_parts, which wraps the pixels with an
[Image attached at: ...] hint.
Add a Compose UI regression test asserting the send button is displayed
with a pending image attachment and an empty input.
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
* fix(chat): skip empty assistant tool-call placeholder rows in REST transcript
Non-reasoning models (e.g. gemini-3.5-flash) store a tool-call turn as an
empty assistant row (content = "", no reasoning) with a tool_calls list.
The REST transcript returns these verbatim, and mapServerMessages was only
filtering empty assistant rows that carried reasoning text (the issue #771
thinking-model case). With no reasoning, the filter check failed and the
placeholder rows fell through — rendering as empty bubbles with Copy buttons
in the chat list.
Fix: skip ANY empty assistant row regardless of whether reasoning is present.
If it carries reasoning, stash it for folding (issue #771 path unchanged).
If it doesn't, it's a pure tool-call placeholder — silently drop it.
No user-visible content is lost: these rows never held displayable text.
Verified on device (hermes37 emulator): session 'Friendly greeting #9' had
10 ghost empty bubbles; after fix the transcript shows only real messages.
Issue: #956
* fix(chat): blank-content guard in FullBleedAgentMessage prose renderer
Defense-in-depth for the ghost-bubble fix (#953): never render an empty
prose block (blank text + lone Copy button) if a placeholder row ever
slips past upstream mapping. Streaming messages keep rendering so the
live cursor survives until the first delta lands.
Verified on device: cold start of 'Friendly greeting #9' renders only
real content — no empty bubbles.
---------
Co-authored-by: M57 <hy4ri@users.noreply.github.com>