Wrapped Viral-Loop. The honest Wrapped recap is now shareable end-to-end: a
first-run "aha", one-click sharing, an opt-in hosted permalink, and an opt-in
public leaderboard — privacy-safe and anonymous-first.
Added
- First-run "aha" (
lean-ctx discover): the first run surfaces a concrete, projected token saving for the current project (one-time marker in~/.lean-ctx), withdiscover --cardexporting a shareable "Ghost Tokens" SVG. Non-UTF-8 shell histories (zsh metafied format) are now read lossily so the projection never silently sees empty history. - One-click share (
gain --copy/--open): copy a ready-to-post share line to the clipboard or open the generated SVG/HTML card in the browser — cross-platform (pbcopy/clip/wl-copy/xclip/xsel,open/start/xdg-open). - Hosted Wrapped permalink (
gain --publish/--unpublish): anonymously publish a whitelisted, privacy-safe slice of the recap and get a shareableleanctx.com/w/<id>URL (copied to clipboard). Whitelist-only (deny_unknown_fields), one-timeedit_tokenstored locally for later removal, optional account claim. Server-rendered page carries per-card Open Graph / Twitter meta;og:imageis aresvg-rasterized 1200×630 PNG. Contract:docs/contracts/wrapped-permalink-v1.md. - Opt-in public leaderboard (
gain --publish --leaderboard): off by default; when set, the card is listed onleanctx.com/leaderboard(server-rendered, top 50 by realized tokens saved). Only the user-chosen display name is person-facing; everything else is an aggregate. JSON at/api/leaderboard. - Per-day version in
lean-ctx gain(#307): each row in "Recent Days" and thegain --dailytable now shows the lean-ctx version active that day, so a compression change can be attributed to a release. Days recorded before this field stay blank (—). The version is stamped on each day's stats and carried through the cross-process stats merge.
Fixed
2>&1(and>&,&>,N>&M) misread as a command (#334): the shell-allowlist parser split a single&as a background separator even inside a redirect, sopnpm run compile 2>&1was parsed aspnpm run compile 2>and a bogus command1, which was then blocked. A&adjacent to>is now correctly treated as part of the redirect, not a separator; genuine background&still splits. Fixes false'1' is not in the shell allowlistblocks in MCP mode (Cursor/opencode/etc.).- Auto-update ignored
config.toml(#335): a scheduler installed earlier kept runninglean-ctx updateeven after the user setupdates.auto_update = false, because theupdatecommand never re-checked config. Scheduled runs (--quiet/--scheduled) now obey config:auto_update = falseskips the update and removes the orphaned scheduler (self-heal), andnotify_only = truedowngrades to a check (never installs). Manuallean-ctx updateis an explicit action and always proceeds. - macOS bash login shells missed the hook and PATH (user report): bash login shells (Terminal.app, IDE terminals,
bash -l) read~/.bash_profile/~/.profile, never~/.bashrc— yet the hook (and the installer's~/.local/binPATH export) land in~/.bashrc.lean-ctx setupnow ensures the login profile sources~/.bashrc(idempotent, Debian/Ubuntu-style), so the hook and PATH take effect in login shells.install.shprints the matching one-liner; uninstall removes the snippet. zsh is unaffected (it always reads~/.zshrc). - Event feed flooded with false "denied" policy violations: auto-preload candidates from the project graph are repo-relative (e.g.
rust/src/core/foo.rs); the path jail resolved them against the daemon's CWD (not the project root), so every candidate failed with "no existing ancestor" and was logged as a policy violation. Relative candidates now resolve against the jail root, and a genuinely missing file is no longer mislabeled as a security denial. As defense-in-depth,ctx_preloadnow resolves its jail root from the dispatch-provided project root when no explicitpathand no session root are available, so it never silently jails against the daemon CWD in any IDE. ctx_searchand the background index build could hang on special files (FIFOs, sockets, devices) (#336): a regular-file guard now skips non-regular paths before any blocking read —read_to_stringon a named pipe blocks forever waiting for a writer, which surfaced as random, unlogged hangs.ctx_searchadditionally enforces a wall-clock deadline (LEAN_CTX_SEARCH_DEADLINE_MS, default 10s) and returns partial results with a note instead of hanging. Reproduced with a real FIFO and covered by regression tests (search_skips_named_pipe_without_hanging,build_skips_named_pipe_without_hanging).- No compression in the Codex Desktop / Cloud app (#337): lean-ctx's transparent shell/file compression for Codex is hook-driven (the
codex-pretoolusehook reroutes commands throughlean-ctx -c), but the Codex Desktop and Cloud app run in app-server mode where lifecycle hooks do not fire (OpenAI codex#13019) — so identical commands compressed in the Codex CLI but not in the app. The Codex instructions (~/.codex/AGENTS.md+LEAN-CTX.md) now state this explicitly and direct the agent to proactively route work through the MCP tools (ctx_shell/ctx_read/ctx_search) orlean-ctx -cin the Desktop/Cloud app, which is the channel that is available there.lean-ctx doctoradds a Codex note so a healthy config no longer looks like a silent failure. (Hooks remain the automatic path in the Codex CLI once trusted via/hooks.)
Upgrade
lean-ctx update # recommended (auto-downloads + refreshes shell hooks)
cargo install lean-ctx # or
npm update -g lean-ctx-bin # or
brew upgrade lean-ctxNote: After upgrading via cargo/npm/brew, run
lean-ctx setupto refresh shell aliases.lean-ctx updatedoes this automatically.
Full Changelog: v3.7.1...v3.7.1