Provider tool output could enter timeline persistence and live streams without a size limit. Bound canonical shell output before coalescing, storage, history hydration, and dispatch so every provider follows the same 64 KiB budget.
Nested native stacks fell back to the navigation library's light background during cross-stack swaps. Share the active app surface color across every stack without subscribing route layouts to all theme runtime changes.
* feat(app): expose archive for every workspace
Workspace actions now archive one workspace by id. The daemon remains responsible for backing-specific cleanup, including removing a managed worktree only after its final workspace is archived.
* refactor(app): clarify archive descriptor name
* fix(app): preserve workspace archive safety
* fix(app): allow archive without upstream
* refactor(app): remove stale archive callback
* test(app): cover workspace archive ownership
* fix(server): stop reconnects reviving agents during shutdown
Shutdown previously took its agent snapshot while reconnects and in-flight registrations could still add or repersist agents. Gate ingress and registration first so closed agents cannot return during teardown.
* fix(server): drain late sessions during shutdown
* fix(app): preserve loader behavior in retained panels
Keep the running footer mounted across panel switches. Inactive loaders stop their animation work, then realign to the original wall-clock phase before they become visible.
* perf(app): remove inactive loader wrapper worklet
* perf(app): pause hidden turn elapsed timers
* perf(app): reduce loader animation work
Keep one wall-clock-aligned clock for visible loaders and detach retained
hidden loaders without unmounting them. Preserve the 950 ms sequence and
reduced-motion behavior.
Plain chat views started the history virtualizer even without virtualized rows. Its delayed scroll callback could outlive the mounted view and make the app test job fail during environment teardown.
* fix(app): stabilize streamed chat rendering
Use deterministic Markdown AST keys and preserve unique row identities when an assistant message resumes after a tool. Keep native gesture and plan-card children correctly keyed to avoid unsupported Fabric reconciliation paths.
* fix(app): stabilize retained native panels
Keep retained workspace roots in a stable native order and make active
panels present in the selection commit. Hidden panels now stop expensive
subscriptions and animations without losing mounted state.
* fix(app): harden retained panel activity
Project picker tests had depended on a placeholder changed for fuzzy search. Use a dedicated input test ID so product copy no longer breaks the selectors.
* fix(codex): keep parent turns active during sub-agent work
Codex multi-agent activity is thread-scoped. Treating child events as root
activity could end the foreground turn early and splice child output into
parent messages.
Route legacy and current activity shapes through stable child identities and
preserve message boundaries across live and resumed turns.
* fix(codex): preserve sub-agent details across stream chunks
Keep empty activity paths explicit and normalize the synthetic assistant
boundary for every chunk in the active message.
* fix(codex): route legacy child events by thread
* fix(codex): stabilize sub-agent activity lifecycles
* fix(codex): retain child tool activity and terminal state
* Hide keyboard shortcut badges in workspace menu on native
The archive item's shortcut badge (e.g. Ctrl+Shift+⌫) rendered in the
workspace kebab/context menu on mobile, where there's no physical
keyboard to invoke it. Gate the trailing badge behind !isNative in both
kebab menu variants.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(app): hide native shortcuts in every workspace menu
Workspace menus were duplicated across project and status views, so the status path missed the native gate. Centralize the menu so every sidebar view shares the same shortcut policy.
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* perf(app): keep large sidebars responsive
Sidebar rows rescanned every agent for each session update, multiplying work with both workspace and agent count. Build workspace activity once and share the derived sidebar model so updates scale with the underlying collections.
* test(app): use valid agent fixture for workspace restore
* refactor(app): keep sidebar model surface focused
* fix(app): keep mobile sidebars synced with store
Gesture-owned skip flags could swallow the next store sync after a no-op or overlapping gesture, leaving React state and Reanimated shared values split. Always reconcile both mobile sidebars from the panel store after gesture animations.
* test(app): keep sidebar sync coverage pure
* fix(app): keep sidebar close transitions idempotent
* fix(app): keep mobile sidebars stable through interruptions
Independent React and worklet state let stale gesture or animation callbacks
overwrite newer panel commands. Use one revisioned target and one transient
motion runtime so outdated callbacks cannot restore an earlier panel.
* fix(pi): avoid raw images for text-only models
Pi text-only models reject image content, and Pi persists the rejected raw image in session history. Materialize those image prompts to local files and send path hints while preserving raw images for vision-capable models.
* fix(pi): require explicit vision support
Default unknown Pi model capabilities to the text-hint path so raw image forwarding only happens for models that declare image input. Also keep materialized image files in a private per-user temp directory with restrictive file modes.
* fix(pi): harden materialized image temp dirs
* test(server): accept per-user image attachment dirs
* fix(server): use private temp dirs for materialized images
* fix(server): refresh missing image temp cache
* test(server): clean image temp dirs
* feat(app): restore compact Changes diff controls
Keep the folder tree behind a view toggle while preserving the flat file list as the default.
Move secondary diff options into the overflow menu so the Changes toolbar stays compact.
* fix(app): mirror whitespace diff option copy
* fix(app): polish diff controls review follow-up
Move canFetch guard before first await so disabled refresh bails out synchronously instead of entering async path. Add .catch() swallow for fire-and-forget call to prevent unhandled promise rejections when react-query cancels pending queries during rapid tooltip open/close cycles.
* fix(pi): add get_session_stats fallback from get_state for old OMP binaries
Older Oh My Pi binaries don't support the get_session_stats RPC command,
leaving session usage stats blank in Paseo. This adds a compat layer in
cli-runtime.ts where getSessionStats() tries get_session_stats first, then
falls back to extracting context window usage from get_state.
The fallback provides contextUsage.tokens and contextWindow even when the
binary lacks full token/cost reporting — enough to keep the context meter
working. Token counts and cost still require the newer RPC.
Added three tests:
- Fallback triggers when get_session_stats is unsupported (throws)
- No fallback when get_session_stats returns valid data
- Returns empty object when both commands fail
* fix(pi): use nullish check instead of truthy for cost field in getSessionStats
Group changed files in the Changes view into a collapsible directory
tree instead of a flat list, on every form factor — consistent with the
Files explorer, which already renders a directory tree on mobile.
Folders are collapsible and expanded by default, single-child directory
chains are compressed into one row (packages/app/src), and folder rows
show aggregate +/- stats.
Client-only, built entirely from the existing ParsedDiffFile paths:
- diff-tree.ts: pure build/compress/flatten of the directory hierarchy,
keyed by full uncompressed dir path so collapse state survives
compression changes as the diff mutates.
- diff-flat-items.ts: pure buildDiffFlatItems + sumHeightsBefore. The
function retains a flat mode (showTree=false) as a tested seam for a
possible future flat/tree toggle; sticky header indices are
file-headers-only, derived from the post-collapse list.
- panel-store: diffCollapsedFoldersByWorkspace slice (collapsed-set, so
folders default to expanded), persisted via version 12. The set is
reconciled against the current diff so folders that leave and reappear
default to expanded and the stored set stays bounded.
Presentation primitives (chevron, indent guides, indent constant) are
extracted into components/tree-primitives and shared with the Files
explorer, which drops its private copies (and a banned useUnistyles
call site). The two trees now render identical rows; only the
tree-building stays separate (server listings vs. diff paths).
The toolbar's expand-all stays file-diffs-only (renamed
allFileDiffsExpanded); a separate control collapses/expands all folders.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>