diff --git a/DEVELOPER.md b/DEVELOPER.md index ad76aca..a222e46 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -30,6 +30,7 @@ Tunables read by the plugin at runtime. Most users don't need to touch these — | `REFLEXIO_EMBEDDING_PROVIDER` | `local_service` when local embedding is enabled | Embedding provider mode: `cloud`, `local_service`, `internal_service`, `inprocess`, or `off`. | | `REFLEXIO_EMBEDDING_SERVICE_URL` | `http://127.0.0.1:$EMBEDDING_PORT` | OpenAI-compatible embedding endpoint used by `local_service` and `internal_service`. | | `EMBEDDING_PORT` | `8072` | Local embedding daemon port. Shared by Claude Code and Codex on the same machine. | +| `REFLEXIO_RERANK_DEVICE` | `cpu` | Torch device for the in-process cross-encoder reranker used by search. Defaults to CPU: auto-selected MPS on Apple Silicon accumulates gigabytes of GPU memory in the backend process for no latency win at this model size. Set to `cuda` only for GPU deployments. | | `CLAUDE_SMART_ENABLE_OPTIMIZER` | enabled unless set to `0` | Hook-side env var that controls shared skill optimization and rollups during `SessionStart`. Set it in Claude Code settings, not `~/.reflexio/.env`. | | `CLAUDE_SMART_CITATIONS` | `on` | Controls the final `✨ claude-smart rule applied` marker instruction. `on` (default) injects a compact instruction asking the assistant to cite only memories that materially changed the answer. `off` skips injection of the citation instruction entirely and strips any stray marker line from the assistant text before publishing. Legacy values `auto` and `marker-only` are accepted as enabled aliases. Set in Claude Code settings (hook env), not `~/.reflexio/.env`. | | `CLAUDE_SMART_CITATION_LINK_STYLE` | `markdown` | Controls the visible links in the final `✨ claude-smart rule applied` marker. `markdown` asks the model to emit `[human title](dashboard URL)` links and is the Codex default because Codex renders markdown links in assistant messages. `osc8` asks it to emit terminal-native OSC 8 hyperlinks so the human title can be clickable without showing the URL; unsupported terminals should fall back to markdown links. | diff --git a/bin/claude-smart.js b/bin/claude-smart.js index 160b1df..3e8ba62 100755 --- a/bin/claude-smart.js +++ b/bin/claude-smart.js @@ -905,7 +905,7 @@ async function installVendoredReflexio(pluginRoot, uv, env) { process.stdout.write(`Installing bundled Reflexio source from ${vendorRoot}...\n`); let code = await runChecked( uv, - ["pip", "install", "--project", pluginRoot, "--python", pythonPath, "--quiet", "-e", vendorRoot], + ["pip", "install", "--project", pluginRoot, "--python", pythonPath, "--quiet", "--reinstall", "--no-deps", vendorRoot], { cwd: pluginRoot, env }, ); if (code !== 0) { @@ -914,7 +914,7 @@ async function installVendoredReflexio(pluginRoot, uv, env) { ); code = await runChecked( uv, - ["pip", "install", "--project", pluginRoot, "--python", pythonPath, "-e", vendorRoot], + ["pip", "install", "--project", pluginRoot, "--python", pythonPath, "--reinstall", "--no-deps", vendorRoot], { cwd: pluginRoot, env }, ); } diff --git a/plugin/pyproject.toml b/plugin/pyproject.toml index 0265d6d..41253dd 100644 --- a/plugin/pyproject.toml +++ b/plugin/pyproject.toml @@ -9,7 +9,7 @@ dependencies = [ # normal installs; vendor releases may override it after uv sync by # installing plugin/vendor/reflexio. Keep in sync via # scripts/sync-reflexio-dep.py. - "reflexio-ai>=0.2.23", + "reflexio-ai>=0.2.25", # Needed when Reflexio runs the local embedding provider (ONNXMiniLM_L6_V2). # Pulls in onnxruntime + tokenizers; the ~80 MB ONNX model itself is # downloaded on first use, not at install time. diff --git a/plugin/scripts/backend-service.sh b/plugin/scripts/backend-service.sh index df4a344..2cfa6ec 100755 --- a/plugin/scripts/backend-service.sh +++ b/plugin/scripts/backend-service.sh @@ -5,8 +5,8 @@ # # Subcommands: # start probe /health; if nothing we recognize is on the port, -# spawn `uv run reflexio services start --only backend -# --no-reload` detached. Polls /health briefly so first +# spawn the prepared venv's `reflexio services start --only +# backend --no-reload` detached. Polls /health briefly so first # use after session start lands on a warm server, then # returns a continue payload regardless. # stop SIGTERM the recorded process group, escalating to @@ -183,6 +183,35 @@ port_holder() { | awk 'NR==2 {print $1" (pid "$2")"; exit}' } +ensure_vendored_reflexio_active() { + vendor="$PLUGIN_ROOT/vendor/reflexio" + [ -f "$vendor/pyproject.toml" ] || return 0 + plugin_python="$(claude_smart_plugin_python "$PLUGIN_ROOT")" + [ -x "$plugin_python" ] || return 0 + if "$plugin_python" - "$vendor/pyproject.toml" <<'PY' >/dev/null 2>&1; then +import importlib.metadata +import re +import sys +from pathlib import Path + +text = Path(sys.argv[1]).read_text(encoding="utf-8") +match = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE) +if not match: + raise SystemExit(1) +expected = match.group(1) +try: + installed = importlib.metadata.version("reflexio-ai") +except importlib.metadata.PackageNotFoundError: + raise SystemExit(1) +raise SystemExit(0 if installed == expected else 1) +PY + return 0 + fi + claude_smart_append_capped_log "$LOG_FILE" "$LOG_MAX_BYTES" \ + "[claude-smart] backend: repairing vendored Reflexio install before start" + uv pip install --project "$PLUGIN_ROOT" --python "$plugin_python" --quiet --reinstall --no-deps "$vendor" >&2 +} + # Full shutdown: kill the recorded process group (if any) then sweep # both the backend port and the embedding-service port for surviving # reflexio listeners. Used by both `stop` and the opt-in `session-end` @@ -243,6 +272,7 @@ case "$CMD" in fi fi cd "$PLUGIN_ROOT" + ensure_vendored_reflexio_active # Cap local interaction history to keep the SQLite store small for # claude-smart users. Reflexio's library defaults are much higher @@ -266,6 +296,21 @@ case "$CMD" in # without touching the file on disk. export REFLEXIO_STORAGE="sqlite" + backend_pythonpath="${PYTHONPATH:-}" + if [ -d "$PLUGIN_ROOT/vendor/reflexio/reflexio" ]; then + vendor_pythonpath="$PLUGIN_ROOT/vendor/reflexio" + pythonpath_sep=":" + if claude_smart_is_windows; then + # Native Windows Python expects ;-separated Windows-style paths in + # PYTHONPATH; MSYS does not auto-convert arbitrary env vars. + pythonpath_sep=";" + if command -v cygpath >/dev/null 2>&1; then + vendor_pythonpath="$(cygpath -w "$vendor_pythonpath")" + fi + fi + backend_pythonpath="$vendor_pythonpath${backend_pythonpath:+$pythonpath_sep$backend_pythonpath}" + fi + # (nohup; no process groups). backend-log-runner.sh owns stdout/stderr # capture so process output cannot grow backend.log past its cap. # @@ -277,11 +322,12 @@ case "$CMD" in # CLAUDE_SMART_BACKEND_WORKERS for power users running concurrent # Claude Code sessions or wanting zero-downtime recycling. workers="${CLAUDE_SMART_BACKEND_WORKERS:-1}" + backend_python="$(claude_smart_plugin_python "$PLUGIN_ROOT")" claude_smart_spawn_detached bash "$HERE/backend-log-runner.sh" \ "$LOG_FILE" "$LOG_MAX_BYTES" -- \ env PYTHONIOENCODING="${PYTHONIOENCODING:-utf-8}" \ - uv run --project "$PLUGIN_ROOT" --no-sync --quiet \ - reflexio services start --only backend --no-reload --workers "$workers" + PYTHONPATH="$backend_pythonpath" \ + "$backend_python" -m reflexio.cli services start --only backend --no-reload --workers "$workers" svc_pid=$! # Record the spawned pid, not a pgid sampled with ps. On POSIX, # setsid/python os.setsid make this pid the new process group leader; diff --git a/plugin/scripts/cli.sh b/plugin/scripts/cli.sh index 42d691f..f6f5032 100755 --- a/plugin/scripts/cli.sh +++ b/plugin/scripts/cli.sh @@ -91,4 +91,5 @@ if ! claude_smart_python_imports "$PLUGIN_ROOT" claude_smart.cli; then fi fi -exec uv run --project "$PLUGIN_ROOT" --no-sync --quiet python -m claude_smart.cli "$@" +PLUGIN_PYTHON="$(claude_smart_plugin_python "$PLUGIN_ROOT")" +exec "$PLUGIN_PYTHON" -m claude_smart.cli "$@" diff --git a/plugin/scripts/ensure-plugin-root.sh b/plugin/scripts/ensure-plugin-root.sh index 0872f4c..936f6b8 100755 --- a/plugin/scripts/ensure-plugin-root.sh +++ b/plugin/scripts/ensure-plugin-root.sh @@ -20,6 +20,7 @@ if [ ! -f "$TARGET/pyproject.toml" ]; then echo "[claude-smart] ensure-plugin-root: $TARGET is not a plugin dir (no pyproject.toml)" >&2 exit 1 fi +TARGET="$(cd "$TARGET" && pwd -P)" LINK="$HOME/.reflexio/plugin-root" mkdir -p "$(dirname "$LINK")" diff --git a/plugin/scripts/hook_entry.sh b/plugin/scripts/hook_entry.sh index 27b98f3..67c3914 100755 --- a/plugin/scripts/hook_entry.sh +++ b/plugin/scripts/hook_entry.sh @@ -3,8 +3,9 @@ # CLAUDE_PLUGIN_ROOT points at the plugin dir (dev: /plugin; # installed: ~/.claude/plugins/cache/reflexioai/claude-smart/), # which is also the Python project root with pyproject.toml + uv.lock. -# We invoke via `uv run --project --no-sync` so the prepared env is used without -# undoing editable Reflexio installs from local development. +# We invoke the prepared venv Python directly so hooks use the dependency set +# produced by smart-install.sh, including the vendored Reflexio snapshot it +# installs non-editably (--reinstall --no-deps). # # If the Setup hook recorded an install failure at # ~/.claude-smart/install-failed, short-circuit with a user-visible @@ -135,4 +136,5 @@ if ! ensure_hook_package_importable; then fi # Stdin is the hook payload JSON — stream it through to the Python CLI. -exec uv run --project "$PLUGIN_ROOT" --no-sync --quiet python -m claude_smart.hook "$HOST" "$EVENT" +PLUGIN_PYTHON="$(claude_smart_plugin_python "$PLUGIN_ROOT")" +exec "$PLUGIN_PYTHON" -m claude_smart.hook "$HOST" "$EVENT" diff --git a/plugin/scripts/smart-install.sh b/plugin/scripts/smart-install.sh index d706b2c..f0f194a 100755 --- a/plugin/scripts/smart-install.sh +++ b/plugin/scripts/smart-install.sh @@ -142,12 +142,12 @@ install_vendored_reflexio() { fi echo "[claude-smart] installing bundled Reflexio source from $VENDORED_REFLEXIO" >&2 - if uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" --quiet -e "$VENDORED_REFLEXIO" >&2; then + if uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" --quiet --reinstall --no-deps "$VENDORED_REFLEXIO" >&2; then return 0 fi echo "[claude-smart] warning: quiet vendored Reflexio install failed in $PLUGIN_ROOT; retrying with full output." >&2 - if ! uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" -e "$VENDORED_REFLEXIO" >&2; then + if ! uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" --reinstall --no-deps "$VENDORED_REFLEXIO" >&2; then write_failure "vendored Reflexio install failed in $PLUGIN_ROOT" fi } diff --git a/plugin/uv.lock b/plugin/uv.lock index 92d695a..81c0317 100644 --- a/plugin/uv.lock +++ b/plugin/uv.lock @@ -293,6 +293,63 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.7" @@ -437,7 +494,7 @@ dev = [ requires-dist = [ { name = "chromadb", specifier = ">=0.5" }, { name = "einops", specifier = ">=0.8.0" }, - { name = "reflexio-ai", specifier = ">=0.2.23" }, + { name = "reflexio-ai", specifier = ">=0.2.25" }, { name = "sqlite-vec", specifier = ">=0.1.6" }, ] @@ -477,6 +534,59 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, ] +[[package]] +name = "cryptography" +version = "48.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" }, + { url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" }, + { url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" }, + { url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" }, + { url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" }, + { url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" }, + { url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" }, + { url = "https://files.pythonhosted.org/packages/42/06/3e768b4c3bc78201583fa35a0e18f640dd782ff41afba88f8545481a8874/cryptography-48.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345", size = 7989830, upload-time = "2026-06-09T22:31:07.8Z" }, + { url = "https://files.pythonhosted.org/packages/8a/13/6476736484b94041110c8340a3eb63962fea4975baea8cb4a512adb44d4d/cryptography-48.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4", size = 4689201, upload-time = "2026-06-09T22:31:09.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/62/65a87f34d2a431546e2509b85d55e8c90df86d668f6731da64d538512ac2/cryptography-48.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991", size = 4702822, upload-time = "2026-06-09T22:32:24.409Z" }, + { url = "https://files.pythonhosted.org/packages/7f/59/810b5204b0a9b10f4b6bc06bd551a8b609803cd931806bc3b71884b225e5/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265", size = 4694875, upload-time = "2026-06-09T22:32:08.737Z" }, + { url = "https://files.pythonhosted.org/packages/24/dc/d8ca05ffea724eec6d232ea6f18e74c269eb6bdfdcc9bfba689790d1325f/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17", size = 5290385, upload-time = "2026-06-09T22:31:15.212Z" }, + { url = "https://files.pythonhosted.org/packages/03/8c/3be6cb4da181f5bb6c19cf560c2359d60644a6b5fc5b57854e528f47b296/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411", size = 4737082, upload-time = "2026-06-09T22:32:22.66Z" }, + { url = "https://files.pythonhosted.org/packages/aa/f6/d5f60a5a1434dbfd949e227fd0065d194c7e6b6ac526b17f5c06152b8231/cryptography-48.0.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02", size = 4325328, upload-time = "2026-06-09T22:32:10.777Z" }, + { url = "https://files.pythonhosted.org/packages/17/b7/ba75dd947a14b6ad907b01ae8f6b5b348cdd1b48142f0063dee9e20c1d9d/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa", size = 4694530, upload-time = "2026-06-09T22:31:53.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/29/50d6b9e8aff12d8b67afaeb3569335e32dc83a5723e3bbded24fdac9f809/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3", size = 5245046, upload-time = "2026-06-09T22:31:25.774Z" }, + { url = "https://files.pythonhosted.org/packages/9f/04/618f4115cfc0add0838c82507aa18a346089428da8653ad38b3ff36f5cb3/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c", size = 4736660, upload-time = "2026-06-09T22:32:12.676Z" }, + { url = "https://files.pythonhosted.org/packages/24/9c/06e062462a0de28a3b3911322eded4c16deb9f441b1b7575d3dc59488ab5/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72", size = 4822229, upload-time = "2026-06-09T22:31:17.062Z" }, + { url = "https://files.pythonhosted.org/packages/f4/be/0561971eaaee4b8a0e7d5113c536921063ab91aaf23278ac374eaf881e11/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9", size = 4966364, upload-time = "2026-06-09T22:31:32.842Z" }, + { url = "https://files.pythonhosted.org/packages/a4/27/728c77876f12b000820b69ae490f3c4083775e79e07827e9e60be07ad209/cryptography-48.0.1-cp314-cp314t-win32.whl", hash = "sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471", size = 3278498, upload-time = "2026-06-09T22:31:29.154Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/79a612c6d7b1e6ee0edd43633d53035bec2cfb78c82b76f7864f39e36f34/cryptography-48.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2", size = 3798790, upload-time = "2026-06-09T22:31:56.697Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" }, + { url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" }, + { url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" }, + { url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" }, + { url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" }, + { url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" }, +] + [[package]] name = "cuda-bindings" version = "13.2.0" @@ -2371,6 +2481,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ea/6d/41faa414cde66ec023b0ca8402a8f11cb61731c3dc27c082909cbbd1f929/pybase64-1.4.3-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:f7537fa22ae56a0bf51e4b0ffc075926ad91c618e1416330939f7ef366b58e3b", size = 36231, upload-time = "2025-12-06T13:26:31.656Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pydantic" version = "2.13.4" @@ -2641,7 +2760,7 @@ wheels = [ [[package]] name = "reflexio-ai" -version = "0.2.23" +version = "0.2.25" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -2651,6 +2770,7 @@ dependencies = [ { name = "cachetools" }, { name = "chromadb" }, { name = "colorlog" }, + { name = "cryptography" }, { name = "duckduckgo-search" }, { name = "einops" }, { name = "fastapi" }, @@ -2672,6 +2792,7 @@ dependencies = [ { name = "rich" }, { name = "sentence-transformers" }, { name = "slowapi" }, + { name = "sqlite-vec" }, { name = "tenacity" }, { name = "tiktoken" }, { name = "typer" }, @@ -2679,9 +2800,9 @@ dependencies = [ { name = "websocket-client" }, { name = "xlsxwriter" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/16/0faedcc5ace628da0b08717038525d560984d26395cab8eb674ddb7e2f00/reflexio_ai-0.2.23.tar.gz", hash = "sha256:35de6e2301c80cf03fd718afe18edf4e4b73c329a30b9575d06993c7c929d64d", size = 740410, upload-time = "2026-05-25T01:49:30.202Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/da/323d788e55db2041caf1ffbb52a3536b959ac12ee8e22d40e7d53da10e96/reflexio_ai-0.2.25.tar.gz", hash = "sha256:4435145c865e397a9e4fb86560fa9378ba9094e99646f9c2df65cb4de7dd4fac", size = 754836, upload-time = "2026-06-10T18:03:11.997Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b2/5046a5bfced0829578f786ee96faef1febf7edc9473e65018616a2dced76/reflexio_ai-0.2.23-py3-none-any.whl", hash = "sha256:9362663884a05da891eb7c9b5085b6af2a6df41e0a2adca3ba629c9dcc42d0c1", size = 953090, upload-time = "2026-05-25T01:49:31.839Z" }, + { url = "https://files.pythonhosted.org/packages/16/7c/ef6cfaf172eecc02d6834828c549c314d013b6b3019bf7186dc50eeb9c5c/reflexio_ai-0.2.25-py3-none-any.whl", hash = "sha256:927b20323cbfe6a32df2092ce617ed2abec78a57b8c70e61eff501862b455dca", size = 1024584, upload-time = "2026-06-10T18:03:13.525Z" }, ] [[package]] diff --git a/reflexio.lock.json b/reflexio.lock.json index 3502ec9..f2ea517 100644 --- a/reflexio.lock.json +++ b/reflexio.lock.json @@ -1,9 +1,9 @@ { "package": "reflexio-ai", "repo": "https://github.com/ReflexioAI/reflexio.git", - "version": "0.2.23", - "commit": "33e179e3b3cff6bf84d90fc7c173ce75bc011785", - "dependency": "reflexio-ai>=0.2.23", + "version": "0.2.25", + "commit": "1aedbc6c080442c140dd35005ccf5a736de938c7", + "dependency": "reflexio-ai>=0.2.25", "source": "pypi", - "updated_at": "2026-05-25T01:52:19Z" + "updated_at": "2026-06-10T18:07:10Z" } diff --git a/scripts/release-with-reflexio.sh b/scripts/release-with-reflexio.sh index 94d0e1e..33558d6 100755 --- a/scripts/release-with-reflexio.sh +++ b/scripts/release-with-reflexio.sh @@ -59,7 +59,7 @@ case "$REFLEXIO_RELEASE_SOURCE" in echo "error: plugin Python was not created by uv sync: $PLUGIN_PYTHON" >&2 exit 1 fi - uv pip install --project plugin --python "$PLUGIN_PYTHON" -e plugin/vendor/reflexio + uv pip install --project plugin --python "$PLUGIN_PYTHON" --reinstall --no-deps plugin/vendor/reflexio ;; pypi) "$PYTHON_BIN" scripts/sync-reflexio-dep.py \ diff --git a/tests/test_install_scripts.py b/tests/test_install_scripts.py index 13866e7..a4d8816 100644 --- a/tests/test_install_scripts.py +++ b/tests/test_install_scripts.py @@ -316,6 +316,22 @@ def test_backend_service_forces_utf8_stdio_for_managed_backend() -> None: assert 'env PYTHONIOENCODING="${PYTHONIOENCODING:-utf-8}"' in service +def test_backend_service_uses_prepared_venv_reflexio_cli() -> None: + service = (REPO_ROOT / "plugin" / "scripts" / "backend-service.sh").read_text() + + assert 'backend_python="$(claude_smart_plugin_python "$PLUGIN_ROOT")"' in service + assert '"$backend_python" -m reflexio.cli services start' in service + assert 'uv run --project "$PLUGIN_ROOT" --no-sync --quiet' not in service + assert "ensure_vendored_reflexio_active" in service + assert 'plugin_python="$(claude_smart_plugin_python "$PLUGIN_ROOT")"' in service + assert ( + 'uv pip install --project "$PLUGIN_ROOT" --python "$plugin_python" ' + '--quiet --reinstall --no-deps "$vendor"' + ) in service + assert 'vendor_pythonpath="$PLUGIN_ROOT/vendor/reflexio"' in service + assert 'PYTHONPATH="$backend_pythonpath"' in service + + def test_backend_service_pins_reflexio_home_to_user_home() -> None: service = (REPO_ROOT / "plugin" / "scripts" / "backend-service.sh").read_text() @@ -1082,7 +1098,12 @@ def test_cli_sh_suppresses_installer_hook_payload_on_self_heal(tmp_path: Path) - 'touch "$HOME/import-ok"\n' ) (venv_bin / "python").write_text( - '#!/bin/sh\n[ -f "$HOME/import-ok" ] && exit 0\nexit 1\n' + "#!/bin/sh\n" + 'if [ "$1" = "-" ]; then\n' + ' [ -f "$HOME/import-ok" ] && exit 0\n' + " exit 1\n" + "fi\n" + "printf 'cli ran\\n'\n" ) (bin_dir / "uv").write_text("#!/bin/sh\nprintf 'cli ran\\n'\nexit 0\n") for executable in [ @@ -1182,7 +1203,7 @@ def test_reflexio_vendor_release_uses_generated_bundle() -> None: assert 'PYTHON_BIN="${PYTHON:-python3}"' in release_script assert '"$PYTHON_BIN" scripts/vendor-reflexio.py' in release_script assert "uv pip install --project plugin --python" in release_script - assert "-e plugin/vendor/reflexio" in release_script + assert "--reinstall --no-deps plugin/vendor/reflexio" in release_script assert "OK: npm tarball includes vendored Reflexio files" in release_script assert "Keep generated plugin/vendor/reflexio in place" in release_script assert "make release-npm VERSION=" in release_script @@ -1199,7 +1220,7 @@ def test_reflexio_vendor_release_uses_generated_bundle() -> None: assert 'VENDORED_REFLEXIO="$PLUGIN_ROOT/vendor/reflexio"' in smart_install assert ( 'uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" ' - '--quiet -e "$VENDORED_REFLEXIO"' + '--quiet --reinstall --no-deps "$VENDORED_REFLEXIO"' ) in smart_install assert "vendored Reflexio install failed" in smart_install assert "install_vendored_reflexio" in smart_install @@ -1348,7 +1369,7 @@ def test_smart_install_installs_vendored_reflexio(tmp_path: Path) -> None: uv_log = (tmp_path / "uv.log").read_text() assert "sync --locked --python 3.12 --quiet" in uv_log assert f"pip install --project {plugin_root}" in uv_log - assert f"-e {vendor}" in uv_log + assert f"--reinstall --no-deps {vendor}" in uv_log @pytest.mark.parametrize( @@ -1432,6 +1453,40 @@ def test_smart_install_redirects_reflexio_stray_copies_to_stable_root( assert str(session_root) not in uv_log +def test_ensure_plugin_root_canonicalizes_symlink_target(tmp_path: Path) -> None: + plugin_root = tmp_path / ".codex" / "plugins" / "cache" / "reflexioai" / "claude-smart" / "0.2.43" + scripts = plugin_root / "scripts" + scripts.mkdir(parents=True) + shutil.copy2( + REPO_ROOT / "plugin" / "scripts" / "ensure-plugin-root.sh", + scripts / "ensure-plugin-root.sh", + ) + (plugin_root / "pyproject.toml").write_text("[project]\nname='claude-smart'\n") + + link = tmp_path / ".reflexio" / "plugin-root" + link.parent.mkdir() + link.symlink_to(plugin_root, target_is_directory=True) + + env = _isolated_env(tmp_path) + result = subprocess.run( + [ + "/bin/bash", + "--noprofile", + "--norc", + str(link / "scripts" / "ensure-plugin-root.sh"), + str(link), + "--force", + ], + env=env, + text=True, + capture_output=True, + check=False, + ) + + assert result.returncode == 0, result.stderr + assert os.readlink(link) == str(plugin_root) + + def test_smart_install_repairs_reflexio_template_env_drift(tmp_path: Path) -> None: plugin_root = tmp_path / "plugin" scripts = plugin_root / "scripts" @@ -1838,8 +1893,25 @@ def test_hook_entry_failure_marker_uses_resolved_python_on_windows( def test_hook_entry_defaults_codex_citation_links_to_markdown(tmp_path: Path) -> None: + plugin_root = tmp_path / "plugin" + scripts = plugin_root / "scripts" + venv_bin = plugin_root / ".venv" / "bin" bin_dir = tmp_path / "bin" + scripts.mkdir(parents=True) + venv_bin.mkdir(parents=True) bin_dir.mkdir() + shutil.copy2(LIB, scripts / "_lib.sh") + shutil.copy2(HOOK_ENTRY, scripts / "hook_entry.sh") + (venv_bin / "python").write_text( + "#!/bin/sh\n" + 'if [ "$1" = "-" ]; then\n' + " cat >/dev/null\n" + " exit 0\n" + "fi\n" + 'printf \'%s\\n\' "{\\"hookSpecificOutput\\":' + '{\\"hookEventName\\":\\"UserPromptSubmit\\",' + '\\"additionalContext\\":\\"$CLAUDE_SMART_CITATION_LINK_STYLE\\"}}"\n' + ) uv = bin_dir / "uv" uv.write_text( "#!/bin/sh\n" @@ -1847,13 +1919,18 @@ def test_hook_entry_defaults_codex_citation_links_to_markdown(tmp_path: Path) -> '{\\"hookEventName\\":\\"UserPromptSubmit\\",' '\\"additionalContext\\":\\"$CLAUDE_SMART_CITATION_LINK_STYLE\\"}}"\n' ) - uv.chmod(uv.stat().st_mode | stat.S_IXUSR) + for executable in [ + scripts / "hook_entry.sh", + venv_bin / "python", + uv, + ]: + executable.chmod(executable.stat().st_mode | stat.S_IXUSR) env = _isolated_env(tmp_path) env["PATH"] = f"{bin_dir}{os.pathsep}{env['PATH']}" env.pop("CLAUDE_SMART_CITATION_LINK_STYLE", None) result = subprocess.run( - [str(HOOK_ENTRY), "codex", "user-prompt"], + [str(scripts / "hook_entry.sh"), "codex", "user-prompt"], env=env, text=True, input=json.dumps({"session_id": "s1", "prompt": "What food do I like?"}), @@ -1867,7 +1944,7 @@ def test_hook_entry_defaults_codex_citation_links_to_markdown(tmp_path: Path) -> env["CLAUDE_SMART_CITATION_LINK_STYLE"] = "osc8" result = subprocess.run( - [str(HOOK_ENTRY), "codex", "user-prompt"], + [str(scripts / "hook_entry.sh"), "codex", "user-prompt"], env=env, text=True, input=json.dumps({"session_id": "s1", "prompt": "What food do I like?"}),