flurryx-code-memory 0.4.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/PKG-INFO +1 -1
  2. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/README.md +74 -5
  3. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/pyproject.toml +1 -1
  4. flurryx_code_memory-0.5.0/src/code_memory/__init__.py +8 -0
  5. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/cli.py +55 -0
  6. flurryx_code_memory-0.5.0/src/code_memory/updater.py +396 -0
  7. flurryx_code_memory-0.4.0/src/code_memory/__init__.py +0 -1
  8. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/.claude-plugin/marketplace.json +0 -0
  9. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/.env.example +0 -0
  10. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/.gitignore +0 -0
  11. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/CHANGELOG.md +0 -0
  12. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docker/docker-compose.yml +0 -0
  13. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docs/BENCHMARK.md +0 -0
  14. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docs/BENCHMARK_VS_BASELINE.json +0 -0
  15. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docs/BENCHMARK_VS_BASELINE.md +0 -0
  16. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docs/architecture.png +0 -0
  17. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docs/benchmark-raw.json +0 -0
  18. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/docs/hero.png +0 -0
  19. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/install.ps1 +0 -0
  20. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/install.sh +0 -0
  21. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/.claude-plugin/plugin.json +0 -0
  22. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/README.md +0 -0
  23. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/commands/code-memory.md +0 -0
  24. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/hooks/hooks.json +0 -0
  25. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/install.sh +0 -0
  26. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/claim-intent.js +0 -0
  27. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/claim-intent.test.js +0 -0
  28. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/format.js +0 -0
  29. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/intent.js +0 -0
  30. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/io.js +0 -0
  31. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/memory.js +0 -0
  32. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/lib/state.js +0 -0
  33. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/on-post-tool.js +0 -0
  34. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/on-pre-tool.js +0 -0
  35. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/on-retrieve-seen.js +0 -0
  36. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/on-session-start.js +0 -0
  37. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/on-stop.js +0 -0
  38. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/on-user-prompt.js +0 -0
  39. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/scripts/resolver-debounce.js +0 -0
  40. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/claude-code/skills/code-memory/SKILL.md +0 -0
  41. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/README.md +0 -0
  42. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/install.sh +0 -0
  43. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/package-lock.json +0 -0
  44. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/package.json +0 -0
  45. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/scripts/add-mcp.py +0 -0
  46. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/scripts/install.mjs +0 -0
  47. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/scripts/uninstall.mjs +0 -0
  48. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/skills/code-memory/SKILL.md +0 -0
  49. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/src/code-memory-lib/claim-intent.test.mts +0 -0
  50. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/src/code-memory-lib/claim-intent.ts +0 -0
  51. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/src/code-memory-lib/intent.ts +0 -0
  52. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/src/code-memory-lib/memory-client.ts +0 -0
  53. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/src/code-memory.ts +0 -0
  54. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/plugins/opencode/tsconfig.json +0 -0
  55. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/benchmark.py +0 -0
  56. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/benchmark_queries.json +0 -0
  57. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/benchmark_vs_baseline.py +0 -0
  58. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/benchmark_vs_grep.sh +0 -0
  59. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/ingest.py +0 -0
  60. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/install.ps1 +0 -0
  61. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/scripts/install.sh +0 -0
  62. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/claims/__init__.py +0 -0
  63. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/claims/extractor.py +0 -0
  64. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/claims/indexer.py +0 -0
  65. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/claims/resolver.py +0 -0
  66. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/claims/store.py +0 -0
  67. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/config.py +0 -0
  68. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/embed/__init__.py +0 -0
  69. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/embed/cache.py +0 -0
  70. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/embed/m3.py +0 -0
  71. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/embed/ollama.py +0 -0
  72. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/embed/tei.py +0 -0
  73. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/episodic/__init__.py +0 -0
  74. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/episodic/sqlite_store.py +0 -0
  75. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/__init__.py +0 -0
  76. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/csproj.py +0 -0
  77. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/dll.py +0 -0
  78. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/gitignore.py +0 -0
  79. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/nuget.py +0 -0
  80. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/sanity.py +0 -0
  81. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/sln.py +0 -0
  82. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/extractor/treesitter.py +0 -0
  83. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/graph/__init__.py +0 -0
  84. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/graph/falkor_store.py +0 -0
  85. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/mcp_server.py +0 -0
  86. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/metrics.py +0 -0
  87. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/__init__.py +0 -0
  88. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/git_delta.py +0 -0
  89. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/ingest_state.py +0 -0
  90. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/pipeline.py +0 -0
  91. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/reset.py +0 -0
  92. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/resolver.py +0 -0
  93. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/orchestrator/retrieve.py +0 -0
  94. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/resilience.py +0 -0
  95. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/__init__.py +0 -0
  96. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/autostart/__init__.py +0 -0
  97. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/autostart/base.py +0 -0
  98. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/autostart/launchd.py +0 -0
  99. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/autostart/schtasks.py +0 -0
  100. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/autostart/systemd.py +0 -0
  101. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/hooks.py +0 -0
  102. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/safety.py +0 -0
  103. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/snapshot.py +0 -0
  104. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/store.py +0 -0
  105. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/sync.py +0 -0
  106. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/sync/watcher.py +0 -0
  107. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/vector/__init__.py +0 -0
  108. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/src/code_memory/vector/qdrant_store.py +0 -0
  109. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_autostart_adapters.py +0 -0
  110. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_chunk_text.py +0 -0
  111. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_claim_extractor.py +0 -0
  112. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_claim_indexer.py +0 -0
  113. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_claim_resolver.py +0 -0
  114. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_claim_store.py +0 -0
  115. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_config_embed_dim.py +0 -0
  116. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_config_sentinel.py +0 -0
  117. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_csproj.py +0 -0
  118. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_dll_members.py +0 -0
  119. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_dll_parser.py +0 -0
  120. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_embed_backend.py +0 -0
  121. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_embed_cache.py +0 -0
  122. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_embed_m3.py +0 -0
  123. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_embed_tei.py +0 -0
  124. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_episode_dedup.py +0 -0
  125. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_episode_head_sha.py +0 -0
  126. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_csharp.py +0 -0
  127. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_filters.py +0 -0
  128. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_php.py +0 -0
  129. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_python_imports.py +0 -0
  130. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_receiver_type.py +0 -0
  131. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_references.py +0 -0
  132. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_sanity.py +0 -0
  133. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_ts_abstract.py +0 -0
  134. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_ts_inject.py +0 -0
  135. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_extractor_utf8.py +0 -0
  136. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_file_containment.py +0 -0
  137. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_git_delta.py +0 -0
  138. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_graph_queries.py +0 -0
  139. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_graph_temporal.py +0 -0
  140. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_graph_vacuum_at_sha.py +0 -0
  141. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_hooks_installer.py +0 -0
  142. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_ingest_state.py +0 -0
  143. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_mcp_assert_claim.py +0 -0
  144. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_mcp_server_descriptions.py +0 -0
  145. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_mcp_strict_project.py +0 -0
  146. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_metrics.py +0 -0
  147. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_nuget_resolver.py +0 -0
  148. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_overload_resolution.py +0 -0
  149. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_partial_class.py +0 -0
  150. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_pipeline_references.py +0 -0
  151. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_pipeline_temporal_wiring.py +0 -0
  152. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_qdrant_legacy_guard.py +0 -0
  153. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_razor_inject.py +0 -0
  154. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_resilience.py +0 -0
  155. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_resolver.py +0 -0
  156. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_resolver_assembly.py +0 -0
  157. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_retrieve_claims_surfacing.py +0 -0
  158. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_retrieve_rerank.py +0 -0
  159. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_sln.py +0 -0
  160. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_smoke.py +0 -0
  161. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_snapshot_e2e.py +0 -0
  162. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_snapshot_format.py +0 -0
  163. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_snapshot_store.py +0 -0
  164. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_sync_decision_tree.py +0 -0
  165. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_watch_safety.py +0 -0
  166. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_watcher_debouncer.py +0 -0
  167. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_watcher_exclude.py +0 -0
  168. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/tests/test_watcher_ref_events.py +0 -0
  169. {flurryx_code_memory-0.4.0 → flurryx_code_memory-0.5.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flurryx-code-memory
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Local lightweight memory layer for coding agents: FalkorDB + Qdrant + Ollama (BGE-M3) + tree-sitter
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: anyio>=4.4
@@ -17,7 +17,7 @@ Structural symbol graph  ·  semantic vector recall  ·  epi
17
17
  [![tree-sitter](https://img.shields.io/badge/parser-tree--sitter-228B22)](https://tree-sitter.github.io/)
18
18
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
19
19
 
20
- **Jump to:** [Get it running](#installation)  ·  [Plug it into your agent](#mcp-server)  ·  [How it scores vs `rg`](#benchmarks)
20
+ **Jump to:** [Get it running](#installation)  ·  [Update it](#updating)  ·  [Plug it into your agent](#mcp-server)  ·  [How it scores vs `rg`](#benchmarks)
21
21
 
22
22
  </div>
23
23
 
@@ -66,6 +66,22 @@ _Full tables + methodology in [Benchmarks](#benchmarks)._
66
66
 
67
67
  ## Installation
68
68
 
69
+ > [!TIP]
70
+ > ### 🔄 Already installed? Update in one command.
71
+ >
72
+ > ```bash
73
+ > code-memory update # smart refresh: CLI + Docker images + present Ollama models + plugins
74
+ > code-memory update --check # dry-run: print current vs latest, exit non-zero if behind
75
+ > code-memory update --full # re-run the one-liner installer (adds anything missing)
76
+ > ```
77
+ >
78
+ > `update` is **idempotent and selective** — it only touches components that are already
79
+ > installed locally. No re-prompting for extras you opted out of, no docker churn if
80
+ > compose isn't on this machine. Run it weekly, or after a release announcement.
81
+ >
82
+ > Bleeding edge from `main`: `code-memory update --bleeding`. Full details below in
83
+ > [Updating](#updating).
84
+
69
85
  `code-memory` installs in **one command**. Pick your OS, paste it, you're done.
70
86
 
71
87
  **🍎 macOS**
@@ -154,8 +170,13 @@ iwr https://raw.githubusercontent.com/fmflurry/code-memory/main/install.ps1 -Out
154
170
  <summary><strong>Manual install (à la carte, no one-liner)</strong></summary>
155
171
 
156
172
  ```bash
157
- # 1. CLI (via uv)
158
- uv tool install --from git+https://github.com/fmflurry/code-memory code-memory
173
+ # 1. CLI (PyPI — recommended)
174
+ uv tool install flurryx-code-memory
175
+ # or: pipx install flurryx-code-memory
176
+ # or: pip install flurryx-code-memory
177
+ #
178
+ # Bleeding edge from main:
179
+ # uv tool install --from git+https://github.com/fmflurry/code-memory flurryx-code-memory
159
180
 
160
181
  # 2. Infra (compose + env)
161
182
  mkdir -p ~/.code-memory/docker
@@ -173,7 +194,7 @@ claude plugin marketplace add https://github.com/fmflurry/code-memory
173
194
  claude plugin install code-memory@code-memory --scope user
174
195
  claude mcp add code-memory --scope user \
175
196
  -e CODE_MEMORY_PROJECT=auto \
176
- -- uvx --from git+https://github.com/fmflurry/code-memory code-memory-mcp
197
+ -- uvx --from flurryx-code-memory code-memory-mcp
177
198
 
178
199
  # 5. OpenCode plugin
179
200
  npm i -g code-memory-opencode
@@ -189,7 +210,7 @@ Just the Claude Code MCP server — no auto-retrieve / auto-record hooks, no Doc
189
210
 
190
211
  ```bash
191
212
  claude mcp add code-memory \
192
- -- uvx --from git+https://github.com/fmflurry/code-memory code-memory-mcp
213
+ -- uvx --from flurryx-code-memory code-memory-mcp
193
214
  ```
194
215
 
195
216
  </details>
@@ -238,6 +259,54 @@ cd code-memory
238
259
 
239
260
  ---
240
261
 
262
+ ## Updating
263
+
264
+ After the initial install, never run the one-liner again — use the built-in updater:
265
+
266
+ ```bash
267
+ code-memory update # smart, idempotent, no re-prompts
268
+ code-memory update --check # dry-run; exit 1 if behind, 0 if current
269
+ code-memory update --full # behave like a fresh one-liner install
270
+ code-memory update --bleeding # install CLI from git+main instead of PyPI
271
+ ```
272
+
273
+ ### What it does
274
+
275
+ `update` introspects your machine and refreshes **only what is already installed**:
276
+
277
+ | Component | Detection | Refresh action |
278
+ | --------------------------- | ------------------------------------------------------ | ------------------------------------------------- |
279
+ | **CLI** | `sys.prefix` (uv tool / pipx / pip / editable) | upgrade via the same channel |
280
+ | **FalkorDB + Qdrant** | `~/.code-memory/docker/docker-compose.yml` or running | `docker compose pull && up -d` |
281
+ | **Ollama models** | present in `ollama list` (`bge-m3`, `gemma2:9b`, …) | `ollama pull <model>` (only for already-pulled) |
282
+ | **Claude Code plugin** | `claude plugin list \| grep code-memory` | `claude plugin install … --force` |
283
+ | **OpenCode plugin** | `npm ls -g code-memory-opencode` | `npm i -g code-memory-opencode` |
284
+ | **Python extras** | `FlagEmbedding` / `dnfile` import probe | covered by the CLI upgrade |
285
+
286
+ Anything you **didn't** install stays untouched. No "do you want gemma?" prompt, no
287
+ docker churn on a machine that hits remote infra, no plugin re-registration if you
288
+ deliberately removed it.
289
+
290
+ ### Sample output
291
+
292
+ ```
293
+ $ code-memory update --check
294
+ code-memory updater (install: uv-tool)
295
+ CLI: 0.4.0 → latest: 0.5.0
296
+ Components detected locally:
297
+ • Docker: FalkorDB (running)
298
+ • Docker: Qdrant (running)
299
+ • Ollama: bge-m3
300
+ · Ollama: gemma2:9b [not installed — skip]
301
+ • Claude Code plugin
302
+ • Claude Code MCP
303
+ · OpenCode plugin (npm) [not installed — skip]
304
+ ```
305
+
306
+ Use `code-memory update --check` from CI or a cron to nudge devs when a release ships.
307
+
308
+ ---
309
+
241
310
  ## What is this?
242
311
 
243
312
  `code-memory` gives a coding agent (Claude Code, OpenCode, Cursor, your own harness) a memory it can actually use:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "flurryx-code-memory"
7
- version = "0.4.0"
7
+ version = "0.5.0"
8
8
  description = "Local lightweight memory layer for coding agents: FalkorDB + Qdrant + Ollama (BGE-M3) + tree-sitter"
9
9
  requires-python = ">=3.11"
10
10
  dependencies = [
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.metadata import PackageNotFoundError, version as _pkg_version
4
+
5
+ try:
6
+ __version__ = _pkg_version("flurryx-code-memory")
7
+ except PackageNotFoundError: # editable / source checkout without install
8
+ __version__ = "0.0.0+local"
@@ -27,6 +27,28 @@ def _graph_for(project: str | None) -> FalkorStore:
27
27
  app = typer.Typer(no_args_is_help=True, add_completion=False, help="code-memory CLI")
28
28
 
29
29
 
30
+ def _version_callback(value: bool) -> None:
31
+ if value:
32
+ from . import __version__
33
+
34
+ typer.echo(__version__)
35
+ raise typer.Exit()
36
+
37
+
38
+ @app.callback()
39
+ def _main(
40
+ version: bool = typer.Option(
41
+ False,
42
+ "--version",
43
+ "-V",
44
+ callback=_version_callback,
45
+ is_eager=True,
46
+ help="Print version and exit.",
47
+ ),
48
+ ) -> None:
49
+ """code-memory CLI."""
50
+
51
+
30
52
  ProjectOpt = typer.Option(
31
53
  None,
32
54
  "--project",
@@ -1188,5 +1210,38 @@ def autostart_status(
1188
1210
  )
1189
1211
 
1190
1212
 
1213
+ @app.command()
1214
+ def update(
1215
+ check: bool = typer.Option(
1216
+ False,
1217
+ "--check",
1218
+ help="Only print the current/latest state and exit (no changes).",
1219
+ ),
1220
+ full: bool = typer.Option(
1221
+ False,
1222
+ "--full",
1223
+ help="Re-run the one-liner installer (refresh docker/env/plugins from scratch).",
1224
+ ),
1225
+ bleeding: bool = typer.Option(
1226
+ False,
1227
+ "--bleeding",
1228
+ help="Install CLI from git+main instead of PyPI.",
1229
+ ),
1230
+ ) -> None:
1231
+ """Smart-update code-memory: refresh only components already installed locally.
1232
+
1233
+ Default behavior detects the CLI install method (uv tool / pipx / pip) and
1234
+ upgrades it in place, then refreshes Docker images, present Ollama models,
1235
+ and registered Claude/OpenCode plugins. Pieces that were never installed
1236
+ stay untouched — no prompts, no re-asking.
1237
+
1238
+ Use ``--check`` for a dry-run, ``--full`` to behave like a fresh install.
1239
+ """
1240
+ from .updater import run_update
1241
+
1242
+ rc = run_update(check_only=check, full=full, bleeding=bleeding)
1243
+ raise typer.Exit(code=rc)
1244
+
1245
+
1191
1246
  if __name__ == "__main__":
1192
1247
  app()
@@ -0,0 +1,396 @@
1
+ """Smart updater for code-memory.
2
+
3
+ Detects which components are already installed locally and refreshes
4
+ only those — never asks the user to re-confirm pieces they already opted
5
+ into during the initial one-liner install.
6
+
7
+ Components inspected:
8
+
9
+ * CLI install method (``uv tool`` / ``pipx`` / ``pip``) + version vs PyPI
10
+ * Docker stack (FalkorDB + Qdrant)
11
+ * Ollama models present locally (``bge-m3``, optionally ``gemma2:9b``)
12
+ * Optional Python extras (``hybrid`` via ``FlagEmbedding``, ``dotnet`` via ``dnfile``)
13
+ * Claude Code plugin + MCP server registration
14
+ * OpenCode global npm package
15
+
16
+ The update flow is intentionally idempotent and noisy-on-change only:
17
+ already-current items print one line each, anything actually upgraded
18
+ prints its old/new state.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import importlib.util
24
+ import json
25
+ import os
26
+ import shutil
27
+ import subprocess
28
+ import sys
29
+ from dataclasses import dataclass, field
30
+ from pathlib import Path
31
+ from typing import Literal
32
+
33
+ import httpx
34
+
35
+ from . import __version__ as _LOCAL_VERSION
36
+
37
+ PYPI_PACKAGE = "flurryx-code-memory"
38
+ DEFAULT_REPO_URL = os.environ.get(
39
+ "CODEMEMORY_REPO_URL", "https://github.com/fmflurry/code-memory"
40
+ )
41
+ CODEMEMORY_HOME = Path(os.environ.get("CODEMEMORY_HOME", str(Path.home() / ".code-memory")))
42
+
43
+ InstallMethod = Literal["uv-tool", "pipx", "pip", "editable", "unknown"]
44
+
45
+
46
+ @dataclass
47
+ class ComponentState:
48
+ name: str
49
+ present: bool
50
+ detail: str = ""
51
+ current: str | None = None
52
+ latest: str | None = None
53
+
54
+
55
+ @dataclass
56
+ class UpdatePlan:
57
+ install_method: InstallMethod
58
+ components: list[ComponentState] = field(default_factory=list)
59
+ cli_current: str = ""
60
+ cli_latest: str = ""
61
+
62
+
63
+ # ---------- detection ----------
64
+
65
+
66
+ def _run(cmd: list[str], *, check: bool = False, capture: bool = True) -> subprocess.CompletedProcess[str]:
67
+ return subprocess.run(
68
+ cmd, check=check, capture_output=capture, text=True, env={**os.environ}
69
+ )
70
+
71
+
72
+ def _have(binary: str) -> bool:
73
+ return shutil.which(binary) is not None
74
+
75
+
76
+ def current_cli_version() -> str:
77
+ return _LOCAL_VERSION
78
+
79
+
80
+ def latest_pypi_version(pkg: str = PYPI_PACKAGE, *, timeout: float = 5.0) -> str | None:
81
+ try:
82
+ r = httpx.get(f"https://pypi.org/pypi/{pkg}/json", timeout=timeout)
83
+ r.raise_for_status()
84
+ return r.json()["info"]["version"]
85
+ except Exception: # noqa: BLE001
86
+ return None
87
+
88
+
89
+ def detect_install_method() -> InstallMethod:
90
+ """Best-effort: where is the running interpreter living?
91
+
92
+ Editable installs are detected via PEP 610 ``direct_url.json``;
93
+ uv tool / pipx are detected from ``sys.prefix`` (the venv root),
94
+ not ``sys.executable`` which on macOS often resolves through a
95
+ symlink into Homebrew/conda.
96
+ """
97
+ if _is_editable_install():
98
+ return "editable"
99
+
100
+ prefix = str(Path(sys.prefix).resolve()).lower()
101
+ if "/uv/tools/" in prefix or "\\uv\\tools\\" in prefix:
102
+ return "uv-tool"
103
+ if "/pipx/venvs/" in prefix or "\\pipx\\venvs\\" in prefix:
104
+ return "pipx"
105
+ if _have("pip") and _pip_shows():
106
+ return "pip"
107
+ return "unknown"
108
+
109
+
110
+ def _is_editable_install() -> bool:
111
+ try:
112
+ from importlib.metadata import distribution
113
+
114
+ d = distribution(PYPI_PACKAGE)
115
+ raw = d.read_text("direct_url.json") or ""
116
+ if not raw:
117
+ return False
118
+ return bool(json.loads(raw).get("dir_info", {}).get("editable"))
119
+ except Exception: # noqa: BLE001
120
+ return False
121
+
122
+
123
+ def _pip_shows() -> bool:
124
+ p = _run([sys.executable, "-m", "pip", "show", PYPI_PACKAGE])
125
+ return p.returncode == 0
126
+
127
+
128
+ def _ollama_models() -> list[str]:
129
+ if not _have("ollama"):
130
+ return []
131
+ p = _run(["ollama", "list"])
132
+ if p.returncode != 0:
133
+ return []
134
+ names: list[str] = []
135
+ for line in p.stdout.splitlines()[1:]:
136
+ first = line.split()
137
+ if first:
138
+ names.append(first[0])
139
+ return names
140
+
141
+
142
+ def _docker_compose_present() -> bool:
143
+ return (CODEMEMORY_HOME / "docker" / "docker-compose.yml").exists()
144
+
145
+
146
+ def _docker_running(service: str) -> bool:
147
+ if not _have("docker"):
148
+ return False
149
+ p = _run(["docker", "ps", "--format", "{{.Names}}"])
150
+ if p.returncode != 0:
151
+ return False
152
+ return any(service in name for name in p.stdout.splitlines())
153
+
154
+
155
+ def _claude_plugin_present() -> bool:
156
+ if not _have("claude"):
157
+ return False
158
+ p = _run(["claude", "plugin", "list"])
159
+ return p.returncode == 0 and "code-memory" in p.stdout
160
+
161
+
162
+ def _claude_mcp_present() -> bool:
163
+ if not _have("claude"):
164
+ return False
165
+ p = _run(["claude", "mcp", "list"])
166
+ return p.returncode == 0 and "code-memory" in p.stdout
167
+
168
+
169
+ def _npm_pkg_present(pkg: str = "code-memory-opencode") -> bool:
170
+ if not _have("npm"):
171
+ return False
172
+ p = _run(["npm", "ls", "-g", "--depth=0", "--json"])
173
+ if p.returncode != 0:
174
+ return False
175
+ try:
176
+ deps = json.loads(p.stdout).get("dependencies", {})
177
+ return pkg in deps
178
+ except Exception: # noqa: BLE001
179
+ return False
180
+
181
+
182
+ def _python_module_present(mod: str) -> bool:
183
+ return importlib.util.find_spec(mod) is not None
184
+
185
+
186
+ def build_plan() -> UpdatePlan:
187
+ plan = UpdatePlan(install_method=detect_install_method())
188
+ plan.cli_current = current_cli_version()
189
+ plan.cli_latest = latest_pypi_version() or "?"
190
+
191
+ falkor_running = _docker_running("falkor")
192
+ qdrant_running = _docker_running("qdrant")
193
+ compose_here = _docker_compose_present()
194
+
195
+ plan.components = [
196
+ ComponentState(
197
+ name="CLI (flurryx-code-memory)",
198
+ present=True,
199
+ detail=f"via {plan.install_method}",
200
+ current=plan.cli_current,
201
+ latest=plan.cli_latest,
202
+ ),
203
+ ComponentState(
204
+ name="Docker: FalkorDB",
205
+ present=compose_here or falkor_running,
206
+ detail="running" if falkor_running else ("compose present" if compose_here else "stopped"),
207
+ ),
208
+ ComponentState(
209
+ name="Docker: Qdrant",
210
+ present=compose_here or qdrant_running,
211
+ detail="running" if qdrant_running else ("compose present" if compose_here else "stopped"),
212
+ ),
213
+ ]
214
+
215
+ models = _ollama_models()
216
+ for m in ("bge-m3", "gemma2:9b"):
217
+ plan.components.append(
218
+ ComponentState(
219
+ name=f"Ollama: {m}",
220
+ present=any(name.startswith(m) for name in models),
221
+ )
222
+ )
223
+
224
+ plan.components.append(
225
+ ComponentState(
226
+ name="Extra: hybrid (FlagEmbedding)",
227
+ present=_python_module_present("FlagEmbedding"),
228
+ )
229
+ )
230
+ plan.components.append(
231
+ ComponentState(
232
+ name="Extra: dotnet (dnfile)",
233
+ present=_python_module_present("dnfile"),
234
+ )
235
+ )
236
+
237
+ plan.components.append(
238
+ ComponentState(name="Claude Code plugin", present=_claude_plugin_present())
239
+ )
240
+ plan.components.append(
241
+ ComponentState(name="Claude Code MCP", present=_claude_mcp_present())
242
+ )
243
+ plan.components.append(
244
+ ComponentState(name="OpenCode plugin (npm)", present=_npm_pkg_present())
245
+ )
246
+
247
+ return plan
248
+
249
+
250
+ # ---------- upgrade actions ----------
251
+
252
+
253
+ def upgrade_cli(method: InstallMethod, *, bleeding: bool = False) -> tuple[bool, str]:
254
+ """Upgrade the CLI in-place via the same channel it was installed from."""
255
+ source = f"git+{DEFAULT_REPO_URL}" if bleeding else PYPI_PACKAGE
256
+ if method == "uv-tool":
257
+ if bleeding:
258
+ cmd = ["uv", "tool", "install", "--force", "--from", source, "code-memory"]
259
+ else:
260
+ cmd = ["uv", "tool", "upgrade", PYPI_PACKAGE]
261
+ elif method == "pipx":
262
+ cmd = ["pipx", "upgrade", PYPI_PACKAGE] if not bleeding else [
263
+ "pipx", "install", "--force", source
264
+ ]
265
+ elif method == "pip":
266
+ cmd = [sys.executable, "-m", "pip", "install", "--upgrade", source]
267
+ elif method == "editable":
268
+ return False, "editable install — `git pull` in the repo to update"
269
+ else:
270
+ return False, "unknown install method — re-run the one-liner installer"
271
+ p = _run(cmd, capture=False)
272
+ return p.returncode == 0, " ".join(cmd)
273
+
274
+
275
+ def upgrade_docker_images() -> tuple[bool, str]:
276
+ if not _docker_compose_present() or not _have("docker"):
277
+ return False, "skipped (no compose / docker)"
278
+ compose = CODEMEMORY_HOME / "docker" / "docker-compose.yml"
279
+ pull = _run(
280
+ ["docker", "compose", "-f", str(compose), "--project-directory", str(CODEMEMORY_HOME), "pull"],
281
+ capture=False,
282
+ )
283
+ if pull.returncode != 0:
284
+ return False, "docker compose pull failed"
285
+ up = _run(
286
+ ["docker", "compose", "-f", str(compose), "--project-directory", str(CODEMEMORY_HOME), "up", "-d"],
287
+ capture=False,
288
+ )
289
+ return up.returncode == 0, "compose pulled + up"
290
+
291
+
292
+ def upgrade_ollama_model(model: str) -> tuple[bool, str]:
293
+ if not _have("ollama"):
294
+ return False, "ollama not on PATH"
295
+ p = _run(["ollama", "pull", model], capture=False)
296
+ return p.returncode == 0, f"pulled {model}"
297
+
298
+
299
+ def upgrade_claude_plugin() -> tuple[bool, str]:
300
+ if not _have("claude"):
301
+ return False, "claude CLI not on PATH"
302
+ # `claude plugin install` is idempotent — re-pin to latest from marketplace
303
+ p = _run(
304
+ ["claude", "plugin", "install", "code-memory@code-memory", "--scope", "user", "--force"],
305
+ capture=False,
306
+ )
307
+ return p.returncode == 0, "claude plugin refreshed"
308
+
309
+
310
+ def upgrade_npm_pkg(pkg: str = "code-memory-opencode") -> tuple[bool, str]:
311
+ if not _have("npm"):
312
+ return False, "npm not on PATH"
313
+ p = _run(["npm", "i", "-g", pkg], capture=False)
314
+ return p.returncode == 0, f"npm i -g {pkg}"
315
+
316
+
317
+ # ---------- orchestrator ----------
318
+
319
+
320
+ def run_update(*, check_only: bool, full: bool, bleeding: bool) -> int:
321
+ """Top-level entry point used by the CLI.
322
+
323
+ ``check_only`` prints the plan and exits 0/1 based on whether anything
324
+ is behind. ``full`` re-runs the one-liner installer (curl … | bash).
325
+ Default is the smart path: upgrade-in-place only what is already present.
326
+ """
327
+ plan = build_plan()
328
+ _print_plan(plan)
329
+
330
+ behind_cli = plan.cli_latest not in ("?", plan.cli_current)
331
+
332
+ if check_only:
333
+ return 1 if behind_cli else 0
334
+
335
+ if full:
336
+ return _run_full_installer()
337
+
338
+ rc = 0
339
+ if behind_cli:
340
+ ok, detail = upgrade_cli(plan.install_method, bleeding=bleeding)
341
+ print(f" CLI upgrade: {'ok' if ok else 'FAILED'} — {detail}")
342
+ rc |= 0 if ok else 1
343
+ else:
344
+ print(f" CLI: already {plan.cli_current}")
345
+
346
+ for comp in plan.components:
347
+ if not comp.present:
348
+ continue
349
+ if comp.name == "Docker: FalkorDB" or comp.name == "Docker: Qdrant":
350
+ # one pass for both
351
+ continue
352
+ if comp.name.startswith("Ollama: "):
353
+ model = comp.name.split(": ", 1)[1]
354
+ ok, detail = upgrade_ollama_model(model)
355
+ print(f" {comp.name}: {'ok' if ok else 'skip'} — {detail}")
356
+ elif comp.name == "Claude Code plugin":
357
+ ok, detail = upgrade_claude_plugin()
358
+ print(f" {comp.name}: {'ok' if ok else 'skip'} — {detail}")
359
+ elif comp.name == "OpenCode plugin (npm)":
360
+ ok, detail = upgrade_npm_pkg()
361
+ print(f" {comp.name}: {'ok' if ok else 'skip'} — {detail}")
362
+
363
+ if any(c.present for c in plan.components if c.name.startswith("Docker:")):
364
+ ok, detail = upgrade_docker_images()
365
+ print(f" Docker stack: {'ok' if ok else 'skip'} — {detail}")
366
+
367
+ return rc
368
+
369
+
370
+ def _print_plan(plan: UpdatePlan) -> None:
371
+ print(f"code-memory updater (install: {plan.install_method})")
372
+ print(f" CLI: {plan.cli_current} → latest: {plan.cli_latest}")
373
+ print(" Components detected locally:")
374
+ for c in plan.components[1:]: # skip CLI row, already shown
375
+ mark = "•" if c.present else "·"
376
+ suffix = f" ({c.detail})" if c.detail else ""
377
+ state = "" if c.present else " [not installed — skip]"
378
+ print(f" {mark} {c.name}{suffix}{state}")
379
+
380
+
381
+ def _run_full_installer() -> int:
382
+ """Pipe the one-liner installer through bash (or PowerShell on Windows)."""
383
+ raw = os.environ.get(
384
+ "CODEMEMORY_RAW_URL", "https://raw.githubusercontent.com/fmflurry/code-memory/main"
385
+ )
386
+ if sys.platform == "win32":
387
+ cmd = [
388
+ "powershell",
389
+ "-NoProfile",
390
+ "-Command",
391
+ f"irm {raw}/install.ps1 | iex",
392
+ ]
393
+ else:
394
+ cmd = ["bash", "-c", f"curl -fsSL {raw}/install.sh | bash"]
395
+ p = _run(cmd, capture=False)
396
+ return p.returncode
@@ -1 +0,0 @@
1
- __version__ = "0.1.0"