claude-smart 0.2.42 → 0.2.44

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 (402) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +1 -1
  3. package/bin/claude-smart.js +2 -2
  4. package/package.json +9 -3
  5. package/plugin/.claude-plugin/plugin.json +9 -3
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +23 -3
  8. package/plugin/pyproject.toml +3 -3
  9. package/plugin/scripts/_lib.sh +91 -0
  10. package/plugin/scripts/backend-service.sh +51 -4
  11. package/plugin/scripts/cli.sh +3 -1
  12. package/plugin/scripts/codex-hook.js +72 -4
  13. package/plugin/scripts/dashboard-build.sh +1 -0
  14. package/plugin/scripts/dashboard-service.sh +1 -0
  15. package/plugin/scripts/ensure-plugin-root.sh +1 -0
  16. package/plugin/scripts/hook_entry.sh +6 -3
  17. package/plugin/scripts/smart-install.sh +3 -2
  18. package/plugin/src/README.md +57 -0
  19. package/plugin/src/claude_smart/context_format.py +11 -12
  20. package/plugin/src/claude_smart/cs_cite.py +26 -12
  21. package/plugin/src/claude_smart/ids.py +13 -5
  22. package/plugin/uv.lock +126 -5
  23. package/plugin/vendor/reflexio/.env.example +62 -0
  24. package/plugin/vendor/reflexio/LICENSE +201 -0
  25. package/plugin/vendor/reflexio/README.md +338 -0
  26. package/plugin/vendor/reflexio/pyproject.toml +274 -0
  27. package/plugin/vendor/reflexio/reflexio/README.md +184 -0
  28. package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
  29. package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
  30. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
  31. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
  32. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
  33. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
  34. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
  35. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
  36. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
  37. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
  38. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
  39. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
  40. package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
  41. package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
  42. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
  43. package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
  44. package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
  45. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +265 -0
  46. package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
  47. package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
  48. package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
  49. package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
  50. package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
  51. package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
  52. package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
  53. package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
  54. package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
  57. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +964 -0
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
  62. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
  63. package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
  64. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
  65. package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
  66. package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
  67. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
  68. package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
  69. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
  70. package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
  71. package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
  72. package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
  73. package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
  74. package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
  75. package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
  145. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
  146. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
  147. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
  148. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
  149. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
  150. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
  151. package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
  152. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
  153. package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
  154. package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
  155. package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
  156. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
  157. package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
  158. package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
  159. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
  160. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
  161. package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
  162. package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
  163. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
  164. package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
  165. package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
  166. package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
  167. package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
  168. package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
  169. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
  170. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1112 -0
  171. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
  172. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
  173. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
  174. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
  175. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +768 -0
  176. package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
  177. package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
  178. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
  179. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
  180. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
  181. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
  182. package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +333 -0
  183. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
  184. package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
  185. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
  186. package/plugin/vendor/reflexio/reflexio/server/README.md +622 -0
  187. package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
  188. package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
  189. package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
  190. package/plugin/vendor/reflexio/reflexio/server/api.py +2868 -0
  191. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +34 -0
  192. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/account_api.py +143 -0
  193. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/health_api.py +91 -0
  194. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/pending_tool_call_api.py +572 -0
  195. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +66 -0
  196. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +562 -0
  197. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +50 -0
  198. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/stall_state_api.py +100 -0
  199. package/plugin/vendor/reflexio/reflexio/server/cache/__init__.py +15 -0
  200. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +208 -0
  201. package/plugin/vendor/reflexio/reflexio/server/correlation.py +46 -0
  202. package/plugin/vendor/reflexio/reflexio/server/llm/__init__.py +30 -0
  203. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +359 -0
  204. package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
  205. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1871 -0
  206. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +140 -0
  207. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +479 -0
  208. package/plugin/vendor/reflexio/reflexio/server/llm/providers/__init__.py +1 -0
  209. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1122 -0
  210. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_stream_parser.py +197 -0
  211. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +338 -0
  212. package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +213 -0
  213. package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +288 -0
  214. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/__init__.py +6 -0
  215. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +187 -0
  216. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
  217. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +716 -0
  218. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +179 -0
  219. package/plugin/vendor/reflexio/reflexio/server/prompt/__init__.py +0 -0
  220. package/plugin/vendor/reflexio/reflexio/server/prompt/_dispatchers.py +54 -0
  221. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/README.md +121 -0
  222. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation/v1.0.0.prompt.md +58 -0
  223. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation_with_comparison/v1.0.0.prompt.md +76 -0
  224. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/answer_synthesis/v1.5.2.prompt.md +88 -0
  225. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/compress_session_for_query/v1.3.0.prompt.md +31 -0
  226. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +20 -0
  227. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.0.0.prompt.md +53 -0
  228. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.1.0.prompt.md +57 -0
  229. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.2.0.prompt.md +68 -0
  230. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.3.0.prompt.md +70 -0
  231. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.4.0.prompt.md +77 -0
  232. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.5.0.prompt.md +82 -0
  233. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +83 -0
  234. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.1.0.prompt.md +193 -0
  235. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +206 -0
  236. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0-deprecated.prompt.md +66 -0
  237. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0.prompt.md +43 -0
  238. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.1.0.prompt.md +46 -0
  239. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0-deprecated.prompt.md +64 -0
  240. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0.prompt.md +39 -0
  241. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.1.0.prompt.md +39 -0
  242. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.2.0.prompt.md +47 -0
  243. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +58 -0
  244. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.1.prompt.md +69 -0
  245. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +71 -0
  246. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.0.2.prompt.md +254 -0
  247. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
  248. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +283 -0
  249. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.2.prompt.md +234 -0
  250. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +244 -0
  251. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
  252. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
  253. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
  254. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
  255. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
  256. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +137 -0
  257. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
  258. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
  259. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
  260. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
  261. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
  262. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
  263. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
  264. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
  265. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
  266. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
  267. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
  268. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
  269. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
  270. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
  271. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
  272. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
  273. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
  274. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
  275. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
  276. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
  277. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
  278. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
  279. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
  280. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
  281. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
  282. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
  283. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/README.md +58 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
  289. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
  290. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +336 -0
  292. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1668 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
  296. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
  297. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/embedding_text.py +62 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
  311. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
  312. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
  313. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
  318. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +358 -0
  319. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
  320. package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
  321. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +535 -0
  322. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
  323. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +779 -0
  324. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
  325. package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +94 -0
  326. package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
  327. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +702 -0
  328. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
  329. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
  330. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
  331. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +1045 -0
  332. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
  333. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
  334. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
  335. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
  336. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
  337. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
  338. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
  339. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
  340. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
  341. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
  342. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
  343. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
  344. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
  345. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
  346. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
  347. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
  348. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +772 -0
  349. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
  350. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +737 -0
  351. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
  352. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
  353. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
  354. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +803 -0
  355. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
  356. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
  357. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +80 -0
  358. package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
  359. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +756 -0
  360. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
  361. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
  362. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
  363. package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
  364. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
  365. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
  366. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
  367. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
  368. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1298 -0
  369. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
  370. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
  371. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
  372. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
  373. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
  374. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
  375. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
  376. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
  377. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
  378. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
  379. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +384 -0
  380. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
  381. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
  382. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
  383. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
  384. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
  385. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
  386. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
  387. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
  388. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
  389. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +572 -0
  390. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
  391. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
  392. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
  393. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
  394. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
  395. package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
  396. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
  397. package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
  398. package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
  399. package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
  400. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
  401. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
  402. package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
