claude-smart 0.2.44 → 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.
- package/.claude-plugin/marketplace.json +3 -3
- package/README.md +34 -5
- package/bin/claude-smart.js +295 -5
- package/package.json +22 -3
- package/plugin/.claude-plugin/plugin.json +4 -2
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/README.md +22 -2
- package/plugin/commands/clear-all.md +1 -0
- package/plugin/commands/dashboard.md +1 -0
- package/plugin/commands/learn.md +1 -0
- package/plugin/commands/restart.md +1 -0
- package/plugin/commands/show.md +1 -0
- package/plugin/dashboard/app/configure/env/page.tsx +40 -14
- package/plugin/dashboard/app/configure/server/page.tsx +51 -1
- package/plugin/dashboard/app/preferences/[id]/page.tsx +8 -8
- package/plugin/dashboard/app/skills/project/[id]/page.tsx +7 -3
- package/plugin/dashboard/app/skills/shared/[id]/page.tsx +10 -3
- package/plugin/dashboard/lib/claude-settings-file.ts +20 -10
- package/plugin/dashboard/lib/reflexio-client.ts +16 -0
- package/plugin/dashboard/lib/status.ts +10 -3
- package/plugin/dashboard/lib/types.ts +18 -6
- package/plugin/hooks/codex-hooks.json +0 -1
- package/plugin/opencode/assistant-buffer.ts +108 -0
- package/plugin/opencode/dist/assistant-buffer.js +96 -0
- package/plugin/opencode/dist/internal.js +12 -0
- package/plugin/opencode/dist/payload.js +85 -0
- package/plugin/opencode/dist/server.mjs +158 -0
- package/plugin/opencode/internal.ts +18 -0
- package/plugin/opencode/package.json +3 -0
- package/plugin/opencode/payload.ts +90 -0
- package/plugin/opencode/server.mts +174 -0
- package/plugin/opencode/tsconfig.json +13 -0
- package/plugin/pyproject.toml +20 -3
- package/plugin/scripts/_lib.sh +77 -29
- package/plugin/scripts/backend-service.sh +27 -5
- package/plugin/scripts/dashboard-service.sh +7 -5
- package/plugin/scripts/ensure-plugin-root.sh +4 -4
- package/plugin/scripts/hook_entry.sh +3 -3
- package/plugin/scripts/opencode-claude-compat +4 -0
- package/plugin/scripts/opencode-claude-compat.cmd +3 -0
- package/plugin/scripts/opencode-claude-compat.js +225 -0
- package/plugin/scripts/smart-install.sh +10 -8
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +304 -6
- package/plugin/src/claude_smart/env_config.py +12 -4
- package/plugin/src/claude_smart/events/session_start.py +26 -7
- package/plugin/src/claude_smart/events/stop.py +1 -1
- package/plugin/src/claude_smart/ids.py +1 -1
- package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
- package/plugin/src/claude_smart/runtime.py +7 -1
- package/plugin/uv.lock +1 -1
- package/plugin/vendor/reflexio/.env.example +54 -30
- package/plugin/vendor/reflexio/README.md +14 -8
- package/plugin/vendor/reflexio/pyproject.toml +13 -1
- package/plugin/vendor/reflexio/reflexio/README.md +1 -0
- package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
- package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
- package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
- package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
- package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
- package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
- package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +210 -50
- package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
- package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
- package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
- package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
- package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
- package/plugin/vendor/reflexio/reflexio/client/client.py +57 -13
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
- package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +238 -10
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +16 -5
- package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +198 -6
- package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +29 -20
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +2 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
- package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +52 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +88 -7
- package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
- package/plugin/vendor/reflexio/reflexio/server/README.md +45 -32
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
- package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
- package/plugin/vendor/reflexio/reflexio/server/_auth.py +65 -2
- package/plugin/vendor/reflexio/reflexio/server/api.py +734 -85
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +3 -1
- package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
- package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
- package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
- package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
- package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
- package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +266 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +26 -11
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
- package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +39 -16
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +193 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
- package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +11 -12
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +316 -178
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +84 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
- package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +30 -22
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
- package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +83 -6
- package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +27 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +642 -197
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +61 -104
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +628 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +978 -184
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +519 -128
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +77 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +131 -20
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +36 -53
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +243 -7
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +121 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +60 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +229 -32
- package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
- package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
- package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
- package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
- package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
- package/scripts/setup-claude-smart.sh +8 -3
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
- /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
- /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
- /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
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
230
|
+
for env_path in _env_search_paths():
|
|
120
231
|
if env_path.exists():
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
260
|
-
|
|
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: {
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
545
|
+
target.write_text(content)
|
|
546
|
+
target.chmod(0o600)
|
|
547
|
+
_load_dotenv_pruned(target)
|
|
278
548
|
|
|
279
|
-
sys.stdout.write(f"Created env file: {
|
|
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 {
|
|
552
|
+
sys.stdout.write(f" Edit {target} to add your API keys.\n\n")
|
|
283
553
|
sys.stdout.flush()
|
|
284
|
-
return
|
|
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
|
-
|
|
198
|
-
|
|
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 =
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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
|
-
|
|
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
|
|
8
|
-
|
|
9
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|