claude-smart 0.2.44 → 0.2.46

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 (323) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +34 -5
  3. package/bin/claude-smart.js +295 -5
  4. package/package.json +22 -3
  5. package/plugin/.claude-plugin/plugin.json +4 -2
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +22 -2
  8. package/plugin/commands/clear-all.md +1 -0
  9. package/plugin/commands/dashboard.md +1 -0
  10. package/plugin/commands/learn.md +1 -0
  11. package/plugin/commands/restart.md +1 -0
  12. package/plugin/commands/show.md +1 -0
  13. package/plugin/dashboard/app/configure/env/page.tsx +40 -14
  14. package/plugin/dashboard/app/configure/server/page.tsx +51 -1
  15. package/plugin/dashboard/app/preferences/[id]/page.tsx +8 -8
  16. package/plugin/dashboard/app/skills/project/[id]/page.tsx +7 -3
  17. package/plugin/dashboard/app/skills/shared/[id]/page.tsx +10 -3
  18. package/plugin/dashboard/lib/claude-settings-file.ts +20 -10
  19. package/plugin/dashboard/lib/reflexio-client.ts +16 -0
  20. package/plugin/dashboard/lib/status.ts +10 -3
  21. package/plugin/dashboard/lib/types.ts +18 -6
  22. package/plugin/hooks/codex-hooks.json +0 -1
  23. package/plugin/opencode/assistant-buffer.ts +108 -0
  24. package/plugin/opencode/dist/assistant-buffer.js +96 -0
  25. package/plugin/opencode/dist/internal.js +12 -0
  26. package/plugin/opencode/dist/payload.js +85 -0
  27. package/plugin/opencode/dist/server.mjs +158 -0
  28. package/plugin/opencode/internal.ts +18 -0
  29. package/plugin/opencode/package.json +3 -0
  30. package/plugin/opencode/payload.ts +90 -0
  31. package/plugin/opencode/server.mts +174 -0
  32. package/plugin/opencode/tsconfig.json +13 -0
  33. package/plugin/pyproject.toml +20 -3
  34. package/plugin/scripts/_lib.sh +77 -29
  35. package/plugin/scripts/backend-service.sh +27 -5
  36. package/plugin/scripts/dashboard-service.sh +7 -5
  37. package/plugin/scripts/ensure-plugin-root.sh +4 -4
  38. package/plugin/scripts/hook_entry.sh +3 -3
  39. package/plugin/scripts/opencode-claude-compat +4 -0
  40. package/plugin/scripts/opencode-claude-compat.cmd +3 -0
  41. package/plugin/scripts/opencode-claude-compat.js +225 -0
  42. package/plugin/scripts/smart-install.sh +10 -8
  43. package/plugin/src/README.md +1 -1
  44. package/plugin/src/claude_smart/cli.py +304 -6
  45. package/plugin/src/claude_smart/env_config.py +12 -4
  46. package/plugin/src/claude_smart/events/session_start.py +26 -7
  47. package/plugin/src/claude_smart/events/stop.py +1 -1
  48. package/plugin/src/claude_smart/ids.py +1 -1
  49. package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
  50. package/plugin/src/claude_smart/runtime.py +7 -1
  51. package/plugin/uv.lock +1 -1
  52. package/plugin/vendor/reflexio/.env.example +54 -30
  53. package/plugin/vendor/reflexio/README.md +14 -8
  54. package/plugin/vendor/reflexio/pyproject.toml +13 -1
  55. package/plugin/vendor/reflexio/reflexio/README.md +1 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
  57. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
  58. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +210 -50
  63. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
  64. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
  65. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
  66. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
  67. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
  68. package/plugin/vendor/reflexio/reflexio/client/client.py +57 -13
  69. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
  70. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
  71. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
  72. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
  73. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
  74. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
  75. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
  142. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +238 -10
  143. package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
  144. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +16 -5
  145. package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
  146. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +198 -6
  147. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
  148. package/plugin/vendor/reflexio/reflexio/lib/_search.py +29 -20
  149. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +2 -1
  150. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
  151. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
  152. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
  153. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
  154. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
  155. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +52 -0
  156. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
  157. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
  158. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +88 -7
  159. package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
  160. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
  161. package/plugin/vendor/reflexio/reflexio/server/README.md +45 -32
  162. package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
  163. package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
  164. package/plugin/vendor/reflexio/reflexio/server/_auth.py +65 -2
  165. package/plugin/vendor/reflexio/reflexio/server/api.py +734 -85
  166. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
  167. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +3 -1
  168. package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
  169. package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
  170. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
  171. package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
  172. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
  173. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
  174. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
  175. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
  176. package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
  177. package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
  178. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
  179. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
  180. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
  181. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
  182. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
  183. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
  184. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
  185. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
  186. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
  187. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
  188. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +266 -0
  189. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
  190. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
  191. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
  192. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
  193. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
  194. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
  195. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
  196. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
  197. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
  198. package/plugin/vendor/reflexio/reflexio/server/services/README.md +26 -11
  199. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
  200. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
  201. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
  202. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
  203. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
  204. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
  205. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
  206. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
  207. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
  208. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
  209. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
  210. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
  211. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
  212. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
  213. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
  214. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
  215. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
  216. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
  217. package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
  218. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
  219. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
  220. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
  221. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +39 -16
  222. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
  223. package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
  224. package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +193 -0
  225. package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
  226. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
  227. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +11 -12
  228. package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
  229. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +316 -178
  230. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
  231. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
  232. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
  233. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
  234. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
  235. package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +84 -0
  236. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
  237. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
  238. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
  239. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
  240. package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
  241. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
  242. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +30 -22
  243. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
  244. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
  245. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
  246. package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
  247. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
  248. package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
  249. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +83 -6
  250. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
  251. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
  252. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
  253. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +27 -0
  254. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
  255. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
  256. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
  257. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +642 -197
  258. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +61 -104
  259. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +628 -0
  260. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
  261. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +978 -184
  262. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +519 -128
  263. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +77 -3
  264. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
  265. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
  266. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +131 -20
  267. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
  268. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
  269. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +36 -53
  270. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
  271. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
  272. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +243 -7
  273. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +121 -1
  274. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +60 -0
  275. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
  276. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
  277. package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
  278. package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
  279. package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
  281. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +229 -32
  282. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
  283. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
  284. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
  285. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
  286. package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
  287. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
  288. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
  289. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
  290. package/scripts/setup-claude-smart.sh +8 -3
  291. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
  292. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
  293. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
  294. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
  295. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
  296. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
  297. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
  298. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
  299. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
  300. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
  301. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
  302. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
  303. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
  304. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
  305. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
  306. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
  307. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
  308. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
  309. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
  310. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
  311. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
  312. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
  313. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
  314. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
  318. /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
  319. /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
  320. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
  321. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
  322. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
  323. /package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_extractor.py → components/extractor.py} +0 -0
