feat: expose a library surface and JSON snapshot API for headless con…#133
Conversation
…sumers abtop is binary-only today. This makes it a lib+bin crate so local tools can reuse abtop's data-collection layer in-process — without reimplementing session discovery, shelling out, or depending on the terminal frontend. What changed: - Split the entry point: src/main.rs becomes a thin shim that calls abtop::run(); all logic moves to src/lib.rs (a pure relocation). - New App::tick_no_summaries(): refresh monitored data WITHOUT spawning `claude --print`, so headless consumers never touch the user's Claude quota. tick() is now tick_no_summaries() + drain_and_retry_summaries() — unchanged behavior for the TUI. - New src/snapshot.rs: App::to_snapshot(interval_ms) returns a JSON-friendly Snapshot DTO (SessionView / McpServerView / ...). Pure read — never ticks or spawns. - #[derive(Serialize)] on the model/host DTO types it serializes. - New `abtop --json` flag: print one snapshot and exit. Notes: - The TUI, all existing flags, and output are unchanged. - No new dependencies — serde and serde_json are already in the tree. - snapshot.rs ships unit tests; all 164 tests + 1 doctest pass. - Enum wire formats (SessionStatus as "Thinking"/..., chat roles as "user"/"assistant") are documented as stable. Reference consumer: https://github.com/XKHoshizora/abtop-web-ui — a local-first web dashboard built entirely on this API. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
graykode
left a comment
There was a problem hiding this comment.
security looks clean — no new dependencies or workflow changes, and the existing update shell/network path is only moved into the lib entrypoint.
Two things need fixing before this lands:
cargo clippy -- -D warningsfails now thatcollectoris public fromsrc/lib.rs;CodexCollector::new()andOpenCodeCollector::new()triggerclippy::new_without_default(--all-targetsalso catchesClaudeCollector). Either keep the collector module internal or add/allow the required defaults.- the new JSON snapshot exposes prompt-derived
summary,chat_messages, full child commands, cwd/config roots, etc., but README privacy still says prompt text is never displayed. Please either remove/gate those fields from--json, or document the JSON privacy surface explicitly so scripts do not accidentally log transcript content.
I verified cargo test passes locally, and cargo run -- --demo --json produces valid JSON.
graykode
left a comment
There was a problem hiding this comment.
security still looks clean. pushed a fix for the public collector clippy failures and documented the JSON snapshot privacy surface, with a regression test for the README wording. cargo build, cargo clippy --all-targets -- -D warnings, cargo test, and the demo JSON smoke check all pass locally.
|
Thank you for the fast review — and for fixing both points directly! For context: Now that this has landed, I wish switch it to depend on upstream Thanks again for abtop! |
The library API (App::to_snapshot, Snapshot, tick_no_summaries) was merged upstream in graykode/abtop#133 and released in v0.4.8, so depend on it directly via a git tag rather than the XKHoshizora/abtop fork. - Cargo.toml: abtop -> { git = graykode/abtop, tag = v0.4.8 } - release.yml: drop the fork sibling-checkout step (cargo fetches the git dep) - README (EN + zh): build-from-source no longer needs a ../abtop sibling clone Verified: cargo build pulls abtop v0.4.8 from git and links cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Make
abtopa lib + bin crate so local tools can reuse its data-collectionlayer in-process — no re-scanning, no subprocesses, no terminal dependency — and
serialize the same state the TUI shows.
Why
I built abtop-web-ui, a local-first
web dashboard for abtop sessions. It currently depends on a fork because abtop is
binary-only. This PR upstreams the minimal library surface it needs, so it (and
other tools) can depend on
abtopdirectly.Changes
src/main.rsbecomes a thin shim callingabtop::run(); thelogic moves to
src/lib.rs(a pure relocation).App::tick_no_summaries(): refresh data without spawningclaude --print,so headless consumers never spend the user's Claude quota.
tick()is nowtick_no_summaries()+drain_and_retry_summaries()— unchanged for the TUI.src/snapshot.rs:App::to_snapshot(interval_ms)returns a JSON-friendlySnapshotDTO. Pure read; never ticks or spawns.#[derive(Serialize)]on the model/host DTO types it serializes.abtop --json: print one snapshot and exit.snapshot unit tests.
Safety / compatibility
serde/serde_jsonare already in the tree.cargo test: 164 passing (158 existing + 6 new) + 1 doctest.SessionStatus→"Thinking"…,chat roles →
"user"/"assistant").Happy to split this (e.g. drop
--json, or land the bin→lib split separately),gate serialization behind a Cargo feature, or adjust naming — whatever fits your
preferences. Thanks for abtop! 🙏