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
@@ -8,6 +8,7 @@ from __future__ import annotations
8
8
 
9
9
  import importlib.resources
10
10
  import logging
11
+ import os
11
12
  import re
12
13
  import secrets
13
14
  import sys
@@ -15,7 +16,7 @@ from pathlib import Path
15
16
 
16
17
  _logger = logging.getLogger(__name__)
17
18
 
18
- from dotenv import load_dotenv
19
+ from dotenv import dotenv_values, load_dotenv
19
20
 
20
21
  from .paths import reflexio_home
21
22
 
@@ -23,6 +24,21 @@ _USER_ENV_DIR = reflexio_home()
23
24
  _USER_ENV_FILE = _USER_ENV_DIR / ".env"
24
25
 
25
26
 
27
+ def user_env_file() -> Path:
28
+ """Return the user-level .env path, honoring ``REFLEXIO_ENV_FILE``.
29
+
30
+ When ``REFLEXIO_ENV_FILE`` is set (and non-blank) it overrides the default
31
+ ``~/.reflexio/.env``. This lets a second local backend keep its env separate
32
+ from the OSS reflexio default that also lives under ``~/.reflexio`` — e.g.
33
+ claude-smart points this at ``~/.claude-smart/.env`` so an OSS reflexio
34
+ ``.env`` (with its own ``REFLEXIO_STORAGE`` etc.) can't leak into it. The data
35
+ directory is independent (see ``LOCAL_STORAGE_PATH``), so both backends can
36
+ still share ``~/.reflexio/data``.
37
+ """
38
+ override = os.environ.get("REFLEXIO_ENV_FILE", "").strip()
39
+ return Path(override).expanduser() if override else _USER_ENV_FILE
40
+
41
+
26
42
  # Path to the .env file that load_reflexio_env last resolved — None until
27
43
  # load_reflexio_env runs for the first time. Exposed via get_loaded_env_path
28
44
  # so the startup banner can show the operator exactly which dotenv was
@@ -33,10 +49,72 @@ _loaded_env_path: Path | None = None
33
49
  def get_env_path() -> Path:
34
50
  """Return the canonical path to the user-level .env file.
35
51
 
36
- Returns:
37
- Path: ``~/.reflexio/.env``
52
+ Honors ``REFLEXIO_ENV_FILE`` (see :func:`user_env_file`); defaults to
53
+ ``~/.reflexio/.env``.
54
+ """
55
+ return user_env_file()
56
+
57
+
58
+ def block_implicit_dotenv_walkup() -> None:
59
+ """Neutralize path-less ``dotenv.load_dotenv()`` autoloads (the walk-up).
60
+
61
+ Third-party libraries — notably ``litellm`` at import time
62
+ (``litellm/__init__.py``) — call ``load_dotenv()`` with no arguments. With
63
+ no path, python-dotenv runs ``find_dotenv()``, which walks **up** the
64
+ directory tree and loads the first ``.env`` it finds. Run from the
65
+ ``open_source/reflexio`` submodule inside the enterprise monorepo, that
66
+ climbs to the enterprise-root ``.env`` (platform-configured) and leaks
67
+ ``BACKEND_PORT`` / ``DEPLOYMENT_MODE`` / ``REFLEXIO_STORAGE`` into the
68
+ process — silently overriding the OSS launcher's own ``806*`` defaults.
69
+
70
+ Reflexio loads env deliberately via :func:`load_reflexio_env`, scoped to
71
+ ``./.env`` + ``~/.reflexio/.env`` and never walking up, so a library's
72
+ implicit autoload is redundant. This installs a shim on
73
+ ``dotenv.load_dotenv`` that no-ops the path-less form while passing explicit
74
+ ``load_dotenv(dotenv_path=...)`` / ``stream=...`` calls through unchanged.
75
+ Reflexio's own loader binds ``load_dotenv`` at import and always passes an
76
+ explicit path, so it is unaffected regardless.
77
+
78
+ Must run before the first ``import litellm`` in the process — the CLI entry
79
+ point (:func:`reflexio.cli.__main__.main`) calls it first thing. Idempotent.
80
+ Only the CLI launcher installs this: the spawned server subprocesses bind
81
+ the parent-resolved ``--port`` and the OSS server never reads
82
+ ``DEPLOYMENT_MODE``, so the launcher process is the only place the leak
83
+ changes behavior.
38
84
  """
