#
tokens: 49534/50000 2/625 files (page 40/47)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 40 of 47. Use http://codebase.md/doobidoo/mcp-memory-service?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .claude
│   ├── agents
│   │   ├── amp-bridge.md
│   │   ├── amp-pr-automator.md
│   │   ├── code-quality-guard.md
│   │   ├── gemini-pr-automator.md
│   │   └── github-release-manager.md
│   ├── settings.local.json.backup
│   └── settings.local.json.local
├── .commit-message
├── .dockerignore
├── .env.example
├── .env.sqlite.backup
├── .envnn#
├── .gitattributes
├── .github
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   ├── feature_request.yml
│   │   └── performance_issue.yml
│   ├── pull_request_template.md
│   └── workflows
│       ├── bridge-tests.yml
│       ├── CACHE_FIX.md
│       ├── claude-code-review.yml
│       ├── claude.yml
│       ├── cleanup-images.yml.disabled
│       ├── dev-setup-validation.yml
│       ├── docker-publish.yml
│       ├── LATEST_FIXES.md
│       ├── main-optimized.yml.disabled
│       ├── main.yml
│       ├── publish-and-test.yml
│       ├── README_OPTIMIZATION.md
│       ├── release-tag.yml.disabled
│       ├── release.yml
│       ├── roadmap-review-reminder.yml
│       ├── SECRET_CONDITIONAL_FIX.md
│       └── WORKFLOW_FIXES.md
├── .gitignore
├── .mcp.json.backup
├── .mcp.json.template
├── .pyscn
│   ├── .gitignore
│   └── reports
│       └── analyze_20251123_214224.html
├── AGENTS.md
├── archive
│   ├── deployment
│   │   ├── deploy_fastmcp_fixed.sh
│   │   ├── deploy_http_with_mcp.sh
│   │   └── deploy_mcp_v4.sh
│   ├── deployment-configs
│   │   ├── empty_config.yml
│   │   └── smithery.yaml
│   ├── development
│   │   └── test_fastmcp.py
│   ├── docs-removed-2025-08-23
│   │   ├── authentication.md
│   │   ├── claude_integration.md
│   │   ├── claude-code-compatibility.md
│   │   ├── claude-code-integration.md
│   │   ├── claude-code-quickstart.md
│   │   ├── claude-desktop-setup.md
│   │   ├── complete-setup-guide.md
│   │   ├── database-synchronization.md
│   │   ├── development
│   │   │   ├── autonomous-memory-consolidation.md
│   │   │   ├── CLEANUP_PLAN.md
│   │   │   ├── CLEANUP_README.md
│   │   │   ├── CLEANUP_SUMMARY.md
│   │   │   ├── dream-inspired-memory-consolidation.md
│   │   │   ├── hybrid-slm-memory-consolidation.md
│   │   │   ├── mcp-milestone.md
│   │   │   ├── multi-client-architecture.md
│   │   │   ├── test-results.md
│   │   │   └── TIMESTAMP_FIX_SUMMARY.md
│   │   ├── distributed-sync.md
│   │   ├── invocation_guide.md
│   │   ├── macos-intel.md
│   │   ├── master-guide.md
│   │   ├── mcp-client-configuration.md
│   │   ├── multi-client-server.md
│   │   ├── service-installation.md
│   │   ├── sessions
│   │   │   └── MCP_ENHANCEMENT_SESSION_MEMORY_v4.1.0.md
│   │   ├── UBUNTU_SETUP.md
│   │   ├── ubuntu.md
│   │   ├── windows-setup.md
│   │   └── windows.md
│   ├── docs-root-cleanup-2025-08-23
│   │   ├── AWESOME_LIST_SUBMISSION.md
│   │   ├── CLOUDFLARE_IMPLEMENTATION.md
│   │   ├── DOCUMENTATION_ANALYSIS.md
│   │   ├── DOCUMENTATION_CLEANUP_PLAN.md
│   │   ├── DOCUMENTATION_CONSOLIDATION_COMPLETE.md
│   │   ├── LITESTREAM_SETUP_GUIDE.md
│   │   ├── lm_studio_system_prompt.md
│   │   ├── PYTORCH_DOWNLOAD_FIX.md
│   │   └── README-ORIGINAL-BACKUP.md
│   ├── investigations
│   │   └── MACOS_HOOKS_INVESTIGATION.md
│   ├── litestream-configs-v6.3.0
│   │   ├── install_service.sh
│   │   ├── litestream_master_config_fixed.yml
│   │   ├── litestream_master_config.yml
│   │   ├── litestream_replica_config_fixed.yml
│   │   ├── litestream_replica_config.yml
│   │   ├── litestream_replica_simple.yml
│   │   ├── litestream-http.service
│   │   ├── litestream.service
│   │   └── requirements-cloudflare.txt
│   ├── release-notes
│   │   └── release-notes-v7.1.4.md
│   └── setup-development
│       ├── README.md
│       ├── setup_consolidation_mdns.sh
│       ├── STARTUP_SETUP_GUIDE.md
│       └── test_service.sh
├── CHANGELOG-HISTORIC.md
├── CHANGELOG.md
├── claude_commands
│   ├── memory-context.md
│   ├── memory-health.md
│   ├── memory-ingest-dir.md
│   ├── memory-ingest.md
│   ├── memory-recall.md
│   ├── memory-search.md
│   ├── memory-store.md
│   ├── README.md
│   └── session-start.md
├── claude-hooks
│   ├── config.json
│   ├── config.template.json
│   ├── CONFIGURATION.md
│   ├── core
│   │   ├── memory-retrieval.js
│   │   ├── mid-conversation.js
│   │   ├── session-end.js
│   │   ├── session-start.js
│   │   └── topic-change.js
│   ├── debug-pattern-test.js
│   ├── install_claude_hooks_windows.ps1
│   ├── install_hooks.py
│   ├── memory-mode-controller.js
│   ├── MIGRATION.md
│   ├── README-NATURAL-TRIGGERS.md
│   ├── README-phase2.md
│   ├── README.md
│   ├── simple-test.js
│   ├── statusline.sh
│   ├── test-adaptive-weights.js
│   ├── test-dual-protocol-hook.js
│   ├── test-mcp-hook.js
│   ├── test-natural-triggers.js
│   ├── test-recency-scoring.js
│   ├── tests
│   │   ├── integration-test.js
│   │   ├── phase2-integration-test.js
│   │   ├── test-code-execution.js
│   │   ├── test-cross-session.json
│   │   ├── test-session-tracking.json
│   │   └── test-threading.json
│   ├── utilities
│   │   ├── adaptive-pattern-detector.js
│   │   ├── context-formatter.js
│   │   ├── context-shift-detector.js
│   │   ├── conversation-analyzer.js
│   │   ├── dynamic-context-updater.js
│   │   ├── git-analyzer.js
│   │   ├── mcp-client.js
│   │   ├── memory-client.js
│   │   ├── memory-scorer.js
│   │   ├── performance-manager.js
│   │   ├── project-detector.js
│   │   ├── session-tracker.js
│   │   ├── tiered-conversation-monitor.js
│   │   └── version-checker.js
│   └── WINDOWS-SESSIONSTART-BUG.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Development-Sprint-November-2025.md
├── docs
│   ├── amp-cli-bridge.md
│   ├── api
│   │   ├── code-execution-interface.md
│   │   ├── memory-metadata-api.md
│   │   ├── PHASE1_IMPLEMENTATION_SUMMARY.md
│   │   ├── PHASE2_IMPLEMENTATION_SUMMARY.md
│   │   ├── PHASE2_REPORT.md
│   │   └── tag-standardization.md
│   ├── architecture
│   │   ├── search-enhancement-spec.md
│   │   └── search-examples.md
│   ├── architecture.md
│   ├── archive
│   │   └── obsolete-workflows
│   │       ├── load_memory_context.md
│   │       └── README.md
│   ├── assets
│   │   └── images
│   │       ├── dashboard-v3.3.0-preview.png
│   │       ├── memory-awareness-hooks-example.png
│   │       ├── project-infographic.svg
│   │       └── README.md
│   ├── CLAUDE_CODE_QUICK_REFERENCE.md
│   ├── cloudflare-setup.md
│   ├── deployment
│   │   ├── docker.md
│   │   ├── dual-service.md
│   │   ├── production-guide.md
│   │   └── systemd-service.md
│   ├── development
│   │   ├── ai-agent-instructions.md
│   │   ├── code-quality
│   │   │   ├── phase-2a-completion.md
│   │   │   ├── phase-2a-handle-get-prompt.md
│   │   │   ├── phase-2a-index.md
│   │   │   ├── phase-2a-install-package.md
│   │   │   └── phase-2b-session-summary.md
│   │   ├── code-quality-workflow.md
│   │   ├── dashboard-workflow.md
│   │   ├── issue-management.md
│   │   ├── pr-review-guide.md
│   │   ├── refactoring-notes.md
│   │   ├── release-checklist.md
│   │   └── todo-tracker.md
│   ├── docker-optimized-build.md
│   ├── document-ingestion.md
│   ├── DOCUMENTATION_AUDIT.md
│   ├── enhancement-roadmap-issue-14.md
│   ├── examples
│   │   ├── analysis-scripts.js
│   │   ├── maintenance-session-example.md
│   │   ├── memory-distribution-chart.jsx
│   │   └── tag-schema.json
│   ├── first-time-setup.md
│   ├── glama-deployment.md
│   ├── guides
│   │   ├── advanced-command-examples.md
│   │   ├── chromadb-migration.md
│   │   ├── commands-vs-mcp-server.md
│   │   ├── mcp-enhancements.md
│   │   ├── mdns-service-discovery.md
│   │   ├── memory-consolidation-guide.md
│   │   ├── migration.md
│   │   ├── scripts.md
│   │   └── STORAGE_BACKENDS.md
│   ├── HOOK_IMPROVEMENTS.md
│   ├── hooks
│   │   └── phase2-code-execution-migration.md
│   ├── http-server-management.md
│   ├── ide-compatability.md
│   ├── IMAGE_RETENTION_POLICY.md
│   ├── images
│   │   └── dashboard-placeholder.md
│   ├── implementation
│   │   ├── health_checks.md
│   │   └── performance.md
│   ├── IMPLEMENTATION_PLAN_HTTP_SSE.md
│   ├── integration
│   │   ├── homebrew.md
│   │   └── multi-client.md
│   ├── integrations
│   │   ├── gemini.md
│   │   ├── groq-bridge.md
│   │   ├── groq-integration-summary.md
│   │   └── groq-model-comparison.md
│   ├── integrations.md
│   ├── legacy
│   │   └── dual-protocol-hooks.md
│   ├── LM_STUDIO_COMPATIBILITY.md
│   ├── maintenance
│   │   └── memory-maintenance.md
│   ├── mastery
│   │   ├── api-reference.md
│   │   ├── architecture-overview.md
│   │   ├── configuration-guide.md
│   │   ├── local-setup-and-run.md
│   │   ├── testing-guide.md
│   │   └── troubleshooting.md
│   ├── migration
│   │   └── code-execution-api-quick-start.md
│   ├── natural-memory-triggers
│   │   ├── cli-reference.md
│   │   ├── installation-guide.md
│   │   └── performance-optimization.md
│   ├── oauth-setup.md
│   ├── pr-graphql-integration.md
│   ├── quick-setup-cloudflare-dual-environment.md
│   ├── README.md
│   ├── remote-configuration-wiki-section.md
│   ├── research
│   │   ├── code-execution-interface-implementation.md
│   │   └── code-execution-interface-summary.md
│   ├── ROADMAP.md
│   ├── sqlite-vec-backend.md
│   ├── statistics
│   │   ├── charts
│   │   │   ├── activity_patterns.png
│   │   │   ├── contributors.png
│   │   │   ├── growth_trajectory.png
│   │   │   ├── monthly_activity.png
│   │   │   └── october_sprint.png
│   │   ├── data
│   │   │   ├── activity_by_day.csv
│   │   │   ├── activity_by_hour.csv
│   │   │   ├── contributors.csv
│   │   │   └── monthly_activity.csv
│   │   ├── generate_charts.py
│   │   └── REPOSITORY_STATISTICS.md
│   ├── technical
│   │   ├── development.md
│   │   ├── memory-migration.md
│   │   ├── migration-log.md
│   │   ├── sqlite-vec-embedding-fixes.md
│   │   └── tag-storage.md
│   ├── testing
│   │   └── regression-tests.md
│   ├── testing-cloudflare-backend.md
│   ├── troubleshooting
│   │   ├── cloudflare-api-token-setup.md
│   │   ├── cloudflare-authentication.md
│   │   ├── general.md
│   │   ├── hooks-quick-reference.md
│   │   ├── pr162-schema-caching-issue.md
│   │   ├── session-end-hooks.md
│   │   └── sync-issues.md
│   └── tutorials
│       ├── advanced-techniques.md
│       ├── data-analysis.md
│       └── demo-session-walkthrough.md
├── examples
│   ├── claude_desktop_config_template.json
│   ├── claude_desktop_config_windows.json
│   ├── claude-desktop-http-config.json
│   ├── config
│   │   └── claude_desktop_config.json
│   ├── http-mcp-bridge.js
│   ├── memory_export_template.json
│   ├── README.md
│   ├── setup
│   │   └── setup_multi_client_complete.py
│   └── start_https_example.sh
├── install_service.py
├── install.py
├── LICENSE
├── NOTICE
├── pyproject.toml
├── pytest.ini
├── README.md
├── run_server.py
├── scripts
│   ├── .claude
│   │   └── settings.local.json
│   ├── archive
│   │   └── check_missing_timestamps.py
│   ├── backup
│   │   ├── backup_memories.py
│   │   ├── backup_sqlite_vec.sh
│   │   ├── export_distributable_memories.sh
│   │   └── restore_memories.py
│   ├── benchmarks
│   │   ├── benchmark_code_execution_api.py
│   │   ├── benchmark_hybrid_sync.py
│   │   └── benchmark_server_caching.py
│   ├── database
│   │   ├── analyze_sqlite_vec_db.py
│   │   ├── check_sqlite_vec_status.py
│   │   ├── db_health_check.py
│   │   └── simple_timestamp_check.py
│   ├── development
│   │   ├── debug_server_initialization.py
│   │   ├── find_orphaned_files.py
│   │   ├── fix_mdns.sh
│   │   ├── fix_sitecustomize.py
│   │   ├── remote_ingest.sh
│   │   ├── setup-git-merge-drivers.sh
│   │   ├── uv-lock-merge.sh
│   │   └── verify_hybrid_sync.py
│   ├── hooks
│   │   └── pre-commit
│   ├── installation
│   │   ├── install_linux_service.py
│   │   ├── install_macos_service.py
│   │   ├── install_uv.py
│   │   ├── install_windows_service.py
│   │   ├── install.py
│   │   ├── setup_backup_cron.sh
│   │   ├── setup_claude_mcp.sh
│   │   └── setup_cloudflare_resources.py
│   ├── linux
│   │   ├── service_status.sh
│   │   ├── start_service.sh
│   │   ├── stop_service.sh
│   │   ├── uninstall_service.sh
│   │   └── view_logs.sh
│   ├── maintenance
│   │   ├── assign_memory_types.py
│   │   ├── check_memory_types.py
│   │   ├── cleanup_corrupted_encoding.py
│   │   ├── cleanup_memories.py
│   │   ├── cleanup_organize.py
│   │   ├── consolidate_memory_types.py
│   │   ├── consolidation_mappings.json
│   │   ├── delete_orphaned_vectors_fixed.py
│   │   ├── fast_cleanup_duplicates_with_tracking.sh
│   │   ├── find_all_duplicates.py
│   │   ├── find_cloudflare_duplicates.py
│   │   ├── find_duplicates.py
│   │   ├── memory-types.md
│   │   ├── README.md
│   │   ├── recover_timestamps_from_cloudflare.py
│   │   ├── regenerate_embeddings.py
│   │   ├── repair_malformed_tags.py
│   │   ├── repair_memories.py
│   │   ├── repair_sqlite_vec_embeddings.py
│   │   ├── repair_zero_embeddings.py
│   │   ├── restore_from_json_export.py
│   │   └── scan_todos.sh
│   ├── migration
│   │   ├── cleanup_mcp_timestamps.py
│   │   ├── legacy
│   │   │   └── migrate_chroma_to_sqlite.py
│   │   ├── mcp-migration.py
│   │   ├── migrate_sqlite_vec_embeddings.py
│   │   ├── migrate_storage.py
│   │   ├── migrate_tags.py
│   │   ├── migrate_timestamps.py
│   │   ├── migrate_to_cloudflare.py
│   │   ├── migrate_to_sqlite_vec.py
│   │   ├── migrate_v5_enhanced.py
│   │   ├── TIMESTAMP_CLEANUP_README.md
│   │   └── verify_mcp_timestamps.py
│   ├── pr
│   │   ├── amp_collect_results.sh
│   │   ├── amp_detect_breaking_changes.sh
│   │   ├── amp_generate_tests.sh
│   │   ├── amp_pr_review.sh
│   │   ├── amp_quality_gate.sh
│   │   ├── amp_suggest_fixes.sh
│   │   ├── auto_review.sh
│   │   ├── detect_breaking_changes.sh
│   │   ├── generate_tests.sh
│   │   ├── lib
│   │   │   └── graphql_helpers.sh
│   │   ├── quality_gate.sh
│   │   ├── resolve_threads.sh
│   │   ├── run_pyscn_analysis.sh
│   │   ├── run_quality_checks.sh
│   │   ├── thread_status.sh
│   │   └── watch_reviews.sh
│   ├── quality
│   │   ├── fix_dead_code_install.sh
│   │   ├── phase1_dead_code_analysis.md
│   │   ├── phase2_complexity_analysis.md
│   │   ├── README_PHASE1.md
│   │   ├── README_PHASE2.md
│   │   ├── track_pyscn_metrics.sh
│   │   └── weekly_quality_review.sh
│   ├── README.md
│   ├── run
│   │   ├── run_mcp_memory.sh
│   │   ├── run-with-uv.sh
│   │   └── start_sqlite_vec.sh
│   ├── run_memory_server.py
│   ├── server
│   │   ├── check_http_server.py
│   │   ├── check_server_health.py
│   │   ├── memory_offline.py
│   │   ├── preload_models.py
│   │   ├── run_http_server.py
│   │   ├── run_memory_server.py
│   │   ├── start_http_server.bat
│   │   └── start_http_server.sh
│   ├── service
│   │   ├── deploy_dual_services.sh
│   │   ├── install_http_service.sh
│   │   ├── mcp-memory-http.service
│   │   ├── mcp-memory.service
│   │   ├── memory_service_manager.sh
│   │   ├── service_control.sh
│   │   ├── service_utils.py
│   │   └── update_service.sh
│   ├── sync
│   │   ├── check_drift.py
│   │   ├── claude_sync_commands.py
│   │   ├── export_memories.py
│   │   ├── import_memories.py
│   │   ├── litestream
│   │   │   ├── apply_local_changes.sh
│   │   │   ├── enhanced_memory_store.sh
│   │   │   ├── init_staging_db.sh
│   │   │   ├── io.litestream.replication.plist
│   │   │   ├── manual_sync.sh
│   │   │   ├── memory_sync.sh
│   │   │   ├── pull_remote_changes.sh
│   │   │   ├── push_to_remote.sh
│   │   │   ├── README.md
│   │   │   ├── resolve_conflicts.sh
│   │   │   ├── setup_local_litestream.sh
│   │   │   ├── setup_remote_litestream.sh
│   │   │   ├── staging_db_init.sql
│   │   │   ├── stash_local_changes.sh
│   │   │   ├── sync_from_remote_noconfig.sh
│   │   │   └── sync_from_remote.sh
│   │   ├── README.md
│   │   ├── safe_cloudflare_update.sh
│   │   ├── sync_memory_backends.py
│   │   └── sync_now.py
│   ├── testing
│   │   ├── run_complete_test.py
│   │   ├── run_memory_test.sh
│   │   ├── simple_test.py
│   │   ├── test_cleanup_logic.py
│   │   ├── test_cloudflare_backend.py
│   │   ├── test_docker_functionality.py
│   │   ├── test_installation.py
│   │   ├── test_mdns.py
│   │   ├── test_memory_api.py
│   │   ├── test_memory_simple.py
│   │   ├── test_migration.py
│   │   ├── test_search_api.py
│   │   ├── test_sqlite_vec_embeddings.py
│   │   ├── test_sse_events.py
│   │   ├── test-connection.py
│   │   └── test-hook.js
│   ├── utils
│   │   ├── claude_commands_utils.py
│   │   ├── generate_personalized_claude_md.sh
│   │   ├── groq
│   │   ├── groq_agent_bridge.py
│   │   ├── list-collections.py
│   │   ├── memory_wrapper_uv.py
│   │   ├── query_memories.py
│   │   ├── smithery_wrapper.py
│   │   ├── test_groq_bridge.sh
│   │   └── uv_wrapper.py
│   └── validation
│       ├── check_dev_setup.py
│       ├── check_documentation_links.py
│       ├── diagnose_backend_config.py
│       ├── validate_configuration_complete.py
│       ├── validate_memories.py
│       ├── validate_migration.py
│       ├── validate_timestamp_integrity.py
│       ├── verify_environment.py
│       ├── verify_pytorch_windows.py
│       └── verify_torch.py
├── SECURITY.md
├── selective_timestamp_recovery.py
├── SPONSORS.md
├── src
│   └── mcp_memory_service
│       ├── __init__.py
│       ├── api
│       │   ├── __init__.py
│       │   ├── client.py
│       │   ├── operations.py
│       │   ├── sync_wrapper.py
│       │   └── types.py
│       ├── backup
│       │   ├── __init__.py
│       │   └── scheduler.py
│       ├── cli
│       │   ├── __init__.py
│       │   ├── ingestion.py
│       │   ├── main.py
│       │   └── utils.py
│       ├── config.py
│       ├── consolidation
│       │   ├── __init__.py
│       │   ├── associations.py
│       │   ├── base.py
│       │   ├── clustering.py
│       │   ├── compression.py
│       │   ├── consolidator.py
│       │   ├── decay.py
│       │   ├── forgetting.py
│       │   ├── health.py
│       │   └── scheduler.py
│       ├── dependency_check.py
│       ├── discovery
│       │   ├── __init__.py
│       │   ├── client.py
│       │   └── mdns_service.py
│       ├── embeddings
│       │   ├── __init__.py
│       │   └── onnx_embeddings.py
│       ├── ingestion
│       │   ├── __init__.py
│       │   ├── base.py
│       │   ├── chunker.py
│       │   ├── csv_loader.py
│       │   ├── json_loader.py
│       │   ├── pdf_loader.py
│       │   ├── registry.py
│       │   ├── semtools_loader.py
│       │   └── text_loader.py
│       ├── lm_studio_compat.py
│       ├── mcp_server.py
│       ├── models
│       │   ├── __init__.py
│       │   └── memory.py
│       ├── server.py
│       ├── services
│       │   ├── __init__.py
│       │   └── memory_service.py
│       ├── storage
│       │   ├── __init__.py
│       │   ├── base.py
│       │   ├── cloudflare.py
│       │   ├── factory.py
│       │   ├── http_client.py
│       │   ├── hybrid.py
│       │   └── sqlite_vec.py
│       ├── sync
│       │   ├── __init__.py
│       │   ├── exporter.py
│       │   ├── importer.py
│       │   └── litestream_config.py
│       ├── utils
│       │   ├── __init__.py
│       │   ├── cache_manager.py
│       │   ├── content_splitter.py
│       │   ├── db_utils.py
│       │   ├── debug.py
│       │   ├── document_processing.py
│       │   ├── gpu_detection.py
│       │   ├── hashing.py
│       │   ├── http_server_manager.py
│       │   ├── port_detection.py
│       │   ├── system_detection.py
│       │   └── time_parser.py
│       └── web
│           ├── __init__.py
│           ├── api
│           │   ├── __init__.py
│           │   ├── analytics.py
│           │   ├── backup.py
│           │   ├── consolidation.py
│           │   ├── documents.py
│           │   ├── events.py
│           │   ├── health.py
│           │   ├── manage.py
│           │   ├── mcp.py
│           │   ├── memories.py
│           │   ├── search.py
│           │   └── sync.py
│           ├── app.py
│           ├── dependencies.py
│           ├── oauth
│           │   ├── __init__.py
│           │   ├── authorization.py
│           │   ├── discovery.py
│           │   ├── middleware.py
│           │   ├── models.py
│           │   ├── registration.py
│           │   └── storage.py
│           ├── sse.py
│           └── static
│               ├── app.js
│               ├── index.html
│               ├── README.md
│               ├── sse_test.html
│               └── style.css
├── start_http_debug.bat
├── start_http_server.sh
├── test_document.txt
├── test_version_checker.js
├── tests
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   ├── test_compact_types.py
│   │   └── test_operations.py
│   ├── bridge
│   │   ├── mock_responses.js
│   │   ├── package-lock.json
│   │   ├── package.json
│   │   └── test_http_mcp_bridge.js
│   ├── conftest.py
│   ├── consolidation
│   │   ├── __init__.py
│   │   ├── conftest.py
│   │   ├── test_associations.py
│   │   ├── test_clustering.py
│   │   ├── test_compression.py
│   │   ├── test_consolidator.py
│   │   ├── test_decay.py
│   │   └── test_forgetting.py
│   ├── contracts
│   │   └── api-specification.yml
│   ├── integration
│   │   ├── package-lock.json
│   │   ├── package.json
│   │   ├── test_api_key_fallback.py
│   │   ├── test_api_memories_chronological.py
│   │   ├── test_api_tag_time_search.py
│   │   ├── test_api_with_memory_service.py
│   │   ├── test_bridge_integration.js
│   │   ├── test_cli_interfaces.py
│   │   ├── test_cloudflare_connection.py
│   │   ├── test_concurrent_clients.py
│   │   ├── test_data_serialization_consistency.py
│   │   ├── test_http_server_startup.py
│   │   ├── test_mcp_memory.py
│   │   ├── test_mdns_integration.py
│   │   ├── test_oauth_basic_auth.py
│   │   ├── test_oauth_flow.py
│   │   ├── test_server_handlers.py
│   │   └── test_store_memory.py
│   ├── performance
│   │   ├── test_background_sync.py
│   │   └── test_hybrid_live.py
│   ├── README.md
│   ├── smithery
│   │   └── test_smithery.py
│   ├── sqlite
│   │   └── simple_sqlite_vec_test.py
│   ├── test_client.py
│   ├── test_content_splitting.py
│   ├── test_database.py
│   ├── test_hybrid_cloudflare_limits.py
│   ├── test_hybrid_storage.py
│   ├── test_memory_ops.py
│   ├── test_semantic_search.py
│   ├── test_sqlite_vec_storage.py
│   ├── test_time_parser.py
│   ├── test_timestamp_preservation.py
│   ├── timestamp
│   │   ├── test_hook_vs_manual_storage.py
│   │   ├── test_issue99_final_validation.py
│   │   ├── test_search_retrieval_inconsistency.py
│   │   ├── test_timestamp_issue.py
│   │   └── test_timestamp_simple.py
│   └── unit
│       ├── conftest.py
│       ├── test_cloudflare_storage.py
│       ├── test_csv_loader.py
│       ├── test_fastapi_dependencies.py
│       ├── test_import.py
│       ├── test_json_loader.py
│       ├── test_mdns_simple.py
│       ├── test_mdns.py
│       ├── test_memory_service.py
│       ├── test_memory.py
│       ├── test_semtools_loader.py
│       ├── test_storage_interface_compatibility.py
│       └── test_tag_time_filtering.py
├── tools
│   ├── docker
│   │   ├── DEPRECATED.md
│   │   ├── docker-compose.http.yml
│   │   ├── docker-compose.pythonpath.yml
│   │   ├── docker-compose.standalone.yml
│   │   ├── docker-compose.uv.yml
│   │   ├── docker-compose.yml
│   │   ├── docker-entrypoint-persistent.sh
│   │   ├── docker-entrypoint-unified.sh
│   │   ├── docker-entrypoint.sh
│   │   ├── Dockerfile
│   │   ├── Dockerfile.glama
│   │   ├── Dockerfile.slim
│   │   ├── README.md
│   │   └── test-docker-modes.sh
│   └── README.md
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/src/mcp_memory_service/web/static/index.html:
--------------------------------------------------------------------------------

