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,510 @@
|
|
|
1
|
+
"""Interactive mode loop for Muse."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from code_muse.agents import get_current_agent
|
|
9
|
+
from code_muse.cli_runner.runner import _render_response, run_prompt_with_attachments
|
|
10
|
+
from code_muse.command_line.attachments import parse_prompt_attachments
|
|
11
|
+
from code_muse.command_line.clipboard import get_clipboard_manager
|
|
12
|
+
from code_muse.command_line.command_handler import handle_command
|
|
13
|
+
from code_muse.command_line.shell_passthrough import (
|
|
14
|
+
execute_shell_passthrough,
|
|
15
|
+
is_shell_passthrough,
|
|
16
|
+
)
|
|
17
|
+
from code_muse.command_line.wiggum_state import (
|
|
18
|
+
get_wiggum_prompt,
|
|
19
|
+
increment_wiggum_count,
|
|
20
|
+
is_wiggum_active,
|
|
21
|
+
stop_wiggum,
|
|
22
|
+
)
|
|
23
|
+
from code_muse.config import (
|
|
24
|
+
AUTOSAVE_DIR,
|
|
25
|
+
COMMAND_HISTORY_FILE,
|
|
26
|
+
auto_save_session_if_enabled,
|
|
27
|
+
finalize_autosave_session,
|
|
28
|
+
save_command_to_history,
|
|
29
|
+
)
|
|
30
|
+
from code_muse.keymap import get_cancel_agent_display_name
|
|
31
|
+
from code_muse.messaging import (
|
|
32
|
+
emit_error,
|
|
33
|
+
emit_info,
|
|
34
|
+
emit_success,
|
|
35
|
+
emit_system_message,
|
|
36
|
+
emit_warning,
|
|
37
|
+
)
|
|
38
|
+
from code_muse.terminal_utils import (
|
|
39
|
+
print_truecolor_warning,
|
|
40
|
+
reset_windows_terminal_ansi,
|
|
41
|
+
reset_windows_terminal_full,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _show_startup_info(display_console) -> None:
|
|
46
|
+
"""Display startup messages and terminal capability warnings."""
|
|
47
|
+
emit_system_message(
|
|
48
|
+
"Type '/exit', '/quit', or press Ctrl+D to exit the interactive mode."
|
|
49
|
+
)
|
|
50
|
+
emit_system_message("Type 'clear' to reset the conversation history.")
|
|
51
|
+
emit_system_message("Type /help to view all commands")
|
|
52
|
+
emit_system_message(
|
|
53
|
+
"Type @ for path completion, or /model to pick a model. "
|
|
54
|
+
"Toggle multiline with Alt+M or F2; newline: Ctrl+J."
|
|
55
|
+
)
|
|
56
|
+
emit_system_message("Paste images: Ctrl+V (even on Mac!), F3, or /paste command.")
|
|
57
|
+
import platform
|
|
58
|
+
|
|
59
|
+
if platform.system() == "Darwin":
|
|
60
|
+
emit_system_message(
|
|
61
|
+
"š” macOS tip: Use Ctrl+V (not Cmd+V) to paste images in terminal."
|
|
62
|
+
)
|
|
63
|
+
cancel_key = get_cancel_agent_display_name()
|
|
64
|
+
emit_system_message(
|
|
65
|
+
f"Press {cancel_key} during processing to cancel the current task "
|
|
66
|
+
f"or inference. Use Ctrl+X to interrupt running shell commands."
|
|
67
|
+
)
|
|
68
|
+
emit_system_message(
|
|
69
|
+
"Use /autosave_load to manually load a previous autosave session."
|
|
70
|
+
)
|
|
71
|
+
emit_system_message(
|
|
72
|
+
"Use /diff to configure diff highlighting colors for file changes."
|
|
73
|
+
)
|
|
74
|
+
emit_system_message("To re-run the tutorial, use /tutorial.")
|
|
75
|
+
emit_system_message(
|
|
76
|
+
"!<command> to run shell commands directly (e.g., !git status)",
|
|
77
|
+
)
|
|
78
|
+
# Print truecolor warning LAST so it's the most visible thing on startup
|
|
79
|
+
# Big ugly red box should be impossible to miss! š“
|
|
80
|
+
print_truecolor_warning(display_console)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async def _handle_initial_command(initial_command: str, agent, display_console) -> bool:
|
|
84
|
+
"""Process an initial command passed on the CLI before entering the main loop.
|
|
85
|
+
|
|
86
|
+
Returns True if the initial command was fully handled, False otherwise.
|
|
87
|
+
"""
|
|
88
|
+
if is_shell_passthrough(initial_command):
|
|
89
|
+
execute_shell_passthrough(initial_command)
|
|
90
|
+
return True
|
|
91
|
+
|
|
92
|
+
emit_info(f"Processing initial command: {initial_command}")
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
# Check if any tool is waiting for user input before showing spinner
|
|
96
|
+
try:
|
|
97
|
+
from code_muse.tools.command_runner import is_awaiting_user_input
|
|
98
|
+
|
|
99
|
+
awaiting_input = is_awaiting_user_input()
|
|
100
|
+
except ImportError:
|
|
101
|
+
awaiting_input = False
|
|
102
|
+
|
|
103
|
+
# Run with or without spinner based on whether we're awaiting input
|
|
104
|
+
response, agent_task = await run_prompt_with_attachments(
|
|
105
|
+
agent,
|
|
106
|
+
initial_command,
|
|
107
|
+
spinner_console=display_console,
|
|
108
|
+
use_spinner=not awaiting_input,
|
|
109
|
+
)
|
|
110
|
+
if response is not None:
|
|
111
|
+
agent_response = response.output
|
|
112
|
+
|
|
113
|
+
# Update the agent's message history with the complete conversation
|
|
114
|
+
# including the final assistant response
|
|
115
|
+
if hasattr(response, "all_messages"):
|
|
116
|
+
agent.set_message_history(list(response.all_messages()))
|
|
117
|
+
|
|
118
|
+
# Emit structured message for proper markdown rendering
|
|
119
|
+
from code_muse.messaging import get_message_bus
|
|
120
|
+
from code_muse.messaging.messages import AgentResponseMessage
|
|
121
|
+
|
|
122
|
+
response_msg = AgentResponseMessage(
|
|
123
|
+
content=agent_response,
|
|
124
|
+
is_markdown=True,
|
|
125
|
+
)
|
|
126
|
+
get_message_bus().emit(response_msg)
|
|
127
|
+
|
|
128
|
+
emit_success("Continuing in Interactive Mode")
|
|
129
|
+
emit_system_message(
|
|
130
|
+
"Your command and response are preserved in the conversation history."
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
except Exception as e:
|
|
134
|
+
emit_error(f"Error processing initial command: {str(e)}")
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
return True
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _ensure_prompt_toolkit() -> None:
|
|
141
|
+
"""Ensure prompt_toolkit is installed, installing it if missing."""
|
|
142
|
+
try:
|
|
143
|
+
from code_muse.command_line.prompt_toolkit_completion import (
|
|
144
|
+
get_input_with_combined_completion, # noqa: F401
|
|
145
|
+
get_prompt_with_active_model, # noqa: F401
|
|
146
|
+
)
|
|
147
|
+
except ImportError:
|
|
148
|
+
emit_warning("Warning: prompt_toolkit not installed. Installing now...")
|
|
149
|
+
try:
|
|
150
|
+
import subprocess
|
|
151
|
+
|
|
152
|
+
subprocess.check_call(
|
|
153
|
+
[sys.executable, "-m", "pip", "install", "--quiet", "prompt_toolkit"]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
emit_success("Successfully installed prompt_toolkit")
|
|
157
|
+
except Exception as e:
|
|
158
|
+
emit_error(f"Error installing prompt_toolkit: {e}")
|
|
159
|
+
emit_warning("Falling back to basic input without tab completion")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _maybe_run_onboarding() -> None:
|
|
163
|
+
"""Run the onboarding tutorial on first startup if needed."""
|
|
164
|
+
try:
|
|
165
|
+
from code_muse.command_line.onboarding_wizard import should_show_onboarding
|
|
166
|
+
|
|
167
|
+
if should_show_onboarding():
|
|
168
|
+
import concurrent.futures
|
|
169
|
+
|
|
170
|
+
from code_muse.command_line.onboarding_wizard import run_onboarding_wizard
|
|
171
|
+
from code_muse.config import set_model_name
|
|
172
|
+
|
|
173
|
+
# FREE-THREADED: ThreadPoolExecutor works with free-threaded Python 3.14.
|
|
174
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
175
|
+
future = executor.submit(lambda: asyncio.run(run_onboarding_wizard()))
|
|
176
|
+
result = future.result(timeout=300)
|
|
177
|
+
|
|
178
|
+
if result == "chatgpt":
|
|
179
|
+
emit_info("š Starting ChatGPT OAuth flow...")
|
|
180
|
+
from code_muse.plugins.chatgpt_oauth.oauth_flow import run_oauth_flow
|
|
181
|
+
|
|
182
|
+
run_oauth_flow()
|
|
183
|
+
set_model_name("chatgpt-gpt-5.4")
|
|
184
|
+
elif result == "claude":
|
|
185
|
+
emit_info("š Starting Claude Code OAuth flow...")
|
|
186
|
+
from code_muse.plugins.claude_code_oauth.register_callbacks import (
|
|
187
|
+
_perform_authentication,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
_perform_authentication()
|
|
191
|
+
set_model_name("claude-code-claude-opus-4-7")
|
|
192
|
+
elif result == "completed":
|
|
193
|
+
emit_info("š Tutorial complete! Happy coding!")
|
|
194
|
+
elif result == "skipped":
|
|
195
|
+
emit_info("āļø Tutorial skipped. Run /tutorial anytime!")
|
|
196
|
+
except Exception as e:
|
|
197
|
+
emit_warning(f"Tutorial auto-start failed: {e}")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
async def _read_user_input(message_renderer, display_console) -> str:
|
|
201
|
+
"""Read user input via prompt_toolkit or fallback to basic input."""
|
|
202
|
+
try:
|
|
203
|
+
from code_muse.command_line.prompt_toolkit_completion import (
|
|
204
|
+
get_input_with_combined_completion,
|
|
205
|
+
get_prompt_with_active_model,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
reset_windows_terminal_ansi()
|
|
209
|
+
task = await get_input_with_combined_completion(
|
|
210
|
+
get_prompt_with_active_model(), history_file=COMMAND_HISTORY_FILE
|
|
211
|
+
)
|
|
212
|
+
try:
|
|
213
|
+
from code_muse.terminal_utils import ensure_ctrl_c_disabled
|
|
214
|
+
|
|
215
|
+
ensure_ctrl_c_disabled()
|
|
216
|
+
except ImportError:
|
|
217
|
+
pass
|
|
218
|
+
return task
|
|
219
|
+
except ImportError:
|
|
220
|
+
return input(">>> ")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _handle_keyboard_interrupt(display_console) -> None:
|
|
224
|
+
"""Handle Ctrl+C during input by resetting terminal and stopping wiggum."""
|
|
225
|
+
reset_windows_terminal_full()
|
|
226
|
+
|
|
227
|
+
if is_wiggum_active():
|
|
228
|
+
stop_wiggum()
|
|
229
|
+
emit_warning("\nš© Wiggum loop stopped!")
|
|
230
|
+
else:
|
|
231
|
+
emit_warning("\nInput cancelled")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
async def _cancel_agent_task_if_running(current_agent_task) -> None:
|
|
235
|
+
"""Cancel a running agent task and await its completion."""
|
|
236
|
+
if current_agent_task and not current_agent_task.done():
|
|
237
|
+
emit_info("Cancelling running agent task...")
|
|
238
|
+
current_agent_task.cancel()
|
|
239
|
+
try: # noqa: SIM105
|
|
240
|
+
await current_agent_task
|
|
241
|
+
except asyncio.CancelledError:
|
|
242
|
+
pass
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
async def _handle_eof() -> None:
|
|
246
|
+
"""Handle Ctrl+D by printing goodbye."""
|
|
247
|
+
emit_success("\nGoodbye! (Ctrl+D)")
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _is_shell_passthrough_and_execute(task: str) -> bool:
|
|
251
|
+
"""If the task is a shell passthrough, execute it and return True."""
|
|
252
|
+
|
|
253
|
+
if is_shell_passthrough(task):
|
|
254
|
+
execute_shell_passthrough(task)
|
|
255
|
+
return True
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
async def _is_exit_command(task: str) -> bool:
|
|
260
|
+
"""Check for exit commands and return True if exiting."""
|
|
261
|
+
if task.strip().lower() in ["exit", "quit"] or task.strip().lower() in [
|
|
262
|
+
"/exit",
|
|
263
|
+
"/quit",
|
|
264
|
+
]:
|
|
265
|
+
emit_success("Goodbye!")
|
|
266
|
+
return True
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _is_clear_command(task: str) -> bool:
|
|
271
|
+
"""Check for clear commands, rotate session and clear history if matched."""
|
|
272
|
+
if task.strip().lower() in ("clear", "/clear"):
|
|
273
|
+
agent = get_current_agent()
|
|
274
|
+
new_session_id = finalize_autosave_session()
|
|
275
|
+
agent.clear_message_history()
|
|
276
|
+
emit_warning("Conversation history cleared!")
|
|
277
|
+
emit_system_message("The agent will not remember previous interactions.")
|
|
278
|
+
emit_info(f"Auto-save session rotated to: {new_session_id}")
|
|
279
|
+
clipboard_manager = get_clipboard_manager()
|
|
280
|
+
clipboard_count = clipboard_manager.get_pending_count()
|
|
281
|
+
clipboard_manager.clear_pending()
|
|
282
|
+
if clipboard_count > 0:
|
|
283
|
+
emit_info(f"Cleared {clipboard_count} pending clipboard image(s)")
|
|
284
|
+
return True
|
|
285
|
+
return False
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
async def _handle_slash_command(cleaned: str):
|
|
289
|
+
"""Route a slash command and return a sentinel or the prompt to execute."""
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
command_result = handle_command(cleaned)
|
|
293
|
+
except Exception as e:
|
|
294
|
+
emit_error(f"Command error: {e}")
|
|
295
|
+
return "__CONTINUE__"
|
|
296
|
+
if command_result is True:
|
|
297
|
+
return "__CONTINUE__"
|
|
298
|
+
elif isinstance(command_result, str):
|
|
299
|
+
if command_result == "__AUTOSAVE_LOAD__":
|
|
300
|
+
try:
|
|
301
|
+
use_interactive_picker = sys.stdin.isatty() and sys.stdout.isatty()
|
|
302
|
+
if os.getenv("MUSE_NO_TUI") == "1":
|
|
303
|
+
use_interactive_picker = False
|
|
304
|
+
if use_interactive_picker:
|
|
305
|
+
from code_muse.command_line.autosave_menu import (
|
|
306
|
+
interactive_autosave_picker,
|
|
307
|
+
)
|
|
308
|
+
from code_muse.config import set_current_autosave_from_session_name
|
|
309
|
+
from code_muse.session_storage import (
|
|
310
|
+
load_session,
|
|
311
|
+
restore_autosave_interactively,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
chosen_session = await interactive_autosave_picker()
|
|
315
|
+
if not chosen_session:
|
|
316
|
+
emit_warning("Autosave load cancelled")
|
|
317
|
+
return "__CONTINUE__"
|
|
318
|
+
base_dir = Path(AUTOSAVE_DIR)
|
|
319
|
+
history = load_session(chosen_session, base_dir)
|
|
320
|
+
agent = get_current_agent()
|
|
321
|
+
agent.set_message_history(history)
|
|
322
|
+
set_current_autosave_from_session_name(chosen_session)
|
|
323
|
+
total_tokens = sum(
|
|
324
|
+
agent.estimate_tokens_for_message(msg) for msg in history
|
|
325
|
+
)
|
|
326
|
+
session_path = base_dir / f"{chosen_session}.json"
|
|
327
|
+
emit_success(
|
|
328
|
+
f"ā
Autosave loaded: {len(history)} messages "
|
|
329
|
+
f"({total_tokens} tokens)\nš From: {session_path}"
|
|
330
|
+
)
|
|
331
|
+
from code_muse.command_line.autosave_menu import (
|
|
332
|
+
display_resumed_history,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
display_resumed_history(history)
|
|
336
|
+
else:
|
|
337
|
+
await restore_autosave_interactively(Path(AUTOSAVE_DIR))
|
|
338
|
+
except Exception as e:
|
|
339
|
+
emit_error(f"Failed to load autosave: {e}")
|
|
340
|
+
return "__CONTINUE__"
|
|
341
|
+
else:
|
|
342
|
+
return command_result
|
|
343
|
+
elif command_result is False:
|
|
344
|
+
return None
|
|
345
|
+
return None
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
async def _run_main_input_loop(message_renderer, display_console):
|
|
349
|
+
"""Gather and process user input until a non-command task is ready."""
|
|
350
|
+
while True:
|
|
351
|
+
current_agent = get_current_agent()
|
|
352
|
+
user_prompt = current_agent.get_user_prompt() or "Enter your coding task:"
|
|
353
|
+
emit_info(f"{user_prompt}\n")
|
|
354
|
+
|
|
355
|
+
try:
|
|
356
|
+
task = await _read_user_input(message_renderer, display_console)
|
|
357
|
+
except KeyboardInterrupt, asyncio.CancelledError:
|
|
358
|
+
_handle_keyboard_interrupt(display_console)
|
|
359
|
+
continue
|
|
360
|
+
except EOFError:
|
|
361
|
+
await _handle_eof()
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
if _is_shell_passthrough_and_execute(task):
|
|
365
|
+
continue
|
|
366
|
+
if await _is_exit_command(task):
|
|
367
|
+
return None
|
|
368
|
+
if _is_clear_command(task):
|
|
369
|
+
continue
|
|
370
|
+
|
|
371
|
+
processed = parse_prompt_attachments(task)
|
|
372
|
+
cleaned = (processed.prompt or "").strip()
|
|
373
|
+
if cleaned.startswith("/"):
|
|
374
|
+
action = await _handle_slash_command(cleaned)
|
|
375
|
+
if action == "__CONTINUE__":
|
|
376
|
+
continue
|
|
377
|
+
if isinstance(action, str):
|
|
378
|
+
task = action
|
|
379
|
+
|
|
380
|
+
if task.strip():
|
|
381
|
+
save_command_to_history(task)
|
|
382
|
+
return task
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def _handle_agent_cancellation(display_console) -> None:
|
|
386
|
+
"""Reset terminal state after an agent task is cancelled."""
|
|
387
|
+
reset_windows_terminal_ansi()
|
|
388
|
+
try:
|
|
389
|
+
from code_muse.terminal_utils import ensure_ctrl_c_disabled
|
|
390
|
+
|
|
391
|
+
ensure_ctrl_c_disabled()
|
|
392
|
+
except ImportError:
|
|
393
|
+
pass
|
|
394
|
+
|
|
395
|
+
if is_wiggum_active():
|
|
396
|
+
stop_wiggum()
|
|
397
|
+
emit_warning("š© Wiggum loop stopped due to cancellation")
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
async def _render_and_autosave(result, current_agent, display_console) -> None:
|
|
401
|
+
"""Render agent response and autosave session."""
|
|
402
|
+
_render_response(result, current_agent, display_console)
|
|
403
|
+
# Brief pause to ensure all messages are rendered
|
|
404
|
+
await asyncio.sleep(0.1)
|
|
405
|
+
auto_save_session_if_enabled()
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
async def _wiggum_loop(current_agent, message_renderer, display_console):
|
|
409
|
+
"""Run the wiggum re-loop until it completes or is cancelled.
|
|
410
|
+
|
|
411
|
+
Returns the current agent after the wiggum loop completes.
|
|
412
|
+
"""
|
|
413
|
+
while is_wiggum_active():
|
|
414
|
+
wiggum_prompt = get_wiggum_prompt()
|
|
415
|
+
if not wiggum_prompt:
|
|
416
|
+
stop_wiggum()
|
|
417
|
+
break
|
|
418
|
+
|
|
419
|
+
loop_num = increment_wiggum_count()
|
|
420
|
+
emit_warning(f"\nš© WIGGUM RELOOPING! (Loop #{loop_num})")
|
|
421
|
+
emit_system_message(f"Re-running prompt: {wiggum_prompt}")
|
|
422
|
+
|
|
423
|
+
new_session_id = finalize_autosave_session()
|
|
424
|
+
current_agent.clear_message_history()
|
|
425
|
+
emit_system_message(f"Context cleared. Session rotated to: {new_session_id}")
|
|
426
|
+
|
|
427
|
+
await asyncio.sleep(0.5)
|
|
428
|
+
|
|
429
|
+
try:
|
|
430
|
+
result, _ = await run_prompt_with_attachments(
|
|
431
|
+
current_agent,
|
|
432
|
+
wiggum_prompt,
|
|
433
|
+
spinner_console=message_renderer.console,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
if result is None:
|
|
437
|
+
emit_warning("Wiggum loop cancelled by user")
|
|
438
|
+
stop_wiggum()
|
|
439
|
+
break
|
|
440
|
+
|
|
441
|
+
await _render_and_autosave(result, current_agent, display_console)
|
|
442
|
+
|
|
443
|
+
except KeyboardInterrupt:
|
|
444
|
+
emit_warning("\nš© Wiggum loop interrupted by Ctrl+C")
|
|
445
|
+
stop_wiggum()
|
|
446
|
+
break
|
|
447
|
+
except Exception as e:
|
|
448
|
+
emit_error(f"Wiggum loop error: {e}")
|
|
449
|
+
stop_wiggum()
|
|
450
|
+
break
|
|
451
|
+
|
|
452
|
+
return current_agent
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
async def interactive_mode(message_renderer, initial_command: str = None) -> None:
|
|
456
|
+
"""Run the agent in interactive mode."""
|
|
457
|
+
|
|
458
|
+
display_console = message_renderer.console
|
|
459
|
+
current_agent = get_current_agent()
|
|
460
|
+
|
|
461
|
+
_show_startup_info(display_console)
|
|
462
|
+
|
|
463
|
+
if initial_command:
|
|
464
|
+
await _handle_initial_command(initial_command, current_agent, display_console)
|
|
465
|
+
|
|
466
|
+
_ensure_prompt_toolkit()
|
|
467
|
+
|
|
468
|
+
# Autosave loading is now manual - use /autosave_load command
|
|
469
|
+
|
|
470
|
+
_maybe_run_onboarding()
|
|
471
|
+
|
|
472
|
+
# Track the current agent task for cancellation on quit
|
|
473
|
+
current_agent_task = None
|
|
474
|
+
|
|
475
|
+
while True:
|
|
476
|
+
task = await _run_main_input_loop(message_renderer, display_console)
|
|
477
|
+
if task is None:
|
|
478
|
+
await _cancel_agent_task_if_running(current_agent_task)
|
|
479
|
+
break
|
|
480
|
+
|
|
481
|
+
current_agent = get_current_agent()
|
|
482
|
+
|
|
483
|
+
try:
|
|
484
|
+
result, current_agent_task = await run_prompt_with_attachments(
|
|
485
|
+
current_agent,
|
|
486
|
+
task,
|
|
487
|
+
spinner_console=message_renderer.console,
|
|
488
|
+
)
|
|
489
|
+
if result is None:
|
|
490
|
+
_handle_agent_cancellation(display_console)
|
|
491
|
+
continue
|
|
492
|
+
await _render_and_autosave(result, current_agent, display_console)
|
|
493
|
+
except Exception:
|
|
494
|
+
from code_muse.messaging.queue_console import get_queue_console
|
|
495
|
+
|
|
496
|
+
get_queue_console().print_exception()
|
|
497
|
+
auto_save_session_if_enabled()
|
|
498
|
+
|
|
499
|
+
current_agent = await _wiggum_loop(
|
|
500
|
+
current_agent, message_renderer, display_console
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
# Re-disable Ctrl+C if needed (uvx mode) - must be done after
|
|
504
|
+
# each iteration as various operations may restore console mode
|
|
505
|
+
try:
|
|
506
|
+
from code_muse.terminal_utils import ensure_ctrl_c_disabled
|
|
507
|
+
|
|
508
|
+
ensure_ctrl_c_disabled()
|
|
509
|
+
except ImportError:
|
|
510
|
+
pass
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Resume session logic for Muse."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from code_muse.agents import get_current_agent
|
|
7
|
+
from code_muse.messaging import emit_error, emit_success, emit_warning
|
|
8
|
+
from code_muse.session_storage import load_session
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _resume_session_from_path(raw_path: str, *, allow_legacy: bool = False) -> None:
|
|
12
|
+
"""Restore agent message history from a saved session file.
|
|
13
|
+
|
|
14
|
+
Accepts any path (autosaves, contexts, somewhere weird on disk). We don't
|
|
15
|
+
care where it lives ā we just decompose into (parent_dir, stem) and reuse
|
|
16
|
+
``session_storage.load_session`` so we stay DRY.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
session_path = Path(raw_path).expanduser().resolve()
|
|
20
|
+
|
|
21
|
+
if not session_path.exists():
|
|
22
|
+
emit_error(f"--resume: session file not found: {session_path}")
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
25
|
+
if session_path.suffix == ".json":
|
|
26
|
+
pass # preferred format
|
|
27
|
+
elif session_path.suffix == ".pkl":
|
|
28
|
+
if not allow_legacy:
|
|
29
|
+
emit_error(
|
|
30
|
+
f"--resume: legacy pickle sessions are blocked by default. "
|
|
31
|
+
f"Use --import-legacy-pickle-session if you "
|
|
32
|
+
f"really need to load {session_path}"
|
|
33
|
+
)
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
emit_warning(
|
|
36
|
+
"DANGER: loading legacy pickle session ā this can execute arbitrary code!"
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
emit_error(
|
|
40
|
+
f"--resume: expected a .json session file, "
|
|
41
|
+
f"got '{session_path.suffix}': {session_path}"
|
|
42
|
+
)
|
|
43
|
+
sys.exit(1)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
history = load_session(
|
|
47
|
+
session_path.stem, session_path.parent, allow_legacy=allow_legacy
|
|
48
|
+
)
|
|
49
|
+
except Exception as exc:
|
|
50
|
+
emit_error(f"--resume: failed to load session: {exc}")
|
|
51
|
+
sys.exit(1)
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
agent = get_current_agent()
|
|
55
|
+
agent.set_message_history(history)
|
|
56
|
+
except Exception as exc:
|
|
57
|
+
emit_error(f"--resume: failed to attach history to agent: {exc}")
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
|
|
60
|
+
# Rotate autosave id so we don't clobber the original file we just resumed.
|
|
61
|
+
try:
|
|
62
|
+
from code_muse.config import rotate_autosave_id
|
|
63
|
+
|
|
64
|
+
rotate_autosave_id()
|
|
65
|
+
except Exception:
|
|
66
|
+
pass # autosave rotation is best-effort
|
|
67
|
+
|
|
68
|
+
total_tokens = sum(agent.estimate_tokens_for_message(m) for m in history)
|
|
69
|
+
emit_success(
|
|
70
|
+
f"ā
Resumed session: {len(history)} messages ({total_tokens} tokens)\n"
|
|
71
|
+
f"š From: {session_path}"
|
|
72
|
+
)
|