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,277 @@
|
|
|
1
|
+
"""Register slash commands and startup hook for the token-tracking plugin.
|
|
2
|
+
|
|
3
|
+
Commands:
|
|
4
|
+
/tracking gain [today|week|month|all]
|
|
5
|
+
/tracking cc-economics [today|week|month|all]
|
|
6
|
+
/tracking session [N]
|
|
7
|
+
/tracking edit-efficiency [today|week|month|all]
|
|
8
|
+
/tracking help
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from code_muse.callbacks import register_callback
|
|
15
|
+
from code_muse.config import get_current_autosave_id
|
|
16
|
+
from code_muse.messaging import emit_info
|
|
17
|
+
from code_muse.plugins.token_tracking.database import TrackingDatabase, get_tracking_db
|
|
18
|
+
from code_muse.plugins.token_tracking.edit_analyzer import analyze_replacement
|
|
19
|
+
from code_muse.plugins.token_tracking.reports import (
|
|
20
|
+
cc_economics_report,
|
|
21
|
+
edit_efficiency_report,
|
|
22
|
+
gain_report,
|
|
23
|
+
session_report,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_db() -> TrackingDatabase:
|
|
30
|
+
"""Return the shared ``TrackingDatabase`` instance."""
|
|
31
|
+
return get_tracking_db()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ------------------------------------------------------------------
|
|
35
|
+
# Startup hook
|
|
36
|
+
# ------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _on_startup() -> None:
|
|
40
|
+
"""Run database cleanup on application startup."""
|
|
41
|
+
try:
|
|
42
|
+
db = _get_db()
|
|
43
|
+
removed = db.cleanup()
|
|
44
|
+
logger.debug("Token tracking startup cleanup removed %s rows", removed)
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ------------------------------------------------------------------
|
|
50
|
+
# Post-tool-call hook (edit efficiency tracking)
|
|
51
|
+
# ------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _on_post_tool_call(
|
|
55
|
+
tool_name: str,
|
|
56
|
+
tool_args: dict[str, Any],
|
|
57
|
+
result: Any,
|
|
58
|
+
duration_ms: float,
|
|
59
|
+
context: Any = None,
|
|
60
|
+
) -> Any:
|
|
61
|
+
"""Intercept file-edit tools to measure context inflation.
|
|
62
|
+
|
|
63
|
+
Analyses ``create_file``, ``replace_in_file``, and ``delete_snippet``
|
|
64
|
+
calls, stores byte-level metrics, and returns *None* so the tool
|
|
65
|
+
result is left untouched.
|
|
66
|
+
"""
|
|
67
|
+
if tool_name not in ("create_file", "replace_in_file", "delete_snippet"):
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
file_path = tool_args.get("file_path", "")
|
|
72
|
+
success = True
|
|
73
|
+
if isinstance(result, dict) and result.get("error"):
|
|
74
|
+
success = False
|
|
75
|
+
|
|
76
|
+
if tool_name == "create_file":
|
|
77
|
+
old_text = ""
|
|
78
|
+
new_text = tool_args.get("content", "")
|
|
79
|
+
_store_edit_analysis(tool_name, file_path, old_text, new_text, success)
|
|
80
|
+
|
|
81
|
+
elif tool_name == "delete_snippet":
|
|
82
|
+
old_text = tool_args.get("snippet", "")
|
|
83
|
+
new_text = ""
|
|
84
|
+
_store_edit_analysis(tool_name, file_path, old_text, new_text, success)
|
|
85
|
+
|
|
86
|
+
elif tool_name == "replace_in_file":
|
|
87
|
+
replacements = tool_args.get("replacements", [])
|
|
88
|
+
if not replacements:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
# Aggregate across all replacements in this call (Pi style)
|
|
92
|
+
totals: dict[str, int] = {
|
|
93
|
+
"old_bytes": 0,
|
|
94
|
+
"new_bytes": 0,
|
|
95
|
+
"total_edit_bytes": 0,
|
|
96
|
+
"shared_prefix_bytes": 0,
|
|
97
|
+
"shared_suffix_bytes": 0,
|
|
98
|
+
"shared_context_bytes": 0,
|
|
99
|
+
"core_old_bytes": 0,
|
|
100
|
+
"core_new_bytes": 0,
|
|
101
|
+
"core_bytes": 0,
|
|
102
|
+
"wrapper_payload_bytes": 0,
|
|
103
|
+
}
|
|
104
|
+
has_core_change = False
|
|
105
|
+
total_core = 0
|
|
106
|
+
total_edit = 0
|
|
107
|
+
|
|
108
|
+
for rep in replacements:
|
|
109
|
+
old_text = rep.get("old_text", "")
|
|
110
|
+
new_text = rep.get("new_text", "")
|
|
111
|
+
analysis = analyze_replacement(old_text, new_text)
|
|
112
|
+
|
|
113
|
+
for key in totals:
|
|
114
|
+
totals[key] += analysis[key]
|
|
115
|
+
|
|
116
|
+
if not analysis["no_core_change"]:
|
|
117
|
+
has_core_change = True
|
|
118
|
+
total_core += analysis["core_bytes"]
|
|
119
|
+
total_edit += analysis["total_edit_bytes"]
|
|
120
|
+
|
|
121
|
+
no_core_change = not has_core_change
|
|
122
|
+
inflation_ratio = (
|
|
123
|
+
None
|
|
124
|
+
if no_core_change
|
|
125
|
+
else (total_edit / total_core if total_core else None)
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
db = _get_db()
|
|
129
|
+
db.insert_edit_analysis(
|
|
130
|
+
tool_name=tool_name,
|
|
131
|
+
file_path=file_path,
|
|
132
|
+
old_bytes=totals["old_bytes"],
|
|
133
|
+
new_bytes=totals["new_bytes"],
|
|
134
|
+
total_edit_bytes=totals["total_edit_bytes"],
|
|
135
|
+
shared_prefix_bytes=totals["shared_prefix_bytes"],
|
|
136
|
+
shared_suffix_bytes=totals["shared_suffix_bytes"],
|
|
137
|
+
shared_context_bytes=totals["shared_context_bytes"],
|
|
138
|
+
core_old_bytes=totals["core_old_bytes"],
|
|
139
|
+
core_new_bytes=totals["core_new_bytes"],
|
|
140
|
+
core_bytes=totals["core_bytes"],
|
|
141
|
+
wrapper_payload_bytes=totals["wrapper_payload_bytes"],
|
|
142
|
+
inflation_ratio=inflation_ratio,
|
|
143
|
+
no_core_change=no_core_change,
|
|
144
|
+
success=success,
|
|
145
|
+
session_id=get_current_autosave_id(),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
except Exception:
|
|
149
|
+
logger.debug("Edit efficiency tracking failed for %s", tool_name, exc_info=True)
|
|
150
|
+
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _store_edit_analysis(
|
|
155
|
+
tool_name: str,
|
|
156
|
+
file_path: str,
|
|
157
|
+
old_text: str,
|
|
158
|
+
new_text: str,
|
|
159
|
+
success: bool,
|
|
160
|
+
) -> None:
|
|
161
|
+
"""Analyze a single replacement and store it in the database."""
|
|
162
|
+
analysis = analyze_replacement(old_text, new_text)
|
|
163
|
+
db = _get_db()
|
|
164
|
+
db.insert_edit_analysis(
|
|
165
|
+
tool_name=tool_name,
|
|
166
|
+
file_path=file_path,
|
|
167
|
+
old_bytes=analysis["old_bytes"],
|
|
168
|
+
new_bytes=analysis["new_bytes"],
|
|
169
|
+
total_edit_bytes=analysis["total_edit_bytes"],
|
|
170
|
+
shared_prefix_bytes=analysis["shared_prefix_bytes"],
|
|
171
|
+
shared_suffix_bytes=analysis["shared_suffix_bytes"],
|
|
172
|
+
shared_context_bytes=analysis["shared_context_bytes"],
|
|
173
|
+
core_old_bytes=analysis["core_old_bytes"],
|
|
174
|
+
core_new_bytes=analysis["core_new_bytes"],
|
|
175
|
+
core_bytes=analysis["core_bytes"],
|
|
176
|
+
wrapper_payload_bytes=analysis["wrapper_payload_bytes"],
|
|
177
|
+
inflation_ratio=analysis["inflation_ratio"],
|
|
178
|
+
no_core_change=analysis["no_core_change"],
|
|
179
|
+
success=success,
|
|
180
|
+
session_id=get_current_autosave_id(),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# ------------------------------------------------------------------
|
|
185
|
+
# Help
|
|
186
|
+
# ------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _on_custom_command_help() -> list[tuple[str, str]]:
|
|
190
|
+
"""Provide help entries for /help display."""
|
|
191
|
+
return [
|
|
192
|
+
("tracking gain [time]", "Token savings report (today/week/month/all)"),
|
|
193
|
+
("tracking cc-economics [time]", "Estimated Claude Code dollar savings"),
|
|
194
|
+
("tracking session [N]", "Per-session adoption stats (default 10)"),
|
|
195
|
+
(
|
|
196
|
+
"tracking edit-efficiency [time]",
|
|
197
|
+
"Edit context-inflation / efficiency report",
|
|
198
|
+
),
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# ------------------------------------------------------------------
|
|
203
|
+
# Slash-command handler
|
|
204
|
+
# ------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
async def _on_custom_command(command: str, name: str) -> bool | None:
|
|
208
|
+
"""Handle ``/tracking …`` slash commands.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
command: Full command string (e.g. ``/tracking gain week``).
|
|
212
|
+
name: First token after the slash (always ``tracking`` here).
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
``True`` if handled, ``None`` if not a tracking command.
|
|
216
|
+
"""
|
|
217
|
+
if name != "tracking":
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
tokens = command.strip().split()
|
|
221
|
+
subcommand = tokens[1] if len(tokens) > 1 else "help"
|
|
222
|
+
arg = tokens[2] if len(tokens) > 2 else None
|
|
223
|
+
|
|
224
|
+
db = _get_db()
|
|
225
|
+
|
|
226
|
+
if subcommand in ("help",):
|
|
227
|
+
emit_info(
|
|
228
|
+
"Available /tracking commands:\n"
|
|
229
|
+
" /tracking gain [today|week|month|all]\n"
|
|
230
|
+
" /tracking cc-economics [today|week|month|all]\n"
|
|
231
|
+
" /tracking session [N]\n"
|
|
232
|
+
" /tracking help"
|
|
233
|
+
)
|
|
234
|
+
return True
|
|
235
|
+
|
|
236
|
+
if subcommand == "gain":
|
|
237
|
+
time_range = arg or "all"
|
|
238
|
+
report = gain_report(db, time_range)
|
|
239
|
+
emit_info(report)
|
|
240
|
+
return True
|
|
241
|
+
|
|
242
|
+
if subcommand == "cc-economics":
|
|
243
|
+
time_range = arg or "all"
|
|
244
|
+
report = cc_economics_report(db, time_range)
|
|
245
|
+
emit_info(report)
|
|
246
|
+
return True
|
|
247
|
+
|
|
248
|
+
if subcommand == "session":
|
|
249
|
+
limit = int(arg) if arg is not None and arg.isdigit() else 10
|
|
250
|
+
report = session_report(db, limit)
|
|
251
|
+
emit_info(report)
|
|
252
|
+
return True
|
|
253
|
+
|
|
254
|
+
if subcommand == "edit-efficiency":
|
|
255
|
+
time_range = arg or "all"
|
|
256
|
+
report = edit_efficiency_report(db, time_range)
|
|
257
|
+
emit_info(report)
|
|
258
|
+
return True
|
|
259
|
+
|
|
260
|
+
# Unknown subcommand — still consumed by this plugin
|
|
261
|
+
emit_info(
|
|
262
|
+
f"Unknown /tracking subcommand: {subcommand}\n"
|
|
263
|
+
"Try /tracking help for available commands."
|
|
264
|
+
)
|
|
265
|
+
return True
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# ------------------------------------------------------------------
|
|
269
|
+
# Register
|
|
270
|
+
# ------------------------------------------------------------------
|
|
271
|
+
|
|
272
|
+
register_callback("startup", _on_startup)
|
|
273
|
+
register_callback("custom_command_help", _on_custom_command_help)
|
|
274
|
+
register_callback("custom_command", _on_custom_command)
|
|
275
|
+
register_callback("post_tool_call", _on_post_tool_call)
|
|
276
|
+
|
|
277
|
+
logger.debug("Token Tracking plugin callbacks registered")
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"""Query and formatting functions for token tracking reports.
|
|
2
|
+
|
|
3
|
+
Provides ``gain_report``, ``cc_economics_report``, and ``session_report``.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from code_muse.plugins.token_tracking.database import TrackingDatabase
|
|
7
|
+
|
|
8
|
+
# ------------------------------------------------------------------
|
|
9
|
+
# Time-range helpers
|
|
10
|
+
# ------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
_TIME_RANGE_SQL = {
|
|
13
|
+
"today": "date(timestamp) = date('now')",
|
|
14
|
+
"week": "timestamp >= datetime('now', '-7 days')",
|
|
15
|
+
"month": "timestamp >= datetime('now', '-30 days')",
|
|
16
|
+
"all": "1=1",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _time_filter(time_range: str) -> str:
|
|
21
|
+
"""Return a SQLite WHERE clause fragment for the given range."""
|
|
22
|
+
return _TIME_RANGE_SQL.get(time_range, "1=1")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ------------------------------------------------------------------
|
|
26
|
+
# Cost estimation
|
|
27
|
+
# ------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _estimate_tokens_to_cost(input_tokens: int, output_tokens: int = 0) -> float:
|
|
31
|
+
"""Estimate Claude 3.5 Sonnet cost in USD.
|
|
32
|
+
|
|
33
|
+
Pricing:
|
|
34
|
+
* $3 / 1M input tokens
|
|
35
|
+
* $15 / 1M output tokens
|
|
36
|
+
"""
|
|
37
|
+
input_cost = input_tokens * 3.0 / 1_000_000
|
|
38
|
+
output_cost = output_tokens * 15.0 / 1_000_000
|
|
39
|
+
return input_cost + output_cost
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ------------------------------------------------------------------
|
|
43
|
+
# Reports
|
|
44
|
+
# ------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def gain_report(db: TrackingDatabase, time_range: str = "all") -> str:
|
|
48
|
+
"""Format a token-savings report.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
db: A ``TrackingDatabase`` instance.
|
|
52
|
+
time_range: One of ``today``, ``week``, ``month``, ``all``.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Multi-line string suitable for display in the UI.
|
|
56
|
+
"""
|
|
57
|
+
where = _time_filter(time_range)
|
|
58
|
+
|
|
59
|
+
row = db.query_one(
|
|
60
|
+
f"""
|
|
61
|
+
SELECT
|
|
62
|
+
COALESCE(SUM(raw_tokens), 0),
|
|
63
|
+
COALESCE(SUM(compressed_tokens), 0),
|
|
64
|
+
COUNT(*)
|
|
65
|
+
FROM executions
|
|
66
|
+
WHERE {where}
|
|
67
|
+
"""
|
|
68
|
+
)
|
|
69
|
+
total_raw, total_compressed, total_commands = row or (0, 0, 0)
|
|
70
|
+
total_raw = int(total_raw)
|
|
71
|
+
total_compressed = int(total_compressed)
|
|
72
|
+
total_commands = int(total_commands)
|
|
73
|
+
|
|
74
|
+
saved = total_raw - total_compressed
|
|
75
|
+
savings_pct = (saved / max(total_raw, 1) * 100.0) if total_raw else 0.0
|
|
76
|
+
|
|
77
|
+
top_strategies = db.query_all(
|
|
78
|
+
f"""
|
|
79
|
+
SELECT
|
|
80
|
+
strategy,
|
|
81
|
+
COUNT(*) AS cmd_count,
|
|
82
|
+
COALESCE(SUM(raw_tokens - compressed_tokens), 0) AS saved_tokens
|
|
83
|
+
FROM executions
|
|
84
|
+
WHERE {where}
|
|
85
|
+
GROUP BY strategy
|
|
86
|
+
ORDER BY saved_tokens DESC
|
|
87
|
+
LIMIT 5
|
|
88
|
+
"""
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
lines = [
|
|
92
|
+
"Token Savings Report",
|
|
93
|
+
f"Time range: {time_range}",
|
|
94
|
+
f"Total commands: {total_commands}",
|
|
95
|
+
f"Raw tokens: {total_raw} → Compressed tokens: {total_compressed}",
|
|
96
|
+
f"Savings: {saved} tokens ({savings_pct:.1f}%)",
|
|
97
|
+
"Top 5 strategies:",
|
|
98
|
+
]
|
|
99
|
+
if top_strategies:
|
|
100
|
+
for strategy, cmd_count, saved_tokens in top_strategies:
|
|
101
|
+
lines.append(
|
|
102
|
+
f" {strategy}: {cmd_count} commands, {int(saved_tokens)} tokens saved"
|
|
103
|
+
)
|
|
104
|
+
else:
|
|
105
|
+
lines.append(" (no data)")
|
|
106
|
+
|
|
107
|
+
return "\n".join(lines)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def cc_economics_report(db: TrackingDatabase, time_range: str = "all") -> str:
|
|
111
|
+
"""Estimate dollar savings using Claude Code pricing.
|
|
112
|
+
|
|
113
|
+
Treats raw tokens as "uncompressed input" and compressed tokens as
|
|
114
|
+
"actual input after filtering". Output tokens are not tracked
|
|
115
|
+
separately so we only show input-side economics.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
db: A ``TrackingDatabase`` instance.
|
|
119
|
+
time_range: One of ``today``, ``week``, ``month``, ``all``.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Compact, LLM-readable summary string.
|
|
123
|
+
"""
|
|
124
|
+
where = _time_filter(time_range)
|
|
125
|
+
|
|
126
|
+
row = db.query_one(
|
|
127
|
+
f"""
|
|
128
|
+
SELECT COALESCE(SUM(raw_tokens), 0), COALESCE(SUM(compressed_tokens), 0)
|
|
129
|
+
FROM executions
|
|
130
|
+
WHERE {where}
|
|
131
|
+
"""
|
|
132
|
+
)
|
|
133
|
+
total_raw, total_compressed = row or (0, 0)
|
|
134
|
+
total_raw = int(total_raw)
|
|
135
|
+
total_compressed = int(total_compressed)
|
|
136
|
+
|
|
137
|
+
cost_uncompressed = _estimate_tokens_to_cost(total_raw, 0)
|
|
138
|
+
cost_compressed = _estimate_tokens_to_cost(total_compressed, 0)
|
|
139
|
+
savings = cost_uncompressed - cost_compressed
|
|
140
|
+
|
|
141
|
+
lines = [
|
|
142
|
+
"Claude Code Economics Report",
|
|
143
|
+
f"Time range: {time_range}",
|
|
144
|
+
f"Uncompressed input cost: ${cost_uncompressed:.4f}",
|
|
145
|
+
f"Compressed input cost: ${cost_compressed:.4f}",
|
|
146
|
+
f"Estimated savings: ${savings:.4f}",
|
|
147
|
+
]
|
|
148
|
+
return "\n".join(lines)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def session_report(db: TrackingDatabase, limit: int = 10) -> str:
|
|
152
|
+
"""Report per-session adoption statistics.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
db: A ``TrackingDatabase`` instance.
|
|
156
|
+
limit: Maximum number of recent sessions to show.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Multi-line string with adoption metrics per session.
|
|
160
|
+
"""
|
|
161
|
+
sessions = db.query_all(
|
|
162
|
+
"""
|
|
163
|
+
SELECT
|
|
164
|
+
session_id,
|
|
165
|
+
COUNT(*) AS total_commands,
|
|
166
|
+
SUM(CASE WHEN strategy != 'unknown' THEN 1 ELSE 0 END) AS filtered_commands,
|
|
167
|
+
MIN(timestamp) AS first_ts,
|
|
168
|
+
MAX(timestamp) AS last_ts
|
|
169
|
+
FROM executions
|
|
170
|
+
GROUP BY session_id
|
|
171
|
+
ORDER BY first_ts DESC
|
|
172
|
+
LIMIT ?
|
|
173
|
+
""",
|
|
174
|
+
(limit,),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if not sessions:
|
|
178
|
+
return "Session Report\n(no tracking data)"
|
|
179
|
+
|
|
180
|
+
lines = ["Session Report"]
|
|
181
|
+
total_adoption_sum = 0.0
|
|
182
|
+
total_sessions = len(sessions)
|
|
183
|
+
|
|
184
|
+
for session_id, total_cmds, filtered_cmds, first_ts, last_ts in sessions:
|
|
185
|
+
total_cmds = int(total_cmds)
|
|
186
|
+
filtered_cmds = int(filtered_cmds)
|
|
187
|
+
adoption = (filtered_cmds / max(total_cmds, 1)) * 100.0
|
|
188
|
+
total_adoption_sum += adoption
|
|
189
|
+
|
|
190
|
+
flag = " ⚠️ low adoption" if adoption < 50 else ""
|
|
191
|
+
lines.append(
|
|
192
|
+
f"\nSession {session_id[:8]}…"
|
|
193
|
+
f"\n Commands: {total_cmds} total, {filtered_cmds} filtered"
|
|
194
|
+
f"\n Adoption: {adoption:.1f}%{flag}"
|
|
195
|
+
f"\n First: {first_ts}"
|
|
196
|
+
f"\n Last: {last_ts}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
overall_avg = total_adoption_sum / max(total_sessions, 1)
|
|
200
|
+
lines.append(f"\nOverall average adoption: {overall_avg:.1f}%")
|
|
201
|
+
|
|
202
|
+
return "\n".join(lines)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# ------------------------------------------------------------------
|
|
206
|
+
# Edit efficiency report
|
|
207
|
+
# ------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def edit_efficiency_report(db: TrackingDatabase, time_range: str = "all") -> str:
|
|
211
|
+
"""Format an edit-efficiency / context-inflation report.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
db: A ``TrackingDatabase`` instance.
|
|
215
|
+
time_range: One of ``today``, ``week``, ``month``, ``all``.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Multi-line string suitable for display in the UI.
|
|
219
|
+
"""
|
|
220
|
+
edits = db.query_edit_summary(time_range)
|
|
221
|
+
|
|
222
|
+
if not edits:
|
|
223
|
+
range_label = {
|
|
224
|
+
"today": "today",
|
|
225
|
+
"week": "last 7 days",
|
|
226
|
+
"month": "last 30 days",
|
|
227
|
+
"all": "all time",
|
|
228
|
+
}.get(time_range, time_range)
|
|
229
|
+
return f"Edit Efficiency Report ({range_label})\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n(no edit tracking data)"
|
|
230
|
+
|
|
231
|
+
total = len(edits)
|
|
232
|
+
tool_counts: dict[str, int] = {}
|
|
233
|
+
inflation_values: list[float] = []
|
|
234
|
+
no_core_count = 0
|
|
235
|
+
edits_with_inflation: list[tuple[float, str, int, int]] = []
|
|
236
|
+
bucket_success: dict[str, list[tuple[int, int]]] = {
|
|
237
|
+
"<4x": [],
|
|
238
|
+
"4-10x": [],
|
|
239
|
+
"10-25x": [],
|
|
240
|
+
"25x+": [],
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
for edit in edits:
|
|
244
|
+
tool = edit["tool_name"]
|
|
245
|
+
tool_counts[tool] = tool_counts.get(tool, 0) + 1
|
|
246
|
+
|
|
247
|
+
if edit["no_core_change"]:
|
|
248
|
+
no_core_count += 1
|
|
249
|
+
|
|
250
|
+
ratio = edit["inflation_ratio"]
|
|
251
|
+
if ratio is not None:
|
|
252
|
+
inflation_values.append(ratio)
|
|
253
|
+
edits_with_inflation.append(
|
|
254
|
+
(ratio, edit["file_path"], edit["total_edit_bytes"], edit["core_bytes"])
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
success = 1 if edit["success"] else 0
|
|
258
|
+
if ratio < 4:
|
|
259
|
+
bucket_success["<4x"].append((success, 1))
|
|
260
|
+
elif ratio < 10:
|
|
261
|
+
bucket_success["4-10x"].append((success, 1))
|
|
262
|
+
elif ratio < 25:
|
|
263
|
+
bucket_success["10-25x"].append((success, 1))
|
|
264
|
+
else:
|
|
265
|
+
bucket_success["25x+"].append((success, 1))
|
|
266
|
+
else:
|
|
267
|
+
# No core change — count in no_core bucket but don't show inflation
|
|
268
|
+
pass
|
|
269
|
+
|
|
270
|
+
range_label = {
|
|
271
|
+
"today": "today",
|
|
272
|
+
"week": "last 7 days",
|
|
273
|
+
"month": "last 30 days",
|
|
274
|
+
"all": "all time",
|
|
275
|
+
}.get(time_range, time_range)
|
|
276
|
+
|
|
277
|
+
lines = [
|
|
278
|
+
f"Edit Efficiency Report ({range_label})",
|
|
279
|
+
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
|
|
280
|
+
f"Total edit calls: {total}",
|
|
281
|
+
]
|
|
282
|
+
for tool, count in sorted(tool_counts.items(), key=lambda x: -x[1]):
|
|
283
|
+
lines.append(f" • {tool}: {count}")
|
|
284
|
+
|
|
285
|
+
lines.append("")
|
|
286
|
+
lines.append("Context inflation:")
|
|
287
|
+
|
|
288
|
+
if inflation_values:
|
|
289
|
+
inflation_values.sort()
|
|
290
|
+
median = inflation_values[len(inflation_values) // 2]
|
|
291
|
+
p95_idx = int(len(inflation_values) * 0.95)
|
|
292
|
+
p95 = inflation_values[min(p95_idx, len(inflation_values) - 1)]
|
|
293
|
+
lines.append(f" median inflation: {median:.2f}x")
|
|
294
|
+
lines.append(f" p95 inflation: {p95:.2f}x")
|
|
295
|
+
else:
|
|
296
|
+
lines.append(" median inflation: N/A")
|
|
297
|
+
lines.append(" p95 inflation: N/A")
|
|
298
|
+
|
|
299
|
+
lines.append(
|
|
300
|
+
f" no-core-change: {no_core_count} edits ({no_core_count / max(total, 1) * 100:.1f}%)"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# Worst offenders
|
|
304
|
+
worst = sorted(edits_with_inflation, key=lambda x: -x[0])[:10]
|
|
305
|
+
worst = [w for w in worst if w[0] > 20]
|
|
306
|
+
if worst:
|
|
307
|
+
lines.append("")
|
|
308
|
+
lines.append("Worst offenders (>20x inflation):")
|
|
309
|
+
for i, (ratio, path, total_bytes, core_bytes) in enumerate(worst, 1):
|
|
310
|
+
lines.append(
|
|
311
|
+
f" {i}. {path} — {ratio:.1f}x ({total_bytes:,} bytes → {core_bytes:,} bytes core)"
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Failure rate by bucket
|
|
315
|
+
lines.append("")
|
|
316
|
+
lines.append("Failure rate by inflation bucket:")
|
|
317
|
+
for bucket in ("<4x", "4-10x", "10-25x", "25x+"):
|
|
318
|
+
entries = bucket_success[bucket]
|
|
319
|
+
if entries:
|
|
320
|
+
successes = sum(s for s, _ in entries)
|
|
321
|
+
total_bucket = len(entries)
|
|
322
|
+
rate = successes / total_bucket * 100
|
|
323
|
+
lines.append(
|
|
324
|
+
f" {bucket}: {rate:.1f}% success ({successes}/{total_bucket})"
|
|
325
|
+
)
|
|
326
|
+
else:
|
|
327
|
+
lines.append(f" {bucket}: N/A")
|
|
328
|
+
|
|
329
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Universal Constructor - Dynamic tool creation and management plugin.
|
|
2
|
+
|
|
3
|
+
This plugin enables users to create, manage, and deploy custom tools
|
|
4
|
+
that extend Muse's capabilities. Tools are stored in the user's
|
|
5
|
+
config directory and can be organized into namespaces via subdirectories.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
# User tools directory - where user-created UC tools live
|
|
11
|
+
USER_UC_DIR = Path.home() / ".muse" / "plugins" / "universal_constructor"
|
|
12
|
+
|
|
13
|
+
__all__ = ["USER_UC_DIR"]
|