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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function eventProperties(event) {
|
|
5
|
+
return isRecord(event.properties) ? event.properties : event;
|
|
6
|
+
}
|
|
7
|
+
export function sessionIDFrom(value) {
|
|
8
|
+
if (!isRecord(value))
|
|
9
|
+
return "";
|
|
10
|
+
const raw = value.sessionID ?? value.session_id;
|
|
11
|
+
return typeof raw === "string" ? raw : "";
|
|
12
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { eventProperties, isRecord, sessionIDFrom } from "./internal.js";
|
|
2
|
+
function textFromParts(parts) {
|
|
3
|
+
if (!Array.isArray(parts))
|
|
4
|
+
return "";
|
|
5
|
+
return parts
|
|
6
|
+
.map((part) => (part && part.type === "text" && typeof part.text === "string" ? part.text : ""))
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.join("\n\n");
|
|
9
|
+
}
|
|
10
|
+
export function eventPayload(event, cwd) {
|
|
11
|
+
const properties = eventProperties(event);
|
|
12
|
+
const info = isRecord(properties.info) ? properties.info : {};
|
|
13
|
+
return {
|
|
14
|
+
session_id: sessionIDFrom(properties) || sessionIDFrom(info),
|
|
15
|
+
cwd: typeof info.directory === "string" ? info.directory : cwd,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function chatMessagePayload(input, output, cwd) {
|
|
19
|
+
const message = isRecord(output.message) ? output.message : {};
|
|
20
|
+
const prompt = textFromParts(output.parts) ||
|
|
21
|
+
(typeof message.content === "string" ? message.content : "") ||
|
|
22
|
+
textFromParts(message.parts);
|
|
23
|
+
return {
|
|
24
|
+
session_id: sessionIDFrom(input),
|
|
25
|
+
cwd,
|
|
26
|
+
prompt,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function normalizeToolName(tool) {
|
|
30
|
+
const lowered = tool.toLowerCase();
|
|
31
|
+
if (lowered === "edit")
|
|
32
|
+
return "Edit";
|
|
33
|
+
if (lowered === "write")
|
|
34
|
+
return "Write";
|
|
35
|
+
if (lowered === "apply_patch")
|
|
36
|
+
return "apply_patch";
|
|
37
|
+
if (["bash", "shell", "terminal", "exec", "command"].includes(lowered))
|
|
38
|
+
return "Bash";
|
|
39
|
+
return tool;
|
|
40
|
+
}
|
|
41
|
+
export function normalizeToolInput(tool, args) {
|
|
42
|
+
if (!isRecord(args))
|
|
43
|
+
return {};
|
|
44
|
+
const out = { ...args };
|
|
45
|
+
const copy = (from, to) => {
|
|
46
|
+
if (from in args && !(to in out))
|
|
47
|
+
out[to] = args[from];
|
|
48
|
+
};
|
|
49
|
+
copy("filePath", "file_path");
|
|
50
|
+
copy("oldString", "old_string");
|
|
51
|
+
copy("newString", "new_string");
|
|
52
|
+
copy("patchText", "command");
|
|
53
|
+
if (normalizeToolName(tool) === "Bash") {
|
|
54
|
+
copy("cmd", "command");
|
|
55
|
+
copy("script", "command");
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
export function toolAfterPayload(input, output, cwd) {
|
|
60
|
+
const tool = typeof input.tool === "string" ? input.tool : "";
|
|
61
|
+
const text = typeof output.output === "string" ? output.output : "";
|
|
62
|
+
const response = {
|
|
63
|
+
output: text,
|
|
64
|
+
stdout: text,
|
|
65
|
+
};
|
|
66
|
+
if (typeof output.title === "string")
|
|
67
|
+
response.title = output.title;
|
|
68
|
+
if (isRecord(output.metadata))
|
|
69
|
+
response.metadata = output.metadata;
|
|
70
|
+
if (isRecord(output.metadata) && output.metadata.error)
|
|
71
|
+
response.error = output.metadata.error;
|
|
72
|
+
return {
|
|
73
|
+
session_id: sessionIDFrom(input),
|
|
74
|
+
cwd,
|
|
75
|
+
tool_name: normalizeToolName(tool),
|
|
76
|
+
tool_input: normalizeToolInput(tool, input.args),
|
|
77
|
+
tool_response: response,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function stopPayload(event, cwd, lastAssistantMessage) {
|
|
81
|
+
return {
|
|
82
|
+
...eventPayload(event, cwd),
|
|
83
|
+
last_assistant_message: lastAssistantMessage,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { AssistantBuffer } from "./assistant-buffer.js";
|
|
5
|
+
import { sessionIDFrom } from "./internal.js";
|
|
6
|
+
import { chatMessagePayload, eventPayload, stopPayload, toolAfterPayload } from "./payload.js";
|
|
7
|
+
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const PLUGIN_ROOT = resolve(MODULE_DIR, "../..");
|
|
9
|
+
const SCRIPTS_DIR = resolve(PLUGIN_ROOT, "scripts");
|
|
10
|
+
const HOOK_ENTRY = resolve(SCRIPTS_DIR, "hook_entry.sh");
|
|
11
|
+
const BACKEND_SERVICE = resolve(SCRIPTS_DIR, "backend-service.sh");
|
|
12
|
+
const DASHBOARD_SERVICE = resolve(SCRIPTS_DIR, "dashboard-service.sh");
|
|
13
|
+
function contextFrom(result) {
|
|
14
|
+
const hookOutput = result.hookSpecificOutput;
|
|
15
|
+
if (!hookOutput || typeof hookOutput !== "object")
|
|
16
|
+
return "";
|
|
17
|
+
const additional = hookOutput.additionalContext;
|
|
18
|
+
return typeof additional === "string" ? additional : "";
|
|
19
|
+
}
|
|
20
|
+
function parseFirstJsonObject(text) {
|
|
21
|
+
for (const line of text.split(/\r?\n/)) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (!trimmed.startsWith("{"))
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(trimmed);
|
|
27
|
+
if (parsed && typeof parsed === "object")
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
function runScript(script, args, payload) {
|
|
37
|
+
return new Promise((resolvePromise) => {
|
|
38
|
+
const child = spawn("bash", [script, ...args], {
|
|
39
|
+
cwd: PLUGIN_ROOT,
|
|
40
|
+
env: {
|
|
41
|
+
...process.env,
|
|
42
|
+
CLAUDE_PLUGIN_ROOT: PLUGIN_ROOT,
|
|
43
|
+
CLAUDE_SMART_HOST: "opencode",
|
|
44
|
+
},
|
|
45
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
46
|
+
});
|
|
47
|
+
let stdout = "";
|
|
48
|
+
child.stdout.on("data", (chunk) => {
|
|
49
|
+
stdout += chunk.toString();
|
|
50
|
+
});
|
|
51
|
+
child.stderr.on("data", (chunk) => {
|
|
52
|
+
process.stderr.write(chunk);
|
|
53
|
+
});
|
|
54
|
+
child.stdin.on("error", () => {
|
|
55
|
+
// Hooks can exit before reading stdin on marker-gated setup failures.
|
|
56
|
+
});
|
|
57
|
+
child.on("error", () => resolvePromise({}));
|
|
58
|
+
child.on("close", () => resolvePromise(parseFirstJsonObject(stdout)));
|
|
59
|
+
try {
|
|
60
|
+
if (payload)
|
|
61
|
+
child.stdin.write(JSON.stringify(payload));
|
|
62
|
+
child.stdin.end();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
resolvePromise({});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function runService(script, subcommand) {
|
|
70
|
+
return runScript(script, [subcommand]).then(() => undefined);
|
|
71
|
+
}
|
|
72
|
+
function cacheContext(cache, sessionID, result) {
|
|
73
|
+
const context = contextFrom(result);
|
|
74
|
+
if (!sessionID || !context)
|
|
75
|
+
return;
|
|
76
|
+
const pending = cache.get(sessionID) ?? [];
|
|
77
|
+
pending.push(context);
|
|
78
|
+
cache.set(sessionID, pending);
|
|
79
|
+
}
|
|
80
|
+
async function server(input) {
|
|
81
|
+
const pendingContext = new Map();
|
|
82
|
+
const activeSessions = new Set();
|
|
83
|
+
const completedAssistantText = new Map();
|
|
84
|
+
const assistant = new AssistantBuffer();
|
|
85
|
+
const cwd = input.directory;
|
|
86
|
+
async function flushStop(sessionID) {
|
|
87
|
+
if (!sessionID || !activeSessions.has(sessionID))
|
|
88
|
+
return;
|
|
89
|
+
activeSessions.delete(sessionID);
|
|
90
|
+
const text = assistant.text(sessionID) || completedAssistantText.get(sessionID) || "";
|
|
91
|
+
completedAssistantText.delete(sessionID);
|
|
92
|
+
await runScript(HOOK_ENTRY, ["opencode", "stop"], stopPayload({ properties: { sessionID, info: { directory: cwd } } }, cwd, text));
|
|
93
|
+
assistant.clear(sessionID);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
event: async ({ event }) => {
|
|
97
|
+
const type = event.type;
|
|
98
|
+
assistant.update(event);
|
|
99
|
+
if (type === "session.created") {
|
|
100
|
+
const payload = eventPayload(event, cwd);
|
|
101
|
+
const sessionID = String(payload.session_id || "");
|
|
102
|
+
if (!sessionID)
|
|
103
|
+
return;
|
|
104
|
+
activeSessions.add(sessionID);
|
|
105
|
+
await runService(BACKEND_SERVICE, "start");
|
|
106
|
+
await runService(DASHBOARD_SERVICE, "start");
|
|
107
|
+
const result = await runScript(HOOK_ENTRY, ["opencode", "session-start"], payload);
|
|
108
|
+
cacheContext(pendingContext, sessionID, result);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (type === "session.idle") {
|
|
112
|
+
const payload = eventPayload(event, cwd);
|
|
113
|
+
const sessionID = String(payload.session_id || "");
|
|
114
|
+
if (!sessionID)
|
|
115
|
+
return;
|
|
116
|
+
await flushStop(sessionID);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"chat.message": async (hookInput, output) => {
|
|
120
|
+
const payload = chatMessagePayload(hookInput, output, cwd);
|
|
121
|
+
if (!payload.session_id || !payload.prompt)
|
|
122
|
+
return;
|
|
123
|
+
activeSessions.add(String(payload.session_id || ""));
|
|
124
|
+
const result = await runScript(HOOK_ENTRY, ["opencode", "user-prompt"], payload);
|
|
125
|
+
cacheContext(pendingContext, String(payload.session_id || ""), result);
|
|
126
|
+
},
|
|
127
|
+
"experimental.chat.system.transform": async (hookInput, output) => {
|
|
128
|
+
const sessionID = sessionIDFrom(hookInput);
|
|
129
|
+
const pending = pendingContext.get(sessionID);
|
|
130
|
+
if (!pending?.length)
|
|
131
|
+
return;
|
|
132
|
+
output.system.push(...pending);
|
|
133
|
+
pendingContext.delete(sessionID);
|
|
134
|
+
},
|
|
135
|
+
"tool.execute.after": async (hookInput, output) => {
|
|
136
|
+
const payload = toolAfterPayload(hookInput, output, cwd);
|
|
137
|
+
if (!payload.session_id || !payload.tool_name)
|
|
138
|
+
return;
|
|
139
|
+
await runScript(HOOK_ENTRY, ["opencode", "post-tool"], payload);
|
|
140
|
+
},
|
|
141
|
+
"experimental.text.complete": async (hookInput, output) => {
|
|
142
|
+
const sessionID = typeof hookInput.sessionID === "string" ? hookInput.sessionID : "";
|
|
143
|
+
if (!sessionID)
|
|
144
|
+
return;
|
|
145
|
+
if (typeof output.text === "string")
|
|
146
|
+
completedAssistantText.set(sessionID, output.text);
|
|
147
|
+
},
|
|
148
|
+
dispose: async () => {
|
|
149
|
+
await Promise.all([...activeSessions].map((sessionID) => flushStop(sessionID)));
|
|
150
|
+
await runService(DASHBOARD_SERVICE, "session-end");
|
|
151
|
+
await runService(BACKEND_SERVICE, "session-end");
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export default {
|
|
156
|
+
id: "claude-smart",
|
|
157
|
+
server,
|
|
158
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type EventLike = {
|
|
2
|
+
type?: string
|
|
3
|
+
properties?: Record<string, unknown>
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
7
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function eventProperties(event: EventLike): Record<string, unknown> {
|
|
11
|
+
return isRecord(event.properties) ? event.properties : (event as Record<string, unknown>)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function sessionIDFrom(value: unknown): string {
|
|
15
|
+
if (!isRecord(value)) return ""
|
|
16
|
+
const raw = value.sessionID ?? value.session_id
|
|
17
|
+
return typeof raw === "string" ? raw : ""
|
|
18
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { eventProperties, type EventLike, isRecord, sessionIDFrom } from "./internal.js"
|
|
2
|
+
|
|
3
|
+
type PartLike = {
|
|
4
|
+
type?: string
|
|
5
|
+
text?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type PythonPayload = Record<string, unknown>
|
|
9
|
+
|
|
10
|
+
function textFromParts(parts: unknown): string {
|
|
11
|
+
if (!Array.isArray(parts)) return ""
|
|
12
|
+
return parts
|
|
13
|
+
.map((part: PartLike) => (part && part.type === "text" && typeof part.text === "string" ? part.text : ""))
|
|
14
|
+
.filter(Boolean)
|
|
15
|
+
.join("\n\n")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function eventPayload(event: EventLike, cwd: string): PythonPayload {
|
|
19
|
+
const properties = eventProperties(event)
|
|
20
|
+
const info = isRecord(properties.info) ? properties.info : {}
|
|
21
|
+
return {
|
|
22
|
+
session_id: sessionIDFrom(properties) || sessionIDFrom(info),
|
|
23
|
+
cwd: typeof info.directory === "string" ? info.directory : cwd,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function chatMessagePayload(input: Record<string, unknown>, output: Record<string, unknown>, cwd: string): PythonPayload {
|
|
28
|
+
const message = isRecord(output.message) ? output.message : {}
|
|
29
|
+
const prompt =
|
|
30
|
+
textFromParts(output.parts) ||
|
|
31
|
+
(typeof message.content === "string" ? message.content : "") ||
|
|
32
|
+
textFromParts(message.parts)
|
|
33
|
+
return {
|
|
34
|
+
session_id: sessionIDFrom(input),
|
|
35
|
+
cwd,
|
|
36
|
+
prompt,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function normalizeToolName(tool: string): string {
|
|
41
|
+
const lowered = tool.toLowerCase()
|
|
42
|
+
if (lowered === "edit") return "Edit"
|
|
43
|
+
if (lowered === "write") return "Write"
|
|
44
|
+
if (lowered === "apply_patch") return "apply_patch"
|
|
45
|
+
if (["bash", "shell", "terminal", "exec", "command"].includes(lowered)) return "Bash"
|
|
46
|
+
return tool
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function normalizeToolInput(tool: string, args: unknown): Record<string, unknown> {
|
|
50
|
+
if (!isRecord(args)) return {}
|
|
51
|
+
const out: Record<string, unknown> = { ...args }
|
|
52
|
+
const copy = (from: string, to: string) => {
|
|
53
|
+
if (from in args && !(to in out)) out[to] = args[from]
|
|
54
|
+
}
|
|
55
|
+
copy("filePath", "file_path")
|
|
56
|
+
copy("oldString", "old_string")
|
|
57
|
+
copy("newString", "new_string")
|
|
58
|
+
copy("patchText", "command")
|
|
59
|
+
if (normalizeToolName(tool) === "Bash") {
|
|
60
|
+
copy("cmd", "command")
|
|
61
|
+
copy("script", "command")
|
|
62
|
+
}
|
|
63
|
+
return out
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function toolAfterPayload(input: Record<string, unknown>, output: Record<string, unknown>, cwd: string): PythonPayload {
|
|
67
|
+
const tool = typeof input.tool === "string" ? input.tool : ""
|
|
68
|
+
const text = typeof output.output === "string" ? output.output : ""
|
|
69
|
+
const response: Record<string, unknown> = {
|
|
70
|
+
output: text,
|
|
71
|
+
stdout: text,
|
|
72
|
+
}
|
|
73
|
+
if (typeof output.title === "string") response.title = output.title
|
|
74
|
+
if (isRecord(output.metadata)) response.metadata = output.metadata
|
|
75
|
+
if (isRecord(output.metadata) && output.metadata.error) response.error = output.metadata.error
|
|
76
|
+
return {
|
|
77
|
+
session_id: sessionIDFrom(input),
|
|
78
|
+
cwd,
|
|
79
|
+
tool_name: normalizeToolName(tool),
|
|
80
|
+
tool_input: normalizeToolInput(tool, input.args),
|
|
81
|
+
tool_response: response,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function stopPayload(event: EventLike, cwd: string, lastAssistantMessage: string): PythonPayload {
|
|
86
|
+
return {
|
|
87
|
+
...eventPayload(event, cwd),
|
|
88
|
+
last_assistant_message: lastAssistantMessage,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { spawn } from "node:child_process"
|
|
2
|
+
import { dirname, resolve } from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
|
|
5
|
+
import { AssistantBuffer } from "./assistant-buffer.js"
|
|
6
|
+
import { sessionIDFrom } from "./internal.js"
|
|
7
|
+
import { chatMessagePayload, eventPayload, stopPayload, toolAfterPayload } from "./payload.js"
|
|
8
|
+
|
|
9
|
+
type HookResult = Record<string, unknown>
|
|
10
|
+
|
|
11
|
+
type PluginInput = {
|
|
12
|
+
directory: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type EventInput = {
|
|
16
|
+
event: {
|
|
17
|
+
type?: string
|
|
18
|
+
properties?: Record<string, unknown>
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const MODULE_DIR = dirname(fileURLToPath(import.meta.url))
|
|
23
|
+
const PLUGIN_ROOT = resolve(MODULE_DIR, "../..")
|
|
24
|
+
const SCRIPTS_DIR = resolve(PLUGIN_ROOT, "scripts")
|
|
25
|
+
const HOOK_ENTRY = resolve(SCRIPTS_DIR, "hook_entry.sh")
|
|
26
|
+
const BACKEND_SERVICE = resolve(SCRIPTS_DIR, "backend-service.sh")
|
|
27
|
+
const DASHBOARD_SERVICE = resolve(SCRIPTS_DIR, "dashboard-service.sh")
|
|
28
|
+
|
|
29
|
+
function contextFrom(result: HookResult): string {
|
|
30
|
+
const hookOutput = result.hookSpecificOutput
|
|
31
|
+
if (!hookOutput || typeof hookOutput !== "object") return ""
|
|
32
|
+
const additional = (hookOutput as Record<string, unknown>).additionalContext
|
|
33
|
+
return typeof additional === "string" ? additional : ""
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseFirstJsonObject(text: string): HookResult {
|
|
37
|
+
for (const line of text.split(/\r?\n/)) {
|
|
38
|
+
const trimmed = line.trim()
|
|
39
|
+
if (!trimmed.startsWith("{")) continue
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(trimmed)
|
|
42
|
+
if (parsed && typeof parsed === "object") return parsed as HookResult
|
|
43
|
+
} catch {
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function runScript(script: string, args: string[], payload?: Record<string, unknown>): Promise<HookResult> {
|
|
51
|
+
return new Promise((resolvePromise) => {
|
|
52
|
+
const child = spawn("bash", [script, ...args], {
|
|
53
|
+
cwd: PLUGIN_ROOT,
|
|
54
|
+
env: {
|
|
55
|
+
...process.env,
|
|
56
|
+
CLAUDE_PLUGIN_ROOT: PLUGIN_ROOT,
|
|
57
|
+
CLAUDE_SMART_HOST: "opencode",
|
|
58
|
+
},
|
|
59
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
60
|
+
})
|
|
61
|
+
let stdout = ""
|
|
62
|
+
child.stdout.on("data", (chunk) => {
|
|
63
|
+
stdout += chunk.toString()
|
|
64
|
+
})
|
|
65
|
+
child.stderr.on("data", (chunk) => {
|
|
66
|
+
process.stderr.write(chunk)
|
|
67
|
+
})
|
|
68
|
+
child.stdin.on("error", () => {
|
|
69
|
+
// Hooks can exit before reading stdin on marker-gated setup failures.
|
|
70
|
+
})
|
|
71
|
+
child.on("error", () => resolvePromise({}))
|
|
72
|
+
child.on("close", () => resolvePromise(parseFirstJsonObject(stdout)))
|
|
73
|
+
try {
|
|
74
|
+
if (payload) child.stdin.write(JSON.stringify(payload))
|
|
75
|
+
child.stdin.end()
|
|
76
|
+
} catch {
|
|
77
|
+
resolvePromise({})
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function runService(script: string, subcommand: string): Promise<void> {
|
|
83
|
+
return runScript(script, [subcommand]).then(() => undefined)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function cacheContext(cache: Map<string, string[]>, sessionID: string, result: HookResult): void {
|
|
87
|
+
const context = contextFrom(result)
|
|
88
|
+
if (!sessionID || !context) return
|
|
89
|
+
const pending = cache.get(sessionID) ?? []
|
|
90
|
+
pending.push(context)
|
|
91
|
+
cache.set(sessionID, pending)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function server(input: PluginInput) {
|
|
95
|
+
const pendingContext = new Map<string, string[]>()
|
|
96
|
+
const activeSessions = new Set<string>()
|
|
97
|
+
const completedAssistantText = new Map<string, string>()
|
|
98
|
+
const assistant = new AssistantBuffer()
|
|
99
|
+
const cwd = input.directory
|
|
100
|
+
|
|
101
|
+
async function flushStop(sessionID: string): Promise<void> {
|
|
102
|
+
if (!sessionID || !activeSessions.has(sessionID)) return
|
|
103
|
+
activeSessions.delete(sessionID)
|
|
104
|
+
const text = assistant.text(sessionID) || completedAssistantText.get(sessionID) || ""
|
|
105
|
+
completedAssistantText.delete(sessionID)
|
|
106
|
+
await runScript(
|
|
107
|
+
HOOK_ENTRY,
|
|
108
|
+
["opencode", "stop"],
|
|
109
|
+
stopPayload({ properties: { sessionID, info: { directory: cwd } } }, cwd, text),
|
|
110
|
+
)
|
|
111
|
+
assistant.clear(sessionID)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
event: async ({ event }: EventInput) => {
|
|
116
|
+
const type = event.type
|
|
117
|
+
assistant.update(event)
|
|
118
|
+
if (type === "session.created") {
|
|
119
|
+
const payload = eventPayload(event, cwd)
|
|
120
|
+
const sessionID = String(payload.session_id || "")
|
|
121
|
+
if (!sessionID) return
|
|
122
|
+
activeSessions.add(sessionID)
|
|
123
|
+
await runService(BACKEND_SERVICE, "start")
|
|
124
|
+
await runService(DASHBOARD_SERVICE, "start")
|
|
125
|
+
const result = await runScript(HOOK_ENTRY, ["opencode", "session-start"], payload)
|
|
126
|
+
cacheContext(pendingContext, sessionID, result)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
if (type === "session.idle") {
|
|
130
|
+
const payload = eventPayload(event, cwd)
|
|
131
|
+
const sessionID = String(payload.session_id || "")
|
|
132
|
+
if (!sessionID) return
|
|
133
|
+
await flushStop(sessionID)
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"chat.message": async (hookInput: Record<string, unknown>, output: Record<string, unknown>) => {
|
|
137
|
+
const payload = chatMessagePayload(hookInput, output, cwd)
|
|
138
|
+
if (!payload.session_id || !payload.prompt) return
|
|
139
|
+
activeSessions.add(String(payload.session_id || ""))
|
|
140
|
+
const result = await runScript(HOOK_ENTRY, ["opencode", "user-prompt"], payload)
|
|
141
|
+
cacheContext(pendingContext, String(payload.session_id || ""), result)
|
|
142
|
+
},
|
|
143
|
+
"experimental.chat.system.transform": async (hookInput: Record<string, unknown>, output: { system: string[] }) => {
|
|
144
|
+
const sessionID = sessionIDFrom(hookInput)
|
|
145
|
+
const pending = pendingContext.get(sessionID)
|
|
146
|
+
if (!pending?.length) return
|
|
147
|
+
output.system.push(...pending)
|
|
148
|
+
pendingContext.delete(sessionID)
|
|
149
|
+
},
|
|
150
|
+
"tool.execute.after": async (hookInput: Record<string, unknown>, output: Record<string, unknown>) => {
|
|
151
|
+
const payload = toolAfterPayload(hookInput, output, cwd)
|
|
152
|
+
if (!payload.session_id || !payload.tool_name) return
|
|
153
|
+
await runScript(HOOK_ENTRY, ["opencode", "post-tool"], payload)
|
|
154
|
+
},
|
|
155
|
+
"experimental.text.complete": async (
|
|
156
|
+
hookInput: { sessionID?: string },
|
|
157
|
+
output: { text?: string },
|
|
158
|
+
) => {
|
|
159
|
+
const sessionID = typeof hookInput.sessionID === "string" ? hookInput.sessionID : ""
|
|
160
|
+
if (!sessionID) return
|
|
161
|
+
if (typeof output.text === "string") completedAssistantText.set(sessionID, output.text)
|
|
162
|
+
},
|
|
163
|
+
dispose: async () => {
|
|
164
|
+
await Promise.all([...activeSessions].map((sessionID) => flushStop(sessionID)))
|
|
165
|
+
await runService(DASHBOARD_SERVICE, "session-end")
|
|
166
|
+
await runService(BACKEND_SERVICE, "session-end")
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default {
|
|
172
|
+
id: "claude-smart",
|
|
173
|
+
server,
|
|
174
|
+
}
|
package/plugin/pyproject.toml
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "claude-smart"
|
|
3
|
-
version = "0.2.
|
|
4
|
-
description = "Self-improving Claude Code and
|
|
3
|
+
version = "0.2.46"
|
|
4
|
+
description = "Self-improving Claude Code, Codex, and OpenCode plugin that turns corrections into Preferences, Project-specific skills, and Shared skills"
|
|
5
|
+
keywords = [
|
|
6
|
+
"claude",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"claude-code-plugin",
|
|
9
|
+
"codex",
|
|
10
|
+
"codex-plugin",
|
|
11
|
+
"opencode",
|
|
12
|
+
"opencode-plugin",
|
|
13
|
+
"memory",
|
|
14
|
+
"agent-memory",
|
|
15
|
+
"plugin",
|
|
16
|
+
"reflexio",
|
|
17
|
+
"self-improvement",
|
|
18
|
+
"self-improving-agents",
|
|
19
|
+
"skills",
|
|
20
|
+
"learning",
|
|
21
|
+
]
|
|
5
22
|
readme = "README.md"
|
|
6
23
|
requires-python = ">=3.12"
|
|
7
24
|
dependencies = [
|
|
@@ -9,7 +26,7 @@ dependencies = [
|
|
|
9
26
|
# normal installs; vendor releases may override it after uv sync by
|
|
10
27
|
# installing plugin/vendor/reflexio. Keep in sync via
|
|
11
28
|
# scripts/sync-reflexio-dep.py.
|
|
12
|
-
"reflexio-ai>=0.2.
|
|
29
|
+
"reflexio-ai>=0.2.27",
|
|
13
30
|
# Needed when Reflexio runs the local embedding provider (ONNXMiniLM_L6_V2).
|
|
14
31
|
# Pulls in onnxruntime + tokenizers; the ~80 MB ONNX model itself is
|
|
15
32
|
# downloaded on first use, not at install time.
|
package/plugin/scripts/_lib.sh
CHANGED
|
@@ -87,8 +87,12 @@ claude_smart_env_unquote() {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
claude_smart_source_reflexio_env() {
|
|
90
|
+
# claude-smart's env lives at ~/.claude-smart/.env (kept separate from the OSS
|
|
91
|
+
# reflexio default ~/.reflexio/.env). Stays in sync with
|
|
92
|
+
# env_config.REFLEXIO_ENV_PATH and the REFLEXIO_ENV_FILE export in
|
|
93
|
+
# backend-service.sh.
|
|
90
94
|
local env_file line key value
|
|
91
|
-
env_file="$HOME/.
|
|
95
|
+
env_file="$HOME/.claude-smart/.env"
|
|
92
96
|
[ -f "$env_file" ] || return 0
|
|
93
97
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
94
98
|
line="${line#"${line%%[![:space:]]*}"}"
|
|
@@ -34,6 +34,21 @@ EMBEDDING_PORT="${EMBEDDING_PORT:-8072}"
|
|
|
34
34
|
export BACKEND_PORT="$PORT"
|
|
35
35
|
export EMBEDDING_PORT
|
|
36
36
|
|
|
37
|
+
# Run claude-smart's backend under its own org id. The reflexio no-auth resolver
|
|
38
|
+
# reads REFLEXIO_DEFAULT_ORG_ID, which scopes the request org -> config file
|
|
39
|
+
# name (config_<org>.json) and SQLite data. Hard-set (not :-defaulted) so a
|
|
40
|
+
# value in the shared ~/.reflexio/.env can't drag claude-smart back onto
|
|
41
|
+
# "self-host-org" and collide with the enterprise self-host backend over
|
|
42
|
+
# config_self-host-org.json. Must stay in sync with cli.py's config path.
|
|
43
|
+
export REFLEXIO_DEFAULT_ORG_ID="claude-smart"
|
|
44
|
+
|
|
45
|
+
# Load claude-smart's env from ~/.claude-smart/.env instead of the reflexio
|
|
46
|
+
# default ~/.reflexio/.env, so an OSS reflexio backend's .env on this machine
|
|
47
|
+
# can't leak in. The data dir is independent (LOCAL_STORAGE_PATH), so both still
|
|
48
|
+
# share ~/.reflexio/data. Must stay in sync with env_config.REFLEXIO_ENV_PATH and
|
|
49
|
+
# the source path in _lib.sh (claude_smart_source_reflexio_env).
|
|
50
|
+
export REFLEXIO_ENV_FILE="$HOME/.claude-smart/.env"
|
|
51
|
+
|
|
37
52
|
# Default: route extraction through the active host CLI + ONNX embedder
|
|
38
53
|
# so claude-smart works without any LLM API key. Users can opt out by
|
|
39
54
|
# pre-exporting these to 0.
|
|
@@ -50,7 +65,12 @@ PLUGIN_ROOT="$(cd "$HERE/.." && pwd)"
|
|
|
50
65
|
claude_smart_reexec_stable_plugin_root_if_needed "$PLUGIN_ROOT" "backend-service.sh" "$@"
|
|
51
66
|
|
|
52
67
|
if [ -z "${CLAUDE_SMART_CLI_PATH:-}" ]; then
|
|
53
|
-
if [ "${CLAUDE_SMART_HOST:-claude-code}" = "
|
|
68
|
+
if [ "${CLAUDE_SMART_HOST:-claude-code}" = "opencode" ] && command -v opencode >/dev/null 2>&1; then
|
|
69
|
+
# Preserve Reflexio's Claude CLI provider contract while routing
|
|
70
|
+
# generation through the user's authenticated OpenCode setup.
|
|
71
|
+
claude_smart_prepend_node_bins
|
|
72
|
+
export CLAUDE_SMART_CLI_PATH="$PLUGIN_ROOT/scripts/opencode-claude-compat"
|
|
73
|
+
elif [ "${CLAUDE_SMART_HOST:-claude-code}" = "codex" ]; then
|
|
54
74
|
# Reflexio's provider still calls CLAUDE_SMART_CLI_PATH with Claude CLI
|
|
55
75
|
# flags. Use a small compatibility executable that translates that narrow
|
|
56
76
|
# contract to `codex exec`.
|
|
@@ -286,7 +306,7 @@ case "$CMD" in
|
|
|
286
306
|
# Keep plugin runtime data in ~/.reflexio even when the backend imports
|
|
287
307
|
# Reflexio from an editable checkout inside a larger repo with its own
|
|
288
308
|
# .env. python-dotenv respects pre-existing env vars, so this prevents a
|
|
289
|
-
# parent REFLEXIO_LOG_DIR from sending claude-smart to
|
|
309
|
+
# parent REFLEXIO_LOG_DIR from sending claude-smart to unrelated configs.
|
|
290
310
|
export REFLEXIO_LOG_DIR="${REFLEXIO_LOG_DIR:-$HOME}"
|
|
291
311
|
|
|
292
312
|
# Force sqlite: the plugin venv ships only the open-source reflexio
|
|
@@ -32,12 +32,12 @@ if [ "$FORCE" = "--force" ]; then
|
|
|
32
32
|
fi
|
|
33
33
|
|
|
34
34
|
# Opt-in: when CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=1 (set in the
|
|
35
|
-
# environment or in ~/.
|
|
35
|
+
# environment or in ~/.claude-smart/.env), always relink to $TARGET so the
|
|
36
36
|
# symlink tracks the currently loaded plugin.
|
|
37
37
|
FOLLOW="${CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION:-}"
|
|
38
|
-
if [ -z "$FOLLOW" ] && [ -f "$HOME/.
|
|
39
|
-
FOLLOW="$(grep -E '^CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=' "$HOME/.
|
|
40
|
-
| tail -n1 |
|
|
38
|
+
if [ -z "$FOLLOW" ] && [ -f "$HOME/.claude-smart/.env" ]; then
|
|
39
|
+
FOLLOW="$(grep -E '^(export[[:space:]]+)?CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=' "$HOME/.claude-smart/.env" \
|
|
40
|
+
| tail -n1 | sed -E 's/^(export[[:space:]]+)?CLAUDE_SMART_PLUGIN_ROOT_FOLLOW_SESSION=//')"
|
|
41
41
|
# Strip a single pair of surrounding double or single quotes, if present.
|
|
42
42
|
FOLLOW="${FOLLOW#\"}"; FOLLOW="${FOLLOW%\"}"
|
|
43
43
|
FOLLOW="${FOLLOW#\'}"; FOLLOW="${FOLLOW%\'}"
|