@@ -0,0 +1,964 @@
1
+ """Interactive setup wizard for Reflexio integrations.
2
+
3
+ Note: a previous ``claude-code`` subcommand was removed; see the
4
+ submodule README migration notes for cleanup of legacy hook entries
5
+ in ``~/.claude/settings.json``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ import re
12
+ import shutil
13
+ import subprocess
14
+ import sys
15
+ from pathlib import Path
16
+ from typing import Annotated
17
+
18
+ import typer
19
+
20
+ app = typer.Typer(
21
+ help=(
22
+ "Configure Reflexio: run 'init' for plain CLI setup, use 'openclaw' "
23
+ "to install host-tool hooks, or use 'openai-codex' to configure "
24
+ "Codex OAuth tokens."
25
+ )
26
+ )
27
+
28
+ _PROVIDERS: dict[str, dict[str, str]] = {
29
+ "openai": {
30
+ "env_var": "OPENAI_API_KEY",
31
+ "model": "gpt-5.4-mini",
32
+ "display": "OpenAI",
33
+ },
34
+ "anthropic": {
35
+ "env_var": "ANTHROPIC_API_KEY",
36
+ "model": "claude-sonnet-4-6",
37
+ "display": "Anthropic",
38
+ },
39
+ "gemini": {
40
+ "env_var": "GEMINI_API_KEY",
41
+ "model": "gemini-3-flash-preview",
42
+ "display": "Gemini",
43
+ },
44
+ "deepseek": {
45
+ "env_var": "DEEPSEEK_API_KEY",
46
+ "model": "deepseek-chat",
47
+ "display": "DeepSeek",
48
+ },
49
+ "openrouter": {
50
+ "env_var": "OPENROUTER_API_KEY",
51
+ "model": "gemini-3-flash-preview",
52
+ "display": "OpenRouter",
53
+ },
54
+ "minimax": {
55
+ "env_var": "MINIMAX_API_KEY",
56
+ "model": "MiniMax-M2.7",
57
+ "display": "MiniMax",
58
+ },
59
+ "dashscope": {
60
+ "env_var": "DASHSCOPE_API_KEY",
61
+ "model": "qwen-plus",
62
+ "display": "DashScope",
63
+ },
64
+ "xai": {"env_var": "XAI_API_KEY", "model": "grok-3-mini", "display": "xAI"},
65
+ "moonshot": {
66
+ "env_var": "MOONSHOT_API_KEY",
67
+ "model": "moonshot-v1-8k",
68
+ "display": "Moonshot",
69
+ },
70
+ "zai": {"env_var": "ZAI_API_KEY", "model": "glm-4-flash", "display": "ZAI"},
71
+ }
72
+
73
+ _EMBEDDING_PROVIDERS: frozenset[str] = frozenset({"openai", "gemini"})
74
+
75
+
76
+ def _set_env_var(env_path: Path, key: str, value: str) -> None:
77
+ """Write or update an environment variable in a .env file.
78
+
79
+ Thin wrapper around :func:`reflexio.cli.env_loader.set_env_var` kept
80
+ for backward compatibility with tests that import this name.
81
+
82
+ Args:
83
+ env_path (Path): Path to the .env file.
84
+ key (str): Environment variable name.
85
+ value (str): Environment variable value.
86
+ """
87
+ from reflexio.cli.env_loader import set_env_var
88
+
89
+ set_env_var(env_path, key, value)
90
+
91
+
92
+ def _prompt_llm_provider(env_path: Path) -> tuple[str, str, str]:
93
+ """Interactively prompt the user to choose an LLM provider and API key.
94
+
95
+ Args:
96
+ env_path (Path): Path to the .env file for writing the key.
97
+
98
+ Returns:
99
+ tuple[str, str, str]: The display name, default model, and provider key
100
+ for the chosen provider.
101
+ """
102
+ provider_keys = list(_PROVIDERS.keys())
103
+
104
+ typer.echo("\nWhich LLM provider for feedback extraction?")
105
+ for idx, key in enumerate(provider_keys, 1):
106
+ display = _PROVIDERS[key]["display"]
107
+ model = _PROVIDERS[key]["model"]
108
+ typer.echo(f" [{idx}] {display:<14s} ({model})")
109
+
110
+ choice = typer.prompt("Choice", type=int)
111
+ if not 1 <= choice <= len(provider_keys):
112
+ typer.echo(f"Error: choice must be between 1 and {len(provider_keys)}")
113
+ raise typer.Exit(1)
114
+
115
+ selected_key = provider_keys[choice - 1]
116
+ provider_info = _PROVIDERS[selected_key]
117
+ env_var = provider_info["env_var"]
118
+ model = provider_info["model"]
119
+ display_name = provider_info["display"]
120
+
121
+ api_key = typer.prompt(f"Enter your {env_var}")
122
+ if not api_key.strip():
123
+ typer.echo("Error: API key cannot be empty")
124
+ raise typer.Exit(1)
125
+ _set_env_var(env_path, env_var, api_key)
126
+
127
+ return display_name, model, selected_key
128
+
129
+
130
+ # Map embedding provider keys to their canonical model names. Used by both
131
+ # the interactive prompt (writes the choice to org config) and the
132
+ # ``--embedding`` flag (skips the prompt entirely for CI). Kept here so the
133
+ # two call sites can't drift on what e.g. "gemini" actually means.
134
+ _EMBEDDING_MODEL_NAMES: dict[str, str] = {
135
+ "local": "local/minilm-l6-v2",
136
+ "openai": "text-embedding-3-small",
137
+ "gemini": "gemini/gemini-embedding-001",
138
+ }
139
+
140
+
141
+ # Valid values for the ``--embedding`` flag across every setup command.
142
+ # Defined once here so a typo in one command surface (init, openclaw)
143
+ # doesn't silently fall through to "auto" in another.
144
+ _VALID_EMBEDDING_FLAGS: frozenset[str] = frozenset(
145
+ {"auto", "local", "openai", "gemini"}
146
+ )
147
+
148
+
149
+ def _build_embedding_choices() -> list[tuple[str, str | None, str]]:
150
+ """Build the interactive embedding-provider menu at call time.
151
+
152
+ The local option is included only when ``chromadb`` is importable; built
153
+ dynamically so the menu always reflects the current Python environment
154
+ rather than a snapshot frozen at module load.
155
+
156
+ Returns:
157
+ list[tuple[str, str | None, str]]: ``(provider_key, env_var_name,
158
+ display_label)`` rows. ``env_var_name`` is ``None`` for the local
159
+ provider (no API key needed).
160
+ """
161
+ from reflexio.server.llm.providers.local_embedding_provider import (
162
+ is_chromadb_importable,
163
+ )
164
+
165
+ choices: list[tuple[str, str | None, str]] = []
166
+ if is_chromadb_importable():
167
+ choices.append(
168
+ (
169
+ "local",
170
+ None,
171
+ "Local (in-process MiniLM-L6-v2; ~25 MB; no API key needed)",
172
+ )
173
+ )
174
+ choices.extend(
175
+ [
176
+ ("openai", "OPENAI_API_KEY", "OpenAI (text-embedding-3-small)"),
177
+ ("gemini", "GEMINI_API_KEY", "Gemini (gemini-embedding-001)"),
178
+ ]
179
+ )
180
+ return choices
181
+
182
+
183
+ def _is_non_interactive() -> bool:
184
+ """Return True when prompts must be skipped (CI / scripted use).
185
+
186
+ Two triggers:
187
+
188
+ - stdin is not a TTY (``nohup``, container, pipe-fed shell)
189
+ - ``REFLEXIO_NONINTERACTIVE=1`` in the environment (explicit opt-out)
190
+ """
191
+ if os.environ.get("REFLEXIO_NONINTERACTIVE") == "1":
192
+ return True
193
+ return not sys.stdin.isatty()
194
+
195
+
196
+ def _prompt_embedding_provider(env_path: Path, llm_provider_key: str) -> str | None:
197
+ """Prompt for an embedding-capable API key if the LLM provider lacks embedding support.
198
+
199
+ Skips the prompt when the LLM provider already supports embeddings, or
200
+ when the environment is non-interactive (no TTY or
201
+ ``REFLEXIO_NONINTERACTIVE=1``). In the non-interactive case the first
202
+ available choice is returned without writing to ``.env``.
203
+
204
+ Args:
205
+ env_path (Path): Path to the .env file for writing the key.
206
+ llm_provider_key (str): The provider key selected for LLM generation.
207
+
208
+ Returns:
209
+ str | None: Display name of the embedding provider, or None if the LLM
210
+ provider already supports embeddings.
211
+ """
212
+ if llm_provider_key in _EMBEDDING_PROVIDERS:
213
+ return None
214
+
215
+ choices = _build_embedding_choices()
216
+ if not choices:
217
+ return None
218
+
219
+ # Non-interactive: pick the first available option without prompting. When
220
+ # chromadb is importable that's local (no key required); otherwise it's
221
+ # OpenAI or Gemini, which still won't have an API key but at least the
222
+ # caller knows the wizard didn't block.
223
+ if _is_non_interactive():
224
+ provider_key, env_var, _ = choices[0]
225
+ if env_var is None:
226
+ # Local needs no key — nothing to write.
227
+ return _provider_display(provider_key)
228
+ return _provider_display(provider_key)
229
+
230
+ llm_display = _PROVIDERS[llm_provider_key]["display"]
231
+ typer.echo(f"\nYour LLM provider ({llm_display}) doesn't support text embeddings.")
232
+ typer.echo("Reflexio needs an embedding model for semantic search.\n")
233
+ typer.echo("Which provider for embeddings?")
234
+ for idx, (_, _, label) in enumerate(choices, 1):
235
+ typer.echo(f" [{idx}] {label}")
236
+
237
+ choice = typer.prompt("Choice", type=int, default=1)
238
+ if not 1 <= choice <= len(choices):
239
+ typer.echo(f"Error: choice must be between 1 and {len(choices)}")
240
+ raise typer.Exit(1)
241
+
242
+ provider_key, env_var, _ = choices[choice - 1]
243
+ if env_var is None:
244
+ # Local: no API key needed.
245
+ return _provider_display(provider_key)
246
+
247
+ api_key = typer.prompt(f"Enter your {env_var}")
248
+ if not api_key.strip():
249
+ typer.echo("Error: API key cannot be empty")
250
+ raise typer.Exit(1)
251
+ _set_env_var(env_path, env_var, api_key)
252
+
253
+ return _provider_display(provider_key)
254
+
255
+
256
+ def _provider_display(provider_key: str) -> str:
257
+ """Return the user-facing display name for a provider key.
258
+
259
+ The local provider isn't in ``_PROVIDERS`` (which only lists LLM
260
+ providers), so this helper centralizes the special case.
261
+ """
262
+ if provider_key == "local":
263
+ return "Local (MiniLM-L6-v2)"
264
+ return _PROVIDERS[provider_key]["display"]
265
+
266
+
267
+ def _write_embedding_model_to_org_config(model_name: str) -> None:
268
+ """Persist the user's embedding choice to the default-org config file.
269
+
270
+ Loads the existing config, updates ``llm_config.embedding_model_name``,
271
+ and writes it back. All other fields are preserved. Reuses the same
272
+ ``LocalFileConfigStorage`` round-trip pattern as ``save_storage_to_config``.
273
+
274
+ Args:
275
+ model_name: Canonical model name to persist
276
+ (e.g. ``"local/minilm-l6-v2"``).
277
+ """
278
+ from reflexio.models.config_schema import LLMConfig
279
+ from reflexio.server.services.configurator.local_file_config_storage import (
280
+ LocalFileConfigStorage,
281
+ )
282
+
283
+ storage = LocalFileConfigStorage("self-host-org")
284
+ config = storage.load_config()
285
+ if config.llm_config is None:
286
+ config.llm_config = LLMConfig(embedding_model_name=model_name)
287
+ else:
288
+ config.llm_config.embedding_model_name = model_name
289
+ storage.save_config(config)
290
+
291
+
292
+ def _choose_embedding_provider(env_path: Path, *, embedding_flag: str) -> str | None:
293
+ """Run the upfront embedding-provider step for ``setup init``.
294
+
295
+ Behaviour matrix:
296
+
297
+ +-----------------+----------------+-------------------------------------+
298
+ | ``embedding`` | TTY? | What happens |
299
+ +=================+================+=====================================+
300
+ | ``"local"`` / | (any) | Write the matching model to org |
301
+ | ``"openai"`` / | | config; no prompt. |
302
+ | ``"gemini"`` | | |
303
+ +-----------------+----------------+-------------------------------------+
304
+ | ``"auto"`` | non-interactive| No prompt, no org-config write — |
305
+ | | | runtime auto-detection (Layer A) |
306
+ | | | picks the embedder. |
307
+ +-----------------+----------------+-------------------------------------+
308
+ | ``"auto"`` | interactive | Show the menu (default = local |
309
+ | | | when chromadb is importable). Write |
310
+ | | | the choice to org config; for |
311
+ | | | OpenAI / Gemini also collect the |
312
+ | | | API key inline. |
313
+ +-----------------+----------------+-------------------------------------+
314
+
315
+ Args:
316
+ env_path: Path to the user's .env file. Used to write the cloud
317
+ embedding API key when the user picks OpenAI / Gemini in the
318
+ interactive prompt.
319
+ embedding_flag: Value of the ``--embedding`` flag. ``"auto"`` is
320
+ the default and means "ask interactively, or fall back to
321
+ runtime auto-detection if there's no TTY."
322
+
323
+ Returns:
324
+ str | None: Display name of the chosen embedding provider, or None
325
+ when no override was written (auto + non-interactive, or no
326
+ choices available).
327
+ """
328
+ if embedding_flag in _EMBEDDING_MODEL_NAMES:
329
+ # Explicit non-default flag wins over interactive / auto-detection.
330
+ # ``--embedding=local`` requires chromadb at runtime, so refuse to
331
+ # persist a broken override the same way the interactive flow
332
+ # hides the option in that situation.
333
+ if embedding_flag == "local":
334
+ from reflexio.server.llm.providers.local_embedding_provider import (
335
+ is_chromadb_importable,
336
+ )
337
+
338
+ if not is_chromadb_importable():
339
+ typer.echo(
340
+ "Error: --embedding=local requires chromadb. "
341
+ "Install it with `pip install chromadb` or pick "
342
+ "openai/gemini/auto."
343
+ )
344
+ raise typer.Exit(1)
345
+ _write_embedding_model_to_org_config(_EMBEDDING_MODEL_NAMES[embedding_flag])
346
+ return _provider_display(embedding_flag)
347
+
348
+ # embedding_flag == "auto" from here on.
349
+ if _is_non_interactive():
350
+ # No TTY → runtime auto-detection picks the embedder. No write.
351
+ return None
352
+
353
+ choices = _build_embedding_choices()
354
+ if not choices:
355
+ # No providers available (chromadb not importable AND no cloud
356
+ # embedders in scope). Defer to runtime auto-detection, which will
357
+ # raise a clear error if nothing matches.
358
+ return None
359
+
360
+ typer.echo("\nChoose embedding provider:")
361
+ for idx, (_, _, label) in enumerate(choices, 1):
362
+ suffix = " — recommended" if idx == 1 else ""
363
+ typer.echo(f" [{idx}] {label}{suffix}")
364
+
365
+ choice = typer.prompt("Choice", type=int, default=1)
366
+ if not 1 <= choice <= len(choices):
367
+ typer.echo(f"Error: choice must be between 1 and {len(choices)}")
368
+ raise typer.Exit(1)
369
+
370
+ provider_key, env_var, _ = choices[choice - 1]
371
+
372
+ # For cloud embedders the user clearly wants that provider, so collect
373
+ # the API key inline if it isn't already set. Local has env_var=None.
374
+ # Validation runs BEFORE the org-config write so a blank API key
375
+ # leaves ``llm_config.embedding_model_name`` untouched rather than
376
+ # mutating it to a provider that still isn't configured.
377
+ if env_var is not None and not os.environ.get(env_var):
378
+ api_key = typer.prompt(f"Enter your {env_var}")
379
+ if not api_key.strip():
380
+ typer.echo("Error: API key cannot be empty")
381
+ raise typer.Exit(1)
382
+ _set_env_var(env_path, env_var, api_key)
383
+
384
+ _write_embedding_model_to_org_config(_EMBEDDING_MODEL_NAMES[provider_key])
385
+ return _provider_display(provider_key)
386
+
387
+
388
+ _LOCAL_SERVER_URL = "http://localhost:8081"
389
+
390
+
391
+ def _prompt_local_sqlite(env_path: Path) -> str:
392
+ """Option 1 — local SQLite with a local Reflexio server.
393
+
394
+ Writes ``REFLEXIO_URL`` pointing at the local server so the CLI
395
+ and any installed integration hooks (e.g., OpenClaw) know where
396
+ to connect.
397
+
398
+ Args:
399
+ env_path (Path): Path to the .env file.
400
+
401
+ Returns:
402
+ str: Storage label for the wizard summary.
403
+ """
404
+ _set_env_var(env_path, "REFLEXIO_URL", _LOCAL_SERVER_URL)
405
+ return "SQLite (local)"
406
+
407
+
408
+ def _prompt_managed_reflexio(env_path: Path) -> str:
409
+ """Option 2 — point the CLI at reflexio.ai + verify via whoami.
410
+
411
+ Prompts for a Reflexio API key, writes ``REFLEXIO_URL`` and
412
+ ``REFLEXIO_API_KEY`` to ``.env``, then calls ``whoami()`` to
413
+ verify the account and show resolved storage per-org.
414
+
415
+ Args:
416
+ env_path (Path): Path to the .env file.
417
+
418
+ Returns:
419
+ str: Storage label for the wizard summary.
420
+ """
421
+ reflexio_api_key = typer.prompt("Reflexio API key")
422
+ if not reflexio_api_key.strip():
423
+ typer.echo("Error: API key cannot be empty")
424
+ raise typer.Exit(1)
425
+
426
+ from reflexio.defaults import DEFAULT_SERVER_URL
427
+
428
+ _set_env_var(env_path, "REFLEXIO_URL", DEFAULT_SERVER_URL)
429
+ _set_env_var(env_path, "REFLEXIO_API_KEY", reflexio_api_key)
430
+
431
+ try:
432
+ from reflexio.client.client import ReflexioClient
433
+
434
+ client = ReflexioClient(
435
+ api_key=reflexio_api_key, url_endpoint=DEFAULT_SERVER_URL
436
+ )
437
+ resp = client.whoami()
438
+ except Exception as exc: # noqa: BLE001
439
+ typer.echo(f"\n (could not verify account — {type(exc).__name__}: {exc})")
440
+ return "Managed Reflexio"
441
+
442
+ if not resp.success:
443
+ typer.echo(
444
+ f"\n (account verification failed: {resp.message or 'unknown error'})"
445
+ )
446
+ return "Managed Reflexio"
447
+
448
+ # Detect the "server is in self-host mode" case. If the remote server
449
+ # returns the canonical ``self-host-org`` default org id, it means
450
+ # auth isn't being enforced — anyone hitting the endpoint without a
451
+ # token would see the same response. The user's API key was not
452
+ # actually validated, and any publishes will land in the server's
453
+ # shared default storage instead of the user's per-org Supabase.
454
+ if resp.org_id == "self-host-org":
455
+ typer.echo(
456
+ "\n ⚠ The remote server returned the default 'self-host-org' "
457
+ "identity instead of your real org."
458
+ )
459
+ typer.echo(
460
+ " Your API key was NOT validated. The server is running in "
461
+ "self-host mode, which means:"
462
+ )
463
+ typer.echo(
464
+ " • All publishes will land in the server's shared "
465
+ "storage, not your per-org Supabase."
466
+ )
467
+ typer.echo(
468
+ " • Other users hitting the same server share the same data namespace."
469
+ )
470
+ typer.echo(
471
+ " Contact the server operator to enable enterprise auth, "
472
+ "or point REFLEXIO_URL at a deployment that enforces it."
473
+ )
474
+ return "Managed Reflexio"
475
+
476
+ typer.echo("\n Verified cloud account:")
477
+ typer.echo(f" Org ID: {resp.org_id}")
478
+ typer.echo(f" Storage type: {resp.storage_type or 'unconfigured'}")
479
+ if resp.storage_label:
480
+ marker = "[configured]" if resp.storage_configured else "[unconfigured]"
481
+ typer.echo(f" Storage: {resp.storage_label} {marker}")
482
+ if not resp.storage_configured:
483
+ typer.echo(
484
+ "\n ⚠ Your org has no storage configured at "
485
+ f"{DEFAULT_SERVER_URL}/settings."
486
+ )
487
+ typer.echo(
488
+ " Publishes will succeed but no data will be written until "
489
+ "you configure it."
490
+ )
491
+
492
+ return "Managed Reflexio"
493
+
494
+
495
+ def _prompt_self_hosted(env_path: Path) -> str:
496
+ """Option 3 — point the CLI at a self-hosted Reflexio server.
497
+
498
+ Prompts for a Reflexio API key and writes ``REFLEXIO_URL`` (defaulting
499
+ to localhost) and ``REFLEXIO_API_KEY`` to ``.env``.
500
+
501
+ Args:
502
+ env_path (Path): Path to the .env file for writing credentials.
503
+
504
+ Returns:
505
+ str: Storage label for the wizard summary.
506
+ """
507
+ reflexio_url = typer.prompt("Reflexio server URL", default=_LOCAL_SERVER_URL)
508
+ reflexio_api_key = typer.prompt("Reflexio API key")
509
+ if not reflexio_api_key.strip():
510
+ typer.echo("Error: API key cannot be empty")
511
+ raise typer.Exit(1)
512
+
513
+ _set_env_var(env_path, "REFLEXIO_URL", reflexio_url)
514
+ _set_env_var(env_path, "REFLEXIO_API_KEY", reflexio_api_key)
515
+
516
+ return "Self-hosted Reflexio"
517
+
518
+
519
+ def _prompt_storage(env_path: Path) -> str:
520
+ """Interactively prompt the user to choose a storage backend.
521
+
522
+ Args:
523
+ env_path (Path): Path to the .env file to update.
524
+
525
+ Returns:
526
+ str: The storage mode label for the wizard summary.
527
+ """
528
+ typer.echo("\nWhere should Reflexio store data?")
529
+ typer.echo(" [1] Local SQLite (default, no setup needed)")
530
+ typer.echo(
531
+ " [2] Managed Reflexio (reflexio.ai — storage managed at reflexio.ai/settings)"
532
+ )
533
+ typer.echo(" [3] Self-hosted Reflexio (connect to your own server)")
534
+
535
+ choice = typer.prompt("Choice", type=int, default=1)
536
+ if choice == 1:
537
+ return _prompt_local_sqlite(env_path)
538
+ if choice == 2:
539
+ return _prompt_managed_reflexio(env_path)
540
+ if choice == 3:
541
+ return _prompt_self_hosted(env_path)
542
+
543
+ typer.echo("Error: choice must be 1, 2, or 3")
544
+ raise typer.Exit(1)
545
+
546
+
547
+ def _install_openclaw_integration() -> bool:
548
+ """Install the Reflexio plugin into OpenClaw via the plugin system.
549
+
550
+ Returns:
551
+ bool: True if the plugin was verified as registered.
552
+
553
+ Raises:
554
+ typer.Exit: If the openclaw CLI is not found on PATH.
555
+ """
556
+ if not shutil.which("openclaw"):
557
+ typer.echo("Error: openclaw CLI not found. Install from https://openclaw.ai")
558
+ raise typer.Exit(1)
559
+
560
+ import reflexio
561
+
562
+ pkg_dir = Path(reflexio.__file__).parent
563
+ plugin_dir = pkg_dir / "integrations" / "openclaw" / "plugin"
564
+
565
+ if not plugin_dir.exists():
566
+ typer.echo(f"Error: plugin directory not found at {plugin_dir}")
567
+ raise typer.Exit(1)
568
+
569
+ # Clean install: remove any existing installation and stale extension dir
570
+ subprocess.run(
571
+ ["openclaw", "plugins", "uninstall", "--force", "reflexio-federated"],
572
+ check=False,
573
+ capture_output=True,
574
+ text=True,
575
+ )
576
+ stale_ext = Path.home() / ".openclaw" / "extensions" / "reflexio-federated"
577
+ shutil.rmtree(stale_ext, ignore_errors=True)
578
+
579
+ # Install plugin and restart gateway so inspect sees the new state
580
+ try:
581
+ subprocess.run(
582
+ ["openclaw", "plugins", "install", str(plugin_dir)],
583
+ check=True,
584
+ capture_output=True,
585
+ text=True,
586
+ )
587
+ subprocess.run(
588
+ ["openclaw", "plugins", "enable", "reflexio-federated"],
589
+ check=True,
590
+ capture_output=True,
591
+ text=True,
592
+ )
593
+ subprocess.run(
594
+ ["openclaw", "gateway", "restart"],
595
+ check=True,
596
+ capture_output=True,
597
+ text=True,
598
+ )
599
+ except subprocess.CalledProcessError as exc:
600
+ typer.echo(f"Error: openclaw command failed: {exc.stderr or exc.stdout}")
601
+ raise typer.Exit(1) from exc
602
+
603
+ # Verify — match exact "Status: loaded" to avoid false positives from
604
+ # "not loaded" or "unloaded"
605
+ result = subprocess.run(
606
+ ["openclaw", "plugins", "inspect", "reflexio-federated"],
607
+ capture_output=True,
608
+ text=True,
609
+ )
610
+ if re.search(r"Status:\s*loaded\b", result.stdout):
611
+ typer.echo("Plugin installed and registered")
612
+ return True
613
+
614
+ typer.echo(
615
+ "Error: Plugin not loaded -- check 'openclaw plugins inspect reflexio-federated'"
616
+ )
617
+ return False
618
+
619
+
620
+ def _uninstall_openclaw() -> None:
621
+ """Remove the Reflexio integration from OpenClaw."""
622
+ typer.confirm(
623
+ "This will remove the Reflexio integration from OpenClaw. Continue?",
624
+ abort=True,
625
+ )
626
+ if shutil.which("openclaw"):
627
+ subprocess.run(
628
+ ["openclaw", "plugins", "disable", "reflexio-federated"],
629
+ check=False,
630
+ capture_output=True,
631
+ text=True,
632
+ )
633
+ subprocess.run(
634
+ ["openclaw", "plugins", "uninstall", "--force", "reflexio-federated"],
635
+ check=False,
636
+ capture_output=True,
637
+ text=True,
638
+ )
639
+ else:
640
+ typer.echo("Warning: openclaw CLI not found on PATH, skipping plugin removal")
641
+
642
+ # Remove setup markers
643
+ from reflexio.cli.paths import reflexio_home
644
+
645
+ reflexio_dir = reflexio_home()
646
+ if reflexio_dir.exists():
647
+ for marker in reflexio_dir.glob(".setup_complete_*"):
648
+ marker.unlink(missing_ok=True)
649
+ typer.echo(f"Removed setup marker: {marker}")
650
+
651
+ typer.echo("Reflexio integration fully removed from OpenClaw.")
652
+
653
+
654
+ @app.command("openclaw")
655
+ def openclaw(
656
+ uninstall: Annotated[
657
+ bool,
658
+ typer.Option(
659
+ "--uninstall", help="Remove the Reflexio integration from OpenClaw"
660
+ ),
661
+ ] = False,
662
+ embedding: Annotated[
663
+ str,
664
+ typer.Option(
665
+ "--embedding",
666
+ help=(
667
+ "Embedding provider: 'local' (in-process MiniLM), 'openai', "
668
+ "'gemini', or 'auto' (default — let runtime auto-detection "
669
+ "pick). Skips the interactive prompt."
670
+ ),
671
+ ),
672
+ ] = "auto",
673
+ ) -> None:
674
+ """Set up (or remove) the Reflexio integration for OpenClaw."""
675
+ if uninstall:
676
+ _uninstall_openclaw()
677
+ return
678
+
679
+ if embedding not in _VALID_EMBEDDING_FLAGS:
680
+ typer.echo(
681
+ f"Error: --embedding must be one of "
682
+ f"{sorted(_VALID_EMBEDDING_FLAGS)}, got {embedding!r}"
683
+ )
684
+ raise typer.Exit(1)
685
+
686
+ # Step 1: Load .env path. Always target ~/.reflexio/.env — running setup
687
+ # from a worktree or project root that happens to contain its own .env
688
+ # would otherwise pollute that file via load_reflexio_env's CWD-first
689
+ # search. Setup writes are user-global, not project-local.
690
+ from reflexio.cli.env_loader import ensure_user_env_for_setup
691
+
692
+ env_path = ensure_user_env_for_setup()
693
+ if env_path is None:
694
+ typer.echo("Error: could not locate or create a .env file")
695
+ raise typer.Exit(1)
696
+
697
+ # Step 2: LLM provider
698
+ display_name, model, _provider_key = _prompt_llm_provider(env_path)
699
+
700
+ # Step 3: Storage. Decided BEFORE the embedding step because Managed /
701
+ # Self-hosted modes own their own embedding config server-side, and a
702
+ # local override would just shadow the operator's choice.
703
+ storage_label = _prompt_storage(env_path)
704
+
705
+ # Step 3.5: Upfront embedding-provider step. Local is the default when
706
+ # chromadb is importable; the choice persists to org config so it
707
+ # survives later cloud-key changes. Skipped for remote storage modes
708
+ # for the reason above.
709
+ is_remote = storage_label in {"Managed Reflexio", "Self-hosted Reflexio"}
710
+ embedding_label: str | None = None
711
+ if not is_remote:
712
+ embedding_label = _choose_embedding_provider(env_path, embedding_flag=embedding)
713
+
714
+ # Step 4: Install OpenClaw integration
715
+ typer.echo("")
716
+ hook_ok = _install_openclaw_integration()
717
+
718
+ # Step 5: Summary
719
+ hook_status = "reflexio-federated" if hook_ok else "reflexio-federated (unverified)"
720
+
721
+ typer.echo("")
722
+ typer.echo("Setup complete!")
723
+ typer.echo(f" LLM Provider: {display_name} ({model})")
724
+ if embedding_label:
725
+ typer.echo(f" Embedding Provider: {embedding_label}")
726
+ typer.echo(f" Storage: {storage_label}")
727
+ typer.echo(f" Plugin: {hook_status}")
728
+ typer.echo("")
729
+ typer.echo("Next steps:")
730
+ typer.echo(" 1. Restart OpenClaw gateway: openclaw gateway restart")
731
+ typer.echo(
732
+ " 2. Start a conversation -- Reflexio will capture and learn automatically"
733
+ )
734
+
735
+
736
+ # ---------------------------------------------------------------------------
737
+ # Generic (integration-less) setup
738
+ # ---------------------------------------------------------------------------
739
+
740
+
741
+ @app.command("init")
742
+ def init(
743
+ skip_llm: Annotated[
744
+ bool,
745
+ typer.Option(
746
+ "--skip-llm",
747
+ help=(
748
+ "Skip the LLM provider prompt (use when you're only "
749
+ "going to publish to a managed Reflexio server, which "
750
+ "manages its own LLM keys server-side)"
751
+ ),
752
+ ),
753
+ ] = False,
754
+ embedding: Annotated[
755
+ str,
756
+ typer.Option(
757
+ "--embedding",
758
+ help=(
759
+ "Embedding provider: 'local' (in-process MiniLM), 'openai', "
760
+ "'gemini', or 'auto' (default — let runtime auto-detection "
761
+ "pick). Skips the interactive prompt."
762
+ ),
763
+ ),
764
+ ] = "auto",
765
+ ) -> None:
766
+ """Configure Reflexio without installing any integration.
767
+
768
+ Writes ``REFLEXIO_URL`` / ``REFLEXIO_API_KEY`` / LLM provider keys
769
+ / storage backend into ``~/.reflexio/.env``. This is the command
770
+ to run if you're using the ``reflexio`` CLI directly from your
771
+ shell and don't need the OpenClaw hook installation.
772
+
773
+ Under the hood it reuses the same ``_prompt_storage`` +
774
+ ``_prompt_llm_provider`` helpers the integration setup commands
775
+ use, so the flow and the resulting ``.env`` are identical to what
776
+ you'd get from those commands minus the hook-installation step.
777
+
778
+ Args:
779
+ skip_llm: When True, skip the LLM provider prompt. Useful if
780
+ you're only going to point the CLI at a managed Reflexio
781
+ server, which handles extraction with its own LLM keys.
782
+ embedding: Embedding-provider selector for non-interactive use.
783
+ ``"auto"`` (default) leaves the choice to runtime
784
+ auto-detection. ``"local"`` / ``"openai"`` / ``"gemini"``
785
+ persist the corresponding model to org config and skip the
786
+ prompt. Honors ``REFLEXIO_NONINTERACTIVE=1`` (skips the
787
+ prompt and behaves as ``"auto"`` when the flag is left at
788
+ its default).
789
+ """
790
+ if embedding not in _VALID_EMBEDDING_FLAGS:
791
+ typer.echo(
792
+ f"Error: --embedding must be one of "
793
+ f"{sorted(_VALID_EMBEDDING_FLAGS)}, got {embedding!r}"
794
+ )
795
+ raise typer.Exit(1)
796
+
797
+ # Always target ~/.reflexio/.env — see ensure_user_env_for_setup docstring
798
+ # for why we don't honor a CWD-local .env in setup commands.
799
+ from reflexio.cli.env_loader import ensure_user_env_for_setup
800
+
801
+ env_path = ensure_user_env_for_setup()
802
+ if env_path is None:
803
+ typer.echo("Error: could not locate or create a .env file")
804
+ raise typer.Exit(1)
805
+
806
+ # Step 1: Storage (ask first — managed mode doesn't need an LLM key)
807
+ storage_label = _prompt_storage(env_path)
808
+
809
+ # Step 2: LLM provider (skipped for managed mode — the remote server
810
+ # handles extraction so the local .env doesn't need an LLM key).
811
+ # Also skipped when the user explicitly passes --skip-llm.
812
+ is_managed = storage_label == "Managed Reflexio"
813
+ is_remote = storage_label in {"Managed Reflexio", "Self-hosted Reflexio"}
814
+ display_name: str | None = None
815
+ model: str | None = None
816
+ embedding_label: str | None = None
817
+ if is_managed:
818
+ typer.echo(
819
+ "\nSkipping LLM provider — Managed Reflexio handles "
820
+ "extraction server-side with its own model keys."
821
+ )
822
+ elif skip_llm:
823
+ typer.echo("\nSkipping LLM provider per --skip-llm.")
824
+ else:
825
+ display_name, model, _ = _prompt_llm_provider(env_path)
826
+
827
+ # Step 2.5: Upfront embedding-provider step. Local is the default when
828
+ # chromadb is importable; the choice is persisted to org config so it
829
+ # survives later cloud-key changes. Skipped for both Managed and
830
+ # Self-hosted modes — the remote server owns its own model config and
831
+ # a local override would just shadow whatever the operator set there.
832
+ # Replaces the legacy ``_prompt_embedding_provider`` call here — that
833
+ # helper still exists for the ``services start`` first-run wizard.
834
+ if not is_remote:
835
+ embedding_label = _choose_embedding_provider(env_path, embedding_flag=embedding)
836
+
837
+ # Step 3: Summary — no integration to print
838
+ typer.echo("")
839
+ typer.echo("Setup complete!")
840
+ if display_name and model:
841
+ typer.echo(f" LLM Provider: {display_name} ({model})")
842
+ if embedding_label:
843
+ typer.echo(f" Embedding Provider: {embedding_label}")
844
+ typer.echo(f" Storage: {storage_label}")
845
+ typer.echo(f" .env: {env_path}")
846
+ typer.echo("")
847
+ typer.echo(
848
+ "Next: run 'reflexio status whoami' to verify the connection "
849
+ "(managed mode) or 'reflexio services start' to launch the "
850
+ "local backend (SQLite / self-hosted mode)."
851
+ )
852
+
853
+
854
+ @app.command("openai-codex")
855
+ def openai_codex_setup(
856
+ no_browser: Annotated[
857
+ bool,
858
+ typer.Option(
859
+ "--no-browser",
860
+ help="Don't auto-open the browser; print the URL to copy/paste instead.",
861
+ ),
862
+ ] = False,
863
+ timeout: Annotated[
864
+ int,
865
+ typer.Option(
866
+ "--timeout",
867
+ help="Seconds to wait for the OAuth callback before failing.",
868
+ ),
869
+ ] = 300,
870
+ show: Annotated[
871
+ bool,
872
+ typer.Option(
873
+ "--show",
874
+ help="Print currently saved Codex token metadata and exit (no login).",
875
+ ),
876
+ ] = False,
877
+ logout: Annotated[
878
+ bool,
879
+ typer.Option(
880
+ "--logout",
881
+ help="Delete the saved Codex token file and exit.",
882
+ ),
883
+ ] = False,
884
+ ) -> None:
885
+ """Sign in to OpenAI via your ChatGPT subscription (Codex OAuth).
886
+
887
+ Stores access + refresh tokens at ``~/.reflexio/auth/openai-codex.json``.
888
+ The codex proxy and any other reflexio component that needs OpenAI auth
889
+ reads from this file directly — no dependency on OpenClaw or any other
890
+ CLI. The proxy auto-refreshes the access token when it nears expiry.
891
+
892
+ Run this once; the codex proxy (``codex_proxy.py``) then picks up the
893
+ stored tokens automatically on start.
894
+
895
+ Re-run this command if your subscription tier changes or the
896
+ refresh_token gets revoked (rare).
897
+ """
898
+ # Imported here so plain `reflexio --help` doesn't require the OAuth
899
+ # module to load (slight startup speedup; mostly cosmetic).
900
+ from reflexio.cli.codex_auth import (
901
+ REFLEXIO_CODEX_TOKENS_PATH,
902
+ get_fresh_tokens,
903
+ load_tokens_raw,
904
+ login_interactive,
905
+ )
906
+
907
+ if logout:
908
+ if REFLEXIO_CODEX_TOKENS_PATH.exists():
909
+ REFLEXIO_CODEX_TOKENS_PATH.unlink()
910
+ typer.echo(f"Removed {REFLEXIO_CODEX_TOKENS_PATH}")
911
+ else:
912
+ typer.echo("No saved Codex tokens to remove.")
913
+ return
914
+
915
+ if show:
916
+ tokens = load_tokens_raw()
917
+ if tokens is None:
918
+ typer.echo(f"No tokens at {REFLEXIO_CODEX_TOKENS_PATH}.")
919
+ typer.echo("Run `reflexio setup openai-codex` to sign in.")
920
+ raise typer.Exit(1)
921
+ typer.echo(f" path: {REFLEXIO_CODEX_TOKENS_PATH}")
922
+ typer.echo(f" email: {tokens.email}")
923
+ typer.echo(f" plan_type: {tokens.plan_type}")
924
+ typer.echo(
925
+ f" account_id ...{tokens.account_id[-8:]}"
926
+ if tokens.account_id
927
+ else " account_id (empty)"
928
+ )
929
+ typer.echo(f" expires_at: {tokens.expires_at} (unix epoch)")
930
+ typer.echo(f" expired: {tokens.is_expired()}")
931
+ return
932
+
933
+ typer.echo("Starting OpenAI Codex OAuth flow...")
934
+ try:
935
+ tokens = login_interactive(
936
+ open_browser=not no_browser,
937
+ timeout_s=timeout,
938
+ )
939
+ except TimeoutError as e:
940
+ typer.echo(f"Timed out: {e}")
941
+ raise typer.Exit(1) from e
942
+ except ValueError as e:
943
+ typer.echo(f"Login failed: {e}")
944
+ raise typer.Exit(1) from e
945
+
946
+ typer.echo("")
947
+ typer.echo("Sign-in successful.")
948
+ typer.echo(f" saved to: {REFLEXIO_CODEX_TOKENS_PATH}")
949
+ if tokens.email:
950
+ typer.echo(f" email: {tokens.email}")
951
+ typer.echo(f" plan_type: {tokens.plan_type}")
952
+ typer.echo("")
953
+ typer.echo("Verify the token resolves cleanly via the proxy's health endpoint:")
954
+ typer.echo(" curl -s http://127.0.0.1:11435/health | jq")
955
+ typer.echo("")
956
+ typer.echo(
957
+ "If the saved plan_type doesn't match what you expect (e.g. shows "
958
+ "'plus' instead of 'max-x20'), wait a minute for OpenAI to propagate "
959
+ "the subscription change and re-run this command — the JWT is issued "
960
+ "at sign-in time."
961
+ )
962
+ # Exercise the refresh path immediately so any clock skew between the
963
+ # JWT's `exp` claim and our local clock is caught now, not at first use.
964
+ _ = get_fresh_tokens()