flurryx-code-memory 0.7.5__tar.gz → 0.7.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/CHANGELOG.md +38 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/PKG-INFO +2 -2
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/pyproject.toml +2 -2
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/install.ps1 +98 -14
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/install.sh +98 -14
- flurryx_code_memory-0.7.6/src/code_memory/_console.py +32 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/cli.py +14 -1
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/mcp_server.py +3 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/updater.py +146 -1
- flurryx_code_memory-0.7.6/tests/test_console_encoding.py +63 -0
- flurryx_code_memory-0.7.6/tests/test_extras_offer.py +327 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/uv.lock +10 -7
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/.claude-plugin/marketplace.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/.env.example +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/.gitignore +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/README.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docker/docker-compose.yml +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docs/BENCHMARK.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docs/BENCHMARK_VS_BASELINE.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docs/BENCHMARK_VS_BASELINE.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docs/architecture.png +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docs/benchmark-raw.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/docs/hero.png +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/install.ps1 +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/install.sh +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/README.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/commands/code-memory.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/hooks/hooks.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/install.sh +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/lib/claim-intent.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/lib/claim-intent.test.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/lib/io.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/lib/memory.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/lib/state.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/on-post-tool.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/on-pre-tool.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/on-retrieve-seen.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/on-session-start.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/on-stop.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/on-user-prompt.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/scripts/resolver-debounce.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/claude-code/skills/code-memory/SKILL.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/README.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/hooks/hooks.json.template +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/install.sh +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/rules/code-memory.mdc +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/lib/claim-intent.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/lib/claim-intent.test.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/lib/io.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/lib/memory.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/lib/state.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-after-file-edit.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-before-mcp-execution.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-before-submit-prompt.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-post-tool-use.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-pre-compact.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-pre-tool-use.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-session-end.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-session-start.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/on-stop.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/cursor/scripts/resolver-debounce.js +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/README.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/install.sh +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/package-lock.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/package.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/scripts/add-mcp.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/scripts/install.mjs +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/scripts/uninstall.mjs +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/skills/code-memory/SKILL.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/src/code-memory-lib/claim-intent.test.mts +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/src/code-memory-lib/claim-intent.ts +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/src/code-memory-lib/memory-client.ts +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/src/code-memory.ts +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/opencode/tsconfig.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/vibe/README.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/vibe/install.sh +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/plugins/vibe/skills/code-memory/SKILL.md +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/benchmark.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/benchmark_queries.json +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/benchmark_vs_baseline.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/benchmark_vs_grep.sh +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/scripts/ingest.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/claims/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/claims/extractor.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/claims/indexer.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/claims/resolver.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/claims/store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/config.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/embed/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/embed/cache.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/embed/m3.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/embed/ollama.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/embed/tei.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/episodic/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/episodic/sqlite_store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/csproj.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/dll.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/gitignore.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/nuget.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/sanity.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/sln.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/extractor/treesitter.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/graph/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/graph/falkor_store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/metrics.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/git_delta.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/ingest_state.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/pipeline.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/reset.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/resolver.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/orchestrator/retrieve.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/resilience.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/autostart/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/autostart/base.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/autostart/launchd.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/autostart/schtasks.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/autostart/systemd.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/hooks.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/safety.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/single_flight.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/snapshot.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/sync.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/sync/watcher.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/vector/__init__.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/src/code_memory/vector/qdrant_store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_autostart_adapters.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_chunk_text.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_claim_extractor.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_claim_indexer.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_claim_resolver.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_claim_store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_config_embed_dim.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_config_ipv4_defaults.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_config_sentinel.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_csproj.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_dll_members.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_dll_parser.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_embed_backend.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_embed_cache.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_embed_m3.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_embed_ollama_timeout.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_embed_tei.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_ensure_fresh_no_blocking.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_episode_dedup.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_episode_head_sha.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_csharp.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_dart.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_filters.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_parser_compat.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_php.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_python_imports.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_receiver_type.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_references.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_sanity.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_ts_abstract.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_ts_inject.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_extractor_utf8.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_file_containment.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_git_delta.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_graph_queries.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_graph_shadow_swap.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_graph_temporal.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_graph_vacuum_at_sha.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_hooks_installer.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_ingest_safety_and_lock.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_ingest_state.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_mcp_assert_claim.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_mcp_server_descriptions.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_mcp_shutdown.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_mcp_strict_project.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_metrics.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_nuget_resolver.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_overload_resolution.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_partial_class.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_pipeline_health_check.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_pipeline_references.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_pipeline_temporal_wiring.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_qdrant_legacy_guard.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_razor_inject.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_resilience.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_resolver.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_resolver_assembly.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_retrieve_claims_surfacing.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_retrieve_rerank.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_sln.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_smoke.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_snapshot_e2e.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_snapshot_format.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_snapshot_store.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_sync_decision_tree.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_watch_safety.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_watcher_debouncer.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_watcher_exclude.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_watcher_ref_events.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_worktree_autostart_guard.py +0 -0
- {flurryx_code_memory-0.7.5 → flurryx_code_memory-0.7.6}/tests/test_worktree_slug.py +0 -0
|
@@ -8,10 +8,48 @@ when the repo grows.
|
|
|
8
8
|
This file complements `git log`: commits explain mechanics, this file
|
|
9
9
|
explains intent.
|
|
10
10
|
|
|
11
|
+
## [0.7.6] — 2026-06-21
|
|
12
|
+
|
|
13
|
+
Release theme: **Correct tree-sitter pin + Windows console & extras fixes**.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
**tree-sitter-language-pack pinned to `==1.8.1`** (was `==1.0.0` in the broken 0.7.5).
|
|
18
|
+
Version 1.0.0 has no bundled language grammars (it uses a download model), so
|
|
19
|
+
`get_language('csharp')` raised `LanguageNotFoundError` and extraction produced
|
|
20
|
+
zero symbols on every platform. Version 1.9.1 is also broken (raises `'bytes'
|
|
21
|
+
object is not an instance of 'str'` even on macOS — a 1.9.x regression). 1.8.1
|
|
22
|
+
is the last known-good release with bundled grammars; the original Windows
|
|
23
|
+
failure was caused by the loose `>=0.7` floor letting fresh installs float to
|
|
24
|
+
1.9.1.
|
|
25
|
+
|
|
26
|
+
Reason: stop floating into broken 1.9.x and restore symbol extraction everywhere.
|
|
27
|
+
|
|
28
|
+
**Windows console crash in `code-memory update`**: stdout/stderr are now forced
|
|
29
|
+
to UTF-8 (`errors="replace"`) at the CLI and MCP entry points, so Unicode
|
|
30
|
+
status glyphs (→, •, ✓) no longer raise `UnicodeEncodeError` on cp1252
|
|
31
|
+
PowerShell consoles.
|
|
32
|
+
|
|
33
|
+
Reason: the updater crashed before doing any work on non-UTF-8 Windows terminals.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
**Optional-extras selection prompt** in `code-memory update` and the install
|
|
38
|
+
one-liner (`install.sh` / `install.ps1`): users are now asked which optional
|
|
39
|
+
extras to enable (`dotnet` for .NET assembly indexing, `hybrid` for in-process
|
|
40
|
+
BGE-M3). TTY-gated with a `CODEMEMORY_EXTRAS` env override and an `--extras`
|
|
41
|
+
flag; non-interactive runs install nothing new. Also fixes the bash installer
|
|
42
|
+
gating the prompt on `[ -t 0 ]`, which was always false under `curl | bash` so
|
|
43
|
+
the prompt never appeared.
|
|
44
|
+
|
|
45
|
+
Reason: previously there was no way to opt into .NET indexing during update/install.
|
|
46
|
+
|
|
11
47
|
## [0.7.5] — 2026-06-21
|
|
12
48
|
|
|
13
49
|
Release theme: **Windows ingest fix — pin tree-sitter-language-pack**.
|
|
14
50
|
|
|
51
|
+
**⚠️ Superseded by 0.7.6 — this release pinned tree-sitter-language-pack==1.0.0 which broke extraction (no bundled grammars). Do not use.**
|
|
52
|
+
|
|
15
53
|
### Fixed
|
|
16
54
|
|
|
17
55
|
**What:** pinned `tree-sitter-language-pack` to `==1.0.0` (was `>=0.7`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flurryx-code-memory
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.6
|
|
4
4
|
Summary: Local lightweight memory layer for coding agents: FalkorDB + Qdrant + Ollama (BGE-M3) + tree-sitter
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Requires-Dist: anyio>=4.4
|
|
@@ -10,7 +10,7 @@ Requires-Dist: mcp>=1.0
|
|
|
10
10
|
Requires-Dist: pydantic>=2.8
|
|
11
11
|
Requires-Dist: qdrant-client>=1.12
|
|
12
12
|
Requires-Dist: rich>=13.7
|
|
13
|
-
Requires-Dist: tree-sitter-language-pack==1.
|
|
13
|
+
Requires-Dist: tree-sitter-language-pack==1.8.1
|
|
14
14
|
Requires-Dist: tree-sitter>=0.23
|
|
15
15
|
Requires-Dist: typer>=0.12
|
|
16
16
|
Requires-Dist: watchdog>=4.0
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flurryx-code-memory"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.6"
|
|
8
8
|
description = "Local lightweight memory layer for coding agents: FalkorDB + Qdrant + Ollama (BGE-M3) + tree-sitter"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
dependencies = [
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
"qdrant-client>=1.12",
|
|
13
13
|
"falkordb>=1.0.10",
|
|
14
14
|
"tree-sitter>=0.23",
|
|
15
|
-
"tree-sitter-language-pack==1.
|
|
15
|
+
"tree-sitter-language-pack==1.8.1",
|
|
16
16
|
"pydantic>=2.8",
|
|
17
17
|
"typer>=0.12",
|
|
18
18
|
"rich>=13.7",
|
|
@@ -25,6 +25,15 @@
|
|
|
25
25
|
metadata indexing (Assembly + Type graph nodes from .dll referenced
|
|
26
26
|
via .csproj). Skip if no .NET source in repos you ingest.
|
|
27
27
|
|
|
28
|
+
.PARAMETER WithHybrid
|
|
29
|
+
Install the [hybrid] extra (FlagEmbedding, ~2 GB torch). Enables in-process
|
|
30
|
+
BGE-M3 dense+sparse hybrid reranking. Heavy — skip unless you need it.
|
|
31
|
+
|
|
32
|
+
.PARAMETER Extras
|
|
33
|
+
Comma list of optional extras to install (e.g. 'dotnet,hybrid'), or 'none'
|
|
34
|
+
to bypass the interactive prompt. Overrides -WithDotnet/-WithHybrid and the
|
|
35
|
+
CODEMEMORY_EXTRAS environment variable.
|
|
36
|
+
|
|
28
37
|
.PARAMETER Plugins
|
|
29
38
|
Comma-separated whitelist of harness plugins to install:
|
|
30
39
|
'opencode', 'claudecode', 'cursor', 'all', or 'none'. Bypasses the
|
|
@@ -37,14 +46,22 @@
|
|
|
37
46
|
./.cursor.
|
|
38
47
|
|
|
39
48
|
.PARAMETER ExtrasInteractive
|
|
40
|
-
Set to `$false` to skip the interactive extras prompt.
|
|
41
|
-
|
|
49
|
+
Set to `$false` to skip the interactive extras prompt entirely. Overridden
|
|
50
|
+
by -Extras, -WithDotnet, -WithHybrid, and the CODEMEMORY_EXTRAS env var.
|
|
42
51
|
|
|
43
52
|
.EXAMPLE
|
|
44
53
|
./scripts/install.ps1
|
|
45
54
|
./scripts/install.ps1 -NoOllama
|
|
46
55
|
./scripts/install.ps1 -WithDotnet -Plugins all
|
|
56
|
+
./scripts/install.ps1 -WithHybrid
|
|
57
|
+
./scripts/install.ps1 -Extras dotnet,hybrid
|
|
58
|
+
./scripts/install.ps1 -Extras none
|
|
47
59
|
./scripts/install.ps1 -Plugins claudecode -PluginsScope project
|
|
60
|
+
|
|
61
|
+
.NOTES
|
|
62
|
+
Environment variables:
|
|
63
|
+
CODEMEMORY_EXTRAS=dotnet,hybrid same as -Extras (overrides interactive prompt)
|
|
64
|
+
CODEMEMORY_EXTRAS=none skip extras entirely
|
|
48
65
|
#>
|
|
49
66
|
|
|
50
67
|
[CmdletBinding()]
|
|
@@ -54,6 +71,8 @@ param(
|
|
|
54
71
|
[switch]$NoTests,
|
|
55
72
|
[switch]$NoMcp,
|
|
56
73
|
[switch]$WithDotnet,
|
|
74
|
+
[switch]$WithHybrid,
|
|
75
|
+
[string]$Extras = '',
|
|
57
76
|
[string]$Plugins = '',
|
|
58
77
|
[ValidateSet('global', 'project')]
|
|
59
78
|
[string]$PluginsScope = 'global',
|
|
@@ -195,24 +214,89 @@ Ok "pip upgraded"
|
|
|
195
214
|
|
|
196
215
|
# ---------- 3. package install ----------
|
|
197
216
|
# Resolve optional extras up front so we do one pip resolve.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
#
|
|
218
|
+
# Optional extras — keep in sync with EXTRAS registry in updater.py.
|
|
219
|
+
# dotnet: .NET assembly metadata indexing (dnfile, ~200 KB).
|
|
220
|
+
# hybrid: in-process BGE-M3 dense+sparse via FlagEmbedding (~2 GB torch).
|
|
221
|
+
#
|
|
222
|
+
# Priority: -Extras / -WithDotnet / -WithHybrid (CLI) >
|
|
223
|
+
# CODEMEMORY_EXTRAS env var > interactive prompt > skip.
|
|
224
|
+
#
|
|
225
|
+
# $isTty: true when running interactively (not under irm|iex which redirects stdin).
|
|
226
|
+
$isTty = [Environment]::UserInteractive -and -not [Console]::IsInputRedirected
|
|
227
|
+
|
|
228
|
+
$installDotnet = [bool]$WithDotnet
|
|
229
|
+
$installHybrid = [bool]$WithHybrid
|
|
230
|
+
|
|
231
|
+
# Fold legacy switches into -Extras when -Extras is not already set.
|
|
232
|
+
if ([string]::IsNullOrWhiteSpace($Extras)) {
|
|
233
|
+
$legacyParts = @()
|
|
234
|
+
if ($WithDotnet) { $legacyParts += 'dotnet' }
|
|
235
|
+
if ($WithHybrid) { $legacyParts += 'hybrid' }
|
|
236
|
+
if ($legacyParts.Count -gt 0) { $Extras = $legacyParts -join ',' }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Determine effective source.
|
|
240
|
+
$effectiveExtras = $Extras
|
|
241
|
+
if ([string]::IsNullOrWhiteSpace($effectiveExtras)) {
|
|
242
|
+
$envExtras = [System.Environment]::GetEnvironmentVariable('CODEMEMORY_EXTRAS')
|
|
243
|
+
if (-not [string]::IsNullOrWhiteSpace($envExtras)) {
|
|
244
|
+
$effectiveExtras = $envExtras.Trim()
|
|
206
245
|
}
|
|
207
246
|
}
|
|
208
247
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
248
|
+
if (-not [string]::IsNullOrWhiteSpace($effectiveExtras)) {
|
|
249
|
+
# Flag/env path — parse comma list.
|
|
250
|
+
if ($effectiveExtras -ieq 'none') {
|
|
251
|
+
$installDotnet = $false
|
|
252
|
+
$installHybrid = $false
|
|
253
|
+
} else {
|
|
254
|
+
foreach ($ep in $effectiveExtras.Split(',')) {
|
|
255
|
+
switch ($ep.Trim().ToLower()) {
|
|
256
|
+
'dotnet' { $installDotnet = $true }
|
|
257
|
+
'hybrid' { $installHybrid = $true }
|
|
258
|
+
'' { }
|
|
259
|
+
default { Warn "unknown extra '$($ep.Trim())' (known: dotnet, hybrid) — skipped" }
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} elseif ($ExtrasInteractive -and $isTty) {
|
|
264
|
+
# Interactive TTY path.
|
|
265
|
+
Step "Optional extras"
|
|
266
|
+
# Keep descriptions in sync with updater.py EXTRAS registry.
|
|
267
|
+
Write-Host " [dotnet] .NET assembly metadata indexing (dnfile, ~200 KB)."
|
|
268
|
+
Write-Host " Skip if no .csproj / .NET source in repos you ingest."
|
|
269
|
+
Write-Host ""
|
|
270
|
+
Write-Host " [hybrid] In-process BGE-M3 dense+sparse via FlagEmbedding."
|
|
271
|
+
Write-Host " Heavy — pulls torch (~2 GB). Skip unless you need hybrid reranking."
|
|
272
|
+
Write-Host ""
|
|
273
|
+
if (Prompt-YesNo "Install [dotnet] extra?" $false) { $installDotnet = $true }
|
|
274
|
+
if (Prompt-YesNo "Install [hybrid] extra?" $false) { $installHybrid = $true }
|
|
275
|
+
} else {
|
|
276
|
+
# Non-interactive, no env override — dim hint only, no install.
|
|
277
|
+
Dim "hint: optional extras not installed. Re-run with -Extras dotnet,hybrid or set CODEMEMORY_EXTRAS=dotnet,hybrid."
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
$extrasBase = @('dev')
|
|
281
|
+
if ($installDotnet) { $extrasBase += 'dotnet' }
|
|
282
|
+
if ($installHybrid) { $extrasBase += 'hybrid' }
|
|
283
|
+
$extrasJoined = ($extrasBase -join ',')
|
|
212
284
|
|
|
213
285
|
Step "Installing code-memory (editable, extras: $extrasJoined)"
|
|
214
|
-
|
|
286
|
+
# Base [dev] is hard-fail. Optional extras are non-fatal — a missing build
|
|
287
|
+
# dependency (e.g. torch wheel unavailable) must not abort the whole install.
|
|
288
|
+
& pip install -e ".[dev]"
|
|
215
289
|
if ($LASTEXITCODE -ne 0) { Die "pip install failed" }
|
|
290
|
+
if ($installDotnet -or $installHybrid) {
|
|
291
|
+
$optionalParts = @()
|
|
292
|
+
if ($installDotnet) { $optionalParts += 'dotnet' }
|
|
293
|
+
if ($installHybrid) { $optionalParts += 'hybrid' }
|
|
294
|
+
$optionalJoined = $optionalParts -join ','
|
|
295
|
+
& pip install -e ".[dev,$optionalJoined]"
|
|
296
|
+
if ($LASTEXITCODE -ne 0) {
|
|
297
|
+
Warn "optional extras install failed (dev install succeeded; re-run: pip install -e '.[$optionalJoined]')"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
216
300
|
Ok "code-memory installed"
|
|
217
301
|
|
|
218
302
|
# ---------- 4. .env ----------
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
# ./scripts/install.sh --with-claims # also pull gemma2:9b for Graphiti-style
|
|
11
11
|
# # user-claim extraction (~5.4 GB)
|
|
12
12
|
# ./scripts/install.sh --with-dotnet # install [dotnet] extra (dnfile, ~200 KB; .NET DLL metadata indexing)
|
|
13
|
+
# ./scripts/install.sh --with-hybrid # install [hybrid] extra (FlagEmbedding; ~2 GB torch)
|
|
14
|
+
# ./scripts/install.sh --extras=dotnet,hybrid
|
|
15
|
+
# # install named extras (comma list)
|
|
13
16
|
# ./scripts/install.sh --extras=none # bypass interactive prompt; install only [dev]
|
|
14
17
|
# ./scripts/install.sh --plugins=opencode,claudecode,cursor
|
|
15
18
|
# # install named harness plugins (non-interactive)
|
|
@@ -21,6 +24,10 @@
|
|
|
21
24
|
# # default scope is global (~/.config/opencode,
|
|
22
25
|
# # ~/.claude, ~/.cursor)
|
|
23
26
|
#
|
|
27
|
+
# Environment variables:
|
|
28
|
+
# CODEMEMORY_EXTRAS=dotnet,hybrid # same as --extras=... (overrides interactive prompt)
|
|
29
|
+
# CODEMEMORY_EXTRAS=none # skip extras entirely
|
|
30
|
+
#
|
|
24
31
|
set -euo pipefail
|
|
25
32
|
|
|
26
33
|
# ---------- helpers ----------
|
|
@@ -48,8 +55,11 @@ SKIP_OLLAMA=0
|
|
|
48
55
|
SKIP_TESTS=0
|
|
49
56
|
SKIP_MCP=0
|
|
50
57
|
WITH_DOTNET=0
|
|
58
|
+
WITH_HYBRID=0
|
|
51
59
|
WITH_CLAIMS=0
|
|
52
|
-
|
|
60
|
+
# EXTRAS_ARG: CLI value of --extras=... (overrides CODEMEMORY_EXTRAS env and interactive).
|
|
61
|
+
# Empty means "not set by CLI"; "none" means skip; comma list means install those extras.
|
|
62
|
+
EXTRAS_ARG=""
|
|
53
63
|
PLUGINS_ARG="" # empty = interactive; explicit value bypasses prompt
|
|
54
64
|
PLUGINS_SCOPE="global" # global | project
|
|
55
65
|
for arg in "$@"; do
|
|
@@ -58,13 +68,14 @@ for arg in "$@"; do
|
|
|
58
68
|
--no-ollama) SKIP_OLLAMA=1 ;;
|
|
59
69
|
--no-tests) SKIP_TESTS=1 ;;
|
|
60
70
|
--no-mcp) SKIP_MCP=1 ;;
|
|
61
|
-
--with-dotnet)
|
|
62
|
-
--with-
|
|
71
|
+
--with-dotnet) WITH_DOTNET=1 ;;
|
|
72
|
+
--with-hybrid) WITH_HYBRID=1 ;;
|
|
73
|
+
--with-claims) WITH_CLAIMS=1 ;;
|
|
63
74
|
--extras=*) EXTRAS_ARG="${arg#--extras=}" ;;
|
|
64
75
|
--plugins=*) PLUGINS_ARG="${arg#--plugins=}" ;;
|
|
65
76
|
--plugins-scope=*) PLUGINS_SCOPE="${arg#--plugins-scope=}" ;;
|
|
66
77
|
-h|--help)
|
|
67
|
-
sed -n '1,
|
|
78
|
+
sed -n '1,29p' "$0"; exit 0 ;;
|
|
68
79
|
*) die "unknown flag: $arg" ;;
|
|
69
80
|
esac
|
|
70
81
|
done
|
|
@@ -190,22 +201,95 @@ prompt_yes_no() {
|
|
|
190
201
|
[ "$ans" = "y" ] || [ "$ans" = "yes" ]
|
|
191
202
|
}
|
|
192
203
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
# ---------- extras resolution (contract mirrors updater.py / install.ps1) ----------
|
|
205
|
+
# Optional extras in pyproject.toml — keep in sync with EXTRAS registry in updater.py.
|
|
206
|
+
# dotnet: .NET assembly metadata indexing (dnfile, ~200 KB).
|
|
207
|
+
# hybrid: in-process BGE-M3 dense+sparse via FlagEmbedding (~2 GB torch).
|
|
208
|
+
#
|
|
209
|
+
# Priority: CLI flag (--extras= / --with-dotnet / --with-hybrid) >
|
|
210
|
+
# CODEMEMORY_EXTRAS env var > interactive prompt > skip.
|
|
211
|
+
#
|
|
212
|
+
# TTY_OK = true when we can safely prompt:
|
|
213
|
+
# - Both stdin+stdout are a real TTY, OR /dev/tty is readable as a fallback
|
|
214
|
+
# (handles curl|bash where fd 0 is the pipe but /dev/tty is the terminal).
|
|
215
|
+
TTY_OK=0
|
|
216
|
+
if [ -t 0 ] && [ -t 1 ]; then
|
|
217
|
+
TTY_OK=1
|
|
218
|
+
elif [ -r /dev/tty ]; then
|
|
219
|
+
TTY_OK=1
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
# Build the effective extras list.
|
|
223
|
+
# We accumulate into INSTALL_DOTNET / INSTALL_HYBRID, then build the pip string.
|
|
224
|
+
INSTALL_DOTNET=0
|
|
225
|
+
INSTALL_HYBRID=0
|
|
226
|
+
|
|
227
|
+
# Fold legacy --with-dotnet / --with-hybrid into the generic flag path.
|
|
228
|
+
[ "$WITH_DOTNET" -eq 1 ] && EXTRAS_ARG="${EXTRAS_ARG:-dotnet}"
|
|
229
|
+
[ "$WITH_HYBRID" -eq 1 ] && {
|
|
230
|
+
if [ -n "$EXTRAS_ARG" ] && [ "$EXTRAS_ARG" != "none" ]; then
|
|
231
|
+
EXTRAS_ARG="${EXTRAS_ARG},hybrid"
|
|
232
|
+
elif [ -z "$EXTRAS_ARG" ]; then
|
|
233
|
+
EXTRAS_ARG="hybrid"
|
|
234
|
+
fi
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
# Determine effective source of extras selection.
|
|
238
|
+
EFFECTIVE_EXTRAS=""
|
|
239
|
+
if [ -n "$EXTRAS_ARG" ]; then
|
|
240
|
+
EFFECTIVE_EXTRAS="$EXTRAS_ARG"
|
|
241
|
+
elif [ -n "${CODEMEMORY_EXTRAS:-}" ]; then
|
|
242
|
+
EFFECTIVE_EXTRAS="$CODEMEMORY_EXTRAS"
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
if [ -n "$EFFECTIVE_EXTRAS" ]; then
|
|
246
|
+
# env/flag path — parse comma list.
|
|
247
|
+
if [ "$EFFECTIVE_EXTRAS" = "none" ]; then
|
|
248
|
+
: # install nothing extra
|
|
249
|
+
else
|
|
250
|
+
IFS=',' read -r -a _extras_parts <<< "$EFFECTIVE_EXTRAS"
|
|
251
|
+
for _ep in "${_extras_parts[@]}"; do
|
|
252
|
+
_ep="$(printf '%s' "$_ep" | tr -d '[:space:]')"
|
|
253
|
+
case "$_ep" in
|
|
254
|
+
dotnet) INSTALL_DOTNET=1 ;;
|
|
255
|
+
hybrid) INSTALL_HYBRID=1 ;;
|
|
256
|
+
"") ;;
|
|
257
|
+
*) warn "unknown extra '$_ep' (known: dotnet, hybrid) — skipped" ;;
|
|
258
|
+
esac
|
|
259
|
+
done
|
|
201
260
|
fi
|
|
261
|
+
elif [ "$TTY_OK" -eq 1 ]; then
|
|
262
|
+
# Interactive path.
|
|
263
|
+
step "Optional extras"
|
|
264
|
+
# Keep descriptions in sync with updater.py EXTRAS registry.
|
|
265
|
+
echo " [dotnet] .NET assembly metadata indexing (dnfile, ~200 KB)."
|
|
266
|
+
echo " Skip if no .csproj / .NET source in repos you ingest."
|
|
267
|
+
echo
|
|
268
|
+
echo " [hybrid] In-process BGE-M3 dense+sparse via FlagEmbedding."
|
|
269
|
+
echo " Heavy — pulls torch (~2 GB). Skip unless you need hybrid reranking."
|
|
270
|
+
echo
|
|
271
|
+
if prompt_yes_no "Install [dotnet] extra?" "n"; then INSTALL_DOTNET=1; fi
|
|
272
|
+
if prompt_yes_no "Install [hybrid] extra?" "n"; then INSTALL_HYBRID=1; fi
|
|
273
|
+
else
|
|
274
|
+
# Non-interactive, no env override — skip silently with a dim hint.
|
|
275
|
+
printf "${DIM} hint: optional extras not installed. Re-run with --extras=dotnet,hybrid or set CODEMEMORY_EXTRAS=dotnet,hybrid.${RST}\n"
|
|
202
276
|
fi
|
|
203
277
|
|
|
204
278
|
EXTRAS="dev"
|
|
205
|
-
[ "$
|
|
279
|
+
[ "$INSTALL_DOTNET" -eq 1 ] && EXTRAS="${EXTRAS},dotnet"
|
|
280
|
+
[ "$INSTALL_HYBRID" -eq 1 ] && EXTRAS="${EXTRAS},hybrid"
|
|
206
281
|
|
|
207
282
|
step "Installing code-memory (editable, extras: $EXTRAS)"
|
|
208
|
-
|
|
283
|
+
# The base [dev] install is hard-fail; optional extras are non-fatal so a
|
|
284
|
+
# missing build dependency (e.g. torch wheel not available) does not abort
|
|
285
|
+
# the whole install under set -e.
|
|
286
|
+
pip install -e ".[dev]"
|
|
287
|
+
if [ "$INSTALL_DOTNET" -eq 1 ] || [ "$INSTALL_HYBRID" -eq 1 ]; then
|
|
288
|
+
_optional_extras="${EXTRAS#dev}"
|
|
289
|
+
_optional_extras="${_optional_extras#,}"
|
|
290
|
+
pip install -e ".[dev,${_optional_extras}]" \
|
|
291
|
+
|| warn "optional extras install failed (dev install succeeded; re-run: pip install -e '.[${_optional_extras}]')"
|
|
292
|
+
fi
|
|
209
293
|
ok "code-memory installed"
|
|
210
294
|
|
|
211
295
|
# ---------- 4. .env ----------
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Console encoding utilities.
|
|
2
|
+
|
|
3
|
+
Ensures stdout/stderr are safe on non-UTF-8 consoles (e.g. Windows cp1252).
|
|
4
|
+
Must be imported with zero heavy dependencies so it can be called at the
|
|
5
|
+
earliest point of every CLI entry point.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _force_utf8_console() -> None:
|
|
14
|
+
"""Reconfigure stdout and stderr to UTF-8 with errors='replace'.
|
|
15
|
+
|
|
16
|
+
On Windows the console inherits the active code page (often cp1252 / cp850).
|
|
17
|
+
Python's ``TextIOWrapper.reconfigure`` switches to UTF-8 while keeping the
|
|
18
|
+
same underlying buffer, so Unicode decoration chars (→ • ✓ —) render
|
|
19
|
+
correctly on a real Windows console (Python uses the Unicode console API)
|
|
20
|
+
and degrade to ``?`` when redirected to a cp1252 pipe — never a crash.
|
|
21
|
+
|
|
22
|
+
The ``getattr`` guard + bare ``except Exception`` make this a safe no-op
|
|
23
|
+
on stream types that lack ``reconfigure`` (e.g. pytest's ``CaptureFixture``
|
|
24
|
+
or ``io.StringIO``).
|
|
25
|
+
"""
|
|
26
|
+
for stream in (sys.stdout, sys.stderr):
|
|
27
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
28
|
+
if reconfigure is not None:
|
|
29
|
+
try:
|
|
30
|
+
reconfigure(encoding="utf-8", errors="replace")
|
|
31
|
+
except Exception: # noqa: BLE001
|
|
32
|
+
pass
|
|
@@ -12,12 +12,15 @@ from rich import print as rprint
|
|
|
12
12
|
|
|
13
13
|
from dataclasses import asdict as _asdict
|
|
14
14
|
|
|
15
|
+
from ._console import _force_utf8_console
|
|
15
16
|
from .config import CONFIG, detect_project_slug
|
|
16
17
|
from .episodic import Episode
|
|
17
18
|
from .graph import FalkorStore
|
|
18
19
|
from .orchestrator import Pipeline, Retriever, list_projects, reset_all, reset_project
|
|
19
20
|
from .orchestrator import git_delta as _git_delta
|
|
20
21
|
|
|
22
|
+
_force_utf8_console()
|
|
23
|
+
|
|
21
24
|
|
|
22
25
|
def _graph_for(project: str | None) -> FalkorStore:
|
|
23
26
|
slug = project or detect_project_slug()
|
|
@@ -1269,6 +1272,14 @@ def update(
|
|
|
1269
1272
|
"--bleeding",
|
|
1270
1273
|
help="Install CLI from git+main instead of PyPI.",
|
|
1271
1274
|
),
|
|
1275
|
+
extras: str | None = typer.Option(
|
|
1276
|
+
None,
|
|
1277
|
+
"--extras",
|
|
1278
|
+
help=(
|
|
1279
|
+
"Comma list of optional extras to install (e.g. dotnet,hybrid), or 'none'."
|
|
1280
|
+
" Overrides the interactive prompt and CODEMEMORY_EXTRAS env var."
|
|
1281
|
+
),
|
|
1282
|
+
),
|
|
1272
1283
|
) -> None:
|
|
1273
1284
|
"""Smart-update code-memory: refresh only components already installed locally.
|
|
1274
1285
|
|
|
@@ -1278,10 +1289,12 @@ def update(
|
|
|
1278
1289
|
stay untouched — no prompts, no re-asking.
|
|
1279
1290
|
|
|
1280
1291
|
Use ``--check`` for a dry-run, ``--full`` to behave like a fresh install.
|
|
1292
|
+
Use ``--extras dotnet,hybrid`` to install optional Python extras, or
|
|
1293
|
+
``--extras none`` to suppress the interactive prompt.
|
|
1281
1294
|
"""
|
|
1282
1295
|
from .updater import run_update
|
|
1283
1296
|
|
|
1284
|
-
rc = run_update(check_only=check, full=full, bleeding=bleeding)
|
|
1297
|
+
rc = run_update(check_only=check, full=full, bleeding=bleeding, extras_override=extras)
|
|
1285
1298
|
raise typer.Exit(code=rc)
|
|
1286
1299
|
|
|
1287
1300
|
|
|
@@ -1984,6 +1984,9 @@ async def _run() -> None:
|
|
|
1984
1984
|
|
|
1985
1985
|
|
|
1986
1986
|
def main() -> None:
|
|
1987
|
+
from ._console import _force_utf8_console
|
|
1988
|
+
|
|
1989
|
+
_force_utf8_console()
|
|
1987
1990
|
logging.basicConfig(
|
|
1988
1991
|
level=os.environ.get("CODE_MEMORY_LOG_LEVEL", "INFO"),
|
|
1989
1992
|
format="%(asctime)s %(levelname)s %(name)s %(message)s",
|
|
@@ -464,12 +464,21 @@ def upgrade_npm_pkg(pkg: str = "code-memory-opencode") -> tuple[bool, str]:
|
|
|
464
464
|
# ---------- orchestrator ----------
|
|
465
465
|
|
|
466
466
|
|
|
467
|
-
def run_update(
|
|
467
|
+
def run_update(
|
|
468
|
+
*,
|
|
469
|
+
check_only: bool,
|
|
470
|
+
full: bool,
|
|
471
|
+
bleeding: bool,
|
|
472
|
+
extras_override: str | None = None,
|
|
473
|
+
) -> int:
|
|
468
474
|
"""Top-level entry point used by the CLI.
|
|
469
475
|
|
|
470
476
|
``check_only`` prints the plan and exits 0/1 based on whether anything
|
|
471
477
|
is behind. ``full`` re-runs the one-liner installer (curl … | bash).
|
|
472
478
|
Default is the smart path: upgrade-in-place only what is already present.
|
|
479
|
+
|
|
480
|
+
``extras_override`` is the value of the ``--extras`` CLI flag (highest
|
|
481
|
+
priority over the ``CODEMEMORY_EXTRAS`` env var).
|
|
473
482
|
"""
|
|
474
483
|
plan = build_plan()
|
|
475
484
|
_print_plan(plan)
|
|
@@ -511,6 +520,7 @@ def run_update(*, check_only: bool, full: bool, bleeding: bool) -> int:
|
|
|
511
520
|
ok, detail = upgrade_docker_images()
|
|
512
521
|
print(f" Docker stack: {'ok' if ok else 'skip'} — {detail}")
|
|
513
522
|
|
|
523
|
+
rc |= offer_missing_extras(plan.install_method, extras_override=extras_override)
|
|
514
524
|
return rc
|
|
515
525
|
|
|
516
526
|
|
|
@@ -525,6 +535,141 @@ def _print_plan(plan: UpdatePlan) -> None:
|
|
|
525
535
|
print(f" {mark} {c.name}{suffix}{state}")
|
|
526
536
|
|
|
527
537
|
|
|
538
|
+
def resolve_extras_selection(
|
|
539
|
+
*,
|
|
540
|
+
env_value: str | None,
|
|
541
|
+
is_tty: bool,
|
|
542
|
+
missing: list[str],
|
|
543
|
+
) -> tuple[list[str], str]:
|
|
544
|
+
"""Pure helper — no I/O — that decides which extras to install.
|
|
545
|
+
|
|
546
|
+
Returns ``(selected_names, mode)`` where ``mode`` is one of
|
|
547
|
+
``"env"``, ``"interactive"``, or ``"skip"``.
|
|
548
|
+
|
|
549
|
+
Priority:
|
|
550
|
+
1. ``env_value`` not None → parse comma list; ``"none"`` or empty → nothing.
|
|
551
|
+
2. ``is_tty`` True → caller must run the interactive loop (mode=``"interactive"``).
|
|
552
|
+
3. Otherwise → skip (non-interactive, no env override).
|
|
553
|
+
"""
|
|
554
|
+
if env_value is not None:
|
|
555
|
+
stripped = env_value.strip()
|
|
556
|
+
if stripped.lower() == "none" or stripped == "":
|
|
557
|
+
return [], "env"
|
|
558
|
+
names = [n.strip() for n in stripped.split(",") if n.strip()]
|
|
559
|
+
valid = [n for n in names if n in EXTRAS and n in missing]
|
|
560
|
+
return valid, "env"
|
|
561
|
+
if is_tty:
|
|
562
|
+
return [], "interactive"
|
|
563
|
+
return [], "skip"
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def _install_selected_extras(names: list[str], method: InstallMethod) -> int:
|
|
567
|
+
"""Install a list of extras; returns OR of per-extra return codes.
|
|
568
|
+
|
|
569
|
+
A single failed extra does not abort the rest — each failure sets the
|
|
570
|
+
nonzero bit in ``rc`` but installation continues.
|
|
571
|
+
"""
|
|
572
|
+
rc = 0
|
|
573
|
+
for name in names:
|
|
574
|
+
print()
|
|
575
|
+
print(f"Installing extra: {name}")
|
|
576
|
+
ok, detail = install_extra(name, method)
|
|
577
|
+
marker = "ok" if ok else "FAILED"
|
|
578
|
+
print(f" {marker} — {detail}")
|
|
579
|
+
rc |= 0 if ok else 1
|
|
580
|
+
return rc
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def offer_missing_extras(
|
|
584
|
+
method: InstallMethod,
|
|
585
|
+
*,
|
|
586
|
+
extras_override: str | None = None,
|
|
587
|
+
) -> int:
|
|
588
|
+
"""Offer to install extras that are not yet present.
|
|
589
|
+
|
|
590
|
+
Called automatically at the end of the smart ``run_update`` path.
|
|
591
|
+
Never blocks ``--check`` / ``--full`` (those return before reaching here).
|
|
592
|
+
|
|
593
|
+
Priority: ``extras_override`` (CLI ``--extras`` flag) >
|
|
594
|
+
``CODEMEMORY_EXTRAS`` env var > interactive prompt > skip silently.
|
|
595
|
+
"""
|
|
596
|
+
missing = [n for n in EXTRAS if not _python_module_present(EXTRAS[n]["module"])]
|
|
597
|
+
if not missing:
|
|
598
|
+
return 0
|
|
599
|
+
|
|
600
|
+
if method in ("unknown",):
|
|
601
|
+
print(
|
|
602
|
+
f"\033[2m hint: optional extras not yet installed: {', '.join(missing)}.\n"
|
|
603
|
+
" Run `code-memory extras` or set CODEMEMORY_EXTRAS=dotnet,hybrid.\033[0m"
|
|
604
|
+
)
|
|
605
|
+
return 0
|
|
606
|
+
|
|
607
|
+
# For editable installs, we need a valid pyproject.toml to install extras.
|
|
608
|
+
if method == "editable":
|
|
609
|
+
repo_root = Path(__file__).resolve().parents[2]
|
|
610
|
+
if not (repo_root / "pyproject.toml").exists():
|
|
611
|
+
print(
|
|
612
|
+
f"\033[2m hint: editable install without pyproject.toml at {repo_root};\n"
|
|
613
|
+
" cannot install optional extras automatically.\033[0m"
|
|
614
|
+
)
|
|
615
|
+
return 0
|
|
616
|
+
|
|
617
|
+
# Determine TTY status safely.
|
|
618
|
+
try:
|
|
619
|
+
is_tty = sys.stdin.isatty()
|
|
620
|
+
except Exception: # noqa: BLE001
|
|
621
|
+
is_tty = False
|
|
622
|
+
|
|
623
|
+
# CLI flag takes precedence over env var.
|
|
624
|
+
effective_env = extras_override if extras_override is not None else os.environ.get("CODEMEMORY_EXTRAS")
|
|
625
|
+
|
|
626
|
+
selected, mode = resolve_extras_selection(
|
|
627
|
+
env_value=effective_env,
|
|
628
|
+
is_tty=is_tty,
|
|
629
|
+
missing=missing,
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
if mode == "env":
|
|
633
|
+
if effective_env is not None:
|
|
634
|
+
# Warn about any names that were not in EXTRAS or already installed.
|
|
635
|
+
raw_names = [n.strip() for n in effective_env.split(",") if n.strip() and n.strip().lower() != "none"]
|
|
636
|
+
unknown = [n for n in raw_names if n not in EXTRAS]
|
|
637
|
+
already = [n for n in raw_names if n in EXTRAS and n not in missing]
|
|
638
|
+
for n in unknown:
|
|
639
|
+
print(f"\033[33m [warn]\033[0m unknown extra '{n}' (known: {', '.join(EXTRAS)})")
|
|
640
|
+
for n in already:
|
|
641
|
+
print(f" · {n} already installed — skipped")
|
|
642
|
+
if not selected:
|
|
643
|
+
return 0
|
|
644
|
+
return _install_selected_extras(selected, method)
|
|
645
|
+
|
|
646
|
+
if mode == "interactive":
|
|
647
|
+
todo: list[str] = []
|
|
648
|
+
print()
|
|
649
|
+
print("Optional extras available:")
|
|
650
|
+
for name in missing:
|
|
651
|
+
info = EXTRAS[name]
|
|
652
|
+
print(f" · {name} — not installed")
|
|
653
|
+
print(f" {info['desc']}")
|
|
654
|
+
try:
|
|
655
|
+
answer = input(f" Install `{name}`? [y/N] ").strip().lower()
|
|
656
|
+
except EOFError:
|
|
657
|
+
answer = ""
|
|
658
|
+
if answer in ("y", "yes"):
|
|
659
|
+
todo.append(name)
|
|
660
|
+
if not todo:
|
|
661
|
+
print("Nothing to install.")
|
|
662
|
+
return 0
|
|
663
|
+
return _install_selected_extras(todo, method)
|
|
664
|
+
|
|
665
|
+
# mode == "skip"
|
|
666
|
+
print(
|
|
667
|
+
f"\033[2m hint: optional extras not yet installed: {', '.join(missing)}.\n"
|
|
668
|
+
" Re-run with CODEMEMORY_EXTRAS=dotnet,hybrid or `code-memory extras`.\033[0m"
|
|
669
|
+
)
|
|
670
|
+
return 0
|
|
671
|
+
|
|
672
|
+
|
|
528
673
|
def install_extra(name: str, method: InstallMethod) -> tuple[bool, str]:
|
|
529
674
|
"""Install a single optional extra using whichever channel owns the CLI.
|
|
530
675
|
|