```html
   1 | <!DOCTYPE html>
   2 | <html lang="en">
   3 | <head>
   4 |     <meta charset="UTF-8">
   5 |     <meta name="viewport" content="width=device-width, initial-scale=1.0">
   6 |     <title>MCP Memory Service - Dashboard</title>
   7 |     <link rel="stylesheet" href="/static/style.css">
   8 |     <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🧠</text></svg>">
   9 | </head>
  10 | <body>
  11 |     <!-- Main Application Container -->
  12 |     <div id="app" class="app-container">
  13 | 
  14 |         <!-- Header with Navigation -->
  15 |         <header class="app-header">
  16 |             <div class="header-content">
  17 |                 <div class="logo-section">
  18 |                     <h1 class="app-title">🧠 MCP Memory</h1>
  19 |                     <span id="versionBadge" class="version-badge">Loading...</span>
  20 |                 </div>
  21 | 
  22 |                 <!-- SVG Icon Definitions -->
  23 |                 <svg style="display: none;" aria-hidden="true">
  24 |                     <defs>
  25 |                         <symbol id="info-icon" viewBox="0 0 24 24">
  26 |                             <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/>
  27 |                             <path d="M12 8v.01M12 12v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
  28 |                         </symbol>
  29 |                     </defs>
  30 |                 </svg>
  31 | 
  32 |                 <!-- Quick Search Bar -->
  33 |                 <div class="search-section">
  34 |                     <div class="search-container">
  35 |                         <input type="text"
  36 |                                id="quickSearch"
  37 |                                class="search-input"
  38 |                                placeholder="🔍 Search your memories..."
  39 |                                autocomplete="off">
  40 |                         <button class="search-btn" type="button" aria-label="Search">
  41 |                             <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
  42 |                                 <path d="M21.71 20.29L18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a1 1 0 0 0 1.42-1.42zM11 18a7 7 0 1 1 7-7 7 7 0 0 1-7 7z"/>
  43 |                             </svg>
  44 |                         </button>
  45 |                     </div>
  46 |                 </div>
  47 | 
  48 |                 <!-- Action Buttons -->
  49 |                 <div class="action-buttons">
  50 |                     <button id="addMemoryBtn" class="btn btn-primary" title="Add New Memory">
  51 |                         <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
  52 |                             <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
  53 |                         </svg>
  54 |                         <span class="btn-text">Add Memory</span>
  55 |                     </button>
  56 |                     <button id="themeToggleBtn" class="btn btn-secondary" title="Toggle Dark Mode">
  57 |                         <svg id="sunIcon" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
  58 |                             <circle cx="12" cy="12" r="5"/>
  59 |                             <line x1="12" y1="1" x2="12" y2="3"/>
  60 |                             <line x1="12" y1="21" x2="12" y2="23"/>
  61 |                             <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
  62 |                             <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
  63 |                             <line x1="1" y1="12" x2="3" y2="12"/>
  64 |                             <line x1="21" y1="12" x2="23" y2="12"/>
  65 |                             <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
  66 |                             <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
  67 |                         </svg>
  68 |                         <svg id="moonIcon" class="hidden" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
  69 |                             <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
  70 |                         </svg>
  71 |                     </button>
  72 |                     <button id="settingsBtn" class="btn btn-secondary" title="Settings">
  73 |                         <svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
  74 |                             <circle cx="12" cy="12" r="3"/>
  75 |                             <path d="M12 1v6m0 6v10M1 12h6m6 0h10"/>
  76 |                             <path d="M4.22 4.22l4.24 4.24m7.08 7.08l4.24 4.24M4.22 19.78l4.24-4.24m7.08-7.08l4.24-4.24"/>
  77 |                         </svg>
  78 |                     </button>
  79 |                 </div>
  80 |             </div>
  81 |         </header>
  82 | 
  83 |         <!-- Main Navigation -->
  84 |         <nav class="main-nav">
  85 |             <div class="nav-container">
  86 |                 <button class="nav-item active" data-view="dashboard">
  87 |                     <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
  88 |                         <path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/>
  89 |                     </svg>
  90 |                     Dashboard
  91 |                 </button>
  92 |                 <button class="nav-item" data-view="search">
  93 |                     <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
  94 |                         <path d="M21.71 20.29L18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a1 1 0 0 0 1.42-1.42zM11 18a7 7 0 1 1 7-7 7 7 0 0 1-7 7z"/>
  95 |                     </svg>
  96 |                     Search
  97 |                 </button>
  98 |                 <button class="nav-item" data-view="browse">
  99 |                 <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 100 |                 <path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z"/>
 101 |                 </svg>
 102 |                 Browse
 103 |                 </button>
 104 |                 <button class="nav-item" data-view="documents">
 105 |                     <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 106 |                         <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
 107 |                     </svg>
 108 |                     Documents
 109 |                 </button>
 110 |                 <button class="nav-item" data-view="manage">
 111 |                     <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 112 |                         <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
 113 |                     </svg>
 114 |                     Manage
 115 |                 </button>
 116 |                 <button class="nav-item" data-view="analytics">
 117 |                     <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 118 |                         <path d="M5 9.2h3V19H5zM10.6 5h2.8v14h-2.8zm5.6 8H19v6h-2.8z"/>
 119 |                     </svg>
 120 |                     Analytics
 121 |                 </button>
 122 |                 <button class="nav-item" data-view="apiDocs">
 123 |                     <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 124 |                         <path d="M14,17H7V15H14M17,13H7V11H17M17,9H7V7H17M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z"/>
 125 |                     </svg>
 126 |                     API Docs
 127 |                 </button>
 128 |             </div>
 129 |         </nav>
 130 | 
 131 |         <!-- Main Content Area -->
 132 |         <main class="main-content">
 133 |             <!-- Dashboard View -->
 134 |             <div id="dashboardView" class="view-container active">
 135 |                 <div class="dashboard-grid">
 136 |                     <!-- Welcome Section -->
 137 |                     <section class="welcome-card">
 138 |                         <h2>Welcome to your Memory Dashboard</h2>
 139 |                         <p>Manage your AI memories with semantic search, real-time updates, and intelligent organization.</p>
 140 |                         <div class="quick-stats">
 141 |                             <div class="stat-item">
 142 |                                 <span class="stat-number" id="totalMemories">—</span>
 143 |                                 <span class="stat-label">Total Memories</span>
 144 |                             </div>
 145 |                             <div class="stat-item">
 146 |                                 <span class="stat-number" id="recentMemories">—</span>
 147 |                                 <span class="stat-label">This Week</span>
 148 |                             </div>
 149 |                             <div class="stat-item">
 150 |                                 <span class="stat-number" id="uniqueTags">—</span>
 151 |                                 <span class="stat-label">Tags</span>
 152 |                             </div>
 153 |                         </div>
 154 |                     </section>
 155 | 
 156 |                     <!-- Recent Memories -->
 157 |                     <section class="recent-memories">
 158 |                         <h3>Recent Memories</h3>
 159 |                         <div id="recentMemoriesList" class="memory-list">
 160 |                             <!-- Dynamic content will be loaded here -->
 161 |                         </div>
 162 |                     </section>
 163 | 
 164 |                     <!-- Quick Actions -->
 165 |                     <section class="quick-actions">
 166 |                         <h3>Quick Actions</h3>
 167 |                         <div class="action-grid">
 168 |                             <button class="action-card" data-action="quick-search">
 169 |                                 <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
 170 |                                     <path d="M21.71 20.29L18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a1 1 0 0 0 1.42-1.42zM11 18a7 7 0 1 1 7-7 7 7 0 0 1-7 7z"/>
 171 |                                 </svg>
 172 |                                 <span>Advanced Search</span>
 173 |                             </button>
 174 |                             <button class="action-card" data-action="add-memory">
 175 |                                 <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
 176 |                                     <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
 177 |                                 </svg>
 178 |                                 <span>Add Memory</span>
 179 |                             </button>
 180 |                             <button class="action-card" data-action="browse-tags">
 181 |                                 <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
 182 |                                     <path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/>
 183 |                                 </svg>
 184 |                                 <span>Browse Tags</span>
 185 |                             </button>
 186 |                             <button class="action-card" data-action="export-data">
 187 |                                 <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
 188 |                                     <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
 189 |                                 </svg>
 190 |                                 <span>Export Data</span>
 191 |                             </button>
 192 |                         </div>
 193 | 
 194 |                         <!-- Compact Sync Control (Hybrid Mode Only) -->
 195 |                         <div id="syncControl" class="sync-control-compact">
 196 |                             <div class="sync-row">
 197 |                                 <div class="sync-status">
 198 |                                     <span id="syncStatusDot" class="sync-dot"></span>
 199 |                                     <span id="syncStatusText" class="sync-text-sm">Checking...</span>
 200 |                                 </div>
 201 |                                 <span id="syncProgress" class="sync-progress-sm"></span>
 202 |                                 <div class="sync-buttons-sm">
 203 |                                     <button type="button" id="pauseSyncButton" class="btn-icon-sm" title="Pause sync">
 204 |                                         <svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24">
 205 |                                             <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
 206 |                                         </svg>
 207 |                                     </button>
 208 |                                     <button type="button" id="resumeSyncButton" class="btn-icon-sm" title="Resume sync">
 209 |                                         <svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24">
 210 |                                             <path d="M8 5v14l11-7z"/>
 211 |                                         </svg>
 212 |                                     </button>
 213 |                                     <button type="button" id="forceSyncButton" class="btn-icon-sm btn-icon-primary" title="Sync now">
 214 |                                         <svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24">
 215 |                                             <path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/>
 216 |                                         </svg>
 217 |                                     </button>
 218 |                                 </div>
 219 |                             </div>
 220 |                         </div>
 221 |                     </section>
 222 |                 </div>
 223 |             </div>
 224 | 
 225 |             <!-- Search View -->
 226 |             <div id="searchView" class="view-container">
 227 |                 <div class="search-layout">
 228 |                     <!-- Advanced Search Panel -->
 229 |                     <aside class="search-filters">
 230 |                         <div class="filters-header">
 231 |                             <h3>Search Filters
 232 |                                 <span class="tooltip" title="Filters work together: combine tags, dates, and types to narrow your search">
 233 |                                     <svg width="16" height="16" fill="currentColor"><use href="#info-icon"/></svg>
 234 |                                 </span>
 235 |                             </h3>
 236 |                             <div class="mode-toggle-compact">
 237 |                                 <label class="toggle-switch">
 238 |                                     <input type="checkbox" id="liveSearchToggle" checked>
 239 |                                     <span class="slider"></span>
 240 |                                 </label>
 241 |                                 <span class="tooltip" title="Toggle between live search (updates as you type) and manual search mode">
 242 |                                     <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
 243 |                                         <path d="M13 2L3 14h8l-1 8 10-12h-8l1-8z" fill="currentColor"/>
 244 |                                     </svg>
 245 |                                 </span>
 246 |                             </div>
 247 |                         </div>
 248 | 
 249 |                         <!-- Search Mode Indicator -->
 250 |                         <div class="search-mode-indicator">
 251 |                             <span class="mode-status">
 252 |                                 <span id="searchModeText">Live Search</span> mode
 253 |                             </span>
 254 |                         </div>
 255 | 
 256 |                         <div class="filter-section">
 257 |                             <label for="tagFilter">Tags
 258 |                                 <span class="tooltip" title="Enter tags separated by commas (e.g., work, coding, important)">
 259 |                                     <svg width="16" height="16" fill="currentColor"><use href="#info-icon"/></svg>
 260 |                                 </span>
 261 |                             </label>
 262 |                             <input type="text" id="tagFilter" placeholder="e.g., work, coding, important">
 263 |                             <small class="help-text">Separate multiple tags with commas</small>
 264 |                         </div>
 265 | 
 266 |                         <div class="filter-section">
 267 |                             <label for="dateFilter">Date Range
 268 |                                 <span class="tooltip" title="Filter memories by when they were created">
 269 |                                     <svg width="16" height="16" fill="currentColor"><use href="#info-icon"/></svg>
 270 |                                 </span>
 271 |                             </label>
 272 |                             <select id="dateFilter">
 273 |                                 <option value="">All time</option>
 274 |                                 <option value="today">Today</option>
 275 |                                 <option value="yesterday">Yesterday</option>
 276 |                                 <option value="week">This week</option>
 277 |                                 <option value="month">This month</option>
 278 |                                 <option value="quarter">This quarter</option>
 279 |                                 <option value="year">This year</option>
 280 |                             </select>
 281 |                             <small class="help-text">Select a time period to filter memories</small>
 282 |                         </div>
 283 | 
 284 |                         <div class="filter-section">
 285 |                             <label for="typeFilter">Content Type
 286 |                                 <span class="tooltip" title="Filter by the type of content stored">
 287 |                                     <svg width="16" height="16" fill="currentColor"><use href="#info-icon"/></svg>
 288 |                                 </span>
 289 |                             </label>
 290 |                             <select id="typeFilter">
 291 |                                 <option value="">All types</option>
 292 |                                 <option value="note">Notes</option>
 293 |                                 <option value="code">Code</option>
 294 |                                 <option value="reference">References</option>
 295 |                                 <option value="idea">Ideas</option>
 296 |                             </select>
 297 |                             <small class="help-text">Choose the type of memories to show</small>
 298 |                         </div>
 299 | 
 300 |                         <!-- Filter Actions -->
 301 |                         <div class="filter-actions">
 302 |                             <button type="button" id="applyFiltersBtn" class="btn btn-primary">
 303 |                                 <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
 304 |                                     <path d="M21.71 20.29L18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a1 1 0 0 0 1.42-1.42zM11 18a7 7 0 1 1 7-7 7 7 0 0 1-7 7z"/>
 305 |                                 </svg>
 306 |                                 Search
 307 |                             </button>
 308 |                             <button type="button" id="clearFiltersBtn" class="btn btn-secondary">
 309 |                                 <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
 310 |                                     <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
 311 |                                 </svg>
 312 |                                 Clear All
 313 |                             </button>
 314 |                         </div>
 315 | 
 316 |                         <!-- Active Filters Display -->
 317 |                         <div id="activeFilters" class="active-filters" style="display: none;">
 318 |                             <h4>Active Filters:</h4>
 319 |                             <div id="activeFiltersList" class="filter-pills">
 320 |                                 <!-- Dynamic filter pills will be added here -->
 321 |                             </div>
 322 |                         </div>
 323 |                     </aside>
 324 | 
 325 |                     <!-- Search Results -->
 326 |                     <div class="search-results">
 327 |                         <div class="search-header">
 328 |                             <h2>Search Results</h2>
 329 |                             <div class="results-meta">
 330 |                                 <span id="resultsCount">0 results</span>
 331 |                                 <div class="view-options">
 332 |                                     <button class="view-btn active" data-view="grid">Grid</button>
 333 |                                     <button class="view-btn" data-view="list">List</button>
 334 |                                 </div>
 335 |                             </div>
 336 |                         </div>
 337 |                         <div id="searchResultsList" class="memory-grid">
 338 |                             <!-- Dynamic search results will be loaded here -->
 339 |                         </div>
 340 |                     </div>
 341 |                 </div>
 342 |             </div>
 343 | 
 344 |             <!-- Documents View -->
 345 |             <div id="documentsView" class="view-container">
 346 |                 <div class="documents-layout">
 347 |                     <!-- Document Upload Section -->
 348 |                     <section class="documents-section">
 349 |                         <h2>📄 Document Ingestion</h2>
 350 |                         <div class="upload-area">
 351 |                             <div id="dropZone" class="drop-zone">
 352 |                                 <div class="drop-zone-content">
 353 |                                     <svg width="48" height="48" fill="currentColor" viewBox="0 0 24 24">
 354 |                                         <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
 355 |                                     </svg>
 356 |                                     <h3>Drag & drop files here</h3>
 357 |                                     <p>or <button id="fileSelectBtn" class="link-button">browse to select files</button></p>
 358 |                                     <p class="supported-formats">Supported formats: PDF, TXT, MD, JSON</p>
 359 |                                     <input type="file" id="fileInput" multiple accept=".pdf,.txt,.md,.json" style="display: none;">
 360 |                                 </div>
 361 |                             </div>
 362 |                         </div>
 363 | 
 364 |                         <!-- Upload Configuration -->
 365 |                         <div class="upload-config">
 366 |                         <div class="config-section">
 367 |                         <label for="docTags">Tags (comma-separated)</label>
 368 |                         <input type="text" id="docTags" placeholder="e.g., documentation, reference, manual" class="form-control">
 369 |                             <small class="form-help">Tags will be applied to all files. Use spaces or commas as separators.</small>
 370 |                         </div>
 371 | 
 372 |                              <!-- Processing Mode Toggle (shown when multiple files selected) -->
 373 |                              <div class="config-section" id="processingModeSection" style="display: none;">
 374 |                              <label>Processing Mode <span class="info-icon info-icon-processing" title="Click for processing mode explanation">ℹ️</span></label>
 375 |                                  <div class="processing-mode-toggle">
 376 |                                      <button type="button" id="batchModeBtn" class="mode-btn active" data-mode="batch">
 377 |                                          <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
 378 |                                              <path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z"/>
 379 |                                          </svg>
 380 |                                          Batch Processing
 381 |                                      </button>
 382 |                                      <button type="button" id="individualModeBtn" class="mode-btn" data-mode="individual">
 383 |                                          <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
 384 |                                              <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
 385 |                                          </svg>
 386 |                                          Individual Processing
 387 |                                      </button>
 388 |                                  </div>
 389 |                                  <div class="mode-description" id="modeDescription">
 390 |                                      <small>All selected files will be processed together with the same tags.</small>
 391 |                                  </div>
 392 |                              </div>
 393 |                             <div class="config-row">
 394 |                                 <div class="config-section">
 395 |                                     <label for="chunkSize">
 396 |                                         Chunk Size: <span id="chunkSizeValue">1000</span> chars
 397 |                                         <span class="info-icon" title="Click for chunking recommendations">ℹ️</span>
 398 |                                     </label>
 399 |                                     <input type="range" id="chunkSize" min="500" max="2000" value="1000" step="100" class="form-control">
 400 |                                 </div>
 401 |                                 <div class="config-section">
 402 |                                     <label for="chunkOverlap">
 403 |                                         Overlap: <span id="chunkOverlapValue">200</span> chars
 404 |                                         <span class="info-icon info-icon-overlap" title="Click for overlap explanation">ℹ️</span>
 405 |                                     </label>
 406 |                                     <input type="range" id="chunkOverlap" min="0" max="500" value="200" step="50" class="form-control">
 407 |                                 </div>
 408 |                             </div>
 409 | 
 410 |                             <!-- Chunking Help Section (collapsible) -->
 411 |                             <div id="chunkingHelpSection" class="chunking-help" style="display: none;">
 412 |                                 <div class="help-header">
 413 |                                     <strong>📚 Chunking Configuration Guide</strong>
 414 |                                     <button class="close-help" data-action="hideChunkingHelp">×</button>
 415 |                                 </div>
 416 |                                 <div class="help-content">
 417 |                                     <p class="help-note">
 418 |                                         <strong>Note:</strong> Actual chunk sizes may vary as the system respects paragraph boundaries
 419 |                                         to maintain semantic coherence.
 420 |                                     </p>
 421 | 
 422 |                                     <div class="help-recommendations">
 423 |                                         <div class="help-option">
 424 |                                             <div class="help-option-header">
 425 |                                                 <strong>✅ Default (1000 chars, 200 overlap)</strong>
 426 |                                                 <span class="help-tag">Recommended</span>
 427 |                                             </div>
 428 |                                             <p><strong>Best for:</strong> Technical documentation, reference manuals, knowledge bases</p>
 429 |                                             <p><strong>Why:</strong> Paragraph-aware chunking preserves complete thoughts and context</p>
 430 |                                         </div>
 431 | 
 432 |                                         <div class="help-option">
 433 |                                             <div class="help-option-header">
 434 |                                                 <strong>🔍 Smaller Chunks (500 chars, 100 overlap)</strong>
 435 |                                             </div>
 436 |                                             <p><strong>Best for:</strong> Dense technical docs, code documentation, API references</p>
 437 |                                             <p><strong>Trade-off:</strong> More granular retrieval but may split paragraphs more aggressively</p>
 438 |                                         </div>
 439 | 
 440 |                                         <div class="help-option">
 441 |                                             <div class="help-option-header">
 442 |                                                 <strong>📖 Larger Chunks (2000 chars, 400 overlap)</strong>
 443 |                                             </div>
 444 |                                             <p><strong>Best for:</strong> Narrative documents, articles, blogs, long-form content</p>
 445 |                                             <p><strong>Trade-off:</strong> Better context but less precise retrieval</p>
 446 |                                         </div>
 447 |                                     </div>
 448 | 
 449 |                                     <div class="help-tips">
 450 |                                         <strong>💡 Tips:</strong>
 451 |                                         <ul>
 452 |                                             <li><strong>Overlap</strong> helps maintain context across chunk boundaries</li>
 453 |                                             <li><strong>Higher overlap</strong> = better continuity but more redundancy</li>
 454 |                                             <li>Test different settings on a sample document to find optimal configuration</li>
 455 |                                             <li>Chunks preserve complete sentences and paragraphs when possible</li>
 456 |                                         </ul>
 457 |                                     </div>
 458 |                                 </div>
 459 |                             </div>
 460 | 
 461 |                             <!-- Overlap Help Section (collapsible) -->
 462 |                             <div id="overlapHelpSection" class="chunking-help overlap-help" style="display: none;">
 463 |                                 <div class="help-header">
 464 |                                     <strong>🔗 Chunk Overlap Explained</strong>
 465 |                                     <button class="close-help" data-action="hideOverlapHelp">×</button>
 466 |                                 </div>
 467 |                                 <div class="help-content">
 468 |                                     <p class="help-note">
 469 |                                         <strong>What is overlap?</strong> Overlap is the number of characters that are duplicated
 470 |                                         between consecutive chunks. This helps maintain context across chunk boundaries.
 471 |                                     </p>
 472 | 
 473 |                                     <div class="help-example">
 474 |                                         <strong>Visual Example:</strong>
 475 |                                         <div class="overlap-diagram">
 476 |                                             <div class="chunk-demo">
 477 |                                                 <span class="chunk-part unique">Chunk 1 unique content...</span>
 478 |                                                 <span class="chunk-part overlap">shared overlap region</span>
 479 |                                             </div>
 480 |                                             <div class="chunk-demo">
 481 |                                                 <span class="chunk-part overlap">shared overlap region</span>
 482 |                                                 <span class="chunk-part unique">Chunk 2 unique content...</span>
 483 |                                             </div>
 484 |                                         </div>
 485 |                                     </div>
 486 | 
 487 |                                     <div class="help-recommendations">
 488 |                                         <div class="help-option">
 489 |                                             <div class="help-option-header">
 490 |                                                 <strong>🎯 No Overlap (0 chars)</strong>
 491 |                                             </div>
 492 |                                             <p><strong>Best for:</strong> Maximum storage efficiency, no redundancy needed</p>
 493 |                                             <p><strong>Trade-off:</strong> Context may be lost at chunk boundaries</p>
 494 |                                         </div>
 495 | 
 496 |                                         <div class="help-option">
 497 |                                             <div class="help-option-header">
 498 |                                                 <strong>✅ Medium Overlap (200 chars)</strong>
 499 |                                                 <span class="help-tag">Recommended</span>
 500 |                                             </div>
 501 |                                             <p><strong>Best for:</strong> Most documents - balances context and efficiency</p>
 502 |                                             <p><strong>Why:</strong> Preserves 1-2 sentences of context across boundaries</p>
 503 |                                         </div>
 504 | 
 505 |                                         <div class="help-option">
 506 |                                             <div class="help-option-header">
 507 |                                                 <strong>🔄 High Overlap (400+ chars)</strong>
 508 |                                             </div>
 509 |                                             <p><strong>Best for:</strong> Complex technical content requiring maximum context</p>
 510 |                                             <p><strong>Trade-off:</strong> More storage and processing, higher redundancy</p>
 511 |                                         </div>
 512 |                                     </div>
 513 | 
 514 |                                     <div class="help-tips">
 515 |                                         <strong>💡 Guidelines:</strong>
 516 |                                         <ul>
 517 |                                             <li><strong>Rule of thumb:</strong> Overlap should be 15-25% of chunk size</li>
 518 |                                             <li><strong>Small chunks (500)</strong> → Use 100-150 overlap</li>
 519 |                                             <li><strong>Medium chunks (1000)</strong> → Use 200-250 overlap</li>
 520 |                                             <li><strong>Large chunks (2000)</strong> → Use 400-500 overlap</li>
 521 |                                             <li>Higher overlap helps with search accuracy but increases storage</li>
 522 |                                             <li>Zero overlap is fine for well-structured documents with clear sections</li>
 523 |                                         </ul>
 524 |                                     </div>
 525 |                                 </div>
 526 |                             </div>
 527 | 
 528 |                             <!-- Processing Mode Help Section (collapsible) -->
 529 |                              <div id="processingModeHelpSection" class="chunking-help processing-mode-help" style="display: none;">
 530 |                                  <div class="help-header">
 531 |                                      <strong>⚙️ Processing Mode Options</strong>
 532 |                                      <button class="close-help" data-action="hideProcessingModeHelp">×</button>
 533 |                                  </div>
 534 |                                  <div class="help-content">
 535 |                                      <p class="help-note">
 536 |                                          <strong>When uploading multiple files,</strong> choose how they should be processed.
 537 |                                          Both modes apply the same tags to all files.
 538 |                                      </p>
 539 | 
 540 |                                      <div class="help-recommendations">
 541 |                                          <div class="help-option">
 542 |                                              <div class="help-option-header">
 543 |                                                  <strong>📦 Batch Processing</strong>
 544 |                                                  <span class="help-tag">Default</span>
 545 |                                              </div>
 546 |                                              <p><strong>What it does:</strong> Uploads all files together as one operation</p>
 547 |                                              <p><strong>Best for:</strong> Similar files, fast bulk processing, when you want files grouped together</p>
 548 |                                              <p><strong>Pros:</strong> Faster, simpler, single progress indicator</p>
 549 |                                              <p><strong>Cons:</strong> One file failure can affect the whole batch</p>
 550 |                                          </div>
 551 | 
 552 |                                          <div class="help-option">
 553 |                                              <div class="help-option-header">
 554 |                                                  <strong>🔄 Individual Processing</strong>
 555 |                                              </div>
 556 |                                              <p><strong>What it does:</strong> Uploads each file separately with individual API calls</p>
 557 |                                              <p><strong>Best for:</strong> Mixed file types, when you want error isolation, or need individual progress tracking</p>
 558 |                                              <p><strong>Pros:</strong> Better error handling, individual progress, more robust</p>
 559 |                                              <p><strong>Cons:</strong> Slightly slower due to sequential processing</p>
 560 |                                          </div>
 561 |                                      </div>
 562 | 
 563 |                                      <div class="help-tips">
 564 |                                          <strong>💡 When to choose each mode:</strong>
 565 |                                          <ul>
 566 |                                              <li><strong>Batch mode:</strong> When files are similar and you want them processed quickly together</li>
 567 |                                              <li><strong>Individual mode:</strong> When files might have different processing requirements or you want to ensure all files get processed even if some fail</li>
 568 |                                              <li><strong>Single files:</strong> Always processed individually (no choice needed)</li>
 569 |                                              <li>Both modes apply the same tags to all files</li>
 570 |                                          </ul>
 571 |                                      </div>
 572 |                                  </div>
 573 |                              </div>
 574 | 
 575 |                              <div class="config-section">
 576 |                                 <label for="memoryType">Memory Type</label>
 577 |                                 <select id="memoryType" class="form-control">
 578 |                                     <option value="document">Document</option>
 579 |                                     <option value="reference">Reference</option>
 580 |                                     <option value="knowledge">Knowledge</option>
 581 |                                     <option value="note">Note</option>
 582 |                                 </select>
 583 |                              </div>
 584 |                         </div>
 585 | 
 586 |                         <!-- Upload Button -->
 587 |                         <div class="upload-actions">
 588 |                             <button id="uploadBtn" class="btn btn-primary" disabled>
 589 |                                 <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 590 |                                     <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
 591 |                                 </svg>
 592 |                                 Upload & Ingest
 593 |                             </button>
 594 |                         </div>
 595 |                     </section>
 596 | 
 597 |                     <!-- Upload Queue/History Section -->
 598 |                     <section class="documents-section">
 599 |                         <h2>📊 Upload History</h2>
 600 |                         <div id="uploadHistory" class="upload-history">
 601 |                             <div class="loading-spinner"></div>
 602 |                             <p>Loading upload history...</p>
 603 |                         </div>
 604 |                     </section>
 605 | 
 606 |                     <!-- Document Content Search Section -->
 607 |                     <section class="documents-section">
 608 |                         <h2>🔍 Search Ingested Content</h2>
 609 |                         <p class="section-description">Search within your uploaded documents to verify content is indexed</p>
 610 |                         <div class="doc-search-container">
 611 |                             <input type="text"
 612 |                                    id="docSearchInput"
 613 |                                    class="search-input"
 614 |                                    placeholder="Search for content within ingested documents...">
 615 |                             <button id="docSearchBtn" class="btn btn-primary">Search Documents</button>
 616 |                         </div>
 617 |                         <div id="docSearchResults" class="doc-search-results" style="display: none;">
 618 |                             <div class="search-results-header">
 619 |                                 <h3>Search Results</h3>
 620 |                                 <span id="docSearchCount" class="results-count">0 results</span>
 621 |                             </div>
 622 |                             <div id="docSearchResultsList" class="search-results-list">
 623 |                                 <!-- Results will be populated here -->
 624 |                             </div>
 625 |                         </div>
 626 |                     </section>
 627 |                 </div>
 628 |             </div>
 629 | 
 630 |             <!-- Other views (Browse, Manage, Analytics) will be added in subsequent phases -->
 631 |             <div id="browseView" class="view-container">
 632 |                 <div class="view-header">
 633 |                     <h2>Browse by Tags</h2>
 634 |                     <p>Explore your memories organized by tags</p>
 635 |                 </div>
 636 | 
 637 |                 <div class="browse-content">
 638 |                     <div id="tagsCloudContainer" class="tags-cloud">
 639 |                         <!-- Dynamic tags will be loaded here -->
 640 |                     </div>
 641 | 
 642 |                     <div id="taggedMemoriesContainer" class="tagged-memories" style="display: none;">
 643 |                         <div class="section-header">
 644 |                             <h3 id="selectedTagTitle">Memories tagged with: <span id="selectedTagName"></span></h3>
 645 |                             <button id="clearTagFilter" class="btn btn-secondary">Show All Tags</button>
 646 |                         </div>
 647 |                         <div id="taggedMemoriesList" class="memory-grid">
 648 |                             <!-- Filtered memories will be shown here -->
 649 |                         </div>
 650 |                     </div>
 651 |                 </div>
 652 |             </div>
 653 | 
 654 |             <!-- Manage View -->
 655 |             <div id="manageView" class="view-container">
 656 |                 <div class="manage-layout">
 657 |                     <!-- Bulk Operations Section -->
 658 |                     <section class="manage-section">
 659 |                         <h2>🧹 Bulk Operations</h2>
 660 |                         <div class="bulk-ops-grid">
 661 |                             <div class="bulk-op-card">
 662 |                                 <h3>Delete by Tag</h3>
 663 |                                 <p>Remove all memories with a specific tag</p>
 664 |                                 <div class="op-controls">
 665 |                                     <select id="deleteTagSelect" class="form-control">
 666 |                                         <option value="">Select tag...</option>
 667 |                                     </select>
 668 |                                     <button id="deleteByTagBtn" class="btn btn-danger">Delete</button>
 669 |                                 </div>
 670 |                             </div>
 671 | 
 672 |                             <div class="bulk-op-card">
 673 |                                 <h3>Cleanup Duplicates</h3>
 674 |                                 <p>Remove duplicate memories based on content</p>
 675 |                                 <div class="op-controls">
 676 |                                     <button id="cleanupDuplicatesBtn" class="btn btn-warning">Run Cleanup</button>
 677 |                                 </div>
 678 |                             </div>
 679 | 
 680 |                             <div class="bulk-op-card">
 681 |                                 <h3>Delete by Date</h3>
 682 |                                 <p>Remove memories older than a specific date</p>
 683 |                                 <div class="op-controls">
 684 |                                     <input type="date" id="deleteDateInput" class="form-control">
 685 |                                     <button id="deleteByDateBtn" class="btn btn-danger">Delete</button>
 686 |                                 </div>
 687 |                             </div>
 688 |                         </div>
 689 |                     </section>
 690 | 
 691 |                     <!-- Tag Management Section -->
 692 |                     <section class="manage-section">
 693 |                         <h2>🏷️ Tag Management</h2>
 694 |                         <div id="tagManagementContainer">
 695 |                             <div class="loading-spinner"></div>
 696 |                             <p>Loading tag statistics...</p>
 697 |                         </div>
 698 |                     </section>
 699 | 
 700 |                     <!-- System Operations Section -->
 701 |                     <section class="manage-section">
 702 |                         <h2>⚙️ System Maintenance</h2>
 703 |                         <div class="system-ops-grid">
 704 |                             <div class="system-op-card">
 705 |                                 <h3>Database Optimization</h3>
 706 |                                 <p>Optimize database performance</p>
 707 |                                 <button id="optimizeDbBtn" class="btn btn-secondary" disabled>Optimize DB</button>
 708 |                             </div>
 709 | 
 710 |                             <div class="system-op-card">
 711 |                                 <h3>Rebuild Search Index</h3>
 712 |                                 <p>Rebuild search indexes for better performance</p>
 713 |                                 <button id="rebuildIndexBtn" class="btn btn-secondary" disabled>Rebuild Index</button>
 714 |                             </div>
 715 |                         </div>
 716 |                     </section>
 717 |                 </div>
 718 |             </div>
 719 | 
 720 |             <!-- Analytics View -->
 721 |             <div id="analyticsView" class="view-container">
 722 |                 <div class="analytics-layout">
 723 |                     <!-- Key Metrics Cards -->
 724 |                     <section class="analytics-section">
 725 |                         <h2>📊 Key Metrics</h2>
 726 |                         <div class="metrics-grid">
 727 |                             <div class="metric-card">
 728 |                                 <div class="metric-value" id="analyticsTotalMemories">-</div>
 729 |                                 <div class="metric-label">Total Memories</div>
 730 |                             </div>
 731 |                             <div class="metric-card">
 732 |                                 <div class="metric-value" id="analyticsThisWeek">-</div>
 733 |                                 <div class="metric-label">This Week</div>
 734 |                             </div>
 735 |                             <div class="metric-card">
 736 |                                 <div class="metric-value" id="analyticsUniqueTags">-</div>
 737 |                                 <div class="metric-label">Unique Tags</div>
 738 |                             </div>
 739 |                             <div class="metric-card">
 740 |                                 <div class="metric-value" id="analyticsDbSize">-</div>
 741 |                                 <div class="metric-label">Database Size</div>
 742 |                             </div>
 743 |                         </div>
 744 |                     </section>
 745 | 
 746 |                     <!-- Charts Section -->
 747 |                     <section class="analytics-section">
 748 |                         <h2>📈 Trends & Charts</h2>
 749 |                         <div class="charts-grid">
 750 |                             <div class="chart-card">
 751 |                                 <h3>Memory Growth Over Time</h3>
 752 |                                 <div class="chart-controls">
 753 |                                     <select id="growthPeriodSelect" class="form-control">
 754 |                                         <option value="week">Last Week</option>
 755 |                                         <option value="month" selected>Last Month</option>
 756 |                                         <option value="quarter">Last Quarter</option>
 757 |                                         <option value="year">Last Year</option>
 758 |                                     </select>
 759 |                                 </div>
 760 |                                 <div id="memoryGrowthChart" class="chart-container">
 761 |                                     <div class="loading-spinner"></div>
 762 |                                     <p>Loading chart...</p>
 763 |                                 </div>
 764 |                             </div>
 765 | 
 766 |                             <div class="chart-card">
 767 |                                 <h3>Tag Usage Distribution</h3>
 768 |                                 <div id="tagUsageChart" class="chart-container">
 769 |                                     <div class="loading-spinner"></div>
 770 |                                     <p>Loading chart...</p>
 771 |                                 </div>
 772 |                             </div>
 773 | 
 774 |                             <div class="chart-card">
 775 |                                 <h3>Memory Types Distribution</h3>
 776 |                                 <div id="memoryTypesChart" class="chart-container">
 777 |                                     <div class="loading-spinner"></div>
 778 |                                     <p>Loading chart...</p>
 779 |                                 </div>
 780 |                             </div>
 781 | 
 782 |                                     <div class="chart-card">
 783 |                                     <h3>Activity Heatmap</h3>
 784 |                                     <div class="chart-controls">
 785 |                                     <select id="heatmapPeriodSelect" class="form-control">
 786 |                                     <option value="90" selected>Last 90 Days</option>
 787 |                                     <option value="180">Last 6 Months</option>
 788 |                                     <option value="365">Last Year</option>
 789 |                                         </select>
 790 |                                         </div>
 791 |                                         <div id="activityHeatmapChart" class="chart-container">
 792 |                                             <div class="loading-spinner"></div>
 793 |                                         <p>Loading heatmap...</p>
 794 |                                     </div>
 795 |                                     </div>
 796 |                             </section>
 797 | 
 798 |                             <!-- Detailed Analytics -->
 799 |                             <section class="analytics-section">
 800 |                             <h2>📋 Detailed Reports</h2>
 801 |                             <div class="reports-grid">
 802 |                             <div class="report-card">
 803 |                             <h3>Top Tags</h3>
 804 |                             <div class="chart-controls">
 805 |                             <select id="topTagsPeriodSelect" class="form-control">
 806 |                             <option value="7d">Last 7 Days</option>
 807 |                             <option value="30d" selected>Last 30 Days</option>
 808 |                             <option value="90d">Last 90 Days</option>
 809 |                             <option value="all">All Time</option>
 810 |                             </select>
 811 |                             </div>
 812 |                             <div id="topTagsList" class="report-content">
 813 |                                      <div class="loading-spinner"></div>
 814 |                                      <p>Loading...</p>
 815 |                                  </div>
 816 |                              </div>
 817 | 
 818 |                              <div class="report-card">
 819 |                                  <h3>Recent Activity</h3>
 820 |                                  <div class="chart-controls">
 821 |                                      <select id="activityGranularitySelect" class="form-control">
 822 |                                          <option value="hourly">By Hour</option>
 823 |                                          <option value="daily" selected>By Day</option>
 824 |                                          <option value="weekly">By Week</option>
 825 |                                      </select>
 826 |                                  </div>
 827 |                                  <div id="recentActivityList" class="report-content">
 828 |                                      <div class="loading-spinner"></div>
 829 |                                      <p>Loading...</p>
 830 |                                  </div>
 831 |                              </div>
 832 | 
 833 |                              <div class="report-card">
 834 |                                  <h3>Storage Report</h3>
 835 |                                  <div id="storageReport" class="report-content">
 836 |                                      <div class="loading-spinner"></div>
 837 |                                      <p>Loading...</p>
 838 |                                  </div>
 839 |                              </div>
 840 |                          </div>
 841 |                      </section>
 842 |                 </div>
 843 |             </div>
 844 | 
 845 |             <!-- API Documentation View -->
 846 |             <div id="apiDocsView" class="view-container">
 847 |                 <div class="api-docs-header">
 848 |                     <h2>🔗 API Documentation</h2>
 849 |                     <p>Comprehensive REST API endpoints for MCP Memory Service</p>
 850 |                     <div class="api-docs-links">
 851 |                         <a href="/api/docs" target="_blank" class="btn btn-primary">
 852 |                             <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 853 |                                 <path d="M14,17H7V15H14M17,13H7V11H17M17,9H7V7H17M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z"/>
 854 |                             </svg>
 855 |                             Interactive Swagger UI
 856 |                         </a>
 857 |                         <a href="/api/redoc" target="_blank" class="btn btn-secondary">
 858 |                             <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 859 |                                 <path d="M14,17H7V15H14M17,13H7V11H17M17,9H7V7H17M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z"/>
 860 |                             </svg>
 861 |                             ReDoc Documentation
 862 |                         </a>
 863 |                         <a href="/api-overview" target="_blank" class="btn btn-secondary">
 864 |                             <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
 865 |                                 <path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4M11,16.5L18,9.5L16.59,8.09L11,13.67L7.91,10.59L6.5,12L11,16.5Z"/>
 866 |                             </svg>
 867 |                             API Overview Page
 868 |                         </a>
 869 |                     </div>
 870 |                 </div>
 871 | 
 872 |                 <div class="api-endpoints-grid">
 873 |                     <!-- Memory Management -->
 874 |                     <div class="endpoint-section">
 875 |                         <h3>💾 Memory Management</h3>
 876 |                         <div class="endpoint-list">
 877 |                             <div class="endpoint-item">
 878 |                                 <span class="method post">POST</span>
 879 |                                 <span class="path">/api/memories</span>
 880 |                                 <span class="description">Store a new memory with automatic embedding generation</span>
 881 |                             </div>
 882 |                             <div class="endpoint-item">
 883 |                                 <span class="method get">GET</span>
 884 |                                 <span class="path">/api/memories</span>
 885 |                                 <span class="description">List all memories with pagination support</span>
 886 |                             </div>
 887 |                             <div class="endpoint-item">
 888 |                                 <span class="method get">GET</span>
 889 |                                 <span class="path">/api/memories/{content_hash}</span>
 890 |                                 <span class="description">Retrieve a specific memory by content hash</span>
 891 |                             </div>
 892 |                             <div class="endpoint-item">
 893 |                                 <span class="method delete">DELETE</span>
 894 |                                 <span class="path">/api/memories/{content_hash}</span>
 895 |                                 <span class="description">Delete a memory and its embeddings</span>
 896 |                             </div>
 897 |                         </div>
 898 |                     </div>
 899 | 
 900 |                     <!-- Search Operations -->
 901 |                     <div class="endpoint-section">
 902 |                         <h3>🔍 Search Operations</h3>
 903 |                         <div class="endpoint-list">
 904 |                             <div class="endpoint-item">
 905 |                                 <span class="method post">POST</span>
 906 |                                 <span class="path">/api/search</span>
 907 |                                 <span class="description">Semantic similarity search using embeddings</span>
 908 |                             </div>
 909 |                             <div class="endpoint-item">
 910 |                                 <span class="method post">POST</span>
 911 |                                 <span class="path">/api/search/by-tag</span>
 912 |                                 <span class="description">Search memories by tags (AND/OR logic)</span>
 913 |                             </div>
 914 |                             <div class="endpoint-item">
 915 |                                 <span class="method post">POST</span>
 916 |                                 <span class="path">/api/search/by-time</span>
 917 |                                 <span class="description">Natural language time-based queries</span>
 918 |                             </div>
 919 |                             <div class="endpoint-item">
 920 |                                 <span class="method get">GET</span>
 921 |                                 <span class="path">/api/search/similar/{content_hash}</span>
 922 |                                 <span class="description">Find memories similar to a specific one</span>
 923 |                             </div>
 924 |                         </div>
 925 |                     </div>
 926 | 
 927 |                     <!-- Real-time Events -->
 928 |                     <div class="endpoint-section">
 929 |                         <h3>📡 Real-time Events</h3>
 930 |                         <div class="endpoint-list">
 931 |                             <div class="endpoint-item">
 932 |                                 <span class="method get">GET</span>
 933 |                                 <span class="path">/api/events</span>
 934 |                                 <span class="description">Subscribe to real-time memory events stream</span>
 935 |                             </div>
 936 |                             <div class="endpoint-item">
 937 |                                 <span class="method get">GET</span>
 938 |                                 <span class="path">/api/events/stats</span>
 939 |                                 <span class="description">View SSE connection statistics</span>
 940 |                             </div>
 941 |                         </div>
 942 |                     </div>
 943 | 
 944 |                     <!-- Health & Status -->
 945 |                     <div class="endpoint-section">
 946 |                         <h3>🏥 Health & Status</h3>
 947 |                         <div class="endpoint-list">
 948 |                             <div class="endpoint-item">
 949 |                                 <span class="method get">GET</span>
 950 |                                 <span class="path">/api/health</span>
 951 |                                 <span class="description">Quick health check endpoint</span>
 952 |                             </div>
 953 |                             <div class="endpoint-item">
 954 |                                 <span class="method get">GET</span>
 955 |                                 <span class="path">/api/health/detailed</span>
 956 |                                 <span class="description">Detailed health with database statistics</span>
 957 |                             </div>
 958 |                         </div>
 959 |                     </div>
 960 |                 </div>
 961 |             </div>
 962 |         </main>
 963 | 
 964 |         <!-- Footer -->
 965 |         <footer class="app-footer">
 966 |             <div class="footer-content">
 967 |                 <div class="footer-section">
 968 |                     <h4>Documentation</h4>
 969 |                     <ul class="footer-links">
 970 |                         <li><a href="https://github.com/doobidoo/mcp-memory-service/wiki" target="_blank" rel="noopener">
 971 |                             📚 Wiki Home
 972 |                         </a></li>
 973 |                         <li><a href="https://github.com/doobidoo/mcp-memory-service/wiki/07-TROUBLESHOOTING" target="_blank" rel="noopener">
 974 |                             🔧 Troubleshooting Guide
 975 |                         </a></li>
 976 |                         <li><a href="https://github.com/doobidoo/mcp-memory-service/wiki/07-TROUBLESHOOTING#backend-configuration-issues" target="_blank" rel="noopener">
 977 |                             ⚙️ Configuration Issues
 978 |                         </a></li>
 979 |                     </ul>
 980 |                 </div>
 981 | 
 982 |                 <div class="footer-section">
 983 |                     <h4>Resources</h4>
 984 |                     <ul class="footer-links">
 985 |                         <li><a href="https://github.com/doobidoo/mcp-memory-service" target="_blank" rel="noopener">
 986 |                             <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
 987 |                                 <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
 988 |                             </svg>
 989 |                             GitHub Repository
 990 |                         </a></li>
 991 |                         <li><a href="https://doobidoo.github.io" target="_blank" rel="noopener">
 992 |                             🌐 Portfolio
 993 |                         </a></li>
 994 |                         <li><a href="/api/docs" target="_blank">
 995 |                             📖 API Documentation
 996 |                         </a></li>
 997 |                     </ul>
 998 |                 </div>
 999 | 
1000 |                 <div class="footer-section">
1001 |                     <h4>About</h4>
1002 |                     <p class="footer-description">
1003 |                         MCP Memory Service - Semantic memory management for AI assistants
1004 |                     </p>
1005 |                     <div class="footer-license">
1006 |                         <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
1007 |                             <path d="M14,17H7V15H14M17,13H7V11H17M17,9H7V7H17M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z"/>
1008 |                         </svg>
1009 |                         <a href="https://github.com/doobidoo/mcp-memory-service/blob/main/LICENSE" target="_blank" rel="noopener">
1010 |                             Licensed under Apache 2.0
1011 |                         </a>
1012 |                     </div>
1013 |                     <div class="footer-copyright">
1014 |                         © 2024 Heinrich Krupp
1015 |                     </div>
1016 |                 </div>
1017 |             </div>
1018 |         </footer>
1019 | 
1020 |         <!-- Memory Detail Modal -->
1021 |         <div id="memoryModal" class="modal-overlay">
1022 |             <div class="modal-content">
1023 |                 <div class="modal-header">
1024 |                     <h3 id="modalTitle">Memory Details</h3>
1025 |                     <button class="modal-close" aria-label="Close">
1026 |                         <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
1027 |                             <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
1028 |                         </svg>
1029 |                     </button>
1030 |                 </div>
1031 |                 <div class="modal-body">
1032 |                     <div id="modalContent">
1033 |                         <!-- Dynamic memory content -->
1034 |                     </div>
1035 |                 </div>
1036 |                 <div class="modal-footer">
1037 |                     <button class="btn btn-secondary" id="editMemoryBtn">Edit</button>
1038 |                     <button class="btn btn-danger" id="deleteMemoryBtn">Delete</button>
1039 |                     <button class="btn btn-primary" id="shareMemoryBtn">Share</button>
1040 |                 </div>
1041 |             </div>
1042 |         </div>
1043 | 
1044 |         <!-- Add Memory Modal -->
1045 |         <div id="addMemoryModal" class="modal-overlay">
1046 |             <div class="modal-content">
1047 |                 <div class="modal-header">
1048 |                     <h3>Add New Memory</h3>
1049 |                     <button class="modal-close" aria-label="Close">
1050 |                         <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
1051 |                             <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
1052 |                         </svg>
1053 |                     </button>
1054 |                 </div>
1055 |                 <div class="modal-body">
1056 |                     <form id="addMemoryForm">
1057 |                         <div class="form-group">
1058 |                             <label for="memoryContent">Content</label>
1059 |                             <textarea id="memoryContent" rows="6" placeholder="Enter your memory content..."></textarea>
1060 |                         </div>
1061 |                         <div class="form-group">
1062 |                             <label for="memoryTags">Tags (comma-separated)</label>
1063 |                             <input type="text" id="memoryTags" placeholder="e.g., coding, javascript, api">
1064 |                         </div>
1065 |                         <div class="form-group">
1066 |                             <label for="memoryType">Type</label>
1067 |                             <select id="memoryType">
1068 |                                 <option value="note">Note</option>
1069 |                                 <option value="code">Code</option>
1070 |                                 <option value="reference">Reference</option>
1071 |                                 <option value="idea">Idea</option>
1072 |                             </select>
1073 |                         </div>
1074 |                     </form>
1075 |                 </div>
1076 |                 <div class="modal-footer">
1077 |                     <button class="btn btn-secondary" id="cancelAddBtn">Cancel</button>
1078 |                     <button class="btn btn-primary" id="saveMemoryBtn">Save Memory</button>
1079 |                 </div>
1080 |             </div>
1081 |         </div>
1082 | 
1083 |         <!-- Settings Modal -->
1084 |         <div id="settingsModal" class="modal-overlay">
1085 |             <div class="modal-content">
1086 |                 <div class="modal-header">
1087 |                     <h3>Settings</h3>
1088 |                     <button class="modal-close" aria-label="Close">
1089 |                         <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
1090 |                             <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
1091 |                         </svg>
1092 |                     </button>
1093 |                 </div>
1094 |                 <div class="modal-body">
1095 |                     <form id="settingsForm">
1096 |                         <h4 class="settings-section-heading">Preferences</h4>
1097 |                         <div class="form-group">
1098 |                             <label for="themeSelect">Theme</label>
1099 |                             <select id="themeSelect">
1100 |                                 <option value="light">Light</option>
1101 |                                 <option value="dark">Dark</option>
1102 |                             </select>
1103 |                         </div>
1104 |                         <div class="form-group">
1105 |                             <label for="viewDensity">View Density</label>
1106 |                             <select id="viewDensity">
1107 |                                 <option value="comfortable">Comfortable</option>
1108 |                                 <option value="compact">Compact</option>
1109 |                             </select>
1110 |                         </div>
1111 |                         <div class="form-group">
1112 |                             <label for="previewLines">Memory Preview Lines</label>
1113 |                             <input type="number" id="previewLines" min="1" max="10" value="3">
1114 |                         </div>
1115 | 
1116 |                         <hr class="settings-divider">
1117 | 
1118 |                         <h4 class="settings-section-heading" style="margin-bottom: var(--space-4);">System Information</h4>
1119 |                         <div class="system-info">
1120 |                             <div class="info-row">
1121 |                                 <span class="info-label">Version:</span>
1122 |                                 <span class="info-value" id="settingsVersion">Loading...</span>
1123 |                             </div>
1124 |                             <div class="info-row">
1125 |                                 <span class="info-label">Storage Backend:</span>
1126 |                                 <span class="info-value" id="settingsBackend">Loading...</span>
1127 |                             </div>
1128 |                             <div class="info-row">
1129 |                                 <span class="info-label">Primary Backend:</span>
1130 |                                 <span class="info-value" id="settingsPrimaryBackend">Loading...</span>
1131 |                             </div>
1132 |                             <div class="info-row">
1133 |                                 <span class="info-label">Embedding Model:</span>
1134 |                                 <span class="info-value" id="settingsEmbeddingModel">Loading...</span>
1135 |                             </div>
1136 |                             <div class="info-row">
1137 |                                 <span class="info-label">Embedding Dimensions:</span>
1138 |                                 <span class="info-value" id="settingsEmbeddingDim">Loading...</span>
1139 |                             </div>
1140 |                             <div class="info-row">
1141 |                                 <span class="info-label">Database Size:</span>
1142 |                                 <span class="info-value" id="settingsDbSize">Loading...</span>
1143 |                             </div>
1144 |                             <div class="info-row">
1145 |                                 <span class="info-label">Total Memories:</span>
1146 |                                 <span class="info-value" id="settingsTotalMemories">Loading...</span>
1147 |                             </div>
1148 |                             <div class="info-row">
1149 |                                 <span class="info-label">Uptime:</span>
1150 |                                 <span class="info-value" id="settingsUptime">Loading...</span>
1151 |                             </div>
1152 |                         </div>
1153 | 
1154 |                         <hr class="settings-divider">
1155 | 
1156 |                         <h4 class="settings-section-heading">Backup & Restore</h4>
1157 |                         <div class="backup-settings">
1158 |                             <div class="info-row">
1159 |                                 <span class="info-label">Last Backup:</span>
1160 |                                 <span class="info-value" id="settingsLastBackup">Never</span>
1161 |                             </div>
1162 |                             <div class="info-row">
1163 |                                 <span class="info-label">Backup Count:</span>
1164 |                                 <span class="info-value" id="settingsBackupCount">0</span>
1165 |                             </div>
1166 |                             <div class="info-row">
1167 |                                 <span class="info-label">Next Scheduled:</span>
1168 |                                 <span class="info-value" id="settingsNextBackup">-</span>
1169 |                             </div>
1170 |                             <div class="backup-actions">
1171 |                                 <button id="backupNowButton" class="btn btn-sm btn-primary">Create Backup Now</button>
1172 |                                 <button id="viewBackupsButton" class="btn btn-sm btn-secondary">View Backups</button>
1173 |                             </div>
1174 |                         </div>
1175 |                     </form>
1176 |                 </div>
1177 |                 <div class="modal-footer">
1178 |                     <button class="btn btn-secondary" id="cancelSettingsBtn">Cancel</button>
1179 |                     <button class="btn btn-primary" id="saveSettingsBtn">Save Settings</button>
1180 |                 </div>
1181 |             </div>
1182 |         </div>
1183 | 
1184 |         <!-- Loading Overlay -->
1185 |         <div id="loadingOverlay" class="loading-overlay">
1186 |             <div class="loading-spinner"></div>
1187 |             <p>Loading...</p>
1188 |         </div>
1189 | 
1190 |         <!-- Toast Notifications -->
1191 |         <div id="toastContainer" class="toast-container"></div>
1192 |     </div>
1193 | 
1194 |     <!-- Connection Status Indicator -->
1195 |     <div id="connectionStatus" class="connection-status">
1196 |         <div class="status-indicator"></div>
1197 |         <span class="status-text">Connected</span>
1198 |     </div>
1199 | 
1200 |     <!-- Memory Viewer Modal -->
1201 |     <div id="memoryViewerModal" class="modal" style="display: none;">
1202 |         <div class="modal-content memory-viewer-content">
1203 |             <div class="modal-header">
1204 |                 <h2>📝 Document Memory Chunks</h2>
1205 |                 <button class="modal-close" data-action="closeMemoryViewer">&times;</button>
1206 |             </div>
1207 |             <div class="modal-body">
1208 |                 <div class="document-info">
1209 |                     <h3 id="memoryViewerFilename">Loading...</h3>
1210 |                     <p id="memoryViewerStats" class="text-muted">0 chunks found</p>
1211 |                 </div>
1212 |                 <div class="memory-chunks-container">
1213 |                     <div id="memoryChunksList" class="memory-chunks-list">
1214 |                         <!-- Chunks will be populated here -->
1215 |                     </div>
1216 |                 </div>
1217 |             </div>
1218 |             <div class="modal-footer">
1219 |                 <button class="btn btn-secondary" data-action="closeMemoryViewer">Close</button>
1220 |             </div>
1221 |         </div>
1222 |     </div>
1223 | 
1224 |     <script src="/static/app.js?v=8.27.2-TOAST-AND-ICON"></script>
1225 |     <link rel="stylesheet" href="/static/style.css?v=8.27.2-TOAST-AND-ICON">
1226 | </body>
1227 | </html>
```

