claude-smart 0.2.45 → 0.2.47

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 (353) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +47 -10
  3. package/bin/claude-smart.js +535 -23
  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 +27 -6
  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/layout.tsx +20 -0
  16. package/plugin/dashboard/app/preferences/[id]/page.tsx +8 -8
  17. package/plugin/dashboard/app/skills/project/[id]/page.tsx +7 -3
  18. package/plugin/dashboard/app/skills/shared/[id]/page.tsx +10 -3
  19. package/plugin/dashboard/lib/claude-settings-file.ts +20 -10
  20. package/plugin/dashboard/lib/reflexio-client.ts +16 -0
  21. package/plugin/dashboard/lib/status.ts +10 -3
  22. package/plugin/dashboard/lib/types.ts +18 -6
  23. package/plugin/hooks/codex-hooks.json +0 -1
  24. package/plugin/opencode/assistant-buffer.ts +108 -0
  25. package/plugin/opencode/dist/assistant-buffer.js +96 -0
  26. package/plugin/opencode/dist/internal.js +12 -0
  27. package/plugin/opencode/dist/payload.js +85 -0
  28. package/plugin/opencode/dist/server.mjs +232 -0
  29. package/plugin/opencode/internal.ts +18 -0
  30. package/plugin/opencode/package.json +3 -0
  31. package/plugin/opencode/payload.ts +90 -0
  32. package/plugin/opencode/server.mts +251 -0
  33. package/plugin/opencode/tsconfig.json +13 -0
  34. package/plugin/pyproject.toml +25 -4
  35. package/plugin/scripts/_lib.sh +5 -1
  36. package/plugin/scripts/backend-service.sh +22 -2
  37. package/plugin/scripts/ensure-plugin-root.sh +4 -4
  38. package/plugin/scripts/hook_entry.sh +1 -1
  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 +17 -9
  43. package/plugin/src/README.md +1 -1
  44. package/plugin/src/claude_smart/cli.py +498 -12
  45. package/plugin/src/claude_smart/context_format.py +9 -9
  46. package/plugin/src/claude_smart/cs_cite.py +66 -19
  47. package/plugin/src/claude_smart/env_config.py +12 -4
  48. package/plugin/src/claude_smart/events/session_start.py +26 -7
  49. package/plugin/src/claude_smart/events/stop.py +1 -1
  50. package/plugin/src/claude_smart/ids.py +1 -1
  51. package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
  52. package/plugin/src/claude_smart/runtime.py +7 -1
  53. package/plugin/uv.lock +5 -5
  54. package/plugin/vendor/reflexio/.env.example +54 -30
  55. package/plugin/vendor/reflexio/README.md +17 -11
  56. package/plugin/vendor/reflexio/pyproject.toml +13 -1
  57. package/plugin/vendor/reflexio/reflexio/README.md +4 -1
  58. package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
  59. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
  60. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
  63. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
  64. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +212 -52
  65. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
  66. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
  67. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
  68. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
  69. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
  70. package/plugin/vendor/reflexio/reflexio/cli/utils.py +44 -1
  71. package/plugin/vendor/reflexio/reflexio/client/client.py +154 -13
  72. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
  73. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
  74. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
  75. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
  145. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +246 -10
  146. package/plugin/vendor/reflexio/reflexio/lib/_base.py +15 -0
  147. package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
  148. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +17 -5
  149. package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
  150. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +224 -21
  151. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
  152. package/plugin/vendor/reflexio/reflexio/lib/_search.py +52 -25
  153. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +11 -1
  154. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +1 -0
  155. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
  156. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
  157. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/governance.py +117 -0
  158. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
  159. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
  160. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
  161. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +97 -3
  162. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
  163. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
  164. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +104 -7
  165. package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
  166. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
  167. package/plugin/vendor/reflexio/reflexio/server/README.md +58 -33
  168. package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
  169. package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
  170. package/plugin/vendor/reflexio/reflexio/server/api.py +899 -103
  171. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
  172. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +4 -2
  173. package/plugin/vendor/reflexio/reflexio/server/auth.py +90 -0
  174. package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
  175. package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
  176. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
  177. package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
  178. package/plugin/vendor/reflexio/reflexio/server/extensions.py +213 -0
  179. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
  180. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
  181. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
  182. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +4 -4
  183. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1 -1
  184. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
  185. package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
  186. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +12 -1
  187. package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
  188. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
  189. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
  190. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
  191. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
  192. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
  193. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
  194. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
  195. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
  196. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
  197. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
  198. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +278 -0
  199. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
  200. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
  201. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
  202. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
  203. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
  204. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
  205. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
  206. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
  207. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
  208. package/plugin/vendor/reflexio/reflexio/server/services/README.md +28 -11
  209. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
  210. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
  211. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
  212. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
  213. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
  214. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
  215. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
  216. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
  217. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
  218. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
  219. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
  220. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
  221. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
  222. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
  223. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
  224. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
  225. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
  226. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
  227. package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
  228. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
  229. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
  230. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
  231. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +47 -16
  232. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
  233. package/plugin/vendor/reflexio/reflexio/server/services/governance/config.py +52 -0
  234. package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +378 -0
  235. package/plugin/vendor/reflexio/reflexio/server/services/governance/subject_refs.py +34 -0
  236. package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
  237. package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +219 -0
  238. package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
  239. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
  240. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +18 -11
  241. package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_prompt_processing.py +100 -0
  242. package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
  243. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +334 -178
  244. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
  245. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
  246. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
  247. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
  248. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
  249. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
  250. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
  251. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
  252. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
  253. package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
  254. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
  255. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +31 -22
  256. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
  257. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
  258. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
  259. package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
  260. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
  261. package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
  262. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/recency.py +211 -0
  263. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +99 -6
  264. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
  265. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
  266. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
  267. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +31 -0
  268. package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +681 -0
  269. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
  270. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +16 -2
  271. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
  272. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +644 -197
  273. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +106 -119
  274. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +1965 -0
  275. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +630 -0
  276. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
  277. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +31 -1369
  278. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +756 -210
  279. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +148 -34
  280. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
  281. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
  282. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/__init__.py +13 -0
  283. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +952 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +189 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_optimization.py +247 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +145 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +838 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +150 -23
  289. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
  290. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +40 -57
  292. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_governance.py +148 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +4 -677
  296. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +134 -1
  297. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +62 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/__init__.py +13 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +365 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +124 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_optimization.py +85 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_source_linkage.py +47 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +333 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +372 -34
  311. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
  312. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
  313. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
  314. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
  315. package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
  316. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
  317. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
  318. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
  319. package/scripts/setup-claude-smart.sh +8 -3
  320. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
  321. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
  322. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
  323. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
  324. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
  325. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
  326. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
  327. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
  328. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
  329. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
  330. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
  331. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
  332. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
  333. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
  334. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
  335. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
  336. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
  337. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
  338. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
  339. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
  340. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
  341. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
  342. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
  343. package/plugin/vendor/reflexio/reflexio/server/_auth.py +0 -25
  344. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
  345. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
  346. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
  347. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
  348. /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
  349. /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
  350. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
  351. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
  352. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
  353. /package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_extractor.py → components/extractor.py} +0 -0
