claude-smart 0.2.45 → 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 (322) 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 +5 -1
  35. package/plugin/scripts/backend-service.sh +22 -2
  36. package/plugin/scripts/ensure-plugin-root.sh +4 -4
  37. package/plugin/scripts/hook_entry.sh +1 -1
  38. package/plugin/scripts/opencode-claude-compat +4 -0
  39. package/plugin/scripts/opencode-claude-compat.cmd +3 -0
  40. package/plugin/scripts/opencode-claude-compat.js +225 -0
  41. package/plugin/scripts/smart-install.sh +10 -8
  42. package/plugin/src/README.md +1 -1
  43. package/plugin/src/claude_smart/cli.py +304 -6
  44. package/plugin/src/claude_smart/env_config.py +12 -4
  45. package/plugin/src/claude_smart/events/session_start.py +26 -7
  46. package/plugin/src/claude_smart/events/stop.py +1 -1
  47. package/plugin/src/claude_smart/ids.py +1 -1
  48. package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
  49. package/plugin/src/claude_smart/runtime.py +7 -1
  50. package/plugin/uv.lock +1 -1
  51. package/plugin/vendor/reflexio/.env.example +54 -30
  52. package/plugin/vendor/reflexio/README.md +14 -8
  53. package/plugin/vendor/reflexio/pyproject.toml +13 -1
  54. package/plugin/vendor/reflexio/reflexio/README.md +1 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
  56. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
  57. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +210 -50
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
  63. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
  64. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
  65. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
  66. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
  67. package/plugin/vendor/reflexio/reflexio/client/client.py +57 -13
  68. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
  69. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
  70. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
  71. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
  72. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
  73. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
  74. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
  75. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
  141. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +238 -10
  142. package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
  143. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +16 -5
  144. package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
  145. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +198 -6
  146. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
  147. package/plugin/vendor/reflexio/reflexio/lib/_search.py +29 -20
  148. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +2 -1
  149. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
  150. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
  151. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
  152. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
  153. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
  154. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +52 -0
  155. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
  156. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
  157. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +88 -7
  158. package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
  159. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
  160. package/plugin/vendor/reflexio/reflexio/server/README.md +45 -32
  161. package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
  162. package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
  163. package/plugin/vendor/reflexio/reflexio/server/_auth.py +65 -2
  164. package/plugin/vendor/reflexio/reflexio/server/api.py +734 -85
  165. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
  166. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +3 -1
  167. package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
  168. package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
  169. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
  170. package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
  171. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
  172. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
  173. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
  174. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
  175. package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
  176. package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
  177. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
  178. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
  179. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
  180. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
  181. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
  182. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
  183. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
  184. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
  185. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
  186. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
  187. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +266 -0
  188. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
  189. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
  190. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
  191. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
  192. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
  193. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
  194. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
  195. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
  196. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
  197. package/plugin/vendor/reflexio/reflexio/server/services/README.md +26 -11
  198. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
  199. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
  200. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
  201. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
  202. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
  203. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
  204. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
  205. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
  206. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
  207. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
  208. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
  209. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
  210. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
  211. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
  212. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
  213. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
  214. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
  215. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
  216. package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
  217. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
  218. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
  219. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
  220. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +39 -16
  221. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
  222. package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
  223. package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +193 -0
  224. package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
  225. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
  226. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +11 -12
  227. package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
  228. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +316 -178
  229. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
  230. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
  231. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
  232. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
  233. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
  234. package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +84 -0
  235. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
  236. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
  237. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
  238. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
  239. package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
  240. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
  241. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +30 -22
  242. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
  243. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
  244. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
  245. package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
  246. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
  247. package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
  248. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +83 -6
  249. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
  250. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
  251. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
  252. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +27 -0
  253. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
  254. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
  255. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
  256. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +642 -197
  257. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +61 -104
  258. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +628 -0
  259. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
  260. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +978 -184
  261. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +519 -128
  262. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +77 -3
  263. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
  264. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
  265. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +131 -20
  266. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
  267. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
  268. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +36 -53
  269. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
  270. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
  271. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +243 -7
  272. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +121 -1
  273. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +60 -0
  274. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
  275. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
  276. package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
  277. package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
  278. package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
  279. package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +229 -32
  281. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
  282. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
  283. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
  284. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
  285. package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
  286. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
  287. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
  288. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
  289. package/scripts/setup-claude-smart.sh +8 -3
  290. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
  291. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
  292. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
  293. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
  294. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
  295. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
  296. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
  297. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
  298. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
  299. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
  300. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
  301. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
  302. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
  303. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
  304. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
  305. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
  306. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
  307. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
  308. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
  309. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
  310. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
  311. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
  312. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
  313. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
  317. /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
  318. /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
  319. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
  320. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
  321. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
  322. /package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_extractor.py → components/extractor.py} +0 -0