--------------------------------------------------------------------------------
/scripts/installation/install.py:
--------------------------------------------------------------------------------

```python
   1 | #!/usr/bin/env python3
   2 | """
   3 | Installation script for MCP Memory Service with cross-platform compatibility.
   4 | This script guides users through the installation process with the appropriate
   5 | dependencies for their platform.
   6 | """
   7 | import os
   8 | import sys
   9 | import platform
  10 | import subprocess
  11 | import argparse
  12 | import shutil
  13 | from pathlib import Path
  14 | from typing import Tuple, Dict, Any, Optional
  15 | import re
  16 | 
  17 | # Import shared GPU detection utilities
  18 | try:
  19 |     from mcp_memory_service.utils.gpu_detection import detect_gpu as shared_detect_gpu
  20 | except ImportError:
  21 |     # Fallback for scripts directory context
  22 |     sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  23 |     from src.mcp_memory_service.utils.gpu_detection import detect_gpu as shared_detect_gpu
  24 | 
  25 | def is_python_version_at_least(major, minor):
  26 |     """Check if current Python version is at least the specified version.
  27 | 
  28 |     Args:
  29 |         major: Major version number
  30 |         minor: Minor version number
  31 | 
  32 |     Returns:
  33 |         bool: True if current Python version >= specified version
  34 |     """
  35 |     return sys.version_info >= (major, minor)
  36 | 
  37 | def get_python_version_string():
  38 |     """Get Python version as a string (e.g., '3.12').
  39 | 
  40 |     Returns:
  41 |         str: Python version string
  42 |     """
  43 |     return f"{sys.version_info.major}.{sys.version_info.minor}"
  44 | 
  45 | def get_package_version():
  46 |     """Get the current package version from pyproject.toml.
  47 | 
  48 |     Returns:
  49 |         str: The version string from pyproject.toml or fallback version
  50 |     """
  51 |     fallback_version = "7.2.0"
  52 | 
  53 |     try:
  54 |         # Get path to pyproject.toml relative to this script
  55 |         pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
  56 | 
  57 |         if not pyproject_path.exists():
  58 |             print_warning(f"pyproject.toml not found at {pyproject_path}, using fallback version {fallback_version}")
  59 |             return fallback_version
  60 | 
  61 |         with open(pyproject_path, "r", encoding="utf-8") as f:
  62 |             content = f.read()
  63 | 
  64 |         # Extract version using regex - matches standard pyproject.toml format
  65 |         version_pattern = r'^version\s*=\s*["\']([^"\'\n]+)["\']'
  66 |         version_match = re.search(version_pattern, content, re.MULTILINE)
  67 | 
  68 |         if version_match:
  69 |             version = version_match.group(1).strip()
  70 |             if version:  # Ensure non-empty version
  71 |                 return version
  72 |             else:
  73 |                 print_warning("Empty version found in pyproject.toml, using fallback")
  74 |                 return fallback_version
  75 |         else:
  76 |             print_warning("Version not found in pyproject.toml, using fallback")
  77 |             return fallback_version
  78 | 
  79 |     except (OSError, IOError) as e:
  80 |         print_warning(f"Failed to read pyproject.toml: {e}, using fallback version {fallback_version}")
  81 |         return fallback_version
  82 |     except Exception as e:
  83 |         print_warning(f"Unexpected error parsing version: {e}, using fallback version {fallback_version}")
  84 |         return fallback_version
  85 | 
  86 | def print_header(text):
  87 |     """Print a formatted header."""
  88 |     print("\n" + "=" * 80)
  89 |     print(f" {text}")
  90 |     print("=" * 80)
  91 | 
  92 | def print_step(step, text):
  93 |     """Print a formatted step."""
  94 |     print(f"\n[{step}] {text}")
  95 | 
  96 | def print_info(text):
  97 |     """Print formatted info text."""
  98 |     print(f"  → {text}")
  99 | 
 100 | def print_error(text):
 101 |     """Print formatted error text."""
 102 |     print(f"  ❌ ERROR: {text}")
 103 | 
 104 | def print_success(text):
 105 |     """Print formatted success text."""
 106 |     print(f"  ✅ {text}")
 107 | 
 108 | def print_warning(text):
 109 |     """Print formatted warning text."""
 110 |     print(f"  ⚠️  {text}")
 111 | 
 112 | def run_command_safe(cmd, success_msg=None, error_msg=None, silent=False,
 113 |                      timeout=None, fallback_in_venv=False):
 114 |     """
 115 |     Run a subprocess command with standardized error handling.
 116 | 
 117 |     Args:
 118 |         cmd: Command to run (list of strings)
 119 |         success_msg: Message to print on success
 120 |         error_msg: Custom error message
 121 |         silent: If True, suppress stdout/stderr
 122 |         timeout: Command timeout in seconds
 123 |         fallback_in_venv: If True and command fails, warn instead of error when in virtual environment
 124 | 
 125 |     Returns:
 126 |         tuple: (success: bool, result: subprocess.CompletedProcess or None)
 127 |     """
 128 |     # Validate command input
 129 |     if not cmd or not isinstance(cmd, (list, tuple)):
 130 |         print_error("Invalid command: must be a non-empty list or tuple")
 131 |         return False, None
 132 | 
 133 |     if not all(isinstance(arg, (str, int, float)) for arg in cmd if arg is not None):
 134 |         print_error("Invalid command arguments: all arguments must be strings, numbers, or None")
 135 |         return False, None
 136 | 
 137 |     # Filter out None values and convert to strings
 138 |     cmd_clean = [str(arg) for arg in cmd if arg is not None]
 139 |     if not cmd_clean:
 140 |         print_error("Command is empty after filtering")
 141 |         return False, None
 142 | 
 143 |     try:
 144 |         kwargs = {'capture_output': False, 'text': True}
 145 |         if silent:
 146 |             kwargs.update({'stdout': subprocess.DEVNULL, 'stderr': subprocess.DEVNULL})
 147 |         if timeout:
 148 |             kwargs['timeout'] = timeout
 149 | 
 150 |         result = subprocess.run(cmd_clean, check=True, **kwargs)
 151 |         if success_msg:
 152 |             print_success(success_msg)
 153 |         return True, result
 154 |     except subprocess.TimeoutExpired as e:
 155 |         if error_msg:
 156 |             timeout_msg = error_msg
 157 |         elif hasattr(e, 'timeout') and e.timeout:
 158 |             timeout_msg = f"Command timed out after {e.timeout}s"
 159 |         else:
 160 |             timeout_msg = "Command timed out"
 161 |         print_error(timeout_msg)
 162 |         return False, None
 163 |     except subprocess.CalledProcessError as e:
 164 |         if fallback_in_venv:
 165 |             in_venv = sys.prefix != sys.base_prefix
 166 |             if in_venv:
 167 |                 fallback_msg = error_msg or "Command failed, but you're in a virtual environment. If you're using an alternative package manager, this may be normal."
 168 |                 print_warning(fallback_msg)
 169 |                 print_warning("Note: Installation may not have succeeded. Please verify manually if needed.")
 170 |                 return True, None  # Proceed anyway in venv with warning
 171 | 
 172 |         if error_msg:
 173 |             print_error(error_msg)
 174 |         else:
 175 |             # Safe command formatting for error messages
 176 |             cmd_str = ' '.join(f'"{arg}"' if ' ' in str(arg) else str(arg) for arg in cmd_clean)
 177 |             print_error(f"Command failed (exit code {e.returncode}): {cmd_str}")
 178 |         return False, None
 179 |     except FileNotFoundError:
 180 |         if error_msg:
 181 |             print_error(error_msg)
 182 |         else:
 183 |             print_error(f"Command not found: {cmd_clean[0]}")
 184 |         return False, None
 185 |     except PermissionError:
 186 |         permission_msg = error_msg or f"Permission denied executing: {cmd_clean[0]}"
 187 |         print_error(permission_msg)
 188 |         return False, None
 189 | 
 190 | def install_package_safe(package, success_msg=None, error_msg=None, fallback_in_venv=True):
 191 |     """
 192 |     Install a Python package with standardized error handling.
 193 | 
 194 |     Args:
 195 |         package: Package name or requirement string
 196 |         success_msg: Message to print on success
 197 |         error_msg: Custom error message
 198 |         fallback_in_venv: If True, warn instead of error when in virtual environment
 199 | 
 200 |     Returns:
 201 |         bool: True if installation succeeded OR if fallback was applied (see warning messages)
 202 |     """
 203 |     cmd = [sys.executable, '-m', 'pip', 'install', package]
 204 |     default_success = success_msg or f"{package} installed successfully"
 205 |     default_error = error_msg or f"Failed to install {package}"
 206 | 
 207 |     if fallback_in_venv:
 208 |         default_error += ". If you're using an alternative package manager like uv, please install manually."
 209 | 
 210 |     success, _ = run_command_safe(
 211 |         cmd,
 212 |         success_msg=default_success,
 213 |         error_msg=default_error,
 214 |         silent=True,
 215 |         fallback_in_venv=fallback_in_venv
 216 |     )
 217 |     return success
 218 | 
 219 | def detect_system():
 220 |     """Detect the system architecture and platform."""
 221 |     system = platform.system().lower()
 222 |     machine = platform.machine().lower()
 223 |     python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
 224 |     
 225 |     is_windows = system == "windows"
 226 |     is_macos = system == "darwin"
 227 |     is_linux = system == "linux"
 228 |     is_arm = machine in ("arm64", "aarch64")
 229 |     is_x86 = machine in ("x86_64", "amd64", "x64")
 230 |     
 231 |     print_info(f"System: {platform.system()} {platform.release()}")
 232 |     print_info(f"Architecture: {machine}")
 233 |     print_info(f"Python: {python_version}")
 234 |     
 235 |     # Check for virtual environment
 236 |     in_venv = sys.prefix != sys.base_prefix
 237 |     if not in_venv:
 238 |         print_warning("Not running in a virtual environment. It's recommended to install in a virtual environment.")
 239 |     else:
 240 |         print_info(f"Virtual environment: {sys.prefix}")
 241 |     
 242 |     # Check for Homebrew PyTorch installation
 243 |     has_homebrew_pytorch = False
 244 |     homebrew_pytorch_version = None
 245 |     if is_macos:
 246 |         try:
 247 |             # Check if pytorch is installed via brew
 248 |             result = subprocess.run(
 249 |                 ['brew', 'list', 'pytorch', '--version'],
 250 |                 capture_output=True,
 251 |                 text=True
 252 |             )
 253 |             if result.returncode == 0:
 254 |                 has_homebrew_pytorch = True
 255 |                 # Extract version from output
 256 |                 version_line = result.stdout.strip()
 257 |                 homebrew_pytorch_version = version_line.split()[1] if len(version_line.split()) > 1 else "Unknown"
 258 |                 print_info(f"Detected Homebrew PyTorch installation: {homebrew_pytorch_version}")
 259 |         except (subprocess.SubprocessError, FileNotFoundError):
 260 |             pass
 261 |     
 262 |     return {
 263 |         "system": system,
 264 |         "machine": machine,
 265 |         "python_version": python_version,
 266 |         "is_windows": is_windows,
 267 |         "is_macos": is_macos,
 268 |         "is_linux": is_linux,
 269 |         "is_arm": is_arm,
 270 |         "is_x86": is_x86,
 271 |         "in_venv": in_venv,
 272 |         "has_homebrew_pytorch": has_homebrew_pytorch,
 273 |         "homebrew_pytorch_version": homebrew_pytorch_version
 274 |     }
 275 | 
 276 | def detect_gpu():
 277 |     """Detect GPU and acceleration capabilities.
 278 | 
 279 |     Wrapper function that uses the shared GPU detection module.
 280 |     """
 281 |     system_info = detect_system()
 282 | 
 283 |     # Use shared GPU detection module
 284 |     gpu_info = shared_detect_gpu(system_info)
 285 | 
 286 |     # Print GPU information (maintain installer output format)
 287 |     if gpu_info.get("has_cuda"):
 288 |         cuda_version = gpu_info.get("cuda_version")
 289 |         print_info(f"CUDA detected: {cuda_version or 'Unknown version'}")
 290 |     if gpu_info.get("has_rocm"):
 291 |         rocm_version = gpu_info.get("rocm_version")
 292 |         print_info(f"ROCm detected: {rocm_version or 'Unknown version'}")
 293 |     if gpu_info.get("has_mps"):
 294 |         print_info("Apple Metal Performance Shaders (MPS) detected")
 295 |     if gpu_info.get("has_directml"):
 296 |         directml_version = gpu_info.get("directml_version")
 297 |         if directml_version:
 298 |             print_info(f"DirectML detected: {directml_version}")
 299 |         else:
 300 |             print_info("DirectML detected")
 301 | 
 302 |     if not (gpu_info.get("has_cuda") or gpu_info.get("has_rocm") or
 303 |             gpu_info.get("has_mps") or gpu_info.get("has_directml")):
 304 |         print_info("No GPU acceleration detected, will use CPU-only mode")
 305 | 
 306 |     return gpu_info
 307 | 
 308 | def check_dependencies():
 309 |     """Check for required dependencies.
 310 |     
 311 |     Note on package managers:
 312 |     - Traditional virtual environments (venv, virtualenv) include pip by default
 313 |     - Alternative package managers like uv may not include pip or may manage packages differently
 314 |     - We attempt multiple detection methods for pip and only fail if:
 315 |       a) We're not in a virtual environment, or
 316 |       b) We can't detect pip AND can't install dependencies
 317 |     
 318 |     We proceed with installation even if pip isn't detected when in a virtual environment,
 319 |     assuming an alternative package manager (like uv) is handling dependencies.
 320 |     
 321 |     Returns:
 322 |         bool: True if all dependencies are met, False otherwise.
 323 |     """
 324 |     print_step("2", "Checking dependencies")
 325 |     
 326 |     # Check for pip
 327 |     pip_installed = False
 328 |     
 329 |     # Try subprocess check first
 330 |     success, _ = run_command_safe(
 331 |         [sys.executable, '-m', 'pip', '--version'],
 332 |         success_msg="pip is installed",
 333 |         silent=True,
 334 |         fallback_in_venv=True
 335 |     )
 336 | 
 337 |     if success:
 338 |         pip_installed = True
 339 |     else:
 340 |         # Fallback to import check
 341 |         try:
 342 |             import pip
 343 |             pip_installed = True
 344 |             print_info(f"pip is installed: {pip.__version__}")
 345 |         except ImportError:
 346 |             # Check if we're in a virtual environment
 347 |             in_venv = sys.prefix != sys.base_prefix
 348 |             if in_venv:
 349 |                 print_warning("pip could not be detected, but you're in a virtual environment. "
 350 |                             "If you're using uv or another alternative package manager, this is normal. "
 351 |                             "Continuing installation...")
 352 |                 pip_installed = True  # Proceed anyway
 353 |             else:
 354 |                 print_error("pip is not installed. Please install pip first.")
 355 |                 return False
 356 |     
 357 |     # Check for setuptools
 358 |     try:
 359 |         import setuptools
 360 |         print_info(f"setuptools is installed: {setuptools.__version__}")
 361 |     except ImportError:
 362 |         print_warning("setuptools is not installed. Will attempt to install it.")
 363 |         # If pip is available, use it to install setuptools
 364 |         if pip_installed:
 365 |             success = install_package_safe("setuptools")
 366 |             if not success:
 367 |                 return False
 368 |         else:
 369 |             # Should be unreachable since pip_installed would only be False if we returned earlier
 370 |             print_error("Cannot install setuptools without pip. Please install setuptools manually.")
 371 |             return False
 372 |     
 373 |     # Check for wheel
 374 |     try:
 375 |         import wheel
 376 |         print_info(f"wheel is installed: {wheel.__version__}")
 377 |     except ImportError:
 378 |         print_warning("wheel is not installed. Will attempt to install it.")
 379 |         # If pip is available, use it to install wheel
 380 |         if pip_installed:
 381 |             success = install_package_safe("wheel")
 382 |             if not success:
 383 |                 return False
 384 |         else:
 385 |             # Should be unreachable since pip_installed would only be False if we returned earlier
 386 |             print_error("Cannot install wheel without pip. Please install wheel manually.")
 387 |             return False
 388 |     
 389 |     return True
 390 | 
 391 | def install_pytorch_platform_specific(system_info, gpu_info):
 392 |     """Install PyTorch with platform-specific configurations."""
 393 |     if system_info["is_windows"]:
 394 |         return install_pytorch_windows(gpu_info)
 395 |     elif system_info["is_macos"] and system_info["is_x86"]:
 396 |         return install_pytorch_macos_intel()
 397 |     else:
 398 |         # For other platforms, let the regular installer handle it
 399 |         return True
 400 | 
 401 | def install_pytorch_macos_intel():
 402 |     """Install PyTorch specifically for macOS with Intel CPUs."""
 403 |     print_step("3a", "Installing PyTorch for macOS Intel CPU")
 404 |     
 405 |     # Use the versions known to work well on macOS Intel and with Python 3.13+
 406 |     try:
 407 |         # For Python 3.13+, we need newer PyTorch versions
 408 |         python_version = sys.version_info
 409 |         
 410 |         if python_version >= (3, 13):
 411 |             # For Python 3.13+, try to install latest compatible version
 412 |             print_info(f"Installing PyTorch for macOS Intel (Python {python_version.major}.{python_version.minor})...")
 413 |             print_info("Attempting to install latest PyTorch compatible with Python 3.13...")
 414 |             
 415 |             # Try to install without version specifiers to get latest compatible version
 416 |             cmd = [
 417 |                 sys.executable, '-m', 'pip', 'install',
 418 |                 "torch", "torchvision", "torchaudio"
 419 |             ]
 420 |             success, _ = run_command_safe(
 421 |                 cmd,
 422 |                 success_msg="Latest PyTorch installed successfully",
 423 |                 silent=False
 424 |             )
 425 | 
 426 |             if success:
 427 |                 st_version = "3.0.0"  # Newer sentence-transformers for newer PyTorch
 428 |             else:
 429 |                 print_warning("Failed to install latest PyTorch, trying fallback version...")
 430 |                 # Fallback to a specific version
 431 |                 torch_version = "2.1.0"
 432 |                 torch_vision_version = "0.16.0"
 433 |                 torch_audio_version = "2.1.0"
 434 |                 st_version = "3.0.0"
 435 | 
 436 |                 print_info(f"Trying fallback to PyTorch {torch_version}...")
 437 | 
 438 |                 cmd = [
 439 |                     sys.executable, '-m', 'pip', 'install',
 440 |                     f"torch=={torch_version}",
 441 |                     f"torchvision=={torch_vision_version}",
 442 |                     f"torchaudio=={torch_audio_version}"
 443 |                 ]
 444 |                 success, _ = run_command_safe(
 445 |                     cmd,
 446 |                     success_msg=f"PyTorch {torch_version} installed successfully",
 447 |                     error_msg="Failed to install PyTorch fallback version",
 448 |                     silent=False
 449 |                 )
 450 |                 if not success:
 451 |                     return False
 452 |         else:
 453 |             # Use traditional versions for older Python
 454 |             torch_version = "1.13.1"
 455 |             torch_vision_version = "0.14.1"
 456 |             torch_audio_version = "0.13.1"
 457 |             st_version = "2.2.2"
 458 |             
 459 |             print_info(f"Installing PyTorch {torch_version} for macOS Intel (Python {python_version.major}.{python_version.minor})...")
 460 |             
 461 |             # Install PyTorch first with compatible version
 462 |             packages = [f"torch=={torch_version}", f"torchvision=={torch_vision_version}", f"torchaudio=={torch_audio_version}"]
 463 |             success, _ = run_command_safe(
 464 |                 [sys.executable, '-m', 'pip', 'install'] + packages,
 465 |                 success_msg=f"PyTorch {torch_version} installed successfully"
 466 |             )
 467 |             if not success:
 468 |                 raise RuntimeError(f"Failed to install PyTorch {torch_version}")
 469 |         
 470 |         # Install a compatible version of sentence-transformers
 471 |         print_info(f"Installing sentence-transformers {st_version}...")
 472 |         success, _ = run_command_safe(
 473 |             [sys.executable, '-m', 'pip', 'install', f"sentence-transformers=={st_version}"],
 474 |             success_msg=f"sentence-transformers {st_version} installed successfully"
 475 |         )
 476 |         if not success:
 477 |             raise RuntimeError(f"Failed to install sentence-transformers {st_version}")
 478 |         
 479 |         print_success(f"PyTorch {torch_version} and sentence-transformers {st_version} installed successfully for macOS Intel")
 480 |         return True
 481 |     except RuntimeError as e:
 482 |         print_error(f"Failed to install PyTorch for macOS Intel: {e}")
 483 |         
 484 |         # Provide fallback instructions
 485 |         if python_version >= (3, 13):
 486 |             print_warning("You may need to manually install compatible versions for Python 3.13+ on Intel macOS:")
 487 |             print_info("pip install torch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0")
 488 |             print_info("pip install sentence-transformers==3.0.0")
 489 |         else:
 490 |             print_warning("You may need to manually install compatible versions for Intel macOS:")
 491 |             print_info("pip install torch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1")
 492 |             print_info("pip install sentence-transformers==2.2.2")
 493 |         
 494 |         return False
 495 | 
 496 | def install_pytorch_windows(gpu_info):
 497 |     """Install PyTorch on Windows using the appropriate index URL."""
 498 |     print_step("3a", "Installing PyTorch for Windows")
 499 |     
 500 |     # Determine the appropriate PyTorch index URL based on GPU
 501 |     if gpu_info["has_cuda"]:
 502 |         # Get CUDA version and determine appropriate index URL
 503 |         cuda_version = gpu_info.get("cuda_version", "")
 504 |         
 505 |         # Extract major version from CUDA version string
 506 |         cuda_major = None
 507 |         if cuda_version:
 508 |             # Try to extract the major version (e.g., "11.8" -> "11")
 509 |             try:
 510 |                 cuda_major = cuda_version.split('.')[0]
 511 |             except (IndexError, AttributeError):
 512 |                 pass
 513 |         
 514 |         # Default to cu118 if we couldn't determine the version or it's not a common one
 515 |         if cuda_major == "12":
 516 |             cuda_suffix = "cu121"  # CUDA 12.x
 517 |             print_info(f"Detected CUDA {cuda_version}, using cu121 channel")
 518 |         elif cuda_major == "11":
 519 |             cuda_suffix = "cu118"  # CUDA 11.x
 520 |             print_info(f"Detected CUDA {cuda_version}, using cu118 channel")
 521 |         elif cuda_major == "10":
 522 |             cuda_suffix = "cu102"  # CUDA 10.x
 523 |             print_info(f"Detected CUDA {cuda_version}, using cu102 channel")
 524 |         else:
 525 |             # Default to cu118 as a safe choice for newer NVIDIA GPUs
 526 |             cuda_suffix = "cu118"
 527 |             print_info(f"Using default cu118 channel for CUDA {cuda_version}")
 528 |             
 529 |         index_url = f"https://download.pytorch.org/whl/{cuda_suffix}"
 530 |     else:
 531 |         # CPU-only version
 532 |         index_url = "https://download.pytorch.org/whl/cpu"
 533 |         print_info("Using CPU-only PyTorch for Windows")
 534 |     
 535 |     # Install PyTorch with the appropriate index URL
 536 |     try:
 537 |         # Use a stable version that's known to have Windows wheels
 538 |         torch_version = "2.1.0"  # This version has Windows wheels available
 539 |         
 540 |         cmd = [
 541 |             sys.executable, '-m', 'pip', 'install',
 542 |             f"torch=={torch_version}",
 543 |             f"torchvision=={torch_version}",
 544 |             f"torchaudio=={torch_version}",
 545 |             f"--index-url={index_url}"
 546 |         ]
 547 |         
 548 |         success, _ = run_command_safe(
 549 |             cmd,
 550 |             success_msg="PyTorch installed successfully for Windows",
 551 |             error_msg="Failed to install PyTorch for Windows",
 552 |             silent=False
 553 |         )
 554 |         if not success:
 555 |             return False
 556 |         
 557 |         # Check if DirectML is needed
 558 |         if gpu_info["has_directml"]:
 559 |             success = install_package_safe(
 560 |                 "torch-directml>=0.2.0",
 561 |                 success_msg="torch-directml installed successfully for DirectML support",
 562 |                 error_msg="Failed to install torch-directml"
 563 |             )
 564 |             if not success:
 565 |                 print_warning("DirectML support may not be available")
 566 |             
 567 |         print_success("PyTorch installed successfully for Windows")
 568 |         return True
 569 |     except RuntimeError as e:
 570 |         print_error(f"Failed to install PyTorch for Windows: {e}")
 571 |         print_warning("You may need to manually install PyTorch using instructions from https://pytorch.org/get-started/locally/")
 572 |         return False
 573 | 
 574 | def detect_storage_backend_compatibility(system_info, gpu_info):
 575 |     """Detect which storage backends are compatible with the current environment."""
 576 |     print_step("3a", "Analyzing storage backend compatibility")
 577 |     
 578 |     compatibility = {
 579 |         "cloudflare": {"supported": True, "issues": [], "recommendation": "production"},
 580 |         "sqlite_vec": {"supported": True, "issues": [], "recommendation": "development"},
 581 |         "chromadb": {"supported": True, "issues": [], "recommendation": "team"},
 582 |         "hybrid": {"supported": True, "issues": [], "recommendation": "recommended"}
 583 |     }
 584 |     
 585 |     # Check ChromaDB compatibility issues
 586 |     chromadb_issues = []
 587 |     
 588 |     # macOS Intel compatibility issues
 589 |     if system_info["is_macos"] and system_info["is_x86"]:
 590 |         chromadb_issues.append("ChromaDB has known installation issues on older macOS Intel systems")
 591 |         chromadb_issues.append("May require specific dependency versions")
 592 |         compatibility["chromadb"]["recommendation"] = "problematic"
 593 |         compatibility["sqlite_vec"]["recommendation"] = "recommended"
 594 |     
 595 |     # Memory constraints
 596 |     total_memory_gb = 0
 597 |     try:
 598 |         import psutil
 599 |         total_memory_gb = psutil.virtual_memory().total / (1024**3)
 600 |     except ImportError:
 601 |         # Fallback memory detection
 602 |         try:
 603 |             with open('/proc/meminfo', 'r') as f:
 604 |                 for line in f:
 605 |                     if line.startswith('MemTotal:'):
 606 |                         total_memory_gb = int(line.split()[1]) / (1024**2)
 607 |                         break
 608 |         except (FileNotFoundError, IOError):
 609 |             pass
 610 |     
 611 |     if total_memory_gb > 0 and total_memory_gb < 4:
 612 |         chromadb_issues.append(f"System has {total_memory_gb:.1f}GB RAM - ChromaDB may consume significant memory")
 613 |         compatibility["sqlite_vec"]["recommendation"] = "recommended"
 614 |     
 615 |     # Older Python versions
 616 |     python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
 617 |     if sys.version_info < (3, 9):
 618 |         chromadb_issues.append(f"Python {python_version} may have ChromaDB compatibility issues")
 619 |     
 620 |     # ARM architecture considerations
 621 |     if system_info["is_arm"]:
 622 |         print_info("ARM architecture detected - both backends should work well")
 623 |     
 624 |     compatibility["chromadb"]["issues"] = chromadb_issues
 625 |     
 626 |     # Print compatibility analysis
 627 |     print_info("Storage Backend Compatibility Analysis:")
 628 |     
 629 |     for backend, info in compatibility.items():
 630 |         status = "✅" if info["supported"] else "❌"
 631 |         rec_text = {
 632 |             "production": "☁️ PRODUCTION (Cloud)",
 633 |             "development": "🪶 DEVELOPMENT (Local)",
 634 |             "team": "👥 TEAM (Multi-client)",
 635 |             "recommended": "🌟 RECOMMENDED",
 636 |             "default": "📦 Standard",
 637 |             "problematic": "⚠️  May have issues",
 638 |             "lightweight": "🪶 Lightweight"
 639 |         }.get(info["recommendation"], "")
 640 |         
 641 |         print_info(f"  {status} {backend.upper()}: {rec_text}")
 642 |         
 643 |         if info["issues"]:
 644 |             for issue in info["issues"]:
 645 |                 print_info(f"    • {issue}")
 646 |     
 647 |     return compatibility
 648 | 
 649 | def choose_storage_backend(system_info, gpu_info, args):
 650 |     """Choose storage backend based on environment and user preferences."""
 651 |     compatibility = detect_storage_backend_compatibility(system_info, gpu_info)
 652 |     
 653 |     # Check if user specified a backend via environment
 654 |     env_backend = os.environ.get('MCP_MEMORY_STORAGE_BACKEND')
 655 |     if env_backend:
 656 |         print_info(f"Using storage backend from environment: {env_backend}")
 657 |         return env_backend
 658 |     
 659 |     # Check for command line argument (we'll add this)
 660 |     if hasattr(args, 'storage_backend') and args.storage_backend:
 661 |         print_info(f"Using storage backend from command line: {args.storage_backend}")
 662 |         return args.storage_backend
 663 |     
 664 |     # Auto-select based on compatibility
 665 |     recommended_backend = None
 666 |     for backend, info in compatibility.items():
 667 |         if info["recommendation"] == "recommended":
 668 |             recommended_backend = backend
 669 |             break
 670 |     
 671 |     if not recommended_backend:
 672 |         recommended_backend = "sqlite_vec"  # Default fallback for local development
 673 | 
 674 |     # Interactive backend selection
 675 |     print_step("3b", "Storage Backend Selection")
 676 |     print_info("Choose the storage backend that best fits your use case:")
 677 |     print_info("")
 678 |     print_info("Usage scenarios:")
 679 |     print_info("  1. Production/Shared (Cloudflare) - Cloud storage, multi-user access, requires credentials")
 680 |     print_info("  2. Development/Personal (SQLite-vec) - Local, lightweight, single-user")
 681 |     print_info("  3. Team/Multi-client (ChromaDB) - Local server, multiple clients")
 682 |     print_info("  4. Hybrid (Recommended) - Fast local SQLite + background Cloudflare sync")
 683 |     print_info("  5. Auto-detect - Try optimal backend based on your system")
 684 |     print_info("")
 685 | 
 686 |     # Show compatibility analysis
 687 |     for i, (backend, info) in enumerate(compatibility.items(), 1):
 688 |         if backend == "auto_detect":
 689 |             continue
 690 |         status = "✅" if info["supported"] else "❌"
 691 |         rec_text = {
 692 |             "production": "☁️ PRODUCTION (Cloud)",
 693 |             "development": "🪶 DEVELOPMENT (Local)",
 694 |             "team": "👥 TEAM (Multi-client)",
 695 |             "recommended": "🌟 RECOMMENDED",
 696 |             "problematic": "⚠️  May have issues"
 697 |         }.get(info["recommendation"], "")
 698 |         print_info(f"  {status} {i}. {backend.upper()}: {rec_text}")
 699 |         if info["issues"]:
 700 |             for issue in info["issues"]:
 701 |                 print_info(f"     • {issue}")
 702 | 
 703 |     print_info("")
 704 |     default_choice = "2" if compatibility["chromadb"]["recommendation"] == "problematic" else "2"
 705 | 
 706 |     while True:
 707 |         try:
 708 |             choice = input(f"Choose storage backend [1-5] (default: 4 - hybrid): ").strip()
 709 |             if not choice:
 710 |                 choice = "4"  # Default to hybrid
 711 | 
 712 |             if choice == "1":
 713 |                 return "cloudflare"
 714 |             elif choice == "2":
 715 |                 return "sqlite_vec"
 716 |             elif choice == "3":
 717 |                 return "chromadb"
 718 |             elif choice == "4":
 719 |                 return "hybrid"
 720 |             elif choice == "5":
 721 |                 return "auto_detect"
 722 |             else:
 723 |                 print_error("Please enter 1, 2, 3, 4, or 5")
 724 |         except (EOFError, KeyboardInterrupt):
 725 |             print_info(f"\nUsing recommended backend: hybrid")
 726 |             return "hybrid"
 727 | 
 728 | def setup_cloudflare_credentials():
 729 |     """Interactive setup of Cloudflare credentials."""
 730 |     print_step("3c", "Cloudflare Backend Setup")
 731 |     print_info("Cloudflare backend requires API credentials for D1 database and Vectorize index.")
 732 |     print_info("You'll need:")
 733 |     print_info("  • Cloudflare API Token (with D1 and Vectorize permissions)")
 734 |     print_info("  • Account ID")
 735 |     print_info("  • D1 Database ID")
 736 |     print_info("  • Vectorize Index name")
 737 |     print_info("")
 738 |     print_info("Visit https://dash.cloudflare.com to get these credentials.")
 739 |     print_info("")
 740 | 
 741 |     credentials = {}
 742 | 
 743 |     try:
 744 |         # Get API Token
 745 |         while True:
 746 |             token = input("Enter Cloudflare API Token: ").strip()
 747 |             if token:
 748 |                 credentials['CLOUDFLARE_API_TOKEN'] = token
 749 |                 break
 750 |             print_error("API token is required")
 751 | 
 752 |         # Get Account ID
 753 |         while True:
 754 |             account_id = input("Enter Cloudflare Account ID: ").strip()
 755 |             if account_id:
 756 |                 credentials['CLOUDFLARE_ACCOUNT_ID'] = account_id
 757 |                 break
 758 |             print_error("Account ID is required")
 759 | 
 760 |         # Get D1 Database ID
 761 |         while True:
 762 |             d1_id = input("Enter D1 Database ID: ").strip()
 763 |             if d1_id:
 764 |                 credentials['CLOUDFLARE_D1_DATABASE_ID'] = d1_id
 765 |                 break
 766 |             print_error("D1 Database ID is required")
 767 | 
 768 |         # Get Vectorize Index
 769 |         vectorize_index = input("Enter Vectorize Index name (default: mcp-memory-index): ").strip()
 770 |         if not vectorize_index:
 771 |             vectorize_index = "mcp-memory-index"
 772 |         credentials['CLOUDFLARE_VECTORIZE_INDEX'] = vectorize_index
 773 | 
 774 |         # Set storage backend
 775 |         credentials['MCP_MEMORY_STORAGE_BACKEND'] = 'cloudflare'
 776 | 
 777 |         return credentials
 778 | 
 779 |     except (EOFError, KeyboardInterrupt):
 780 |         print_info("\nCloudflare setup cancelled.")
 781 |         return None
 782 | 
 783 | def save_credentials_to_env(credentials):
 784 |     """Save credentials to .env file and current environment."""
 785 |     env_file = Path('.env')
 786 | 
 787 |     # Read existing .env content if it exists
 788 |     existing_lines = []
 789 |     if env_file.exists():
 790 |         with open(env_file, 'r') as f:
 791 |             existing_lines = f.readlines()
 792 | 
 793 |     # Filter out any existing Cloudflare variables
 794 |     filtered_lines = [
 795 |         line for line in existing_lines
 796 |         if not any(key in line for key in credentials.keys())
 797 |     ]
 798 | 
 799 |     # Add new credentials
 800 |     with open(env_file, 'w') as f:
 801 |         # Write existing non-Cloudflare lines
 802 |         f.writelines(filtered_lines)
 803 | 
 804 |         # Add separator if file wasn't empty
 805 |         if filtered_lines and not filtered_lines[-1].endswith('\n'):
 806 |             f.write('\n')
 807 |         if filtered_lines:
 808 |             f.write('\n# Cloudflare Backend Configuration\n')
 809 | 
 810 |         # Write Cloudflare credentials
 811 |         for key, value in credentials.items():
 812 |             f.write(f'{key}={value}\n')
 813 | 
 814 |     # Also set credentials in current environment for immediate use
 815 |     for key, value in credentials.items():
 816 |         os.environ[key] = value
 817 | 
 818 |     print_success(f"Credentials saved to .env file and current environment")
 819 | 
 820 | def test_cloudflare_connection(credentials):
 821 |     """Test Cloudflare API connection."""
 822 |     print_info("Testing Cloudflare API connection...")
 823 | 
 824 |     try:
 825 |         import requests
 826 | 
 827 |         headers = {
 828 |             'Authorization': f"Bearer {credentials['CLOUDFLARE_API_TOKEN']}",
 829 |             'Content-Type': 'application/json'
 830 |         }
 831 | 
 832 |         # Test API token validity
 833 |         response = requests.get(
 834 |             "https://api.cloudflare.com/client/v4/user/tokens/verify",
 835 |             headers=headers,
 836 |             timeout=10
 837 |         )
 838 | 
 839 |         if response.status_code == 200:
 840 |             data = response.json()
 841 |             if data.get("success"):
 842 |                 print_success("API token is valid")
 843 |                 return True
 844 |             else:
 845 |                 print_error(f"API token validation failed: {data.get('errors')}")
 846 |                 return False
 847 |         else:
 848 |             print_error(f"API connection failed with status {response.status_code}")
 849 |             return False
 850 | 
 851 |     except ImportError:
 852 |         print_warning("Could not test connection (requests not installed)")
 853 |         print_info("Connection will be tested when the service starts")
 854 |         return True
 855 |     except Exception as e:
 856 |         print_warning(f"Could not test connection: {e}")
 857 |         print_info("Connection will be tested when the service starts")
 858 |         return True
 859 | 
 860 | def install_storage_backend(backend, system_info):
 861 |     """Install the chosen storage backend."""
 862 |     print_step("3c", f"Installing {backend} storage backend")
 863 | 
 864 |     if backend == "cloudflare":
 865 |         print_info("Cloudflare backend uses cloud services - no local dependencies needed")
 866 | 
 867 |         # Setup credentials interactively
 868 |         credentials = setup_cloudflare_credentials()
 869 |         if not credentials:
 870 |             print_warning("Cloudflare setup cancelled. Falling back to SQLite-vec.")
 871 |             return install_storage_backend("sqlite_vec", system_info)
 872 | 
 873 |         # Save credentials to .env file
 874 |         save_credentials_to_env(credentials)
 875 | 
 876 |         # Test connection
 877 |         connection_ok = test_cloudflare_connection(credentials)
 878 |         if connection_ok:
 879 |             print_success("Cloudflare backend configured successfully")
 880 |             return "cloudflare"
 881 |         else:
 882 |             print_warning("Cloudflare connection test failed. You can continue and fix credentials later.")
 883 |             fallback = input("Continue with Cloudflare anyway? [y/N]: ").strip().lower()
 884 |             if fallback.startswith('y'):
 885 |                 return "cloudflare"
 886 |             else:
 887 |                 print_info("Falling back to SQLite-vec for local development.")
 888 |                 return install_storage_backend("sqlite_vec", system_info)
 889 | 
 890 |     elif backend == "sqlite_vec":
 891 |         return install_package_safe(
 892 |             "sqlite-vec",
 893 |             success_msg="SQLite-vec installed successfully",
 894 |             error_msg="Failed to install SQLite-vec"
 895 |         )
 896 | 
 897 |     elif backend == "hybrid":
 898 |         print_info("Hybrid backend combines fast local SQLite with background Cloudflare sync")
 899 | 
 900 |         # First install SQLite-vec for local storage
 901 |         print_info("Installing SQLite-vec for local storage...")
 902 |         sqlite_success = install_package_safe(
 903 |             "sqlite-vec",
 904 |             success_msg="SQLite-vec installed successfully",
 905 |             error_msg="Failed to install SQLite-vec"
 906 |         )
 907 |         if not sqlite_success:
 908 |             print_error("Hybrid backend requires SQLite-vec. Installation failed.")
 909 |             return False
 910 | 
 911 |         # Setup Cloudflare credentials for cloud sync
 912 |         print_info("Configuring Cloudflare for background synchronization...")
 913 |         credentials = setup_cloudflare_credentials()
 914 |         if not credentials:
 915 |             print_warning("Cloudflare setup cancelled.")
 916 |             fallback = input("Continue with SQLite-vec only? [Y/n]: ").strip().lower()
 917 |             if not fallback or fallback.startswith('y'):
 918 |                 print_info("Falling back to SQLite-vec for local-only operation.")
 919 |                 return "sqlite_vec"
 920 |             else:
 921 |                 return False
 922 | 
 923 |         # Update credentials to set hybrid backend
 924 |         credentials['MCP_MEMORY_STORAGE_BACKEND'] = 'hybrid'
 925 | 
 926 |         # Save credentials to .env file
 927 |         save_credentials_to_env(credentials)
 928 | 
 929 |         # Test connection
 930 |         connection_ok = test_cloudflare_connection(credentials)
 931 |         if connection_ok:
 932 |             print_success("Hybrid backend configured successfully")
 933 |             print_info("  • Local storage: SQLite-vec (5ms reads)")
 934 |             print_info("  • Cloud sync: Cloudflare (background)")
 935 |             return "hybrid"
 936 |         else:
 937 |             print_warning("Cloudflare connection test failed.")
 938 |             fallback = input("Continue with hybrid (will sync when connection available)? [Y/n]: ").strip().lower()
 939 |             if not fallback or fallback.startswith('y'):
 940 |                 print_info("Hybrid backend will sync to Cloudflare when connection is available")
 941 |                 return "hybrid"
 942 |             else:
 943 |                 print_info("Falling back to SQLite-vec for local development.")
 944 |                 return "sqlite_vec"
 945 | 
 946 |     elif backend == "chromadb":
 947 |         chromadb_version = "0.5.23"
 948 |         success = install_package_safe(
 949 |             f"chromadb=={chromadb_version}",
 950 |             success_msg=f"ChromaDB {chromadb_version} installed successfully",
 951 |             error_msg="Failed to install ChromaDB"
 952 |         )
 953 |         if not success:
 954 |             print_info("This is a known issue on some systems (especially older macOS Intel)")
 955 |         return success
 956 |             
 957 |     elif backend == "auto_detect":
 958 |         print_info("Attempting auto-detection...")
 959 |         print_info("Auto-detect will prioritize local backends (SQLite-vec, ChromaDB)")
 960 |         print_info("For production use, manually select Cloudflare backend.")
 961 | 
 962 |         # For auto-detect, try SQLite-vec first (most reliable)
 963 |         print_info("Trying SQLite-vec installation...")
 964 |         if install_storage_backend("sqlite_vec", system_info):
 965 |             print_success("SQLite-vec installed successfully")
 966 |             return "sqlite_vec"
 967 | 
 968 |         print_warning("SQLite-vec installation failed, trying ChromaDB...")
 969 |         if install_storage_backend("chromadb", system_info):
 970 |             print_success("ChromaDB installed successfully as fallback")
 971 |             return "chromadb"
 972 | 
 973 |         print_error("All local storage backends failed to install")
 974 |         print_info("Consider manually configuring Cloudflare backend for production use")
 975 |         return False
 976 |     
 977 |     return False
 978 | 
 979 | def _detect_installer_command():
 980 |     """Detect available package installer (pip or uv)."""
 981 |     # Check if pip is available
 982 |     pip_available, _ = run_command_safe(
 983 |         [sys.executable, '-m', 'pip', '--version'],
 984 |         silent=True
 985 |     )
 986 | 
 987 |     # Detect if uv is available
 988 |     uv_path = shutil.which("uv")
 989 |     uv_available = uv_path is not None
 990 | 
 991 |     # Decide installer command prefix
 992 |     if pip_available:
 993 |         return [sys.executable, '-m', 'pip']
 994 |     elif uv_available:
 995 |         print_warning("pip not found, but uv detected. Using 'uv pip' for installation.")
 996 |         return ['uv', 'pip']
 997 |     else:
 998 |         print_error("Neither pip nor uv detected. Cannot install packages.")
 999 |         return None
1000 | 
1001 | def _setup_storage_and_gpu_environment(args, system_info, gpu_info, env):
1002 |     """Set up storage backend and GPU environment variables."""
1003 |     # Choose and install storage backend
1004 |     chosen_backend = choose_storage_backend(system_info, gpu_info, args)
1005 | 
1006 |     # Check if chromadb was chosen but flag not provided
1007 |     if chosen_backend == "chromadb" and not args.with_chromadb:
1008 |         print_warning("ChromaDB backend selected but --with-chromadb flag not provided")
1009 |         print_info("ChromaDB requires heavy ML dependencies (~1-2GB).")
1010 |         print_info("To use ChromaDB, run: python scripts/installation/install.py --with-chromadb")
1011 |         print_info("Switching to SQLite-vec backend instead...")
1012 |         chosen_backend = "sqlite_vec"
1013 | 
1014 |     # ChromaDB automatically includes ML dependencies
1015 |     if args.with_chromadb:
1016 |         args.with_ml = True
1017 | 
1018 |     if chosen_backend == "auto_detect":
1019 |         # Handle auto-detection case - prefer sqlite_vec if chromadb not explicitly requested
1020 |         if not args.with_chromadb:
1021 |             print_info("Auto-detection: Using SQLite-vec (lightweight option)")
1022 |             chosen_backend = "sqlite_vec"
1023 |         else:
1024 |             actual_backend = install_storage_backend(chosen_backend, system_info)
1025 |             if not actual_backend:
1026 |                 print_error("Failed to install any storage backend")
1027 |                 return False
1028 |             chosen_backend = actual_backend
1029 |     else:
1030 |         # Install the chosen backend
1031 |         if not install_storage_backend(chosen_backend, system_info):
1032 |             print_error(f"Failed to install {chosen_backend} storage backend")
1033 |             return False
1034 | 
1035 |     # Set environment variable for chosen backend
1036 |     if chosen_backend in ["sqlite_vec", "hybrid", "cloudflare"]:
1037 |         env['MCP_MEMORY_STORAGE_BACKEND'] = chosen_backend
1038 |         if chosen_backend == "sqlite_vec":
1039 |             print_info("Configured to use SQLite-vec storage backend")
1040 |         elif chosen_backend == "hybrid":
1041 |             print_info("Configured to use Hybrid storage backend (SQLite + Cloudflare)")
1042 |         elif chosen_backend == "cloudflare":
1043 |             print_info("Configured to use Cloudflare storage backend")
1044 |     else:
1045 |         env['MCP_MEMORY_STORAGE_BACKEND'] = 'chromadb'
1046 |         print_info("Configured to use ChromaDB storage backend")
1047 | 
1048 |     # Set environment variables based on detected GPU
1049 |     if gpu_info.get("has_cuda"):
1050 |         print_info("Configuring for CUDA installation")
1051 |     elif gpu_info.get("has_rocm"):
1052 |         print_info("Configuring for ROCm installation")
1053 |         env['MCP_MEMORY_USE_ROCM'] = '1'
1054 |     elif gpu_info.get("has_mps"):
1055 |         print_info("Configuring for Apple Silicon MPS installation")
1056 |         env['PYTORCH_ENABLE_MPS_FALLBACK'] = '1'
1057 |     elif gpu_info.get("has_directml"):
1058 |         print_info("Configuring for DirectML installation")
1059 |         env['MCP_MEMORY_USE_DIRECTML'] = '1'
1060 |     else:
1061 |         print_info("Configuring for CPU-only installation")
1062 |         env['MCP_MEMORY_USE_ONNX'] = '1'
1063 | 
1064 |     # Check for Homebrew PyTorch installation
1065 |     using_homebrew_pytorch = False
1066 |     if system_info.get("has_homebrew_pytorch"):
1067 |         print_info(f"Using existing Homebrew PyTorch installation (version: {system_info.get('homebrew_pytorch_version')})")
1068 |         using_homebrew_pytorch = True
1069 |         # Set the environment variable to use ONNX for embeddings
1070 |         env['MCP_MEMORY_USE_ONNX'] = '1'
1071 |         # Skip the PyTorch installation step
1072 |         pytorch_installed = True
1073 |     else:
1074 |         # Handle platform-specific PyTorch installation
1075 |         pytorch_installed = install_pytorch_platform_specific(system_info, gpu_info)
1076 |         if not pytorch_installed:
1077 |             print_warning("Platform-specific PyTorch installation failed, but will continue with package installation")
1078 | 
1079 |     try:
1080 |         # SQLite-vec with ONNX for macOS with homebrew PyTorch or compatibility issues
1081 |         if (system_info["is_macos"] and system_info["is_x86"] and 
1082 |             (sys.version_info >= (3, 13) or using_homebrew_pytorch or args.skip_pytorch)):
1083 |             
1084 |             if using_homebrew_pytorch:
1085 |                 print_info("Using Homebrew PyTorch - installing with SQLite-vec + ONNX configuration")
1086 |             elif args.skip_pytorch:
1087 |                 print_info("Skipping PyTorch installation - using SQLite-vec + ONNX configuration")
1088 |             else:
1089 |                 print_info("Using Python 3.13+ on macOS Intel - using SQLite-vec + ONNX configuration")
1090 |             
1091 |             # First try to install without ML dependencies
1092 |             try:
1093 |                 cmd = installer_cmd + ['install', '--no-deps'] + install_mode + ['.']
1094 |                 success, _ = run_command_safe(
1095 |                     cmd,
1096 |                     success_msg="Package installed with --no-deps successfully",
1097 |                     error_msg="Failed to install package with --no-deps",
1098 |                     silent=False
1099 |                 )
1100 |                 if not success:
1101 |                     raise Exception("Installation failed")
1102 |                 
1103 |                 # Install core dependencies except torch/sentence-transformers
1104 |                 print_info("Installing core dependencies except ML libraries...")
1105 |                 
1106 |                 # Create a list of dependencies to install
1107 |                 # Note: mcp and tokenizers are already in core dependencies
1108 |                 dependencies = [
1109 |                     "onnxruntime>=1.14.1"  # ONNX runtime for lightweight embeddings
1110 |                 ]
1111 | 
1112 |                 # Add backend-specific dependencies (sqlite-vec, mcp, tokenizers are already in core)
1113 |                 if args.with_chromadb:
1114 |                     dependencies.append("chromadb==0.5.23")
1115 |                 
1116 |                 # Install dependencies
1117 |                 cmd = [sys.executable, '-m', 'pip', 'install'] + dependencies
1118 |                 success, _ = run_command_safe(
1119 |                     cmd,
1120 |                     success_msg="Core dependencies installed successfully",
1121 |                     error_msg="Failed to install core dependencies",
1122 |                     silent=False
1123 |                 )
1124 |                 if not success:
1125 |                     raise Exception("Core dependency installation failed")
1126 |                 
1127 |                 # Set environment variables for ONNX
1128 |                 print_info("Configuring to use ONNX runtime for inference without PyTorch...")
1129 |                 env['MCP_MEMORY_USE_ONNX'] = '1'
1130 |                 if chosen_backend != "sqlite_vec":
1131 |                     print_info("Switching to SQLite-vec backend for better compatibility")
1132 |                     env['MCP_MEMORY_STORAGE_BACKEND'] = 'sqlite_vec'
1133 |                 
1134 |                 print_success("MCP Memory Service installed successfully (SQLite-vec + ONNX)")
1135 |                 
1136 |                 if using_homebrew_pytorch:
1137 |                     print_info("Using Homebrew PyTorch installation for embedding generation")
1138 |                     print_info("Environment configured to use SQLite-vec backend and ONNX runtime")
1139 |                 else:
1140 |                     print_warning("ML libraries (PyTorch/sentence-transformers) were not installed due to compatibility issues")
1141 |                     print_info("The service will use ONNX runtime for inference instead")
1142 |                 
1143 |                 return True
1144 |             except Exception as e:
1145 |                 print_error(f"Failed to install with ONNX approach: {e}")
1146 |                 # Fall through to try standard installation
1147 |         
1148 |         # Standard installation with appropriate optional dependencies
1149 |         install_target = ['.']
1150 | 
1151 |         # Determine which optional dependencies to include based on backend and flags
1152 |         if args.with_chromadb:
1153 |             install_target = ['.[chromadb]']
1154 |             print_info("Installing with ChromaDB backend support (includes ML dependencies)")
1155 |         elif args.with_ml:
1156 |             if chosen_backend == "sqlite_vec":
1157 |                 install_target = ['.[sqlite-ml]']
1158 |                 print_info("Installing SQLite-vec with full ML capabilities (torch + sentence-transformers)")
1159 |             else:
1160 |                 install_target = ['.[ml]']
1161 |                 print_info("Installing with ML dependencies for semantic search and embeddings")
1162 |         elif chosen_backend == "sqlite_vec":
1163 |             install_target = ['.[sqlite]']
1164 |             print_info("Installing SQLite-vec with lightweight ONNX embeddings (recommended)")
1165 |             print_info("For full ML capabilities with SQLite-vec, use --with-ml flag")
1166 |         else:
1167 |             print_info("Installing lightweight version (no ML dependencies by default)")
1168 |             print_info("For full functionality, use --with-ml flag or install with: pip install mcp-memory-service[ml]")
1169 | 
1170 |         cmd = installer_cmd + ['install'] + install_mode + install_target
1171 |         success, _ = run_command_safe(
1172 |             cmd,
1173 |             success_msg="MCP Memory Service installed successfully",
1174 |             error_msg="Failed to install MCP Memory Service",
1175 |             silent=False
1176 |         )
1177 |         return success
1178 |     except Exception as e:
1179 |         print_error(f"Failed to install MCP Memory Service: {e}")
1180 |         
1181 |         # Special handling for macOS with compatibility issues
1182 |         if system_info["is_macos"] and system_info["is_x86"]:
1183 |             print_warning("Installation on macOS Intel is challenging")
1184 |             print_info("Try manually installing with:")
1185 |             print_info("1. pip install --no-deps .")
1186 |             print_info("2. pip install sqlite-vec>=0.1.0 mcp>=1.0.0,<2.0.0 onnxruntime>=1.14.1")
1187 |             print_info("3. export MCP_MEMORY_USE_ONNX=1")
1188 |             print_info("4. export MCP_MEMORY_STORAGE_BACKEND=sqlite_vec")
1189 |             
1190 |             if system_info.get("has_homebrew_pytorch"):
1191 |                 print_info("Homebrew PyTorch was detected but installation still failed.")
1192 |                 print_info("Try running: python install.py --storage-backend sqlite_vec --skip-pytorch")
1193 |             
1194 |         return False
1195 | 
1196 | def get_platform_base_dir() -> Path:
1197 |     """Get platform-specific base directory for MCP Memory storage.
1198 | 
1199 |     Returns:
1200 |         Path: Platform-appropriate base directory
1201 |     """
1202 |     home_dir = Path.home()
1203 | 
1204 |     PLATFORM_PATHS = {
1205 |         'Darwin': home_dir / 'Library' / 'Application Support' / 'mcp-memory',
1206 |         'Windows': Path(os.environ.get('LOCALAPPDATA', '')) / 'mcp-memory',
1207 |     }
1208 | 
1209 |     system = platform.system()
1210 |     return PLATFORM_PATHS.get(system, home_dir / '.local' / 'share' / 'mcp-memory')
1211 | 
1212 | 
1213 | def setup_storage_directories(backend: str, base_dir: Path, args) -> Tuple[Path, Path, bool]:
1214 |     """Setup storage and backup directories for the specified backend.
1215 | 
1216 |     Args:
1217 |         backend: Storage backend type
1218 |         base_dir: Base directory for storage
1219 |         args: Command line arguments
1220 | 
1221 |     Returns:
1222 |         Tuple of (storage_path, backups_path, success)
1223 |     """
1224 |     if backend in ['sqlite_vec', 'hybrid', 'cloudflare']:
1225 |         storage_path = args.chroma_path or (base_dir / 'sqlite_vec.db')
1226 |         storage_dir = storage_path.parent if storage_path.name.endswith('.db') else storage_path
1227 |     else:  # chromadb
1228 |         storage_path = args.chroma_path or (base_dir / 'chroma_db')
1229 |         storage_dir = storage_path
1230 | 
1231 |     backups_path = args.backups_path or (base_dir / 'backups')
1232 | 
1233 |     try:
1234 |         os.makedirs(storage_dir, exist_ok=True)
1235 |         os.makedirs(backups_path, exist_ok=True)
1236 | 
1237 |         # Test writability
1238 |         test_file = Path(storage_dir) / '.write_test'
1239 |         test_file.write_text('test')
1240 |         test_file.unlink()
1241 | 
1242 |         print_info(f"Storage path: {storage_path}")
1243 |         print_info(f"Backups path: {backups_path}")
1244 |         return storage_path, backups_path, True
1245 | 
1246 |     except (OSError, IOError, PermissionError) as e:
1247 |         print_error(f"Failed to configure storage paths: {e}")
1248 |         return storage_path, backups_path, False
1249 |     except Exception as e:
1250 |         print_error(f"Unexpected error configuring storage paths: {e}")
1251 |         return storage_path, backups_path, False
1252 | 
1253 | 
1254 | def build_mcp_env_config(storage_backend: str, storage_path: Path,
1255 |                          backups_path: Path) -> Dict[str, str]:
1256 |     """Build MCP environment configuration for Claude Desktop.
1257 | 
1258 |     Args:
1259 |         storage_backend: Type of storage backend
1260 |         storage_path: Path to storage directory/file
1261 |         backups_path: Path to backups directory
1262 | 
1263 |     Returns:
1264 |         Dict of environment variables for MCP configuration
1265 |     """
1266 |     env_config = {
1267 |         "MCP_MEMORY_BACKUPS_PATH": str(backups_path),
1268 |         "MCP_MEMORY_STORAGE_BACKEND": storage_backend
1269 |     }
1270 | 
1271 |     if storage_backend in ['sqlite_vec', 'hybrid']:
1272 |         env_config["MCP_MEMORY_SQLITE_PATH"] = str(storage_path)
1273 |         env_config["MCP_MEMORY_SQLITE_PRAGMAS"] = "busy_timeout=15000,cache_size=20000"
1274 | 
1275 |     if storage_backend in ['hybrid', 'cloudflare']:
1276 |         cloudflare_vars = [
1277 |             'CLOUDFLARE_API_TOKEN',
1278 |             'CLOUDFLARE_ACCOUNT_ID',
1279 |             'CLOUDFLARE_D1_DATABASE_ID',
1280 |             'CLOUDFLARE_VECTORIZE_INDEX'
1281 |         ]
1282 |         for var in cloudflare_vars:
1283 |             value = os.environ.get(var)
1284 |             if value:
1285 |                 env_config[var] = value
1286 | 
1287 |     if storage_backend == 'chromadb':
1288 |         env_config["MCP_MEMORY_CHROMA_PATH"] = str(storage_path)
1289 | 
1290 |     return env_config
1291 | 
1292 | 
1293 | def update_claude_config_file(config_path: Path, env_config: Dict[str, str],
1294 |                               project_root: Path, is_windows: bool) -> bool:
1295 |     """Update Claude Desktop configuration file with MCP Memory settings.
1296 | 
1297 |     Args:
1298 |         config_path: Path to Claude config file
1299 |         env_config: Environment configuration dictionary
1300 |         project_root: Root directory of the project
1301 |         is_windows: Whether running on Windows
1302 | 
1303 |     Returns:
1304 |         bool: True if update succeeded
1305 |     """
1306 |     try:
1307 |         config_text = config_path.read_text()
1308 |         config = json.loads(config_text)
1309 | 
1310 |         if not isinstance(config, dict):
1311 |             print_warning(f"Invalid config format in {config_path}")
1312 |             return False
1313 | 
1314 |         if 'mcpServers' not in config:
1315 |             config['mcpServers'] = {}
1316 | 
1317 |         # Create server configuration
1318 |         if is_windows:
1319 |             script_path = str((project_root / "memory_wrapper.py").resolve())
1320 |             config['mcpServers']['memory'] = {
1321 |                 "command": "python",
1322 |                 "args": [script_path],
1323 |                 "env": env_config
1324 |             }
1325 |         else:
1326 |             config['mcpServers']['memory'] = {
1327 |                 "command": "uv",
1328 |                 "args": [
1329 |                     "--directory",
1330 |                     str(project_root.resolve()),
1331 |                     "run",
1332 |                     "memory"
1333 |                 ],
1334 |                 "env": env_config
1335 |             }
1336 | 
1337 |         config_path.write_text(json.dumps(config, indent=2))
1338 |         print_success("Updated Claude Desktop configuration")
1339 |         return True
1340 | 
1341 |     except (OSError, PermissionError, json.JSONDecodeError) as e:
1342 |         print_warning(f"Failed to update Claude Desktop configuration: {e}")
1343 |         return False
1344 | 
1345 | 
1346 | def configure_paths(args):
1347 |     """Configure paths for the MCP Memory Service."""
1348 |     print_step("4", "Configuring paths")
1349 | 
1350 |     # Get system info
1351 |     system_info = detect_system()
1352 | 
1353 |     # Get platform-specific base directory
1354 |     base_dir = get_platform_base_dir()
1355 |     storage_backend = os.environ.get('MCP_MEMORY_STORAGE_BACKEND', 'chromadb')
1356 | 
1357 |     # Setup storage directories
1358 |     storage_path, backups_path, success = setup_storage_directories(
1359 |         storage_backend, base_dir, args
1360 |     )
1361 |     if not success:
1362 |         print_warning("Continuing with Claude Desktop configuration despite storage setup failure")
1363 | 
1364 |     # Test backups directory
1365 |     try:
1366 |         test_file = Path(backups_path) / '.write_test'
1367 |         test_file.write_text('test')
1368 |         test_file.unlink()
1369 |         print_success("Storage directories created and are writable")
1370 |     except (OSError, PermissionError) as e:
1371 |         print_error(f"Failed to test backups directory: {e}")
1372 |         print_warning("Continuing with Claude Desktop configuration")
1373 | 
1374 |     # Configure Claude Desktop
1375 |     env_config = build_mcp_env_config(storage_backend, storage_path, backups_path)
1376 |     project_root = Path(__file__).parent.parent.parent
1377 | 
1378 |     home_dir = Path.home()
1379 |     claude_config_paths = [
1380 |         home_dir / 'Library' / 'Application Support' / 'Claude' / 'claude_desktop_config.json',
1381 |         home_dir / '.config' / 'Claude' / 'claude_desktop_config.json',
1382 |         Path('claude_config') / 'claude_desktop_config.json'
1383 |     ]
1384 | 
1385 |     for config_path in claude_config_paths:
1386 |         if config_path.exists():
1387 |             print_info(f"Found Claude Desktop config at {config_path}")
1388 |             if update_claude_config_file(config_path, env_config, project_root,
1389 |                                         system_info["is_windows"]):
1390 |                 break
1391 | 
1392 |     return True
1393 | 
1394 | def verify_installation():
1395 |     """Verify the installation."""
1396 |     print_step("5", "Verifying installation")
1397 |     
1398 |     # Get system info
1399 |     system_info = detect_system()
1400 |     
1401 |     # Check if the package is installed
1402 |     try:
1403 |         import mcp_memory_service
1404 |         print_success(f"MCP Memory Service is installed: {mcp_memory_service.__file__}")
1405 |     except ImportError:
1406 |         print_error("MCP Memory Service is not installed correctly")
1407 |         return False
1408 |     
1409 |     # Check if the entry point is available
1410 |     memory_script = shutil.which('memory')
1411 |     if memory_script:
1412 |         print_success(f"Memory command is available: {memory_script}")
1413 |     else:
1414 |         print_warning("Memory command is not available in PATH")
1415 |     
1416 |     # Check storage backend installation
1417 |     storage_backend = os.environ.get('MCP_MEMORY_STORAGE_BACKEND', 'sqlite_vec')
1418 |     
1419 |     if storage_backend == 'sqlite_vec':
1420 |         try:
1421 |             import sqlite_vec
1422 |             print_success(f"SQLite-vec is installed: {sqlite_vec.__version__}")
1423 |         except ImportError:
1424 |             print_error("SQLite-vec is not installed correctly")
1425 |             return False
1426 |     elif storage_backend == 'chromadb':
1427 |         try:
1428 |             import chromadb
1429 |             print_success(f"ChromaDB is installed: {chromadb.__version__}")
1430 |         except ImportError:
1431 |             print_error("ChromaDB is not installed correctly")
1432 |             return False
1433 |     
1434 |     # Check for ONNX runtime
1435 |     try:
1436 |         import onnxruntime
1437 |         print_success(f"ONNX Runtime is installed: {onnxruntime.__version__}")
1438 |         use_onnx = os.environ.get('MCP_MEMORY_USE_ONNX', '').lower() in ('1', 'true', 'yes')
1439 |         if use_onnx:
1440 |             print_info("Environment configured to use ONNX runtime for embeddings")
1441 |             # Check for tokenizers (required for ONNX)
1442 |             try:
1443 |                 import tokenizers
1444 |                 print_success(f"Tokenizers is installed: {tokenizers.__version__}")
1445 |             except ImportError:
1446 |                 print_warning("Tokenizers not installed but required for ONNX embeddings")
1447 |                 print_info("Install with: pip install tokenizers>=0.20.0")
1448 |     except ImportError:
1449 |         print_warning("ONNX Runtime is not installed. This is recommended for PyTorch-free operation.")
1450 |         print_info("Install with: pip install onnxruntime>=1.14.1 tokenizers>=0.20.0")
1451 |     
1452 |     # Check for Homebrew PyTorch
1453 |     homebrew_pytorch = False
1454 |     if system_info.get("has_homebrew_pytorch"):
1455 |         homebrew_pytorch = True
1456 |         print_success(f"Homebrew PyTorch detected: {system_info.get('homebrew_pytorch_version')}")
1457 |         print_info("Using system-installed PyTorch instead of pip version")
1458 |     
1459 |     # Check ML dependencies as optional
1460 |     pytorch_installed = False
1461 |     try:
1462 |         import torch
1463 |         pytorch_installed = True
1464 |         print_info(f"PyTorch is installed: {torch.__version__}")
1465 |         
1466 |         # Check for CUDA
1467 |         if torch.cuda.is_available():
1468 |             print_success(f"CUDA is available: {torch.version.cuda}")
1469 |             print_info(f"GPU: {torch.cuda.get_device_name(0)}")
1470 |         # Check for MPS (Apple Silicon)
1471 |         elif hasattr(torch.backends, 'mps') and torch.backends.mps.is_available():
1472 |             print_success("MPS (Metal Performance Shaders) is available")
1473 |         # Check for DirectML
1474 |         else:
1475 |             try:
1476 |                 import torch_directml
1477 |                 version = getattr(torch_directml, '__version__', 'Unknown version')
1478 |                 print_success(f"DirectML is available: {version}")
1479 |             except ImportError:
1480 |                 print_info("Using CPU-only PyTorch")
1481 |         
1482 |         # For macOS Intel, verify compatibility with sentence-transformers
1483 |         if system_info["is_macos"] and system_info["is_x86"]:
1484 |             torch_version = torch.__version__.split('.')
1485 |             major, minor = int(torch_version[0]), int(torch_version[1])
1486 |             
1487 |             print_info(f"Verifying torch compatibility on macOS Intel (v{major}.{minor})")
1488 |             if major < 1 or (major == 1 and minor < 6):
1489 |                 print_warning(f"PyTorch version {torch.__version__} may be too old for sentence-transformers")
1490 |             elif major > 2 or (major == 2 and minor > 1):
1491 |                 print_warning(f"PyTorch version {torch.__version__} may be too new for sentence-transformers 2.2.2")
1492 |                 print_info("If you encounter issues, try downgrading to torch 2.0.1")
1493 |             
1494 |     except ImportError:
1495 |         print_warning("PyTorch is not installed via pip. This is okay for basic operation with SQLite-vec backend.")
1496 |         if homebrew_pytorch:
1497 |             print_info("Using Homebrew PyTorch installation instead of pip version")
1498 |         else:
1499 |             print_info("For full functionality including embedding generation, install with: pip install 'mcp-memory-service[ml]'")
1500 |         pytorch_installed = False
1501 |     
1502 |     # Check if sentence-transformers is installed correctly (only if PyTorch is installed)
1503 |     if pytorch_installed or homebrew_pytorch:
1504 |         try:
1505 |             import sentence_transformers
1506 |             print_success(f"sentence-transformers is installed: {sentence_transformers.__version__}")
1507 |             
1508 |             if pytorch_installed:
1509 |                 # Verify compatibility between torch and sentence-transformers
1510 |                 st_version = sentence_transformers.__version__.split('.')
1511 |                 torch_version = torch.__version__.split('.')
1512 |                 
1513 |                 st_major, st_minor = int(st_version[0]), int(st_version[1])
1514 |                 torch_major, torch_minor = int(torch_version[0]), int(torch_version[1])
1515 |                 
1516 |                 # Specific compatibility check for macOS Intel
1517 |                 if system_info["is_macos"] and system_info["is_x86"]:
1518 |                     if st_major >= 3 and (torch_major < 1 or (torch_major == 1 and torch_minor < 11)):
1519 |                         print_warning(f"sentence-transformers {sentence_transformers.__version__} requires torch>=1.11.0")
1520 |                         print_info("This may cause runtime issues - consider downgrading sentence-transformers to 2.2.2")
1521 |             
1522 |             # Verify by trying to load a model (minimal test)
1523 |             try:
1524 |                 print_info("Testing sentence-transformers model loading...")
1525 |                 test_model = sentence_transformers.SentenceTransformer('paraphrase-MiniLM-L3-v2')
1526 |                 print_success("Successfully loaded test model")
1527 |             except Exception as e:
1528 |                 print_warning(f"Model loading test failed: {e}")
1529 |                 print_warning("There may be compatibility issues between PyTorch and sentence-transformers")
1530 |                 
1531 |         except ImportError:
1532 |             print_warning("sentence-transformers is not installed. This is okay for basic operation with SQLite-vec backend.")
1533 |             print_info("For full functionality including embedding generation, install with: pip install 'mcp-memory-service[ml]'")
1534 |     
1535 |     # Check for SQLite-vec + ONNX configuration
1536 |     if storage_backend == 'sqlite_vec' and os.environ.get('MCP_MEMORY_USE_ONNX', '').lower() in ('1', 'true', 'yes'):
1537 |         print_success("SQLite-vec + ONNX configuration is set up correctly")
1538 |         print_info("This configuration can run without PyTorch dependency")
1539 |         
1540 |         try:
1541 |             # Import the key components to verify installation
1542 |             from mcp_memory_service.storage.sqlite_vec import SqliteVecMemoryStorage
1543 |             from mcp_memory_service.models.memory import Memory
1544 |             print_success("SQLite-vec + ONNX components loaded successfully")
1545 |             
1546 |             # Check paths
1547 |             sqlite_path = os.environ.get('MCP_MEMORY_SQLITE_PATH', '')
1548 |             if sqlite_path:
1549 |                 print_info(f"SQLite-vec database path: {sqlite_path}")
1550 |             else:
1551 |                 print_warning("MCP_MEMORY_SQLITE_PATH is not set")
1552 |             
1553 |             backups_path = os.environ.get('MCP_MEMORY_BACKUPS_PATH', '')
1554 |             if backups_path:
1555 |                 print_info(f"Backups path: {backups_path}")
1556 |             else:
1557 |                 print_warning("MCP_MEMORY_BACKUPS_PATH is not set")
1558 |             
1559 |         except ImportError as e:
1560 |             print_error(f"Failed to import SQLite-vec components: {e}")
1561 |             return False
1562 |             
1563 |     # Check if MCP Memory Service package is installed correctly
1564 |     try:
1565 |         import mcp_memory_service
1566 |         print_success(f"MCP Memory Service is installed correctly")
1567 |         return True
1568 |     except ImportError:
1569 |         print_error("MCP Memory Service is not installed correctly")
1570 |         return False
1571 | 
1572 | def install_claude_hooks(args, system_info):
1573 |     """Install Claude Code memory awareness hooks."""
1574 |     print_step("5", "Installing Claude Code Memory Awareness Hooks")
1575 | 
1576 |     try:
1577 |         # Check if Claude Code is available
1578 |         claude_available = shutil.which("claude") is not None
1579 |         if not claude_available:
1580 |             print_warning("Claude Code CLI not found")
1581 |             print_info("You can install hooks manually later using:")
1582 |             print_info("  cd claude-hooks && python install_hooks.py --basic")
1583 |             return
1584 | 
1585 |         print_info("Claude Code CLI detected")
1586 | 
1587 |         # Use unified Python installer for cross-platform compatibility
1588 |         claude_hooks_dir = Path(__file__).parent.parent.parent / "claude-hooks"
1589 |         unified_installer = claude_hooks_dir / "install_hooks.py"
1590 | 
1591 |         if not unified_installer.exists():
1592 |             print_error("Unified hook installer not found at expected location")
1593 |             print_info("Please ensure the unified installer is available:")
1594 |             print_info(f"  Expected: {unified_installer}")
1595 |             return
1596 | 
1597 |         # Prepare installer command with appropriate options
1598 |         version = get_package_version()
1599 |         if args.install_natural_triggers:
1600 |             print_info(f"Installing Natural Memory Triggers v{version}...")
1601 |             installer_cmd = [sys.executable, str(unified_installer), "--natural-triggers"]
1602 |         else:
1603 |             print_info("Installing standard memory awareness hooks...")
1604 |             installer_cmd = [sys.executable, str(unified_installer), "--basic"]
1605 | 
1606 |         # Run the unified Python installer
1607 |         print_info(f"Running unified hook installer: {unified_installer.name}")
1608 |         result = subprocess.run(
1609 |             installer_cmd,
1610 |             cwd=str(claude_hooks_dir),
1611 |             capture_output=True,
1612 |             text=True
1613 |         )
1614 | 
1615 |         if result.returncode == 0:
1616 |             print_success("Claude Code memory awareness hooks installed successfully")
1617 |             if args.install_natural_triggers:
1618 |                 print_info(f"✅ Natural Memory Triggers v{version} enabled")
1619 |                 print_info("✅ Intelligent trigger detection with 85%+ accuracy")
1620 |                 print_info("✅ Multi-tier performance optimization")
1621 |                 print_info("✅ CLI management tools available")
1622 |                 print_info("")
1623 |                 print_info("Manage Natural Memory Triggers:")
1624 |                 print_info("  node ~/.claude/hooks/memory-mode-controller.js status")
1625 |                 print_info("  node ~/.claude/hooks/memory-mode-controller.js profile balanced")
1626 |             else:
1627 |                 print_info("✅ Standard memory awareness hooks enabled")
1628 |                 print_info("✅ Session-start and session-end hooks active")
1629 |         else:
1630 |             print_warning("Hook installation completed with warnings")
1631 |             if result.stdout:
1632 |                 print_info("Installer output:")
1633 |                 print_info(result.stdout)
1634 |             if result.stderr:
1635 |                 print_warning("Installer warnings:")
1636 |                 print_warning(result.stderr)
1637 | 
1638 |     except Exception as e:
1639 |         print_warning(f"Failed to install hooks automatically: {e}")
1640 |         print_info("You can install hooks manually later using the unified installer:")
1641 |         print_info("  cd claude-hooks && python install_hooks.py --basic")
1642 |         if args.install_natural_triggers:
1643 |             print_info("For Natural Memory Triggers:")
1644 |             print_info("  cd claude-hooks && python install_hooks.py --natural-triggers")
1645 | 
1646 | def detect_development_context():
1647 |     """Detect if user is likely a developer (has .git directory).
1648 | 
1649 |     Returns:
1650 |         bool: True if .git directory exists
1651 |     """
1652 |     git_dir = Path(".git")
1653 |     return git_dir.exists() and git_dir.is_dir()
1654 | 
1655 | def recommend_editable_install(args):
1656 |     """Recommend editable install for developers.
1657 | 
1658 |     If .git directory detected and --dev not specified, prompts user to use
1659 |     editable install mode. This prevents the common "stale venv vs source code"
1660 |     issue where MCP servers load from site-packages instead of source files.
1661 | 
1662 |     Args:
1663 |         args: Parsed command line arguments
1664 | 
1665 |     Returns:
1666 |         bool: True if editable install should be used
1667 |     """
1668 |     # If already in dev mode, nothing to do
1669 |     if args.dev:
1670 |         return True
1671 | 
1672 |     # Detect development context
1673 |     if detect_development_context():
1674 |         print_warning("Detected git repository - you may be a developer!")
1675 |         print("")
1676 |         print_info("For development, EDITABLE install is strongly recommended:")
1677 |         print_info("  pip install -e .")
1678 |         print("")
1679 |         print_info("Why this matters:")
1680 |         print_info("  • MCP servers load from site-packages, not source files")
1681 |         print_info("  • Without -e flag, source changes won't take effect")
1682 |         print_info("  • System restart won't help - it just relaunches stale code")
1683 |         print_info("  • Common symptom: Code shows v8.23.0 but server reports v8.5.3")
1684 |         print("")
1685 |         print_info("Editable install ensures:")
1686 |         print_info("  • Source changes take effect immediately (after server restart)")
1687 |         print_info("  • No need to reinstall package after every change")
1688 |         print_info("  • Easier debugging and development workflow")
1689 |         print("")
1690 | 
1691 |         response = input("Install in EDITABLE mode (recommended for development)? [Y/n]: ").lower().strip()
1692 |         if response == '' or response == 'y' or response == 'yes':
1693 |             args.dev = True
1694 |             print_success("Enabled editable install mode")
1695 |             return True
1696 |         else:
1697 |             print_warning("Proceeding with standard install (not editable)")
1698 |             print_warning("Remember: You'll need to reinstall after every source change!")
1699 |             return False
1700 | 
1701 |     return False
1702 | 
1703 | def main():
1704 |     """Main installation function."""
1705 |     parser = argparse.ArgumentParser(description="Install MCP Memory Service")
1706 |     parser.add_argument('--dev', action='store_true', help='Install in development mode')
1707 |     parser.add_argument('--chroma-path', type=str, help='Path to ChromaDB storage')
1708 |     parser.add_argument('--backups-path', type=str, help='Path to backups storage')
1709 |     parser.add_argument('--force-compatible-deps', action='store_true',
1710 |                         help='Force compatible versions of PyTorch (2.0.1) and sentence-transformers (2.2.2)')
1711 |     parser.add_argument('--fallback-deps', action='store_true',
1712 |                         help='Use fallback versions of PyTorch (1.13.1) and sentence-transformers (2.2.2)')
1713 |     parser.add_argument('--storage-backend', choices=['cloudflare', 'sqlite_vec', 'chromadb', 'hybrid', 'auto_detect'],
1714 |                         help='Choose storage backend: cloudflare (production), sqlite_vec (development), chromadb (team), hybrid (production + local), or auto_detect')
1715 |     parser.add_argument('--skip-pytorch', action='store_true',
1716 |                         help='Skip PyTorch installation and use ONNX runtime with SQLite-vec backend instead')
1717 |     parser.add_argument('--use-homebrew-pytorch', action='store_true',
1718 |                         help='Use existing Homebrew PyTorch installation instead of pip version')
1719 |     parser.add_argument('--install-hooks', action='store_true',
1720 |                         help='Install Claude Code memory awareness hooks after main installation')
1721 |     parser.add_argument('--install-natural-triggers', action='store_true',
1722 |                         help='Install Natural Memory Triggers (requires Claude Code)')
1723 |     parser.add_argument('--with-ml', action='store_true',
1724 |                         help='Include ML dependencies (torch, sentence-transformers) for semantic search and embeddings')
1725 |     parser.add_argument('--with-chromadb', action='store_true',
1726 |                         help='Include ChromaDB backend support (automatically includes ML dependencies)')
1727 |     args = parser.parse_args()
1728 | 
1729 |     # Check if this is a development context and recommend editable install
1730 |     recommend_editable_install(args)
1731 | 
1732 |     print_header("MCP Memory Service Installation")
1733 |     
1734 |     # Step 1: Detect system
1735 |     print_step("1", "Detecting system")
1736 |     system_info = detect_system()
1737 |     
1738 |     # Check if user requested force-compatible dependencies for macOS Intel
1739 |     if args.force_compatible_deps:
1740 |         if system_info["is_macos"] and system_info["is_x86"]:
1741 |             print_info("Installing compatible dependencies as requested...")
1742 |             # Select versions based on Python version
1743 |             python_version = sys.version_info
1744 |             if python_version >= (3, 13):
1745 |                 # Python 3.13+ compatible versions
1746 |                 torch_version = "2.3.0"
1747 |                 torch_vision_version = "0.18.0"
1748 |                 torch_audio_version = "2.3.0"
1749 |                 st_version = "3.0.0"
1750 |             else:
1751 |                 # Older Python versions
1752 |                 torch_version = "2.0.1"
1753 |                 torch_vision_version = "2.0.1"
1754 |                 torch_audio_version = "2.0.1"
1755 |                 st_version = "2.2.2"
1756 |                 
1757 |             cmd = [
1758 |                 sys.executable, '-m', 'pip', 'install',
1759 |                 f"torch=={torch_version}", f"torchvision=={torch_vision_version}", f"torchaudio=={torch_audio_version}",
1760 |                 f"sentence-transformers=={st_version}"
1761 |             ]
1762 |             success, _ = run_command_safe(
1763 |                 cmd,
1764 |                 success_msg="Compatible dependencies installed successfully",
1765 |                 error_msg="Failed to install compatible dependencies",
1766 |                 silent=False
1767 |             )
1768 |         else:
1769 |             print_warning("--force-compatible-deps is only applicable for macOS with Intel CPUs")
1770 |     
1771 |     # Check if user requested fallback dependencies for troubleshooting
1772 |     if args.fallback_deps:
1773 |         print_info("Installing fallback dependencies as requested...")
1774 |         # Select versions based on Python version
1775 |         python_version = sys.version_info
1776 |         if python_version >= (3, 13):
1777 |             # Python 3.13+ compatible fallback versions
1778 |             torch_version = "2.3.0"
1779 |             torch_vision_version = "0.18.0"
1780 |             torch_audio_version = "2.3.0"
1781 |             st_version = "3.0.0"
1782 |         else:
1783 |             # Older Python fallback versions
1784 |             torch_version = "1.13.1"
1785 |             torch_vision_version = "0.14.1"
1786 |             torch_audio_version = "0.13.1"
1787 |             st_version = "2.2.2"
1788 |             
1789 |         cmd = [
1790 |             sys.executable, '-m', 'pip', 'install',
1791 |             f"torch=={torch_version}", f"torchvision=={torch_vision_version}", f"torchaudio=={torch_audio_version}",
1792 |             f"sentence-transformers=={st_version}"
1793 |         ]
1794 |         success, _ = run_command_safe(
1795 |             cmd,
1796 |             success_msg="Fallback dependencies installed successfully",
1797 |             error_msg="Failed to install fallback dependencies",
1798 |             silent=False
1799 |         )
1800 |     
1801 |     # Step 2: Check dependencies
1802 |     if not check_dependencies():
1803 |         sys.exit(1)
1804 |     
1805 |     # Step 3: Install package
1806 |     if not install_package(args):
1807 |         # If installation fails and we're on macOS Intel, suggest using the force-compatible-deps option
1808 |         if system_info["is_macos"] and system_info["is_x86"]:
1809 |             print_warning("Installation failed on macOS Intel.")
1810 |             print_info("Try running the script with '--force-compatible-deps' to force compatible versions:")
1811 |             print_info("python install.py --force-compatible-deps")
1812 |         sys.exit(1)
1813 |     
1814 |     # Step 4: Configure paths
1815 |     if not configure_paths(args):
1816 |         print_warning("Path configuration failed, but installation may still work")
1817 |     
1818 |     # Step 5: Verify installation
1819 |     if not verify_installation():
1820 |         print_warning("Installation verification failed, but installation may still work")
1821 |         # If verification fails and we're on macOS Intel, suggest using the force-compatible-deps option
1822 |         if system_info["is_macos"] and system_info["is_x86"]:
1823 |             python_version = sys.version_info
1824 |             print_info("For macOS Intel compatibility issues, try these steps:")
1825 |             print_info("1. First uninstall current packages: pip uninstall -y torch torchvision torchaudio sentence-transformers")
1826 |             print_info("2. Then reinstall with compatible versions: python install.py --force-compatible-deps")
1827 |             
1828 |             if python_version >= (3, 13):
1829 |                 print_info("For Python 3.13+, you may need to manually install the following:")
1830 |                 print_info("pip install torch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0")
1831 |                 print_info("pip install sentence-transformers==3.0.0")
1832 |     
1833 |     print_header("Installation Complete")
1834 |     
1835 |     # Get final storage backend info
1836 |     final_backend = os.environ.get('MCP_MEMORY_STORAGE_BACKEND', 'chromadb')
1837 |     use_onnx = os.environ.get('MCP_MEMORY_USE_ONNX', '').lower() in ('1', 'true', 'yes')
1838 |     
1839 |     print_info("You can now run the MCP Memory Service using the 'memory' command")
1840 |     print_info(f"Storage Backend: {final_backend.upper()}")
1841 | 
1842 |     if final_backend == 'sqlite_vec':
1843 |         print_info("✅ Using SQLite-vec - lightweight, fast, minimal dependencies")
1844 |         print_info("   • No complex dependencies or build issues")
1845 |         print_info("   • Excellent performance for typical use cases")
1846 |     elif final_backend == 'hybrid':
1847 |         print_info("✅ Using Hybrid Backend - RECOMMENDED for production")
1848 |         print_info("   • Fast local SQLite-vec storage (5ms reads)")
1849 |         print_info("   • Background Cloudflare sync for multi-device access")
1850 |         print_info("   • SQLite pragmas configured for concurrent access")
1851 |         print_info("   • Zero user-facing latency for cloud operations")
1852 |     elif final_backend == 'cloudflare':
1853 |         print_info("✅ Using Cloudflare Backend - cloud-only storage")
1854 |         print_info("   • Distributed edge storage with D1 database")
1855 |         print_info("   • Vectorize index for semantic search")
1856 |         print_info("   • Multi-device synchronization")
1857 |     else:
1858 |         print_info("✅ Using ChromaDB - full-featured vector database")
1859 |         print_info("   • Advanced features and extensive ecosystem")
1860 |     
1861 |     if use_onnx:
1862 |         print_info("✅ Using ONNX Runtime for inference")
1863 |         print_info("   • Compatible with Homebrew PyTorch")
1864 |         print_info("   • Reduced dependencies for better compatibility")
1865 | 
1866 |     # Show ML dependencies status
1867 |     if args.with_ml or args.with_chromadb:
1868 |         print_info("✅ ML Dependencies Installed")
1869 |         print_info("   • Full semantic search and embedding generation enabled")
1870 |         print_info("   • PyTorch and sentence-transformers available")
1871 |     else:
1872 |         print_info("ℹ️  Lightweight Installation (No ML Dependencies)")
1873 |         print_info("   • Basic functionality without semantic search")
1874 |         print_info("   • To enable full features: pip install mcp-memory-service[ml]")
1875 |     
1876 |     print_info("For more information, see the README.md file")
1877 | 
1878 |     # Install hooks if requested
1879 |     if args.install_hooks or args.install_natural_triggers:
1880 |         install_claude_hooks(args, system_info)
1881 |     
1882 |     # Print macOS Intel specific information if applicable
1883 |     if system_info["is_macos"] and system_info["is_x86"]:
1884 |         print_info("\nMacOS Intel Notes:")
1885 |         
1886 |         if system_info.get("has_homebrew_pytorch"):
1887 |             print_info("- Using Homebrew PyTorch installation: " + system_info.get("homebrew_pytorch_version", "Unknown"))
1888 |             print_info("- The MCP Memory Service is configured to use SQLite-vec + ONNX runtime")
1889 |             print_info("- To start the memory service, use:")
1890 |             print_info("  export MCP_MEMORY_USE_ONNX=1")
1891 |             print_info("  export MCP_MEMORY_STORAGE_BACKEND=sqlite_vec")
1892 |             print_info("  memory")
1893 |         else:
1894 |             print_info("- If you encounter issues, try the --force-compatible-deps option")
1895 |             
1896 |             python_version = sys.version_info
1897 |             if python_version >= (3, 13):
1898 |                 print_info("- For optimal performance on Intel Macs with Python 3.13+, torch==2.3.0 and sentence-transformers==3.0.0 are recommended")
1899 |                 print_info("- You can manually install these versions with:")
1900 |                 print_info("  pip install torch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0 sentence-transformers==3.0.0")
1901 |             else:
1902 |                 print_info("- For optimal performance on Intel Macs, torch==2.0.1 and sentence-transformers==2.2.2 are recommended")
1903 |                 print_info("- You can manually install these versions with:")
1904 |                 print_info("  pip install torch==2.0.1 torchvision==2.0.1 torchaudio==2.0.1 sentence-transformers==2.2.2")
1905 |                 
1906 |         print_info("\nTroubleshooting Tips:")
1907 |         print_info("- If you have a Homebrew PyTorch installation, use: --use-homebrew-pytorch")
1908 |         print_info("- To completely skip PyTorch installation, use: --skip-pytorch")
1909 |         print_info("- To force the SQLite-vec backend, use: --storage-backend sqlite_vec")
1910 |         print_info("- For lightweight installation without ML, use: (default behavior)")
1911 |         print_info("- For full ML capabilities, use: --with-ml")
1912 |         print_info("- For ChromaDB with ML, use: --with-chromadb")
1913 |         print_info("- For a quick test, try running: python test_memory.py")
1914 |         print_info("- To install Claude Code hooks: --install-hooks")
1915 |         print_info("- To install Natural Memory Triggers: --install-natural-triggers")
1916 | 
1917 | if __name__ == "__main__":
1918 |     main()
```
Page 40/47FirstPrevNextLast