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,438 @@
|
|
|
1
|
+
"""Git compression strategies for the filter engine.
|
|
2
|
+
|
|
3
|
+
Parses common git command output and produces compact summaries.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
from code_muse.plugins.filter_engine.registry import get_registry
|
|
9
|
+
from code_muse.plugins.filter_engine.verbosity import VerbosityLevel
|
|
10
|
+
from code_muse.tools.command_runner import ShellCommandOutput
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _compress_plain_git_status(
|
|
14
|
+
stdout: str,
|
|
15
|
+
stderr: str,
|
|
16
|
+
verbosity: VerbosityLevel,
|
|
17
|
+
) -> ShellCommandOutput:
|
|
18
|
+
"""Fallback parser for human-readable ``git status`` output."""
|
|
19
|
+
lines = stdout.strip().splitlines()
|
|
20
|
+
|
|
21
|
+
cdef str branch = "unknown"
|
|
22
|
+
cdef int staged = 0
|
|
23
|
+
cdef int unstaged = 0
|
|
24
|
+
cdef int untracked = 0
|
|
25
|
+
|
|
26
|
+
cdef bint in_staged = False
|
|
27
|
+
cdef bint in_unstaged = False
|
|
28
|
+
cdef bint in_untracked = False
|
|
29
|
+
cdef str line
|
|
30
|
+
cdef str raw
|
|
31
|
+
|
|
32
|
+
for raw in lines:
|
|
33
|
+
line = raw.strip()
|
|
34
|
+
if line.startswith("On branch "):
|
|
35
|
+
branch = line[10:].strip()
|
|
36
|
+
elif line.startswith("HEAD detached "):
|
|
37
|
+
branch = line[14:].strip().split()[0]
|
|
38
|
+
elif line == "Changes to be committed:":
|
|
39
|
+
in_staged = True
|
|
40
|
+
in_unstaged = False
|
|
41
|
+
in_untracked = False
|
|
42
|
+
elif line == "Changes not staged for commit:":
|
|
43
|
+
in_staged = False
|
|
44
|
+
in_unstaged = True
|
|
45
|
+
in_untracked = False
|
|
46
|
+
elif line == "Untracked files:":
|
|
47
|
+
in_staged = False
|
|
48
|
+
in_unstaged = False
|
|
49
|
+
in_untracked = True
|
|
50
|
+
elif line == "":
|
|
51
|
+
in_staged = in_unstaged = in_untracked = False
|
|
52
|
+
elif line.startswith("("):
|
|
53
|
+
continue
|
|
54
|
+
elif in_staged and any(
|
|
55
|
+
line.startswith(p)
|
|
56
|
+
for p in ("modified:", "new file:", "deleted:", "renamed:", "copied:")
|
|
57
|
+
):
|
|
58
|
+
staged += 1
|
|
59
|
+
elif in_unstaged and any(
|
|
60
|
+
line.startswith(p) for p in ("modified:", "deleted:", "renamed:")
|
|
61
|
+
):
|
|
62
|
+
unstaged += 1
|
|
63
|
+
elif in_untracked and not line.startswith("("):
|
|
64
|
+
untracked += 1
|
|
65
|
+
|
|
66
|
+
summary = (
|
|
67
|
+
f"branch:{branch} | staged:{staged} unstaged:{unstaged} untracked:{untracked}"
|
|
68
|
+
)
|
|
69
|
+
if verbosity >= VerbosityLevel.VERBOSE:
|
|
70
|
+
summary += f"\n{stdout.strip()}"
|
|
71
|
+
|
|
72
|
+
success = not stderr.strip() or "error" not in stderr.lower()
|
|
73
|
+
return ShellCommandOutput(
|
|
74
|
+
success=success,
|
|
75
|
+
command="git status",
|
|
76
|
+
stdout=summary,
|
|
77
|
+
stderr=stderr if verbosity >= VerbosityLevel.VERY_VERBOSE else None,
|
|
78
|
+
exit_code=0,
|
|
79
|
+
execution_time=None,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def compress_git_status(
|
|
84
|
+
stdout: str,
|
|
85
|
+
stderr: str,
|
|
86
|
+
verbosity: VerbosityLevel,
|
|
87
|
+
) -> ShellCommandOutput:
|
|
88
|
+
"""Compress ``git status`` output into a compact summary.
|
|
89
|
+
|
|
90
|
+
Parses porcelain-style status lines and counts staged, unstaged, and
|
|
91
|
+
untracked files. Also extracts branch name and ahead/behind counts.
|
|
92
|
+
|
|
93
|
+
Falls back to a plain-text parser when the output does not look like
|
|
94
|
+
porcelain (e.g. the user ran ``git status`` without ``--porcelain``).
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
stdout: Raw command stdout.
|
|
98
|
+
stderr: Raw command stderr.
|
|
99
|
+
verbosity: Current verbosity level.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
A :class:`ShellCommandOutput` with the compressed summary.
|
|
103
|
+
"""
|
|
104
|
+
lines = stdout.strip().splitlines()
|
|
105
|
+
|
|
106
|
+
# Detect plain (human-readable) git status output
|
|
107
|
+
if lines and (
|
|
108
|
+
lines[0].startswith("On branch ")
|
|
109
|
+
or lines[0].startswith("HEAD detached ")
|
|
110
|
+
or lines[0].startswith("nothing to commit")
|
|
111
|
+
):
|
|
112
|
+
return _compress_plain_git_status(stdout, stderr, verbosity)
|
|
113
|
+
|
|
114
|
+
cdef str branch = "unknown"
|
|
115
|
+
cdef int ahead = 0
|
|
116
|
+
cdef int behind = 0
|
|
117
|
+
|
|
118
|
+
cdef int staged = 0
|
|
119
|
+
cdef int unstaged = 0
|
|
120
|
+
cdef int untracked = 0
|
|
121
|
+
|
|
122
|
+
file_lists: dict[str, list[str]] = {
|
|
123
|
+
"M": [],
|
|
124
|
+
"A": [],
|
|
125
|
+
"D": [],
|
|
126
|
+
"??": [],
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
cdef str line
|
|
130
|
+
cdef str xy
|
|
131
|
+
cdef str filename
|
|
132
|
+
cdef str index_char
|
|
133
|
+
cdef str worktree_char
|
|
134
|
+
cdef object branch_match
|
|
135
|
+
cdef object ahead_match
|
|
136
|
+
cdef object behind_match
|
|
137
|
+
|
|
138
|
+
for line in lines:
|
|
139
|
+
line = line.rstrip("\r")
|
|
140
|
+
if line.startswith("##"):
|
|
141
|
+
# Branch line: ## main...origin/main [ahead 2, behind 1]
|
|
142
|
+
branch_match = re.search(r"##\s+([^.\s]+)", line)
|
|
143
|
+
if branch_match:
|
|
144
|
+
branch = branch_match.group(1)
|
|
145
|
+
ahead_match = re.search(r"ahead\s+(\d+)", line)
|
|
146
|
+
if ahead_match:
|
|
147
|
+
ahead = int(ahead_match.group(1))
|
|
148
|
+
behind_match = re.search(r"behind\s+(\d+)", line)
|
|
149
|
+
if behind_match:
|
|
150
|
+
behind = int(behind_match.group(1))
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
if len(line) >= 2 and (line.startswith("??") or line[0] in " MADRC"):
|
|
154
|
+
# Porcelain status line: XY filename
|
|
155
|
+
xy = line[:2]
|
|
156
|
+
filename = line[3:] if len(line) > 3 else ""
|
|
157
|
+
|
|
158
|
+
if xy == "??":
|
|
159
|
+
untracked += 1
|
|
160
|
+
file_lists["??"].append(filename)
|
|
161
|
+
else:
|
|
162
|
+
index_char = xy[0]
|
|
163
|
+
worktree_char = xy[1]
|
|
164
|
+
if index_char in "MADRC":
|
|
165
|
+
staged += 1
|
|
166
|
+
if index_char in file_lists:
|
|
167
|
+
file_lists[index_char].append(filename)
|
|
168
|
+
if worktree_char in "MADRC":
|
|
169
|
+
unstaged += 1
|
|
170
|
+
if worktree_char in file_lists:
|
|
171
|
+
file_lists[worktree_char].append(filename)
|
|
172
|
+
|
|
173
|
+
summary = (
|
|
174
|
+
f"branch:{branch} ↑{ahead} ↓{behind} | "
|
|
175
|
+
f"M:{len(file_lists['M'])} A:{len(file_lists['A'])} "
|
|
176
|
+
f"D:{len(file_lists['D'])} ??{len(file_lists['??'])}"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if verbosity >= VerbosityLevel.VERBOSE:
|
|
180
|
+
parts = [summary]
|
|
181
|
+
for key, files in file_lists.items():
|
|
182
|
+
if files:
|
|
183
|
+
parts.append(f"{key}: {', '.join(files[:20])}")
|
|
184
|
+
if len(files) > 20:
|
|
185
|
+
parts.append(f" ... and {len(files) - 20} more")
|
|
186
|
+
summary = "\n".join(parts)
|
|
187
|
+
|
|
188
|
+
success = not stderr.strip() or "error" not in stderr.lower()
|
|
189
|
+
return ShellCommandOutput(
|
|
190
|
+
success=success,
|
|
191
|
+
command="git status",
|
|
192
|
+
stdout=summary,
|
|
193
|
+
stderr=stderr if verbosity >= VerbosityLevel.VERY_VERBOSE else None,
|
|
194
|
+
exit_code=0,
|
|
195
|
+
execution_time=None,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def compress_git_log(
|
|
200
|
+
stdout: str,
|
|
201
|
+
stderr: str,
|
|
202
|
+
verbosity: VerbosityLevel,
|
|
203
|
+
) -> ShellCommandOutput:
|
|
204
|
+
"""Compress ``git log --oneline`` output into a compact summary.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
stdout: Raw command stdout.
|
|
208
|
+
stderr: Raw command stderr.
|
|
209
|
+
verbosity: Current verbosity level.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
A :class:`ShellCommandOutput` with the compressed summary.
|
|
213
|
+
"""
|
|
214
|
+
lines = [line for line in stdout.strip().splitlines() if line.strip()]
|
|
215
|
+
cdef int count = len(lines)
|
|
216
|
+
|
|
217
|
+
if count == 0:
|
|
218
|
+
return ShellCommandOutput(
|
|
219
|
+
success=True,
|
|
220
|
+
command="git log",
|
|
221
|
+
stdout="0 commits",
|
|
222
|
+
stderr=stderr if verbosity >= VerbosityLevel.VERY_VERBOSE else None,
|
|
223
|
+
exit_code=0,
|
|
224
|
+
execution_time=None,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
cdef str first_hash = lines[0][:7] if lines[0] else ""
|
|
228
|
+
cdef str last_hash = lines[-1][:7] if lines[-1] else ""
|
|
229
|
+
|
|
230
|
+
# Extract commit messages (after the hash)
|
|
231
|
+
messages: list[str] = []
|
|
232
|
+
cdef list parts
|
|
233
|
+
cdef str line
|
|
234
|
+
cdef str msg
|
|
235
|
+
|
|
236
|
+
for line in lines:
|
|
237
|
+
parts = line.split(None, 1)
|
|
238
|
+
if len(parts) > 1:
|
|
239
|
+
messages.append(parts[1])
|
|
240
|
+
else:
|
|
241
|
+
messages.append(line)
|
|
242
|
+
|
|
243
|
+
preview = ", ".join(messages[:3])
|
|
244
|
+
if len(messages) > 3:
|
|
245
|
+
preview += f", ... ({len(messages) - 3} more)"
|
|
246
|
+
|
|
247
|
+
summary = f"{count} commits ({first_hash}..{last_hash}): {preview}"
|
|
248
|
+
|
|
249
|
+
if verbosity >= VerbosityLevel.VERBOSE:
|
|
250
|
+
summary = f"{count} commits ({first_hash}..{last_hash}):\n" + "\n".join(
|
|
251
|
+
f" {line[:7]} {msg}" for line, msg in zip(lines, messages, strict=False)
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
success = not stderr.strip() or "error" not in stderr.lower()
|
|
255
|
+
return ShellCommandOutput(
|
|
256
|
+
success=success,
|
|
257
|
+
command="git log",
|
|
258
|
+
stdout=summary,
|
|
259
|
+
stderr=stderr if verbosity >= VerbosityLevel.VERY_VERBOSE else None,
|
|
260
|
+
exit_code=0,
|
|
261
|
+
execution_time=None,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def compress_git_diff(
|
|
266
|
+
stdout: str,
|
|
267
|
+
stderr: str,
|
|
268
|
+
verbosity: VerbosityLevel,
|
|
269
|
+
) -> ShellCommandOutput:
|
|
270
|
+
"""Compress ``git diff`` output into a compact summary.
|
|
271
|
+
|
|
272
|
+
When *verbosity* is :attr:`~VerbosityLevel.VERBOSE` or higher the raw
|
|
273
|
+
diff is preserved. Otherwise parses ``--stat`` style output or falls
|
|
274
|
+
back to counting changed hunks.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
stdout: Raw command stdout.
|
|
278
|
+
stderr: Raw command stderr.
|
|
279
|
+
verbosity: Current verbosity level.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
A :class:`ShellCommandOutput` with the compressed summary.
|
|
283
|
+
"""
|
|
284
|
+
if verbosity >= VerbosityLevel.VERBOSE:
|
|
285
|
+
# Return full diff at -v and above
|
|
286
|
+
success = not stderr.strip() or "error" not in stderr.lower()
|
|
287
|
+
return ShellCommandOutput(
|
|
288
|
+
success=success,
|
|
289
|
+
command="git diff",
|
|
290
|
+
stdout=stdout,
|
|
291
|
+
stderr=stderr,
|
|
292
|
+
exit_code=0,
|
|
293
|
+
execution_time=None,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
cdef int files_changed = 0
|
|
297
|
+
cdef int insertions = 0
|
|
298
|
+
cdef int deletions = 0
|
|
299
|
+
cdef bint stat_found = False
|
|
300
|
+
|
|
301
|
+
stat_pattern = re.compile(
|
|
302
|
+
r"^\s*(\d+) files? changed, (\d+) insertions?\(\+\), (\d+) deletions?\(-\)"
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
cdef str line
|
|
306
|
+
cdef object match
|
|
307
|
+
|
|
308
|
+
for line in stdout.splitlines():
|
|
309
|
+
if not stat_found:
|
|
310
|
+
match = stat_pattern.search(line)
|
|
311
|
+
if match:
|
|
312
|
+
files_changed = int(match.group(1))
|
|
313
|
+
insertions = int(match.group(2))
|
|
314
|
+
deletions = int(match.group(3))
|
|
315
|
+
stat_found = True
|
|
316
|
+
continue
|
|
317
|
+
if line.startswith("diff --git"):
|
|
318
|
+
files_changed += 1
|
|
319
|
+
elif line.startswith("+") and not line.startswith("+++"):
|
|
320
|
+
insertions += 1
|
|
321
|
+
elif line.startswith("-") and not line.startswith("---"):
|
|
322
|
+
deletions += 1
|
|
323
|
+
|
|
324
|
+
summary = (
|
|
325
|
+
f"{files_changed} files changed, {insertions} "
|
|
326
|
+
f"insertions(+), {deletions} deletions(-)"
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
success = not stderr.strip() or "error" not in stderr.lower()
|
|
330
|
+
return ShellCommandOutput(
|
|
331
|
+
success=success,
|
|
332
|
+
command="git diff",
|
|
333
|
+
stdout=summary,
|
|
334
|
+
stderr=stderr if verbosity >= VerbosityLevel.VERY_VERBOSE else None,
|
|
335
|
+
exit_code=0,
|
|
336
|
+
execution_time=None,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def compress_git_mutation(
|
|
341
|
+
stdout: str,
|
|
342
|
+
stderr: str,
|
|
343
|
+
verbosity: VerbosityLevel,
|
|
344
|
+
) -> ShellCommandOutput:
|
|
345
|
+
"""Compress output from mutating git commands (add, commit, push, pull, etc.).
|
|
346
|
+
|
|
347
|
+
Returns a minimal ``"ok"`` or ``"ok <hash>"`` summary. On error the
|
|
348
|
+
stderr is surfaced.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
stdout: Raw command stdout.
|
|
352
|
+
stderr: Raw command stderr.
|
|
353
|
+
verbosity: Current verbosity level.
|
|
354
|
+
"""
|
|
355
|
+
cdef bint has_error = bool(stderr.strip()) and (
|
|
356
|
+
"error" in stderr.lower()
|
|
357
|
+
or "fatal" in stderr.lower()
|
|
358
|
+
or "conflict" in stderr.lower()
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
if has_error:
|
|
362
|
+
error_msg = stderr.strip().splitlines()[0] if stderr.strip() else "Git error"
|
|
363
|
+
summary = f"ERROR: {error_msg}"
|
|
364
|
+
return ShellCommandOutput(
|
|
365
|
+
success=False,
|
|
366
|
+
command="git",
|
|
367
|
+
stdout=None,
|
|
368
|
+
stderr=summary,
|
|
369
|
+
exit_code=1,
|
|
370
|
+
execution_time=None,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
# Try to extract a commit hash from stdout
|
|
374
|
+
cdef object hash_match = re.search(r"\b([a-f0-9]{7,40})\b", stdout)
|
|
375
|
+
cdef str commit_hash = hash_match.group(1)[:7] if hash_match else ""
|
|
376
|
+
|
|
377
|
+
summary = f"ok {commit_hash}" if commit_hash else "ok"
|
|
378
|
+
|
|
379
|
+
if verbosity >= VerbosityLevel.VERBOSE and stdout.strip():
|
|
380
|
+
summary += f"\n{stdout.strip()}"
|
|
381
|
+
|
|
382
|
+
return ShellCommandOutput(
|
|
383
|
+
success=True,
|
|
384
|
+
command="git",
|
|
385
|
+
stdout=summary,
|
|
386
|
+
stderr=None,
|
|
387
|
+
exit_code=0,
|
|
388
|
+
execution_time=None,
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def compress_git(
|
|
393
|
+
command: str,
|
|
394
|
+
stdout: str,
|
|
395
|
+
stderr: str,
|
|
396
|
+
exit_code: int,
|
|
397
|
+
verbosity: VerbosityLevel,
|
|
398
|
+
) -> ShellCommandOutput | None:
|
|
399
|
+
"""Main dispatcher for git compression strategies.
|
|
400
|
+
|
|
401
|
+
Args:
|
|
402
|
+
command: The original git command.
|
|
403
|
+
stdout: Raw stdout from the command.
|
|
404
|
+
stderr: Raw stderr from the command.
|
|
405
|
+
exit_code: Process exit code.
|
|
406
|
+
verbosity: Current verbosity level.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
A compressed :class:`ShellCommandOutput` or ``None`` on error.
|
|
410
|
+
"""
|
|
411
|
+
cdef str stripped = command.strip()
|
|
412
|
+
cdef object mutation_pattern
|
|
413
|
+
|
|
414
|
+
# Determine subcommand
|
|
415
|
+
if re.search(r"git\s+status", stripped):
|
|
416
|
+
return compress_git_status(stdout, stderr, verbosity)
|
|
417
|
+
|
|
418
|
+
if re.search(r"git\s+log", stripped):
|
|
419
|
+
return compress_git_log(stdout, stderr, verbosity)
|
|
420
|
+
|
|
421
|
+
if re.search(r"git\s+diff", stripped):
|
|
422
|
+
return compress_git_diff(stdout, stderr, verbosity)
|
|
423
|
+
|
|
424
|
+
# Mutations: add, commit, push, pull, fetch, merge, rebase, stash, reset, etc.
|
|
425
|
+
mutation_pattern = re.compile(
|
|
426
|
+
r"git\s+(add|commit|push|pull|fetch|merge|rebase|stash|reset|checkout|branch|tag|remote|init|clone)"
|
|
427
|
+
)
|
|
428
|
+
if mutation_pattern.search(stripped):
|
|
429
|
+
return compress_git_mutation(stdout, stderr, verbosity)
|
|
430
|
+
|
|
431
|
+
# Fallback: treat everything else as a mutation
|
|
432
|
+
return compress_git_mutation(stdout, stderr, verbosity)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
# ---------------------------------------------------------------------------
|
|
436
|
+
# Register with the strategy registry
|
|
437
|
+
# ---------------------------------------------------------------------------
|
|
438
|
+
get_registry().register("git", compress_git, priority=0)
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""SmartCrusher JSON compression engine.
|
|
2
|
+
|
|
3
|
+
Takes analyzed JSON patterns and produces compact output.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from code_muse.plugins.filter_engine.strategies.json_patterns import analyze_json
|
|
10
|
+
from code_muse.plugins.filter_engine.verbosity import VerbosityLevel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _format_compact(obj: Any) -> str:
|
|
14
|
+
"""Format a value as compact JSON-like string (no unnecessary whitespace).
|
|
15
|
+
|
|
16
|
+
Uses an explicit stack instead of recursion to avoid deep-call overhead
|
|
17
|
+
and temporary object churn on nested structures.
|
|
18
|
+
"""
|
|
19
|
+
cdef list result
|
|
20
|
+
cdef list stack
|
|
21
|
+
cdef str kind
|
|
22
|
+
cdef object data
|
|
23
|
+
cdef object value
|
|
24
|
+
cdef list items
|
|
25
|
+
cdef object k
|
|
26
|
+
cdef object v
|
|
27
|
+
cdef int i
|
|
28
|
+
cdef str first
|
|
29
|
+
cdef str second
|
|
30
|
+
|
|
31
|
+
# Scalar fast-paths — return immediately without stack overhead.
|
|
32
|
+
if isinstance(obj, str):
|
|
33
|
+
return json.dumps(obj)
|
|
34
|
+
if isinstance(obj, bool):
|
|
35
|
+
return "true" if obj else "false"
|
|
36
|
+
if isinstance(obj, (int, float)):
|
|
37
|
+
return str(obj)
|
|
38
|
+
if obj is None:
|
|
39
|
+
return "null"
|
|
40
|
+
|
|
41
|
+
# Iterative walk for containers.
|
|
42
|
+
result = []
|
|
43
|
+
# Stack entries: (kind, data)
|
|
44
|
+
# "val" -> data is any value to format
|
|
45
|
+
# "raw" -> data is a string to append verbatim
|
|
46
|
+
# "cdict" -> append "}"
|
|
47
|
+
# "clist" -> append "]"
|
|
48
|
+
stack = [("val", obj)]
|
|
49
|
+
|
|
50
|
+
while stack:
|
|
51
|
+
kind, data = stack.pop()
|
|
52
|
+
if kind == "raw":
|
|
53
|
+
result.append(data)
|
|
54
|
+
continue
|
|
55
|
+
if kind == "cdict":
|
|
56
|
+
result.append("}")
|
|
57
|
+
continue
|
|
58
|
+
if kind == "clist":
|
|
59
|
+
result.append("]")
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
# kind == "val"
|
|
63
|
+
value = data
|
|
64
|
+
if isinstance(value, str):
|
|
65
|
+
result.append(json.dumps(value))
|
|
66
|
+
elif isinstance(value, bool):
|
|
67
|
+
result.append("true" if value else "false")
|
|
68
|
+
elif isinstance(value, (int, float)):
|
|
69
|
+
result.append(str(value))
|
|
70
|
+
elif value is None:
|
|
71
|
+
result.append("null")
|
|
72
|
+
elif isinstance(value, dict):
|
|
73
|
+
if not value:
|
|
74
|
+
result.append("{}")
|
|
75
|
+
else:
|
|
76
|
+
result.append("{")
|
|
77
|
+
stack.append(("cdict", None))
|
|
78
|
+
items = list(value.items())
|
|
79
|
+
for i in range(len(items) - 1, -1, -1):
|
|
80
|
+
k, v = items[i]
|
|
81
|
+
stack.append(("val", v))
|
|
82
|
+
stack.append(("raw", f"{json.dumps(k)}:"))
|
|
83
|
+
if i > 0:
|
|
84
|
+
stack.append(("raw", ","))
|
|
85
|
+
elif isinstance(value, list):
|
|
86
|
+
if not value:
|
|
87
|
+
result.append("[]")
|
|
88
|
+
elif len(value) <= 3:
|
|
89
|
+
result.append("[")
|
|
90
|
+
stack.append(("clist", None))
|
|
91
|
+
for i in range(len(value) - 1, -1, -1):
|
|
92
|
+
stack.append(("val", value[i]))
|
|
93
|
+
if i > 0:
|
|
94
|
+
stack.append(("raw", ","))
|
|
95
|
+
else:
|
|
96
|
+
# Long list — inline first two items (still iterative).
|
|
97
|
+
first = _format_compact(value[0])
|
|
98
|
+
second = _format_compact(value[1])
|
|
99
|
+
result.append(f"[{first},{second},...{len(value)}items]")
|
|
100
|
+
else:
|
|
101
|
+
result.append(json.dumps(value))
|
|
102
|
+
|
|
103
|
+
return "".join(result)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def compress_json(
|
|
107
|
+
data: Any,
|
|
108
|
+
verbosity: VerbosityLevel | int = VerbosityLevel.COMPACT,
|
|
109
|
+
max_output_chars: int = 4000,
|
|
110
|
+
) -> str:
|
|
111
|
+
"""Compress JSON data using SmartCrusher.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
data: Parsed JSON (dict, list, or scalar).
|
|
115
|
+
verbosity: Compression level. 0 = max, 4 = near-original.
|
|
116
|
+
max_output_chars: Hard output limit.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Compact JSON string.
|
|
120
|
+
"""
|
|
121
|
+
if isinstance(verbosity, int):
|
|
122
|
+
level = verbosity
|
|
123
|
+
else:
|
|
124
|
+
level = verbosity.value if hasattr(verbosity, "value") else 1
|
|
125
|
+
|
|
126
|
+
if not isinstance(data, (dict, list)):
|
|
127
|
+
# Scalar — just return it compactly
|
|
128
|
+
return json.dumps(data)
|
|
129
|
+
|
|
130
|
+
analysis = analyze_json(data)
|
|
131
|
+
|
|
132
|
+
# If it's a homogeneous array with template, use template compression
|
|
133
|
+
if analysis["is_homogeneous"] and analysis["template"] and isinstance(data, list):
|
|
134
|
+
return _compress_homogeneous_array(data, analysis, level, max_output_chars)
|
|
135
|
+
|
|
136
|
+
# Otherwise, compact formatting
|
|
137
|
+
if isinstance(data, dict):
|
|
138
|
+
return _compress_dict(data, analysis, level, max_output_chars)
|
|
139
|
+
elif isinstance(data, list):
|
|
140
|
+
return _compress_list(data, analysis, level, max_output_chars)
|
|
141
|
+
|
|
142
|
+
return json.dumps(data)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _compress_homogeneous_array(
|
|
146
|
+
data: list[dict],
|
|
147
|
+
analysis: dict[str, Any],
|
|
148
|
+
level: int,
|
|
149
|
+
max_chars: int,
|
|
150
|
+
) -> str:
|
|
151
|
+
"""Compress array of same-shape dicts using template notation."""
|
|
152
|
+
template = analysis["template"]
|
|
153
|
+
field_scores = analysis["field_scores"]
|
|
154
|
+
|
|
155
|
+
# Select fields based on verbosity
|
|
156
|
+
keep_keys = _select_fields(template, field_scores, level)
|
|
157
|
+
|
|
158
|
+
if level == 0:
|
|
159
|
+
# Ultra-compact: template + values array only
|
|
160
|
+
key_order = [k for k in keep_keys if k in template]
|
|
161
|
+
values = []
|
|
162
|
+
for item in data:
|
|
163
|
+
row = [item.get(k) for k in key_order]
|
|
164
|
+
values.append(row)
|
|
165
|
+
template_str = ",".join(key_order)
|
|
166
|
+
compact_values = _format_compact(values)
|
|
167
|
+
result = f"{{@{template_str}}}{compact_values}"
|
|
168
|
+
return result[:max_chars]
|
|
169
|
+
|
|
170
|
+
# Level 1+: keep some structure
|
|
171
|
+
if level >= 1:
|
|
172
|
+
compact_items = []
|
|
173
|
+
for item in data:
|
|
174
|
+
kept = {k: item.get(k) for k in keep_keys if k in item}
|
|
175
|
+
compact_items.append(_format_compact(kept))
|
|
176
|
+
inner = ",".join(compact_items[:20]) # limit to 20 items shown
|
|
177
|
+
if len(data) > 20:
|
|
178
|
+
inner += f",...{len(data) - 20}more"
|
|
179
|
+
return f"[{inner}]"[:max_chars]
|
|
180
|
+
|
|
181
|
+
return json.dumps(data)[:max_chars]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _compress_dict(
|
|
185
|
+
data: dict,
|
|
186
|
+
analysis: dict[str, Any],
|
|
187
|
+
level: int,
|
|
188
|
+
max_chars: int,
|
|
189
|
+
) -> str:
|
|
190
|
+
"""Compress a single dict."""
|
|
191
|
+
field_scores = analysis["field_scores"] or {}
|
|
192
|
+
if not field_scores:
|
|
193
|
+
# Simple case: build field scores from data
|
|
194
|
+
field_scores = {}
|
|
195
|
+
for key in data:
|
|
196
|
+
if key.lower() in ("error", "exception"):
|
|
197
|
+
field_scores[key] = 1.0
|
|
198
|
+
elif key.startswith("_"):
|
|
199
|
+
field_scores[key] = 0.1
|
|
200
|
+
else:
|
|
201
|
+
field_scores[key] = 0.6
|
|
202
|
+
|
|
203
|
+
keep_keys = _select_fields(data, field_scores, level)
|
|
204
|
+
|
|
205
|
+
if level == 0:
|
|
206
|
+
kept = {k: data[k] for k in keep_keys if k in data}
|
|
207
|
+
if not kept:
|
|
208
|
+
# Fallback: keep all keys but format compactly
|
|
209
|
+
kept = {k: data[k] for k in data}
|
|
210
|
+
return _format_compact(kept)[:max_chars]
|
|
211
|
+
|
|
212
|
+
if level >= 1:
|
|
213
|
+
return json.dumps(data)[:max_chars]
|
|
214
|
+
|
|
215
|
+
return json.dumps(data)[:max_chars]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _compress_list(
|
|
219
|
+
data: list,
|
|
220
|
+
analysis: dict[str, Any],
|
|
221
|
+
level: int,
|
|
222
|
+
max_chars: int,
|
|
223
|
+
) -> str:
|
|
224
|
+
"""Compress a generic list (non-homogeneous)."""
|
|
225
|
+
if level == 0:
|
|
226
|
+
if len(data) <= 5:
|
|
227
|
+
return _format_compact(data)[:max_chars]
|
|
228
|
+
return f"[{len(data)} items]"[:max_chars]
|
|
229
|
+
if level >= 1:
|
|
230
|
+
return json.dumps(data)[:max_chars]
|
|
231
|
+
return json.dumps(data)[:max_chars]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _select_fields(
|
|
235
|
+
schema: dict[str, Any] | None,
|
|
236
|
+
scores: dict[str, float],
|
|
237
|
+
level: int,
|
|
238
|
+
) -> list[str]:
|
|
239
|
+
"""Select which fields to keep based on verbosity level and scores.
|
|
240
|
+
|
|
241
|
+
Level 0: keep only score >= 0.7 (names, errors)
|
|
242
|
+
Level 1: keep score >= 0.5
|
|
243
|
+
Level 2: keep score >= 0.3
|
|
244
|
+
Level 3: keep score >= 0.1
|
|
245
|
+
Level 4: keep all
|
|
246
|
+
"""
|
|
247
|
+
thresholds = {0: 0.7, 1: 0.5, 2: 0.3, 3: 0.1, 4: 0.0}
|
|
248
|
+
threshold = thresholds.get(level, 0.3)
|
|
249
|
+
|
|
250
|
+
if not schema:
|
|
251
|
+
return []
|
|
252
|
+
|
|
253
|
+
return [k for k, v in scores.items() if v >= threshold]
|