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,440 @@
|
|
|
1
|
+
"""Universal Constructor safety and approval engine.
|
|
2
|
+
|
|
3
|
+
Validates tool names/namespaces, blocks dangerous code patterns,
|
|
4
|
+
and stores per-tool approval decisions keyed by code hash.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import ast
|
|
8
|
+
import contextlib
|
|
9
|
+
import hashlib
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# XDG state directory for private approval storage
|
|
19
|
+
_APPROVAL_DIR = (
|
|
20
|
+
Path(os.environ.get("XDG_STATE_HOME", Path.home() / ".local" / "state"))
|
|
21
|
+
/ "code_muse"
|
|
22
|
+
)
|
|
23
|
+
_APPROVAL_FILE = _APPROVAL_DIR / "uc_approvals.json"
|
|
24
|
+
|
|
25
|
+
# Valid tool name: [a-zA-Z_][a-zA-Z0-9_]*
|
|
26
|
+
_VALID_NAME_RE = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
|
|
27
|
+
|
|
28
|
+
# Reserved module names that should not be used as tool names
|
|
29
|
+
_RESERVED_MODULE_NAMES: set[str] = {
|
|
30
|
+
"abc",
|
|
31
|
+
"ast",
|
|
32
|
+
"builtins",
|
|
33
|
+
"code",
|
|
34
|
+
"codecs",
|
|
35
|
+
"collections",
|
|
36
|
+
"copy",
|
|
37
|
+
"datetime",
|
|
38
|
+
"enum",
|
|
39
|
+
"fnmatch",
|
|
40
|
+
"functools",
|
|
41
|
+
"glob",
|
|
42
|
+
"hashlib",
|
|
43
|
+
"importlib",
|
|
44
|
+
"inspect",
|
|
45
|
+
"io",
|
|
46
|
+
"json",
|
|
47
|
+
"logging",
|
|
48
|
+
"math",
|
|
49
|
+
"os",
|
|
50
|
+
"pathlib",
|
|
51
|
+
"pickle",
|
|
52
|
+
"platform",
|
|
53
|
+
"random",
|
|
54
|
+
"re",
|
|
55
|
+
"shutil",
|
|
56
|
+
"signal",
|
|
57
|
+
"socket",
|
|
58
|
+
"sqlite3",
|
|
59
|
+
"string",
|
|
60
|
+
"subprocess",
|
|
61
|
+
"sys",
|
|
62
|
+
"tempfile",
|
|
63
|
+
"threading",
|
|
64
|
+
"time",
|
|
65
|
+
"traceback",
|
|
66
|
+
"types",
|
|
67
|
+
"typing",
|
|
68
|
+
"urllib",
|
|
69
|
+
"uuid",
|
|
70
|
+
"warnings",
|
|
71
|
+
"xml",
|
|
72
|
+
"zipfile",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Dangerous patterns that should BLOCK tool creation/execution
|
|
76
|
+
_DANGEROUS_IMPORTS_BLOCK: set[str] = {
|
|
77
|
+
"subprocess",
|
|
78
|
+
"os.system",
|
|
79
|
+
"eval",
|
|
80
|
+
"exec",
|
|
81
|
+
"compile",
|
|
82
|
+
"__import__",
|
|
83
|
+
"pickle",
|
|
84
|
+
"marshal",
|
|
85
|
+
"socket",
|
|
86
|
+
"ctypes",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_DANGEROUS_CALLS_BLOCK: set[str] = {
|
|
90
|
+
"eval",
|
|
91
|
+
"exec",
|
|
92
|
+
"compile",
|
|
93
|
+
"__import__",
|
|
94
|
+
"system",
|
|
95
|
+
"popen",
|
|
96
|
+
"spawn",
|
|
97
|
+
"fork",
|
|
98
|
+
"globals",
|
|
99
|
+
"locals",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Additional dangerous patterns that require explicit approval
|
|
103
|
+
_DANGEROUS_IMPORTS_APPROVAL: set[str] = {
|
|
104
|
+
"requests",
|
|
105
|
+
"urllib",
|
|
106
|
+
"http.client",
|
|
107
|
+
"ftplib",
|
|
108
|
+
"smtplib",
|
|
109
|
+
"paramiko",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_DANGEROUS_OPEN_MODES = {
|
|
113
|
+
"w",
|
|
114
|
+
"a",
|
|
115
|
+
"x",
|
|
116
|
+
"wb",
|
|
117
|
+
"ab",
|
|
118
|
+
"xb",
|
|
119
|
+
"w+",
|
|
120
|
+
"a+",
|
|
121
|
+
"r+",
|
|
122
|
+
"rb+",
|
|
123
|
+
"wb+",
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _ensure_private_dir(path: Path) -> Path:
|
|
128
|
+
"""Ensure directory exists with 0o700 permissions."""
|
|
129
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
130
|
+
with contextlib.suppress(OSError):
|
|
131
|
+
os.chmod(path, 0o700)
|
|
132
|
+
return path
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _atomic_write_private_json(file_path: Path, data: dict) -> None:
|
|
136
|
+
"""Atomically write JSON with 0o600 permissions."""
|
|
137
|
+
tmp_path = file_path.with_suffix(".tmp")
|
|
138
|
+
try:
|
|
139
|
+
fd = os.open(
|
|
140
|
+
str(tmp_path),
|
|
141
|
+
os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
142
|
+
0o600,
|
|
143
|
+
)
|
|
144
|
+
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
|
145
|
+
json.dump(data, f, indent=2)
|
|
146
|
+
f.flush()
|
|
147
|
+
os.fsync(f.fileno())
|
|
148
|
+
os.replace(str(tmp_path), str(file_path))
|
|
149
|
+
with contextlib.suppress(OSError):
|
|
150
|
+
os.chmod(file_path, 0o600)
|
|
151
|
+
except Exception:
|
|
152
|
+
with contextlib.suppress(OSError):
|
|
153
|
+
tmp_path.unlink(missing_ok=True)
|
|
154
|
+
raise
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _load_approval_db() -> dict[str, dict]:
|
|
158
|
+
"""Load the UC approval database from private storage."""
|
|
159
|
+
_ensure_private_dir(_APPROVAL_DIR)
|
|
160
|
+
if not _APPROVAL_FILE.exists():
|
|
161
|
+
return {}
|
|
162
|
+
try:
|
|
163
|
+
with open(_APPROVAL_FILE, encoding="utf-8") as f:
|
|
164
|
+
data = json.load(f)
|
|
165
|
+
if isinstance(data, dict):
|
|
166
|
+
return data
|
|
167
|
+
except json.JSONDecodeError, OSError:
|
|
168
|
+
pass
|
|
169
|
+
return {}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _save_approval_db(db: dict[str, dict]) -> None:
|
|
173
|
+
"""Save the UC approval database to private storage."""
|
|
174
|
+
_ensure_private_dir(_APPROVAL_DIR)
|
|
175
|
+
_atomic_write_private_json(_APPROVAL_FILE, db)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def compute_code_hash(code: str) -> str:
|
|
179
|
+
"""Compute SHA-256 hash of tool source code."""
|
|
180
|
+
return hashlib.sha256(code.encode("utf-8")).hexdigest()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def validate_tool_name(name: str, *, check_reserved: bool = True) -> str | None:
|
|
184
|
+
"""Strictly validate a tool name or namespace segment.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
name: Tool name or namespace segment to validate.
|
|
188
|
+
check_reserved: If True, reject names matching Python stdlib modules.
|
|
189
|
+
Set to False for namespace segments that don't shadow modules
|
|
190
|
+
(e.g., "json" in "json.validate_files" is a namespace, not
|
|
191
|
+
an import target — the tool is invoked as "uc:json.validate_files").
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Error message if invalid, None if valid.
|
|
195
|
+
"""
|
|
196
|
+
if not name:
|
|
197
|
+
return "Tool name cannot be empty"
|
|
198
|
+
if name.startswith(".") or name.startswith("_"):
|
|
199
|
+
return f"Tool name cannot start with '.' or '_': {name}"
|
|
200
|
+
if name.startswith("__") and name.endswith("__"):
|
|
201
|
+
return f"Dunder names are reserved: {name}"
|
|
202
|
+
if "/" in name or "\\" in name or ".." in name:
|
|
203
|
+
return f"Path traversal characters not allowed: {name}"
|
|
204
|
+
if not _VALID_NAME_RE.match(name):
|
|
205
|
+
return f"Invalid tool name '{name}': must match [a-zA-Z_][a-zA-Z0-9_]*"
|
|
206
|
+
if check_reserved and name.lower() in _RESERVED_MODULE_NAMES:
|
|
207
|
+
return f"Tool name '{name}' is a reserved module name"
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def validate_namespace(namespace: str) -> str | None:
|
|
212
|
+
"""Validate a dot-separated namespace.
|
|
213
|
+
|
|
214
|
+
Namespace segments are not checked against reserved module names
|
|
215
|
+
because they don't shadow Python modules — the full tool is invoked
|
|
216
|
+
as "uc:namespace.tool_name", not "import namespace".
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Error message if invalid, None if valid.
|
|
220
|
+
"""
|
|
221
|
+
if not namespace:
|
|
222
|
+
return None
|
|
223
|
+
parts = namespace.split(".")
|
|
224
|
+
for part in parts:
|
|
225
|
+
error = validate_tool_name(part, check_reserved=False)
|
|
226
|
+
if error:
|
|
227
|
+
return error
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def validate_full_tool_name(name: str) -> str | None:
|
|
232
|
+
"""Validate a full tool name possibly including namespace.
|
|
233
|
+
|
|
234
|
+
Reserved module name checks only apply to the final (leaf) segment,
|
|
235
|
+
since namespace segments don't shadow Python modules — a tool named
|
|
236
|
+
"json.validate_files" is invoked as "uc:json.validate_files", not
|
|
237
|
+
"import json".
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Error message if invalid, None if valid.
|
|
241
|
+
"""
|
|
242
|
+
if not name:
|
|
243
|
+
return "Tool name cannot be empty"
|
|
244
|
+
if name.startswith(".") or name.endswith("."):
|
|
245
|
+
return "Tool name cannot start or end with '.'"
|
|
246
|
+
parts = name.split(".")
|
|
247
|
+
last_index = len(parts) - 1
|
|
248
|
+
for i, part in enumerate(parts):
|
|
249
|
+
# Only the final (leaf) segment can shadow a module name;
|
|
250
|
+
# namespace segments like "json" in "json.validate_files"
|
|
251
|
+
# are always accessed via "uc:" prefix, so skip reserved check.
|
|
252
|
+
is_leaf = i == last_index
|
|
253
|
+
error = validate_tool_name(part, check_reserved=is_leaf)
|
|
254
|
+
if error:
|
|
255
|
+
return error
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class SafetyCheckResult:
|
|
260
|
+
"""Result of a UC safety check."""
|
|
261
|
+
|
|
262
|
+
def __init__(
|
|
263
|
+
self,
|
|
264
|
+
safe: bool = True,
|
|
265
|
+
blocked: bool = False,
|
|
266
|
+
requires_approval: bool = False,
|
|
267
|
+
errors: list[str | None] = None,
|
|
268
|
+
warnings: list[str | None] = None,
|
|
269
|
+
code_hash: str | None = None,
|
|
270
|
+
):
|
|
271
|
+
self.safe = safe
|
|
272
|
+
self.blocked = blocked
|
|
273
|
+
self.requires_approval = requires_approval
|
|
274
|
+
self.errors = errors or []
|
|
275
|
+
self.warnings = warnings or []
|
|
276
|
+
self.code_hash = code_hash
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def check_code_safety(code: str) -> SafetyCheckResult:
|
|
280
|
+
"""Perform strict safety analysis on UC tool code.
|
|
281
|
+
|
|
282
|
+
This is a BLOCKING check (not just advisory). Dangerous patterns
|
|
283
|
+
like eval, exec, subprocess, pickle, etc. cause the tool to be
|
|
284
|
+
rejected. Network-library usage requires explicit approval.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
code: Python source code to analyze.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
SafetyCheckResult indicating whether the code is safe,
|
|
291
|
+
blocked, or requires approval.
|
|
292
|
+
"""
|
|
293
|
+
result = SafetyCheckResult(code_hash=compute_code_hash(code))
|
|
294
|
+
|
|
295
|
+
# Parse AST
|
|
296
|
+
try:
|
|
297
|
+
tree = ast.parse(code)
|
|
298
|
+
except SyntaxError as e:
|
|
299
|
+
result.safe = False
|
|
300
|
+
result.errors.append(f"Syntax error: {e}")
|
|
301
|
+
return result
|
|
302
|
+
|
|
303
|
+
dangerous_found: list[str] = []
|
|
304
|
+
approval_required: list[str] = []
|
|
305
|
+
|
|
306
|
+
for node in ast.walk(tree):
|
|
307
|
+
# Check imports
|
|
308
|
+
if isinstance(node, ast.Import):
|
|
309
|
+
for alias in node.names:
|
|
310
|
+
if alias.name in _DANGEROUS_IMPORTS_BLOCK:
|
|
311
|
+
dangerous_found.append(f"import {alias.name}")
|
|
312
|
+
elif alias.name in _DANGEROUS_IMPORTS_APPROVAL:
|
|
313
|
+
approval_required.append(f"import {alias.name}")
|
|
314
|
+
|
|
315
|
+
elif isinstance(node, ast.ImportFrom):
|
|
316
|
+
module = node.module or ""
|
|
317
|
+
for alias in node.names:
|
|
318
|
+
full_name = f"{module}.{alias.name}"
|
|
319
|
+
if (
|
|
320
|
+
module in _DANGEROUS_IMPORTS_BLOCK
|
|
321
|
+
or full_name in _DANGEROUS_IMPORTS_BLOCK
|
|
322
|
+
):
|
|
323
|
+
dangerous_found.append(f"from {module} import {alias.name}")
|
|
324
|
+
elif (
|
|
325
|
+
module in _DANGEROUS_IMPORTS_APPROVAL
|
|
326
|
+
or full_name in _DANGEROUS_IMPORTS_APPROVAL
|
|
327
|
+
):
|
|
328
|
+
approval_required.append(f"from {module} import {alias.name}")
|
|
329
|
+
|
|
330
|
+
# Check function calls
|
|
331
|
+
elif isinstance(node, ast.Call):
|
|
332
|
+
func_name = _get_call_name(node)
|
|
333
|
+
if func_name in _DANGEROUS_CALLS_BLOCK:
|
|
334
|
+
line = getattr(node, "lineno", "?")
|
|
335
|
+
dangerous_found.append(f"{func_name}() call at line {line}")
|
|
336
|
+
elif func_name == "open":
|
|
337
|
+
if _is_dangerous_open_call(node):
|
|
338
|
+
line = getattr(node, "lineno", "?")
|
|
339
|
+
dangerous_found.append(f"open() with write mode at line {line}")
|
|
340
|
+
|
|
341
|
+
if dangerous_found:
|
|
342
|
+
result.blocked = True
|
|
343
|
+
result.safe = False
|
|
344
|
+
result.errors.append(
|
|
345
|
+
f"Blocked dangerous patterns: {', '.join(dangerous_found)}"
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if approval_required and not result.blocked:
|
|
349
|
+
result.requires_approval = True
|
|
350
|
+
result.warnings.append(
|
|
351
|
+
f"Potentially dangerous patterns require approval: {', '.join(approval_required)}"
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
return result
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _get_call_name(node: ast.Call) -> str:
|
|
358
|
+
"""Extract the function name from a Call node."""
|
|
359
|
+
if hasattr(node, "func"):
|
|
360
|
+
if isinstance(node.func, ast.Name):
|
|
361
|
+
return node.func.id
|
|
362
|
+
elif isinstance(node.func, ast.Attribute):
|
|
363
|
+
return node.func.attr
|
|
364
|
+
return ""
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def _is_dangerous_open_call(node: ast.Call) -> bool:
|
|
368
|
+
"""Check if an open() call uses a dangerous (write) mode."""
|
|
369
|
+
if len(node.args) >= 2:
|
|
370
|
+
mode_arg = node.args[1]
|
|
371
|
+
if isinstance(mode_arg, ast.Constant) and isinstance(mode_arg.value, str):
|
|
372
|
+
return mode_arg.value in _DANGEROUS_OPEN_MODES
|
|
373
|
+
for kw in node.keywords:
|
|
374
|
+
if kw.arg == "mode":
|
|
375
|
+
if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str):
|
|
376
|
+
return kw.value.value in _DANGEROUS_OPEN_MODES
|
|
377
|
+
return False
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class UCApprovalStore:
|
|
381
|
+
"""Persistent store for UC tool approvals keyed by code hash."""
|
|
382
|
+
|
|
383
|
+
def __init__(self):
|
|
384
|
+
self._db: dict[str, dict] = {}
|
|
385
|
+
self._loaded = False
|
|
386
|
+
|
|
387
|
+
def _ensure_loaded(self) -> None:
|
|
388
|
+
if not self._loaded:
|
|
389
|
+
self._db = _load_approval_db()
|
|
390
|
+
self._loaded = True
|
|
391
|
+
|
|
392
|
+
def is_approved(self, tool_name: str, code_hash: str) -> bool:
|
|
393
|
+
"""Check whether a specific code hash is approved for a tool."""
|
|
394
|
+
self._ensure_loaded()
|
|
395
|
+
key = f"{tool_name}:{code_hash}"
|
|
396
|
+
entry = self._db.get(key)
|
|
397
|
+
if entry is None:
|
|
398
|
+
return False
|
|
399
|
+
stored_hash = entry.get("code_hash")
|
|
400
|
+
if stored_hash != code_hash:
|
|
401
|
+
return False
|
|
402
|
+
return entry.get("approved", False)
|
|
403
|
+
|
|
404
|
+
def approve(self, tool_name: str, code_hash: str) -> None:
|
|
405
|
+
"""Explicitly approve a tool code hash."""
|
|
406
|
+
self._ensure_loaded()
|
|
407
|
+
key = f"{tool_name}:{code_hash}"
|
|
408
|
+
self._db[key] = {
|
|
409
|
+
"tool_name": tool_name,
|
|
410
|
+
"code_hash": code_hash,
|
|
411
|
+
"approved": True,
|
|
412
|
+
}
|
|
413
|
+
_save_approval_db(self._db)
|
|
414
|
+
logger.info(f"UC tool approved: {tool_name} (hash={code_hash[:16]}...)")
|
|
415
|
+
|
|
416
|
+
def revoke(self, tool_name: str, code_hash: str) -> None:
|
|
417
|
+
"""Revoke approval for a tool code hash."""
|
|
418
|
+
self._ensure_loaded()
|
|
419
|
+
key = f"{tool_name}:{code_hash}"
|
|
420
|
+
if key in self._db:
|
|
421
|
+
del self._db[key]
|
|
422
|
+
_save_approval_db(self._db)
|
|
423
|
+
logger.info(f"UC tool approval revoked: {tool_name}")
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def is_path_within_uc_dir(file_path: Path, uc_dir: Path) -> bool:
|
|
427
|
+
"""Verify that file_path is safely contained within uc_dir.
|
|
428
|
+
|
|
429
|
+
Resolves both paths and checks for symlink escape.
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
True if file_path is within uc_dir, False otherwise.
|
|
433
|
+
"""
|
|
434
|
+
try:
|
|
435
|
+
resolved_file = file_path.resolve()
|
|
436
|
+
resolved_dir = uc_dir.resolve()
|
|
437
|
+
resolved_file.relative_to(resolved_dir)
|
|
438
|
+
return True
|
|
439
|
+
except ValueError, OSError:
|
|
440
|
+
return False
|