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
@@ -17,13 +17,17 @@ const { execSync, spawn, spawnSync } = require("child_process");
17
17
  const crypto = require("crypto");
18
18
  const {
19
19
  chmodSync,
20
+ constants,
20
21
  cpSync,
21
22
  existsSync,
23
+ accessSync,
22
24
  lstatSync,
23
25
  mkdirSync,
24
26
  readFileSync,
25
27
  readdirSync,
28
+ realpathSync,
26
29
  renameSync,
30
+ rmdirSync,
27
31
  rmSync,
28
32
  statSync,
29
33
  symlinkSync,
@@ -31,12 +35,15 @@ const {
31
35
  } = require("fs");
32
36
  const https = require("https");
33
37
  const { arch, homedir, platform, release, tmpdir } = require("os");
34
- const { dirname, join } = require("path");
38
+ const { dirname, join, resolve } = require("path");
39
+ const { fileURLToPath, pathToFileURL } = require("url");
35
40
 
36
41
  const PLUGIN_SPEC = "claude-smart@reflexioai";
37
42
  const CODEX_MARKETPLACE_NAME = "reflexioai";
38
43
  const CODEX_MARKETPLACE_DISPLAY_NAME = "ReflexioAI";
39
44
  const CODEX_PLUGIN_ID = `claude-smart@${CODEX_MARKETPLACE_NAME}`;
45
+ const OPENCODE_BARE_PLUGIN_SPEC = "claude-smart";
46
+ const OPENCODE_CONFIG_NAMES = ["opencode.json", "opencode.jsonc"];
40
47
  const REFLEXIO_ENV_PATH = join(homedir(), ".reflexio", ".env");
41
48
  const MANAGED_REFLEXIO_URL = "https://www.reflexio.ai/";
42
49
  const MANAGED_SETUP_ENV = "CLAUDE_SMART_MANAGED_SETUP";
@@ -46,6 +53,9 @@ const CLAUDE_SMART_USE_LOCAL_EMBEDDING_ENV = "CLAUDE_SMART_USE_LOCAL_EMBEDDING";
46
53
  const REFLEXIO_USER_ID_ENV = "REFLEXIO_USER_ID";
47
54
  const REFLEXIO_DIR = join(homedir(), ".reflexio");
48
55
  const CLAUDE_SMART_STATE_DIR = join(homedir(), ".claude-smart");
56
+ const OPENCODE_LOCAL_PACKAGE_DIR = join(CLAUDE_SMART_STATE_DIR, "opencode", "claude-smart");
57
+ const OPENCODE_PACKAGE_LOCK_TIMEOUT_MS = 120_000;
58
+ const OPENCODE_PACKAGE_LOCK_STALE_MS = 10 * 60_000;
49
59
  const CODEX_CONFIG_PATH = join(homedir(), ".codex", "config.toml");
50
60
  const PACKAGE_ROOT = dirname(dirname(__filename));
51
61
  const CODEX_MARKETPLACE_DIR = join(
@@ -79,6 +89,9 @@ const CODEX_REQUIRED_FILES = [
79
89
  "plugin/scripts/codex-claude-compat",
80
90
  "plugin/scripts/codex-claude-compat.cmd",
81
91
  "plugin/scripts/codex-claude-compat.js",
92
+ "plugin/scripts/opencode-claude-compat",
93
+ "plugin/scripts/opencode-claude-compat.cmd",
94
+ "plugin/scripts/opencode-claude-compat.js",
82
95
  "plugin/scripts/codex-hook.js",
83
96
  "plugin/scripts/_codex_env.sh",
84
97
  ];
@@ -89,6 +102,7 @@ const COPYTREE_IGNORE_NAMES = new Set([
89
102
  ".venv",
90
103
  ".pytest_cache",
91
104
  ".ruff_cache",
105
+ ".git",
92
106
  "node_modules",
93
107
  ".next",
94
108
  ]);
@@ -342,6 +356,200 @@ function configureReflexioSetup() {
342
356
  return loadReflexioSetupEnv();
343
357
  }
344
358
 
359
+ function stripJsonc(text) {
360
+ let out = "";
361
+ let inString = false;
362
+ let escaped = false;
363
+ const skipTrivia = (index) => {
364
+ while (index < text.length) {
365
+ while (index < text.length && /\s/.test(text[index])) index += 1;
366
+ if (text[index] === "/" && text[index + 1] === "/") {
367
+ index += 2;
368
+ while (index < text.length && !"\r\n".includes(text[index])) index += 1;
369
+ continue;
370
+ }
371
+ if (text[index] === "/" && text[index + 1] === "*") {
372
+ index += 2;
373
+ while (index + 1 < text.length && !(text[index] === "*" && text[index + 1] === "/")) index += 1;
374
+ index = Math.min(index + 2, text.length);
375
+ continue;
376
+ }
377
+ break;
378
+ }
379
+ return index;
380
+ };
381
+ for (let i = 0; i < text.length; i += 1) {
382
+ const ch = text[i];
383
+ const next = text[i + 1] || "";
384
+ if (inString) {
385
+ out += ch;
386
+ if (escaped) escaped = false;
387
+ else if (ch === "\\") escaped = true;
388
+ else if (ch === '"') inString = false;
389
+ continue;
390
+ }
391
+ if (ch === '"') {
392
+ inString = true;
393
+ out += ch;
394
+ continue;
395
+ }
396
+ if (ch === "/" && next === "/") {
397
+ while (i < text.length && !"\r\n".includes(text[i])) i += 1;
398
+ i -= 1;
399
+ continue;
400
+ }
401
+ if (ch === "/" && next === "*") {
402
+ i += 2;
403
+ while (i + 1 < text.length && !(text[i] === "*" && text[i + 1] === "/")) i += 1;
404
+ i += 1;
405
+ continue;
406
+ }
407
+ if (ch === ",") {
408
+ const j = skipTrivia(i + 1);
409
+ if (text[j] === "}" || text[j] === "]") continue;
410
+ }
411
+ out += ch;
412
+ }
413
+ return out;
414
+ }
415
+
416
+ function readJsoncObject(path) {
417
+ const text = existsSync(path) ? readFileSync(path, "utf8") : "{}";
418
+ const parsed = JSON.parse(stripJsonc(text || "{}"));
419
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
420
+ throw new Error(`OpenCode config ${path} must be a JSON object`);
421
+ }
422
+ return parsed;
423
+ }
424
+
425
+ function parseGlobalFlag(args) {
426
+ return args.includes("--global");
427
+ }
428
+
429
+ function opencodeGlobalConfigDir() {
430
+ const xdg = (process.env.XDG_CONFIG_HOME || "").trim();
431
+ const base = xdg ? xdg : join(homedir(), ".config");
432
+ return join(base, "opencode");
433
+ }
434
+
435
+ function opencodeConfigPath(args = [], cwd = process.cwd()) {
436
+ if (parseGlobalFlag(args)) {
437
+ const configDir = opencodeGlobalConfigDir();
438
+ for (const name of OPENCODE_CONFIG_NAMES) {
439
+ const candidate = join(configDir, name);
440
+ if (existsSync(candidate)) return candidate;
441
+ }
442
+ return join(configDir, "opencode.json");
443
+ }
444
+ const candidates = [
445
+ ...OPENCODE_CONFIG_NAMES.map((name) => join(cwd, name)),
446
+ ...OPENCODE_CONFIG_NAMES.map((name) => join(cwd, ".opencode", name)),
447
+ ];
448
+ for (const candidate of candidates) {
449
+ if (existsSync(candidate)) return candidate;
450
+ }
451
+ return join(cwd, "opencode.json");
452
+ }
453
+
454
+ function opencodePluginSpec(entry) {
455
+ if (typeof entry === "string") return entry;
456
+ if (Array.isArray(entry) && typeof entry[0] === "string") return entry[0];
457
+ return null;
458
+ }
459
+
460
+ function opencodeLocalPluginSpec(packageRoot = OPENCODE_LOCAL_PACKAGE_DIR) {
461
+ return pathToFileURL(packageRoot).href;
462
+ }
463
+
464
+ function isOpenCodeLocalPackagePath(packagePath) {
465
+ return (
466
+ sameRealPath(packagePath, OPENCODE_LOCAL_PACKAGE_DIR) ||
467
+ resolve(packagePath) === resolve(OPENCODE_LOCAL_PACKAGE_DIR)
468
+ );
469
+ }
470
+
471
+ function isOpenCodeClaudeSmartSpec(spec) {
472
+ if (!spec) return false;
473
+ if (spec === OPENCODE_BARE_PLUGIN_SPEC || spec.startsWith(`${OPENCODE_BARE_PLUGIN_SPEC}@`)) {
474
+ return true;
475
+ }
476
+ if (!spec.startsWith("file://")) return false;
477
+ let packagePath = null;
478
+ try {
479
+ packagePath = fileURLToPath(spec);
480
+ } catch {
481
+ return false;
482
+ }
483
+ if (isOpenCodeLocalPackagePath(packagePath)) return true;
484
+ try {
485
+ const manifest = JSON.parse(readFileSync(join(packagePath, "package.json"), "utf8"));
486
+ if (manifest && manifest.name === OPENCODE_BARE_PLUGIN_SPEC) return true;
487
+ } catch {
488
+ // Missing or malformed manifests are not enough to identify arbitrary file specs.
489
+ }
490
+ return false;
491
+ }
492
+
493
+ function patchOpenCodePluginConfig(configPath, { install, pluginSpec = null }) {
494
+ const resolvedPluginSpec = install ? (pluginSpec || opencodeLocalPluginSpec()) : pluginSpec;
495
+ const data = readJsoncObject(configPath);
496
+ for (const field of ["plugins", "plugin"]) {
497
+ if (data[field] !== undefined && !Array.isArray(data[field])) {
498
+ throw new Error(`OpenCode config ${configPath} field "${field}" must be a JSON array`);
499
+ }
500
+ }
501
+ const current = [
502
+ ...(Array.isArray(data.plugin) ? data.plugin : []),
503
+ ...(Array.isArray(data.plugins) ? data.plugins : []),
504
+ ];
505
+ const kept = current.filter((entry) => !isOpenCodeClaudeSmartSpec(opencodePluginSpec(entry)));
506
+ const next = install ? [...kept, resolvedPluginSpec] : kept;
507
+ const changed =
508
+ data.plugins !== undefined ||
509
+ (Array.isArray(data.plugin)
510
+ ? next.length !== data.plugin.length || next.some((entry, index) => entry !== data.plugin[index])
511
+ : install && next.length > 0);
512
+ if (!changed) return { changed: false, configPath };
513
+ let backupPath = null;
514
+ if (existsSync(configPath)) {
515
+ const original = readFileSync(configPath, "utf8");
516
+ if (original.trim() && original !== stripJsonc(original)) {
517
+ backupPath = `${configPath}.bak`;
518
+ writeFileSync(backupPath, original);
519
+ }
520
+ }
521
+ data.plugin = next;
522
+ delete data.plugins;
523
+ mkdirSync(dirname(configPath), { recursive: true });
524
+ writeFileSync(configPath, JSON.stringify(data, null, 2) + "\n");
525
+ return { changed: true, configPath, backupPath };
526
+ }
527
+
528
+ function hasExtractionProvider() {
529
+ if ((process.env.REFLEXIO_API_KEY || "").trim()) return true;
530
+ const cliPath = (process.env.CLAUDE_SMART_CLI_PATH || "").trim();
531
+ if (cliPath && isExecutableFile(cliPath)) return true;
532
+ return hasCli("claude") || hasCli("codex") || hasCli("opencode");
533
+ }
534
+
535
+ function isExecutableFile(path) {
536
+ try {
537
+ if (!statSync(path).isFile()) return false;
538
+ accessSync(path, constants.X_OK);
539
+ return true;
540
+ } catch {
541
+ return false;
542
+ }
543
+ }
544
+
545
+ function extractionProviderError() {
546
+ return (
547
+ "error: OpenCode support needs a working learning/extraction provider.\n" +
548
+ "Run `npx claude-smart setup` to configure Reflexio, or install " +
549
+ "OpenCode, Claude Code, or Codex so local extraction can use a supported CLI.\n"
550
+ );
551
+ }
552
+
345
553
  function findClaudeCodePluginRoot() {
346
554
  const cacheRoot = join(homedir(), ".claude", "plugins", "cache", CODEX_MARKETPLACE_NAME, "claude-smart");
347
555
  const candidates = [];
@@ -429,6 +637,130 @@ function forcePluginRoot(pluginRoot) {
429
637
  }
430
638
  }
431
639
 
640
+ function sameRealPath(left, right) {
641
+ try {
642
+ return realpathSync(left) === realpathSync(right);
643
+ } catch {
644
+ return false;
645
+ }
646
+ }
647
+
648
+ function pathEntryExists(path) {
649
+ try {
650
+ lstatSync(path);
651
+ return true;
652
+ } catch {
653
+ return false;
654
+ }
655
+ }
656
+
657
+ function fileSha256(path) {
658
+ return crypto.createHash("sha256").update(readFileSync(path)).digest("hex");
659
+ }
660
+
661
+ function verifyOpenCodePluginPackage(packageRoot) {
662
+ const sourceScript = join(PACKAGE_ROOT, "plugin", "scripts", "smart-install.sh");
663
+ const copiedScript = join(packageRoot, "plugin", "scripts", "smart-install.sh");
664
+ for (const file of [join(packageRoot, "package.json"), copiedScript]) {
665
+ if (!existsSync(file)) {
666
+ throw new Error(`OpenCode local plugin package is missing ${file}`);
667
+ }
668
+ }
669
+ if (fileSha256(sourceScript) !== fileSha256(copiedScript)) {
670
+ throw new Error(
671
+ "OpenCode local plugin package does not match the installed claude-smart package",
672
+ );
673
+ }
674
+ }
675
+
676
+ function sleepSync(ms) {
677
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
678
+ }
679
+
680
+ function withOpenCodePackageInstallLock(fn) {
681
+ const lockDir = join(dirname(OPENCODE_LOCAL_PACKAGE_DIR), ".install.lock");
682
+ mkdirSync(dirname(OPENCODE_LOCAL_PACKAGE_DIR), { recursive: true });
683
+ const deadline = Date.now() + OPENCODE_PACKAGE_LOCK_TIMEOUT_MS;
684
+ while (true) {
685
+ try {
686
+ mkdirSync(lockDir);
687
+ break;
688
+ } catch (err) {
689
+ if (!err || err.code !== "EEXIST") throw err;
690
+ try {
691
+ if (Date.now() - statSync(lockDir).mtimeMs > OPENCODE_PACKAGE_LOCK_STALE_MS) {
692
+ rmSync(lockDir, { recursive: true, force: true });
693
+ continue;
694
+ }
695
+ } catch (statErr) {
696
+ if (statErr && statErr.code !== "ENOENT") throw statErr;
697
+ }
698
+ if (Date.now() >= deadline) {
699
+ throw new Error(`timed out waiting for OpenCode package install lock at ${lockDir}`);
700
+ }
701
+ sleepSync(100);
702
+ }
703
+ }
704
+ try {
705
+ return fn();
706
+ } finally {
707
+ rmSync(lockDir, { recursive: true, force: true });
708
+ }
709
+ }
710
+
711
+ function uniqueOpenCodePackagePath(prefix) {
712
+ return join(
713
+ dirname(OPENCODE_LOCAL_PACKAGE_DIR),
714
+ `${prefix}-${process.pid}-${Date.now()}-${crypto.randomBytes(4).toString("hex")}`,
715
+ );
716
+ }
717
+
718
+ function replaceOpenCodePluginPackage(stagedPackage, packageRoot) {
719
+ const backupPackage = uniqueOpenCodePackagePath(".claude-smart-previous");
720
+ let backupCreated = false;
721
+ try {
722
+ if (pathEntryExists(packageRoot)) {
723
+ renameSync(packageRoot, backupPackage);
724
+ backupCreated = true;
725
+ }
726
+ renameSync(stagedPackage, packageRoot);
727
+ if (backupCreated) {
728
+ rmSync(backupPackage, { recursive: true, force: true });
729
+ }
730
+ } catch (err) {
731
+ if (backupCreated && !existsSync(packageRoot) && existsSync(backupPackage)) {
732
+ renameSync(backupPackage, packageRoot);
733
+ }
734
+ throw err;
735
+ }
736
+ }
737
+
738
+ function installOpenCodePluginPackage() {
739
+ const packageRoot = OPENCODE_LOCAL_PACKAGE_DIR;
740
+ if (sameRealPath(PACKAGE_ROOT, packageRoot)) {
741
+ verifyOpenCodePluginPackage(packageRoot);
742
+ return packageRoot;
743
+ }
744
+ return withOpenCodePackageInstallLock(() => {
745
+ const stagedPackage = uniqueOpenCodePackagePath(".claude-smart-copy");
746
+ rmSync(stagedPackage, { recursive: true, force: true });
747
+ try {
748
+ cpSync(PACKAGE_ROOT, stagedPackage, {
749
+ recursive: true,
750
+ force: true,
751
+ verbatimSymlinks: false,
752
+ filter: shouldCopyPath,
753
+ });
754
+ verifyOpenCodePluginPackage(stagedPackage);
755
+ replaceOpenCodePluginPackage(stagedPackage, packageRoot);
756
+ verifyOpenCodePluginPackage(packageRoot);
757
+ return packageRoot;
758
+ } finally {
759
+ rmSync(stagedPackage, { recursive: true, force: true });
760
+ }
761
+ });
762
+ }
763
+
432
764
  async function bootstrapClaudeCodeInstall() {
433
765
  const pluginRoot = findClaudeCodePluginRoot();
434
766
  if (!pluginRoot) {
@@ -523,6 +855,18 @@ function runChecked(command, args, options = {}) {
523
855
  });
524
856
  }
525
857
 
858
+ function runSilentStatus(command, args, options = {}) {
859
+ const result = spawnSync(command, args, {
860
+ cwd: options.cwd,
861
+ env: options.env || process.env,
862
+ shell: isWindows() && /\.(?:cmd|bat)$/i.test(command),
863
+ stdio: "ignore",
864
+ windowsHide: true,
865
+ });
866
+ if (result.error || result.signal) return 1;
867
+ return typeof result.status === "number" ? result.status : 1;
868
+ }
869
+
526
870
  function runPluginService(pluginRoot, scriptName, subcommand, envOverrides = {}) {
527
871
  const script = join(pluginRoot, "scripts", scriptName);
528
872
  if (!existsSync(script)) return false;
@@ -921,11 +1265,66 @@ async function installVendoredReflexio(pluginRoot, uv, env) {
921
1265
  if (code !== 0) throw new Error(`vendored Reflexio install failed in ${pluginRoot}`);
922
1266
  }
923
1267
 
1268
+ async function syncPluginPythonEnv(pluginRoot, uv, env) {
1269
+ let code = await runChecked(
1270
+ uv,
1271
+ ["sync", "--locked", "--python", "3.12", "--quiet"],
1272
+ { cwd: pluginRoot, env },
1273
+ );
1274
+ if (code === 0) return;
1275
+
1276
+ const lockIsFresh = runSilentStatus(
1277
+ uv,
1278
+ ["lock", "--check", "--python", "3.12"],
1279
+ { cwd: pluginRoot, env },
1280
+ ) === 0;
1281
+ if (lockIsFresh) {
1282
+ process.stderr.write(
1283
+ `warning: quiet uv sync failed in ${pluginRoot}; retrying with full output.\n`,
1284
+ );
1285
+ code = await runChecked(
1286
+ uv,
1287
+ ["sync", "--locked", "--python", "3.12"],
1288
+ { cwd: pluginRoot, env },
1289
+ );
1290
+ if (code !== 0) throw new Error(`uv sync failed in ${pluginRoot}`);
1291
+ return;
1292
+ }
1293
+
1294
+ process.stderr.write(
1295
+ "warning: plugin/uv.lock is out of sync; refreshing local lockfile and retrying uv sync.\n",
1296
+ );
1297
+ code = await runChecked(
1298
+ uv,
1299
+ ["lock", "--python", "3.12"],
1300
+ { cwd: pluginRoot, env },
1301
+ );
1302
+ if (code !== 0) throw new Error(`uv lock failed in ${pluginRoot}`);
1303
+ code = await runChecked(
1304
+ uv,
1305
+ ["sync", "--python", "3.12", "--quiet"],
1306
+ { cwd: pluginRoot, env },
1307
+ );
1308
+ if (code !== 0) {
1309
+ process.stderr.write(
1310
+ `warning: quiet uv sync failed in ${pluginRoot} after refreshing plugin/uv.lock; retrying with full output.\n`,
1311
+ );
1312
+ code = await runChecked(
1313
+ uv,
1314
+ ["sync", "--python", "3.12"],
1315
+ { cwd: pluginRoot, env },
1316
+ );
1317
+ }
1318
+ if (code !== 0) throw new Error(`uv sync failed in ${pluginRoot}`);
1319
+ }
1320
+
924
1321
  async function bootstrapPluginRuntime(pluginRoot, options = {}) {
925
1322
  assertSupportedRuntimePlatform();
926
1323
  process.stdout.write("Preparing claude-smart runtime for hooks...\n");
927
1324
  const nodeRuntime = await ensurePrivateNode();
928
- patchCodexHooksForNode(pluginRoot, nodeRuntime.node);
1325
+ if (options.patchCodexHooks !== false) {
1326
+ patchCodexHooksForNode(pluginRoot, nodeRuntime.node);
1327
+ }
929
1328
  if (options.readOnly) prunePublishHooksForReadOnly(pluginRoot);
930
1329
  ensurePluginRoot(pluginRoot);
931
1330
  const uv = await ensureUv();
@@ -940,27 +1339,12 @@ async function bootstrapPluginRuntime(pluginRoot, options = {}) {
940
1339
  );
941
1340
  if (lockCode !== 0) throw new Error(`uv lock failed in ${pluginRoot}`);
942
1341
  }
943
- let code = await runChecked(
944
- uv,
945
- ["sync", "--locked", "--python", "3.12", "--quiet"],
946
- { cwd: pluginRoot, env },
947
- );
948
- if (code !== 0) {
949
- process.stderr.write(
950
- `warning: quiet uv sync failed in ${pluginRoot}; retrying with full output.\n`,
951
- );
952
- code = await runChecked(
953
- uv,
954
- ["sync", "--locked", "--python", "3.12"],
955
- { cwd: pluginRoot, env },
956
- );
957
- }
958
- if (code !== 0) throw new Error(`uv sync failed in ${pluginRoot}`);
1342
+ await syncPluginPythonEnv(pluginRoot, uv, env);
959
1343
  await installVendoredReflexio(pluginRoot, uv, env);
960
1344
 
961
1345
  const dashboardDir = join(pluginRoot, "dashboard");
962
1346
  if (existsSync(dashboardDir)) {
963
- code = await runChecked(nodeRuntime.npm, ["ci"], { cwd: dashboardDir, env });
1347
+ let code = await runChecked(nodeRuntime.npm, ["ci"], { cwd: dashboardDir, env });
964
1348
  if (code !== 0) throw new Error(`npm ci failed in ${dashboardDir}`);
965
1349
  code = await runChecked(nodeRuntime.npm, ["run", "build"], { cwd: dashboardDir, env });
966
1350
  if (code !== 0) throw new Error(`npm run build failed in ${dashboardDir}`);
@@ -970,13 +1354,15 @@ async function bootstrapPluginRuntime(pluginRoot, options = {}) {
970
1354
  function printHelp() {
971
1355
  process.stdout.write(
972
1356
  [
973
- "claude-smart — install helper for Claude Code and Codex",
1357
+ "claude-smart — install helper for Claude Code, Codex, and OpenCode",
974
1358
  "",
975
1359
  "Usage:",
976
1360
  " npx claude-smart install Install the plugin into Claude Code",
977
1361
  " npx claude-smart install --host codex Register the plugin marketplace for Codex",
1362
+ " npx claude-smart install --host opencode Add claude-smart to OpenCode config",
978
1363
  " npx claude-smart setup Configure managed/read-only/global setup",
979
1364
  " npx claude-smart uninstall --host codex Remove the Codex marketplace registration",
1365
+ " npx claude-smart uninstall --host opencode Remove claude-smart from OpenCode config",
980
1366
  " npx claude-smart --help Show this help",
981
1367
  "",
982
1368
  "Claude Code install:",
@@ -993,9 +1379,16 @@ function printHelp() {
993
1379
  " 6. Trusts and enables claude-smart hook entries in ~/.codex/config.toml",
994
1380
  " 7. Restart Codex.",
995
1381
  "",
1382
+ "OpenCode install:",
1383
+ ` 1. Copies this package to ${OPENCODE_LOCAL_PACKAGE_DIR}`,
1384
+ " 2. Adds that local file:// package to OpenCode's plugin list in opencode.json",
1385
+ " 3. Prepares local services now from the copied plugin runtime",
1386
+ " 4. Restart OpenCode.",
1387
+ "",
996
1388
  "Update:",
997
1389
  " npx claude-smart update Reinstall Claude Code support from this package",
998
1390
  " npx claude-smart update --host codex Reinstall Codex support from this package",
1391
+ " npx claude-smart update --host opencode Reinstall OpenCode support from this package",
999
1392
  " npx claude-smart setup Configure managed/read-only/global setup",
1000
1393
  "",
1001
1394
  "Uninstall:",
@@ -1010,11 +1403,11 @@ function parseHost(args) {
1010
1403
  if (idx === -1) return "claude-code";
1011
1404
  const value = args[idx + 1];
1012
1405
  if (!value) {
1013
- process.stderr.write("error: --host requires a value: claude-code or codex\n");
1406
+ process.stderr.write("error: --host requires a value: claude-code, codex, or opencode\n");
1014
1407
  process.exit(1);
1015
1408
  }
1016
- if (value !== "claude-code" && value !== "codex") {
1017
- process.stderr.write("error: --host must be claude-code or codex\n");
1409
+ if (value !== "claude-code" && value !== "codex" && value !== "opencode") {
1410
+ process.stderr.write("error: --host must be claude-code, codex, or opencode\n");
1018
1411
  process.exit(1);
1019
1412
  }
1020
1413
  return value;
@@ -1433,6 +1826,10 @@ async function runUpdate(args) {
1433
1826
  await runUpdateCodex(args);
1434
1827
  return;
1435
1828
  }
1829
+ if (parseHost(args) === "opencode") {
1830
+ await runUpdateOpenCode(args);
1831
+ return;
1832
+ }
1436
1833
 
1437
1834
  const pluginRoot = findClaudeCodePluginRoot();
1438
1835
  if (pluginRoot) {
@@ -1449,11 +1846,22 @@ async function runUpdateCodex(args) {
1449
1846
  await runInstallCodex(args);
1450
1847
  }
1451
1848
 
1849
+ async function runUpdateOpenCode(args) {
1850
+ const pluginRoot = join(PACKAGE_ROOT, "plugin");
1851
+ stopClaudeSmartServices(pluginRoot);
1852
+ process.stdout.write("Updating claude-smart OpenCode support by reinstalling from this package...\n");
1853
+ await runInstallOpenCode(args);
1854
+ }
1855
+
1452
1856
  async function runUninstall(args) {
1453
1857
  if (parseHost(args) === "codex") {
1454
1858
  await runUninstallCodex();
1455
1859
  return;
1456
1860
  }
1861
+ if (parseHost(args) === "opencode") {
1862
+ await runUninstallOpenCode(args);
1863
+ return;
1864
+ }
1457
1865
 
1458
1866
  if (!hasClaudeCli()) {
1459
1867
  process.stderr.write(
@@ -1504,6 +1912,10 @@ async function runInstall(args, options = {}) {
1504
1912
  await runInstallCodex(args);
1505
1913
  return;
1506
1914
  }
1915
+ if (parseHost(args) === "opencode") {
1916
+ await runInstallOpenCode(args);
1917
+ return;
1918
+ }
1507
1919
 
1508
1920
  if (!hasClaudeCli()) {
1509
1921
  process.stderr.write(
@@ -1686,6 +2098,68 @@ async function runInstallCodex(args) {
1686
2098
  );
1687
2099
  }
1688
2100
 
2101
+ async function runInstallOpenCode(args) {
2102
+ const setup = configureReflexioSetup();
2103
+ const readOnly = setup.readOnly;
2104
+ if (!hasExtractionProvider()) {
2105
+ process.stderr.write(extractionProviderError());
2106
+ process.exit(1);
2107
+ }
2108
+
2109
+ let packageRoot;
2110
+ try {
2111
+ packageRoot = installOpenCodePluginPackage();
2112
+ } catch (err) {
2113
+ process.stderr.write(
2114
+ `error: could not prepare claude-smart OpenCode package: ${err && err.message ? err.message : err}\n`,
2115
+ );
2116
+ process.exit(1);
2117
+ }
2118
+ const pluginRoot = join(packageRoot, "plugin");
2119
+ const pluginSpec = opencodeLocalPluginSpec(packageRoot);
2120
+ let result;
2121
+ try {
2122
+ await bootstrapPluginRuntime(pluginRoot, { readOnly, patchCodexHooks: false });
2123
+ } catch (err) {
2124
+ process.stderr.write(
2125
+ `error: claude-smart OpenCode setup failed during dependency bootstrap: ${err && err.message ? err.message : err}\n`,
2126
+ );
2127
+ process.exit(1);
2128
+ }
2129
+ try {
2130
+ result = patchOpenCodePluginConfig(opencodeConfigPath(args), {
2131
+ install: true,
2132
+ pluginSpec,
2133
+ });
2134
+ } catch (err) {
2135
+ process.stderr.write(`error: could not update OpenCode config: ${err && err.message ? err.message : err}\n`);
2136
+ stopClaudeSmartServices(pluginRoot);
2137
+ process.exit(1);
2138
+ }
2139
+ if (readOnly) {
2140
+ process.stdout.write("Installed read-only hook manifest; publish interactions hooks are disabled.\n");
2141
+ }
2142
+ if (startBackendService(pluginRoot, "opencode")) {
2143
+ process.stdout.write("Started claude-smart backend service.\n");
2144
+ }
2145
+ if (refreshDashboardService(pluginRoot)) {
2146
+ process.stdout.write("Refreshed claude-smart dashboard service.\n");
2147
+ }
2148
+ if (result.backupPath) {
2149
+ process.stdout.write(`Saved a comment-preserving backup of your previous config at ${result.backupPath}.\n`);
2150
+ }
2151
+ process.stdout.write(
2152
+ [
2153
+ "",
2154
+ `${result.changed ? "Updated" : "OpenCode config already includes"} "${pluginSpec}" in ${result.configPath}.`,
2155
+ `Prepared claude-smart OpenCode package at ${packageRoot}.`,
2156
+ "claude-smart OpenCode support is installed.",
2157
+ "Restart OpenCode in your project so it loads the plugin.",
2158
+ "",
2159
+ ].join("\n"),
2160
+ );
2161
+ }
2162
+
1689
2163
  async function runUninstallCodex() {
1690
2164
  stopClaudeSmartServices(join(PACKAGE_ROOT, "plugin"));
1691
2165
  if (!hasCli("codex")) {
@@ -1713,6 +2187,38 @@ async function runUninstallCodex() {
1713
2187
  );
1714
2188
  }
1715
2189
 
2190
+ async function runUninstallOpenCode(args) {
2191
+ stopClaudeSmartServices(join(PACKAGE_ROOT, "plugin"));
2192
+ stopClaudeSmartServices(join(OPENCODE_LOCAL_PACKAGE_DIR, "plugin"));
2193
+ let result;
2194
+ try {
2195
+ result = patchOpenCodePluginConfig(opencodeConfigPath(args), { install: false });
2196
+ } catch (err) {
2197
+ process.stderr.write(`error: could not update OpenCode config: ${err && err.message ? err.message : err}\n`);
2198
+ process.exit(1);
2199
+ }
2200
+ if (result.backupPath) {
2201
+ process.stdout.write(`Saved a comment-preserving backup of your previous config at ${result.backupPath}.\n`);
2202
+ }
2203
+ rmSync(OPENCODE_LOCAL_PACKAGE_DIR, { recursive: true, force: true });
2204
+ try {
2205
+ rmdirSync(dirname(OPENCODE_LOCAL_PACKAGE_DIR));
2206
+ } catch {
2207
+ // Keep the parent when it still contains future OpenCode state.
2208
+ }
2209
+ process.stdout.write(
2210
+ [
2211
+ "",
2212
+ result.changed
2213
+ ? `Removed claude-smart OpenCode plugin entries from ${result.configPath}.`
2214
+ : "OpenCode config did not include claude-smart.",
2215
+ "Restart OpenCode to apply.",
2216
+ ...LOCAL_DATA_NOTICE,
2217
+ "",
2218
+ ].join("\n"),
2219
+ );
2220
+ }
2221
+
1716
2222
  async function main() {
1717
2223
  const args = process.argv.slice(2);
1718
2224
  const cmd = args[0] || "install";
@@ -1764,7 +2270,13 @@ module.exports = {
1764
2270
  ensureUv,
1765
2271
  configureReflexioSetup,
1766
2272
  patchCodexHooksForNode,
2273
+ opencodeConfigPath,
2274
+ opencodeLocalPluginSpec,
2275
+ installOpenCodePluginPackage,
2276
+ patchOpenCodePluginConfig,
2277
+ hasExtractionProvider,
1767
2278
  platformSupportError,
1768
2279
  prunePublishHooksForReadOnly,
1769
2280
  restorePublishHooksFromSource,
2281
+ stripJsonc,
1770
2282
  };