@@ -0,0 +1,251 @@
1
+ import { spawn } from "node:child_process"
2
+ import { existsSync, readFileSync, realpathSync } from "node:fs"
3
+ import { homedir } from "node:os"
4
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path"
5
+ import { fileURLToPath } from "node:url"
6
+
7
+ import { AssistantBuffer } from "./assistant-buffer.js"
8
+ import { sessionIDFrom } from "./internal.js"
9
+ import { chatMessagePayload, eventPayload, stopPayload, toolAfterPayload } from "./payload.js"
10
+
11
+ type HookResult = Record<string, unknown>
12
+
13
+ type PluginInput = {
14
+ directory: string
15
+ }
16
+
17
+ type EventInput = {
18
+ event: {
19
+ type?: string
20
+ properties?: Record<string, unknown>
21
+ }
22
+ }
23
+
24
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url))
25
+
26
+ function homeDir(): string {
27
+ return process.env.HOME || homedir()
28
+ }
29
+
30
+ function textFilePluginRoot(): string | undefined {
31
+ try {
32
+ return readFileSync(join(homeDir(), ".reflexio", "plugin-root.txt"), "utf8").trim() || undefined
33
+ } catch {
34
+ return undefined
35
+ }
36
+ }
37
+
38
+ function isPluginRoot(candidate: string | undefined): candidate is string {
39
+ return !!candidate
40
+ && existsSync(join(candidate, "pyproject.toml"))
41
+ && existsSync(join(candidate, "uv.lock"))
42
+ && existsSync(join(candidate, "scripts", "hook_entry.sh"))
43
+ }
44
+
45
+ function canonicalPluginRoot(candidate: string | undefined): string | undefined {
46
+ if (!isPluginRoot(candidate)) return undefined
47
+ try {
48
+ return realpathSync(candidate)
49
+ } catch {
50
+ return undefined
51
+ }
52
+ }
53
+
54
+ function pathParts(candidate: string): string[] {
55
+ return candidate.split(/[\\/]+/).filter(Boolean)
56
+ }
57
+
58
+ function isDescendantOrSame(child: string, parent: string): boolean {
59
+ const path = relative(parent, child)
60
+ return path === "" || (!path.startsWith("..") && !isAbsolute(path))
61
+ }
62
+
63
+ function isReflexioSessionCopy(candidate: string): boolean {
64
+ try {
65
+ const reflexioRoot = realpathSync(join(homeDir(), ".reflexio"))
66
+ return isDescendantOrSame(candidate, reflexioRoot)
67
+ } catch {
68
+ return false
69
+ }
70
+ }
71
+
72
+ function isTransientPackageRoot(candidate: string): boolean {
73
+ return pathParts(candidate).includes("_npx") || isReflexioSessionCopy(candidate)
74
+ }
75
+
76
+ function resolvePluginRoot(): string {
77
+ const current = resolve(MODULE_DIR, "../..")
78
+ const explicit = canonicalPluginRoot(process.env.CLAUDE_SMART_PLUGIN_ROOT)
79
+ if (explicit) return explicit
80
+
81
+ const currentRoot = canonicalPluginRoot(current)
82
+ if (currentRoot && !isTransientPackageRoot(currentRoot)) return currentRoot
83
+
84
+ const candidates = [
85
+ join(homeDir(), ".reflexio", "plugin-root"),
86
+ textFilePluginRoot(),
87
+ ]
88
+ for (const candidate of candidates) {
89
+ const root = canonicalPluginRoot(candidate)
90
+ if (root) return root
91
+ }
92
+ if (currentRoot) return currentRoot
93
+ try {
94
+ return realpathSync(current)
95
+ } catch {
96
+ return current
97
+ }
98
+ }
99
+
100
+ const PLUGIN_ROOT = resolvePluginRoot()
101
+ const SCRIPTS_DIR = resolve(PLUGIN_ROOT, "scripts")
102
+ const HOOK_ENTRY = resolve(SCRIPTS_DIR, "hook_entry.sh")
103
+ const BACKEND_SERVICE = resolve(SCRIPTS_DIR, "backend-service.sh")
104
+ const DASHBOARD_SERVICE = resolve(SCRIPTS_DIR, "dashboard-service.sh")
105
+
106
+ function contextFrom(result: HookResult): string {
107
+ const hookOutput = result.hookSpecificOutput
108
+ if (!hookOutput || typeof hookOutput !== "object") return ""
109
+ const additional = (hookOutput as Record<string, unknown>).additionalContext
110
+ return typeof additional === "string" ? additional : ""
111
+ }
112
+
113
+ function parseFirstJsonObject(text: string): HookResult {
114
+ for (const line of text.split(/\r?\n/)) {
115
+ const trimmed = line.trim()
116
+ if (!trimmed.startsWith("{")) continue
117
+ try {
118
+ const parsed = JSON.parse(trimmed)
119
+ if (parsed && typeof parsed === "object") return parsed as HookResult
120
+ } catch {
121
+ continue
122
+ }
123
+ }
124
+ return {}
125
+ }
126
+
127
+ function runScript(script: string, args: string[], payload?: Record<string, unknown>): Promise<HookResult> {
128
+ return new Promise((resolvePromise) => {
129
+ const child = spawn("bash", [script, ...args], {
130
+ cwd: PLUGIN_ROOT,
131
+ env: {
132
+ ...process.env,
133
+ CLAUDE_PLUGIN_ROOT: PLUGIN_ROOT,
134
+ CLAUDE_SMART_HOST: "opencode",
135
+ },
136
+ stdio: ["pipe", "pipe", "pipe"],
137
+ })
138
+ let stdout = ""
139
+ child.stdout.on("data", (chunk) => {
140
+ stdout += chunk.toString()
141
+ })
142
+ child.stderr.on("data", (chunk) => {
143
+ process.stderr.write(chunk)
144
+ })
145
+ child.stdin.on("error", () => {
146
+ // Hooks can exit before reading stdin on marker-gated setup failures.
147
+ })
148
+ child.on("error", () => resolvePromise({}))
149
+ child.on("close", () => resolvePromise(parseFirstJsonObject(stdout)))
150
+ try {
151
+ if (payload) child.stdin.write(JSON.stringify(payload))
152
+ child.stdin.end()
153
+ } catch {
154
+ resolvePromise({})
155
+ }
156
+ })
157
+ }
158
+
159
+ function runService(script: string, subcommand: string): Promise<void> {
160
+ return runScript(script, [subcommand]).then(() => undefined)
161
+ }
162
+
163
+ function cacheContext(cache: Map<string, string[]>, sessionID: string, result: HookResult): void {
164
+ const context = contextFrom(result)
165
+ if (!sessionID || !context) return
166
+ const pending = cache.get(sessionID) ?? []
167
+ pending.push(context)
168
+ cache.set(sessionID, pending)
169
+ }
170
+
171
+ async function server(input: PluginInput) {
172
+ const pendingContext = new Map<string, string[]>()
173
+ const activeSessions = new Set<string>()
174
+ const completedAssistantText = new Map<string, string>()
175
+ const assistant = new AssistantBuffer()
176
+ const cwd = input.directory
177
+
178
+ async function flushStop(sessionID: string): Promise<void> {
179
+ if (!sessionID || !activeSessions.has(sessionID)) return
180
+ activeSessions.delete(sessionID)
181
+ const text = assistant.text(sessionID) || completedAssistantText.get(sessionID) || ""
182
+ completedAssistantText.delete(sessionID)
183
+ await runScript(
184
+ HOOK_ENTRY,
185
+ ["opencode", "stop"],
186
+ stopPayload({ properties: { sessionID, info: { directory: cwd } } }, cwd, text),
187
+ )
188
+ assistant.clear(sessionID)
189
+ }
190
+
191
+ return {
192
+ event: async ({ event }: EventInput) => {
193
+ const type = event.type
194
+ assistant.update(event)
195
+ if (type === "session.created") {
196
+ const payload = eventPayload(event, cwd)
197
+ const sessionID = String(payload.session_id || "")
198
+ if (!sessionID) return
199
+ activeSessions.add(sessionID)
200
+ await runService(BACKEND_SERVICE, "start")
201
+ await runService(DASHBOARD_SERVICE, "start")
202
+ const result = await runScript(HOOK_ENTRY, ["opencode", "session-start"], payload)
203
+ cacheContext(pendingContext, sessionID, result)
204
+ return
205
+ }
206
+ if (type === "session.idle") {
207
+ const payload = eventPayload(event, cwd)
208
+ const sessionID = String(payload.session_id || "")
209
+ if (!sessionID) return
210
+ await flushStop(sessionID)
211
+ }
212
+ },
213
+ "chat.message": async (hookInput: Record<string, unknown>, output: Record<string, unknown>) => {
214
+ const payload = chatMessagePayload(hookInput, output, cwd)
215
+ if (!payload.session_id || !payload.prompt) return
216
+ activeSessions.add(String(payload.session_id || ""))
217
+ const result = await runScript(HOOK_ENTRY, ["opencode", "user-prompt"], payload)
218
+ cacheContext(pendingContext, String(payload.session_id || ""), result)
219
+ },
220
+ "experimental.chat.system.transform": async (hookInput: Record<string, unknown>, output: { system: string[] }) => {
221
+ const sessionID = sessionIDFrom(hookInput)
222
+ const pending = pendingContext.get(sessionID)
223
+ if (!pending?.length) return
224
+ output.system.push(...pending)
225
+ pendingContext.delete(sessionID)
226
+ },
227
+ "tool.execute.after": async (hookInput: Record<string, unknown>, output: Record<string, unknown>) => {
228
+ const payload = toolAfterPayload(hookInput, output, cwd)
229
+ if (!payload.session_id || !payload.tool_name) return
230
+ await runScript(HOOK_ENTRY, ["opencode", "post-tool"], payload)
231
+ },
232
+ "experimental.text.complete": async (
233
+ hookInput: { sessionID?: string },
234
+ output: { text?: string },
235
+ ) => {
236
+ const sessionID = typeof hookInput.sessionID === "string" ? hookInput.sessionID : ""
237
+ if (!sessionID) return
238
+ if (typeof output.text === "string") completedAssistantText.set(sessionID, output.text)
239
+ },
240
+ dispose: async () => {
241
+ await Promise.all([...activeSessions].map((sessionID) => flushStop(sessionID)))
242
+ await runService(DASHBOARD_SERVICE, "session-end")
243
+ await runService(BACKEND_SERVICE, "session-end")
244
+ },
245
+ }
246
+ }
247
+
248
+ export default {
249
+ id: "claude-smart",
250
+ server,
251
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "rootDir": ".",
10
+ "outDir": "dist"
11
+ },
12
+ "include": ["*.ts", "*.mts"]
13
+ }
@@ -1,7 +1,24 @@
1
1
  [project]