@@ -3,7 +3,7 @@
3
3
  Exposes the following subcommands:
4
4
 
5
5
  - ``install``: register the GitHub marketplace and install the plugin into
6
- Claude Code, then seed ``~/.reflexio/.env`` with the local-provider flags.
6
+ Claude Code, then seed ``~/.claude-smart/.env`` with the local-provider flags.
7
7
  - ``update``: update the plugin to the latest version via the native Claude
8
8
  Code plugin CLI.
9
9
  - ``uninstall``: remove the plugin from Claude Code via the native plugin
@@ -56,6 +56,8 @@ _CODEX_PLUGIN_CACHE_DIR = (
56
56
  / "claude-smart"
57
57
  )
58
58
  _CODEX_CLI_TIMEOUT_SECONDS = 30
59
+ _OPENCODE_PLUGIN_SPEC = "claude-smart"
60
+ _OPENCODE_CONFIG_NAMES = ("opencode.json", "opencode.jsonc")
59
61
  _REFLEXIO_UNREACHABLE_MSG = (
60
62
  "Failed to reach reflexio. Check ~/.claude-smart/backend.log "
61
63
  "or restart Claude Code.\n"
@@ -83,7 +85,12 @@ _LOCAL_DATA_NOTICE = (
83
85
  _INSTALL_FAILURE_MARKER = _STATE_DIR / "install-failed"
84
86
  _SERVICE_STATUS_PROBE_FAILED = "probe_failed"
85
87
  _DEFAULT_STORAGE_ROOT = _REFLEXIO_DIR / "data"
86
- _REFLEXIO_CONFIG_PATH = _REFLEXIO_DIR / "configs" / "config_self-host-org.json"
88
+ # Org id claude-smart's backend runs under (set via REFLEXIO_DEFAULT_ORG_ID in
89
+ # backend-service.sh). reflexio names the config file config_<org>.json, so this
90
+ # must stay in sync with that export; using our own org keeps us off the
91
+ # enterprise self-host backend's config_self-host-org.json.
92
+ _REFLEXIO_ORG_ID = "claude-smart"
93
+ _REFLEXIO_CONFIG_PATH = _REFLEXIO_DIR / "configs" / f"config_{_REFLEXIO_ORG_ID}.json"
87
94
  _LOCAL_STORAGE_ENV = "LOCAL_STORAGE_PATH"
88
95
  _CODEX_REQUIRED_FILES = (
89
96
  Path(".agents/plugins/marketplace.json"),
@@ -92,6 +99,9 @@ _CODEX_REQUIRED_FILES = (
92
99
  Path("plugin/scripts/codex-claude-compat"),
93
100
  Path("plugin/scripts/codex-claude-compat.cmd"),
94
101
  Path("plugin/scripts/codex-claude-compat.js"),
102
+ Path("plugin/scripts/opencode-claude-compat"),
103
+ Path("plugin/scripts/opencode-claude-compat.cmd"),
104
+ Path("plugin/scripts/opencode-claude-compat.js"),
95
105
  Path("plugin/scripts/codex-hook.js"),
96
106
  Path("plugin/scripts/backend-log-runner.sh"),
97
107
  Path("plugin/scripts/_codex_env.sh"),
@@ -963,6 +973,237 @@ def _configure_reflexio_setup() -> bool:
963
973
  return read_only
964
974
 
965
975
 
976
+ def _strip_jsonc(text: str) -> str:
977
+ """Remove JSONC comments and trailing commas without touching strings."""
978
+
979
+ def skip_trivia(index: int) -> int:
980
+ while index < len(text):
981
+ while index < len(text) and text[index].isspace():
982
+ index += 1
983
+ if text[index : index + 2] == "//":
984
+ index += 2
985
+ while index < len(text) and text[index] not in "\r\n":
986
+ index += 1
987
+ continue
988
+ if text[index : index + 2] == "/*":
989
+ index += 2
990
+ while index + 1 < len(text) and text[index : index + 2] != "*/":
991
+ index += 1
992
+ index = min(index + 2, len(text))
993
+ continue
994
+ break
995
+ return index
996
+
997
+ out: list[str] = []
998
+ in_string = False
999
+ escaped = False
1000
+ i = 0
1001
+ while i < len(text):
1002
+ ch = text[i]
1003
+ nxt = text[i + 1] if i + 1 < len(text) else ""
1004
+ if in_string:
1005
+ out.append(ch)
1006
+ if escaped:
1007
+ escaped = False
1008
+ elif ch == "\\":
1009
+ escaped = True
1010
+ elif ch == '"':
1011
+ in_string = False
1012
+ i += 1
1013
+ continue
1014
+ if ch == '"':
1015
+ in_string = True
1016
+ out.append(ch)
1017
+ i += 1
1018
+ continue
1019
+ if ch == "/" and nxt == "/":
1020
+ while i < len(text) and text[i] not in "\r\n":
1021
+ i += 1
1022
+ continue
1023
+ if ch == "/" and nxt == "*":
1024
+ i += 2
1025
+ while i + 1 < len(text) and not (text[i] == "*" and text[i + 1] == "/"):
1026
+ i += 1
1027
+ i += 2
1028
+ continue
1029
+ if ch == ",":
1030
+ j = skip_trivia(i + 1)
1031
+ if j < len(text) and text[j] in "}]":
1032
+ i += 1
1033
+ continue
1034
+ out.append(ch)
1035
+ i += 1
1036
+ return "".join(out)
1037
+
1038
+
1039
+ def _read_jsonc_object(path: Path) -> dict[str, object]:
1040
+ try:
1041
+ text = path.read_text() if path.exists() else "{}"
1042
+ parsed = json.loads(_strip_jsonc(text or "{}"))
1043
+ except (OSError, json.JSONDecodeError) as exc:
1044
+ raise ValueError(f"could not parse OpenCode config {path}: {exc}") from exc
1045
+ if not isinstance(parsed, dict):
1046
+ raise ValueError(f"OpenCode config {path} must be a JSON object")
1047
+ return parsed
1048
+
1049
+
1050
+ def _opencode_global_config_dir() -> Path:
1051
+ xdg = os.environ.get("XDG_CONFIG_HOME", "").strip()
1052
+ base = Path(xdg) if xdg else Path.home() / ".config"
1053
+ return base / "opencode"
1054
+
1055
+
1056
+ def _opencode_config_path(*, global_config: bool = False, cwd: Path | None = None) -> Path:
1057
+ if global_config:
1058
+ config_dir = _opencode_global_config_dir()
1059
+ for name in _OPENCODE_CONFIG_NAMES:
1060
+ candidate = config_dir / name
1061
+ if candidate.exists():
1062
+ return candidate
1063
+ return config_dir / "opencode.json"
1064
+ base = cwd or Path.cwd()
1065
+ candidates = [
1066
+ *(base / name for name in _OPENCODE_CONFIG_NAMES),
1067
+ *(base / ".opencode" / name for name in _OPENCODE_CONFIG_NAMES),
1068
+ ]
1069
+ for candidate in candidates:
1070
+ if candidate.exists():
1071
+ return candidate
1072
+ return base / "opencode.json"
1073
+
1074
+
1075
+ def _opencode_plugin_spec(entry: object) -> str | None:
1076
+ if isinstance(entry, str):
1077
+ return entry
1078
+ if isinstance(entry, list) and entry and isinstance(entry[0], str):
1079
+ return entry[0]
1080
+ return None
1081
+
1082
+
1083
+ def _patch_opencode_plugin_config(
1084
+ config_path: Path, *, install: bool
1085
+ ) -> tuple[bool, Path]:
1086
+ data = _read_jsonc_object(config_path)
1087
+ for field in ("plugins", "plugin"):
1088
+ value = data.get(field)
1089
+ if value is not None and not isinstance(value, list):
1090
+ raise ValueError(
1091
+ f'OpenCode config {config_path} field "{field}" must be a JSON array'
1092
+ )
1093
+ current_plugin = data.get("plugin")
1094
+ plugins: list[object] = []
1095
+ if isinstance(current_plugin, list):
1096
+ plugins.extend(current_plugin)
1097
+ legacy_plugins = data.get("plugins")
1098
+ if isinstance(legacy_plugins, list):
1099
+ plugins.extend(legacy_plugins)
1100
+ kept = [
1101
+ item
1102
+ for item in plugins
1103
+ if _opencode_plugin_spec(item) != _OPENCODE_PLUGIN_SPEC
1104
+ ]
1105
+ next_plugins = [*kept, _OPENCODE_PLUGIN_SPEC] if install else kept
1106
+ if isinstance(current_plugin, list):
1107
+ changed = ("plugins" in data) or next_plugins != current_plugin
1108
+ else:
1109
+ changed = ("plugins" in data) or (install and bool(next_plugins))
1110
+ if not changed:
1111
+ return False, config_path
1112
+ if config_path.exists():
1113
+ original = config_path.read_text()
1114
+ if original.strip() and original != _strip_jsonc(original):
1115
+ config_path.with_suffix(config_path.suffix + ".bak").write_text(original)
1116
+ data["plugin"] = next_plugins
1117
+ data.pop("plugins", None)
1118
+ config_path.parent.mkdir(parents=True, exist_ok=True)
1119
+ config_path.write_text(json.dumps(data, indent=2) + "\n")
1120
+ return True, config_path
1121
+
1122
+
1123
+ def _has_extraction_provider() -> bool:
1124
+ env_config.load_reflexio_env(_REFLEXIO_ENV_PATH)
1125
+ if os.environ.get(env_config.REFLEXIO_API_KEY_ENV, "").strip():
1126
+ return True
1127
+ cli_path = os.environ.get("CLAUDE_SMART_CLI_PATH", "").strip()
1128
+ if cli_path:
1129
+ resolved = Path(cli_path).expanduser()
1130
+ if resolved.is_file() and os.access(resolved, os.X_OK):
1131
+ return True
1132
+ return bool(shutil.which("claude") or shutil.which("codex") or shutil.which("opencode"))
1133
+
1134
+
1135
+ def _extraction_provider_error() -> str:
1136
+ return (
1137
+ "error: OpenCode support needs a working learning/extraction provider.\n"
1138
+ "Run `npx claude-smart setup` to configure Reflexio, or install "
1139
+ "OpenCode, Claude Code, or Codex so local extraction can use a supported CLI.\n"
1140
+ )
1141
+
1142
+
1143
+ def _opencode_install_supported_from_this_package() -> bool:
1144
+ return (_SCRIPTS_DIR / "smart-install.sh").is_file()
1145
+
1146
+
1147
+ def _bootstrap_opencode_install(read_only: bool) -> tuple[bool, str]:
1148
+ if not _opencode_install_supported_from_this_package():
1149
+ return (
1150
+ False,
1151
+ "OpenCode install is supported from the npm package. "
1152
+ "Run `npx claude-smart install --host opencode`.",
1153
+ )
1154
+ try:
1155
+ _force_plugin_root(_PLUGIN_ROOT)
1156
+ except OSError as exc:
1157
+ return False, str(exc)
1158
+ bash = _resolve_bash()
1159
+ if not bash:
1160
+ return False, "bash is required to bootstrap claude-smart dependencies"
1161
+ result = subprocess.run([bash, str(_SCRIPTS_DIR / "smart-install.sh")], cwd=_PLUGIN_ROOT)
1162
+ if result.returncode != 0:
1163
+ return False, f"smart-install.sh failed in {_PLUGIN_ROOT}"
1164
+ if _INSTALL_FAILURE_MARKER.is_file():
1165
+ first_line = _INSTALL_FAILURE_MARKER.read_text().splitlines()
1166
+ reason = (first_line[0].strip() if first_line else "") or "unknown error"
1167
+ return False, reason
1168
+ if read_only:
1169
+ _prune_publish_hooks_for_read_only(_PLUGIN_ROOT)
1170
+ return True, str(_PLUGIN_ROOT)
1171
+
1172
+
1173
+ def cmd_install_opencode(args: argparse.Namespace) -> int:
1174
+ if not _opencode_install_supported_from_this_package():
1175
+ sys.stderr.write(
1176
+ "error: OpenCode install is supported from the npm package. "
1177
+ "Run `npx claude-smart install --host opencode`.\n"
1178
+ )
1179
+ return 1
1180
+ read_only = _configure_reflexio_setup()
1181
+ if not _has_extraction_provider():
1182
+ sys.stderr.write(_extraction_provider_error())
1183
+ return 1
1184
+ bootstrapped, message = _bootstrap_opencode_install(read_only)
1185
+ if not bootstrapped:
1186
+ sys.stderr.write(
1187
+ f"error: claude-smart OpenCode setup failed during dependency bootstrap: {message}\n"
1188
+ )
1189
+ return 1
1190
+ config_path = _opencode_config_path(
1191
+ global_config=bool(getattr(args, "global_config", False))
1192
+ )
1193
+ try:
1194
+ changed, config_path = _patch_opencode_plugin_config(config_path, install=True)
1195
+ except ValueError as exc:
1196
+ sys.stderr.write(f"error: {exc}\n")
1197
+ return 1
1198
+ action = "Updated" if changed else "OpenCode config already includes"
1199
+ sys.stdout.write(
1200
+ f"{action} `{_OPENCODE_PLUGIN_SPEC}` in {config_path}.\n"
1201
+ f"Prepared claude-smart runtime at {message}.\n"
1202
+ "Restart OpenCode in your project so it loads the plugin.\n"
1203
+ )
1204
+ return 0
1205
+
1206
+
966
1207
  def cmd_install_codex(args: argparse.Namespace) -> int:
967
1208
  """Install the claude-smart plugin marketplace for Codex.
968
1209
 
@@ -1073,7 +1314,7 @@ def cmd_install(args: argparse.Namespace) -> int:
1073
1314
 
1074
1315
  Runs ``claude plugin marketplace add`` (pointed at the bundled marketplace
1075
1316
  at ``_REPO_ROOT``) followed by ``claude plugin install``, then appends the
1076
- local-provider flags to ``~/.reflexio/.env`` so reflexio can route
1317
+ local-provider flags to ``~/.claude-smart/.env`` so reflexio can route
1077
1318
  generation through the local Claude Code CLI.
1078
1319
 
1079
1320
  Args:
@@ -1084,6 +1325,8 @@ def cmd_install(args: argparse.Namespace) -> int:
1084
1325
  """
1085
1326
  if getattr(args, "host", "claude-code") == "codex":
1086
1327
  return cmd_install_codex(args)
1328
+ if getattr(args, "host", "claude-code") == "opencode":
1329
+ return cmd_install_opencode(args)
1087
1330
 
1088
1331
  if not shutil.which("claude"):
1089
1332
  sys.stderr.write(
@@ -1156,6 +1399,8 @@ def cmd_update(args: argparse.Namespace) -> int:
1156
1399
  """
1157
1400
  if getattr(args, "host", "claude-code") == "codex":
1158
1401
  return cmd_update_codex(args)
1402
+ if getattr(args, "host", "claude-code") == "opencode":
1403
+ return cmd_update_opencode(args)
1159
1404
 
1160
1405
  _run_service(_DASHBOARD_SCRIPT, "stop")
1161
1406
  _run_service(_BACKEND_SCRIPT, "stop")
@@ -1182,6 +1427,17 @@ def cmd_update_codex(_args: argparse.Namespace) -> int:
1182
1427
  return cmd_install_codex(install_args)
1183
1428
 
1184
1429
 
1430
+ def cmd_update_opencode(args: argparse.Namespace) -> int:
1431
+ _run_service(_DASHBOARD_SCRIPT, "stop")
1432
+ _run_service(_BACKEND_SCRIPT, "stop")
1433
+ sys.stdout.write(
1434
+ "Updating claude-smart OpenCode support by reinstalling from this package...\n"
1435
+ )
1436
+ install_args = argparse.Namespace(**vars(args))
1437
+ install_args.host = "opencode"
1438
+ return cmd_install_opencode(install_args)
1439
+
1440
+
1185
1441
  def cmd_uninstall(_args: argparse.Namespace) -> int:
1186
1442
  """Uninstall claude-smart from Claude Code via the native plugin CLI.
1187
1443
 
@@ -1196,6 +1452,8 @@ def cmd_uninstall(_args: argparse.Namespace) -> int:
1196
1452
  """
1197
1453
  if getattr(_args, "host", "claude-code") == "codex":
1198
1454
  return cmd_uninstall_codex(_args)
1455
+ if getattr(_args, "host", "claude-code") == "opencode":
1456
+ return cmd_uninstall_opencode(_args)
1199
1457
 
1200
1458
  if not shutil.which("claude"):
1201
1459
  sys.stderr.write(
@@ -1256,6 +1514,28 @@ def cmd_uninstall_codex(_args: argparse.Namespace) -> int:
1256
1514
  return 0
1257
1515
 
1258
1516
 
1517
+ def cmd_uninstall_opencode(args: argparse.Namespace) -> int:
1518
+ _run_service(_DASHBOARD_SCRIPT, "stop")
1519
+ _run_service(_BACKEND_SCRIPT, "stop")
1520
+ config_path = _opencode_config_path(
1521
+ global_config=bool(getattr(args, "global_config", False))
1522
+ )
1523
+ try:
1524
+ changed, config_path = _patch_opencode_plugin_config(config_path, install=False)
1525
+ except ValueError as exc:
1526
+ sys.stderr.write(f"error: {exc}\n")
1527
+ return 1
1528
+ if changed:
1529
+ sys.stdout.write(f"Removed `{_OPENCODE_PLUGIN_SPEC}` from {config_path}.\n")
1530
+ else:
1531
+ sys.stdout.write(f"OpenCode config did not include `{_OPENCODE_PLUGIN_SPEC}`.\n")
1532
+ sys.stdout.write(
1533
+ "Restart OpenCode to apply. "
1534
+ f"{_LOCAL_DATA_NOTICE}"
1535
+ )
1536
+ return 0
1537
+
1538
+
1259
1539
  def cmd_show(args: argparse.Namespace) -> int:
1260
1540
  """Print this project's skills + preferences, plus globally-shared skills.
1261
1541
 
@@ -1981,28 +2261,46 @@ def _build_parser() -> argparse.ArgumentParser:
1981
2261
  inst = sub.add_parser("install", help="Install claude-smart")
1982
2262
  inst.add_argument(
1983
2263
  "--host",
1984
- choices=("claude-code", "codex"),
2264
+ choices=("claude-code", "codex", "opencode"),
1985
2265
  default="claude-code",
1986
2266
  help="Install target host",
1987
2267
  )
2268
+ inst.add_argument(
2269
+ "--global",
2270
+ dest="global_config",
2271
+ action="store_true",
2272
+ help="For OpenCode, patch ~/.config/opencode instead of the project config",
2273
+ )
1988
2274
  inst.set_defaults(func=cmd_install)
1989
2275
 
1990
2276
  upd = sub.add_parser("update", help="Update claude-smart to the latest version")
1991
2277
  upd.add_argument(
1992
2278
  "--host",
1993
- choices=("claude-code", "codex"),
2279
+ choices=("claude-code", "codex", "opencode"),
1994
2280
  default="claude-code",
1995
2281
  help="Update target host",
1996
2282
  )
2283
+ upd.add_argument(
2284
+ "--global",
2285
+ dest="global_config",
2286
+ action="store_true",
2287
+ help="For OpenCode, patch ~/.config/opencode instead of the project config",
2288
+ )
1997
2289
  upd.set_defaults(func=cmd_update)
1998
2290
 
1999
2291
  uni = sub.add_parser("uninstall", help="Remove claude-smart")
2000
2292
  uni.add_argument(
2001
2293
  "--host",
2002
- choices=("claude-code", "codex"),
2294
+ choices=("claude-code", "codex", "opencode"),
2003
2295
  default="claude-code",
2004
2296
  help="Uninstall target host",
2005
2297
  )
2298
+ uni.add_argument(
2299
+ "--global",
2300
+ dest="global_config",
2301
+ action="store_true",
2302
+ help="For OpenCode, patch ~/.config/opencode instead of the project config",
2303
+ )
2006
2304
  uni.set_defaults(func=cmd_uninstall)
2007
2305
 
2008
2306
  sh = sub.add_parser(
@@ -1,11 +1,19 @@
1
- """Shared ``~/.reflexio/.env`` helpers for claude-smart."""
1
+ """Shared ``~/.claude-smart/.env`` helpers for claude-smart.
2
+
3
+ claude-smart keeps its env under ``~/.claude-smart`` (not ``~/.reflexio``) so an
4
+ OSS reflexio backend sharing this machine never leaks its ``.env`` into
5
+ claude-smart. The data directory stays shared at ``~/.reflexio/data``. This path
6
+ must stay in sync with the ``REFLEXIO_ENV_FILE`` export in
7
+ ``scripts/backend-service.sh`` and the source path in
8
+ ``scripts/_lib.sh`` (``claude_smart_source_reflexio_env``).
9
+ """
2
10
 
3
11
  from __future__ import annotations
4
12
 
5
13
  import os
6
14
  from pathlib import Path
7
15
 
8
- REFLEXIO_ENV_PATH = Path.home() / ".reflexio" / ".env"
16
+ REFLEXIO_ENV_PATH = Path.home() / ".claude-smart" / ".env"
9
17
  MANAGED_REFLEXIO_URL = "https://www.reflexio.ai/"
10
18
  REFLEXIO_URL_ENV = "REFLEXIO_URL"
11
19
  REFLEXIO_API_KEY_ENV = "REFLEXIO_API_KEY"
@@ -60,7 +68,7 @@ def parse_env_line(line: str) -> tuple[str, str] | None:
60
68
 
61
69
 
62
70
  def load_reflexio_env(path: Path | None = None) -> None:
63
- """Load ``~/.reflexio/.env`` into ``os.environ`` without overriding values."""
71
+ """Load ``~/.claude-smart/.env`` into ``os.environ`` without overriding values."""
64
72
  path = path or REFLEXIO_ENV_PATH
65
73
  try:
66
74
  text = path.read_text()
@@ -111,7 +119,7 @@ def set_env_vars(path: Path, values: dict[str, str]) -> list[str]:
111
119
 
112
120
 
113
121
  def ensure_local_env_defaults(path: Path | None = None) -> list[str]:
114
- """Create or augment ``~/.reflexio/.env`` for claude-smart local mode.
122
+ """Create or augment ``~/.claude-smart/.env`` for claude-smart local mode.
115
123
 
116
124
  Existing active assignments win. This repairs first installs and deleted
117
125
  env files without clobbering explicit user overrides such as
@@ -5,8 +5,10 @@ from __future__ import annotations
5
5
  import json
6
6
  import os
7
7
  import sys
8
+ from contextlib import suppress
8
9
  from pathlib import Path
9
10
  from typing import Any
11
+ from urllib.parse import urlparse
10
12
 
11
13
  from claude_smart import hook
12
14
  from claude_smart.reflexio_adapter import Adapter
@@ -41,10 +43,12 @@ def _int_env(name: str, default: int) -> int:
41
43
 
42
44
  _CLAUDE_SMART_WINDOW_SIZE = _int_env("CLAUDE_SMART_WINDOW_SIZE", 5)
43
45
  _CLAUDE_SMART_STRIDE_SIZE = _int_env("CLAUDE_SMART_STRIDE_SIZE", 3)
44
- # Optimizer is on by default. Set this env var to "0" to skip pushing the
45
- # claude-smart optimizer defaults on SessionStart (kill switch).
46
- _DISABLE_OPTIMIZER_ENV = "CLAUDE_SMART_ENABLE_OPTIMIZER"
46
+ # Optimizer defaults are local-only by default because they store an absolute
47
+ # path to the claude-smart helper process. Set this env var to "1" to force
48
+ # enabling against a non-local Reflexio URL, or "0" to disable everywhere.
49
+ _OPTIMIZER_ENV = "CLAUDE_SMART_ENABLE_OPTIMIZER"
47
50
  _OPTIMIZER_TIMEOUT_SECONDS = 300
51
+ _LOCAL_REFLEXIO_HOSTS = {"", "localhost", "127.0.0.1", "::1"}
48
52
 
49
53
 
50
54
  def _adapter() -> Adapter:
@@ -109,7 +113,7 @@ def handle(payload: dict[str, Any]) -> None:
109
113
  window_size=_CLAUDE_SMART_WINDOW_SIZE,
110
114
  stride_size=_CLAUDE_SMART_STRIDE_SIZE,
111
115
  )
112
- if os.environ.get(_DISABLE_OPTIMIZER_ENV) != "0":
116
+ if _should_apply_optimizer_defaults(adapter):
113
117
  adapter.apply_optimizer_defaults(
114
118
  script_path=_optimizer_assistant_path(),
115
119
  timeout_seconds=_OPTIMIZER_TIMEOUT_SECONDS,
@@ -131,13 +135,28 @@ def handle(payload: dict[str, Any]) -> None:
131
135
  )
132
136
  sys.stdout.write("\n")
133
137
 
134
- try:
138
+ with suppress(Exception):
135
139
  adapter.mark_stall_notified()
136
- except Exception: # noqa: BLE001 — telemetry must not break session.
137
- pass
138
140
 
139
141
 
140
142
  def _optimizer_assistant_path() -> str:
141
143
  executable = Path(sys.executable)
142
144
  suffix = ".exe" if os.name == "nt" else ""
143
145
  return str(executable.with_name(f"claude-smart-optimizer-assistant{suffix}"))
146
+
147
+
148
+ def _should_apply_optimizer_defaults(adapter: Any) -> bool:
149
+ flag = os.environ.get(_OPTIMIZER_ENV, "").strip().lower()
150
+ if flag in {"0", "false", "no", "off"}:
151
+ return False
152
+ if flag in {"1", "true", "yes", "on"}:
153
+ return True
154
+ return _is_local_reflexio_url(getattr(adapter, "url", ""))
155
+
156
+
157
+ def _is_local_reflexio_url(url: str) -> bool:
158
+ if not url:
159
+ return True
160
+ parsed = urlparse(url)
161
+ host = parsed.hostname if parsed.scheme else url.split(":", 1)[0]
162
+ return (host or "").lower() in _LOCAL_REFLEXIO_HOSTS
@@ -377,7 +377,7 @@ def handle(payload: dict[str, Any]) -> tuple[publish.PublishStatus, int] | None:
377
377
  last_assistant_message = payload.get("last_assistant_message")
378
378
  assistant_text = (
379
379
  last_assistant_message
380
- if runtime.is_codex()
380
+ if (runtime.is_codex() or runtime.is_opencode())
381
381
  and isinstance(last_assistant_message, str)
382
382
  and last_assistant_message
383
383
  else _scan_transcript_for_assistant_text(entries)
@@ -77,7 +77,7 @@ def resolve_user_id(cwd: str | os.PathLike[str] | None = None) -> str:
77
77
  Honors the ``REFLEXIO_USER_ID`` env var as an explicit override (e.g. so a
78
78
  user can point multiple projects at a single Reflexio identity), and
79
79
  otherwise falls back to :func:`resolve_project_id`. The env var is
80
- loaded from ``~/.reflexio/.env`` before reading the process environment so
80
+ loaded from ``~/.claude-smart/.env`` before reading the process environment so
81
81
  CLI commands and hooks use the same identity resolution.
82
82
 
83
83
  Args:
@@ -6,16 +6,15 @@ Exists so hook handlers (a) don't import reflexio directly at module scope
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import inspect
9
10
  import logging
10
11
  import os
11
- import inspect
12
12
  from collections.abc import Sequence
13
13
  from concurrent.futures import ThreadPoolExecutor
14
14
  from dataclasses import dataclass, field
15
15
  from typing import Any
16
16
 
17
- from claude_smart import env_config
18
- from claude_smart import runtime
17
+ from claude_smart import env_config, runtime
19
18
 
20
19
  _LOGGER = logging.getLogger(__name__)
21
20
 
@@ -174,8 +173,9 @@ class Adapter:
174
173
 
175
174
  Idempotent compare-then-write: reads ``Config``, only issues a
176
175
  ``set_config`` when the server-side values differ from the desired
177
- dict below. Called unconditionally from SessionStart; the caller's
178
- only escape hatch is ``CLAUDE_SMART_ENABLE_OPTIMIZER=0``.
176
+ dict below. SessionStart calls this only for local Reflexio URLs by
177
+ default; ``CLAUDE_SMART_ENABLE_OPTIMIZER=1`` forces hosted URLs, and
178
+ ``CLAUDE_SMART_ENABLE_OPTIMIZER=0`` disables it everywhere.
179
179
  """
180
180
  client = self._get_client()
181
181
  if client is None:
@@ -14,7 +14,8 @@ INTERNAL_ENV = "CLAUDE_SMART_INTERNAL"
14
14
 
15
15
  HOST_CLAUDE_CODE = "claude-code"
16
16
  HOST_CODEX = "codex"
17
- VALID_HOSTS = frozenset({HOST_CLAUDE_CODE, HOST_CODEX})
17
+ HOST_OPENCODE = "opencode"
18
+ VALID_HOSTS = frozenset({HOST_CLAUDE_CODE, HOST_CODEX, HOST_OPENCODE})
18
19
 
19
20
  _SHARED_AGENT_VERSION = "claude-code"
20
21
  _current_host: str | None = None
@@ -42,6 +43,11 @@ def is_codex() -> bool:
42
43
  return host() == HOST_CODEX
43
44
 
44
45
 
46
+ def is_opencode() -> bool:
47
+ """True when the current hook invocation came from OpenCode."""
48
+ return host() == HOST_OPENCODE
49
+
50
+
45
51
  def agent_version() -> str:
46
52
  """Reflexio agent version used for shared learning across hosts."""
47
53
  return _SHARED_AGENT_VERSION
package/plugin/uv.lock CHANGED
@@ -476,7 +476,7 @@ wheels = [
476
476
 
477
477
  [[package]]
478
478
  name = "claude-smart"
479
- version = "0.2.44"
479
+ version = "0.2.46"
480
480
  source = { editable = "." }
481
481
  dependencies = [
482
482
  { name = "chromadb" },