39
- return _USER_ENV_FILE
85
+ import functools
86
+ from typing import IO
87
+
88
+ import dotenv
89
+
90
+ original = dotenv.load_dotenv
91
+ if getattr(original, "__reflexio_walkup_guarded__", False):
92
+ return
93
+
94
+ @functools.wraps(original)
95
+ def _guarded(
96
+ dotenv_path: str | os.PathLike[str] | None = None,
97
+ stream: IO[str] | None = None,
98
+ verbose: bool = False,
99
+ override: bool = False,
100
+ interpolate: bool = True,
101
+ encoding: str | None = "utf-8",
102
+ ) -> bool:
103
+ if dotenv_path is None and stream is None:
104
+ # Path-less call would walk up past reflexio's controlled search
105
+ # scope (./.env + ~/.reflexio/.env). Ignore it.
106
+ return False
107
+ return original(
108
+ dotenv_path,
109
+ stream,
110
+ verbose=verbose,
111
+ override=override,
112
+ interpolate=interpolate,
113
+ encoding=encoding,
114
+ )
115
+
116
+ _guarded.__reflexio_walkup_guarded__ = True # type: ignore[attr-defined]
117
+ dotenv.load_dotenv = _guarded
40
118
 
41
119
 
42
120
  def get_loaded_env_path() -> Path | None:
@@ -87,10 +165,43 @@ def set_env_var(env_path: Path, key: str, value: str) -> None:
87
165
  env_path.chmod(0o600)
88
166
 
89
167
 
90
- _ENV_SEARCH_PATHS = [
91
- Path(".env"), # 1. Current directory (local dev / project-level)
92
- _USER_ENV_FILE, # 2. User home default (~/.reflexio/.env)
93
- ]
168
+ def _env_search_paths() -> list[Path]:
169
+ """OSS .env search order, resolved at call time so ``REFLEXIO_ENV_FILE`` is honored."""
170
+ return [
171
+ Path(".env"), # 1. Current directory (local dev / project-level)
172
+ user_env_file(), # 2. User-level file (REFLEXIO_ENV_FILE override, else ~/.reflexio/.env)
173
+ ]
174
+
175
+
176
+ def _load_dotenv_pruned(path: Path, *, override: bool = False) -> None:
177
+ """Load a .env file, treating blank assignments (``KEY=``) as unset.
178
+
179
+ python-dotenv exports a blank ``KEY=`` line as ``os.environ["KEY"] = ""``
180
+ rather than leaving the key unset. That empty string silently defeats every
181
+ ``os.getenv("KEY", default)`` fallback — the root cause of the HF_HOME
182
+ cache-in-repo-root bug, and of any ``int()``/``float()`` parse that crashes
183
+ on ``""``. This wrapper normalizes "set to blank" to "unset" so callers that
184
+ rely on a default behave correctly.
185
+
186
+ After loading, it drops any key the FILE assigned a blank/whitespace value,
187
+ but only when the resulting environment value is still blank — so a real
188
+ process-env value (task definition, shell ``export``) or an earlier-loaded
189
+ file value is never removed.
190
+
191
+ Args:
192
+ path: Path to the .env file to load.
193
+ override: Forwarded to ``load_dotenv``. When False (default) the existing
194
+ process environment wins over the file's values.
195
+ """
196
+ file_vals = dotenv_values(path)
197
+ load_dotenv(dotenv_path=path, override=override)
198
+ for key, value in file_vals.items():
199
+ if (
200
+ value is not None
201
+ and not value.strip()
202
+ and not os.environ.get(key, "").strip()
203
+ ):
204
+ os.environ.pop(key, None)
94
205
 