2
2
  name = "claude-smart"
3
- version = "0.2.45"
4
- description = "Self-improving Claude Code and Codex plugin that turns corrections into Preferences, Project-specific skills, and Shared skills"
3
+ version = "0.2.47"
4
+ description = "Self-improving Claude Code, Codex, and OpenCode plugin that turns corrections into Preferences, Project-specific skills, and Shared skills"
5
+ keywords = [
6
+ "claude",
7
+ "claude-code",
8
+ "claude-code-plugin",
9
+ "codex",
10
+ "codex-plugin",
11
+ "opencode",
12
+ "opencode-plugin",
13
+ "memory",
14
+ "agent-memory",
15
+ "plugin",
16
+ "reflexio",
17
+ "self-improvement",
18
+ "self-improving-agents",
19
+ "skills",
20
+ "learning",
21
+ ]
5
22
  readme = "README.md"
6
23
  requires-python = ">=3.12"
7
24
  dependencies = [
@@ -9,7 +26,7 @@ dependencies = [
9
26
  # normal installs; vendor releases may override it after uv sync by
10
27
  # installing plugin/vendor/reflexio. Keep in sync via
11
28
  # scripts/sync-reflexio-dep.py.
12
- "reflexio-ai>=0.2.25",
29
+ "reflexio-ai>=0.2.27",
13
30
  # Needed when Reflexio runs the local embedding provider (ONNXMiniLM_L6_V2).
14
31
  # Pulls in onnxruntime + tokenizers; the ~80 MB ONNX model itself is
15
32
  # downloaded on first use, not at install time.
@@ -21,9 +38,13 @@ dependencies = [
21
38
  "sqlite-vec>=0.1.6",
22
39
  ]
23
40
 
41
+ # claude-smart is distributed via npm only (see bin/claude-smart.js); it is not
42
+ # published to PyPI, so there is no `claude-smart` console script / uvx entry
43
+ # point. These two scripts are resolved by the runtime from the plugin venv
44
+ # (session_start.py locates claude-smart-optimizer-assistant; the hook is invoked
45
+ # via `python -m claude_smart.hook`), so they stay.
24
46
  [project.scripts]
25
47
  claude-smart-hook = "claude_smart.hook:main"
26
- claude-smart = "claude_smart.cli:main"
27
48
  claude-smart-optimizer-assistant = "claude_smart.optimizer_assistant:main"
28
49
 
29
50
  [build-system]
@@ -87,8 +87,12 @@ claude_smart_env_unquote() {
87
87
  }
88
88
 
89
89
  claude_smart_source_reflexio_env() {
90
+ # claude-smart's env lives at ~/.claude-smart/.env (kept separate from the OSS
91
+ # reflexio default ~/.reflexio/.env). Stays in sync with
92
+ # env_config.REFLEXIO_ENV_PATH and the REFLEXIO_ENV_FILE export in
93
+ # backend-service.sh.
90
94
  local env_file line key value
91
- env_file="$HOME/.reflexio/.env"
95
+ env_file="$HOME/.claude-smart/.env"
92
96
  [ -f "$env_file" ] || return 0
93
97
  while IFS= read -r line || [ -n "$line" ]; do
94
98
  line="${line#"${line%%[![:space:]]*}"}"
@@ -34,6 +34,21 @@ EMBEDDING_PORT="${EMBEDDING_PORT:-8072}"
34
34
  export BACKEND_PORT="$PORT"
35
35
  export EMBEDDING_PORT
36
36
 
37
+ # Run claude-smart's backend under its own org id. The reflexio no-auth resolver
38
+ # reads REFLEXIO_DEFAULT_ORG_ID, which scopes the request org -> config file
39
+ # name (config_<org>.json) and SQLite data. Hard-set (not :-defaulted) so a
40
+ # value in the shared ~/.reflexio/.env can't drag claude-smart back onto
41
+ # "self-host-org" and collide with the enterprise self-host backend over
42
+ # config_self-host-org.json. Must stay in sync with cli.py's config path.
43
+ export REFLEXIO_DEFAULT_ORG_ID="claude-smart"
44
+
45
+ # Load claude-smart's env from ~/.claude-smart/.env instead of the reflexio
46
+ # default ~/.reflexio/.env, so an OSS reflexio backend's .env on this machine
47
+ # can't leak in. The data dir is independent (LOCAL_STORAGE_PATH), so both still
48
+ # share ~/.reflexio/data. Must stay in sync with env_config.REFLEXIO_ENV_PATH and
49
+ # the source path in _lib.sh (claude_smart_source_reflexio_env).
50
+ export REFLEXIO_ENV_FILE="$HOME/.claude-smart/.env"
51
+
37
52
  # Default: route extraction through the active host CLI + ONNX embedder
38
53
  # so claude-smart works without any LLM API key. Users can opt out by
39
54
  # pre-exporting these to 0.
@@ -50,7 +65,12 @@ PLUGIN_ROOT="$(cd "$HERE/.." && pwd)"
50
65
  claude_smart_reexec_stable_plugin_root_if_needed "$PLUGIN_ROOT" "backend-service.sh" "$@"
51
66
 
52
67
  if [ -z "${CLAUDE_SMART_CLI_PATH:-}" ]; then
53
- if [ "${CLAUDE_SMART_HOST:-claude-code}" = "codex" ]; then
68
+ if [ "${CLAUDE_SMART_HOST:-claude-code}" = "opencode" ] && command -v opencode >/dev/null 2>&1; then
69
+ # Preserve Reflexio's Claude CLI provider contract while routing
70
+ # generation through the user's authenticated OpenCode setup.
71
+ claude_smart_prepend_node_bins
72
+ export CLAUDE_SMART_CLI_PATH="$PLUGIN_ROOT/scripts/opencode-claude-compat"
73
+ elif [ "${CLAUDE_SMART_HOST:-claude-code}" = "codex" ]; then
54
74
  # Reflexio's provider still calls CLAUDE_SMART_CLI_PATH with Claude CLI
55
75
  # flags. Use a small compatibility executable that translates that narrow
56
76
  # contract to `codex exec`.
@@ -286,7 +306,7 @@ case "$CMD" in
286
306
  # Keep plugin runtime data in ~/.reflexio even when the backend imports
287
307
  # Reflexio from an editable checkout inside a larger repo with its own
288
308
  # .env. python-dotenv respects pre-existing env vars, so this prevents a
289
- # parent REFLEXIO_LOG_DIR from sending claude-smart to enterprise configs.
309
+ # parent REFLEXIO_LOG_DIR from sending claude-smart to unrelated configs.
290
310
  export REFLEXIO_LOG_DIR="${REFLEXIO_LOG_DIR:-$HOME}"
291
311
 
292
312
  # Force sqlite: the plugin venv ships only the open-source reflexio
@@ -32,12 +32,12 @@ if [ "$FORCE" = "--force" ]; then
32
32
  fi
33
33
 
34
34
  # Opt-in: when CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=1 (set in the
35
- # environment or in ~/.reflexio/.env), always relink to $TARGET so the
35
+ # environment or in ~/.claude-smart/.env), always relink to $TARGET so the
36
36
  # symlink tracks the currently loaded plugin.
37
37
  FOLLOW="${CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION:-}"
38
- if [ -z "$FOLLOW" ] && [ -f "$HOME/.reflexio/.env" ]; then
39
- FOLLOW="$(grep -E '^CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=' "$HOME/.reflexio/.env" \
40
- | tail -n1 | cut -d= -f2-)"
38
+ if [ -z "$FOLLOW" ] && [ -f "$HOME/.claude-smart/.env" ]; then
39
+ FOLLOW="$(grep -E '^(export[[:space:]]+)?CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=' "$HOME/.claude-smart/.env" \
40
+ | tail -n1 | sed -E 's/^(export[[:space:]]+)?CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=//')"
41
41
  # Strip a single pair of surrounding double or single quotes, if present.
42
42
  FOLLOW="${FOLLOW#\"}"; FOLLOW="${FOLLOW%\"}"
43
43
  FOLLOW="${FOLLOW#\'}"; FOLLOW="${FOLLOW%\'}"
@@ -15,7 +15,7 @@ set -eu
15
15
  HOST="claude-code"
16
16
  EVENT="${1:-}"
17
17
  case "$EVENT" in
18
- claude-code|codex)
18
+ claude-code|codex|opencode)
19
19
  HOST="$EVENT"
