feat(cli): presentation and experience polish across every human-facing surface#315
Merged
Conversation
… visible - metadata columns now take their widest value (capped: device 18, agent 12, project 32) - narrow terminals shrink device before project, following the contract compression order - overflowing project labels drop the owner segment first, then truncate from the left - prompts absorb the remaining row width up to 96 columns (was a flat 60-rune cap) - cardinality-1 suppression now surfaces the uniform project/device in the context line - scope labels normalize git remotes to owner/repo and abbreviate $HOME paths to ~ - device labels trim FQDN hostnames to their first dot segment, like hostname -s Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Long snippets used to lose their FTS match markers whenever the text exceeded the row width, so most hits rendered without any highlight. Truncation now walks the marked runes, shifts the window so the first match stays visible with a third of leading context, and re-emits the marker pairs around whatever survives the cut. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- new render.Table primitive aligns by display width, so styled cells no longer shift columns (tabwriter counted ANSI escapes as text and misaligned the profiles and devices headers) - numeric columns are right-aligned and thousands-separated in TTY - PROJECT collapses git remotes to owner/repo and $HOME paths to ~ - STARTED and LAST SYNC render as local wall-clock time in TTY - estimated cost reads as dollars: $2,192.29 instead of $2192.2861 - plain mode keeps raw tab-separated values for scripts Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A dead server address used to hang sync for hours: the HTTP client had no timeouts, and the push circuit breaker only recognized the explicit Unavailable code, so every imported session paid a full kernel TCP retry cycle. Observed live as a sync stuck for 12h on a Tailscale IP. - transport now bounds connection phases (5s dial, 5s TLS handshake, 60s response header); body transfer stays unbounded so large raw pushes on slow links are never cut off mid-stream - isRemoteUnavailable also trips on net errors and DeadlineExceeded, so the first failed connection short-circuits the remaining pushes - summary rows for Denoise/Remote/Warnings use the same padded muted label as the count rows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The show header printed the raw device fingerprint hex; it now resolves the friendly name from the local store. A tokens row joins the metadata block when the session has measured usage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- root help lists commands under Getting started / Explore your history / Import & sync / Remote server groups, with a short Long description of what bare prosa does - window parse errors read as one sentence instead of repeating the wrapped Go error - the empty-search hint drops the --all suggestion when --all is already set Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- contract: content-sized timeline columns, uniform-value context-line segments, normalized scope labels, snippet truncation that keeps the highlight, analytics humanizations, command tables section, sync fail-fast note, conditional empty-search hint - screens/README/usage: scope label examples show owner/repo form - screens: narrow-terminal example matches the in-place column shrink - architecture/cli: render package list gains table.go Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
%q escaped embedded quotes and backslashes, adding visual noise and pushing rows past the width the truncation had just computed. Prompts and search session lines now render inside literal quotes; display text is sanitized to printable runes so nothing needs escaping. Also from review: the $HOME abbreviation is one shared helper (render.AbbreviateHome), and isRemoteUnavailable drops a dead *net.OpError check already covered by the net.Error match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CLI presentation and experience pass: every human-facing surface was run in a real pseudo-TTY against the live local store, defects were fixed, and the loop repeated until the output read cleanly at 60, 80, 100, and 140 columns. Plain (pipe) and
--jsonshapes are untouched except where noted.What changed
Timeline
mz-codes/mz…on every row becomesmz-codes/mz-operator-1.prosa · local · all projects · last 1d · project mz-codes/mz-operator-1 · device tbox).scoped to git@github.com:c3-oss/prosa.git→scoped to c3-oss/prosa; paths under$HOMErender as~/….ip-192-168-0-16.ec2.internal→ip-192-168-0-16).Search
«»pairs around whatever survives the cut.--allsuggestion when--allis already set.Analytics + tables
PROJECTcollapses remotes toowner/repoand$HOMEpaths to~;STARTEDrenders as local wall-clock; cost reads$2,192.29instead of$2192.2861. Plain mode keeps raw values for scripts.render.Tableprimitive aligns by display width. This fixes a real bug:profiles listanddevices listusedtext/tabwriter, which counts ANSI escapes as text — styled headers misaligned every column.Show
tokensrow joins the metadata block when usage was measured.Sync (found live during the run)
prosa syncagainst an unreachable server had been running for 12+ hours: the HTTP client had no timeouts and the push circuit breaker only recognizedCodeUnavailable, so every imported session paid a full kernel TCP retry cycle. The transport now bounds connection phases (5s dial / 5s TLS / 60s response header — body transfer stays unbounded for large pushes), andisRemoteUnavailablealso trips on net errors andDeadlineExceeded. Re-run after the fix: full import of a 5.6k-session backlog completed in ~2 minutes with the documentedRemote: server unavailable …summary line.Help + errors
prosadoes.--last bogusreads as one sentence instead of repeating the wrapped Go error.Docs
docs/cli/rendering-contract.mdupdated for all of the above;screens.md,cli/README.md,usage.mdscope-label examples now match the normalized form;architecture/cli.mdlists the newtable.go.Validation
go test ./...andgo test -race ./internal/cli/...green; new unit tests for column sizing, label fitting, uniform-value context segments, marked-snippet truncation, table alignment, cost/timestamp/project display, and the unreachable-server classifier.golangci-lint run ./internal/cli/...— 0 issues;gofumptclean on touched files;just lint-mdclean.prosa-cli-ux-reviewerandprosa-docs-revieweragents ran over the diff; docs drift they flagged is fixed in the docs commit.🤖 Generated with Claude Code