Skip to content

fix: stop unbounded ~/.reflexio growth from stray per-session plugin copies (#65)#68

Merged
yyiilluu merged 3 commits into
mainfrom
fix/issue-65-stray-plugin-copy-detection
Jun 7, 2026
Merged

fix: stop unbounded ~/.reflexio growth from stray per-session plugin copies (#65)#68
yyiilluu merged 3 commits into
mainfrom
fix/issue-65-stray-plugin-copy-detection

Conversation

@yyiilluu

@yyiilluu yyiilluu commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #65.

On Windows, the host (Claude Code / Codex) sometimes hands the plugin a CLAUDE_PLUGIN_ROOT that 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_modules into 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 ~/.reflexio and redirect execution to the stable, shared plugin root before any heavy install happens.

Changes

Stray-copy detection & redirect (shell)plugin/scripts/_lib.sh

  • claude_smart_is_reflexio_session_copy: structural detection — a plugin-like dir (has pyproject.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:\UsersCUsers..., D:\reposDrepos...), so a fixed Cu* 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 Codex current link) 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 via bash <script> doesn't need the executable bit — cached copies on Windows/NTFS often lack it.

Entry-script guardsbackend-service.sh, cli.sh, dashboard-build.sh, dashboard-service.sh, hook_entry.sh, smart-install.sh

  • Each entry point calls the re-exec guard so a stray root is redirected before bootstrapping a runtime.

Codex hook parityplugin/scripts/codex-hook.js

  • Mirrors the shell logic (isReflexioStrayPluginCopy / stablePluginRootForStrayCopy / stablePluginRoot) and routes every pluginRoot() return path through the redirect.

Windows project-id fixplugin/src/claude_smart/ids.py

  • _basename handles native Windows paths under Git Bash (backslashes / C: drive prefix) via PureWindowsPath, and resolve_project_id falls back to the cwd basename on OSError so a bad path doesn't crash id resolution.

Teststests/test_install_scripts.py, tests/test_ids.py

  • Cover stray-copy detection, redirect-to-stable-root behavior, and Windows path basename derivation.

Test Plan

  • pytest tests/test_install_scripts.py tests/test_ids.py
  • bash -n on every modified shell script
  • Parameterized cases use realistic stray names across drive letters and mixed case (not just Cu*), confirming the structural guard fires where a glob would miss.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Plugin system now intelligently detects temporary plugin copies and automatically redirects execution to stable cached versions, preventing redundant dependency bootstrapping.
    • Improved Windows path handling for consistent project identification across platforms.
  • Tests

    • Added regression tests validating stray plugin detection and stable plugin root resolution.

Yi Lu added 3 commits June 7, 2026 01:01
…#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.
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 988554b6-85cf-4d18-b5fa-16dfbf494630

📥 Commits

Reviewing files that changed from the base of the PR and between 94c1652 and 483191d.

📒 Files selected for processing (11)
  • plugin/scripts/_lib.sh
  • plugin/scripts/backend-service.sh
  • plugin/scripts/cli.sh
  • plugin/scripts/codex-hook.js
  • plugin/scripts/dashboard-build.sh
  • plugin/scripts/dashboard-service.sh
  • plugin/scripts/hook_entry.sh
  • plugin/scripts/smart-install.sh
  • plugin/src/claude_smart/ids.py
  • tests/test_ids.py
  • tests/test_install_scripts.py

📝 Walkthrough

Walkthrough

The PR adds stray plugin copy detection and stable root redirection to prevent unbounded disk growth in ~/.reflexio by reusing existing stable plugin installations instead of bootstrapping dependencies repeatedly per session.

Changes

Stray Plugin Copy Detection and Stable Root Redirection

Layer / File(s) Summary
Stable root detection helpers
plugin/scripts/_lib.sh
Introduced four helpers: claude_smart_canonical_dir resolves physical paths, claude_smart_is_reflexio_session_copy detects stray copies via plugin markers and ~/.reflexio containment checks, claude_smart_stable_plugin_root_for_session_copy finds stable alternates from cache globs and known locations, and claude_smart_reexec_stable_plugin_root_if_needed re-executes scripts from stable roots when necessary.
Shell script bootstrap integration
plugin/scripts/cli.sh, backend-service.sh, dashboard-build.sh, dashboard-service.sh, hook_entry.sh, smart-install.sh
Integrated stray copy detection into six entry points by calling claude_smart_reexec_stable_plugin_root_if_needed immediately after PLUGIN_ROOT computation, enabling early redirection before main logic runs.
Node.js codex hook stable root resolution
plugin/scripts/codex-hook.js
Implemented JavaScript equivalents for stray copy detection and stable root lookup, including real-path comparisons, plugin structure validation, and modification-time-sorted cache scanning. Updated pluginRoot() to apply stable-root resolution to all discovered root candidates.
Cross-platform path basename handling
plugin/src/claude_smart/ids.py
Added _basename() helper with Windows-native path support via PureWindowsPath to handle both normal and Git Bash-style paths correctly. Updated resolve_project_id() to use this helper and improved exception handling to return the basename of the base directory when git fails.
Regression test validation
tests/test_install_scripts.py, tests/test_ids.py
Added regression test for smart-install.sh verifying installation into stable roots instead of stray ~/.reflexio copies, Node.js codex hook test confirming redirection with logging, and Windows-specific path handling tests for basename extraction.

Sequence Diagram

sequenceDiagram
  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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ReflexioAI/claude-smart#26: Both PRs modify codex hook plugin-root resolution logic in plugin/scripts/codex-hook.js; this PR adds canonical stable-root routing while the related PR introduced/updated the Codex hook wrapper itself.
  • ReflexioAI/claude-smart#32: Both PRs modify plugin/scripts/smart-install.sh startup; this PR adds stable-root re-exec guarding while the related PR adds lock/fingerprint/idempotency hardening.

Poem

🐰 Session copies spawn like rabbits fast,
Each one a copy, never to last—
But now we peek for stable ground,
And redirect before terabytes are found!
One root to rule them, one to share,
No more disks gasping for air. 🐇

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-65-stray-plugin-copy-detection

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yyiilluu yyiilluu merged commit 7b225fa into main Jun 7, 2026
6 of 7 checks passed
@yilu331 yilu331 deleted the fix/issue-65-stray-plugin-copy-detection branch June 12, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Critical: per-session runtime copies in ~/.reflexio grow unbounded — 1 TB / 47.7M files, nearly filled a 1.9 TB drive

1 participant