20
20
  EVENT="${2:-}"
21
21
  ;;
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+ SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)/"
4
+ exec node "$SCRIPT_DIR/opencode-claude-compat.js" "$@"
@@ -0,0 +1,3 @@
1
+ @echo off
2
+ set SCRIPT_DIR=%~dp0
3
+ node "%SCRIPT_DIR%opencode-claude-compat.js" %*
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /*
5
+ * Translate Reflexio's Claude CLI provider contract to `opencode run`.
6
+ *
7
+ * Reflexio shells out to CLAUDE_SMART_CLI_PATH as if it were Claude Code:
8
+ *
9
+ * <path> -p --output-format stream-json --model <model> ...
10
+ *
11
+ * Under OpenCode, this bridge preserves that executable contract while routing
12
+ * generation through the user's authenticated OpenCode CLI/provider setup.
13
+ */
14
+
15
+ const { spawnSync } = require("node:child_process");
16
+ const fs = require("node:fs");
17
+ const os = require("node:os");
18
+ const path = require("node:path");
19
+
20
+ const DEFAULT_TIMEOUT_MS = 120_000;
21
+ const AGENT_NAME = "claude-smart-extractor";
22
+
23
+ function main(argv) {
24
+ let workDir = null;
25
+ try {
26
+ const { outputFormat, systemPrompt, model } = parseSupportedArgs(argv);
27
+ const prompt = fs.readFileSync(0, "utf8");
28
+ workDir = prepareWorkDir();
29
+ const content = runOpenCode({
30
+ prompt: combinedPrompt({ prompt, systemPrompt }),
31
+ model,
32
+ workDir,
33
+ });
34
+ const payload =
35
+ outputFormat === "stream-json"
36
+ ? { type: "result", subtype: "success", result: content }
37
+ : { result: content };
38
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
39
+ return 0;
40
+ } catch (error) {
41
+ const message = error instanceof Error ? error.message : String(error);
42
+ process.stderr.write(`opencode-claude-compat: ${message}\n`);
43
+ return 1;
44
+ } finally {
45
+ if (workDir) {
46
+ try {
47
+ fs.rmSync(workDir, { recursive: true, force: true });
48
+ } catch {
49
+ // Best effort cleanup only.
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ function parseSupportedArgs(argv) {
56
+ let outputFormat = "json";
57
+ let systemPrompt = "";
58
+ let model = "";
59
+ let idx = 0;
60
+ while (idx < argv.length) {
61
+ const arg = argv[idx];
62
+ if (arg === "-p") {
63
+ idx += 1;
64
+ } else if (arg === "--output-format") {
65
+ outputFormat = requireValue(argv, idx, arg);
66
+ idx += 2;
67
+ } else if (arg === "--model") {
68
+ model = requireValue(argv, idx, arg);
69
+ idx += 2;
70
+ } else if (arg === "--verbose" || arg === "--include-partial-messages") {
71
+ idx += 1;
72
+ } else if (arg === "--append-system-prompt") {
73
+ systemPrompt = requireValue(argv, idx, arg);
74
+ idx += 2;
75
+ } else {
76
+ throw new Error(`unsupported Claude CLI argument: ${arg}`);
77
+ }
78
+ }
79
+ if (outputFormat !== "json" && outputFormat !== "stream-json") {
80
+ throw new Error(`unsupported --output-format: ${outputFormat}`);
81
+ }
82
+ return { outputFormat, systemPrompt, model };
83
+ }
84
+
85
+ function requireValue(argv, idx, name) {
86
+ if (idx + 1 >= argv.length) {
87
+ throw new Error(`${name} requires a value`);
88
+ }
89
+ return argv[idx + 1];
90
+ }
91
+
92
+ function prepareWorkDir() {
93
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "claude-smart-opencode-"));
94
+ const config = {
95
+ agent: {
96
+ [AGENT_NAME]: {
97
+ description: "Internal claude-smart learning extraction",
98
+ prompt:
99
+ "You are running as an internal claude-smart extraction subprocess. " +
100
+ "Return only the requested text or JSON. Do not use tools, edit files, " +
101
+ "search the workspace, or ask follow-up questions.",
102
+ steps: 2,
103
+ permission: "deny",
104
+ },
105
+ },
106
+ };
107
+ const opencodeDir = path.join(dir, ".opencode");
108
+ fs.mkdirSync(opencodeDir, { recursive: true });
109
+ fs.writeFileSync(path.join(opencodeDir, "opencode.json"), `${JSON.stringify(config, null, 2)}\n`);
110
+ return dir;
111
+ }
112
+
113
+ function runOpenCode({ prompt, model, workDir }) {
114
+ const opencodePath = process.env.CLAUDE_SMART_OPENCODE_PATH || commandPath(opencodeNames());
115
+ if (!opencodePath) {
116
+ throw new Error("opencode CLI not found on PATH");
117
+ }
118
+
119
+ const args = [
120
+ "run",
121
+ "--pure",
122
+ "--format",
123
+ "json",
124
+ "--agent",
125
+ AGENT_NAME,
126
+ "--dir",
127
+ workDir,
128
+ ];
129
+ const selectedModel = opencodeModel(model);
130
+ if (selectedModel) {
131
+ args.push("--model", selectedModel);
132
+ }
133
+ const variant = (process.env.CLAUDE_SMART_OPENCODE_VARIANT || "").trim();
134
+ if (variant) {
135
+ args.push("--variant", variant);
136
+ }
137
+
138
+ const proc = spawnSync(opencodePath, args, {
139
+ input: prompt,
140
+ cwd: workDir,
141
+ encoding: "utf8",
142
+ env: {
143
+ ...process.env,
144
+ CLAUDE_SMART_HOST: "opencode",
145
+ CLAUDE_SMART_INTERNAL: "1",
146
+ CLAUDE_CODE_ENTRYPOINT: "optimizer",
147
+ },
148
+ timeout: timeoutMs(),
149
+ windowsHide: true,
150
+ shell: process.platform === "win32" && /\.(?:cmd|bat)$/i.test(opencodePath),
151
+ });
152
+ if (proc.error) {
153
+ if (proc.error.code === "ETIMEDOUT") {
154
+ throw new Error(`opencode CLI timed out after ${timeoutMs() / 1000}s`);
155
+ }
156
+ throw proc.error;
157
+ }
158
+ if (proc.status !== 0) {
159
+ const stderr = String(proc.stderr || "").trim().slice(0, 500);
160
+ throw new Error(`opencode CLI exited ${proc.status}: ${stderr}`);
161
+ }
162
+ const content = parseOpenCodeJson(proc.stdout);
163
+ if (!content) {
164
+ throw new Error("opencode CLI returned empty output");
165
+ }
166
+ return content;
167
+ }
168
+
169
+ function opencodeModel(modelFromArgs) {
170
+ const explicit = (process.env.CLAUDE_SMART_OPENCODE_MODEL || "").trim();
171
+ if (explicit) return explicit;
172
+ const candidate = (modelFromArgs || "").trim();
173
+ return candidate.includes("/") ? candidate : "";
174
+ }
175
+
176
+ function parseOpenCodeJson(stdout) {
177
+ const chunks = [];
178
+ for (const line of String(stdout || "").split(/\r?\n/)) {
179
+ const trimmed = line.trim();
180
+ if (!trimmed) continue;
181
+ let event;
182
+ try {
183
+ event = JSON.parse(trimmed);
184
+ } catch {
185
+ continue;
186
+ }
187
+ const part = event && typeof event === "object" ? event.part : null;
188
+ if (part && part.type === "text" && typeof part.text === "string") {
189
+ chunks.push(part.text);
190
+ } else if (event.type === "text" && typeof event.text === "string") {
191
+ chunks.push(event.text);
192
+ } else if (event.type === "result" && typeof event.result === "string") {
193
+ chunks.push(event.result);
194
+ }
195
+ }
196
+ return chunks.join("").trim();
197
+ }
198
+
199
+ function timeoutMs() {
200
+ const raw = Number(process.env.CLAUDE_SMART_CLI_TIMEOUT || "");
201
+ if (Number.isFinite(raw) && raw > 0) return raw * 1000;
202
+ return DEFAULT_TIMEOUT_MS;
203
+ }
204
+
205
+ function opencodeNames() {
206
+ return process.platform === "win32" ? ["opencode.cmd", "opencode.exe", "opencode"] : ["opencode"];
207
+ }
208
+
209
+ function commandPath(names) {
210
+ const pathParts = (process.env.PATH || "").split(path.delimiter).filter(Boolean);
211
+ for (const dir of pathParts) {
212
+ for (const name of names) {
213
+ const candidate = path.join(dir, name);
214
+ if (fs.existsSync(candidate)) return candidate;
215
+ }
216
+ }
217
+ return null;
218
+ }
219
+
220
+ function combinedPrompt({ prompt, systemPrompt }) {
221
+ if (!systemPrompt) return prompt;
222
+ return `${systemPrompt}\n\n## Task\n${prompt}`;
223
+ }
224
+
225
+ process.exitCode = main(process.argv.slice(2));