claude-smart 0.2.45 → 0.2.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +5 -1
- package/plugin/scripts/backend-service.sh +22 -2
- package/plugin/scripts/ensure-plugin-root.sh +4 -4
- package/plugin/scripts/hook_entry.sh +1 -1
- 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
package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
"""User-facing CLI for openclaw-smart.
|
|
2
|
+
|
|
3
|
+
Exposes the following subcommands:
|
|
4
|
+
|
|
5
|
+
- ``show``: print current project-specific skills and project preferences
|
|
6
|
+
(as markdown).
|
|
7
|
+
- ``learn``: publish unpublished interactions and force reflexio extraction
|
|
8
|
+
now over the active session buffer.
|
|
9
|
+
- ``restart``: stop and restart the reflexio backend + dashboard services
|
|
10
|
+
so local edits take effect without restarting openClaw.
|
|
11
|
+
- ``clear-all``: delete all local reflexio data and openclaw-smart session
|
|
12
|
+
buffers.
|
|
13
|
+
|
|
14
|
+
Installation/uninstallation is intentionally NOT exposed here — those flows
|
|
15
|
+
live in ``reflexio setup openclaw`` (parent reflexio CLI) and are managed by
|
|
16
|
+
the openClaw plugin system directly.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
import shutil
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
import time
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
from openclaw_smart import context_format, ids, publish, state
|
|
32
|
+
from openclaw_smart.reflexio_adapter import Adapter
|
|
33
|
+
|
|
34
|
+
_REFLEXIO_ENV_PATH = Path.home() / ".reflexio" / ".env"
|
|
35
|
+
_REFLEXIO_UNREACHABLE_MSG = (
|
|
36
|
+
"Failed to reach reflexio. Check ~/.openclaw-smart/backend.log "
|
|
37
|
+
"or restart openClaw.\n"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# plugin/src/openclaw_smart/cli.py -> parents[2] is plugin/
|
|
41
|
+
_THIS_DIR = Path(__file__).resolve().parent
|
|
42
|
+
_PLUGIN_ROOT = _THIS_DIR.parents[2]
|
|
43
|
+
_SCRIPTS_DIR = _PLUGIN_ROOT / "scripts"
|
|
44
|
+
_DASHBOARD_DIR = _PLUGIN_ROOT / "dashboard"
|
|
45
|
+
_BACKEND_SCRIPT = _SCRIPTS_DIR / "backend-service.sh"
|
|
46
|
+
_DASHBOARD_SCRIPT = _SCRIPTS_DIR / "dashboard-service.sh"
|
|
47
|
+
_REFLEXIO_DIR = Path.home() / ".reflexio"
|
|
48
|
+
_DEFAULT_STORAGE_ROOT = _REFLEXIO_DIR / "data"
|
|
49
|
+
_REFLEXIO_CONFIG_PATH = _REFLEXIO_DIR / "configs" / "config_self-host-org.json"
|
|
50
|
+
_LOCAL_STORAGE_ENV = "LOCAL_STORAGE_PATH"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _latest_session_id() -> str | None:
|
|
54
|
+
"""Most-recently-modified session JSONL in the state dir. None if none exist."""
|
|
55
|
+
root = state.state_dir()
|
|
56
|
+
if not root.is_dir():
|
|
57
|
+
return None
|
|
58
|
+
files = sorted(root.glob("*.jsonl"), key=lambda p: p.stat().st_mtime, reverse=True)
|
|
59
|
+
if not files:
|
|
60
|
+
return None
|
|
61
|
+
return files[0].stem
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def cmd_show(args: argparse.Namespace) -> int:
|
|
65
|
+
"""Print this project's skills + preferences, plus globally-shared skills.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
args (argparse.Namespace): Parsed CLI args. Honors ``args.project``
|
|
69
|
+
(override project id for the project-scoped fetches).
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
int: 0 on success.
|
|
73
|
+
"""
|
|
74
|
+
project_id = args.project or ids.resolve_project_id()
|
|
75
|
+
adapter = Adapter()
|
|
76
|
+
user_playbooks, agent_playbooks, profiles = adapter.fetch_all(
|
|
77
|
+
project_id=project_id,
|
|
78
|
+
user_playbook_top_k=3,
|
|
79
|
+
agent_playbook_top_k=3,
|
|
80
|
+
profile_top_k=3,
|
|
81
|
+
)
|
|
82
|
+
md = context_format.render(
|
|
83
|
+
project_id=project_id,
|
|
84
|
+
user_playbooks=user_playbooks,
|
|
85
|
+
agent_playbooks=agent_playbooks,
|
|
86
|
+
profiles=profiles,
|
|
87
|
+
)
|
|
88
|
+
sys.stdout.write(
|
|
89
|
+
md or f"_No skills or preferences yet for project `{project_id}`._\n"
|
|
90
|
+
)
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def cmd_learn(args: argparse.Namespace) -> int:
|
|
95
|
+
"""Force reflexio extraction over the active session's interactions.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
args (argparse.Namespace): Parsed CLI args. Honors ``args.session``
|
|
99
|
+
(defaults to most-recent), ``args.project`` (defaults to
|
|
100
|
+
``ids.resolve_project_id()``), and ``args.note`` (free-form
|
|
101
|
+
text appended as a User turn before publish).
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
int: 0 on success or no-op, 1 if reflexio is unreachable.
|
|
105
|
+
"""
|
|
106
|
+
session_id = args.session or _latest_session_id()
|
|
107
|
+
if not session_id:
|
|
108
|
+
sys.stdout.write("No active openclaw-smart session buffer found.\n")
|
|
109
|
+
return 0
|
|
110
|
+
project_id = args.project or ids.resolve_project_id()
|
|
111
|
+
|
|
112
|
+
note = (args.note or "").strip()
|
|
113
|
+
if note:
|
|
114
|
+
state.append(
|
|
115
|
+
session_id,
|
|
116
|
+
{
|
|
117
|
+
"ts": int(time.time()),
|
|
118
|
+
"role": "User",
|
|
119
|
+
"content": note,
|
|
120
|
+
"user_id": project_id,
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
status, count = publish.publish_unpublished(
|
|
125
|
+
session_id=session_id,
|
|
126
|
+
project_id=project_id,
|
|
127
|
+
force_extraction=True,
|
|
128
|
+
skip_aggregation=False,
|
|
129
|
+
)
|
|
130
|
+
if status == "ok":
|
|
131
|
+
suffix = " (including your note)" if note else ""
|
|
132
|
+
sys.stdout.write(
|
|
133
|
+
f"Forced extraction on session `{session_id}` over {count} interactions{suffix}.\n"
|
|
134
|
+
)
|
|
135
|
+
return 0
|
|
136
|
+
if status == "nothing":
|
|
137
|
+
sys.stdout.write(f"No unpublished interactions on session `{session_id}`.\n")
|
|
138
|
+
return 0
|
|
139
|
+
sys.stdout.write(_REFLEXIO_UNREACHABLE_MSG)
|
|
140
|
+
return 1
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _run_service(script: Path, subcmd: str) -> int:
|
|
144
|
+
"""Invoke a service script (``backend-service.sh`` / ``dashboard-service.sh``).
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
script (Path): Absolute path to the service shell script.
|
|
148
|
+
subcmd (str): Subcommand to pass (``start``, ``stop``, ``status``).
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
int: The script's exit code, or 1 if the script is missing.
|
|
152
|
+
"""
|
|
153
|
+
if not script.exists():
|
|
154
|
+
sys.stderr.write(f"error: {script} not found\n")
|
|
155
|
+
return 1
|
|
156
|
+
try:
|
|
157
|
+
subprocess.run([str(script), subcmd], check=True)
|
|
158
|
+
return 0
|
|
159
|
+
except subprocess.CalledProcessError as exc:
|
|
160
|
+
return exc.returncode or 1
|
|
161
|
+
except OSError as exc:
|
|
162
|
+
# Script lost executable bit, permission denied, missing interpreter, etc.
|
|
163
|
+
sys.stderr.write(f"error: failed to execute {script}: {exc}\n")
|
|
164
|
+
return 1
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _service_status(script: Path, wait_ready_s: float = 3.0) -> str:
|
|
168
|
+
"""Return the one-line status string for a service script."""
|
|
169
|
+
if not script.exists():
|
|
170
|
+
return "script missing"
|
|
171
|
+
deadline = time.monotonic() + wait_ready_s
|
|
172
|
+
while True:
|
|
173
|
+
try:
|
|
174
|
+
result = subprocess.run(
|
|
175
|
+
[str(script), "status"], capture_output=True, text=True, check=False
|
|
176
|
+
)
|
|
177
|
+
except OSError as exc:
|
|
178
|
+
return f"script error: {exc}"
|
|
179
|
+
status = result.stdout.strip() or "unknown"
|
|
180
|
+
if status != "not running" or time.monotonic() >= deadline:
|
|
181
|
+
return status
|
|
182
|
+
time.sleep(0.2)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _is_running_status(status: str) -> bool:
|
|
186
|
+
return status.startswith("running on ")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def cmd_restart(args: argparse.Namespace) -> int:
|
|
190
|
+
"""Restart the reflexio backend and openclaw-smart dashboard services.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
args (argparse.Namespace): Parsed CLI args. Honors
|
|
194
|
+
``args.skip_backend``, ``args.skip_dashboard``, and
|
|
195
|
+
``args.no_rebuild``.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
int: 0 on success, non-zero if the dashboard rebuild fails or
|
|
199
|
+
either service's ``start`` subcommand exits non-zero.
|
|
200
|
+
"""
|
|
201
|
+
do_backend = not args.skip_backend
|
|
202
|
+
do_dashboard = not args.skip_dashboard
|
|
203
|
+
|
|
204
|
+
if not (do_backend or do_dashboard):
|
|
205
|
+
sys.stdout.write("Nothing to restart (both services skipped).\n")
|
|
206
|
+
return 0
|
|
207
|
+
|
|
208
|
+
if do_backend:
|
|
209
|
+
sys.stdout.write("Stopping reflexio backend…\n")
|
|
210
|
+
_run_service(_BACKEND_SCRIPT, "stop")
|
|
211
|
+
if do_dashboard:
|
|
212
|
+
sys.stdout.write("Stopping dashboard…\n")
|
|
213
|
+
_run_service(_DASHBOARD_SCRIPT, "stop")
|
|
214
|
+
|
|
215
|
+
if do_dashboard and not args.no_rebuild and _DASHBOARD_DIR.is_dir():
|
|
216
|
+
rc = _rebuild_dashboard()
|
|
217
|
+
if rc != 0:
|
|
218
|
+
if do_backend:
|
|
219
|
+
_run_service(_BACKEND_SCRIPT, "start")
|
|
220
|
+
return rc
|
|
221
|
+
|
|
222
|
+
start_rc = 0
|
|
223
|
+
if do_backend:
|
|
224
|
+
sys.stdout.write("Starting reflexio backend…\n")
|
|
225
|
+
rc = _run_service(_BACKEND_SCRIPT, "start")
|
|
226
|
+
if rc != 0:
|
|
227
|
+
sys.stderr.write(f"error: reflexio backend failed to start (exit {rc})\n")
|
|
228
|
+
start_rc = rc
|
|
229
|
+
if do_dashboard:
|
|
230
|
+
sys.stdout.write("Starting dashboard…\n")
|
|
231
|
+
rc = _run_service(_DASHBOARD_SCRIPT, "start")
|
|
232
|
+
if rc != 0:
|
|
233
|
+
sys.stderr.write(f"error: dashboard failed to start (exit {rc})\n")
|
|
234
|
+
start_rc = start_rc or rc
|
|
235
|
+
|
|
236
|
+
sys.stdout.write("\n")
|
|
237
|
+
if do_backend:
|
|
238
|
+
sys.stdout.write(f"reflexio backend: {_service_status(_BACKEND_SCRIPT)}\n")
|
|
239
|
+
if do_dashboard:
|
|
240
|
+
sys.stdout.write(f"dashboard: {_service_status(_DASHBOARD_SCRIPT)}\n")
|
|
241
|
+
return start_rc
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _rebuild_dashboard() -> int:
|
|
245
|
+
"""Rebuild the dashboard Next.js bundle, installing deps if needed."""
|
|
246
|
+
if not shutil.which("npm"):
|
|
247
|
+
sys.stderr.write("warning: npm not on PATH; serving previous build\n")
|
|
248
|
+
return 0
|
|
249
|
+
next_bin = _DASHBOARD_DIR / "node_modules" / ".bin" / "next"
|
|
250
|
+
if not next_bin.exists():
|
|
251
|
+
install_cmd = (
|
|
252
|
+
["npm", "ci", "--no-audit", "--no-fund"]
|
|
253
|
+
if (_DASHBOARD_DIR / "package-lock.json").exists()
|
|
254
|
+
else ["npm", "install", "--no-audit", "--no-fund"]
|
|
255
|
+
)
|
|
256
|
+
sys.stdout.write(
|
|
257
|
+
f"Installing dashboard dependencies ({' '.join(install_cmd)})…\n"
|
|
258
|
+
)
|
|
259
|
+
try:
|
|
260
|
+
subprocess.run(install_cmd, cwd=_DASHBOARD_DIR, check=True)
|
|
261
|
+
except subprocess.CalledProcessError as exc:
|
|
262
|
+
sys.stderr.write(
|
|
263
|
+
f"error: dashboard install failed (exit {exc.returncode})\n"
|
|
264
|
+
)
|
|
265
|
+
return exc.returncode or 1
|
|
266
|
+
sys.stdout.write("Rebuilding dashboard…\n")
|
|
267
|
+
try:
|
|
268
|
+
subprocess.run(["npm", "run", "build"], cwd=_DASHBOARD_DIR, check=True)
|
|
269
|
+
except subprocess.CalledProcessError as exc:
|
|
270
|
+
sys.stderr.write(f"error: dashboard build failed (exit {exc.returncode})\n")
|
|
271
|
+
return exc.returncode or 1
|
|
272
|
+
return 0
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class _ClearAllError(RuntimeError):
|
|
276
|
+
"""Raised when a destructive clear-all target is unsafe or unsupported."""
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@dataclass(frozen=True)
|
|
280
|
+
class _ClearAllTarget:
|
|
281
|
+
"""One filesystem target removed by ``clear-all``."""
|
|
282
|
+
|
|
283
|
+
path: Path
|
|
284
|
+
kind: str
|
|
285
|
+
label: str
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _read_dotenv_value(env_path: Path, key: str) -> str | None:
|
|
289
|
+
"""Read one simple KEY=VALUE binding from a dotenv file."""
|
|
290
|
+
if not env_path.is_file():
|
|
291
|
+
return None
|
|
292
|
+
try:
|
|
293
|
+
lines = env_path.read_text().splitlines()
|
|
294
|
+
except OSError:
|
|
295
|
+
return None
|
|
296
|
+
prefix = f"{key}="
|
|
297
|
+
for raw_line in lines:
|
|
298
|
+
line = raw_line.strip()
|
|
299
|
+
if not line or line.startswith("#"):
|
|
300
|
+
continue
|
|
301
|
+
if line.startswith("export "):
|
|
302
|
+
line = line[7:].lstrip()
|
|
303
|
+
if not line.startswith(prefix):
|
|
304
|
+
continue
|
|
305
|
+
value = line[len(prefix) :].strip()
|
|
306
|
+
if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
|
|
307
|
+
value = value[1:-1]
|
|
308
|
+
return value.strip()
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _resolve_absolute_path(raw_path: str | Path, *, source: str) -> Path:
|
|
313
|
+
path = Path(raw_path).expanduser()
|
|
314
|
+
if not path.is_absolute():
|
|
315
|
+
raise _ClearAllError(f"{source} must be an absolute path: {raw_path}")
|
|
316
|
+
return path
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def _effective_storage_root() -> Path:
|
|
320
|
+
raw = os.environ.get(_LOCAL_STORAGE_ENV, "").strip()
|
|
321
|
+
if not raw:
|
|
322
|
+
raw = _read_dotenv_value(_REFLEXIO_ENV_PATH, _LOCAL_STORAGE_ENV) or ""
|
|
323
|
+
return _resolve_absolute_path(
|
|
324
|
+
raw or _DEFAULT_STORAGE_ROOT, source=_LOCAL_STORAGE_ENV
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _load_reflexio_config() -> dict[str, object] | None:
|
|
329
|
+
if not _REFLEXIO_CONFIG_PATH.is_file():
|
|
330
|
+
return None
|
|
331
|
+
try:
|
|
332
|
+
loaded = json.loads(_REFLEXIO_CONFIG_PATH.read_text())
|
|
333
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
334
|
+
raise _ClearAllError(
|
|
335
|
+
f"could not read reflexio config {_REFLEXIO_CONFIG_PATH}: {exc}"
|
|
336
|
+
) from exc
|
|
337
|
+
if not isinstance(loaded, dict):
|
|
338
|
+
raise _ClearAllError(
|
|
339
|
+
f"reflexio config {_REFLEXIO_CONFIG_PATH} is not a JSON object"
|
|
340
|
+
)
|
|
341
|
+
return loaded
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _storage_config_kind(storage_config: dict[str, object]) -> str:
|
|
345
|
+
if storage_config.get("managed_by") == "platform":
|
|
346
|
+
return "remote"
|
|
347
|
+
explicit_type = str(
|
|
348
|
+
storage_config.get("type") or storage_config.get("storage_type") or ""
|
|
349
|
+
).lower()
|
|
350
|
+
if explicit_type in {"supabase", "postgres"}:
|
|
351
|
+
return "remote"
|
|
352
|
+
if explicit_type == "disk":
|
|
353
|
+
return "disk"
|
|
354
|
+
if explicit_type == "sqlite":
|
|
355
|
+
return "sqlite"
|
|
356
|
+
if (
|
|
357
|
+
"url" in storage_config
|
|
358
|
+
and "key" in storage_config
|
|
359
|
+
and "db_url" in storage_config
|
|
360
|
+
):
|
|
361
|
+
return "remote"
|
|
362
|
+
if "db_url" in storage_config:
|
|
363
|
+
return "remote"
|
|
364
|
+
if "dir_path" in storage_config:
|
|
365
|
+
return "disk"
|
|
366
|
+
if "db_path" in storage_config or not storage_config:
|
|
367
|
+
return "sqlite"
|
|
368
|
+
raise _ClearAllError(
|
|
369
|
+
"unsupported reflexio storage_config shape; refusing to delete local data"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def _dangerous_clear_all_paths() -> set[Path]:
|
|
374
|
+
home = Path.home().resolve(strict=False)
|
|
375
|
+
reflexio_dir = _resolve_absolute_path(_REFLEXIO_DIR, source="reflexio dir")
|
|
376
|
+
return {
|
|
377
|
+
Path("/").resolve(strict=False),
|
|
378
|
+
home,
|
|
379
|
+
reflexio_dir.resolve(strict=False),
|
|
380
|
+
_resolve_absolute_path(
|
|
381
|
+
reflexio_dir / "configs", source="reflexio configs"
|
|
382
|
+
).resolve(strict=False),
|
|
383
|
+
_PLUGIN_ROOT.resolve(strict=False),
|
|
384
|
+
_PLUGIN_ROOT.parent.resolve(strict=False),
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _validate_deletion_target(path: Path) -> None:
|
|
389
|
+
if path.exists() and path.is_symlink():
|
|
390
|
+
raise _ClearAllError(f"refusing to delete symlink target: {path}")
|
|
391
|
+
resolved = path.resolve(strict=False)
|
|
392
|
+
if resolved in _dangerous_clear_all_paths():
|
|
393
|
+
raise _ClearAllError(f"refusing to delete dangerous path: {resolved}")
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _disk_org_targets(base_dir: Path) -> list[_ClearAllTarget]:
|
|
397
|
+
if base_dir.exists() and base_dir.is_symlink():
|
|
398
|
+
raise _ClearAllError(
|
|
399
|
+
f"refusing to inspect symlink disk storage dir: {base_dir}"
|
|
400
|
+
)
|
|
401
|
+
if not base_dir.exists():
|
|
402
|
+
return []
|
|
403
|
+
if not base_dir.is_dir():
|
|
404
|
+
raise _ClearAllError(
|
|
405
|
+
f"configured disk storage path is not a directory: {base_dir}"
|
|
406
|
+
)
|
|
407
|
+
return [
|
|
408
|
+
_ClearAllTarget(child, "dir", "disk org data")
|
|
409
|
+
for child in sorted(base_dir.glob("disk_*"))
|
|
410
|
+
]
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _resolve_clear_all_targets() -> list[_ClearAllTarget]:
|
|
414
|
+
targets = [
|
|
415
|
+
_ClearAllTarget(_effective_storage_root(), "dir", "managed local storage root")
|
|
416
|
+
]
|
|
417
|
+
|
|
418
|
+
config = _load_reflexio_config()
|
|
419
|
+
storage_config = config.get("storage_config") if config else None
|
|
420
|
+
if storage_config is not None:
|
|
421
|
+
if not isinstance(storage_config, dict):
|
|
422
|
+
raise _ClearAllError("reflexio storage_config is not a JSON object")
|
|
423
|
+
kind = _storage_config_kind(storage_config)
|
|
424
|
+
if kind == "remote":
|
|
425
|
+
raise _ClearAllError(
|
|
426
|
+
"clear-all only resets local Reflexio storage; "
|
|
427
|
+
"remote Supabase/Postgres storage is not supported"
|
|
428
|
+
)
|
|
429
|
+
if kind == "sqlite":
|
|
430
|
+
raw_db_path = storage_config.get("db_path")
|
|
431
|
+
if isinstance(raw_db_path, str) and raw_db_path.strip():
|
|
432
|
+
db_path = _resolve_absolute_path(
|
|
433
|
+
raw_db_path.strip(), source="configured SQLite db_path"
|
|
434
|
+
)
|
|
435
|
+
targets.extend(
|
|
436
|
+
_ClearAllTarget(
|
|
437
|
+
Path(f"{db_path}{suffix}"),
|
|
438
|
+
"file",
|
|
439
|
+
"configured SQLite data",
|
|
440
|
+
)
|
|
441
|
+
for suffix in ("", "-wal", "-shm", "-journal")
|
|
442
|
+
)
|
|
443
|
+
elif kind == "disk":
|
|
444
|
+
raw_dir_path = storage_config.get("dir_path")
|
|
445
|
+
if not isinstance(raw_dir_path, str) or not raw_dir_path.strip():
|
|
446
|
+
raise _ClearAllError("configured disk storage is missing dir_path")
|
|
447
|
+
disk_base = _resolve_absolute_path(
|
|
448
|
+
raw_dir_path.strip(), source="configured disk dir_path"
|
|
449
|
+
)
|
|
450
|
+
targets.extend(_disk_org_targets(disk_base))
|
|
451
|
+
|
|
452
|
+
deduped: list[_ClearAllTarget] = []
|
|
453
|
+
seen: set[Path] = set()
|
|
454
|
+
for target in targets:
|
|
455
|
+
_validate_deletion_target(target.path)
|
|
456
|
+
resolved = target.path.resolve(strict=False)
|
|
457
|
+
if resolved in seen:
|
|
458
|
+
continue
|
|
459
|
+
deduped.append(_ClearAllTarget(resolved, target.kind, target.label))
|
|
460
|
+
seen.add(resolved)
|
|
461
|
+
return deduped
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _remove_clear_all_target(target: _ClearAllTarget) -> bool:
|
|
465
|
+
"""Remove a target. Returns True when something was actually removed."""
|
|
466
|
+
path = target.path
|
|
467
|
+
if not path.exists():
|
|
468
|
+
return False
|
|
469
|
+
if target.kind == "dir":
|
|
470
|
+
if not path.is_dir():
|
|
471
|
+
raise _ClearAllError(
|
|
472
|
+
f"expected directory target but found non-directory: {path}"
|
|
473
|
+
)
|
|
474
|
+
shutil.rmtree(path)
|
|
475
|
+
return True
|
|
476
|
+
if target.kind == "file":
|
|
477
|
+
if not path.is_file():
|
|
478
|
+
raise _ClearAllError(f"expected file target but found non-file: {path}")
|
|
479
|
+
path.unlink()
|
|
480
|
+
return True
|
|
481
|
+
raise _ClearAllError(f"unknown clear-all target kind: {target.kind}")
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def cmd_clear_all(args: argparse.Namespace) -> int:
|
|
485
|
+
"""Delete all local reflexio data and openclaw-smart session buffers.
|
|
486
|
+
|
|
487
|
+
Stops the managed backend first when it is running, wipes local Reflexio
|
|
488
|
+
data targets, removes local session JSONL buffers under ``state_dir()``,
|
|
489
|
+
then restarts the backend if it was running before. Requires ``--yes``.
|
|
490
|
+
|
|
491
|
+
Args:
|
|
492
|
+
args (argparse.Namespace): Parsed CLI args. Honors ``args.yes``
|
|
493
|
+
(skip the confirmation prompt).
|
|
494
|
+
|
|
495
|
+
Returns:
|
|
496
|
+
int: 0 on success, 1 if reset is unsafe, unsupported, or fails.
|
|
497
|
+
"""
|
|
498
|
+
try:
|
|
499
|
+
targets = _resolve_clear_all_targets()
|
|
500
|
+
except _ClearAllError as exc:
|
|
501
|
+
sys.stderr.write(f"error: {exc}\n")
|
|
502
|
+
return 1
|
|
503
|
+
|
|
504
|
+
if not args.yes:
|
|
505
|
+
target_lines = "\n".join(
|
|
506
|
+
f" - {target.path} ({target.label})" for target in targets
|
|
507
|
+
)
|
|
508
|
+
sys.stdout.write(
|
|
509
|
+
"This will permanently delete ALL local reflexio data at:\n"
|
|
510
|
+
f"{target_lines}\n"
|
|
511
|
+
f"and local session buffers under {state.state_dir()}.\n"
|
|
512
|
+
"If the reflexio backend is running, it will be stopped first "
|
|
513
|
+
"and restarted afterward.\n"
|
|
514
|
+
"Re-run with --yes to confirm.\n"
|
|
515
|
+
)
|
|
516
|
+
return 1
|
|
517
|
+
|
|
518
|
+
was_running = _is_running_status(_service_status(_BACKEND_SCRIPT, wait_ready_s=0.0))
|
|
519
|
+
if was_running:
|
|
520
|
+
sys.stdout.write("Stopping reflexio backend…\n")
|
|
521
|
+
stop_rc = _run_service(_BACKEND_SCRIPT, "stop")
|
|
522
|
+
if stop_rc != 0:
|
|
523
|
+
sys.stderr.write(
|
|
524
|
+
f"error: reflexio backend failed to stop (exit {stop_rc})\n"
|
|
525
|
+
)
|
|
526
|
+
return stop_rc or 1
|
|
527
|
+
|
|
528
|
+
clear_all_failed = False
|
|
529
|
+
removed_targets = 0
|
|
530
|
+
try:
|
|
531
|
+
for target in targets:
|
|
532
|
+
if _remove_clear_all_target(target):
|
|
533
|
+
removed_targets += 1
|
|
534
|
+
except (OSError, _ClearAllError) as exc:
|
|
535
|
+
sys.stderr.write(f"error: could not remove reflexio data: {exc}\n")
|
|
536
|
+
clear_all_failed = True
|
|
537
|
+
|
|
538
|
+
removed_buffers = 0
|
|
539
|
+
root = state.state_dir()
|
|
540
|
+
if not clear_all_failed and root.is_dir():
|
|
541
|
+
for buf in root.glob("*.jsonl"):
|
|
542
|
+
try:
|
|
543
|
+
buf.unlink()
|
|
544
|
+
removed_buffers += 1
|
|
545
|
+
except OSError as exc:
|
|
546
|
+
sys.stderr.write(f"warning: could not remove {buf}: {exc}\n")
|
|
547
|
+
clear_all_failed = True
|
|
548
|
+
|
|
549
|
+
start_rc = 0
|
|
550
|
+
if was_running:
|
|
551
|
+
sys.stdout.write("Starting reflexio backend…\n")
|
|
552
|
+
start_rc = _run_service(_BACKEND_SCRIPT, "start")
|
|
553
|
+
|
|
554
|
+
target_summary = (
|
|
555
|
+
f"removed {removed_targets} data target(s)"
|
|
556
|
+
if removed_targets
|
|
557
|
+
else "nothing to wipe"
|
|
558
|
+
)
|
|
559
|
+
sys.stdout.write(
|
|
560
|
+
f"Cleared reflexio: {target_summary}. "
|
|
561
|
+
f"Removed {removed_buffers} local session buffer(s).\n"
|
|
562
|
+
)
|
|
563
|
+
return start_rc or (1 if clear_all_failed else 0)
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
567
|
+
parser = argparse.ArgumentParser(prog="openclaw-smart")
|
|
568
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
569
|
+
|
|
570
|
+
sh = sub.add_parser(
|
|
571
|
+
"show",
|
|
572
|
+
help="Show current project-specific skills and project preferences",
|
|
573
|
+
)
|
|
574
|
+
sh.add_argument("--project", help="Override project id")
|
|
575
|
+
sh.set_defaults(func=cmd_show)
|
|
576
|
+
|
|
577
|
+
ln = sub.add_parser(
|
|
578
|
+
"learn",
|
|
579
|
+
help="Force reflexio extraction over the active session now",
|
|
580
|
+
)
|
|
581
|
+
ln.add_argument("--session", help="Session id (defaults to latest)")
|
|
582
|
+
ln.add_argument("--project", help="Override project id")
|
|
583
|
+
ln.add_argument(
|
|
584
|
+
"--note",
|
|
585
|
+
default=None,
|
|
586
|
+
help=(
|
|
587
|
+
"Free-form note to publish as a User turn before extraction "
|
|
588
|
+
"(e.g. an insight, preference, or workflow rule)"
|
|
589
|
+
),
|
|
590
|
+
)
|
|
591
|
+
ln.set_defaults(func=cmd_learn)
|
|
592
|
+
|
|
593
|
+
ca = sub.add_parser(
|
|
594
|
+
"clear-all",
|
|
595
|
+
help="Delete all local reflexio data and restart the backend",
|
|
596
|
+
)
|
|
597
|
+
ca.add_argument(
|
|
598
|
+
"--yes",
|
|
599
|
+
action="store_true",
|
|
600
|
+
help="Confirm the destructive clear without prompting",
|
|
601
|
+
)
|
|
602
|
+
ca.set_defaults(func=cmd_clear_all)
|
|
603
|
+
|
|
604
|
+
rs = sub.add_parser(
|
|
605
|
+
"restart",
|
|
606
|
+
help="Restart the reflexio backend and dashboard to pick up changes",
|
|
607
|
+
)
|
|
608
|
+
rs.add_argument(
|
|
609
|
+
"--skip-backend",
|
|
610
|
+
action="store_true",
|
|
611
|
+
help="Do not stop/start the reflexio backend",
|
|
612
|
+
)
|
|
613
|
+
rs.add_argument(
|
|
614
|
+
"--skip-dashboard",
|
|
615
|
+
action="store_true",
|
|
616
|
+
help="Do not stop/start the dashboard",
|
|
617
|
+
)
|
|
618
|
+
rs.add_argument(
|
|
619
|
+
"--no-rebuild",
|
|
620
|
+
action="store_true",
|
|
621
|
+
help="Skip the `npm run build` step before restarting the dashboard",
|
|
622
|
+
)
|
|
623
|
+
rs.set_defaults(func=cmd_restart)
|
|
624
|
+
return parser
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def main(argv: list[str] | None = None) -> int:
|
|
628
|
+
parser = _build_parser()
|
|
629
|
+
args = parser.parse_args(argv)
|
|
630
|
+
return args.func(args)
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
if __name__ == "__main__":
|
|
634
|
+
raise SystemExit(main())
|