Add durable bookmarks across CLI and TUI#121
Open
tony wants to merge 25 commits into
Open
Conversation
adcf5e0 to
cb6377d
Compare
a68c683 to
5ffd718
Compare
5ffd718 to
4e49bbd
Compare
why: Canonical records need a bounded, privacy-minimal bookmark layer that survives CLI and later TUI sessions without mutating agent-owned stores. what: - Add strict versioned bookmark values and transactional XDG persistence. - Add idempotent add/remove/list CLI actions with deterministic output. - Cover validation, durability, permissions, atomicity, and safe errors.
why: Existing snapshots could retain permissive modes, direct callers could receive path-bearing filesystem errors, and custom stores changed caller-owned parent permissions. what: - Repair snapshot modes through the descriptor held under the stable lock. - Translate storage failures into generic path-free, unchained errors. - Preserve existing explicit parent modes while securing owned directories. - Cover each review finding with focused regression tests.
why: Canonical bookmarks need a keyboard-first HUD surface. Saved targets must resolve without freezing Textual or replacing active search state. what: - Add bookmark slash commands, focus-safe toggling, and a compact recall modal. - Offload bookmark loading, identity work, transactions, and target resolution. - Gate writes and callbacks while preserving results and marking saved records. - Cover modal behavior, races, privacy, pump bounds, and guards.
why: Recalled records can carry multi-megabyte bodies, and preparing their line-capped detail snapshot on the Textual pump freezes every interaction. what: - Defer large uncached body truncation to the existing detail worker. - Keep pending find state bounded while preserving generation and cache gates. - Cover single-line and multiline recall under the runtime watchdog.
why: Recall could snapshot entries before an accepted write became durable, while a concurrent toggle left an older resolver able to open a stale modal. what: - Reject recall while a bookmark transaction is pending. - Cancel and invalidate active resolution before launching a write. - Cover both mutation and resolution race interleavings.
why: First-hit resolver coverage and tiny modal fixtures could miss regressions at the fixed 200-entry boundary. what: - Mount and navigate a full-capacity filtered recall modal. - Exercise target-last and target-absent resolver scans under the watchdog. - Assert every candidate hashes off-pump without a heartbeat stall.
why: A find query opened while large-body preparation was pending searched a bounded prefix but retained those incomplete matches after the final body arrived. what: - Recompute live find state when worker-prepared detail becomes visible. - Cover a match beyond the pending prefix and retain existing pending behavior.
why: Final large-detail preparation re-entered the complete find pipeline on the Textual pump. Multi-megabyte sources could freeze input during matching, copying, highlighting, and scroll mapping. what: - Add an independent generation-gated detail-find worker for large sources. - Prepare capped matches, cached bases, overlays, and scroll targets off-pump. - Cover active final apply, stale generations, rapid steps, invalidation, and teardown.
why: Prefix-only find applies have no matches to wrap against. Replacing the requested target with that temporary current index loses steps before the final large source arrives. what: - Keep the unwrapped requested target across prepared find applies. - Cover two pending steps, final match selection, record restore, and explicit query reset.
why: A draining find worker carries scroll geometry for its captured detail width. Applying that result after a resize can move the current match outside the resized viewport. what: - Carry detail width through the prepared result and reject mismatches. - Restart active find after the debounced resize and self-correct layout drift without scanning on the pump. - Cover old-width rejection and the corrected scroll request.
why: A large-detail find could finish during the resize debounce and start a replacement before the post-layout callback started a second replacement. Stale callbacks could also survive an intervening query or record lifecycle. what: - Invalidate detail-find work immediately when resize begins. - Carry a generation token through the post-refresh restart callback. - Cover exact-one replacement and stale lifecycle callback races.
why: Durable bookmarks span CLI and HUD behavior and need one privacy-conscious contract for canonical targets, local state, and current-store recall. what: - Add the canonical scope, storage, and CLI guide with ADR 0016. - Document HUD toggles, filtering, resolution, and unresolved retention. - Add the release deliverable, indexes, and documentation contract tests.
why: Record additions require a content validator while removals do not. A re-add also depends on matching the saved validator, even at capacity. what: - Scope --content-id to record add and document remove syntax. - Explain matching re-adds and mismatched-validator exit behavior. - Pin the distinction in the bookmark documentation contract.
why: Long canonical IDs made the record-add example exceed the command width used by the documentation. what: - Put the content-ID flag and record target on continuation lines. - Keep the console block as one copyable shell command.
why: Bookmark titles and bodies may contain Textual markup-like text. Parsing that content could alter the preview or abort modal mounting. what: - Disable markup parsing for the bookmark preview widget. - Mount a malformed-markup title and assert it renders literally.
why: Following a sidecar-lock symlink could change and lock an unrelated file. Non-regular descriptors are also invalid lock transaction anchors. what: - Open the lock without following symlinks and verify its descriptor type. - Refuse unsafe locks before chmod or flock with path-free public errors. - Preserve a symlink target byte-for-byte and cover non-regular descriptors.
why: The bookmark TUI depended on the package facade in violation of the module boundary, while the public Task 1 dispatcher was not re-exported like its sibling command dispatchers. what: - Import bookmarks from its owning module in the HUD. - Re-export the bookmark dispatcher through the package facade. - Pin only BookmarkArgs and run_bookmark_command in the facade snapshot.
why: Inserting the bookmark parser among required ParserBundle fields broke callers that construct the longstanding four-parser bundle positionally or by keyword. what: - Append the bookmark parser as an optional compatibility field. - Keep internally-created bundles wired to the bookmark-specific parser. - Cover the original positional and keyword constructor forms.
why: A mutation may finish after the live detail record has been rebuilt as a distinct Python object with the same canonical identity. Object comparison left that equivalent record unstarred. what: - Match mutation refreshes against the cached canonical record ID. - Keep unrelated live selections untouched without hashing on the pump. - Mount equivalent and unrelated records around a mutation regression.
why: Cached detail selections invalidated an inactive find group twice, and a subsequent search reset repeated the no-op cancellation. what: - Cancel find preparation only while find state is active. - Let the live find refresh own final-body invalidation.
why: Offloading a multi-megabyte Rich body still lets GIL-bound highlighting and the final Static update stall the Textual pump. what: - Keep complete find sources and absolute match coordinates. - Render bounded initial and match-centered detail excerpts. - Preserve formatted JSON coordinates and legacy body helpers. - Cover watchdog, edge-match, and large-copy bounds.
why: Match-centered JSON excerpts include omission markers, so sniffing the slice as standalone JSON drops syntax token colors. what: - Carry the complete-source format through detail and find snapshots. - Detect legacy formats before slicing inside find preparation. - Assert large JSON excerpts retain token and match styles.
why: Wall-clock heartbeat gaps conflate a blocked Textual pump with host CPU descheduling, making off-pump bookmark tests flaky on shared runners. what: - Hold resolver and detail workers on GIL-releasing events. - Prove pump progress through a scheduled callback and live key handling. - Keep watchdog runtime and dedicated watchdog tests unchanged.
why: Positive pump probes replaced scheduler-sensitive warning checks, but the enabled app-shell watchdog wiring still needs deterministic coverage. what: - Spy watchdog startup while mounting the real explorer shell. - Observe a scheduled heartbeat callback on the pump thread. - Prove teardown stops the watchdog and interval timer.
why: The bookmark changelog test pinned the published a34 section, so it missed the issue 79 deliverable after the unreleased section advanced. what: - Discover the current unreleased version from its heading. - Verify the unreleased section and bookmark deliverable.
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.
Summary
Add durable, private bookmarks keyed by canonical content, stored-occurrence, or thread handles without copying prompt bodies or modifying source histories.
agentgrep bookmark add|remove|listwith idempotent human and JSON workflows, a versioned 200-entry snapshot, private XDG storage, atomic replacement, and symlink-safe locking.bbinding,/bookmark [record|content|thread], and a compact/bookmarksrecall list with resolved and unresolved entries.Relationship
This PR targets the branch for #111 because deterministic record identities are its prerequisite. It is independent of the export PR and can be retargeted to
masterafter #111 lands.Closes #79
Tested
ty, 2,769 passed, 3 skipped, 3 expected failures, and Sphinx.