Files
ai-app/client-core/Cargo.toml
T
irisandClaude Fable 5.1 977bdb9ee0 client-core: the app's own log ring, and POST /client-log to get it off a phone
Iris tests iris builds on a phone with no adb, and Android forbids one
app reading another's logcat, so a `log::info!` in the app can only reach
her if the app carries its own copy and sends it somewhere.

`client_core::log_ring` is that copy: a bounded ring (2000 lines / 256
KiB, whichever bites first) behind a `log::Log` backend that forwards to
whichever real logger the platform installed, so `logcat` and the desktop
terminal see exactly what they saw before. Reading does not consume --
the report and the uploader are two readers of one ring.

`client_core::log_upload` drains it into ai-server's new `POST
/client-log`, which re-emits each line into the server's own tracing
output. Dev Updater already shows that as ai-server's runtime log, so
nothing new is built there. A failed batch is retried from the same
cursor, and nothing in the upload path calls `log!` -- it would land in
the ring it is draining.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:56:20 -04:00

49 lines
2.4 KiB
TOML

[package]
name = "client-core"
version = "0.1.0"
edition = "2024"
# The app's pure logic, held once instead of twice: the event model (shared
# with `server/` via `event-model`), the REST + SSE clients for its HTTP
# surface (see `server/src/routes.rs`'s module doc for the table), the
# transcript fold and cache, the markdown block model, the syntax
# highlighter and the ANSI parser. See `docs/CLIENT_CORE.md` for
# what this holds today, what it does not yet, and how it corresponds to
# the Kotlin it replaces.
#
# No UI framework dependency of any kind -- this crate is meant to outlive
# whichever one the app ends up drawing with (see RUST.md).
[dependencies]
event-model = { path = "../event-model" }
serde = { version = "1", features = ["derive"] }
# "raw_value" is `fetch_transcript_lines`'s reason -- it needs the exact
# bytes the server sent, not this crate's own re-serialization of a parsed
# `Value`, so a cached line and a live SSE frame for the same event agree
# byte-for-byte (see that method's doc). "float_roundtrip" is why they
# agree on a `ts` at all -- see server/Cargo.toml's identical comment.
serde_json = { version = "1", features = ["float_roundtrip", "raw_value"] }
# The blocking HTTP client for the REST calls and the long-lived SSE GETs.
# `server/` already depends on ureq for its own outbound HTTPS (the usage
# poll in usage.rs) and it is rustls-backed like the rest of this project's
# TLS, so this reuses that choice rather than pulling in reqwest's async
# stack -- a client that runs one blocking request at a time, the way
# Api.kt's `HttpURLConnection` calls and Sse.kt's blocking read loop do, has
# no need of an async runtime, and RUST.md's brief for this port is
# "lightweight" throughout.
ureq = { version = "3", features = ["json"] }
# The markdown block split (`markdown_blocks`), which has to agree with the
# renderer in `iris/transcript-ui` about where a block begins -- so it is
# the same parser at the same version, rather than a hand-written splitter
# that would drift from it.
pulldown-cmark = "0.13.4"
# The logging facade only -- `log_ring` implements a `log::Log` backend and
# wraps whichever real one the platform installed (`android_logger` on the
# phone, `env_logger` on the desktop), which is why neither of those is a
# dependency here. See `log_ring`'s module doc.
log = { version = "0.4.28", features = ["std"] }
[dev-dependencies]
tempfile = "3"