code-muse 0.0.1__py3-none-any.whl
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.
- code_muse/__init__.py +26 -0
- code_muse/__main__.py +10 -0
- code_muse/agents/__init__.py +31 -0
- code_muse/agents/_builder.py +214 -0
- code_muse/agents/_compaction.py +506 -0
- code_muse/agents/_diagnostics.py +171 -0
- code_muse/agents/_history.py +382 -0
- code_muse/agents/_key_listeners.py +148 -0
- code_muse/agents/_non_streaming_render.py +148 -0
- code_muse/agents/_runtime.py +596 -0
- code_muse/agents/agent_creator_agent.py +603 -0
- code_muse/agents/agent_helios.py +47 -0
- code_muse/agents/agent_manager.py +740 -0
- code_muse/agents/agent_muse.py +78 -0
- code_muse/agents/agent_planning.py +44 -0
- code_muse/agents/agent_qa_melpomene.py +207 -0
- code_muse/agents/base_agent.py +194 -0
- code_muse/agents/event_stream_handler.py +361 -0
- code_muse/agents/json_agent.py +201 -0
- code_muse/agents/prompt_v3.py +521 -0
- code_muse/agents/subagent_stream_handler.py +273 -0
- code_muse/callbacks.py +941 -0
- code_muse/chatgpt_codex_client.py +333 -0
- code_muse/claude_cache_client.py +853 -0
- code_muse/cli_runner/__init__.py +319 -0
- code_muse/cli_runner/args.py +63 -0
- code_muse/cli_runner/loop.py +510 -0
- code_muse/cli_runner/resume.py +72 -0
- code_muse/cli_runner/runner.py +161 -0
- code_muse/command_line/__init__.py +1 -0
- code_muse/command_line/add_model_menu.py +1331 -0
- code_muse/command_line/agent_menu.py +674 -0
- code_muse/command_line/attachments.py +397 -0
- code_muse/command_line/autosave_menu.py +709 -0
- code_muse/command_line/clipboard.py +528 -0
- code_muse/command_line/colors_menu.py +530 -0
- code_muse/command_line/command_handler.py +262 -0
- code_muse/command_line/command_registry.py +150 -0
- code_muse/command_line/config_commands.py +711 -0
- code_muse/command_line/core_commands.py +740 -0
- code_muse/command_line/diff_menu.py +865 -0
- code_muse/command_line/file_path_completion.py +73 -0
- code_muse/command_line/load_context_completion.py +57 -0
- code_muse/command_line/model_picker_completion.py +512 -0
- code_muse/command_line/model_settings_menu.py +983 -0
- code_muse/command_line/onboarding_slides.py +162 -0
- code_muse/command_line/onboarding_wizard.py +337 -0
- code_muse/command_line/pagination.py +41 -0
- code_muse/command_line/pin_command_completion.py +329 -0
- code_muse/command_line/prompt_toolkit_completion.py +886 -0
- code_muse/command_line/session_commands.py +304 -0
- code_muse/command_line/shell_passthrough.py +145 -0
- code_muse/command_line/skills_completion.py +158 -0
- code_muse/command_line/types.py +18 -0
- code_muse/command_line/uc_menu.py +908 -0
- code_muse/command_line/utils.py +105 -0
- code_muse/command_line/wiggum_state.py +77 -0
- code_muse/config.py +1138 -0
- code_muse/config_agent.py +168 -0
- code_muse/config_appearance.py +241 -0
- code_muse/config_model.py +357 -0
- code_muse/config_security.py +73 -0
- code_muse/error_logging.py +132 -0
- code_muse/evals/__init__.py +35 -0
- code_muse/evals/eval_helpers.py +81 -0
- code_muse/evals/eval_runner.py +299 -0
- code_muse/evals/sample_evals/__init__.py +1 -0
- code_muse/evals/sample_evals/eval_frugal_reads.py +59 -0
- code_muse/evals/sample_evals/eval_memory_planning.py +31 -0
- code_muse/evals/sample_evals/eval_shell_efficiency.py +39 -0
- code_muse/evals/sample_evals/eval_tool_masking.py +33 -0
- code_muse/fs_scan_cache/__init__.py +31 -0
- code_muse/fs_scan_cache/invalidation_hooks.py +89 -0
- code_muse/fs_scan_cache/scan_cache_core.cpython-314-darwin.so +0 -0
- code_muse/fs_scan_cache/scan_cache_core.pyx +203 -0
- code_muse/fs_scan_cache/tool_integration.py +309 -0
- code_muse/fs_scan_cache/ttl_policy.py +44 -0
- code_muse/gemini_code_assist.py +383 -0
- code_muse/gemini_model.py +838 -0
- code_muse/hook_engine/README.md +105 -0
- code_muse/hook_engine/__init__.py +21 -0
- code_muse/hook_engine/aliases.py +153 -0
- code_muse/hook_engine/engine.py +221 -0
- code_muse/hook_engine/executor.py +347 -0
- code_muse/hook_engine/matcher.py +154 -0
- code_muse/hook_engine/models.py +245 -0
- code_muse/hook_engine/registry.py +114 -0
- code_muse/hook_engine/trust.py +268 -0
- code_muse/hook_engine/validator.py +144 -0
- code_muse/http_utils.py +360 -0
- code_muse/keymap.py +128 -0
- code_muse/list_filtering.py +26 -0
- code_muse/main.py +10 -0
- code_muse/messaging/__init__.py +259 -0
- code_muse/messaging/bus.py +621 -0
- code_muse/messaging/commands.py +166 -0
- code_muse/messaging/markdown_patches.py +57 -0
- code_muse/messaging/message_queue.py +397 -0
- code_muse/messaging/messages.py +591 -0
- code_muse/messaging/queue_console.py +269 -0
- code_muse/messaging/renderers.py +308 -0
- code_muse/messaging/rich_renderer.py +1158 -0
- code_muse/messaging/shimmer.py +154 -0
- code_muse/messaging/spinner/__init__.py +87 -0
- code_muse/messaging/spinner/console_spinner.py +250 -0
- code_muse/messaging/spinner/spinner_base.py +82 -0
- code_muse/messaging/subagent_console.py +458 -0
- code_muse/model_factory.py +1203 -0
- code_muse/model_switching.py +59 -0
- code_muse/model_utils.py +156 -0
- code_muse/models.json +66 -0
- code_muse/models_cache/__init__.py +26 -0
- code_muse/models_cache/blocking_lru_cache.py +98 -0
- code_muse/models_cache/cache_writer.py +86 -0
- code_muse/models_cache/sha256_hash.cpython-314-darwin.so +0 -0
- code_muse/models_cache/sha256_hash.pyx +34 -0
- code_muse/models_cache/startup_integration.py +75 -0
- code_muse/models_dev_api.json +1 -0
- code_muse/models_dev_parser.py +590 -0
- code_muse/motion.py +126 -0
- code_muse/plugins/__init__.py +471 -0
- code_muse/plugins/agent_skills/__init__.py +32 -0
- code_muse/plugins/agent_skills/config.py +176 -0
- code_muse/plugins/agent_skills/discovery.py +309 -0
- code_muse/plugins/agent_skills/downloader.py +389 -0
- code_muse/plugins/agent_skills/installer.py +19 -0
- code_muse/plugins/agent_skills/metadata.py +293 -0
- code_muse/plugins/agent_skills/prompt_builder.py +66 -0
- code_muse/plugins/agent_skills/register_callbacks.py +298 -0
- code_muse/plugins/agent_skills/remote_catalog.py +320 -0
- code_muse/plugins/agent_skills/skill_catalog.py +254 -0
- code_muse/plugins/agent_skills/skills_install_menu.py +690 -0
- code_muse/plugins/agent_skills/skills_menu.py +791 -0
- code_muse/plugins/autonomous_memory/__init__.py +39 -0
- code_muse/plugins/autonomous_memory/bm25_scorer.cpython-314-darwin.so +0 -0
- code_muse/plugins/autonomous_memory/bm25_scorer.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/plugins/autonomous_memory/bm25_scorer.pyx +291 -0
- code_muse/plugins/autonomous_memory/consolidation.py +82 -0
- code_muse/plugins/autonomous_memory/extraction.py +382 -0
- code_muse/plugins/autonomous_memory/lease_lock.py +105 -0
- code_muse/plugins/autonomous_memory/memory_injection.py +59 -0
- code_muse/plugins/autonomous_memory/register_callbacks.py +268 -0
- code_muse/plugins/autonomous_memory/secret_scanner.py +62 -0
- code_muse/plugins/autonomous_memory/session_scanner.py +163 -0
- code_muse/plugins/aws_bedrock/__init__.py +14 -0
- code_muse/plugins/aws_bedrock/config.py +99 -0
- code_muse/plugins/aws_bedrock/register_callbacks.py +241 -0
- code_muse/plugins/aws_bedrock/utils.py +153 -0
- code_muse/plugins/azure_foundry/README.md +238 -0
- code_muse/plugins/azure_foundry/__init__.py +15 -0
- code_muse/plugins/azure_foundry/config.py +125 -0
- code_muse/plugins/azure_foundry/discovery.py +187 -0
- code_muse/plugins/azure_foundry/register_callbacks.py +495 -0
- code_muse/plugins/azure_foundry/token.py +180 -0
- code_muse/plugins/azure_foundry/utils.py +345 -0
- code_muse/plugins/build_filter/__init__.py +1 -0
- code_muse/plugins/build_filter/register_callbacks.py +201 -0
- code_muse/plugins/build_filter/strategies/__init__.py +1 -0
- code_muse/plugins/build_filter/strategies/build.py +397 -0
- code_muse/plugins/chatgpt_oauth/__init__.py +6 -0
- code_muse/plugins/chatgpt_oauth/config.py +52 -0
- code_muse/plugins/chatgpt_oauth/oauth_flow.py +338 -0
- code_muse/plugins/chatgpt_oauth/register_callbacks.py +172 -0
- code_muse/plugins/chatgpt_oauth/test_plugin.py +301 -0
- code_muse/plugins/chatgpt_oauth/utils.py +538 -0
- code_muse/plugins/checkpointing/__init__.py +29 -0
- code_muse/plugins/checkpointing/checkpoint_hook.py +51 -0
- code_muse/plugins/checkpointing/conversation_snapshots.py +117 -0
- code_muse/plugins/checkpointing/register_callbacks.py +51 -0
- code_muse/plugins/checkpointing/restore_command.py +263 -0
- code_muse/plugins/checkpointing/rewind_shortcut.py +88 -0
- code_muse/plugins/checkpointing/shadow_git.py +90 -0
- code_muse/plugins/claude_code_hooks/__init__.py +1 -0
- code_muse/plugins/claude_code_hooks/config.py +188 -0
- code_muse/plugins/claude_code_hooks/register_callbacks.py +208 -0
- code_muse/plugins/claude_code_oauth/README.md +167 -0
- code_muse/plugins/claude_code_oauth/SETUP.md +93 -0
- code_muse/plugins/claude_code_oauth/__init__.py +25 -0
- code_muse/plugins/claude_code_oauth/config.py +52 -0
- code_muse/plugins/claude_code_oauth/fast_mode.py +124 -0
- code_muse/plugins/claude_code_oauth/prompt_handler.py +63 -0
- code_muse/plugins/claude_code_oauth/register_callbacks.py +547 -0
- code_muse/plugins/claude_code_oauth/test_fast_mode.py +165 -0
- code_muse/plugins/claude_code_oauth/test_plugin.py +283 -0
- code_muse/plugins/claude_code_oauth/token_refresh_heartbeat.py +237 -0
- code_muse/plugins/claude_code_oauth/utils.py +664 -0
- code_muse/plugins/copilot_auth/__init__.py +11 -0
- code_muse/plugins/copilot_auth/config.py +91 -0
- code_muse/plugins/copilot_auth/reasoning_client.py +409 -0
- code_muse/plugins/copilot_auth/register_callbacks.py +461 -0
- code_muse/plugins/copilot_auth/utils.py +584 -0
- code_muse/plugins/custom_commands/__init__.py +14 -0
- code_muse/plugins/custom_commands/args_injection.py +82 -0
- code_muse/plugins/custom_commands/command_discovery.py +89 -0
- code_muse/plugins/custom_commands/command_toml_schema.py +71 -0
- code_muse/plugins/custom_commands/register_callbacks.py +176 -0
- code_muse/plugins/customizable_commands/__init__.py +0 -0
- code_muse/plugins/customizable_commands/register_callbacks.py +136 -0
- code_muse/plugins/destructive_command_guard/__init__.py +14 -0
- code_muse/plugins/destructive_command_guard/detector.py +375 -0
- code_muse/plugins/destructive_command_guard/register_callbacks.py +148 -0
- code_muse/plugins/example_custom_command/README.md +280 -0
- code_muse/plugins/example_custom_command/register_callbacks.py +51 -0
- code_muse/plugins/file_permission_handler/__init__.py +4 -0
- code_muse/plugins/file_permission_handler/register_callbacks.py +441 -0
- code_muse/plugins/filter_engine/__init__.py +30 -0
- code_muse/plugins/filter_engine/classifier.py +153 -0
- code_muse/plugins/filter_engine/content_detector.py +184 -0
- code_muse/plugins/filter_engine/dispatcher.py +244 -0
- code_muse/plugins/filter_engine/register_callbacks.py +188 -0
- code_muse/plugins/filter_engine/registry.py +279 -0
- code_muse/plugins/filter_engine/strategies/__init__.py +8 -0
- code_muse/plugins/filter_engine/strategies/ast_compressor.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/ast_compressor.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/plugins/filter_engine/strategies/ast_compressor.pyx +348 -0
- code_muse/plugins/filter_engine/strategies/ast_parser.py +167 -0
- code_muse/plugins/filter_engine/strategies/code.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/code.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/plugins/filter_engine/strategies/code.pyx +584 -0
- code_muse/plugins/filter_engine/strategies/git.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/git.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/plugins/filter_engine/strategies/git.pyx +438 -0
- code_muse/plugins/filter_engine/strategies/json_compressor.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/json_compressor.pyx +253 -0
- code_muse/plugins/filter_engine/strategies/json_patterns.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/json_patterns.pyx +178 -0
- code_muse/plugins/filter_engine/strategies/lint.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/lint.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/plugins/filter_engine/strategies/lint.pyx +626 -0
- code_muse/plugins/filter_engine/strategies/test.cpython-314-darwin.so +0 -0
- code_muse/plugins/filter_engine/strategies/test.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/plugins/filter_engine/strategies/test.pyx +431 -0
- code_muse/plugins/filter_engine/verbosity.py +63 -0
- code_muse/plugins/force_push_guard/__init__.py +5 -0
- code_muse/plugins/force_push_guard/detector.py +96 -0
- code_muse/plugins/force_push_guard/register_callbacks.py +144 -0
- code_muse/plugins/force_push_guard/test_detector.py +143 -0
- code_muse/plugins/frontend_emitter/__init__.py +25 -0
- code_muse/plugins/frontend_emitter/emitter.py +121 -0
- code_muse/plugins/frontend_emitter/register_callbacks.py +259 -0
- code_muse/plugins/gac/__init__.py +4 -0
- code_muse/plugins/gac/git_ops.py +136 -0
- code_muse/plugins/gac/prompt.py +191 -0
- code_muse/plugins/gac/register_callbacks.py +82 -0
- code_muse/plugins/hook_creator/__init__.py +1 -0
- code_muse/plugins/hook_creator/register_callbacks.py +34 -0
- code_muse/plugins/hook_manager/__init__.py +1 -0
- code_muse/plugins/hook_manager/config.py +289 -0
- code_muse/plugins/hook_manager/hooks_menu.py +563 -0
- code_muse/plugins/hook_manager/register_callbacks.py +227 -0
- code_muse/plugins/hook_monitor/register_callbacks.py +36 -0
- code_muse/plugins/mindpack/__init__.py +0 -0
- code_muse/plugins/mindpack/factory.py +930 -0
- code_muse/plugins/mindpack/judge.py +573 -0
- code_muse/plugins/mindpack/memory.py +100 -0
- code_muse/plugins/mindpack/mindpack_menu.py +1552 -0
- code_muse/plugins/mindpack/orchestration.py +605 -0
- code_muse/plugins/mindpack/register_callbacks.py +175 -0
- code_muse/plugins/mindpack/schemas.py +358 -0
- code_muse/plugins/mindpack/tools.py +387 -0
- code_muse/plugins/oauth_muse_html.py +226 -0
- code_muse/plugins/ollama_setup/__init__.py +5 -0
- code_muse/plugins/ollama_setup/completer.py +36 -0
- code_muse/plugins/ollama_setup/register_callbacks.py +410 -0
- code_muse/plugins/plan_command/__init__.py +0 -0
- code_muse/plugins/plan_command/register_callbacks.py +206 -0
- code_muse/plugins/plan_mode/__init__.py +37 -0
- code_muse/plugins/plan_mode/mode_cycling.py +40 -0
- code_muse/plugins/plan_mode/plan_generation.py +68 -0
- code_muse/plugins/plan_mode/plan_hooks.py +74 -0
- code_muse/plugins/plan_mode/plan_mode_tools.py +138 -0
- code_muse/plugins/plan_mode/register_callbacks.py +121 -0
- code_muse/plugins/plugin_trust/register_callbacks.py +140 -0
- code_muse/plugins/policy_engine/__init__.py +46 -0
- code_muse/plugins/policy_engine/approval_flow_integration.py +59 -0
- code_muse/plugins/policy_engine/policy_evaluator.py +75 -0
- code_muse/plugins/policy_engine/policy_file_discovery.py +90 -0
- code_muse/plugins/policy_engine/policy_toml_schema.py +115 -0
- code_muse/plugins/policy_engine/register_callbacks.py +112 -0
- code_muse/plugins/pop_command/__init__.py +1 -0
- code_muse/plugins/pop_command/register_callbacks.py +189 -0
- code_muse/plugins/prompt_newline/__init__.py +13 -0
- code_muse/plugins/prompt_newline/config.py +19 -0
- code_muse/plugins/prompt_newline/register_callbacks.py +159 -0
- code_muse/plugins/safety_status/__init__.py +0 -0
- code_muse/plugins/safety_status/register_callbacks.py +113 -0
- code_muse/plugins/semantic_compression/__init__.py +6 -0
- code_muse/plugins/semantic_compression/compressor.py +295 -0
- code_muse/plugins/semantic_compression/config.py +123 -0
- code_muse/plugins/semantic_compression/register_callbacks.py +320 -0
- code_muse/plugins/shell_minimizer/__init__.py +50 -0
- code_muse/plugins/shell_minimizer/builtin_filters.toml +393 -0
- code_muse/plugins/shell_minimizer/pipeline.py +556 -0
- code_muse/plugins/shell_minimizer/primitives.py +482 -0
- code_muse/plugins/shell_minimizer/register_callbacks.py +276 -0
- code_muse/plugins/shell_safety/__init__.py +6 -0
- code_muse/plugins/shell_safety/agent_shell_safety.py +69 -0
- code_muse/plugins/shell_safety/command_cache.py +149 -0
- code_muse/plugins/shell_safety/register_callbacks.py +202 -0
- code_muse/plugins/synthetic_status/__init__.py +1 -0
- code_muse/plugins/synthetic_status/register_callbacks.py +128 -0
- code_muse/plugins/synthetic_status/status_api.py +145 -0
- code_muse/plugins/token_caching/__init__.py +21 -0
- code_muse/plugins/token_caching/cache_hit_tracking.py +128 -0
- code_muse/plugins/token_caching/cacheable_prefix_detection.py +28 -0
- code_muse/plugins/token_caching/register_callbacks.py +54 -0
- code_muse/plugins/token_caching/stats_display.py +35 -0
- code_muse/plugins/token_tracking/__init__.py +26 -0
- code_muse/plugins/token_tracking/database.py +381 -0
- code_muse/plugins/token_tracking/edit_analyzer.py +97 -0
- code_muse/plugins/token_tracking/record.py +55 -0
- code_muse/plugins/token_tracking/register_callbacks.py +277 -0
- code_muse/plugins/token_tracking/reports.py +329 -0
- code_muse/plugins/universal_constructor/__init__.py +13 -0
- code_muse/plugins/universal_constructor/models.py +136 -0
- code_muse/plugins/universal_constructor/register_callbacks.py +47 -0
- code_muse/plugins/universal_constructor/registry.py +390 -0
- code_muse/plugins/universal_constructor/runner.py +474 -0
- code_muse/plugins/universal_constructor/safety.py +440 -0
- code_muse/plugins/universal_constructor/sandbox.py +584 -0
- code_muse/provider_identity.py +105 -0
- code_muse/pydantic_patches.py +410 -0
- code_muse/reopenable_async_client.py +233 -0
- code_muse/round_robin_model.py +151 -0
- code_muse/secret_storage.py +74 -0
- code_muse/security/__init__.py +1 -0
- code_muse/security/redaction.cpython-314-darwin.so +0 -0
- code_muse/security/redaction.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/security/redaction.pyx +135 -0
- code_muse/session_storage.py +565 -0
- code_muse/status_display.py +261 -0
- code_muse/stream_parser/__init__.py +76 -0
- code_muse/stream_parser/assistant_text_parser.py +90 -0
- code_muse/stream_parser/citation_parser.py +76 -0
- code_muse/stream_parser/inline_hidden_tag_parser.py +236 -0
- code_muse/stream_parser/proposed_plan_parser.py +158 -0
- code_muse/stream_parser/stream_text_chunk.py +23 -0
- code_muse/stream_parser/stream_text_parser.py +27 -0
- code_muse/stream_parser/tagged_line_parser.cpython-314-darwin.so +0 -0
- code_muse/stream_parser/tagged_line_parser.pyx +251 -0
- code_muse/stream_parser/utf8_stream_parser.cpython-314-darwin.so +0 -0
- code_muse/stream_parser/utf8_stream_parser.pyx +206 -0
- code_muse/summarization_agent.py +308 -0
- code_muse/terminal_utils.cpython-314-darwin.so +0 -0
- code_muse/terminal_utils.cpython-314-x86_64-linux-gnu.so +0 -0
- code_muse/terminal_utils.pyx +483 -0
- code_muse/tools/__init__.py +459 -0
- code_muse/tools/agent_tools.py +613 -0
- code_muse/tools/ask_user_question/__init__.py +26 -0
- code_muse/tools/ask_user_question/constants.py +73 -0
- code_muse/tools/ask_user_question/demo_tui.py +55 -0
- code_muse/tools/ask_user_question/handler.py +232 -0
- code_muse/tools/ask_user_question/models.py +302 -0
- code_muse/tools/ask_user_question/registration.py +37 -0
- code_muse/tools/ask_user_question/renderers.py +336 -0
- code_muse/tools/ask_user_question/terminal_ui.py +327 -0
- code_muse/tools/ask_user_question/theme.py +156 -0
- code_muse/tools/ask_user_question/tui_loop.py +422 -0
- code_muse/tools/background_jobs.py +99 -0
- code_muse/tools/browser/__init__.py +37 -0
- code_muse/tools/browser/browser_control.py +289 -0
- code_muse/tools/browser/browser_interactions.py +545 -0
- code_muse/tools/browser/browser_locators.py +640 -0
- code_muse/tools/browser/browser_manager.py +376 -0
- code_muse/tools/browser/browser_navigation.py +251 -0
- code_muse/tools/browser/browser_screenshot.py +180 -0
- code_muse/tools/browser/browser_scripts.py +462 -0
- code_muse/tools/browser/browser_workflows.py +222 -0
- code_muse/tools/chrome_cdp/__init__.py +1070 -0
- code_muse/tools/chrome_cdp/register_callbacks.py +61 -0
- code_muse/tools/command_runner.py +1401 -0
- code_muse/tools/common.py +1407 -0
- code_muse/tools/display.py +87 -0
- code_muse/tools/file_modifications.py +1099 -0
- code_muse/tools/file_operations.py +860 -0
- code_muse/tools/image_tools.py +185 -0
- code_muse/tools/meetin_proxy/__init__.py +243 -0
- code_muse/tools/meetin_proxy/capture_addon.py +82 -0
- code_muse/tools/meetin_proxy/proxy_manager.py +326 -0
- code_muse/tools/meetin_proxy/register_callbacks.py +45 -0
- code_muse/tools/path_policy.py +219 -0
- code_muse/tools/skills_tools.py +586 -0
- code_muse/tools/subagent_context.py +158 -0
- code_muse/tools/tools_content.py +50 -0
- code_muse/tools/universal_constructor.py +965 -0
- code_muse/uvx_detection.py +241 -0
- code_muse/version_checker.py +86 -0
- code_muse-0.0.1.data/data/code_muse/models.json +66 -0
- code_muse-0.0.1.data/data/code_muse/models_dev_api.json +1 -0
- code_muse-0.0.1.dist-info/METADATA +845 -0
- code_muse-0.0.1.dist-info/RECORD +394 -0
- code_muse-0.0.1.dist-info/WHEEL +4 -0
- code_muse-0.0.1.dist-info/entry_points.txt +2 -0
- code_muse-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Register callbacks for the prompt_newline plugin.
|
|
2
|
+
|
|
3
|
+
This plugin is a tiny ergonomics hack: it places the user's input cursor on a
|
|
4
|
+
*new line* below the muse/agent/model/cwd chrome, so long working-directory
|
|
5
|
+
paths don't squeeze the typing area.
|
|
6
|
+
|
|
7
|
+
It hooks two things:
|
|
8
|
+
|
|
9
|
+
* ``startup`` — wraps ``get_prompt_with_active_model`` so the FormattedText it
|
|
10
|
+
returns gets a trailing ``\\n`` appended **at call time** (so the slash
|
|
11
|
+
command toggle takes effect immediately, no restart needed).
|
|
12
|
+
* ``custom_command`` / ``custom_command_help`` — exposes ``/prompt_newline``
|
|
13
|
+
for runtime on/off, persisted via ``muse.cfg``.
|
|
14
|
+
|
|
15
|
+
Default: OFF. Opt-in only.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from code_muse.callbacks import register_callback
|
|
19
|
+
from code_muse.plugins.prompt_newline.config import is_enabled, set_enabled
|
|
20
|
+
|
|
21
|
+
_COMMAND_NAME = "prompt_newline"
|
|
22
|
+
_PATCH_ATTR = "_prompt_newline_original"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _emit_info(message: str) -> None:
|
|
26
|
+
from code_muse.messaging import emit_info
|
|
27
|
+
|
|
28
|
+
emit_info(message)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _emit_error(message: str) -> None:
|
|
32
|
+
from code_muse.messaging import emit_error
|
|
33
|
+
|
|
34
|
+
emit_error(message)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _emit_success(message: str) -> None:
|
|
38
|
+
from code_muse.messaging import emit_success
|
|
39
|
+
|
|
40
|
+
emit_success(message)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _append_newline(formatted_text):
|
|
44
|
+
"""Return a new FormattedText with a trailing newline tuple.
|
|
45
|
+
|
|
46
|
+
``FormattedText`` is a ``list`` subclass of ``(style, text)`` tuples, so we
|
|
47
|
+
rebuild it rather than mutating in place — the upstream caller may cache
|
|
48
|
+
or reuse the returned object.
|
|
49
|
+
"""
|
|
50
|
+
from prompt_toolkit.formatted_text import FormattedText
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
return FormattedText(list(formatted_text) + [("", "\n")])
|
|
54
|
+
except Exception:
|
|
55
|
+
# Defensive: never break the prompt if the upstream shape changes.
|
|
56
|
+
return formatted_text
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _install_prompt_patch() -> None:
|
|
60
|
+
"""Monkey-patch ``get_prompt_with_active_model`` to honor ``is_enabled()``.
|
|
61
|
+
|
|
62
|
+
Idempotent: re-running won't double-wrap.
|
|
63
|
+
"""
|
|
64
|
+
from code_muse.command_line import prompt_toolkit_completion as ptc
|
|
65
|
+
|
|
66
|
+
if getattr(ptc, _PATCH_ATTR, None) is not None:
|
|
67
|
+
return # Already patched
|
|
68
|
+
|
|
69
|
+
original = ptc.get_prompt_with_active_model
|
|
70
|
+
setattr(ptc, _PATCH_ATTR, original)
|
|
71
|
+
|
|
72
|
+
def patched(base: str = ">>> "):
|
|
73
|
+
result = original(base)
|
|
74
|
+
if is_enabled():
|
|
75
|
+
return _append_newline(result)
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
ptc.get_prompt_with_active_model = patched
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _on_startup() -> None:
|
|
82
|
+
try:
|
|
83
|
+
_install_prompt_patch()
|
|
84
|
+
except Exception as exc:
|
|
85
|
+
# Plugins must fail gracefully — never crash the app.
|
|
86
|
+
_emit_error(f"prompt_newline: failed to install prompt patch — {exc}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _custom_help() -> list[tuple[str, str]]:
|
|
90
|
+
return [
|
|
91
|
+
(
|
|
92
|
+
_COMMAND_NAME,
|
|
93
|
+
"Toggle placing user input on a new line below the prompt chrome",
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _parse_toggle_arg(command: str) -> bool | None:
|
|
99
|
+
"""Parse ``/prompt_newline [on|off|true|false|toggle]``.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
True/False for an explicit set, or ``None`` to mean "flip current".
|
|
103
|
+
"""
|
|
104
|
+
tokens = command.strip().split()
|
|
105
|
+
if len(tokens) < 2:
|
|
106
|
+
return None # bare /prompt_newline → flip
|
|
107
|
+
arg = tokens[1].lower()
|
|
108
|
+
if arg in ("on", "true", "1", "yes", "enable", "enabled"):
|
|
109
|
+
return True
|
|
110
|
+
if arg in ("off", "false", "0", "no", "disable", "disabled"):
|
|
111
|
+
return False
|
|
112
|
+
if arg in ("toggle",):
|
|
113
|
+
return None
|
|
114
|
+
raise ValueError(arg)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _handle_prompt_newline_command(command: str) -> bool:
|
|
118
|
+
try:
|
|
119
|
+
target = _parse_toggle_arg(command)
|
|
120
|
+
except ValueError as exc:
|
|
121
|
+
_emit_error(
|
|
122
|
+
f"/{_COMMAND_NAME}: unknown argument '{exc.args[0]}'. "
|
|
123
|
+
"Usage: /prompt_newline [on|off|toggle]"
|
|
124
|
+
)
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
if target is None:
|
|
128
|
+
target = not is_enabled()
|
|
129
|
+
|
|
130
|
+
set_enabled(target)
|
|
131
|
+
state = "ON" if target else "OFF"
|
|
132
|
+
_emit_success(f"[Run] prompt_newline is now {state}")
|
|
133
|
+
if target:
|
|
134
|
+
_emit_info("Your input will appear on a fresh line below the prompt chrome.")
|
|
135
|
+
else:
|
|
136
|
+
_emit_info("Prompt is back to single-line mode.")
|
|
137
|
+
return True
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _handle_custom_command(command: str, name: str):
|
|
141
|
+
if name != _COMMAND_NAME:
|
|
142
|
+
return None
|
|
143
|
+
return _handle_prompt_newline_command(command)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
register_callback("startup", _on_startup)
|
|
147
|
+
register_callback("custom_command", _handle_custom_command)
|
|
148
|
+
register_callback("custom_command_help", _custom_help)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
__all__ = [
|
|
152
|
+
"_append_newline",
|
|
153
|
+
"_custom_help",
|
|
154
|
+
"_handle_custom_command",
|
|
155
|
+
"_handle_prompt_newline_command",
|
|
156
|
+
"_install_prompt_patch",
|
|
157
|
+
"_on_startup",
|
|
158
|
+
"_parse_toggle_arg",
|
|
159
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Safety status plugin — concise /safety and /status slash commands.
|
|
2
|
+
|
|
3
|
+
Shows the current risk posture without exposing secret values.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
|
|
10
|
+
from code_muse.callbacks import count_callbacks, register_callback
|
|
11
|
+
from code_muse.messaging import emit_info
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _custom_help() -> list[tuple[str, str]]:
|
|
15
|
+
return [
|
|
16
|
+
("safety", "Show safety and trust status (risk posture)"),
|
|
17
|
+
("status", "Alias for /safety"),
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_status_lines() -> list[str]:
|
|
22
|
+
"""Build a list of safety-status lines. All values are redacted or safe."""
|
|
23
|
+
lines: list[str] = []
|
|
24
|
+
|
|
25
|
+
# Yolo mode
|
|
26
|
+
try:
|
|
27
|
+
from code_muse.config import get_yolo_mode
|
|
28
|
+
|
|
29
|
+
yolo = get_yolo_mode()
|
|
30
|
+
except Exception:
|
|
31
|
+
yolo = False
|
|
32
|
+
lines.append(f"Yolo mode : {'on' if yolo else 'off'}")
|
|
33
|
+
|
|
34
|
+
# Shell safety
|
|
35
|
+
try:
|
|
36
|
+
from code_muse.config import get_safety_permission_level
|
|
37
|
+
|
|
38
|
+
level = get_safety_permission_level()
|
|
39
|
+
except Exception:
|
|
40
|
+
level = "unknown"
|
|
41
|
+
lines.append(f"Shell safety : {level}")
|
|
42
|
+
|
|
43
|
+
# Workspace root
|
|
44
|
+
try:
|
|
45
|
+
from code_muse.tools.path_policy import get_workspace_root
|
|
46
|
+
|
|
47
|
+
ws = get_workspace_root()
|
|
48
|
+
except Exception:
|
|
49
|
+
ws = Path.cwd()
|
|
50
|
+
lines.append(f"Workspace : {ws}")
|
|
51
|
+
|
|
52
|
+
# Sensitive-file policy
|
|
53
|
+
try:
|
|
54
|
+
from code_muse.tools.path_policy import SENSITIVE_PATHS
|
|
55
|
+
|
|
56
|
+
policy = f"{len(SENSITIVE_PATHS)} sensitive patterns"
|
|
57
|
+
except Exception:
|
|
58
|
+
policy = "active"
|
|
59
|
+
lines.append(f"Sensitive policy: {policy}")
|
|
60
|
+
|
|
61
|
+
# Hook trust
|
|
62
|
+
try:
|
|
63
|
+
from code_muse.hook_engine.trust import _load_trust_db
|
|
64
|
+
|
|
65
|
+
db = _load_trust_db()
|
|
66
|
+
hook_count = len(db)
|
|
67
|
+
except Exception:
|
|
68
|
+
hook_count = 0
|
|
69
|
+
lines.append(f"Hook trust : {hook_count} trusted project(s)")
|
|
70
|
+
|
|
71
|
+
# Plugin / callback activity
|
|
72
|
+
try:
|
|
73
|
+
total_callbacks = count_callbacks()
|
|
74
|
+
except Exception:
|
|
75
|
+
total_callbacks = 0
|
|
76
|
+
lines.append(f"Callbacks active: {total_callbacks}")
|
|
77
|
+
|
|
78
|
+
# Universal Constructor
|
|
79
|
+
try:
|
|
80
|
+
from code_muse.config import get_universal_constructor_enabled
|
|
81
|
+
|
|
82
|
+
uc = get_universal_constructor_enabled()
|
|
83
|
+
except Exception:
|
|
84
|
+
uc = True
|
|
85
|
+
lines.append(f"UC enabled : {'yes' if uc else 'no'}")
|
|
86
|
+
|
|
87
|
+
# Environment redaction hint
|
|
88
|
+
lines.append("")
|
|
89
|
+
lines.append("Secret values are redacted in logs and status displays.")
|
|
90
|
+
|
|
91
|
+
return lines
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _render_panel(lines: list[str]) -> Panel:
|
|
95
|
+
body = "\n".join(lines)
|
|
96
|
+
return Panel(body, title="Safety Status", border_style="cyan")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _handle_custom_command(command: str, name: str) -> bool | None:
|
|
100
|
+
if not name:
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
if name in ("safety", "status"):
|
|
104
|
+
lines = _get_status_lines()
|
|
105
|
+
panel = _render_panel(lines)
|
|
106
|
+
emit_info(panel)
|
|
107
|
+
return True
|
|
108
|
+
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
register_callback("custom_command_help", _custom_help)
|
|
113
|
+
register_callback("custom_command", _handle_custom_command)
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"""Semantic Compression Engine.
|
|
2
|
+
|
|
3
|
+
Lossy text compression that removes predictable grammar while preserving
|
|
4
|
+
semantic payload. LLMs reconstruct grammar from content words, so we
|
|
5
|
+
strip the glue and keep the meaning.
|
|
6
|
+
|
|
7
|
+
Rules are applied in tiers:
|
|
8
|
+
- Tier 1 (always safe): articles, copulas, filler phrases, intensifiers,
|
|
9
|
+
complementizer "that"
|
|
10
|
+
- Tier 2 (aggressive): auxiliaries, modals (except must), pronouns,
|
|
11
|
+
relative pronouns
|
|
12
|
+
- Structural: passive→active, nominalization→verb, redundant pairs,
|
|
13
|
+
clause→modifier
|
|
14
|
+
|
|
15
|
+
Always preserved: nouns, main verbs, meaning-bearing modifiers, numbers,
|
|
16
|
+
uncertainty markers, negation, temporal markers, causality, requirements,
|
|
17
|
+
proper nouns, and technical terms.
|
|
18
|
+
|
|
19
|
+
Code blocks (``` fenced ```) are detected and left untouched.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import re
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Tier 1 — always safe deletions
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
# Articles: a, an, the (standalone, word boundary)
|
|
29
|
+
_RE_ARTICLES = re.compile(r"\b(a|an|the)\b", re.IGNORECASE)
|
|
30
|
+
|
|
31
|
+
# Copulas: is, are, was, were, am, be, been, being
|
|
32
|
+
_RE_COPULAS = re.compile(r"\b(is|are|was|were|am|be|been|being)\b", re.IGNORECASE)
|
|
33
|
+
|
|
34
|
+
# Pure intensifiers: very, quite, rather, really, extremely, somewhat
|
|
35
|
+
_RE_INTENSIFIERS = re.compile(
|
|
36
|
+
r"\b(very|quite|rather|really|extremely|somewhat)\b", re.IGNORECASE
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Filler phrase → replacement
|
|
40
|
+
_FILLER_PHRASES: list[tuple[re.Pattern, str]] = [
|
|
41
|
+
(re.compile(r"\bin order to\b", re.IGNORECASE), "to"),
|
|
42
|
+
(re.compile(r"\bdue to the fact that\b", re.IGNORECASE), "because"),
|
|
43
|
+
(re.compile(r"\bin terms of\b", re.IGNORECASE), ""),
|
|
44
|
+
(re.compile(r"\bin the process of\b", re.IGNORECASE), ""),
|
|
45
|
+
(re.compile(r"\bin the context of\b", re.IGNORECASE), ""),
|
|
46
|
+
(re.compile(r"\bit is worth noting that\b", re.IGNORECASE), ""),
|
|
47
|
+
(re.compile(r"\bneedless to say\b", re.IGNORECASE), ""),
|
|
48
|
+
(re.compile(r"\bwhat is called\b", re.IGNORECASE), ""),
|
|
49
|
+
(re.compile(r"\bas a matter of fact\b", re.IGNORECASE), ""),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
# Complementizer "that" after bridge verbs.
|
|
53
|
+
# Matches stems with regular -s/-ed/-ing plus common irregulars.
|
|
54
|
+
# e.g. "report/reports/reported/reporting that X" → "report X"
|
|
55
|
+
_BRIDGE_STEMS = (
|
|
56
|
+
r"know|think|believe|say|see|find|show|note|ensure|suggest"
|
|
57
|
+
r"|indicate|report|state|claim|argue|feel|suspect|realize"
|
|
58
|
+
r"|learn|discover|remember|forget|understand|assume"
|
|
59
|
+
)
|
|
60
|
+
# Captures bridge verb (stem + optional -s/-ed/-ing, or irregular)
|
|
61
|
+
# Suffix handles regular -s/-ed/-ing and e-dropping -d (e.g. assume→assumed)
|
|
62
|
+
_RE_COMPLEMENTIZER = re.compile(
|
|
63
|
+
rf"\b((?:{_BRIDGE_STEMS})(?:s|e?d|ing)?"
|
|
64
|
+
r"|knew|thought|said|saw|seen|found|showed|shown"
|
|
65
|
+
r"|felt|learnt|learnt|forgot|forgotten|understood"
|
|
66
|
+
r")\s+that\b",
|
|
67
|
+
re.IGNORECASE,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# Tier 2 — aggressive (only when aggressive=True)
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
# Auxiliary verbs: have/has/had, do/does/did, will/would
|
|
75
|
+
_RE_AUXILIARIES = re.compile(
|
|
76
|
+
r"\b(have|has|had|do|does|did|will|would)\b", re.IGNORECASE
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Modal verbs except "must"
|
|
80
|
+
_RE_MODALS = re.compile(r"\b(can|could|may|might|should)\b", re.IGNORECASE)
|
|
81
|
+
|
|
82
|
+
# Pronouns (subject/object, when referent is obvious)
|
|
83
|
+
_RE_PRONOUNS = re.compile(
|
|
84
|
+
r"\b(it|this|that|these|those|he|she|they|him|her|them)\b",
|
|
85
|
+
re.IGNORECASE,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Relative pronouns
|
|
89
|
+
_RE_RELATIVES = re.compile(r"\b(which|that|who|whom)\b", re.IGNORECASE)
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Structural compression patterns
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
# Passive → active: "was eaten by dog" → "dog ate"
|
|
96
|
+
# Pattern captures: group 1 = past participle, group 2 = agent noun
|
|
97
|
+
# Handles regular -ed/-en and irregulars like made, gone, done, known
|
|
98
|
+
_PASSIVE_BY_RE = re.compile(
|
|
99
|
+
r"\b(?:is|are|was|were|be|been|being)\s+"
|
|
100
|
+
r"(\w+(?:ed|en|[dt]e?|wn|own))"
|
|
101
|
+
r"\s+by\s+(?:the\s+)?(\w+)",
|
|
102
|
+
re.IGNORECASE,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Nominalization → verb (common patterns)
|
|
106
|
+
_NOMINALIZATIONS: list[tuple[re.Pattern, str]] = [
|
|
107
|
+
(re.compile(r"\bmade? a decision\b", re.IGNORECASE), "decided"),
|
|
108
|
+
(re.compile(r"\bmade? an? analysis\b", re.IGNORECASE), "analyzed"),
|
|
109
|
+
(re.compile(r"\bgave? consideration\b", re.IGNORECASE), "considered"),
|
|
110
|
+
(re.compile(r"\btook? into account\b", re.IGNORECASE), "considered"),
|
|
111
|
+
(re.compile(r"\bmade? an? assessment\b", re.IGNORECASE), "assessed"),
|
|
112
|
+
(re.compile(r"\bmade? an? evaluation\b", re.IGNORECASE), "evaluated"),
|
|
113
|
+
(re.compile(r"\bmade? a recommendation\b", re.IGNORECASE), "recommended"),
|
|
114
|
+
(re.compile(r"\bmade? an? observation\b", re.IGNORECASE), "observed"),
|
|
115
|
+
(re.compile(r"\bmade? a prediction\b", re.IGNORECASE), "predicted"),
|
|
116
|
+
(re.compile(r"\bmade? a statement\b", re.IGNORECASE), "stated"),
|
|
117
|
+
(re.compile(r"\bgave? permission\b", re.IGNORECASE), "permitted"),
|
|
118
|
+
(re.compile(r"\bconducted an? investigation\b", re.IGNORECASE), "investigated"),
|
|
119
|
+
(re.compile(r"\bperformed an? analysis\b", re.IGNORECASE), "analyzed"),
|
|
120
|
+
(re.compile(r"\btook? a look\b", re.IGNORECASE), "looked"),
|
|
121
|
+
(re.compile(r"\breached a conclusion\b", re.IGNORECASE), "concluded"),
|
|
122
|
+
(re.compile(r"\bcame to the conclusion\b", re.IGNORECASE), "concluded"),
|
|
123
|
+
(re.compile(r"\bprovided an? explanation\b", re.IGNORECASE), "explained"),
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
# Redundant pairs → single
|
|
127
|
+
_REDUNDANT_PAIRS: list[tuple[re.Pattern, str]] = [
|
|
128
|
+
(re.compile(r"\beach and every\b", re.IGNORECASE), "every"),
|
|
129
|
+
(re.compile(r"\bfirst and foremost\b", re.IGNORECASE), "first"),
|
|
130
|
+
(re.compile(r"\bbasic and fundamental\b", re.IGNORECASE), "fundamental"),
|
|
131
|
+
(re.compile(r"\bnull and void\b", re.IGNORECASE), "void"),
|
|
132
|
+
(re.compile(r"\btrue and accurate\b", re.IGNORECASE), "accurate"),
|
|
133
|
+
(re.compile(r"\bfull and complete\b", re.IGNORECASE), "complete"),
|
|
134
|
+
(re.compile(r"\bany and all\b", re.IGNORECASE), "all"),
|
|
135
|
+
(re.compile(r"\bvarious and sundry\b", re.IGNORECASE), "various"),
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
# Clause → modifier: "anomaly that was reported" → "reported anomaly"
|
|
139
|
+
# Pattern: noun + relative pronoun + copula + past participle → past participle + noun
|
|
140
|
+
_CLAUSE_TO_MODIFIER_RE = re.compile(
|
|
141
|
+
r"\b(\w+)\s+(?:that|which|who)\s+(?:is|are|was|were|be|been|being)\s+"
|
|
142
|
+
r"(\w+(?:ed|en|[dt]e?|wn|own))\b",
|
|
143
|
+
re.IGNORECASE,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# ---------------------------------------------------------------------------
|
|
147
|
+
# Code block handling
|
|
148
|
+
# ---------------------------------------------------------------------------
|
|
149
|
+
|
|
150
|
+
_FENCE_RE = re.compile(r"```[\s\S]*?```")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _split_code_blocks(text: str) -> list[tuple[bool, str]]:
|
|
154
|
+
"""Split *text* into (is_code, segment) tuples.
|
|
155
|
+
|
|
156
|
+
Code fences (``` ... ```) are marked as code and left untouched.
|
|
157
|
+
Everything else is non-code and eligible for compression.
|
|
158
|
+
"""
|
|
159
|
+
segments: list[tuple[bool, str]] = []
|
|
160
|
+
pos = 0
|
|
161
|
+
for match in _FENCE_RE.finditer(text):
|
|
162
|
+
start = match.start()
|
|
163
|
+
if start > pos:
|
|
164
|
+
segments.append((False, text[pos:start]))
|
|
165
|
+
segments.append((True, match.group()))
|
|
166
|
+
pos = match.end()
|
|
167
|
+
if pos < len(text):
|
|
168
|
+
segments.append((False, text[pos:]))
|
|
169
|
+
return segments
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# ---------------------------------------------------------------------------
|
|
173
|
+
# Core compression pipeline
|
|
174
|
+
# ---------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def compress_semantic(text: str, aggressive: bool = False) -> str:
|
|
178
|
+
"""Apply semantic compression to *text*.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
text:
|
|
183
|
+
The input text to compress.
|
|
184
|
+
aggressive:
|
|
185
|
+
If ``True``, also apply Tier 2 deletions (auxiliaries, modals,
|
|
186
|
+
pronouns, relatives) in addition to Tier 1.
|
|
187
|
+
|
|
188
|
+
Returns
|
|
189
|
+
-------
|
|
190
|
+
str
|
|
191
|
+
The compressed text with code blocks preserved.
|
|
192
|
+
"""
|
|
193
|
+
if not text or not text.strip():
|
|
194
|
+
return text
|
|
195
|
+
|
|
196
|
+
# Split into code and non-code segments
|
|
197
|
+
segments = _split_code_blocks(text)
|
|
198
|
+
|
|
199
|
+
result_parts: list[str] = []
|
|
200
|
+
for is_code, segment in segments:
|
|
201
|
+
if is_code:
|
|
202
|
+
result_parts.append(segment)
|
|
203
|
+
else:
|
|
204
|
+
result_parts.append(_compress_segment(segment, aggressive))
|
|
205
|
+
|
|
206
|
+
return "".join(result_parts)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _compress_segment(segment: str, aggressive: bool) -> str:
|
|
210
|
+
"""Compress a single non-code text segment.
|
|
211
|
+
|
|
212
|
+
Order matters: structural transformations run *before* Tier 1
|
|
213
|
+
deletions so patterns like passive→active can see the copulas
|
|
214
|
+
before they are stripped.
|
|
215
|
+
"""
|
|
216
|
+
s = segment
|
|
217
|
+
|
|
218
|
+
# --- Structural compression (before Tier 1) ---
|
|
219
|
+
|
|
220
|
+
# Passive → active: "was eaten by dog" → "dog ate"
|
|
221
|
+
s = _PASSIVE_BY_RE.sub(r"\2 \1", s)
|
|
222
|
+
|
|
223
|
+
# Clause → modifier: "anomaly that was reported" → "reported anomaly"
|
|
224
|
+
s = _CLAUSE_TO_MODIFIER_RE.sub(r"\2 \1", s)
|
|
225
|
+
|
|
226
|
+
# Nominalizations → verb
|
|
227
|
+
for pattern, replacement in _NOMINALIZATIONS:
|
|
228
|
+
s = pattern.sub(replacement, s)
|
|
229
|
+
|
|
230
|
+
# Redundant pairs → single
|
|
231
|
+
for pattern, replacement in _REDUNDANT_PAIRS:
|
|
232
|
+
s = pattern.sub(replacement, s)
|
|
233
|
+
|
|
234
|
+
# --- Tier 1 (always safe deletions) ---
|
|
235
|
+
|
|
236
|
+
# Filler phrases first (they may contain articles/copulas)
|
|
237
|
+
for pattern, replacement in _FILLER_PHRASES:
|
|
238
|
+
s = pattern.sub(replacement, s)
|
|
239
|
+
|
|
240
|
+
# Complementizer "that" after bridge verbs
|
|
241
|
+
s = _RE_COMPLEMENTIZER.sub(r"\1", s)
|
|
242
|
+
|
|
243
|
+
# Articles
|
|
244
|
+
s = _RE_ARTICLES.sub("", s)
|
|
245
|
+
|
|
246
|
+
# Copulas (after structural pass, so passive→active already fired)
|
|
247
|
+
s = _RE_COPULAS.sub("", s)
|
|
248
|
+
|
|
249
|
+
# Pure intensifiers
|
|
250
|
+
s = _RE_INTENSIFIERS.sub("", s)
|
|
251
|
+
|
|
252
|
+
# --- Tier 2 (aggressive only) ---
|
|
253
|
+
if aggressive:
|
|
254
|
+
s = _RE_AUXILIARIES.sub("", s)
|
|
255
|
+
s = _RE_MODALS.sub("", s)
|
|
256
|
+
s = _RE_PRONOUNS.sub("", s)
|
|
257
|
+
s = _RE_RELATIVES.sub("", s)
|
|
258
|
+
|
|
259
|
+
# --- Post-processing ---
|
|
260
|
+
|
|
261
|
+
# Collapse multiple spaces into one
|
|
262
|
+
s = re.sub(r" {2,}", " ", s)
|
|
263
|
+
|
|
264
|
+
# Remove space before punctuation
|
|
265
|
+
s = re.sub(r" +([.,!?;:])", r"\1", s)
|
|
266
|
+
|
|
267
|
+
# Remove leading/trailing whitespace per line
|
|
268
|
+
lines = [ln.strip() for ln in s.splitlines()]
|
|
269
|
+
s = "\n".join(ln for ln in lines if ln)
|
|
270
|
+
|
|
271
|
+
# Collapse 3+ consecutive newlines into 2
|
|
272
|
+
s = re.sub(r"\n{3,}", "\n\n", s)
|
|
273
|
+
|
|
274
|
+
return s
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
# Convenience: compress known patterns in one shot
|
|
279
|
+
# ---------------------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def compress_for_llm(text: str) -> str:
|
|
283
|
+
"""Compress text intended for LLM consumption (aggressive mode).
|
|
284
|
+
|
|
285
|
+
Equivalent to ``compress_semantic(text, aggressive=True)``.
|
|
286
|
+
"""
|
|
287
|
+
return compress_semantic(text, aggressive=True)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def compress_for_display(text: str) -> str:
|
|
291
|
+
"""Compress text for human display (safe mode only, Tier 1).
|
|
292
|
+
|
|
293
|
+
Equivalent to ``compress_semantic(text, aggressive=False)``.
|
|
294
|
+
"""
|
|
295
|
+
return compress_semantic(text, aggressive=False)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Plugin-level config helpers for semantic_compression."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from code_muse.config import get_value, set_config_value
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
_CONFIG_KEY_ENABLED = "semantic_compression_enabled"
|
|
11
|
+
_CONFIG_KEY_ALLOWLIST = "semantic_compression_allowlist"
|
|
12
|
+
_CONFIG_KEY_BLOCKLIST = "semantic_compression_blocklist"
|
|
13
|
+
_TRUTHY = ("true", "1", "yes", "on")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_semantic_compression_enabled() -> bool:
|
|
17
|
+
"""Check if automatic semantic compression of tool output is enabled.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
True if enabled, False otherwise. Default: False (opt-in).
|
|
21
|
+
"""
|
|
22
|
+
cfg_val = get_value(_CONFIG_KEY_ENABLED)
|
|
23
|
+
if cfg_val is None:
|
|
24
|
+
return False
|
|
25
|
+
return str(cfg_val).strip().lower() in _TRUTHY
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def set_semantic_compression_enabled(enabled: bool) -> None:
|
|
29
|
+
"""Enable or disable automatic semantic compression of tool output.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
enabled: True to enable, False to disable.
|
|
33
|
+
"""
|
|
34
|
+
set_config_value(_CONFIG_KEY_ENABLED, "true" if enabled else "false")
|
|
35
|
+
logger.info("Semantic compression %s", "enabled" if enabled else "disabled")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _parse_json_tool_list(config_value: str | None) -> set[str]:
|
|
39
|
+
"""Parse a JSON list of tool names from config.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Set of tool names. Empty set if config is missing or invalid.
|
|
43
|
+
"""
|
|
44
|
+
if not config_value:
|
|
45
|
+
return set()
|
|
46
|
+
try:
|
|
47
|
+
parsed = json.loads(config_value)
|
|
48
|
+
if isinstance(parsed, list):
|
|
49
|
+
return {str(item).strip() for item in parsed if item}
|
|
50
|
+
except json.JSONDecodeError as e:
|
|
51
|
+
logger.error("Failed to parse tool list config: %s", e)
|
|
52
|
+
return set()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _serialize_tool_list(tool_names: set[str]) -> str:
|
|
56
|
+
"""Serialize a set of tool names to a JSON list string."""
|
|
57
|
+
return json.dumps(sorted(tool_names))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_compression_allowlist() -> set[str]:
|
|
61
|
+
"""Get the set of tool names explicitly allowed for compression.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Set of tool names. If non-empty, ONLY these tools will have
|
|
65
|
+
their output compressed (when enabled). Empty means all tools
|
|
66
|
+
are allowed unless blocked.
|
|
67
|
+
"""
|
|
68
|
+
return _parse_json_tool_list(get_value(_CONFIG_KEY_ALLOWLIST))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def set_compression_allowlist(tool_names: set[str]) -> None:
|
|
72
|
+
"""Set the allowlist of tool names for compression.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
tool_names: Set of tool names to allow. Empty set clears the allowlist.
|
|
76
|
+
"""
|
|
77
|
+
set_config_value(_CONFIG_KEY_ALLOWLIST, _serialize_tool_list(tool_names))
|
|
78
|
+
logger.info("Compression allowlist updated: %s", sorted(tool_names) or "(empty)")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_compression_blocklist() -> set[str]:
|
|
82
|
+
"""Get the set of tool names explicitly blocked from compression.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Set of tool names that will never have their output compressed,
|
|
86
|
+
even when compression is enabled.
|
|
87
|
+
"""
|
|
88
|
+
return _parse_json_tool_list(get_value(_CONFIG_KEY_BLOCKLIST))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def set_compression_blocklist(tool_names: set[str]) -> None:
|
|
92
|
+
"""Set the blocklist of tool names for compression.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
tool_names: Set of tool names to block. Empty set clears the blocklist.
|
|
96
|
+
"""
|
|
97
|
+
set_config_value(_CONFIG_KEY_BLOCKLIST, _serialize_tool_list(tool_names))
|
|
98
|
+
logger.info("Compression blocklist updated: %s", sorted(tool_names) or "(empty)")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def is_tool_allowed(tool_name: str) -> bool:
|
|
102
|
+
"""Check if a specific tool's output should be compressed.
|
|
103
|
+
|
|
104
|
+
Logic:
|
|
105
|
+
1. If blocklist contains the tool name → False.
|
|
106
|
+
2. If allowlist is non-empty and does NOT contain the tool → False.
|
|
107
|
+
3. Otherwise → True.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
tool_name: Name of the tool to check.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
True if the tool's output may be compressed, False otherwise.
|
|
114
|
+
"""
|
|
115
|
+
blocklist = get_compression_blocklist()
|
|
116
|
+
if tool_name in blocklist:
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
allowlist = get_compression_allowlist()
|
|
120
|
+
if allowlist and tool_name not in allowlist:
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
return True
|