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,89 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from code_muse.plugins.custom_commands.command_toml_schema import (
|
|
6
|
+
CommandDef,
|
|
7
|
+
parse_command_toml,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
_VALID_NAME_RE = re.compile(r"^[a-zA-Z0-9_-]+$")
|
|
13
|
+
|
|
14
|
+
_USER_COMMANDS_DIR = Path.home() / ".muse" / "commands"
|
|
15
|
+
_PROJECT_COMMANDS_DIR = Path(".muse") / "commands"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _resolve_namespace(file_path: Path, commands_dir: Path) -> str:
|
|
19
|
+
"""Derive the command namespace from its path relative to *commands_dir*.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
- ``commands_dir / "fix.toml"`` → ``/fix``
|
|
23
|
+
- ``commands_dir / "git" / "fix.toml"`` → ``/git:fix``
|
|
24
|
+
"""
|
|
25
|
+
rel = file_path.relative_to(commands_dir)
|
|
26
|
+
# Drop the .toml extension and replace path separators with colons
|
|
27
|
+
namespace = "/" + str(rel.with_suffix("")).replace("/", ":")
|
|
28
|
+
return namespace
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _scan_tier(commands_dir: Path, tier_label: str) -> dict[str, CommandDef]:
|
|
32
|
+
"""Scan a single directory tier for ``*.toml`` command files.
|
|
33
|
+
|
|
34
|
+
Returns a mapping of ``namespace → CommandDef``.
|
|
35
|
+
"""
|
|
36
|
+
discovered: dict[str, CommandDef] = {}
|
|
37
|
+
if not commands_dir.exists():
|
|
38
|
+
return discovered
|
|
39
|
+
|
|
40
|
+
# Collect both flat and nested files
|
|
41
|
+
files = sorted(commands_dir.rglob("*.toml"))
|
|
42
|
+
for file_path in files:
|
|
43
|
+
# Skip hidden files / directories
|
|
44
|
+
if any(
|
|
45
|
+
part.startswith(".") for part in file_path.relative_to(commands_dir).parts
|
|
46
|
+
):
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
name_part = file_path.stem
|
|
50
|
+
if not _VALID_NAME_RE.match(name_part):
|
|
51
|
+
logger.warning(
|
|
52
|
+
"Skipping invalid command filename %s (names must be alphanumeric, hyphens, underscores)",
|
|
53
|
+
file_path,
|
|
54
|
+
)
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
namespace = _resolve_namespace(file_path, commands_dir)
|
|
58
|
+
try:
|
|
59
|
+
cmd_def = parse_command_toml(file_path)
|
|
60
|
+
cmd_def.name = namespace # override with the namespaced name
|
|
61
|
+
except ValueError as exc:
|
|
62
|
+
logger.warning("Failed to load command from %s: %s", file_path, exc)
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
discovered[namespace] = cmd_def
|
|
66
|
+
|
|
67
|
+
return discovered
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def discover_commands(
|
|
71
|
+
user_dir: Path | None = None,
|
|
72
|
+
project_dir: Path | None = None,
|
|
73
|
+
) -> dict[str, CommandDef]:
|
|
74
|
+
"""Discover custom commands from user and project tiers.
|
|
75
|
+
|
|
76
|
+
Scans ``~/.muse/commands/**/*.toml`` (user tier) and
|
|
77
|
+
``.muse/commands/**/*.toml`` (project tier). Project
|
|
78
|
+
definitions override user definitions for the same namespace.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Mapping of ``namespace → CommandDef``.
|
|
82
|
+
"""
|
|
83
|
+
user_tier = _scan_tier(user_dir or _USER_COMMANDS_DIR, "user")
|
|
84
|
+
project_tier = _scan_tier(project_dir or _PROJECT_COMMANDS_DIR, "project")
|
|
85
|
+
|
|
86
|
+
# Project tier overrides user tier
|
|
87
|
+
merged = dict(user_tier)
|
|
88
|
+
merged.update(project_tier)
|
|
89
|
+
return merged
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
_KNOWN_FIELDS = {"prompt", "description"}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class CommandDef:
|
|
13
|
+
"""Definition of a custom command loaded from a TOML file."""
|
|
14
|
+
|
|
15
|
+
name: str
|
|
16
|
+
prompt: str
|
|
17
|
+
description: str = ""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _warn_unknown_fields(data: dict[str, Any], path: Path) -> None:
|
|
21
|
+
unknown = set(data.keys()) - _KNOWN_FIELDS
|
|
22
|
+
if unknown:
|
|
23
|
+
logger.warning(
|
|
24
|
+
"Unknown fields in command file %s: %s",
|
|
25
|
+
path,
|
|
26
|
+
", ".join(sorted(unknown)),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def parse_command_toml(path: Path) -> CommandDef:
|
|
31
|
+
"""Parse a single command definition from a TOML file.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
path: Path to the ``.toml`` file.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
``CommandDef`` with ``name`` derived from the file path,
|
|
38
|
+
``prompt`` from the TOML ``prompt`` key, and optional
|
|
39
|
+
``description``.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
ValueError: If ``prompt`` is missing, empty, or not a string.
|
|
43
|
+
"""
|
|
44
|
+
import tomllib
|
|
45
|
+
|
|
46
|
+
raw = path.read_text(encoding="utf-8")
|
|
47
|
+
data = tomllib.loads(raw)
|
|
48
|
+
|
|
49
|
+
if not isinstance(data, dict):
|
|
50
|
+
raise ValueError(
|
|
51
|
+
f"Invalid TOML in {path}: expected table, got {type(data).__name__}"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
_warn_unknown_fields(data, path)
|
|
55
|
+
|
|
56
|
+
prompt = data.get("prompt")
|
|
57
|
+
if prompt is None:
|
|
58
|
+
raise ValueError(f"Command file {path} is missing required field 'prompt'")
|
|
59
|
+
if not isinstance(prompt, str):
|
|
60
|
+
raise ValueError(
|
|
61
|
+
f"Command file {path}: 'prompt' must be a string, got {type(prompt).__name__}"
|
|
62
|
+
)
|
|
63
|
+
if not prompt.strip():
|
|
64
|
+
raise ValueError(f"Command file {path}: 'prompt' must be a non-empty string")
|
|
65
|
+
|
|
66
|
+
description = data.get("description", "")
|
|
67
|
+
if description is not None and not isinstance(description, str):
|
|
68
|
+
raise ValueError(f"Command file {path}: 'description' must be a string")
|
|
69
|
+
|
|
70
|
+
name = path.stem
|
|
71
|
+
return CommandDef(name=name, prompt=prompt, description=description or "")
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from code_muse.callbacks import register_callback
|
|
5
|
+
from code_muse.messaging import emit_info, emit_success
|
|
6
|
+
from code_muse.plugins.custom_commands.args_injection import (
|
|
7
|
+
apply_shell_flags,
|
|
8
|
+
detect_shell_blocks,
|
|
9
|
+
inject_args,
|
|
10
|
+
)
|
|
11
|
+
from code_muse.plugins.custom_commands.command_discovery import (
|
|
12
|
+
CommandDef,
|
|
13
|
+
discover_commands,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Result wrapper so command_handler.py sends the prompt to the agent
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CustomCommandResult:
|
|
24
|
+
"""Marker class for custom-command results that should be processed as input."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, content: str):
|
|
27
|
+
self.content = content
|
|
28
|
+
|
|
29
|
+
def __str__(self) -> str:
|
|
30
|
+
return self.content
|
|
31
|
+
|
|
32
|
+
def __repr__(self) -> str:
|
|
33
|
+
return f"CustomCommandResult({len(self.content)} chars)"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Command cache
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
_command_cache: dict[str, CommandDef] = {}
|
|
41
|
+
_cache_loaded: bool = False
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _load_commands() -> None:
|
|
45
|
+
"""Load or reload the command discovery cache."""
|
|
46
|
+
global _command_cache, _cache_loaded
|
|
47
|
+
_command_cache = discover_commands()
|
|
48
|
+
_cache_loaded = True
|
|
49
|
+
logger.debug("Loaded %d custom command(s)", len(_command_cache))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _reload_commands() -> None:
|
|
53
|
+
"""Clear cache and re-discover commands."""
|
|
54
|
+
global _command_cache, _cache_loaded
|
|
55
|
+
_command_cache.clear()
|
|
56
|
+
_cache_loaded = False
|
|
57
|
+
_load_commands()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
# Callbacks
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _on_custom_command(command: str, name: str) -> Any:
|
|
66
|
+
"""Handle a TOML-defined custom command.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
command: Full command string (e.g. ``"/git:fix arg1"``).
|
|
70
|
+
name: Command name extracted by the handler (e.g. ``"git:fix"``).
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
- ``CustomCommandResult(prompt)`` when a custom command is resolved
|
|
74
|
+
and should be sent to the agent as input.
|
|
75
|
+
- ``True`` for management commands (``/commands list``, ``/commands reload``).
|
|
76
|
+
- ``None`` if the command is not recognised (passthrough).
|
|
77
|
+
"""
|
|
78
|
+
if not name:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
# Management commands
|
|
82
|
+
if name == "commands":
|
|
83
|
+
return _handle_commands_management(command)
|
|
84
|
+
|
|
85
|
+
# Ensure cache is populated
|
|
86
|
+
if not _cache_loaded:
|
|
87
|
+
_load_commands()
|
|
88
|
+
|
|
89
|
+
cmd_def = _command_cache.get("/" + name)
|
|
90
|
+
if cmd_def is None:
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
# Extract args (everything after the command name)
|
|
94
|
+
parts = command.split(maxsplit=1)
|
|
95
|
+
args = parts[1] if len(parts) > 1 else ""
|
|
96
|
+
|
|
97
|
+
# Inject {{args}}
|
|
98
|
+
prompt = inject_args(cmd_def.prompt, args)
|
|
99
|
+
|
|
100
|
+
# Shell-context mode: auto-append efficiency flags
|
|
101
|
+
if detect_shell_blocks(prompt):
|
|
102
|
+
prompt = apply_shell_flags(prompt)
|
|
103
|
+
|
|
104
|
+
return CustomCommandResult(prompt)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _handle_commands_management(command: str) -> bool:
|
|
108
|
+
"""Handle ``/commands``, ``/commands list``, and ``/commands reload``."""
|
|
109
|
+
rest = command.split(maxsplit=1)
|
|
110
|
+
subcommand = rest[1].strip().lower() if len(rest) > 1 else ""
|
|
111
|
+
|
|
112
|
+
if subcommand == "reload":
|
|
113
|
+
_reload_commands()
|
|
114
|
+
emit_success(f"🔄 Reloaded {len(_command_cache)} custom command(s)")
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
# Default to list
|
|
118
|
+
return _commands_list()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _commands_list() -> bool:
|
|
122
|
+
"""Display all discovered custom commands and return ``True``."""
|
|
123
|
+
if not _cache_loaded:
|
|
124
|
+
_load_commands()
|
|
125
|
+
|
|
126
|
+
if not _command_cache:
|
|
127
|
+
emit_info("No custom commands found.")
|
|
128
|
+
emit_info(
|
|
129
|
+
"Create .toml files in ~/.muse/commands/ or .muse/commands/"
|
|
130
|
+
)
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
lines: list[str] = ["Custom commands:"]
|
|
134
|
+
for namespace in sorted(_command_cache):
|
|
135
|
+
cmd = _command_cache[namespace]
|
|
136
|
+
desc = f" — {cmd.description}" if cmd.description else ""
|
|
137
|
+
lines.append(f" {namespace}{desc}")
|
|
138
|
+
|
|
139
|
+
lines.append("")
|
|
140
|
+
lines.append("Management:")
|
|
141
|
+
lines.append(" /commands list — Show this list")
|
|
142
|
+
lines.append(" /commands reload — Rescan command directories")
|
|
143
|
+
|
|
144
|
+
emit_info("\n".join(lines))
|
|
145
|
+
return True
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _on_custom_command_help() -> list[tuple[str, str]]:
|
|
149
|
+
"""Return help entries for all discovered commands."""
|
|
150
|
+
if not _cache_loaded:
|
|
151
|
+
_load_commands()
|
|
152
|
+
|
|
153
|
+
entries: list[tuple[str, str]] = []
|
|
154
|
+
for namespace in sorted(_command_cache):
|
|
155
|
+
cmd = _command_cache[namespace]
|
|
156
|
+
desc = cmd.description or "Custom TOML command"
|
|
157
|
+
entries.append((namespace.lstrip("/"), desc))
|
|
158
|
+
|
|
159
|
+
# Management commands
|
|
160
|
+
entries.append(("commands list", "List available custom commands"))
|
|
161
|
+
entries.append(("commands reload", "Rescan custom command directories"))
|
|
162
|
+
return entries
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _on_startup() -> None:
|
|
166
|
+
"""Load commands at startup so they're available immediately."""
|
|
167
|
+
_load_commands()
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# ---------------------------------------------------------------------------
|
|
171
|
+
# Registration
|
|
172
|
+
# ---------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
register_callback("custom_command", _on_custom_command)
|
|
175
|
+
register_callback("custom_command_help", _on_custom_command_help)
|
|
176
|
+
register_callback("startup", _on_startup)
|
|
File without changes
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from code_muse.callbacks import register_callback
|
|
5
|
+
from code_muse.command_line.types import MarkdownCommandResult
|
|
6
|
+
from code_muse.messaging import emit_error, emit_info
|
|
7
|
+
|
|
8
|
+
# Global cache for loaded commands
|
|
9
|
+
_custom_commands: dict[str, str] = {}
|
|
10
|
+
_command_descriptions: dict[str, str] = {}
|
|
11
|
+
_commands_loaded: bool = False # Sentinel to track if commands have been loaded
|
|
12
|
+
|
|
13
|
+
# Directories to scan for commands (in priority order - later directories override earlier)
|
|
14
|
+
_COMMAND_DIRECTORIES = [
|
|
15
|
+
"~/.muse/commands", # Global commands (all projects)
|
|
16
|
+
".claude/commands",
|
|
17
|
+
".github/prompts",
|
|
18
|
+
".agents/commands",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _load_markdown_commands() -> None:
|
|
23
|
+
"""Load markdown command files from the configured directories.
|
|
24
|
+
|
|
25
|
+
Scans for *.md files in the configured directories and loads them
|
|
26
|
+
as custom commands. Later directories override earlier ones with the
|
|
27
|
+
same command name (project commands override global).
|
|
28
|
+
"""
|
|
29
|
+
global _custom_commands, _command_descriptions, _commands_loaded
|
|
30
|
+
|
|
31
|
+
_custom_commands.clear()
|
|
32
|
+
_command_descriptions.clear()
|
|
33
|
+
_commands_loaded = True # Mark as loaded even if directories are empty
|
|
34
|
+
|
|
35
|
+
# Process directories in order - later directories override earlier ones
|
|
36
|
+
for directory in _COMMAND_DIRECTORIES:
|
|
37
|
+
dir_path = Path(directory).expanduser()
|
|
38
|
+
if not dir_path.exists():
|
|
39
|
+
continue
|
|
40
|
+
|
|
41
|
+
# Look for markdown files
|
|
42
|
+
pattern = "*.md" if directory != ".github/prompts" else "*.prompt.md"
|
|
43
|
+
# Sort within directory for consistent ordering
|
|
44
|
+
md_files = sorted(dir_path.glob(pattern))
|
|
45
|
+
|
|
46
|
+
for md_file in md_files:
|
|
47
|
+
try:
|
|
48
|
+
# Extract command name from filename
|
|
49
|
+
if md_file.name.endswith(".prompt.md"):
|
|
50
|
+
base_name = md_file.name[: -len(".prompt.md")]
|
|
51
|
+
else:
|
|
52
|
+
base_name = md_file.stem
|
|
53
|
+
|
|
54
|
+
# Read file content
|
|
55
|
+
content = md_file.read_text(encoding="utf-8").strip()
|
|
56
|
+
if not content:
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
# Extract first line as description (or use filename)
|
|
60
|
+
lines = content.split("\n")
|
|
61
|
+
description = base_name.replace("_", " ").replace("-", " ").title()
|
|
62
|
+
|
|
63
|
+
# Try to get description from first non-empty line that's not a heading
|
|
64
|
+
for line in lines:
|
|
65
|
+
stripped = line.strip()
|
|
66
|
+
if stripped and not stripped.startswith("#"):
|
|
67
|
+
# Truncate long descriptions
|
|
68
|
+
description = stripped[:50] + (
|
|
69
|
+
"..." if len(stripped) > 50 else ""
|
|
70
|
+
)
|
|
71
|
+
break
|
|
72
|
+
|
|
73
|
+
# Later directories override earlier ones (project > global)
|
|
74
|
+
_custom_commands[base_name] = content
|
|
75
|
+
_command_descriptions[base_name] = description
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
emit_error(f"Failed to load command from {md_file}: {e}")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _custom_help() -> list[tuple[str, str]]:
|
|
82
|
+
"""Return help entries for loaded markdown commands."""
|
|
83
|
+
# Reload commands to pick up any changes
|
|
84
|
+
_load_markdown_commands()
|
|
85
|
+
|
|
86
|
+
help_entries = []
|
|
87
|
+
for name, description in sorted(_command_descriptions.items()):
|
|
88
|
+
help_entries.append((name, f"Execute markdown command: {description}"))
|
|
89
|
+
|
|
90
|
+
return help_entries
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _handle_custom_command(command: str, name: str) -> Any | None:
|
|
94
|
+
"""Handle a markdown-based custom command.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
command: The full command string
|
|
98
|
+
name: The command name without leading slash
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
MarkdownCommandResult with content to be processed as input,
|
|
102
|
+
or None if not found
|
|
103
|
+
"""
|
|
104
|
+
if not name:
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
# Ensure commands are loaded (use sentinel, not dict emptiness)
|
|
108
|
+
if not _commands_loaded:
|
|
109
|
+
_load_markdown_commands()
|
|
110
|
+
|
|
111
|
+
# Look up the command
|
|
112
|
+
content = _custom_commands.get(name)
|
|
113
|
+
if content is None:
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
# Extract any additional arguments from the command
|
|
117
|
+
parts = command.split(maxsplit=1)
|
|
118
|
+
args = parts[1] if len(parts) > 1 else ""
|
|
119
|
+
|
|
120
|
+
# If there are arguments, append them to the prompt
|
|
121
|
+
prompt = f"{content}\n\nAdditional context: {args}" if args else content
|
|
122
|
+
|
|
123
|
+
# Emit info message and return the special marker
|
|
124
|
+
emit_info(f"📝 Executing markdown command: {name}")
|
|
125
|
+
return MarkdownCommandResult(prompt)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Register callbacks
|
|
129
|
+
register_callback("custom_command_help", _custom_help)
|
|
130
|
+
register_callback("custom_command", _handle_custom_command)
|
|
131
|
+
|
|
132
|
+
# Re-export the shared type for backward compatibility
|
|
133
|
+
__all__ = ["MarkdownCommandResult"]
|
|
134
|
+
|
|
135
|
+
# Load commands at import time
|
|
136
|
+
_load_markdown_commands()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Destructive command guard plugin.
|
|
2
|
+
|
|
3
|
+
Intercepts potentially-destructive shell commands and prompts the user for
|
|
4
|
+
approval before allowing them through. Always active, pure regex, no LLM calls.
|
|
5
|
+
|
|
6
|
+
Covers:
|
|
7
|
+
- Unix/Linux: rm -rf /, rm -rf ~, rm -rf /*, rm -rf ~/*
|
|
8
|
+
- Cross-platform (git, docker, npm/yarn, twine, SQL clients):
|
|
9
|
+
git push --mirror, git clean -fd, git reset --hard, git checkout/restore .,
|
|
10
|
+
DROP via SQL client, docker prune, npm/yarn publish, twine upload
|
|
11
|
+
- Windows PowerShell: Remove-Item -Recurse -Force, Format-Volume, Clear-Disk,
|
|
12
|
+
Remove-ItemProperty, Clear-RecycleBin, irm | iex (remote code execution)
|
|
13
|
+
- Windows CMD: rd /s /q, del /s system files, format, diskpart, bcdedit, reg delete
|
|
14
|
+
"""
|