@@ -0,0 +1,12 @@
1
+ export function isRecord(value) {
2
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3
+ }
4
+ export function eventProperties(event) {
5
+ return isRecord(event.properties) ? event.properties : event;
6
+ }
7
+ export function sessionIDFrom(value) {
8
+ if (!isRecord(value))
9
+ return "";
10
+ const raw = value.sessionID ?? value.session_id;
11
+ return typeof raw === "string" ? raw : "";
12
+ }
@@ -0,0 +1,85 @@
1
+ import { eventProperties, isRecord, sessionIDFrom } from "./internal.js";
2
+ function textFromParts(parts) {
3
+ if (!Array.isArray(parts))
4
+ return "";
5
+ return parts
6
+ .map((part) => (part && part.type === "text" && typeof part.text === "string" ? part.text : ""))
7
+ .filter(Boolean)
8
+ .join("\n\n");
9
+ }
10
+ export function eventPayload(event, cwd) {
11
+ const properties = eventProperties(event);
12
+ const info = isRecord(properties.info) ? properties.info : {};
13
+ return {
14
+ session_id: sessionIDFrom(properties) || sessionIDFrom(info),
15
+ cwd: typeof info.directory === "string" ? info.directory : cwd,
16
+ };
17
+ }
18
+ export function chatMessagePayload(input, output, cwd) {
19
+ const message = isRecord(output.message) ? output.message : {};
20
+ const prompt = textFromParts(output.parts) ||
21
+ (typeof message.content === "string" ? message.content : "") ||
22
+ textFromParts(message.parts);
23
+ return {
24
+ session_id: sessionIDFrom(input),
25
+ cwd,
26
+ prompt,
27
+ };
28
+ }
29
+ export function normalizeToolName(tool) {
30
+ const lowered = tool.toLowerCase();
31
+ if (lowered === "edit")
32
+ return "Edit";
33
+ if (lowered === "write")
34
+ return "Write";
35
+ if (lowered === "apply_patch")
36
+ return "apply_patch";
37
+ if (["bash", "shell", "terminal", "exec", "command"].includes(lowered))
38
+ return "Bash";
39
+ return tool;
40
+ }
41
+ export function normalizeToolInput(tool, args) {
42
+ if (!isRecord(args))
43
+ return {};
44
+ const out = { ...args };
45
+ const copy = (from, to) => {
46
+ if (from in args && !(to in out))
47
+ out[to] = args[from];
48
+ };
49
+ copy("filePath", "file_path");
50
+ copy("oldString", "old_string");
51
+ copy("newString", "new_string");
52
+ copy("patchText", "command");
53
+ if (normalizeToolName(tool) === "Bash") {
54
+ copy("cmd", "command");
55
+ copy("script", "command");
56
+ }
57
+ return out;
58
+ }
59
+ export function toolAfterPayload(input, output, cwd) {
60
+ const tool = typeof input.tool === "string" ? input.tool : "";
61
+ const text = typeof output.output === "string" ? output.output : "";
62
+ const response = {
63
+ output: text,
64
+ stdout: text,
65
+ };
66
+ if (typeof output.title === "string")
67
+ response.title = output.title;
68
+ if (isRecord(output.metadata))
69
+ response.metadata = output.metadata;
70
+ if (isRecord(output.metadata) && output.metadata.error)
71
+ response.error = output.metadata.error;
72
+ return {
73
+ session_id: sessionIDFrom(input),
74
+ cwd,
75
+ tool_name: normalizeToolName(tool),
76
+ tool_input: normalizeToolInput(tool, input.args),
77
+ tool_response: response,
78
+ };
79
+ }
80
+ export function stopPayload(event, cwd, lastAssistantMessage) {
81
+ return {
82
+ ...eventPayload(event, cwd),
83
+ last_assistant_message: lastAssistantMessage,
84
+ };
85
+ }
@@ -0,0 +1,158 @@
1
+ import { spawn } from "node:child_process";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { AssistantBuffer } from "./assistant-buffer.js";
5
+ import { sessionIDFrom } from "./internal.js";
6
+ import { chatMessagePayload, eventPayload, stopPayload, toolAfterPayload } from "./payload.js";
7
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
8
+ const PLUGIN_ROOT = resolve(MODULE_DIR, "../..");
9
+ const SCRIPTS_DIR = resolve(PLUGIN_ROOT, "scripts");
10
+ const HOOK_ENTRY = resolve(SCRIPTS_DIR, "hook_entry.sh");
11
+ const BACKEND_SERVICE = resolve(SCRIPTS_DIR, "backend-service.sh");
12
+ const DASHBOARD_SERVICE = resolve(SCRIPTS_DIR, "dashboard-service.sh");
13
+ function contextFrom(result) {
14
+ const hookOutput = result.hookSpecificOutput;
15
+ if (!hookOutput || typeof hookOutput !== "object")
16
+ return "";
17
+ const additional = hookOutput.additionalContext;
18
+ return typeof additional === "string" ? additional : "";
19
+ }
20
+ function parseFirstJsonObject(text) {
21
+ for (const line of text.split(/\r?\n/)) {
22
+ const trimmed = line.trim();
23
+ if (!trimmed.startsWith("{"))
24
+ continue;
25
+ try {
26
+ const parsed = JSON.parse(trimmed);
27
+ if (parsed && typeof parsed === "object")
28
+ return parsed;
29
+ }
30
+ catch {
31
+ continue;
32
+ }
33
+ }
34
+ return {};
35
+ }
36
+ function runScript(script, args, payload) {
37
+ return new Promise((resolvePromise) => {
38
+ const child = spawn("bash", [script, ...args], {
39
+ cwd: PLUGIN_ROOT,
40
+ env: {
41
+ ...process.env,
42
+ CLAUDE_PLUGIN_ROOT: PLUGIN_ROOT,
43
+ CLAUDE_SMART_HOST: "opencode",
44
+ },
45
+ stdio: ["pipe", "pipe", "pipe"],
46
+ });
47
+ let stdout = "";
48
+ child.stdout.on("data", (chunk) => {
49
+ stdout += chunk.toString();
50
+ });
51
+ child.stderr.on("data", (chunk) => {
52
+ process.stderr.write(chunk);
53
+ });
54
+ child.stdin.on("error", () => {
55
+ // Hooks can exit before reading stdin on marker-gated setup failures.
56
+ });
57
+ child.on("error", () => resolvePromise({}));
58
+ child.on("close", () => resolvePromise(parseFirstJsonObject(stdout)));
59
+ try {
60
+ if (payload)
61
+ child.stdin.write(JSON.stringify(payload));
62
+ child.stdin.end();
63
+ }
64
+ catch {
65
+ resolvePromise({});
66
+ }
67
+ });
68
+ }
69
+ function runService(script, subcommand) {
70
+ return runScript(script, [subcommand]).then(() => undefined);
71
+ }
72
+ function cacheContext(cache, sessionID, result) {
73
+ const context = contextFrom(result);
74
+ if (!sessionID || !context)
75
+ return;
76
+ const pending = cache.get(sessionID) ?? [];
77
+ pending.push(context);
78
+ cache.set(sessionID, pending);
79
+ }
80
+ async function server(input) {
81
+ const pendingContext = new Map();
82
+ const activeSessions = new Set();
83
+ const completedAssistantText = new Map();
84
+ const assistant = new AssistantBuffer();
85
+ const cwd = input.directory;
86
+ async function flushStop(sessionID) {
87
+ if (!sessionID || !activeSessions.has(sessionID))
88
+ return;
89
+ activeSessions.delete(sessionID);
90
+ const text = assistant.text(sessionID) || completedAssistantText.get(sessionID) || "";
91
+ completedAssistantText.delete(sessionID);
92
+ await runScript(HOOK_ENTRY, ["opencode", "stop"], stopPayload({ properties: { sessionID, info: { directory: cwd } } }, cwd, text));
93
+ assistant.clear(sessionID);
94
+ }
95
+ return {
96
+ event: async ({ event }) => {
97
+ const type = event.type;
98
+ assistant.update(event);
99
+ if (type === "session.created") {
100
+ const payload = eventPayload(event, cwd);
101
+ const sessionID = String(payload.session_id || "");
102
+ if (!sessionID)
103
+ return;
104
+ activeSessions.add(sessionID);
105
+ await runService(BACKEND_SERVICE, "start");
106
+ await runService(DASHBOARD_SERVICE, "start");
107
+ const result = await runScript(HOOK_ENTRY, ["opencode", "session-start"], payload);
108
+ cacheContext(pendingContext, sessionID, result);
109
+ return;
110
+ }
111
+ if (type === "session.idle") {
112
+ const payload = eventPayload(event, cwd);
113
+ const sessionID = String(payload.session_id || "");
114
+ if (!sessionID)
115
+ return;
116
+ await flushStop(sessionID);
117
+ }
118
+ },
119
+ "chat.message": async (hookInput, output) => {
120
+ const payload = chatMessagePayload(hookInput, output, cwd);
121
+ if (!payload.session_id || !payload.prompt)
122
+ return;
123
+ activeSessions.add(String(payload.session_id || ""));
124
+ const result = await runScript(HOOK_ENTRY, ["opencode", "user-prompt"], payload);
125
+ cacheContext(pendingContext, String(payload.session_id || ""), result);
126
+ },
127
+ "experimental.chat.system.transform": async (hookInput, output) => {
128
+ const sessionID = sessionIDFrom(hookInput);
129
+ const pending = pendingContext.get(sessionID);
130
+ if (!pending?.length)
131
+ return;
132
+ output.system.push(...pending);
133
+ pendingContext.delete(sessionID);
134
+ },
135
+ "tool.execute.after": async (hookInput, output) => {
136
+ const payload = toolAfterPayload(hookInput, output, cwd);
137
+ if (!payload.session_id || !payload.tool_name)
138
+ return;
139
+ await runScript(HOOK_ENTRY, ["opencode", "post-tool"], payload);
140
+ },
141
+ "experimental.text.complete": async (hookInput, output) => {
142
+ const sessionID = typeof hookInput.sessionID === "string" ? hookInput.sessionID : "";
143
+ if (!sessionID)
144
+ return;
145
+ if (typeof output.text === "string")
146
+ completedAssistantText.set(sessionID, output.text);
147
+ },
148
+ dispose: async () => {
149
+ await Promise.all([...activeSessions].map((sessionID) => flushStop(sessionID)));
150
+ await runService(DASHBOARD_SERVICE, "session-end");
151
+ await runService(BACKEND_SERVICE, "session-end");
152
+ },
153
+ };
154
+ }
155
+ export default {
156
+ id: "claude-smart",
157
+ server,
158
+ };
@@ -0,0 +1,18 @@
1
+ export type EventLike = {
2
+ type?: string
3
+ properties?: Record<string, unknown>
4
+ }
5
+
6
+ export function isRecord(value: unknown): value is Record<string, unknown> {
7
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value)
8
+ }
9
+
10
+ export function eventProperties(event: EventLike): Record<string, unknown> {
11
+ return isRecord(event.properties) ? event.properties : (event as Record<string, unknown>)
12
+ }
13
+
14
+ export function sessionIDFrom(value: unknown): string {
15
+ if (!isRecord(value)) return ""
16
+ const raw = value.sessionID ?? value.session_id
17
+ return typeof raw === "string" ? raw : ""
18
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,90 @@
1
+ import { eventProperties, type EventLike, isRecord, sessionIDFrom } from "./internal.js"
2
+
3
+ type PartLike = {
4
+ type?: string
5
+ text?: string
6
+ }
7
+
8
+ export type PythonPayload = Record<string, unknown>
9
+
10
+ function textFromParts(parts: unknown): string {
11
+ if (!Array.isArray(parts)) return ""
12
+ return parts
13
+ .map((part: PartLike) => (part && part.type === "text" && typeof part.text === "string" ? part.text : ""))
14
+ .filter(Boolean)
15
+ .join("\n\n")
16
+ }
17
+
18
+ export function eventPayload(event: EventLike, cwd: string): PythonPayload {
19
+ const properties = eventProperties(event)
20
+ const info = isRecord(properties.info) ? properties.info : {}
21
+ return {
22
+ session_id: sessionIDFrom(properties) || sessionIDFrom(info),
23
+ cwd: typeof info.directory === "string" ? info.directory : cwd,
24
+ }
25
+ }
26
+
27
+ export function chatMessagePayload(input: Record<string, unknown>, output: Record<string, unknown>, cwd: string): PythonPayload {
28
+ const message = isRecord(output.message) ? output.message : {}
29
+ const prompt =
30
+ textFromParts(output.parts) ||
31
+ (typeof message.content === "string" ? message.content : "") ||
32
+ textFromParts(message.parts)
33
+ return {
34
+ session_id: sessionIDFrom(input),
35
+ cwd,
36
+ prompt,
37
+ }
38
+ }
39
+
40
+ export function normalizeToolName(tool: string): string {
41
+ const lowered = tool.toLowerCase()
42
+ if (lowered === "edit") return "Edit"
43
+ if (lowered === "write") return "Write"
44
+ if (lowered === "apply_patch") return "apply_patch"
45
+ if (["bash", "shell", "terminal", "exec", "command"].includes(lowered)) return "Bash"
46
+ return tool
47
+ }
48
+
49
+ export function normalizeToolInput(tool: string, args: unknown): Record<string, unknown> {
50
+ if (!isRecord(args)) return {}
51
+ const out: Record<string, unknown> = { ...args }
52
+ const copy = (from: string, to: string) => {
53
+ if (from in args && !(to in out)) out[to] = args[from]
54
+ }
55
+ copy("filePath", "file_path")
56
+ copy("oldString", "old_string")
57
+ copy("newString", "new_string")
58
+ copy("patchText", "command")
59
+ if (normalizeToolName(tool) === "Bash") {
60
+ copy("cmd", "command")
61
+ copy("script", "command")
62
+ }
63
+ return out
64
+ }
65
+
66
+ export function toolAfterPayload(input: Record<string, unknown>, output: Record<string, unknown>, cwd: string): PythonPayload {
67
+ const tool = typeof input.tool === "string" ? input.tool : ""
68
+ const text = typeof output.output === "string" ? output.output : ""
69
+ const response: Record<string, unknown> = {
70
+ output: text,
71
+ stdout: text,
72
+ }
73
+ if (typeof output.title === "string") response.title = output.title
74
+ if (isRecord(output.metadata)) response.metadata = output.metadata
75
+ if (isRecord(output.metadata) && output.metadata.error) response.error = output.metadata.error
76
+ return {
77
+ session_id: sessionIDFrom(input),
78
+ cwd,
79
+ tool_name: normalizeToolName(tool),
80
+ tool_input: normalizeToolInput(tool, input.args),
81
+ tool_response: response,
82
+ }
83
+ }
84
+
85
+ export function stopPayload(event: EventLike, cwd: string, lastAssistantMessage: string): PythonPayload {
86
+ return {
87
+ ...eventPayload(event, cwd),
88
+ last_assistant_message: lastAssistantMessage,
89
+ }
90
+ }
@@ -0,0 +1,174 @@
1
+ import { spawn } from "node:child_process"
2
+ import { dirname, resolve } from "node:path"
3
+ import { fileURLToPath } from "node:url"
4
+
5
+ import { AssistantBuffer } from "./assistant-buffer.js"
6
+ import { sessionIDFrom } from "./internal.js"
7
+ import { chatMessagePayload, eventPayload, stopPayload, toolAfterPayload } from "./payload.js"
8
+
9
+ type HookResult = Record<string, unknown>
10
+
11
+ type PluginInput = {
12
+ directory: string
13
+ }
14
+
15
+ type EventInput = {
16
+ event: {
17
+ type?: string
18
+ properties?: Record<string, unknown>
19
+ }
20
+ }
21
+
22
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url))
23
+ const PLUGIN_ROOT = resolve(MODULE_DIR, "../..")
24
+ const SCRIPTS_DIR = resolve(PLUGIN_ROOT, "scripts")
25
+ const HOOK_ENTRY = resolve(SCRIPTS_DIR, "hook_entry.sh")
26
+ const BACKEND_SERVICE = resolve(SCRIPTS_DIR, "backend-service.sh")
27
+ const DASHBOARD_SERVICE = resolve(SCRIPTS_DIR, "dashboard-service.sh")
28
+
29
+ function contextFrom(result: HookResult): string {
30
+ const hookOutput = result.hookSpecificOutput
31
+ if (!hookOutput || typeof hookOutput !== "object") return ""
32
+ const additional = (hookOutput as Record<string, unknown>).additionalContext
33
+ return typeof additional === "string" ? additional : ""
34
+ }
35
+
36
+ function parseFirstJsonObject(text: string): HookResult {
37
+ for (const line of text.split(/\r?\n/)) {
38
+ const trimmed = line.trim()
39
+ if (!trimmed.startsWith("{")) continue
40
+ try {
41
+ const parsed = JSON.parse(trimmed)
42
+ if (parsed && typeof parsed === "object") return parsed as HookResult
43
+ } catch {
44
+ continue
45
+ }
46
+ }
47
+ return {}
48
+ }
49
+
50
+ function runScript(script: string, args: string[], payload?: Record<string, unknown>): Promise<HookResult> {
51
+ return new Promise((resolvePromise) => {
52
+ const child = spawn("bash", [script, ...args], {
53
+ cwd: PLUGIN_ROOT,
54
+ env: {
55
+ ...process.env,
56
+ CLAUDE_PLUGIN_ROOT: PLUGIN_ROOT,
57
+ CLAUDE_SMART_HOST: "opencode",
58
+ },
59
+ stdio: ["pipe", "pipe", "pipe"],
60
+ })
61
+ let stdout = ""
62
+ child.stdout.on("data", (chunk) => {
63
+ stdout += chunk.toString()
64
+ })
65
+ child.stderr.on("data", (chunk) => {
66
+ process.stderr.write(chunk)
67
+ })
68
+ child.stdin.on("error", () => {
69
+ // Hooks can exit before reading stdin on marker-gated setup failures.
70
+ })
71
+ child.on("error", () => resolvePromise({}))
72
+ child.on("close", () => resolvePromise(parseFirstJsonObject(stdout)))
73
+ try {
74
+ if (payload) child.stdin.write(JSON.stringify(payload))
75
+ child.stdin.end()
76
+ } catch {
77
+ resolvePromise({})
78
+ }
79
+ })
80
+ }
81
+
82
+ function runService(script: string, subcommand: string): Promise<void> {
83
+ return runScript(script, [subcommand]).then(() => undefined)
84
+ }
85
+
86
+ function cacheContext(cache: Map<string, string[]>, sessionID: string, result: HookResult): void {
87
+ const context = contextFrom(result)
88
+ if (!sessionID || !context) return
89
+ const pending = cache.get(sessionID) ?? []
90
+ pending.push(context)
91
+ cache.set(sessionID, pending)
92
+ }
93
+
94
+ async function server(input: PluginInput) {
95
+ const pendingContext = new Map<string, string[]>()
96
+ const activeSessions = new Set<string>()
97
+ const completedAssistantText = new Map<string, string>()
98
+ const assistant = new AssistantBuffer()
99
+ const cwd = input.directory
100
+
101
+ async function flushStop(sessionID: string): Promise<void> {
102
+ if (!sessionID || !activeSessions.has(sessionID)) return
103
+ activeSessions.delete(sessionID)
104
+ const text = assistant.text(sessionID) || completedAssistantText.get(sessionID) || ""
105
+ completedAssistantText.delete(sessionID)
106
+ await runScript(
107
+ HOOK_ENTRY,
108
+ ["opencode", "stop"],
109
+ stopPayload({ properties: { sessionID, info: { directory: cwd } } }, cwd, text),
110
+ )
111
+ assistant.clear(sessionID)
112
+ }
113
+
114
+ return {
115
+ event: async ({ event }: EventInput) => {
116
+ const type = event.type
117
+ assistant.update(event)
118
+ if (type === "session.created") {
119
+ const payload = eventPayload(event, cwd)
120
+ const sessionID = String(payload.session_id || "")
121
+ if (!sessionID) return
122
+ activeSessions.add(sessionID)
123
+ await runService(BACKEND_SERVICE, "start")
124
+ await runService(DASHBOARD_SERVICE, "start")
125
+ const result = await runScript(HOOK_ENTRY, ["opencode", "session-start"], payload)
126
+ cacheContext(pendingContext, sessionID, result)
127
+ return
128
+ }
129
+ if (type === "session.idle") {
130
+ const payload = eventPayload(event, cwd)
131
+ const sessionID = String(payload.session_id || "")
132
+ if (!sessionID) return
133
+ await flushStop(sessionID)
134
+ }
135
+ },
136
+ "chat.message": async (hookInput: Record<string, unknown>, output: Record<string, unknown>) => {
137
+ const payload = chatMessagePayload(hookInput, output, cwd)
138
+ if (!payload.session_id || !payload.prompt) return
139
+ activeSessions.add(String(payload.session_id || ""))
140
+ const result = await runScript(HOOK_ENTRY, ["opencode", "user-prompt"], payload)
141
+ cacheContext(pendingContext, String(payload.session_id || ""), result)
142
+ },
143
+ "experimental.chat.system.transform": async (hookInput: Record<string, unknown>, output: { system: string[] }) => {
144
+ const sessionID = sessionIDFrom(hookInput)
145
+ const pending = pendingContext.get(sessionID)
146
+ if (!pending?.length) return
147
+ output.system.push(...pending)
148
+ pendingContext.delete(sessionID)
149
+ },
150
+ "tool.execute.after": async (hookInput: Record<string, unknown>, output: Record<string, unknown>) => {
151
+ const payload = toolAfterPayload(hookInput, output, cwd)
152
+ if (!payload.session_id || !payload.tool_name) return
153
+ await runScript(HOOK_ENTRY, ["opencode", "post-tool"], payload)
154
+ },
155
+ "experimental.text.complete": async (
156
+ hookInput: { sessionID?: string },
157
+ output: { text?: string },
158
+ ) => {
159
+ const sessionID = typeof hookInput.sessionID === "string" ? hookInput.sessionID : ""
160
+ if (!sessionID) return
161
+ if (typeof output.text === "string") completedAssistantText.set(sessionID, output.text)
162
+ },
163
+ dispose: async () => {
164
+ await Promise.all([...activeSessions].map((sessionID) => flushStop(sessionID)))
165
+ await runService(DASHBOARD_SERVICE, "session-end")
166
+ await runService(BACKEND_SERVICE, "session-end")
167
+ },
168
+ }
169
+ }
170
+
171
+ export default {
172
+ id: "claude-smart",
173
+ server,
174
+ }
@@ -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.46"
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.
@@ -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%\'}"