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,176 @@
|
|
|
1
|
+
"""Plugin-level config helpers for agent_skills."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from code_muse.config import get_value, set_value
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_skill_directories() -> list[Path]:
|
|
13
|
+
"""Get configured skill directories.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
List of skill directory paths from configuration.
|
|
17
|
+
Reads from muse.cfg [muse] section under 'skill_directories' key.
|
|
18
|
+
Default: ['~/.muse/skills', './.muse/skills', './skills']
|
|
19
|
+
|
|
20
|
+
The directories are stored as a JSON list in the config.
|
|
21
|
+
"""
|
|
22
|
+
# Try to read from config first
|
|
23
|
+
config_value = get_value("skill_directories")
|
|
24
|
+
|
|
25
|
+
if config_value:
|
|
26
|
+
try:
|
|
27
|
+
# Parse as JSON
|
|
28
|
+
directories = json.loads(config_value)
|
|
29
|
+
# Ensure it's a list
|
|
30
|
+
if isinstance(directories, list):
|
|
31
|
+
return [Path(d) for d in directories]
|
|
32
|
+
except json.JSONDecodeError as e:
|
|
33
|
+
logger.error(f"Failed to parse skill_directories config: {e}")
|
|
34
|
+
|
|
35
|
+
# Fallback to defaults
|
|
36
|
+
home_skills = Path.home() / ".muse" / "skills"
|
|
37
|
+
project_config_skills = Path.cwd() / ".muse" / "skills"
|
|
38
|
+
local_skills = Path.cwd() / "skills"
|
|
39
|
+
return [
|
|
40
|
+
home_skills,
|
|
41
|
+
project_config_skills,
|
|
42
|
+
local_skills,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def add_skill_directory(path: str | Path) -> bool:
|
|
47
|
+
"""Add a directory to the skills search path.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
path: Path to add to the skill directories list.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
True if the directory was added successfully, False otherwise.
|
|
54
|
+
"""
|
|
55
|
+
directories = [Path(d) for d in get_skill_directories()]
|
|
56
|
+
path = Path(path)
|
|
57
|
+
|
|
58
|
+
# Check if already exists
|
|
59
|
+
if path in directories:
|
|
60
|
+
logger.info(f"Skill directory already exists: {path}")
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
# Add the new directory
|
|
64
|
+
directories.append(path)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
# Save back to config as JSON
|
|
68
|
+
set_value("skill_directories", json.dumps([str(d) for d in directories]))
|
|
69
|
+
logger.info(f"Added skill directory: {path}")
|
|
70
|
+
return True
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.error(f"Failed to add skill directory: {e}")
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def remove_skill_directory(path: str | Path) -> bool:
|
|
77
|
+
"""Remove a directory from the skills search path.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
path: Path to remove from the skill directories list.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
True if the directory was removed successfully, False otherwise.
|
|
84
|
+
"""
|
|
85
|
+
directories = [Path(d) for d in get_skill_directories()]
|
|
86
|
+
path = Path(path)
|
|
87
|
+
|
|
88
|
+
# Check if exists
|
|
89
|
+
if path not in directories:
|
|
90
|
+
logger.info(f"Skill directory not found: {path}")
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
# Remove the directory
|
|
94
|
+
directories.remove(path)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
# Save back to config as JSON
|
|
98
|
+
set_value("skill_directories", json.dumps([str(d) for d in directories]))
|
|
99
|
+
logger.info(f"Removed skill directory: {path}")
|
|
100
|
+
return True
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.error(f"Failed to remove skill directory: {e}")
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_skills_enabled() -> bool:
|
|
107
|
+
"""Check if skills integration is globally enabled.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
True if skills are globally enabled, False otherwise.
|
|
111
|
+
Reads from 'skills_enabled' config key (default: True).
|
|
112
|
+
"""
|
|
113
|
+
cfg_val = get_value("skills_enabled")
|
|
114
|
+
if cfg_val is None:
|
|
115
|
+
return True # Enabled by default
|
|
116
|
+
return str(cfg_val).strip().lower() in {"1", "true", "yes", "on"}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def set_skills_enabled(enabled: bool) -> None:
|
|
120
|
+
"""Enable or disable skills integration globally.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
enabled: True to enable, False to disable.
|
|
124
|
+
"""
|
|
125
|
+
set_value("skills_enabled", "true" if enabled else "false")
|
|
126
|
+
logger.info(f"Skills integration {'enabled' if enabled else 'disabled'}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_disabled_skills() -> set[str]:
|
|
130
|
+
"""Get set of explicitly disabled skill names.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Set of skill names that are disabled.
|
|
134
|
+
Reads from 'disabled_skills' config key as a JSON list.
|
|
135
|
+
"""
|
|
136
|
+
config_value = get_value("disabled_skills")
|
|
137
|
+
|
|
138
|
+
if config_value:
|
|
139
|
+
try:
|
|
140
|
+
# Parse as JSON
|
|
141
|
+
disabled_list = json.loads(config_value)
|
|
142
|
+
# Ensure it's a list and convert to set
|
|
143
|
+
if isinstance(disabled_list, list):
|
|
144
|
+
return set(disabled_list)
|
|
145
|
+
except json.JSONDecodeError as e:
|
|
146
|
+
logger.error(f"Failed to parse disabled_skills config: {e}")
|
|
147
|
+
|
|
148
|
+
return set()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def set_skill_disabled(skill_name: str, disabled: bool) -> None:
|
|
152
|
+
"""Disable or re-enable a specific skill.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
skill_name: Name of the skill to disable/enable.
|
|
156
|
+
disabled: True to disable, False to enable.
|
|
157
|
+
"""
|
|
158
|
+
disabled_skills = get_disabled_skills()
|
|
159
|
+
|
|
160
|
+
if disabled:
|
|
161
|
+
# Add to disabled set
|
|
162
|
+
if skill_name in disabled_skills:
|
|
163
|
+
logger.info(f"Skill already disabled: {skill_name}")
|
|
164
|
+
return
|
|
165
|
+
disabled_skills.add(skill_name)
|
|
166
|
+
logger.info(f"Disabled skill: {skill_name}")
|
|
167
|
+
else:
|
|
168
|
+
# Remove from disabled set
|
|
169
|
+
if skill_name not in disabled_skills:
|
|
170
|
+
logger.info(f"Skill already enabled: {skill_name}")
|
|
171
|
+
return
|
|
172
|
+
disabled_skills.remove(skill_name)
|
|
173
|
+
logger.info(f"Enabled skill: {skill_name}")
|
|
174
|
+
|
|
175
|
+
# Save back to config as JSON
|
|
176
|
+
set_value("disabled_skills", json.dumps(list(disabled_skills)))
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"""Skill discovery - scans directories for valid skills.
|
|
2
|
+
|
|
3
|
+
Includes safety checks for symlink escapes, hidden directories,
|
|
4
|
+
SKILL.md size validation, and executable file awareness.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import contextlib
|
|
8
|
+
import logging
|
|
9
|
+
import stat
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from code_muse.plugins.agent_skills.config import get_skill_directories
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# Max SKILL.md file size before we refuse to read (256 KiB)
|
|
18
|
+
MAX_SKILL_MD_BYTES = 256 * 1024
|
|
19
|
+
|
|
20
|
+
# Cap for skill content injected into model context (chars)
|
|
21
|
+
SKILL_CONTEXT_CAP = 64_000
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class SkillInfo:
|
|
26
|
+
"""Basic skill information from discovery."""
|
|
27
|
+
|
|
28
|
+
name: str
|
|
29
|
+
path: Path
|
|
30
|
+
has_skill_md: bool
|
|
31
|
+
skill_md_size: int | None = None
|
|
32
|
+
skill_md_hash: str | None = None
|
|
33
|
+
source: str | None = None
|
|
34
|
+
trust: str | None = None # "builtin" | "user" | None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Global cache for discovered skills
|
|
38
|
+
_skill_cache: list[SkillInfo | None] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _is_symlink_escape(child: Path, parent: Path) -> bool:
|
|
42
|
+
"""Return True if *child* resolves outside *parent* (symlink escape)."""
|
|
43
|
+
try:
|
|
44
|
+
child.resolve().relative_to(parent.resolve())
|
|
45
|
+
return False
|
|
46
|
+
except ValueError:
|
|
47
|
+
return True
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _has_unexpected_executables(skill_dir: Path) -> bool:
|
|
51
|
+
"""Return True if *skill_dir* contains unexpected executable files.
|
|
52
|
+
|
|
53
|
+
We expect only .md, .txt, .json, .yaml, .yml, .py, .toml files in
|
|
54
|
+
skill directories. Anything with the execute bit set (beyond
|
|
55
|
+
directory traversal) is flagged.
|
|
56
|
+
"""
|
|
57
|
+
safe_extensions = {
|
|
58
|
+
".md",
|
|
59
|
+
".txt",
|
|
60
|
+
".json",
|
|
61
|
+
".yaml",
|
|
62
|
+
".yml",
|
|
63
|
+
".py",
|
|
64
|
+
".toml",
|
|
65
|
+
".cfg",
|
|
66
|
+
".ini",
|
|
67
|
+
".rst",
|
|
68
|
+
".html",
|
|
69
|
+
".css",
|
|
70
|
+
".js",
|
|
71
|
+
}
|
|
72
|
+
try:
|
|
73
|
+
for item in skill_dir.iterdir():
|
|
74
|
+
if not item.is_file():
|
|
75
|
+
continue
|
|
76
|
+
# Skip symlinks that escape
|
|
77
|
+
if item.is_symlink() and _is_symlink_escape(item, skill_dir):
|
|
78
|
+
return True
|
|
79
|
+
# Check for executable bit on non-standard files
|
|
80
|
+
if item.suffix.lower() not in safe_extensions:
|
|
81
|
+
try:
|
|
82
|
+
mode = item.stat().st_mode
|
|
83
|
+
if mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
|
|
84
|
+
logger.warning(
|
|
85
|
+
"Unexpected executable file in skill dir %s: %s",
|
|
86
|
+
skill_dir.name,
|
|
87
|
+
item.name,
|
|
88
|
+
)
|
|
89
|
+
return True
|
|
90
|
+
except OSError:
|
|
91
|
+
pass
|
|
92
|
+
except OSError:
|
|
93
|
+
pass
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_default_skill_directories() -> list[Path]:
|
|
98
|
+
"""Return default directories to scan for skills.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
- ~/.muse/skills (user skills)
|
|
102
|
+
- ./.muse/skills (project config skills)
|
|
103
|
+
- ./skills (project skills)
|
|
104
|
+
"""
|
|
105
|
+
return [
|
|
106
|
+
Path.home() / ".muse" / "skills",
|
|
107
|
+
Path.cwd() / ".muse" / "skills",
|
|
108
|
+
Path.cwd() / "skills",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def is_valid_skill_directory(path: Path) -> bool:
|
|
113
|
+
"""Check if a directory contains a valid SKILL.md file.
|
|
114
|
+
|
|
115
|
+
Also validates that SKILL.md is not oversized and that
|
|
116
|
+
the directory does not contain unexpected executables.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
path: Directory path to check.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
True if the directory is a valid skill directory, False otherwise.
|
|
123
|
+
"""
|
|
124
|
+
if not path.is_dir():
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
skill_md_path = path / "SKILL.md"
|
|
128
|
+
if not skill_md_path.is_file():
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
# Check for symlink escape on SKILL.md
|
|
132
|
+
if _is_symlink_escape(skill_md_path, path):
|
|
133
|
+
logger.warning("SKILL.md in %s is a symlink escape, skipping", path.name)
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
# Validate SKILL.md size before we ever read it
|
|
137
|
+
try:
|
|
138
|
+
size = skill_md_path.stat().st_size
|
|
139
|
+
if size > MAX_SKILL_MD_BYTES:
|
|
140
|
+
logger.warning(
|
|
141
|
+
"SKILL.md in %s is too large (%d bytes, max %d), skipping",
|
|
142
|
+
path.name,
|
|
143
|
+
size,
|
|
144
|
+
MAX_SKILL_MD_BYTES,
|
|
145
|
+
)
|
|
146
|
+
return False
|
|
147
|
+
except OSError:
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
# Check for unexpected executable files
|
|
151
|
+
if _has_unexpected_executables(path):
|
|
152
|
+
logger.warning(
|
|
153
|
+
"Skill directory %s contains unexpected executable files, skipping",
|
|
154
|
+
path.name,
|
|
155
|
+
)
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _compute_skill_md_hash(skill_md_path: Path) -> str | None:
|
|
162
|
+
"""Compute SHA-256 hash of a SKILL.md file."""
|
|
163
|
+
import hashlib
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
content = skill_md_path.read_bytes()
|
|
167
|
+
return hashlib.sha256(content).hexdigest()
|
|
168
|
+
except OSError:
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _classify_skill_source(skill_dir: Path) -> str:
|
|
173
|
+
"""Classify a skill directory as 'builtin' or 'user'."""
|
|
174
|
+
home_skills = Path.home() / ".muse" / "skills"
|
|
175
|
+
try:
|
|
176
|
+
skill_dir.resolve().relative_to(home_skills.resolve())
|
|
177
|
+
return "user"
|
|
178
|
+
except ValueError:
|
|
179
|
+
pass
|
|
180
|
+
# Check if it's under CWD
|
|
181
|
+
try:
|
|
182
|
+
skill_dir.resolve().relative_to(Path.cwd().resolve())
|
|
183
|
+
return "project"
|
|
184
|
+
except ValueError:
|
|
185
|
+
pass
|
|
186
|
+
return "unknown"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def discover_skills(directories: list[Path | None] = None) -> list[SkillInfo]:
|
|
190
|
+
"""Scan directories for valid skills.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
directories: Directories to scan. If None, uses configured
|
|
194
|
+
directories (which includes user-added ones from /skills menu).
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
List of discovered SkillInfo objects.
|
|
198
|
+
"""
|
|
199
|
+
global _skill_cache
|
|
200
|
+
|
|
201
|
+
if directories is None:
|
|
202
|
+
# Use configured directories (respects user-added dirs from /skills menu)
|
|
203
|
+
# then merge with defaults to ensure we always check the standard locations
|
|
204
|
+
configured = [Path(d) for d in get_skill_directories()]
|
|
205
|
+
defaults = get_default_skill_directories()
|
|
206
|
+
# Merge: configured first, then any defaults not already covered
|
|
207
|
+
seen = {p.resolve() for p in configured}
|
|
208
|
+
directories = list(configured)
|
|
209
|
+
for d in defaults:
|
|
210
|
+
if d.resolve() not in seen:
|
|
211
|
+
directories.append(d)
|
|
212
|
+
|
|
213
|
+
discovered_skills: list[SkillInfo] = []
|
|
214
|
+
|
|
215
|
+
for directory in directories:
|
|
216
|
+
if not directory.exists():
|
|
217
|
+
logger.debug("Skill directory does not exist: %s", directory)
|
|
218
|
+
continue
|
|
219
|
+
|
|
220
|
+
if not directory.is_dir():
|
|
221
|
+
logger.warning("Skill path is not a directory: %s", directory)
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
# Scan subdirectories within the skill directory
|
|
225
|
+
for skill_dir in directory.iterdir():
|
|
226
|
+
if not skill_dir.is_dir():
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
# Skip hidden directories
|
|
230
|
+
if skill_dir.name.startswith(".") or skill_dir.name.startswith("_"):
|
|
231
|
+
continue
|
|
232
|
+
|
|
233
|
+
# Skip symlink escapes
|
|
234
|
+
if _is_symlink_escape(skill_dir, directory):
|
|
235
|
+
logger.warning(
|
|
236
|
+
"Skipping skill dir %s: symlink escape from %s",
|
|
237
|
+
skill_dir.name,
|
|
238
|
+
directory,
|
|
239
|
+
)
|
|
240
|
+
continue
|
|
241
|
+
|
|
242
|
+
has_skill_md = is_valid_skill_directory(skill_dir)
|
|
243
|
+
|
|
244
|
+
# Compute metadata for valid skills
|
|
245
|
+
skill_md_size = None
|
|
246
|
+
skill_md_hash = None
|
|
247
|
+
if has_skill_md:
|
|
248
|
+
skill_md_path = skill_dir / "SKILL.md"
|
|
249
|
+
with contextlib.suppress(OSError):
|
|
250
|
+
skill_md_size = skill_md_path.stat().st_size
|
|
251
|
+
skill_md_hash = _compute_skill_md_hash(skill_md_path)
|
|
252
|
+
|
|
253
|
+
source = _classify_skill_source(skill_dir)
|
|
254
|
+
# Built-in skills from the package are always trusted
|
|
255
|
+
trust = "builtin" if source == "unknown" else source
|
|
256
|
+
|
|
257
|
+
skill_info = SkillInfo(
|
|
258
|
+
name=skill_dir.name,
|
|
259
|
+
path=skill_dir,
|
|
260
|
+
has_skill_md=has_skill_md,
|
|
261
|
+
skill_md_size=skill_md_size,
|
|
262
|
+
skill_md_hash=skill_md_hash,
|
|
263
|
+
source=source,
|
|
264
|
+
trust=trust,
|
|
265
|
+
)
|
|
266
|
+
discovered_skills.append(skill_info)
|
|
267
|
+
|
|
268
|
+
if has_skill_md:
|
|
269
|
+
logger.debug(
|
|
270
|
+
"Discovered valid skill: %s at %s", skill_dir.name, skill_dir
|
|
271
|
+
)
|
|
272
|
+
else:
|
|
273
|
+
logger.debug(
|
|
274
|
+
"Found skill directory without SKILL.md: %s", skill_dir.name
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Update cache
|
|
278
|
+
_skill_cache = discovered_skills
|
|
279
|
+
|
|
280
|
+
logger.info(
|
|
281
|
+
"Discovered %d skills from %d directories",
|
|
282
|
+
len(discovered_skills),
|
|
283
|
+
len(directories),
|
|
284
|
+
)
|
|
285
|
+
return discovered_skills
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def refresh_skill_cache() -> list[SkillInfo]:
|
|
289
|
+
"""Force re-discovery of all skills.
|
|
290
|
+
|
|
291
|
+
This clears the cache and performs a fresh scan of all default
|
|
292
|
+
skill directories.
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
List of freshly discovered SkillInfo objects.
|
|
296
|
+
"""
|
|
297
|
+
global _skill_cache
|
|
298
|
+
_skill_cache = None
|
|
299
|
+
return discover_skills()
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def cap_skill_content(content: str, cap: int = SKILL_CONTEXT_CAP) -> str:
|
|
303
|
+
"""Cap skill content to prevent model-context blowup.
|
|
304
|
+
|
|
305
|
+
If content exceeds *cap* characters, it is truncated with a marker.
|
|
306
|
+
"""
|
|
307
|
+
if len(content) <= cap:
|
|
308
|
+
return content
|
|
309
|
+
return content[:cap] + "\n... [skill content truncated]"
|