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,268 @@
|
|
|
1
|
+
"""Autonomous Memory Pipeline — callback registrations.
|
|
2
|
+
|
|
3
|
+
Wires the memory pipeline into the Fast Puppy runtime:
|
|
4
|
+
- ``startup``: log memory status on boot
|
|
5
|
+
- ``get_model_system_prompt``: inject memory into system prompts
|
|
6
|
+
- ``custom_command`` / ``custom_command_help``: ``/memory`` slash command
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from datetime import UTC
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from code_muse.callbacks import register_callback
|
|
14
|
+
from code_muse.messaging import emit_error, emit_success, emit_warning
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Startup
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _setup_cython_hooks() -> None:
|
|
24
|
+
"""Enable pyximport so .pyx modules compile on-the-fly."""
|
|
25
|
+
try:
|
|
26
|
+
import pyximport
|
|
27
|
+
|
|
28
|
+
pyximport.install(language_level=3, build_in_temp=True, inplace=True)
|
|
29
|
+
import code_muse
|
|
30
|
+
|
|
31
|
+
if code_muse.CYTHON_ENABLED:
|
|
32
|
+
emit_success(
|
|
33
|
+
f"✅ Cython enabled — {code_muse.PYX_MODULE_COUNT} modules compiled"
|
|
34
|
+
)
|
|
35
|
+
else:
|
|
36
|
+
emit_warning("⚠️ Cython not available — running in pure Python mode")
|
|
37
|
+
except Exception:
|
|
38
|
+
emit_warning("⚠️ Cython not available — running in pure Python mode")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _on_startup() -> None:
|
|
42
|
+
"""Attempt to load memory injection (non-blocking)."""
|
|
43
|
+
try:
|
|
44
|
+
from .memory_injection import load_memory_injection
|
|
45
|
+
|
|
46
|
+
memory = load_memory_injection()
|
|
47
|
+
if memory:
|
|
48
|
+
logger.info("Memory injection available on startup")
|
|
49
|
+
else:
|
|
50
|
+
logger.debug("No fresh memory injection found")
|
|
51
|
+
except Exception as exc:
|
|
52
|
+
logger.warning(f"Memory startup check failed: {exc}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Startup
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _inject_memory_into_prompt(
|
|
61
|
+
model_name: str, default_system_prompt: str, user_prompt: str
|
|
62
|
+
) -> dict[str, Any | None]:
|
|
63
|
+
"""Callback to inject memory into system prompt.
|
|
64
|
+
|
|
65
|
+
Returns ``None`` when no memory is available so the prompt is unchanged.
|
|
66
|
+
Returns ``handled: False`` so other prompt-augmenting callbacks can
|
|
67
|
+
also run (e.g. the agent_skills plugin).
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
from .memory_injection import load_memory_injection
|
|
71
|
+
|
|
72
|
+
memory_text = load_memory_injection()
|
|
73
|
+
if not memory_text:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
enhanced = f"{default_system_prompt}\n\n## Memory Guidance\n\n"
|
|
77
|
+
enhanced += (
|
|
78
|
+
"The following is accumulated project knowledge from past sessions.\n"
|
|
79
|
+
"Treat it as heuristic context, not authoritative fact. Always prefer\n"
|
|
80
|
+
"current repo evidence over conflicting memory. Cite the memory path\n"
|
|
81
|
+
"(MEMORY.md) when you use remembered information.\n\n"
|
|
82
|
+
)
|
|
83
|
+
enhanced += memory_text
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
"instructions": enhanced,
|
|
87
|
+
"user_prompt": user_prompt,
|
|
88
|
+
"handled": False,
|
|
89
|
+
}
|
|
90
|
+
except Exception as exc:
|
|
91
|
+
logger.warning(f"Memory prompt injection failed: {exc}")
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# /memory slash command
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _memory_command_help() -> list[tuple[str, str]]:
|
|
101
|
+
return [
|
|
102
|
+
("memory", "Show memory status"),
|
|
103
|
+
("memory extract", "Trigger extraction now"),
|
|
104
|
+
("memory forget", "Clear all memory files"),
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _handle_memory_command(command: str, name: str) -> bool | str | None:
|
|
109
|
+
"""Handle ``/memory`` and its subcommands."""
|
|
110
|
+
if name != "memory":
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
parts = command.strip().split()
|
|
114
|
+
subcommand = parts[1] if len(parts) > 1 else ""
|
|
115
|
+
|
|
116
|
+
if subcommand in ("", "status"):
|
|
117
|
+
return _memory_status()
|
|
118
|
+
|
|
119
|
+
if subcommand == "extract":
|
|
120
|
+
return _memory_extract()
|
|
121
|
+
|
|
122
|
+
if subcommand == "forget":
|
|
123
|
+
return _memory_forget()
|
|
124
|
+
|
|
125
|
+
emit_error(f"Unknown /memory subcommand: {subcommand}")
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _memory_status() -> str:
|
|
130
|
+
"""Display current memory status."""
|
|
131
|
+
try:
|
|
132
|
+
from .session_scanner import (
|
|
133
|
+
get_memory_dir,
|
|
134
|
+
get_project_hash,
|
|
135
|
+
get_sessions_dir,
|
|
136
|
+
scan_eligible_sessions,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
sessions_dir = get_sessions_dir()
|
|
140
|
+
state_file = sessions_dir / ".memory_state.json"
|
|
141
|
+
eligible = scan_eligible_sessions(sessions_dir, state_file)
|
|
142
|
+
|
|
143
|
+
project_hash = get_project_hash()
|
|
144
|
+
memory_dir = get_memory_dir(project_hash)
|
|
145
|
+
memory_path = memory_dir / "MEMORY.md"
|
|
146
|
+
summary_path = memory_dir / "memory_summary.md"
|
|
147
|
+
|
|
148
|
+
lines: list[str] = ["=== Memory Status ==="]
|
|
149
|
+
lines.append(f"Eligible sessions: {len(eligible)}")
|
|
150
|
+
lines.append(f"Memory dir: {memory_dir}")
|
|
151
|
+
lines.append(f"MEMORY.md exists: {memory_path.exists()}")
|
|
152
|
+
lines.append(f"memory_summary.md exists: {summary_path.exists()}")
|
|
153
|
+
|
|
154
|
+
if summary_path.exists():
|
|
155
|
+
mtime = summary_path.stat().st_mtime
|
|
156
|
+
from datetime import datetime
|
|
157
|
+
|
|
158
|
+
dt = datetime.fromtimestamp(mtime, tz=UTC)
|
|
159
|
+
lines.append(f"Last extraction: {dt.isoformat()}")
|
|
160
|
+
|
|
161
|
+
return "\n".join(lines)
|
|
162
|
+
except Exception as exc:
|
|
163
|
+
logger.error(f"Memory status failed: {exc}")
|
|
164
|
+
return f"Memory status error: {exc}"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _memory_extract() -> str:
|
|
168
|
+
"""Run the full extraction pipeline immediately."""
|
|
169
|
+
try:
|
|
170
|
+
from .consolidation import consolidate_memories, write_memory_files
|
|
171
|
+
from .extraction import extract_session_knowledge
|
|
172
|
+
from .lease_lock import acquire_memory_lease, release_lease
|
|
173
|
+
from .secret_scanner import scan_for_secrets
|
|
174
|
+
from .session_scanner import (
|
|
175
|
+
get_memory_dir,
|
|
176
|
+
get_project_hash,
|
|
177
|
+
get_sessions_dir,
|
|
178
|
+
mark_session_processed,
|
|
179
|
+
scan_eligible_sessions,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
sessions_dir = get_sessions_dir()
|
|
183
|
+
state_file = sessions_dir / ".memory_state.json"
|
|
184
|
+
eligible = scan_eligible_sessions(sessions_dir, state_file)
|
|
185
|
+
|
|
186
|
+
if not eligible:
|
|
187
|
+
return "No eligible sessions found for extraction."
|
|
188
|
+
|
|
189
|
+
project_hash = get_project_hash()
|
|
190
|
+
memory_dir = get_memory_dir(project_hash)
|
|
191
|
+
|
|
192
|
+
lease = acquire_memory_lease(memory_dir)
|
|
193
|
+
if lease is None:
|
|
194
|
+
return "Memory pipeline is already running (lease held). Try again later."
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
extractions = []
|
|
198
|
+
for info in eligible:
|
|
199
|
+
result = extract_session_knowledge(info.path)
|
|
200
|
+
if result:
|
|
201
|
+
extractions.append(result)
|
|
202
|
+
mark_session_processed(state_file, str(info.path))
|
|
203
|
+
|
|
204
|
+
if not extractions:
|
|
205
|
+
return "Extraction produced no results."
|
|
206
|
+
|
|
207
|
+
consolidated = consolidate_memories(extractions, sessions_dir)
|
|
208
|
+
|
|
209
|
+
# Safety scan before writing
|
|
210
|
+
secrets = scan_for_secrets(consolidated)
|
|
211
|
+
if secrets:
|
|
212
|
+
secret_names = ", ".join(sorted({s.pattern_name for s in secrets}))
|
|
213
|
+
logger.warning(
|
|
214
|
+
f"Secrets detected in consolidated memory: {secret_names}"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
memory_path, summary_path = write_memory_files(consolidated, memory_dir)
|
|
218
|
+
return (
|
|
219
|
+
f"Extraction complete: {len(extractions)} sessions, "
|
|
220
|
+
f"MEMORY.md → {memory_path}, summary → {summary_path}"
|
|
221
|
+
)
|
|
222
|
+
finally:
|
|
223
|
+
release_lease(lease)
|
|
224
|
+
except Exception as exc:
|
|
225
|
+
logger.error(f"Memory extraction failed: {exc}")
|
|
226
|
+
return f"Extraction error: {exc}"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _memory_forget() -> str:
|
|
230
|
+
"""Remove all memory files for the current project."""
|
|
231
|
+
try:
|
|
232
|
+
from .session_scanner import get_memory_dir, get_project_hash
|
|
233
|
+
|
|
234
|
+
project_hash = get_project_hash()
|
|
235
|
+
memory_dir = get_memory_dir(project_hash)
|
|
236
|
+
|
|
237
|
+
if not memory_dir.exists():
|
|
238
|
+
return "No memory files to forget."
|
|
239
|
+
|
|
240
|
+
deleted: list[str] = []
|
|
241
|
+
for child in memory_dir.iterdir():
|
|
242
|
+
try:
|
|
243
|
+
if child.is_file():
|
|
244
|
+
child.unlink()
|
|
245
|
+
deleted.append(child.name)
|
|
246
|
+
elif child.is_dir():
|
|
247
|
+
# Don't recursively delete; just report
|
|
248
|
+
deleted.append(f"{child.name}/ (skipped)")
|
|
249
|
+
except OSError as exc:
|
|
250
|
+
logger.warning(f"Could not delete {child}: {exc}")
|
|
251
|
+
|
|
252
|
+
return f"Forgot memory files: {', '.join(deleted) or 'none'}"
|
|
253
|
+
except Exception as exc:
|
|
254
|
+
logger.error(f"Memory forget failed: {exc}")
|
|
255
|
+
return f"Forget error: {exc}"
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# ---------------------------------------------------------------------------
|
|
259
|
+
# Register callbacks
|
|
260
|
+
# ---------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
register_callback("startup", _setup_cython_hooks)
|
|
263
|
+
register_callback("startup", _on_startup)
|
|
264
|
+
register_callback("get_model_system_prompt", _inject_memory_into_prompt)
|
|
265
|
+
register_callback("custom_command_help", _memory_command_help)
|
|
266
|
+
register_callback("custom_command", _handle_memory_command)
|
|
267
|
+
|
|
268
|
+
logger.info("Autonomous Memory Pipeline plugin loaded")
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Secret scanner for the Autonomous Memory Pipeline.
|
|
2
|
+
|
|
3
|
+
Detects common secret patterns in extracted memory text before it is
|
|
4
|
+
written to disk, helping prevent accidental credential leakage.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import re
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
SCAN_PATTERNS: list[tuple[str, str]] = [
|
|
14
|
+
("aws_access_key", r"AKIA[0-9A-Z]{16}"),
|
|
15
|
+
("github_token", r"ghp_[0-9a-zA-Z]{36}"),
|
|
16
|
+
("openai_api_key", r"sk-[0-9a-zA-Z]{48}"),
|
|
17
|
+
(
|
|
18
|
+
"private_key_header",
|
|
19
|
+
r"-----BEGIN (RSA|EC|OPENSSH|PGP) PRIVATE KEY-----",
|
|
20
|
+
),
|
|
21
|
+
(
|
|
22
|
+
"jwt_token",
|
|
23
|
+
r"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}",
|
|
24
|
+
),
|
|
25
|
+
(
|
|
26
|
+
"generic_api_key",
|
|
27
|
+
r"(api[_-]?key|apikey|secret|token|password)\s*[:=]\s*['\"]?[A-Za-z0-9+/=]{20,}['\"]?",
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class SecretMatch:
|
|
34
|
+
"""A single secret pattern match."""
|
|
35
|
+
|
|
36
|
+
pattern_name: str
|
|
37
|
+
line_number: int
|
|
38
|
+
context: str
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def scan_for_secrets(text: str) -> list[SecretMatch]:
|
|
42
|
+
"""Scan ``text`` for known secret patterns.
|
|
43
|
+
|
|
44
|
+
Returns a list of :class:`SecretMatch` objects with line numbers and
|
|
45
|
+
a short context snippet (first 40 characters of the match).
|
|
46
|
+
"""
|
|
47
|
+
matches: list[SecretMatch] = []
|
|
48
|
+
lines = text.splitlines()
|
|
49
|
+
|
|
50
|
+
for pattern_name, pattern in SCAN_PATTERNS:
|
|
51
|
+
for line_idx, line in enumerate(lines, start=1):
|
|
52
|
+
for match in re.finditer(pattern, line, re.IGNORECASE):
|
|
53
|
+
context = match.group(0)[:40]
|
|
54
|
+
matches.append(
|
|
55
|
+
SecretMatch(
|
|
56
|
+
pattern_name=pattern_name,
|
|
57
|
+
line_number=line_idx,
|
|
58
|
+
context=context,
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return matches
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Session scanner for the Autonomous Memory Pipeline.
|
|
2
|
+
|
|
3
|
+
Discovers eligible past sessions based on message count, activity status,
|
|
4
|
+
and idle time. Tracks processed sessions via a persistent state file.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import hashlib
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
import time
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
IDLE_THRESHOLD_SECONDS = 10_800 # 3 hours
|
|
19
|
+
ACTIVE_THRESHOLD_SECONDS = 1_800 # 30 minutes
|
|
20
|
+
MIN_MESSAGE_COUNT = 10
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class SessionInfo:
|
|
25
|
+
"""Summary of a discovered session directory."""
|
|
26
|
+
|
|
27
|
+
path: Path
|
|
28
|
+
message_count: int
|
|
29
|
+
last_active: float
|
|
30
|
+
is_active: bool
|
|
31
|
+
processed: bool
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _find_messages_file(session_dir: Path) -> Path | None:
|
|
35
|
+
"""Locate the messages file (messages.json or any .jsonl) in a session dir."""
|
|
36
|
+
candidates = [
|
|
37
|
+
session_dir / "messages.json",
|
|
38
|
+
*session_dir.glob("*.jsonl"),
|
|
39
|
+
]
|
|
40
|
+
for candidate in candidates:
|
|
41
|
+
if candidate.exists():
|
|
42
|
+
return candidate
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _count_user_messages(messages_path: Path) -> int:
|
|
47
|
+
"""Count lines that appear to contain a user message."""
|
|
48
|
+
try:
|
|
49
|
+
with messages_path.open("r", encoding="utf-8") as fh:
|
|
50
|
+
return sum(
|
|
51
|
+
1 for line in fh if '"role": "user"' in line or '"role":"user"' in line
|
|
52
|
+
)
|
|
53
|
+
except Exception as exc:
|
|
54
|
+
logger.warning(f"Failed to count messages in {messages_path}: {exc}")
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _read_state(state_file: Path) -> dict[str, Any]:
|
|
59
|
+
"""Read the processed-sessions state file."""
|
|
60
|
+
if not state_file.exists():
|
|
61
|
+
return {"processed": []}
|
|
62
|
+
try:
|
|
63
|
+
with state_file.open("r", encoding="utf-8") as fh:
|
|
64
|
+
data = json.load(fh)
|
|
65
|
+
if isinstance(data, dict) and isinstance(data.get("processed"), list):
|
|
66
|
+
return data
|
|
67
|
+
except Exception as exc:
|
|
68
|
+
logger.warning(f"Corrupt state file {state_file}: {exc}")
|
|
69
|
+
return {"processed": []}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _write_state(state_file: Path, data: dict[str, Any]) -> None:
|
|
73
|
+
"""Persist the processed-sessions state file."""
|
|
74
|
+
state_file.parent.mkdir(parents=True, exist_ok=True)
|
|
75
|
+
with state_file.open("w", encoding="utf-8") as fh:
|
|
76
|
+
json.dump(data, fh, indent=2)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def scan_eligible_sessions(sessions_dir: Path, state_file: Path) -> list[SessionInfo]:
|
|
80
|
+
"""Scan for sessions that are eligible for memory extraction.
|
|
81
|
+
|
|
82
|
+
Filters:
|
|
83
|
+
- message_count >= 10
|
|
84
|
+
- not currently active
|
|
85
|
+
- idle > 3 hours
|
|
86
|
+
- not already processed
|
|
87
|
+
|
|
88
|
+
Results are sorted by ``last_active`` descending (most recent first).
|
|
89
|
+
"""
|
|
90
|
+
if not sessions_dir.exists():
|
|
91
|
+
return []
|
|
92
|
+
|
|
93
|
+
state = _read_state(state_file)
|
|
94
|
+
processed_paths: set[str] = set(state.get("processed", []))
|
|
95
|
+
now = time.time()
|
|
96
|
+
sessions: list[SessionInfo] = []
|
|
97
|
+
|
|
98
|
+
for entry in sessions_dir.iterdir():
|
|
99
|
+
if not entry.is_dir():
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
messages_file = _find_messages_file(entry)
|
|
103
|
+
if messages_file is None:
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
msg_count = _count_user_messages(messages_file)
|
|
107
|
+
last_active = messages_file.stat().st_mtime
|
|
108
|
+
idle_seconds = now - last_active
|
|
109
|
+
|
|
110
|
+
# Active = has a lock file OR recent mtime (< 30 min)
|
|
111
|
+
lock_file = entry / ".session_lock"
|
|
112
|
+
is_active = lock_file.exists() or idle_seconds < ACTIVE_THRESHOLD_SECONDS
|
|
113
|
+
|
|
114
|
+
session_path_str = str(entry)
|
|
115
|
+
processed = session_path_str in processed_paths
|
|
116
|
+
|
|
117
|
+
if msg_count < MIN_MESSAGE_COUNT:
|
|
118
|
+
continue
|
|
119
|
+
if is_active:
|
|
120
|
+
continue
|
|
121
|
+
if idle_seconds <= IDLE_THRESHOLD_SECONDS:
|
|
122
|
+
continue
|
|
123
|
+
if processed:
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
sessions.append(
|
|
127
|
+
SessionInfo(
|
|
128
|
+
path=entry,
|
|
129
|
+
message_count=msg_count,
|
|
130
|
+
last_active=last_active,
|
|
131
|
+
is_active=is_active,
|
|
132
|
+
processed=processed,
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
sessions.sort(key=lambda s: s.last_active, reverse=True)
|
|
137
|
+
return sessions
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def mark_session_processed(state_file: Path, session_path: str) -> None:
|
|
141
|
+
"""Record a session as processed so it won't be re-scanned."""
|
|
142
|
+
state = _read_state(state_file)
|
|
143
|
+
processed: list[str] = state.get("processed", [])
|
|
144
|
+
if session_path not in processed:
|
|
145
|
+
processed.append(session_path)
|
|
146
|
+
state["processed"] = processed
|
|
147
|
+
_write_state(state_file, state)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_sessions_dir() -> Path:
|
|
151
|
+
"""Return the global sessions storage directory."""
|
|
152
|
+
return Path.home() / ".muse" / "sessions"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def get_memory_dir(project_hash: str) -> Path:
|
|
156
|
+
"""Return the memory storage directory for a given project hash."""
|
|
157
|
+
return Path.home() / ".muse" / "memory" / project_hash
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def get_project_hash(cwd: str | None = None) -> str:
|
|
161
|
+
"""Compute a 12-char project hash from the working directory."""
|
|
162
|
+
cwd = cwd or os.getcwd()
|
|
163
|
+
return hashlib.sha256(cwd.encode()).hexdigest()[:12]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""AWS Bedrock Plugin for Muse.
|
|
2
|
+
|
|
3
|
+
This plugin enables Muse to use Anthropic Claude models hosted on
|
|
4
|
+
AWS Bedrock with standard AWS credential chain authentication (env vars,
|
|
5
|
+
profiles, IAM roles, SSO).
|
|
6
|
+
|
|
7
|
+
Supported models:
|
|
8
|
+
- Claude Opus 4.7 (1M context)
|
|
9
|
+
- Claude Opus 4.6 (1M context)
|
|
10
|
+
- Claude Sonnet 4.6 (1M context)
|
|
11
|
+
- Claude Haiku 4.5 (200K context)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Configuration constants for the AWS Bedrock plugin."""
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from code_muse.config import DATA_DIR
|
|
8
|
+
|
|
9
|
+
ENV_AWS_REGION = "AWS_REGION"
|
|
10
|
+
ENV_AWS_PROFILE = "AWS_PROFILE"
|
|
11
|
+
ENV_BEDROCK_REGION = "BEDROCK_REGION"
|
|
12
|
+
|
|
13
|
+
DEFAULT_REGION = "us-east-1"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@functools.lru_cache(maxsize=1)
|
|
17
|
+
def _detect_region() -> str | None:
|
|
18
|
+
"""Detect region from boto3 session or EC2 instance metadata.
|
|
19
|
+
|
|
20
|
+
Result is cached for the process lifetime: on non-EC2 hosts with no
|
|
21
|
+
AWS config, the IMDS path below incurs two 1-second timeouts, and
|
|
22
|
+
this function is called on every model instantiation.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
import boto3
|
|
26
|
+
|
|
27
|
+
region = boto3.Session().region_name
|
|
28
|
+
if region:
|
|
29
|
+
return region
|
|
30
|
+
except Exception:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
import urllib.request
|
|
35
|
+
|
|
36
|
+
token_req = urllib.request.Request(
|
|
37
|
+
"http://169.254.169.254/latest/api/token",
|
|
38
|
+
method="PUT",
|
|
39
|
+
headers={"X-aws-ec2-metadata-token-ttl-seconds": "30"},
|
|
40
|
+
)
|
|
41
|
+
token = urllib.request.urlopen(token_req, timeout=1).read().decode()
|
|
42
|
+
region_req = urllib.request.Request(
|
|
43
|
+
"http://169.254.169.254/latest/meta-data/placement/region",
|
|
44
|
+
headers={"X-aws-ec2-metadata-token": token},
|
|
45
|
+
)
|
|
46
|
+
return urllib.request.urlopen(region_req, timeout=1).read().decode()
|
|
47
|
+
except Exception:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
MODELS: list[dict] = [
|
|
52
|
+
{
|
|
53
|
+
"base_key": "bedrock-opus-4-7",
|
|
54
|
+
"model_id": "us.anthropic.claude-opus-4-7",
|
|
55
|
+
"context_length": 1000000,
|
|
56
|
+
"variants": ["default", "low", "medium", "high", "xhigh", "max"],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"base_key": "bedrock-opus-4-6",
|
|
60
|
+
"model_id": "us.anthropic.claude-opus-4-6-v1:0",
|
|
61
|
+
"context_length": 1000000,
|
|
62
|
+
"variants": ["default", "low", "medium", "high", "max"],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"base_key": "bedrock-sonnet-4-6",
|
|
66
|
+
"model_id": "us.anthropic.claude-sonnet-4-6-v1:0",
|
|
67
|
+
"context_length": 1000000,
|
|
68
|
+
"variants": ["default", "low", "medium", "high", "max"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"base_key": "bedrock-haiku",
|
|
72
|
+
"model_id": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
73
|
+
"context_length": 200000,
|
|
74
|
+
"variants": None,
|
|
75
|
+
},
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_bedrock_region() -> str:
|
|
80
|
+
"""Get the AWS region for Bedrock.
|
|
81
|
+
|
|
82
|
+
Precedence: BEDROCK_REGION > AWS_REGION > boto3 session > default.
|
|
83
|
+
"""
|
|
84
|
+
return (
|
|
85
|
+
os.environ.get(ENV_BEDROCK_REGION)
|
|
86
|
+
or os.environ.get(ENV_AWS_REGION)
|
|
87
|
+
or _detect_region()
|
|
88
|
+
or DEFAULT_REGION
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_aws_profile() -> str | None:
|
|
93
|
+
"""Get the AWS profile name from environment."""
|
|
94
|
+
return os.environ.get(ENV_AWS_PROFILE)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_extra_models_path() -> Path:
|
|
98
|
+
"""Get the path to the extra_models.json file."""
|
|
99
|
+
return Path(DATA_DIR) / "extra_models.json"
|