fix: stop unbounded ~/.reflexio growth from stray per-session plugin copies (#65)#68
Conversation
…#65) A host (e.g. Claude Code/Codex on Windows + Git Bash) can expose the plugin from a cwd-derived copy physically under ~/.reflexio — e.g. C:\Users\Alice\repo mangled to ~/.reflexio/CUsersAliceRepo/plugin. Each entry script derives PLUGIN_ROOT from its own location and smart-install bootstraps .venv + dashboard there, so the full PyTorch/ChromaDB/ONNX/Next runtime gets duplicated into every such copy, eventually exhausting the disk. Detect stray copies structurally — any plugin root whose canonical path is a descendant of ~/.reflexio (the real install only ever places a plugin-root symlink there, which resolves outside ~/.reflexio) — and re-exec the same script from the stable cached root instead. This replaces the earlier case-sensitive `Cu*` prefix match, which missed the real `CUsers...` dirs (capital U) and any non-C: drive (D:\repos -> Drepos...). Also relax the re-exec precondition from -x to -f: we run via `exec bash <script>`, which needs no executable bit, and cached copies on Windows/NTFS often lack +x. Parametrize the regression test over realistic host-mangled names (CUsersAliceRepo, Dreposproj, cusersbobwork) to lock in casing- and drive-independent detection.
…eflexio copies (#65) Extends the stray-copy redirect to the two surfaces the prior commit missed: - dashboard-build.sh derives PLUGIN_ROOT from its own location and runs the dashboard npm build into $PLUGIN_ROOT/dashboard, so it would still write node_modules/.next into a stray ~/.reflexio/CUsers... copy. Add the same re-exec guard as the other entry scripts. - codex-hook.js resolves the plugin root in Node, bypassing the bash guard entirely. Port the structural detection (realpathSync canonicalization, path.relative containment, pyproject.toml + scripts markers) and have pluginRoot() return the stable cached root instead of the stray copy, so every downstream spawn/PATH use points at the canonical runtime. Add a codex-hook regression test using the realistic CUsersAliceRepo name.
…65) Defense-in-depth, separate from the disk-exhaustion root cause: the project id feeds Reflexio's user_id (a DB column, not a path), but under Git Bash the interpreter's Path is PosixPath, so Path("C:\\Users\\Alice\\repo").name returns the whole string instead of "repo" — splitting one project's preferences across two ids if git resolution fails. Add _basename() which routes native Windows paths (backslashes or a drive letter) through PureWindowsPath, and apply it to both the git-toplevel result and the cwd fallback. Also broaden the git failure except to OSError.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (11)
📝 WalkthroughWalkthroughThe PR adds stray plugin copy detection and stable root redirection to prevent unbounded disk growth in ChangesStray Plugin Copy Detection and Stable Root Redirection
Sequence DiagramsequenceDiagram
participant Script as Shell Script
participant Helpers as _lib.sh Helpers
participant Filesystem as Filesystem
participant StableRoot as Stable Plugin Root
Script->>Helpers: claude_smart_reexec_stable_plugin_root_if_needed(PLUGIN_ROOT)
Helpers->>Filesystem: Canonicalize PLUGIN_ROOT path
Helpers->>Filesystem: Check for pyproject.toml + scripts/
Helpers->>Filesystem: Verify descendant of ~/.reflexio
alt Root is Stray Copy
Helpers->>Filesystem: Search stable roots & version caches
Helpers->>Filesystem: Find first canonical non-stray root
Helpers->>StableRoot: Identified stable alternative
Helpers->>StableRoot: exec bash with stable PLUGIN_ROOT
StableRoot->>Script: Script re-executes with stable root
else Root is Already Stable
Helpers->>Script: Continue with current PLUGIN_ROOT
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Closes #65.
On Windows, the host (Claude Code / Codex) sometimes hands the plugin a
CLAUDE_PLUGIN_ROOTthat is a stray, cwd-derived copy of the plugin tree living inside~/.reflexio(e.g.~/.reflexio/CUsers...). When an entry script bootstraps a heavy.venv/node_modulesinto that location, every session accumulates a full PyTorch + ChromaDB + ONNX + Next/TypeScript runtime — ~1.5 GB each — which is never cleaned up and filled the reporter's 1.9 TB drive in roughly two weeks.This PR stops the growth at the source: detect a stray plugin root under
~/.reflexioand redirect execution to the stable, shared plugin root before any heavy install happens.Changes
Stray-copy detection & redirect (shell) —
plugin/scripts/_lib.shclaude_smart_is_reflexio_session_copy: structural detection — a plugin-like dir (haspyproject.toml+scripts/) whose canonical path is a descendant of canonical~/.reflexio. Structural (descendant + markers) rather than name-based, because the host mangles the cwd differently per drive/user/case (C:\Users→CUsers...,D:\repos→Drepos...), so a fixedCu*glob would miss most real copies.claude_smart_stable_plugin_root_for_session_copy: resolves the real shared root from known candidates (~/.reflexio/plugin-root, the Claude marketplace plugin, the Codexcurrentlink) and the Claude/Codex version caches, skipping any candidate that is itself a stray copy.claude_smart_reexec_stable_plugin_root_if_needed:exec bashs the same script from the stable root. Uses-f(not-x) since re-exec viabash <script>doesn't need the executable bit — cached copies on Windows/NTFS often lack it.Entry-script guards —
backend-service.sh,cli.sh,dashboard-build.sh,dashboard-service.sh,hook_entry.sh,smart-install.shCodex hook parity —
plugin/scripts/codex-hook.jsisReflexioStrayPluginCopy/stablePluginRootForStrayCopy/stablePluginRoot) and routes everypluginRoot()return path through the redirect.Windows project-id fix —
plugin/src/claude_smart/ids.py_basenamehandles native Windows paths under Git Bash (backslashes /C:drive prefix) viaPureWindowsPath, andresolve_project_idfalls back to the cwd basename onOSErrorso a bad path doesn't crash id resolution.Tests —
tests/test_install_scripts.py,tests/test_ids.pyTest Plan
pytest tests/test_install_scripts.py tests/test_ids.pybash -non every modified shell scriptCu*), confirming the structural guard fires where a glob would miss.Summary by CodeRabbit
Release Notes
Bug Fixes
Tests