refactor: edition 2024, dep currency, audit-driven modernization, CI hardening#52
Merged
Conversation
Both major bumps compile with zero code changes (rusqlite's bundled SQLite moves to libsqlite3-sys 0.38; agf's toml surface — from_str, Table, Value variants — is stable across 0.8→1). Lockfile refreshed. rust-version starts at 1.88: the code already uses usize::is_multiple_of (1.87, caught by clippy::incompatible_msrv once an MSRV is declared) and the edition-2024 migration that follows adopts let-chains (1.88). Highest dependency MSRV is 1.85. sha2 stays 0.10: 0.11 breaks the gemini hash formatting (digest 0.11 output no longer implements LowerHex). superlighttui stays 0.20: 0.21 adds #[must_use] to separator_colored, wanting 29 call-site updates — deferred to its own change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mechanical migration, zero behavior change:
- cargo fix --edition: wraps the test-only HOME env mutations in
src/scanner/pi.rs in unsafe {} (env mutation is unsafe in 2024)
- cargo clippy --fix: collapses ~37 nested if-let staircases into
let-chains across the scanners and TUI (collapsible_if), now that
edition 2024 stabilizes them
- cargo fmt over the result
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ci.yml: - clippy runs --all-targets so tests are linted like the local gate; it subsumes cargo check, so the separate check job is dropped - Swatinem/rust-cache@v2 on compiling jobs (bundled SQLite C build was recompiled from scratch every run) - workflow concurrency cancels superseded runs on the same ref - windows job now lints (#[cfg(windows)] paths were never clippy'd) - --locked everywhere cargo resolves, so CI tests the committed lockfile release.yml: - verify job fails fast when the tag does not match Cargo.toml version - checksums step fails loudly when an artifact is missing instead of silently skipping it - publish job skips gracefully when CARGO_REGISTRY_TOKEN is unset instead of painting every release red (the secret is not configured) - --locked on release builds and publish Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- fix(gemini): char-boundary-safe 1 KB window in extract_summary_partial — a CJK char straddling byte 1024 panicked and silently erased every Gemini session; + regression test - fix(cursor): hex_decode rejects non-ASCII input before byte-slicing so a corrupt store.db yields None instead of killing the scanner thread; + regression test - perf(claude): pre-filter history.jsonl entries against existing_ids so orphaned sessions never accumulate SessionData/summary tuples (mirrors codex v0.11.4 pre-filter) - perf(claude/codex): drop per-line String alloc in history.jsonl hot loops (borrowed trim instead of to_owned) - perf(mod): cap read_first_line at 512 KiB via Read::take so a pathological newline-free .jsonl is no longer slurped whole; + tests - new shared helpers in scanner/mod.rs, each unit-tested: collapse_whitespace (claude/gemini x3/hermes), project_name_from_path (codex x2/kiro/opencode/pi/cursor), push_concat_titles (opencode/hermes, also drops alloc-per-duplicate) - idiom(codex): 15 match-Some/None/Ok/Err early-exit sites flattened to let-else; find_state_db collect+sort+next replaced with Iterator::max - idiom(cursor): 10 match-continue sites flattened to let-else; encoded_dir now stays a &str (one less alloc per session file) - hermes::message_preview reduced to collapse_whitespace + existing char_prefix - pi tests: replaced edition-migration TODO comments on unsafe env access with HOME_LOCK serialization notes - edition-2024 let-chain flattening verified already applied by migration commit 934bd3b (kiro/gemini pyramids correctly excluded — intermediate bindings make them non-chainable) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- render_chunks consumes its Vec, dropping a String clone per chunk per visible row per frame - update_filter moves match positions out of fuzzy results instead of cloning each Vec per keystroke - apply_sort borrows pinned_sessions and uses stable sort_by_key(!contains) instead of clone + 0/1 rank closure - detect_editor caches the config/env editor lookup in a process-wide OnceLock (was disk read + TOML parse per frame while the action menu is open) - delete confirm (single + bulk) only removes rows and decrements agent counts when delete_session returns Ok, so failed deletes stay visible - watch: clamp selected when a background refresh shrinks the session list (stale cursor blanked the viewport) - merge_agent_sessions: delete dead selected_id snapshot + discarded position scan (apply_sort already restores the cursor) - new_session_with_flags returns String (the Option was never None); both dispatchers unwrapped - dispatch_agent_option / dispatch_mode_option flattened to single let-chains - App::new: drop redundant installed_agents() clone - cycle_summary: let-else + entry API (one hash lookup instead of two), wrap-around semantics preserved - map(..).unwrap_or(..) chains -> is_some_and / is_ok_and / is_none_or / map_or at the audited tui/watch sites Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l tests - model.rs: derive serde::Serialize/Deserialize on Agent (unit variants keep the exact on-disk strings) - cache.rs: re-type CachedSession.agent as Agent and CacheFile.agents as HashMap<Agent, AgentCache>; delete agent_from_str/agent_to_str; from_cached now returns Session (no Option) - cache.rs: add round-trip test pinning the on-disk format (CacheFile round-trips, Agent serializes as "ClaudeCode") - cache.rs: delete clone_cached — write_cache carry-over moves entries out of the owned prior CacheFile via HashMap::remove - cache.rs: cache the AGF_DEBUG probe in a OnceLock-backed debug_enabled() helper (both cache.rs call sites) - main.rs: guard `agf resume --list 0 <query>` usize underflow/panic with take(n.max(1)) - main.rs: replace manual --version argv Vec collect with std::env::args().any(...) - delete.rs: convert four match-Ok/Err-continue ladders to let-else; .filter_map(|e| e.ok()) -> .flatten() at all 8 sites; map().unwrap_or(false) -> is_some_and at 2 sites - shell.rs: MSYSTEM empty-but-set no longer routes native Windows to Posix (is_some_and) - shell.rs: add default_shell_handles_uppercase_exe_and_empty_shell test (lowercase-before-trim order, empty SHELL = unset) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The only user of the Write trait is the unix-gated place_session test fixture; the ungated import was an unused-import error on the new Windows clippy CI job (which is exactly the platform gap that job exists to catch). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged
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.
Six commits, each independently gated (fmt / clippy --all-targets -D warnings / test):
rust-version = "1.88"declared (floor set by let-chains; the code already used 1.87 APIs). sha2 0.11 and superlighttui 0.21 evaluated and deferred (breaking; notes in commit message).cargo fix --edition(test-only unsafe env wraps in pi.rs) +cargo clippy --fixcollapsing ~37 if-let staircases into let-chains.--all-targets(tests were unlinted in CI), rust-cache, per-ref concurrency cancel, Windows clippy,--lockedeverywhere; release.yml gains a tag↔Cargo.toml version guard, loud checksum failures, and a graceful publish skip whenCARGO_REGISTRY_TOKENis unset (every release was ending red).collapse_whitespace/project_name_from_path/push_concat_titleshelpers replacing 5–6 duplicated sites each; gemini UTF-8 char-boundary panic fix (+CJK regression test); cursorhex_decodenon-ASCII guard; claude history orphan pre-filter (same optimization codex got in v0.11.4);read_first_line512 KiB budget; let-else flattening (25 sites).merge_agent_sessionsno-op deleted; watch clamps selection when a refresh shrinks the list.Agentderives serde (hand-rolled string maps deleted; on-disk cache format pinned byte-identical by a new round-trip test);agf resume --list 0underflow panic fixed; delete.rs let-else ladders; PR fix(shell): default to PowerShell on native Windows without the wrapper #49 follow-up shell tests (uppercase.EXE, emptySHELL) and theMSYSTEMempty-set nit.Provenance: findings come from a multi-agent audit (3 area auditors + per-finding adversarial verification; 32 confirmed, 2 rejected) plus an empirical deps/edition trial. Real-data invariant:
agf list --format jsonreturns the identical 585 sessions before and after.🤖 Generated with Claude Code