claude-smart 0.2.45 → 0.2.47
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 +47 -10
- package/bin/claude-smart.js +535 -23
- 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 +27 -6
- 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/layout.tsx +20 -0
- 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 +232 -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 +251 -0
- package/plugin/opencode/tsconfig.json +13 -0
- package/plugin/pyproject.toml +25 -4
- 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 +17 -9
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +498 -12
- package/plugin/src/claude_smart/context_format.py +9 -9
- package/plugin/src/claude_smart/cs_cite.py +66 -19
- 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 +5 -5
- package/plugin/vendor/reflexio/.env.example +54 -30
- package/plugin/vendor/reflexio/README.md +17 -11
- package/plugin/vendor/reflexio/pyproject.toml +13 -1
- package/plugin/vendor/reflexio/reflexio/README.md +4 -1
- 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 +212 -52
- 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/cli/utils.py +44 -1
- package/plugin/vendor/reflexio/reflexio/client/client.py +154 -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 +246 -10
- package/plugin/vendor/reflexio/reflexio/lib/_base.py +15 -0
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +17 -5
- package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +224 -21
- package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +52 -25
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +11 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +1 -0
- 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/domain/governance.py +117 -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 +97 -3
- 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 +104 -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 +58 -33
- 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/api.py +899 -103
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +4 -2
- package/plugin/vendor/reflexio/reflexio/server/auth.py +90 -0
- 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/extensions.py +213 -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/model_defaults.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1 -1
- 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/rerank/cross_encoder_reranker.py +12 -1
- 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 +278 -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 +28 -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 +47 -16
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
- package/plugin/vendor/reflexio/reflexio/server/services/governance/config.py +52 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +378 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/subject_refs.py +34 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +219 -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 +18 -11
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_prompt_processing.py +100 -0
- 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} +334 -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_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} +31 -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/recency.py +211 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +99 -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 +31 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +681 -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 +16 -2
- 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 +644 -197
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +106 -119
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +1965 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +630 -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 +31 -1369
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +756 -210
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +148 -34
- 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/sqlite_storage/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +952 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +189 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_optimization.py +247 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +145 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +838 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +150 -23
- 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 +40 -57
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_governance.py +148 -0
- 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 +4 -677
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +134 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +62 -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/storage/storage_base/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +365 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +124 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_optimization.py +85 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_source_linkage.py +47 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +333 -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 +372 -34
- 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/_auth.py +0 -25
- 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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Exposes the following subcommands:
|
|
4
4
|
|
|
5
5
|
- ``install``: register the GitHub marketplace and install the plugin into
|
|
6
|
-
Claude Code, then seed ``~/.
|
|
6
|
+
Claude Code, then seed ``~/.claude-smart/.env`` with the local-provider flags.
|
|
7
7
|
- ``update``: update the plugin to the latest version via the native Claude
|
|
8
8
|
Code plugin CLI.
|
|
9
9
|
- ``uninstall``: remove the plugin from Claude Code via the native plugin
|
|
@@ -21,6 +21,10 @@ Exposes the following subcommands:
|
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
23
|
import argparse
|
|
24
|
+
from collections.abc import Iterable, Iterator
|
|
25
|
+
from contextlib import contextmanager
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
from hashlib import sha256
|
|
24
28
|
import json
|
|
25
29
|
import os
|
|
26
30
|
import re
|
|
@@ -29,11 +33,11 @@ import shutil
|
|
|
29
33
|
import subprocess
|
|
30
34
|
import sys
|
|
31
35
|
import time
|
|
32
|
-
from collections.abc import Iterable
|
|
33
|
-
from dataclasses import dataclass
|
|
34
36
|
from pathlib import Path
|
|
37
|
+
from urllib.parse import urlparse
|
|
38
|
+
from urllib.request import url2pathname
|
|
35
39
|
|
|
36
|
-
from claude_smart import context_format, env_config, ids, publish, state
|
|
40
|
+
from claude_smart import context_format, cs_cite, env_config, ids, publish, state
|
|
37
41
|
from claude_smart.reflexio_adapter import Adapter
|
|
38
42
|
|
|
39
43
|
_REFLEXIO_ENV_PATH = env_config.REFLEXIO_ENV_PATH
|
|
@@ -56,6 +60,8 @@ _CODEX_PLUGIN_CACHE_DIR = (
|
|
|
56
60
|
/ "claude-smart"
|
|
57
61
|
)
|
|
58
62
|
_CODEX_CLI_TIMEOUT_SECONDS = 30
|
|
63
|
+
_OPENCODE_BARE_PLUGIN_SPEC = "claude-smart"
|
|
64
|
+
_OPENCODE_CONFIG_NAMES = ("opencode.json", "opencode.jsonc")
|
|
59
65
|
_REFLEXIO_UNREACHABLE_MSG = (
|
|
60
66
|
"Failed to reach reflexio. Check ~/.claude-smart/backend.log "
|
|
61
67
|
"or restart Claude Code.\n"
|
|
@@ -70,6 +76,9 @@ _BACKEND_SCRIPT = _SCRIPTS_DIR / "backend-service.sh"
|
|
|
70
76
|
_DASHBOARD_SCRIPT = _SCRIPTS_DIR / "dashboard-service.sh"
|
|
71
77
|
_REFLEXIO_DIR = Path.home() / ".reflexio"
|
|
72
78
|
_STATE_DIR = Path.home() / ".claude-smart"
|
|
79
|
+
_OPENCODE_LOCAL_PACKAGE_DIR = _STATE_DIR / "opencode" / "claude-smart"
|
|
80
|
+
_OPENCODE_PACKAGE_LOCK_TIMEOUT_SECONDS = 120.0
|
|
81
|
+
_OPENCODE_PACKAGE_LOCK_STALE_SECONDS = 10 * 60.0
|
|
73
82
|
_LOCAL_DATA_NOTICE = (
|
|
74
83
|
"Local data was kept so reinstalling claude-smart can reuse your learned "
|
|
75
84
|
"rules, sessions, logs, and local Reflexio data.\n"
|
|
@@ -83,7 +92,12 @@ _LOCAL_DATA_NOTICE = (
|
|
|
83
92
|
_INSTALL_FAILURE_MARKER = _STATE_DIR / "install-failed"
|
|
84
93
|
_SERVICE_STATUS_PROBE_FAILED = "probe_failed"
|
|
85
94
|
_DEFAULT_STORAGE_ROOT = _REFLEXIO_DIR / "data"
|
|
86
|
-
|
|
95
|
+
# Org id claude-smart's backend runs under (set via REFLEXIO_DEFAULT_ORG_ID in
|
|
96
|
+
# backend-service.sh). reflexio names the config file config_<org>.json, so this
|
|
97
|
+
# must stay in sync with that export; using our own org keeps us off the
|
|
98
|
+
# enterprise self-host backend's config_self-host-org.json.
|
|
99
|
+
_REFLEXIO_ORG_ID = "claude-smart"
|
|
100
|
+
_REFLEXIO_CONFIG_PATH = _REFLEXIO_DIR / "configs" / f"config_{_REFLEXIO_ORG_ID}.json"
|
|
87
101
|
_LOCAL_STORAGE_ENV = "LOCAL_STORAGE_PATH"
|
|
88
102
|
_CODEX_REQUIRED_FILES = (
|
|
89
103
|
Path(".agents/plugins/marketplace.json"),
|
|
@@ -92,6 +106,9 @@ _CODEX_REQUIRED_FILES = (
|
|
|
92
106
|
Path("plugin/scripts/codex-claude-compat"),
|
|
93
107
|
Path("plugin/scripts/codex-claude-compat.cmd"),
|
|
94
108
|
Path("plugin/scripts/codex-claude-compat.js"),
|
|
109
|
+
Path("plugin/scripts/opencode-claude-compat"),
|
|
110
|
+
Path("plugin/scripts/opencode-claude-compat.cmd"),
|
|
111
|
+
Path("plugin/scripts/opencode-claude-compat.js"),
|
|
95
112
|
Path("plugin/scripts/codex-hook.js"),
|
|
96
113
|
Path("plugin/scripts/backend-log-runner.sh"),
|
|
97
114
|
Path("plugin/scripts/_codex_env.sh"),
|
|
@@ -103,6 +120,7 @@ _COPYTREE_IGNORE = shutil.ignore_patterns(
|
|
|
103
120
|
"*.pyo",
|
|
104
121
|
".pytest_cache",
|
|
105
122
|
".ruff_cache",
|
|
123
|
+
".git",
|
|
106
124
|
".next",
|
|
107
125
|
"node_modules",
|
|
108
126
|
)
|
|
@@ -963,6 +981,391 @@ def _configure_reflexio_setup() -> bool:
|
|
|
963
981
|
return read_only
|
|
964
982
|
|
|
965
983
|
|
|
984
|
+
def _strip_jsonc(text: str) -> str:
|
|
985
|
+
"""Remove JSONC comments and trailing commas without touching strings."""
|
|
986
|
+
|
|
987
|
+
def skip_trivia(index: int) -> int:
|
|
988
|
+
while index < len(text):
|
|
989
|
+
while index < len(text) and text[index].isspace():
|
|
990
|
+
index += 1
|
|
991
|
+
if text[index : index + 2] == "//":
|
|
992
|
+
index += 2
|
|
993
|
+
while index < len(text) and text[index] not in "\r\n":
|
|
994
|
+
index += 1
|
|
995
|
+
continue
|
|
996
|
+
if text[index : index + 2] == "/*":
|
|
997
|
+
index += 2
|
|
998
|
+
while index + 1 < len(text) and text[index : index + 2] != "*/":
|
|
999
|
+
index += 1
|
|
1000
|
+
index = min(index + 2, len(text))
|
|
1001
|
+
continue
|
|
1002
|
+
break
|
|
1003
|
+
return index
|
|
1004
|
+
|
|
1005
|
+
out: list[str] = []
|
|
1006
|
+
in_string = False
|
|
1007
|
+
escaped = False
|
|
1008
|
+
i = 0
|
|
1009
|
+
while i < len(text):
|
|
1010
|
+
ch = text[i]
|
|
1011
|
+
nxt = text[i + 1] if i + 1 < len(text) else ""
|
|
1012
|
+
if in_string:
|
|
1013
|
+
out.append(ch)
|
|
1014
|
+
if escaped:
|
|
1015
|
+
escaped = False
|
|
1016
|
+
elif ch == "\\":
|
|
1017
|
+
escaped = True
|
|
1018
|
+
elif ch == '"':
|
|
1019
|
+
in_string = False
|
|
1020
|
+
i += 1
|
|
1021
|
+
continue
|
|
1022
|
+
if ch == '"':
|
|
1023
|
+
in_string = True
|
|
1024
|
+
out.append(ch)
|
|
1025
|
+
i += 1
|
|
1026
|
+
continue
|
|
1027
|
+
if ch == "/" and nxt == "/":
|
|
1028
|
+
while i < len(text) and text[i] not in "\r\n":
|
|
1029
|
+
i += 1
|
|
1030
|
+
continue
|
|
1031
|
+
if ch == "/" and nxt == "*":
|
|
1032
|
+
i += 2
|
|
1033
|
+
while i + 1 < len(text) and not (text[i] == "*" and text[i + 1] == "/"):
|
|
1034
|
+
i += 1
|
|
1035
|
+
i += 2
|
|
1036
|
+
continue
|
|
1037
|
+
if ch == ",":
|
|
1038
|
+
j = skip_trivia(i + 1)
|
|
1039
|
+
if j < len(text) and text[j] in "}]":
|
|
1040
|
+
i += 1
|
|
1041
|
+
continue
|
|
1042
|
+
out.append(ch)
|
|
1043
|
+
i += 1
|
|
1044
|
+
return "".join(out)
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
def _read_jsonc_object(path: Path) -> dict[str, object]:
|
|
1048
|
+
try:
|
|
1049
|
+
text = path.read_text() if path.exists() else "{}"
|
|
1050
|
+
parsed = json.loads(_strip_jsonc(text or "{}"))
|
|
1051
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
1052
|
+
raise ValueError(f"could not parse OpenCode config {path}: {exc}") from exc
|
|
1053
|
+
if not isinstance(parsed, dict):
|
|
1054
|
+
raise ValueError(f"OpenCode config {path} must be a JSON object")
|
|
1055
|
+
return parsed
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
def _opencode_global_config_dir() -> Path:
|
|
1059
|
+
xdg = os.environ.get("XDG_CONFIG_HOME", "").strip()
|
|
1060
|
+
base = Path(xdg) if xdg else Path.home() / ".config"
|
|
1061
|
+
return base / "opencode"
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
def _opencode_config_path(*, global_config: bool = False, cwd: Path | None = None) -> Path:
|
|
1065
|
+
if global_config:
|
|
1066
|
+
config_dir = _opencode_global_config_dir()
|
|
1067
|
+
for name in _OPENCODE_CONFIG_NAMES:
|
|
1068
|
+
candidate = config_dir / name
|
|
1069
|
+
if candidate.exists():
|
|
1070
|
+
return candidate
|
|
1071
|
+
return config_dir / "opencode.json"
|
|
1072
|
+
base = cwd or Path.cwd()
|
|
1073
|
+
candidates = [
|
|
1074
|
+
*(base / name for name in _OPENCODE_CONFIG_NAMES),
|
|
1075
|
+
*(base / ".opencode" / name for name in _OPENCODE_CONFIG_NAMES),
|
|
1076
|
+
]
|
|
1077
|
+
for candidate in candidates:
|
|
1078
|
+
if candidate.exists():
|
|
1079
|
+
return candidate
|
|
1080
|
+
return base / "opencode.json"
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
def _opencode_plugin_spec(entry: object) -> str | None:
|
|
1084
|
+
if isinstance(entry, str):
|
|
1085
|
+
return entry
|
|
1086
|
+
if isinstance(entry, list) and entry and isinstance(entry[0], str):
|
|
1087
|
+
return entry[0]
|
|
1088
|
+
return None
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
def _opencode_local_plugin_spec(
|
|
1092
|
+
package_root: Path = _OPENCODE_LOCAL_PACKAGE_DIR,
|
|
1093
|
+
) -> str:
|
|
1094
|
+
return package_root.resolve(strict=False).as_uri()
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
def _is_default_opencode_package_path(package_path: Path) -> bool:
|
|
1098
|
+
if _same_real_path(package_path, _OPENCODE_LOCAL_PACKAGE_DIR):
|
|
1099
|
+
return True
|
|
1100
|
+
try:
|
|
1101
|
+
return package_path.resolve(strict=False) == _OPENCODE_LOCAL_PACKAGE_DIR.resolve(
|
|
1102
|
+
strict=False
|
|
1103
|
+
)
|
|
1104
|
+
except OSError:
|
|
1105
|
+
return False
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
def _is_opencode_claude_smart_spec(spec: str | None) -> bool:
|
|
1109
|
+
if not spec:
|
|
1110
|
+
return False
|
|
1111
|
+
if spec == _OPENCODE_BARE_PLUGIN_SPEC or spec.startswith(
|
|
1112
|
+
f"{_OPENCODE_BARE_PLUGIN_SPEC}@"
|
|
1113
|
+
):
|
|
1114
|
+
return True
|
|
1115
|
+
parsed = urlparse(spec)
|
|
1116
|
+
if parsed.scheme != "file":
|
|
1117
|
+
return False
|
|
1118
|
+
package_path = Path(url2pathname(parsed.path))
|
|
1119
|
+
if _is_default_opencode_package_path(package_path):
|
|
1120
|
+
return True
|
|
1121
|
+
try:
|
|
1122
|
+
manifest = json.loads((package_path / "package.json").read_text())
|
|
1123
|
+
if manifest.get("name") == _OPENCODE_BARE_PLUGIN_SPEC:
|
|
1124
|
+
return True
|
|
1125
|
+
except (OSError, json.JSONDecodeError):
|
|
1126
|
+
pass
|
|
1127
|
+
return False
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
def _patch_opencode_plugin_config(
|
|
1131
|
+
config_path: Path, *, install: bool, plugin_spec: str | None = None
|
|
1132
|
+
) -> tuple[bool, Path]:
|
|
1133
|
+
if install and plugin_spec is None:
|
|
1134
|
+
plugin_spec = _opencode_local_plugin_spec()
|
|
1135
|
+
data = _read_jsonc_object(config_path)
|
|
1136
|
+
for field in ("plugins", "plugin"):
|
|
1137
|
+
value = data.get(field)
|
|
1138
|
+
if value is not None and not isinstance(value, list):
|
|
1139
|
+
raise ValueError(
|
|
1140
|
+
f'OpenCode config {config_path} field "{field}" must be a JSON array'
|
|
1141
|
+
)
|
|
1142
|
+
current_plugin = data.get("plugin")
|
|
1143
|
+
plugins: list[object] = []
|
|
1144
|
+
if isinstance(current_plugin, list):
|
|
1145
|
+
plugins.extend(current_plugin)
|
|
1146
|
+
legacy_plugins = data.get("plugins")
|
|
1147
|
+
if isinstance(legacy_plugins, list):
|
|
1148
|
+
plugins.extend(legacy_plugins)
|
|
1149
|
+
kept = [
|
|
1150
|
+
item
|
|
1151
|
+
for item in plugins
|
|
1152
|
+
if not _is_opencode_claude_smart_spec(_opencode_plugin_spec(item))
|
|
1153
|
+
]
|
|
1154
|
+
if install:
|
|
1155
|
+
assert plugin_spec is not None
|
|
1156
|
+
next_plugins = [*kept, plugin_spec]
|
|
1157
|
+
else:
|
|
1158
|
+
next_plugins = kept
|
|
1159
|
+
if isinstance(current_plugin, list):
|
|
1160
|
+
changed = ("plugins" in data) or next_plugins != current_plugin
|
|
1161
|
+
else:
|
|
1162
|
+
changed = ("plugins" in data) or (install and bool(next_plugins))
|
|
1163
|
+
if not changed:
|
|
1164
|
+
return False, config_path
|
|
1165
|
+
if config_path.exists():
|
|
1166
|
+
original = config_path.read_text()
|
|
1167
|
+
if original.strip() and original != _strip_jsonc(original):
|
|
1168
|
+
config_path.with_suffix(config_path.suffix + ".bak").write_text(original)
|
|
1169
|
+
data["plugin"] = next_plugins
|
|
1170
|
+
data.pop("plugins", None)
|
|
1171
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1172
|
+
config_path.write_text(json.dumps(data, indent=2) + "\n")
|
|
1173
|
+
return True, config_path
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
def _has_extraction_provider() -> bool:
|
|
1177
|
+
env_config.load_reflexio_env(_REFLEXIO_ENV_PATH)
|
|
1178
|
+
if os.environ.get(env_config.REFLEXIO_API_KEY_ENV, "").strip():
|
|
1179
|
+
return True
|
|
1180
|
+
cli_path = os.environ.get("CLAUDE_SMART_CLI_PATH", "").strip()
|
|
1181
|
+
if cli_path:
|
|
1182
|
+
resolved = Path(cli_path).expanduser()
|
|
1183
|
+
if resolved.is_file() and os.access(resolved, os.X_OK):
|
|
1184
|
+
return True
|
|
1185
|
+
return bool(shutil.which("claude") or shutil.which("codex") or shutil.which("opencode"))
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
def _extraction_provider_error() -> str:
|
|
1189
|
+
return (
|
|
1190
|
+
"error: OpenCode support needs a working learning/extraction provider.\n"
|
|
1191
|
+
"Run `npx claude-smart setup` to configure Reflexio, or install "
|
|
1192
|
+
"OpenCode, Claude Code, or Codex so local extraction can use a supported CLI.\n"
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
def _opencode_install_supported_from_this_package() -> bool:
|
|
1197
|
+
return (_SCRIPTS_DIR / "smart-install.sh").is_file()
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
def _file_sha256(path: Path) -> str:
|
|
1201
|
+
return sha256(path.read_bytes()).hexdigest()
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
def _same_real_path(left: Path, right: Path) -> bool:
|
|
1205
|
+
try:
|
|
1206
|
+
return left.resolve(strict=True) == right.resolve(strict=True)
|
|
1207
|
+
except OSError:
|
|
1208
|
+
return False
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
def _verify_opencode_plugin_package(package_root: Path) -> None:
|
|
1212
|
+
source_script = _PLUGIN_ROOT / "scripts" / "smart-install.sh"
|
|
1213
|
+
copied_script = package_root / "plugin" / "scripts" / "smart-install.sh"
|
|
1214
|
+
for path in (package_root / "package.json", copied_script):
|
|
1215
|
+
if not path.exists():
|
|
1216
|
+
raise OSError(f"OpenCode local plugin package is missing {path}")
|
|
1217
|
+
if _file_sha256(source_script) != _file_sha256(copied_script):
|
|
1218
|
+
raise OSError(
|
|
1219
|
+
"OpenCode local plugin package does not match the installed claude-smart package"
|
|
1220
|
+
)
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
@contextmanager
|
|
1224
|
+
def _opencode_package_install_lock(package_root: Path) -> Iterator[None]:
|
|
1225
|
+
lock_dir = package_root.parent / ".install.lock"
|
|
1226
|
+
package_root.parent.mkdir(parents=True, exist_ok=True)
|
|
1227
|
+
deadline = time.monotonic() + _OPENCODE_PACKAGE_LOCK_TIMEOUT_SECONDS
|
|
1228
|
+
while True:
|
|
1229
|
+
try:
|
|
1230
|
+
lock_dir.mkdir()
|
|
1231
|
+
break
|
|
1232
|
+
except FileExistsError:
|
|
1233
|
+
try:
|
|
1234
|
+
stale = (
|
|
1235
|
+
time.time() - lock_dir.stat().st_mtime
|
|
1236
|
+
> _OPENCODE_PACKAGE_LOCK_STALE_SECONDS
|
|
1237
|
+
)
|
|
1238
|
+
except OSError:
|
|
1239
|
+
stale = False
|
|
1240
|
+
if stale:
|
|
1241
|
+
shutil.rmtree(lock_dir, ignore_errors=True)
|
|
1242
|
+
continue
|
|
1243
|
+
if time.monotonic() >= deadline:
|
|
1244
|
+
raise OSError(
|
|
1245
|
+
f"timed out waiting for OpenCode package install lock at {lock_dir}"
|
|
1246
|
+
)
|
|
1247
|
+
time.sleep(0.1)
|
|
1248
|
+
try:
|
|
1249
|
+
yield
|
|
1250
|
+
finally:
|
|
1251
|
+
shutil.rmtree(lock_dir, ignore_errors=True)
|
|
1252
|
+
|
|
1253
|
+
|
|
1254
|
+
def _unique_opencode_package_path(parent: Path, prefix: str) -> Path:
|
|
1255
|
+
return parent / f"{prefix}-{os.getpid()}-{time.monotonic_ns()}"
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
def _replace_opencode_plugin_package(staged_package: Path, package_root: Path) -> None:
|
|
1259
|
+
backup_package = _unique_opencode_package_path(
|
|
1260
|
+
package_root.parent, ".claude-smart-previous"
|
|
1261
|
+
)
|
|
1262
|
+
backup_created = False
|
|
1263
|
+
try:
|
|
1264
|
+
if package_root.exists() or package_root.is_symlink():
|
|
1265
|
+
package_root.rename(backup_package)
|
|
1266
|
+
backup_created = True
|
|
1267
|
+
staged_package.rename(package_root)
|
|
1268
|
+
if backup_created:
|
|
1269
|
+
shutil.rmtree(backup_package, ignore_errors=True)
|
|
1270
|
+
except OSError:
|
|
1271
|
+
if backup_created and not package_root.exists() and backup_package.exists():
|
|
1272
|
+
backup_package.rename(package_root)
|
|
1273
|
+
raise
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
def _install_opencode_plugin_package() -> Path:
|
|
1277
|
+
package_root = _OPENCODE_LOCAL_PACKAGE_DIR
|
|
1278
|
+
if _same_real_path(_REPO_ROOT, package_root):
|
|
1279
|
+
_verify_opencode_plugin_package(package_root)
|
|
1280
|
+
return package_root
|
|
1281
|
+
with _opencode_package_install_lock(package_root):
|
|
1282
|
+
staged_package = _unique_opencode_package_path(
|
|
1283
|
+
package_root.parent, ".claude-smart-copy"
|
|
1284
|
+
)
|
|
1285
|
+
shutil.rmtree(staged_package, ignore_errors=True)
|
|
1286
|
+
try:
|
|
1287
|
+
shutil.copytree(_REPO_ROOT, staged_package, ignore=_COPYTREE_IGNORE)
|
|
1288
|
+
_verify_opencode_plugin_package(staged_package)
|
|
1289
|
+
_replace_opencode_plugin_package(staged_package, package_root)
|
|
1290
|
+
_verify_opencode_plugin_package(package_root)
|
|
1291
|
+
finally:
|
|
1292
|
+
shutil.rmtree(staged_package, ignore_errors=True)
|
|
1293
|
+
return package_root
|
|
1294
|
+
|
|
1295
|
+
|
|
1296
|
+
def _bootstrap_opencode_install(read_only: bool) -> tuple[bool, str]:
|
|
1297
|
+
if not _opencode_install_supported_from_this_package():
|
|
1298
|
+
return (
|
|
1299
|
+
False,
|
|
1300
|
+
"OpenCode install is supported from the npm package. "
|
|
1301
|
+
"Run `npx claude-smart install --host opencode`.",
|
|
1302
|
+
)
|
|
1303
|
+
try:
|
|
1304
|
+
package_root = _install_opencode_plugin_package()
|
|
1305
|
+
except OSError as exc:
|
|
1306
|
+
return False, str(exc)
|
|
1307
|
+
plugin_root = package_root / "plugin"
|
|
1308
|
+
try:
|
|
1309
|
+
_force_plugin_root(plugin_root)
|
|
1310
|
+
except OSError as exc:
|
|
1311
|
+
return False, str(exc)
|
|
1312
|
+
bash = _resolve_bash()
|
|
1313
|
+
if not bash:
|
|
1314
|
+
return False, "bash is required to bootstrap claude-smart dependencies"
|
|
1315
|
+
scripts_dir = plugin_root / "scripts"
|
|
1316
|
+
result = subprocess.run([bash, str(scripts_dir / "smart-install.sh")], cwd=plugin_root)
|
|
1317
|
+
if result.returncode != 0:
|
|
1318
|
+
return False, f"smart-install.sh failed in {plugin_root}"
|
|
1319
|
+
if _INSTALL_FAILURE_MARKER.is_file():
|
|
1320
|
+
first_line = _INSTALL_FAILURE_MARKER.read_text().splitlines()
|
|
1321
|
+
reason = (first_line[0].strip() if first_line else "") or "unknown error"
|
|
1322
|
+
return False, reason
|
|
1323
|
+
if read_only:
|
|
1324
|
+
_prune_publish_hooks_for_read_only(plugin_root)
|
|
1325
|
+
return True, str(package_root)
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
def cmd_install_opencode(args: argparse.Namespace) -> int:
|
|
1329
|
+
if not _opencode_install_supported_from_this_package():
|
|
1330
|
+
sys.stderr.write(
|
|
1331
|
+
"error: OpenCode install is supported from the npm package. "
|
|
1332
|
+
"Run `npx claude-smart install --host opencode`.\n"
|
|
1333
|
+
)
|
|
1334
|
+
return 1
|
|
1335
|
+
read_only = _configure_reflexio_setup()
|
|
1336
|
+
if not _has_extraction_provider():
|
|
1337
|
+
sys.stderr.write(_extraction_provider_error())
|
|
1338
|
+
return 1
|
|
1339
|
+
bootstrapped, package_root_text = _bootstrap_opencode_install(read_only)
|
|
1340
|
+
if not bootstrapped:
|
|
1341
|
+
sys.stderr.write(
|
|
1342
|
+
f"error: claude-smart OpenCode setup failed during dependency bootstrap: {package_root_text}\n"
|
|
1343
|
+
)
|
|
1344
|
+
return 1
|
|
1345
|
+
package_root = Path(package_root_text)
|
|
1346
|
+
plugin_root = package_root / "plugin"
|
|
1347
|
+
plugin_spec = _opencode_local_plugin_spec(package_root)
|
|
1348
|
+
config_path = _opencode_config_path(
|
|
1349
|
+
global_config=bool(getattr(args, "global_config", False))
|
|
1350
|
+
)
|
|
1351
|
+
try:
|
|
1352
|
+
changed, config_path = _patch_opencode_plugin_config(
|
|
1353
|
+
config_path,
|
|
1354
|
+
install=True,
|
|
1355
|
+
plugin_spec=plugin_spec,
|
|
1356
|
+
)
|
|
1357
|
+
except ValueError as exc:
|
|
1358
|
+
sys.stderr.write(f"error: {exc}\n")
|
|
1359
|
+
return 1
|
|
1360
|
+
action = "Updated" if changed else "OpenCode config already includes"
|
|
1361
|
+
sys.stdout.write(
|
|
1362
|
+
f"{action} `{plugin_spec}` in {config_path}.\n"
|
|
1363
|
+
f"Prepared claude-smart runtime at {plugin_root}.\n"
|
|
1364
|
+
"Restart OpenCode in your project so it loads the plugin.\n"
|
|
1365
|
+
)
|
|
1366
|
+
return 0
|
|
1367
|
+
|
|
1368
|
+
|
|
966
1369
|
def cmd_install_codex(args: argparse.Namespace) -> int:
|
|
967
1370
|
"""Install the claude-smart plugin marketplace for Codex.
|
|
968
1371
|
|
|
@@ -1073,7 +1476,7 @@ def cmd_install(args: argparse.Namespace) -> int:
|
|
|
1073
1476
|
|
|
1074
1477
|
Runs ``claude plugin marketplace add`` (pointed at the bundled marketplace
|
|
1075
1478
|
at ``_REPO_ROOT``) followed by ``claude plugin install``, then appends the
|
|
1076
|
-
local-provider flags to ``~/.
|
|
1479
|
+
local-provider flags to ``~/.claude-smart/.env`` so reflexio can route
|
|
1077
1480
|
generation through the local Claude Code CLI.
|
|
1078
1481
|
|
|
1079
1482
|
Args:
|
|
@@ -1084,6 +1487,8 @@ def cmd_install(args: argparse.Namespace) -> int:
|
|
|
1084
1487
|
"""
|
|
1085
1488
|
if getattr(args, "host", "claude-code") == "codex":
|
|
1086
1489
|
return cmd_install_codex(args)
|
|
1490
|
+
if getattr(args, "host", "claude-code") == "opencode":
|
|
1491
|
+
return cmd_install_opencode(args)
|
|
1087
1492
|
|
|
1088
1493
|
if not shutil.which("claude"):
|
|
1089
1494
|
sys.stderr.write(
|
|
@@ -1156,6 +1561,8 @@ def cmd_update(args: argparse.Namespace) -> int:
|
|
|
1156
1561
|
"""
|
|
1157
1562
|
if getattr(args, "host", "claude-code") == "codex":
|
|
1158
1563
|
return cmd_update_codex(args)
|
|
1564
|
+
if getattr(args, "host", "claude-code") == "opencode":
|
|
1565
|
+
return cmd_update_opencode(args)
|
|
1159
1566
|
|
|
1160
1567
|
_run_service(_DASHBOARD_SCRIPT, "stop")
|
|
1161
1568
|
_run_service(_BACKEND_SCRIPT, "stop")
|
|
@@ -1182,6 +1589,17 @@ def cmd_update_codex(_args: argparse.Namespace) -> int:
|
|
|
1182
1589
|
return cmd_install_codex(install_args)
|
|
1183
1590
|
|
|
1184
1591
|
|
|
1592
|
+
def cmd_update_opencode(args: argparse.Namespace) -> int:
|
|
1593
|
+
_run_service(_DASHBOARD_SCRIPT, "stop")
|
|
1594
|
+
_run_service(_BACKEND_SCRIPT, "stop")
|
|
1595
|
+
sys.stdout.write(
|
|
1596
|
+
"Updating claude-smart OpenCode support by reinstalling from this package...\n"
|
|
1597
|
+
)
|
|
1598
|
+
install_args = argparse.Namespace(**vars(args))
|
|
1599
|
+
install_args.host = "opencode"
|
|
1600
|
+
return cmd_install_opencode(install_args)
|
|
1601
|
+
|
|
1602
|
+
|
|
1185
1603
|
def cmd_uninstall(_args: argparse.Namespace) -> int:
|
|
1186
1604
|
"""Uninstall claude-smart from Claude Code via the native plugin CLI.
|
|
1187
1605
|
|
|
@@ -1196,6 +1614,8 @@ def cmd_uninstall(_args: argparse.Namespace) -> int:
|
|
|
1196
1614
|
"""
|
|
1197
1615
|
if getattr(_args, "host", "claude-code") == "codex":
|
|
1198
1616
|
return cmd_uninstall_codex(_args)
|
|
1617
|
+
if getattr(_args, "host", "claude-code") == "opencode":
|
|
1618
|
+
return cmd_uninstall_opencode(_args)
|
|
1199
1619
|
|
|
1200
1620
|
if not shutil.which("claude"):
|
|
1201
1621
|
sys.stderr.write(
|
|
@@ -1256,6 +1676,40 @@ def cmd_uninstall_codex(_args: argparse.Namespace) -> int:
|
|
|
1256
1676
|
return 0
|
|
1257
1677
|
|
|
1258
1678
|
|
|
1679
|
+
def cmd_uninstall_opencode(args: argparse.Namespace) -> int:
|
|
1680
|
+
_run_service(_DASHBOARD_SCRIPT, "stop")
|
|
1681
|
+
_run_service(_BACKEND_SCRIPT, "stop")
|
|
1682
|
+
local_scripts = _OPENCODE_LOCAL_PACKAGE_DIR / "plugin" / "scripts"
|
|
1683
|
+
for script in (
|
|
1684
|
+
local_scripts / "dashboard-service.sh",
|
|
1685
|
+
local_scripts / "backend-service.sh",
|
|
1686
|
+
):
|
|
1687
|
+
if script.exists():
|
|
1688
|
+
_run_service(script, "stop")
|
|
1689
|
+
config_path = _opencode_config_path(
|
|
1690
|
+
global_config=bool(getattr(args, "global_config", False))
|
|
1691
|
+
)
|
|
1692
|
+
try:
|
|
1693
|
+
changed, config_path = _patch_opencode_plugin_config(config_path, install=False)
|
|
1694
|
+
except ValueError as exc:
|
|
1695
|
+
sys.stderr.write(f"error: {exc}\n")
|
|
1696
|
+
return 1
|
|
1697
|
+
shutil.rmtree(_OPENCODE_LOCAL_PACKAGE_DIR, ignore_errors=True)
|
|
1698
|
+
try:
|
|
1699
|
+
_OPENCODE_LOCAL_PACKAGE_DIR.parent.rmdir()
|
|
1700
|
+
except OSError:
|
|
1701
|
+
pass
|
|
1702
|
+
if changed:
|
|
1703
|
+
sys.stdout.write(f"Removed claude-smart OpenCode plugin entries from {config_path}.\n")
|
|
1704
|
+
else:
|
|
1705
|
+
sys.stdout.write("OpenCode config did not include claude-smart.\n")
|
|
1706
|
+
sys.stdout.write(
|
|
1707
|
+
"Restart OpenCode to apply. "
|
|
1708
|
+
f"{_LOCAL_DATA_NOTICE}"
|
|
1709
|
+
)
|
|
1710
|
+
return 0
|
|
1711
|
+
|
|
1712
|
+
|
|
1259
1713
|
def cmd_show(args: argparse.Namespace) -> int:
|
|
1260
1714
|
"""Print this project's skills + preferences, plus globally-shared skills.
|
|
1261
1715
|
|
|
@@ -1292,12 +1746,26 @@ def cmd_show(args: argparse.Namespace) -> int:
|
|
|
1292
1746
|
f"First error: {adapter.read_errors[0]}\n"
|
|
1293
1747
|
)
|
|
1294
1748
|
return 1
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
)
|
|
1749
|
+
body = md or f"_No skills or preferences yet for project `{project_id}`._\n"
|
|
1750
|
+
sys.stdout.write(body + _reflexio_show_footer())
|
|
1298
1751
|
return 0
|
|
1299
1752
|
|
|
1300
1753
|
|
|
1754
|
+
def _reflexio_show_footer() -> str:
|
|
1755
|
+
"""Return the markdown attribution footer appended to ``show`` output.
|
|
1756
|
+
|
|
1757
|
+
Reinforces that claude-smart is powered by the open-source reflexio engine
|
|
1758
|
+
and nudges users to star the repo.
|
|
1759
|
+
|
|
1760
|
+
Returns:
|
|
1761
|
+
str: A leading-separator markdown footer ending in a newline.
|
|
1762
|
+
"""
|
|
1763
|
+
return (
|
|
1764
|
+
f"\n---\n⭐ claude-smart is powered by [reflexio]({cs_cite.REFLEXIO_REPO_URL})"
|
|
1765
|
+
f" — if it helps you, [star it on GitHub]({cs_cite.REFLEXIO_REPO_URL}).\n"
|
|
1766
|
+
)
|
|
1767
|
+
|
|
1768
|
+
|
|
1301
1769
|
def cmd_learn(args: argparse.Namespace) -> int:
|
|
1302
1770
|
"""Force reflexio extraction over the active session's interactions.
|
|
1303
1771
|
|
|
@@ -1981,28 +2449,46 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
1981
2449
|
inst = sub.add_parser("install", help="Install claude-smart")
|
|
1982
2450
|
inst.add_argument(
|
|
1983
2451
|
"--host",
|
|
1984
|
-
choices=("claude-code", "codex"),
|
|
2452
|
+
choices=("claude-code", "codex", "opencode"),
|
|
1985
2453
|
default="claude-code",
|
|
1986
2454
|
help="Install target host",
|
|
1987
2455
|
)
|
|
2456
|
+
inst.add_argument(
|
|
2457
|
+
"--global",
|
|
2458
|
+
dest="global_config",
|
|
2459
|
+
action="store_true",
|
|
2460
|
+
help="For OpenCode, patch ~/.config/opencode instead of the project config",
|
|
2461
|
+
)
|
|
1988
2462
|
inst.set_defaults(func=cmd_install)
|
|
1989
2463
|
|
|
1990
2464
|
upd = sub.add_parser("update", help="Update claude-smart to the latest version")
|
|
1991
2465
|
upd.add_argument(
|
|
1992
2466
|
"--host",
|
|
1993
|
-
choices=("claude-code", "codex"),
|
|
2467
|
+
choices=("claude-code", "codex", "opencode"),
|
|
1994
2468
|
default="claude-code",
|
|
1995
2469
|
help="Update target host",
|
|
1996
2470
|
)
|
|
2471
|
+
upd.add_argument(
|
|
2472
|
+
"--global",
|
|
2473
|
+
dest="global_config",
|
|
2474
|
+
action="store_true",
|
|
2475
|
+
help="For OpenCode, patch ~/.config/opencode instead of the project config",
|
|
2476
|
+
)
|
|
1997
2477
|
upd.set_defaults(func=cmd_update)
|
|
1998
2478
|
|
|
1999
2479
|
uni = sub.add_parser("uninstall", help="Remove claude-smart")
|
|
2000
2480
|
uni.add_argument(
|
|
2001
2481
|
"--host",
|
|
2002
|
-
choices=("claude-code", "codex"),
|
|
2482
|
+
choices=("claude-code", "codex", "opencode"),
|
|
2003
2483
|
default="claude-code",
|
|
2004
2484
|
help="Uninstall target host",
|
|
2005
2485
|
)
|
|
2486
|
+
uni.add_argument(
|
|
2487
|
+
"--global",
|
|
2488
|
+
dest="global_config",
|
|
2489
|
+
action="store_true",
|
|
2490
|
+
help="For OpenCode, patch ~/.config/opencode instead of the project config",
|
|
2491
|
+
)
|
|
2006
2492
|
uni.set_defaults(func=cmd_uninstall)
|
|
2007
2493
|
|
|
2008
2494
|
sh = sub.add_parser(
|
|
@@ -269,7 +269,7 @@ def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str:
|
|
|
269
269
|
gate = cs_cite.WHEN_TO_CITE_COMPACT
|
|
270
270
|
link_style = os.environ.get(_CITATION_LINK_STYLE_ENV, "markdown")
|
|
271
271
|
if link_style == "osc8" and marker_parts:
|
|
272
|
-
marker =
|
|
272
|
+
marker = cs_cite.build_marker(" | ".join(marker_parts), "osc8")
|
|
273
273
|
separator_instruction = (
|
|
274
274
|
" Separate multiple linked memories with the visible ` | ` separator."
|
|
275
275
|
if len(marker_parts) > 1
|
|
@@ -281,12 +281,13 @@ def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str:
|
|
|
281
281
|
)
|
|
282
282
|
if link_style == "osc8":
|
|
283
283
|
return _remoteize_citation_instruction(
|
|
284
|
-
f"{gate} If you do, end with
|
|
285
|
-
"followed by the same linked memory text
|
|
286
|
-
"
|
|
284
|
+
f"{gate} If you do, end with `{cs_cite.MARKER_PREFIX}` "
|
|
285
|
+
"followed by the same linked memory text, then "
|
|
286
|
+
f"`{cs_cite.marker_attribution('osc8')}` linking to the reflexio "
|
|
287
|
+
"repo; keep the links, but do not show the URL."
|
|
287
288
|
)
|
|
288
289
|
if marker_parts:
|
|
289
|
-
marker =
|
|
290
|
+
marker = cs_cite.build_marker(" | ".join(marker_parts), "markdown")
|
|
290
291
|
separator_instruction = (
|
|
291
292
|
" Separate multiple linked memories with the visible ` | ` separator."
|
|
292
293
|
if len(marker_parts) > 1
|
|
@@ -297,9 +298,8 @@ def _compact_citation_instruction(marker_parts: list[str] | None = None) -> str:
|
|
|
297
298
|
f"links: `{marker}`.{separator_instruction}"
|
|
298
299
|
)
|
|
299
300
|
return _remoteize_citation_instruction(
|
|
300
|
-
f"{gate} If you do, end with one final marker like
|
|
301
|
-
"
|
|
302
|
-
"s1-123)` using the shown rule URL."
|
|
301
|
+
f"{gate} If you do, end with one final marker like "
|
|
302
|
+
f"`{cs_cite.MARKDOWN_EXAMPLE_ONE}` using the shown rule URL."
|
|
303
303
|
)
|
|
304
304
|
|
|
305
305
|
|
|
@@ -337,7 +337,7 @@ def _exact_osc8_marker_instruction(entries: list[dict[str, Any]]) -> str:
|
|
|
337
337
|
if not marker_parts:
|
|
338
338
|
return ""
|
|
339
339
|
|
|
340
|
-
marker =
|
|
340
|
+
marker = cs_cite.build_marker(" | ".join(marker_parts), "osc8")
|
|
341
341
|
return (
|
|
342
342
|
"If any listed memory above was used, copy this exact final marker, "
|
|
343
343
|
f"preserving its hidden OSC 8 terminal links: `{marker}`. "
|