The pass condition was the same screen, from the same crate, running in a window with only the layout differing. desktop-app is a new workspace member: a session list (plain iris::widget::Span, rebuilt on selection) beside transcript_ui::build_tree's screen, talking to a real ai-server through client-core's ApiClient/UreqTransport/follow_session_events, with background network I/O on plain std::threads reporting back through winit's EventLoopProxy rather than iris's Tasks (which only redraws once per async closure, not once per SSE event). Both pass-condition proofs held against app/ui-sandbox.sh's real server: the list showed a spawned session, selecting it loaded its transcript, and a message sent from the composer streamed its reply back live. Along the way, a real bug: resuming the SSE stream from a folded item's seq (which for a still-open assistant message is its *first* delta's seq by design) replayed already-folded deltas and duplicated the tail of the reply -- found by a run-headless.sh screenshot, fixed by resuming from the raw wire seq instead, and covered by a regression test. Deliberately simple and said so in app.rs's module doc: every SSE event refolds the whole transcript and rebuilds the right-hand tree from scratch rather than reaching for TranscriptScreen::push_row's incremental append, since a streaming reply is a row whose text keeps changing after it appears and push_row can only add a new one. Fine at a desktop session's scale; the real fix needs transcript-ui to expose updating a row in place. Android is untouched by this step. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
28 lines
1.1 KiB
TOML
28 lines
1.1 KiB
TOML
[package]
|
|
name = "desktop-app"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
|
|
# RUST.md's E4: the same transcript-ui screen (I5) in a winit window on the
|
|
# desktop, beside a session list, talking to a real `ai-server` through
|
|
# `client-core`'s REST + SSE clients. Enrolment reuses the phone's own
|
|
# `aiapp://enroll?...` link (`client-core::config`) rather than inventing a
|
|
# second format -- see DECISIONS.md's 2026-09-05 entry. An ordinary
|
|
# workspace member (unlike `android-app`): nothing here needs the NDK, so
|
|
# `cargo build --workspace --all-targets` at the host stays clean with it
|
|
# included.
|
|
|
|
[dependencies]
|
|
iris = { path = ".." }
|
|
transcript-ui = { path = "../transcript-ui" }
|
|
client-core = { path = "../../client-core" }
|
|
event-model = { path = "../../event-model" }
|
|
# Already pulled in transitively through client-core; used directly here
|
|
# only to persist `EnrolledServer` as the app's own tiny config file (see
|
|
# `config.rs`) -- no new dependency.
|
|
serde_json = { version = "1", features = ["float_roundtrip"] }
|
|
winit = { workspace = true }
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3"
|