95
206
 
96
207
  def load_reflexio_env(
@@ -116,9 +227,9 @@ def load_reflexio_env(
116
227
  Path to the loaded .env file, or None if no .env was found/created.
117
228
  """
118
229
  global _loaded_env_path
119
- for env_path in _ENV_SEARCH_PATHS:
230
+ for env_path in _env_search_paths():
120
231
  if env_path.exists():
121
- load_dotenv(dotenv_path=env_path)
232
+ _load_dotenv_pruned(env_path)
122
233
  resolved = env_path.resolve()
123
234
  _logger.debug("Loaded env from: %s", resolved)
124
235
  _loaded_env_path = resolved
@@ -133,6 +244,165 @@ def load_reflexio_env(
133
244
  return created
134
245
 
135
246
 
247
+ def resolve_mode(cli_mode: str | None = None) -> str | None:
248
+ """Resolve the active deployment mode for mode-aware env loading.
249
+
250
+ Selection precedence:
251
+ 1. Explicit ``--mode`` flag (``cli_mode``)
252
+ 2. ``DEPLOYMENT_MODE`` environment variable
253
+ 3. None (caller falls back to the plain ``.env`` loader)
254
+
255
+ The resolved mode is spliced into ``.env.<mode>`` file paths, so it is
256
+ validated against a safe slug pattern: an empty/whitespace value resolves to
257
+ None (fall back to the plain loader), and anything containing path
258
+ characters (``/``, ``..``) or other non-slug characters raises ValueError
259
+ rather than redirecting reads/writes/chmods outside ``~/.reflexio/``.
260
+
261
+ Args:
262
+ cli_mode: Mode passed explicitly via a CLI flag, if any.
263
+
264
+ Returns:
265
+ The normalized (stripped, lowercased) mode string, or None when no
266
+ mode is selected.
267
+
268
+ Raises:
269
+ ValueError: If the selected mode is not a safe slug.
270
+ """
271
+ raw_mode = cli_mode if cli_mode is not None else os.environ.get("DEPLOYMENT_MODE")
272
+ if raw_mode is None:
273
+ return None
274
+ mode = raw_mode.strip().lower()
275
+ if not mode:
276
+ return None
277
+ if not re.fullmatch(r"[a-z0-9][a-z0-9_-]*", mode):
278
+ raise ValueError(f"Invalid deployment mode: {raw_mode!r}")
279
+ return mode
280
+
281
+
282
+ def load_reflexio_env_for_mode(
283
+ *,
284
+ cli_mode: str | None = None,
285
+ package_data_module: str = "reflexio.data",
286
+ auto_generate_keys: list[str] | None = None,
287
+ ) -> Path | None:
288
+ """Load ``.env.<mode>`` presets plus optional home secrets, mode-aware.
289
+
290
+ Loads the committed ``.env.<mode>`` presets (from CWD or the user home dir)
291
+ together with the optional gitignored ``~/.reflexio/.env.<mode>`` secrets
292
+ file. Both are loaded with ``override=False`` so the process environment
293
+ (task-def / shell ``export``) always wins, and home secrets take precedence
294
+ over committed presets for any disjoint keys.
295
+
296
+ When no mode is resolved, this falls back to :func:`load_reflexio_env`.
297
+
298
+ Args:
299
+ cli_mode: Mode passed explicitly via a CLI flag, if any.
300
+ package_data_module: Module containing the bundled ``.env.<mode>``
301
+ template (for ``importlib.resources``).
302
+ auto_generate_keys: Env var names to auto-generate as hex tokens
303
+ (e.g., ``["JWT_SECRET_KEY"]``) when missing. Generated secrets are
304
+ written ONLY to the gitignored ``~/.reflexio/.env.<mode>`` home
305
+ file — never the committed ``./.env.<mode>`` presets. Load-only
306
+ callers (the uvicorn / migration entrypoints) pass ``None``.
307
+
308
+ Returns:
309
+ Path to the loaded mode env file, or None if nothing was found/created.
310
+ """
311
+ global _loaded_env_path
312
+ mode = resolve_mode(cli_mode)
313
+ if mode is None:
314
+ return load_reflexio_env(
315
+ package_data_module=package_data_module,
316
+ auto_generate_keys=auto_generate_keys,
317
+ )
318
+
319
+ # Optional gitignored home secrets, loaded first so committed presets and
320
+ # process env both still win where they define the same keys.
321
+ home_secrets = _USER_ENV_DIR / f".env.{mode}"
322
+ if home_secrets.exists():
323
+ _load_dotenv_pruned(home_secrets, override=False)
324
+
325
+ loaded: Path | None = None
326
+ for env_path in (Path(f".env.{mode}"), home_secrets):
327
+ if env_path.exists():
328
+ _load_dotenv_pruned(env_path, override=False)
329
+ _loaded_env_path = env_path.resolve()
330
+ _logger.debug("Loaded mode env from: %s (mode=%s)", _loaded_env_path, mode)
331
+ loaded = env_path
332
+ break
333
+
334
+ if loaded is None:
335
+ loaded = _create_default_env_for_mode(mode, package_data_module)
336
+
337
+ # Auto-generate any missing secret keys into the gitignored home file ONLY,
338
+ # never the committed ./.env.<mode> presets file.
339
+ if auto_generate_keys:
340
+ _USER_ENV_DIR.mkdir(parents=True, exist_ok=True)
341
+ _backfill_missing_keys(home_secrets, auto_generate_keys)
342
+
343
+ return loaded
344
+
345
+
346
+ def _create_default_env_for_mode(mode: str, package_data_module: str) -> Path | None:
347
+ """Create ``~/.reflexio/.env.<mode>`` from the bundled mode template.
348
+
349
+ Args:
350
+ mode: The resolved deployment mode (e.g. ``"platform"``).
351
+ package_data_module: Module path for finding the ``.env.<mode>``
352
+ template.
353
+
354
+ Returns:
355
+ Path to the newly created mode env file, or None if no template found.
356
+ """
357
+ global _loaded_env_path
358
+ content = _find_mode_template(mode, package_data_module)
359
+ if content is None:
360
+ return None
361
+ _USER_ENV_DIR.mkdir(parents=True, exist_ok=True)
362
+ target = _USER_ENV_DIR / f".env.{mode}"
363
+ target.write_text(content)
364
+ target.chmod(0o600)
365
+ _load_dotenv_pruned(target, override=False)
366
+ _loaded_env_path = target.resolve()
367
+ return target
368
+
369
+
370
+ def _find_mode_template(mode: str, package_data_module: str) -> str | None:
371
+ """Find ``.env.<mode>`` template content from CWD or package data.
372
+
373
+ Args:
374
+ mode: The resolved deployment mode (e.g. ``"platform"``).
375
+ package_data_module: Dotted module path for importlib.resources lookup.
376
+
377
+ Returns:
378
+ The template content as a string, or None if not found anywhere.
379
+ """
380
+ # 1. Current directory (local dev checkout)
381
+ local = Path(f".env.{mode}")
382
+ if local.exists():
383
+ return local.read_text()
384
+
385
+ # 2. Package data (installed package)
386
+ try:
387
+ ref = importlib.resources.files(package_data_module).joinpath(f".env.{mode}")
388
+ return ref.read_text(encoding="utf-8")
389
+ except (ModuleNotFoundError, FileNotFoundError):
390
+ pass
391
+
392
+ # 3. Editable install: .env.<mode> lives at project root, two levels up.
393
+ try:
394
+ import reflexio as _pkg
395
+
396
+ project_root = Path(_pkg.__file__).resolve().parent.parent
397
+ candidate = project_root / f".env.{mode}"
398
+ if candidate.is_file():
399
+ return candidate.read_text()
400
+ except Exception: # noqa: BLE001, S110
401
+ pass
402
+
403
+ return None
404
+
405
+
136
406
  def ensure_user_env_for_setup(
137
407
  *,
138
408
  package_data_module: str = "reflexio.data",
@@ -161,7 +431,7 @@ def ensure_user_env_for_setup(
161
431
  """
162
432
  global _loaded_env_path
163
433
  if _USER_ENV_FILE.exists():
164
- load_dotenv(dotenv_path=_USER_ENV_FILE)
434
+ _load_dotenv_pruned(_USER_ENV_FILE)
165
435
  resolved = _USER_ENV_FILE.resolve()
166
436
  _logger.debug("Loaded user env from: %s", resolved)
167
437
  _loaded_env_path = resolved
@@ -184,8 +454,6 @@ def _backfill_missing_keys(env_path: Path, keys: list[str]) -> None:
184
454
  env_path: Path to the existing .env file.
185
455
  keys: Env var names to check/generate.
186
456
  """
187
- import os
188
-
189
457
  generated: list[str] = []
190
458
  for key in keys:
191
459
  if os.environ.get(key):
@@ -256,10 +524,12 @@ def _create_default_env(
256
524
  sys.stdout.flush()
257
525
  return None
258
526
 
259
- created_dir = not _USER_ENV_DIR.exists()
260
- _USER_ENV_DIR.mkdir(parents=True, exist_ok=True)
527
+ target = user_env_file() # honors REFLEXIO_ENV_FILE (e.g. ~/.claude-smart/.env)
528
+ target_dir = target.parent
529
+ created_dir = not target_dir.exists()
530
+ target_dir.mkdir(parents=True, exist_ok=True)
261
531
  if created_dir:
262
- sys.stdout.write(f"Created directory: {_USER_ENV_DIR}\n")
532
+ sys.stdout.write(f"Created directory: {target_dir}\n")
263
533
 
264
534
  # Auto-generate secret keys
265
535
  for key in auto_generate_keys:
@@ -272,13 +542,13 @@ def _create_default_env(
272
542
  flags=re.MULTILINE,
273
543
  )
274
544
 
275
- _USER_ENV_FILE.write_text(content)
276
- _USER_ENV_FILE.chmod(0o600)
277
- load_dotenv(dotenv_path=_USER_ENV_FILE)
545
+ target.write_text(content)
546
+ target.chmod(0o600)
547
+ _load_dotenv_pruned(target)
278
548
 
279
- sys.stdout.write(f"Created env file: {_USER_ENV_FILE}\n")
549
+ sys.stdout.write(f"Created env file: {target}\n")
280
550
  if auto_generate_keys:
281
551
  sys.stdout.write(f" Auto-generated: {', '.join(auto_generate_keys)}\n")
282
- sys.stdout.write(f" Edit {_USER_ENV_FILE} to add your API keys.\n\n")
552
+ sys.stdout.write(f" Edit {target} to add your API keys.\n\n")
283
553
  sys.stdout.flush()
284
- return _USER_ENV_FILE
554
+ return target
@@ -187,15 +187,31 @@ def print_startup_banner(
187
187
  ports: dict[str, int],
188
188
  *,
189
189
  supabase_port: int | None = 54321,
190
+ supabase_status: str = "ready",
191
+ failures: list[str] | None = None,
190
192
  log_file: str = DEV_LOG_FILE,
191
193
  config_paths: dict[str, str] | None = None,
192
194
  ) -> None:
193
195
  """Print a consolidated startup summary banner with service URLs.
194
196
 
197
+ Services that were *requested* but failed to reach a ready state are
198
+ rendered with a red "not ready" status (instead of being silently
199
+ omitted), so operators can tell at a glance that startup did not
200
+ fully succeed.
201
+
195
202
  Args:
196
- ports: Mapping of service name to port number.
197
- supabase_port: Supabase port, or None if not running.
198
- log_file: Path to the log file.
203
+ ports: Mapping of service name to port number for services that
204
+ were started (backend/frontend/docs).
205
+ supabase_port: Supabase port to display, or None to omit the
206
+ Supabase line entirely (e.g. when --no-supabase was passed).
207
+ supabase_status: ``"ready"`` (green) or anything else (rendered
208
+ as red "not ready"). Only consulted when ``supabase_port``
209
+ is not None.
210
+ failures: Optional list of human-readable failure summary
211
+ lines. Rendered as a red "Failures" section above the logs
212
+ so the cause is visible without scrolling back through the
213
+ scrollback.
214
+ log_file: Path to the dev-server log file.
199
215
  config_paths: Optional mapping of config-label → path string (e.g.
200
216
  ``{"env": "~/.reflexio/.env", "config": "~/.reflexio/configs/config_default.json"}``).
201
217
  Renders as a "Config" section above the "Logs" line so operators
@@ -219,7 +235,11 @@ def print_startup_banner(
219
235
  if supabase_port is not None:
220
236
  url = f"http://localhost:{supabase_port}"
221
237
  label = colorize(" Supabase ", "36")
222
- status = colorize("ready", "32")
238
+ status = (
239
+ colorize("ready", "32")
240
+ if supabase_status == "ready"
241
+ else colorize("not ready", "31", bold=True)
242
+ )
223
243
  lines.append(f"{label}{url:<26}{status}")
224
244
 
225
245
  home = str(Path.home())
@@ -234,6 +254,11 @@ def print_startup_banner(
234
254
  for label, path in config_paths.items():
235
255
  lines.append(f" {label:<11}{_collapse_home(str(path))}")
236
256
 
257
+ if failures:
258
+ lines.append(f"{'-' * width}")
259
+ lines.append(colorize(" Failures", "31", bold=True))
260
+ lines.extend(colorize(f" - {msg}", "31") for msg in failures)
261
+
237
262
  lines.append(f"{'-' * width}")
238
263
  # Logs section — surface both the general dev log and the LLM I/O log.
239
264
  # LLM_IO_LOG_FILE is the one operators hit first when debugging prompt /
@@ -27,6 +27,13 @@ _PACKAGE_DIR = Path(reflexio.__file__).resolve().parent
27
27
  _EDITABLE_REPO_ROOT = _PACKAGE_DIR.parent
28
28
  DOCS_DIR = _EDITABLE_REPO_ROOT / "docs"
29
29
 
30
+ # Default local ports for the OSS launcher. OSS occupies the 806* range so it
31
+ # never collides with claude-smart / openclaw-smart (807*), enterprise self-host
32
+ # (808*), or enterprise platform (809*). Embedding sits in the *9 slot to mirror
33
+ # the enterprise convention (8089 self-host, 8099 platform). Override per service
34
+ # with the matching CLI flag or {BACKEND,DOCS,EMBEDDING}_PORT env var.
35
+ DEFAULT_OSS_PORTS: dict[str, int] = {"backend": 8061, "docs": 8062, "embedding": 8069}
36
+
30
37
 
31
38
  def add_arguments(parser: argparse.ArgumentParser) -> None:
32
39
  """Add run-services arguments to the parser.
@@ -39,19 +46,19 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
39
46
  "--backend-port",
40
47
  type=int,
41
48
  default=None,
42
- help="Backend port (default: 8081, env: BACKEND_PORT)",
49
+ help="Backend port (default: 8061, env: BACKEND_PORT)",
43
50
  )
44
51
  parser.add_argument(
45
52
  "--docs-port",
46
53
  type=int,
47
54
  default=None,
48
- help="Docs port (default: 8082, env: DOCS_PORT)",
55
+ help="Docs port (default: 8062, env: DOCS_PORT)",
49
56
  )
50
57
  parser.add_argument(
51
58
  "--embedding-port",
52
59
  type=int,
53
60
  default=None,
54
- help="Embedding service port (default: 8072, env: EMBEDDING_PORT)",
61
+ help="Embedding service port (default: 8069, env: EMBEDDING_PORT)",
55
62
  )
56
63
  parser.add_argument(
57
64
  "--only",
@@ -252,7 +259,11 @@ def build_nextjs_service(
252
259
  )
253
260
 
254
261
 
255
- def build_embedding_service(ports: dict[str, int]) -> ServiceConfig:
262
+ def build_embedding_service(
263
+ ports: dict[str, int],
264
+ *,
265
+ app_module: str = "reflexio.server.llm.embedding_service:app",
266
+ ) -> ServiceConfig:
256
267
  """Build the local embedding daemon service configuration."""
257
268
  return ServiceConfig(
258
269
  name="embedding",
@@ -260,7 +271,7 @@ def build_embedding_service(ports: dict[str, int]) -> ServiceConfig:
260
271
  sys.executable,
261
272
  "-m",
262
273
  "uvicorn",
263
- "reflexio.server.llm.embedding_service:app",
274
+ app_module,
264
275
  "--host",
265
276
  "127.0.0.1",
266
277
  "--port",
@@ -319,9 +330,7 @@ def execute(args: argparse.Namespace) -> None:
319
330
  ts = time.strftime("%Y-%m-%d %H:%M:%S %Z")
320
331
  print(f"\n{bar}\n=== NEW REFLEXIO SERVER START — {ts} ===\n{bar}\n")
321
332
 
322
- ports = resolve_ports(
323
- args, defaults={"backend": 8081, "docs": 8082, "embedding": 8072}
324
- )
333
+ ports = resolve_ports(args, defaults=DEFAULT_OSS_PORTS)
325
334
  os.environ["API_BACKEND_URL"] = os.environ.get(
326
335
  "API_BACKEND_URL", f"http://localhost:{ports['backend']}"
327
336
  )
@@ -4,9 +4,12 @@ from __future__ import annotations
4
4
 
5
5
  import argparse
6
6
 
7
- from dotenv import load_dotenv
8
-
9
- from reflexio.cli.run_services import parse_only_flag, resolve_ports
7
+ from reflexio.cli.env_loader import load_reflexio_env
8
+ from reflexio.cli.run_services import (
9
+ DEFAULT_OSS_PORTS,
10
+ parse_only_flag,
11
+ resolve_ports,
12
+ )
10
13
  from reflexio.cli.utils import stop_services
11
14
 
12
15
 
@@ -16,19 +19,19 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
16
19
  "--backend-port",
17
20
  type=int,
18
21
  default=None,
19
- help="Backend port (default: 8081, env: BACKEND_PORT)",
22
+ help="Backend port (default: 8061, env: BACKEND_PORT)",
20
23
  )
21
24
  parser.add_argument(
22
25
  "--docs-port",
23
26
  type=int,
24
27
  default=None,
25
- help="Docs port (default: 8082, env: DOCS_PORT)",
28
+ help="Docs port (default: 8062, env: DOCS_PORT)",
26
29
  )
27
30
  parser.add_argument(
28
31
  "--embedding-port",
29
32
  type=int,
30
33
  default=None,
31
- help="Embedding service port (default: 8072, env: EMBEDDING_PORT)",
34
+ help="Embedding service port (default: 8069, env: EMBEDDING_PORT)",
32
35
  )
33
36
  parser.add_argument(
34
37
  "--only",
@@ -79,11 +82,11 @@ def build_stop_targets(
79
82
 
80
83
  def execute(args: argparse.Namespace) -> None:
81
84
  """Execute the stop-services command."""
82
- load_dotenv()
85
+ # Use reflexio's scoped loader (./.env + ~/.reflexio/.env), not a bare
86
+ # ``dotenv.load_dotenv()`` which walks up to a parent ``.env``.
87
+ load_reflexio_env()
83
88
 
84
- ports = resolve_ports(
85
- args, defaults={"backend": 8081, "docs": 8082, "embedding": 8072}
86
- )
89
+ ports = resolve_ports(args, defaults=DEFAULT_OSS_PORTS)
87
90
  only = parse_only_flag(args.only, {"backend", "docs", "embedding"})
88
91
  port_map, process_patterns = build_stop_targets(only, ports)
89
92