code-puppy-core-plugins 0.0.2__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_puppy_core_plugins/__init__.py +5 -0
- code_puppy_core_plugins/acp/README.md +266 -0
- code_puppy_core_plugins/acp/__init__.py +8 -0
- code_puppy_core_plugins/acp/agent.py +494 -0
- code_puppy_core_plugins/acp/bridge.py +309 -0
- code_puppy_core_plugins/acp/capabilities.py +73 -0
- code_puppy_core_plugins/acp/commands.py +116 -0
- code_puppy_core_plugins/acp/content.py +115 -0
- code_puppy_core_plugins/acp/io_delegation.py +231 -0
- code_puppy_core_plugins/acp/mcp_config.py +66 -0
- code_puppy_core_plugins/acp/permissions.py +159 -0
- code_puppy_core_plugins/acp/persistence.py +197 -0
- code_puppy_core_plugins/acp/register_callbacks.py +110 -0
- code_puppy_core_plugins/acp/replay.py +114 -0
- code_puppy_core_plugins/acp/session.py +329 -0
- code_puppy_core_plugins/acp/session_config.py +179 -0
- code_puppy_core_plugins/acp/state.py +135 -0
- code_puppy_core_plugins/agent_skills/__init__.py +22 -0
- code_puppy_core_plugins/agent_skills/config.py +208 -0
- code_puppy_core_plugins/agent_skills/discovery.py +337 -0
- code_puppy_core_plugins/agent_skills/downloader.py +392 -0
- code_puppy_core_plugins/agent_skills/enabled_skills.py +82 -0
- code_puppy_core_plugins/agent_skills/installer.py +22 -0
- code_puppy_core_plugins/agent_skills/metadata.py +219 -0
- code_puppy_core_plugins/agent_skills/prompt_builder.py +49 -0
- code_puppy_core_plugins/agent_skills/provider.py +52 -0
- code_puppy_core_plugins/agent_skills/register_callbacks.py +309 -0
- code_puppy_core_plugins/agent_skills/remote_catalog.py +322 -0
- code_puppy_core_plugins/agent_skills/skill_catalog.py +257 -0
- code_puppy_core_plugins/agent_skills/skill_commands.py +102 -0
- code_puppy_core_plugins/agent_skills/skills_install_menu.py +698 -0
- code_puppy_core_plugins/agent_skills/skills_menu.py +794 -0
- code_puppy_core_plugins/aws_bedrock/__init__.py +14 -0
- code_puppy_core_plugins/aws_bedrock/config.py +101 -0
- code_puppy_core_plugins/aws_bedrock/register_callbacks.py +243 -0
- code_puppy_core_plugins/aws_bedrock/utils.py +186 -0
- code_puppy_core_plugins/azure_foundry/README.md +238 -0
- code_puppy_core_plugins/azure_foundry/__init__.py +15 -0
- code_puppy_core_plugins/azure_foundry/config.py +126 -0
- code_puppy_core_plugins/azure_foundry/discovery.py +189 -0
- code_puppy_core_plugins/azure_foundry/register_callbacks.py +506 -0
- code_puppy_core_plugins/azure_foundry/token.py +182 -0
- code_puppy_core_plugins/azure_foundry/utils.py +375 -0
- code_puppy_core_plugins/btw/__init__.py +1 -0
- code_puppy_core_plugins/btw/inline_view.py +135 -0
- code_puppy_core_plugins/btw/register_callbacks.py +106 -0
- code_puppy_core_plugins/btw/side_query.py +91 -0
- code_puppy_core_plugins/chatgpt_oauth/IMAGEGEN_SKILL.md +83 -0
- code_puppy_core_plugins/chatgpt_oauth/__init__.py +8 -0
- code_puppy_core_plugins/chatgpt_oauth/config.py +52 -0
- code_puppy_core_plugins/chatgpt_oauth/image_generation.py +253 -0
- code_puppy_core_plugins/chatgpt_oauth/image_tool.py +70 -0
- code_puppy_core_plugins/chatgpt_oauth/oauth_flow.py +461 -0
- code_puppy_core_plugins/chatgpt_oauth/register_callbacks.py +288 -0
- code_puppy_core_plugins/chatgpt_oauth/test_plugin.py +663 -0
- code_puppy_core_plugins/chatgpt_oauth/usage.py +113 -0
- code_puppy_core_plugins/chatgpt_oauth/utils.py +534 -0
- code_puppy_core_plugins/claude_code_hooks/__init__.py +1 -0
- code_puppy_core_plugins/claude_code_hooks/config.py +137 -0
- code_puppy_core_plugins/claude_code_hooks/register_callbacks.py +383 -0
- code_puppy_core_plugins/claude_code_oauth/README.md +167 -0
- code_puppy_core_plugins/claude_code_oauth/SETUP.md +93 -0
- code_puppy_core_plugins/claude_code_oauth/__init__.py +25 -0
- code_puppy_core_plugins/claude_code_oauth/config.py +59 -0
- code_puppy_core_plugins/claude_code_oauth/fast_mode.py +122 -0
- code_puppy_core_plugins/claude_code_oauth/prompt_handler.py +64 -0
- code_puppy_core_plugins/claude_code_oauth/register_callbacks.py +719 -0
- code_puppy_core_plugins/claude_code_oauth/test_plugin.py +285 -0
- code_puppy_core_plugins/claude_code_oauth/token_refresh_heartbeat.py +240 -0
- code_puppy_core_plugins/claude_code_oauth/utils.py +663 -0
- code_puppy_core_plugins/code_puppy_agent/AGENTS_AND_TOOLS.md +155 -0
- code_puppy_core_plugins/code_puppy_agent/MODELS_AND_MCP.md +104 -0
- code_puppy_core_plugins/code_puppy_agent/PLUGINS_AND_CALLBACKS.md +147 -0
- code_puppy_core_plugins/code_puppy_agent/SESSIONS_AND_HISTORY.md +39 -0
- code_puppy_core_plugins/code_puppy_agent/SKILL.md +180 -0
- code_puppy_core_plugins/code_puppy_agent/SKILLS_SYSTEM.md +136 -0
- code_puppy_core_plugins/code_puppy_agent/SYSTEM_PROMPT_CONFIG_AND_I18N.md +160 -0
- code_puppy_core_plugins/code_puppy_agent/__init__.py +5 -0
- code_puppy_core_plugins/code_puppy_agent/register_callbacks.py +46 -0
- code_puppy_core_plugins/computer_use/NativeCapture.swift +123 -0
- code_puppy_core_plugins/computer_use/README.md +109 -0
- code_puppy_core_plugins/computer_use/__init__.py +1 -0
- code_puppy_core_plugins/computer_use/accessibility.py +163 -0
- code_puppy_core_plugins/computer_use/activation.py +75 -0
- code_puppy_core_plugins/computer_use/backend.py +584 -0
- code_puppy_core_plugins/computer_use/backend_types.py +5 -0
- code_puppy_core_plugins/computer_use/capture.py +110 -0
- code_puppy_core_plugins/computer_use/commands.py +62 -0
- code_puppy_core_plugins/computer_use/geometry.py +81 -0
- code_puppy_core_plugins/computer_use/inline_image.py +56 -0
- code_puppy_core_plugins/computer_use/keycodes.py +47 -0
- code_puppy_core_plugins/computer_use/policy.py +144 -0
- code_puppy_core_plugins/computer_use/register_callbacks.py +96 -0
- code_puppy_core_plugins/computer_use/safety.py +18 -0
- code_puppy_core_plugins/computer_use/settle.py +64 -0
- code_puppy_core_plugins/computer_use/state.py +86 -0
- code_puppy_core_plugins/computer_use/tools.py +469 -0
- code_puppy_core_plugins/context_indicator/__init__.py +14 -0
- code_puppy_core_plugins/context_indicator/register_callbacks.py +249 -0
- code_puppy_core_plugins/context_indicator/usage.py +40 -0
- code_puppy_core_plugins/copilot_auth/__init__.py +11 -0
- code_puppy_core_plugins/copilot_auth/config.py +93 -0
- code_puppy_core_plugins/copilot_auth/reasoning_client.py +409 -0
- code_puppy_core_plugins/copilot_auth/register_callbacks.py +460 -0
- code_puppy_core_plugins/copilot_auth/utils.py +587 -0
- code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
- code_puppy_core_plugins/customizable_commands/register_callbacks.py +464 -0
- code_puppy_core_plugins/dbos_durable_exec/__init__.py +1 -0
- code_puppy_core_plugins/dbos_durable_exec/cancel.py +15 -0
- code_puppy_core_plugins/dbos_durable_exec/commands.py +31 -0
- code_puppy_core_plugins/dbos_durable_exec/config.py +31 -0
- code_puppy_core_plugins/dbos_durable_exec/lifecycle.py +83 -0
- code_puppy_core_plugins/dbos_durable_exec/register_callbacks.py +45 -0
- code_puppy_core_plugins/dbos_durable_exec/runtime.py +65 -0
- code_puppy_core_plugins/dbos_durable_exec/startup_lock.py +155 -0
- code_puppy_core_plugins/dbos_durable_exec/workflow_ids.py +16 -0
- code_puppy_core_plugins/dbos_durable_exec/wrapper.py +58 -0
- code_puppy_core_plugins/destructive_command_guard/AGENTS.md +79 -0
- code_puppy_core_plugins/destructive_command_guard/__init__.py +14 -0
- code_puppy_core_plugins/destructive_command_guard/detector.py +374 -0
- code_puppy_core_plugins/destructive_command_guard/register_callbacks.py +165 -0
- code_puppy_core_plugins/emoji_filter/__init__.py +12 -0
- code_puppy_core_plugins/emoji_filter/config.py +26 -0
- code_puppy_core_plugins/emoji_filter/register_callbacks.py +238 -0
- code_puppy_core_plugins/emoji_filter/stripper.py +45 -0
- code_puppy_core_plugins/empty_html_comment_filter/register_callbacks.py +116 -0
- code_puppy_core_plugins/example_custom_command/README.md +328 -0
- code_puppy_core_plugins/example_custom_command/register_callbacks.py +66 -0
- code_puppy_core_plugins/file_permission_handler/__init__.py +4 -0
- code_puppy_core_plugins/file_permission_handler/register_callbacks.py +575 -0
- code_puppy_core_plugins/flux_bootstrap/__init__.py +5 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/README.md +173 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/cheatsheet.md +86 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/pipeline.md +167 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/synopsis.md +392 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/about.md +51 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/address-feedback.md +129 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/ask.md +211 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/aug.md +181 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/auto-pilot.md +71 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/cheatsheet.md +16 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/commit.md +103 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/config.md +108 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/create-pr.md +195 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/exec.md +221 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/new.md +151 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/qa.md +208 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/rebase.md +180 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/review.md +304 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/split.md +120 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/squash-commits.md +179 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/status.md +46 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/tests.md +155 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_about.py +154 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_cheatsheet.py +248 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_status.py +345 -0
- code_puppy_core_plugins/flux_bootstrap/installer.py +256 -0
- code_puppy_core_plugins/flux_bootstrap/register_callbacks.py +71 -0
- code_puppy_core_plugins/force_push_guard/__init__.py +5 -0
- code_puppy_core_plugins/force_push_guard/detector.py +96 -0
- code_puppy_core_plugins/force_push_guard/register_callbacks.py +161 -0
- code_puppy_core_plugins/fork/__init__.py +7 -0
- code_puppy_core_plugins/fork/register_callbacks.py +445 -0
- code_puppy_core_plugins/frontend_emitter/__init__.py +25 -0
- code_puppy_core_plugins/frontend_emitter/emitter.py +249 -0
- code_puppy_core_plugins/frontend_emitter/register_callbacks.py +412 -0
- code_puppy_core_plugins/frontend_emitter/session_context.py +50 -0
- code_puppy_core_plugins/grok_oauth/__init__.py +6 -0
- code_puppy_core_plugins/grok_oauth/config.py +49 -0
- code_puppy_core_plugins/grok_oauth/oauth_flow.py +213 -0
- code_puppy_core_plugins/grok_oauth/register_callbacks.py +132 -0
- code_puppy_core_plugins/grok_oauth/utils.py +195 -0
- code_puppy_core_plugins/herdr/README.md +168 -0
- code_puppy_core_plugins/herdr/__init__.py +9 -0
- code_puppy_core_plugins/herdr/client.py +339 -0
- code_puppy_core_plugins/herdr/register_callbacks.py +140 -0
- code_puppy_core_plugins/herdr/reporter.py +212 -0
- code_puppy_core_plugins/herdr/smoke.py +143 -0
- code_puppy_core_plugins/herdr/sources.py +133 -0
- code_puppy_core_plugins/hook_creator/__init__.py +1 -0
- code_puppy_core_plugins/hook_creator/register_callbacks.py +33 -0
- code_puppy_core_plugins/hook_manager/__init__.py +1 -0
- code_puppy_core_plugins/hook_manager/config.py +290 -0
- code_puppy_core_plugins/hook_manager/hooks_menu.py +571 -0
- code_puppy_core_plugins/hook_manager/register_callbacks.py +227 -0
- code_puppy_core_plugins/meta_oauth/__init__.py +1 -0
- code_puppy_core_plugins/meta_oauth/config.py +55 -0
- code_puppy_core_plugins/meta_oauth/oauth_flow.py +109 -0
- code_puppy_core_plugins/meta_oauth/register_callbacks.py +154 -0
- code_puppy_core_plugins/meta_oauth/utils.py +252 -0
- code_puppy_core_plugins/namespace_skill_search/README.md +118 -0
- code_puppy_core_plugins/namespace_skill_search/__init__.py +15 -0
- code_puppy_core_plugins/namespace_skill_search/namespaces.py +125 -0
- code_puppy_core_plugins/namespace_skill_search/register_callbacks.py +99 -0
- code_puppy_core_plugins/namespace_skill_search/search_tool.py +158 -0
- code_puppy_core_plugins/no_tools/__init__.py +0 -0
- code_puppy_core_plugins/no_tools/register_callbacks.py +42 -0
- code_puppy_core_plugins/oauth_pasteback.py +110 -0
- code_puppy_core_plugins/oauth_puppy_html.py +194 -0
- code_puppy_core_plugins/obsidian_agent/README.md +52 -0
- code_puppy_core_plugins/obsidian_agent/__init__.py +8 -0
- code_puppy_core_plugins/obsidian_agent/agent_obsidian.py +147 -0
- code_puppy_core_plugins/obsidian_agent/register_callbacks.py +13 -0
- code_puppy_core_plugins/ollama/__init__.py +1 -0
- code_puppy_core_plugins/ollama/register_callbacks.py +127 -0
- code_puppy_core_plugins/ollama_setup/__init__.py +5 -0
- code_puppy_core_plugins/ollama_setup/completer.py +38 -0
- code_puppy_core_plugins/ollama_setup/register_callbacks.py +419 -0
- code_puppy_core_plugins/plugin_list/__init__.py +0 -0
- code_puppy_core_plugins/plugin_list/plugin_contributions.py +348 -0
- code_puppy_core_plugins/plugin_list/plugin_meta.py +67 -0
- code_puppy_core_plugins/plugin_list/plugin_text_utils.py +173 -0
- code_puppy_core_plugins/plugin_list/plugins_menu.py +455 -0
- code_puppy_core_plugins/plugin_list/plugins_menu_layout.py +194 -0
- code_puppy_core_plugins/plugin_list/plugins_menu_render.py +431 -0
- code_puppy_core_plugins/plugin_list/project_trust_flow.py +162 -0
- code_puppy_core_plugins/plugin_list/register_callbacks.py +281 -0
- code_puppy_core_plugins/pop_command/__init__.py +1 -0
- code_puppy_core_plugins/pop_command/register_callbacks.py +191 -0
- code_puppy_core_plugins/prompt_newline/__init__.py +13 -0
- code_puppy_core_plugins/prompt_newline/config.py +21 -0
- code_puppy_core_plugins/prompt_newline/register_callbacks.py +163 -0
- code_puppy_core_plugins/prune/__init__.py +1 -0
- code_puppy_core_plugins/prune/prune_menu.py +308 -0
- code_puppy_core_plugins/prune/prune_model.py +517 -0
- code_puppy_core_plugins/prune/prune_render.py +354 -0
- code_puppy_core_plugins/prune/register_callbacks.py +388 -0
- code_puppy_core_plugins/puppy_kennel/README.md +203 -0
- code_puppy_core_plugins/puppy_kennel/__init__.py +6 -0
- code_puppy_core_plugins/puppy_kennel/commands.py +206 -0
- code_puppy_core_plugins/puppy_kennel/config.py +36 -0
- code_puppy_core_plugins/puppy_kennel/kennel.py +368 -0
- code_puppy_core_plugins/puppy_kennel/packer.py +152 -0
- code_puppy_core_plugins/puppy_kennel/recorder.py +83 -0
- code_puppy_core_plugins/puppy_kennel/register_callbacks.py +109 -0
- code_puppy_core_plugins/puppy_kennel/retriever.py +28 -0
- code_puppy_core_plugins/puppy_kennel/schema.py +78 -0
- code_puppy_core_plugins/puppy_kennel/state.py +68 -0
- code_puppy_core_plugins/puppy_kennel/tools.py +449 -0
- code_puppy_core_plugins/puppy_kennel/wings.py +110 -0
- code_puppy_core_plugins/puppy_spinner/README.md +93 -0
- code_puppy_core_plugins/puppy_spinner/__init__.py +11 -0
- code_puppy_core_plugins/puppy_spinner/builtin_frames.py +172 -0
- code_puppy_core_plugins/puppy_spinner/commands.py +116 -0
- code_puppy_core_plugins/puppy_spinner/picker.py +379 -0
- code_puppy_core_plugins/puppy_spinner/register_callbacks.py +193 -0
- code_puppy_core_plugins/puppy_spinner/spinners.py +444 -0
- code_puppy_core_plugins/quick_resume/__init__.py +0 -0
- code_puppy_core_plugins/quick_resume/register_callbacks.py +77 -0
- code_puppy_core_plugins/review_pr/__init__.py +1 -0
- code_puppy_core_plugins/review_pr/register_callbacks.py +162 -0
- code_puppy_core_plugins/shell_safety/__init__.py +6 -0
- code_puppy_core_plugins/shell_safety/agent_shell_safety.py +69 -0
- code_puppy_core_plugins/shell_safety/command_cache.py +156 -0
- code_puppy_core_plugins/shell_safety/register_callbacks.py +203 -0
- code_puppy_core_plugins/stack_dump/__init__.py +1 -0
- code_puppy_core_plugins/stack_dump/register_callbacks.py +79 -0
- code_puppy_core_plugins/statusline/__init__.py +14 -0
- code_puppy_core_plugins/statusline/config.py +68 -0
- code_puppy_core_plugins/statusline/payload.py +138 -0
- code_puppy_core_plugins/statusline/prompt_patch.py +76 -0
- code_puppy_core_plugins/statusline/register_callbacks.py +45 -0
- code_puppy_core_plugins/statusline/runner.py +122 -0
- code_puppy_core_plugins/statusline/statusline_command.py +197 -0
- code_puppy_core_plugins/steer_queue/__init__.py +10 -0
- code_puppy_core_plugins/steer_queue/queue_menu.py +444 -0
- code_puppy_core_plugins/steer_queue/register_callbacks.py +138 -0
- code_puppy_core_plugins/subagent_panel/README.md +102 -0
- code_puppy_core_plugins/subagent_panel/__init__.py +24 -0
- code_puppy_core_plugins/subagent_panel/coalesce_patch.py +242 -0
- code_puppy_core_plugins/subagent_panel/panel_render.py +145 -0
- code_puppy_core_plugins/subagent_panel/register_callbacks.py +535 -0
- code_puppy_core_plugins/subagent_panel/resume_repaint.py +112 -0
- code_puppy_core_plugins/subagent_panel/state.py +231 -0
- code_puppy_core_plugins/switch_agent_resume/__init__.py +5 -0
- code_puppy_core_plugins/switch_agent_resume/register_callbacks.py +314 -0
- code_puppy_core_plugins/theme/README.md +86 -0
- code_puppy_core_plugins/theme/__init__.py +14 -0
- code_puppy_core_plugins/theme/bundled_palettes.py +346 -0
- code_puppy_core_plugins/theme/content_styles.py +146 -0
- code_puppy_core_plugins/theme/osc_palette.py +178 -0
- code_puppy_core_plugins/theme/picker.py +358 -0
- code_puppy_core_plugins/theme/prompt_toolkit_theme.py +113 -0
- code_puppy_core_plugins/theme/register_callbacks.py +348 -0
- code_puppy_core_plugins/theme/rich_themes.py +202 -0
- code_puppy_core_plugins/theme/themes.py +720 -0
- code_puppy_core_plugins/timestamp_heartbeat/__init__.py +1 -0
- code_puppy_core_plugins/timestamp_heartbeat/register_callbacks.py +114 -0
- code_puppy_core_plugins/token_ratio_learner/__init__.py +5 -0
- code_puppy_core_plugins/token_ratio_learner/ratios.py +208 -0
- code_puppy_core_plugins/token_ratio_learner/register_callbacks.py +213 -0
- code_puppy_core_plugins/universal_constructor/__init__.py +13 -0
- code_puppy_core_plugins/universal_constructor/models.py +138 -0
- code_puppy_core_plugins/universal_constructor/provider.py +62 -0
- code_puppy_core_plugins/universal_constructor/register_callbacks.py +75 -0
- code_puppy_core_plugins/universal_constructor/registry.py +302 -0
- code_puppy_core_plugins/universal_constructor/sandbox.py +584 -0
- code_puppy_core_plugins/wide_completion_menu/__init__.py +6 -0
- code_puppy_core_plugins/wide_completion_menu/register_callbacks.py +165 -0
- code_puppy_core_plugins/wiggum/__init__.py +1 -0
- code_puppy_core_plugins/wiggum/goal_runs.py +91 -0
- code_puppy_core_plugins/wiggum/judge.py +299 -0
- code_puppy_core_plugins/wiggum/judge_config.py +249 -0
- code_puppy_core_plugins/wiggum/judges_menu.py +814 -0
- code_puppy_core_plugins/wiggum/register_callbacks.py +569 -0
- code_puppy_core_plugins/wiggum/state.py +89 -0
- code_puppy_core_plugins/yolo_cli/__init__.py +1 -0
- code_puppy_core_plugins/yolo_cli/register_callbacks.py +41 -0
- code_puppy_core_plugins-0.0.2.dist-info/METADATA +64 -0
- code_puppy_core_plugins-0.0.2.dist-info/RECORD +313 -0
- code_puppy_core_plugins-0.0.2.dist-info/WHEEL +4 -0
- code_puppy_core_plugins-0.0.2.dist-info/entry_points.txt +55 -0
- code_puppy_core_plugins-0.0.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""/theme — pick a curated banner+content color theme, interactively or by name.
|
|
2
|
+
|
|
3
|
+
UX:
|
|
4
|
+
/theme → interactive split-panel picker with live preview
|
|
5
|
+
/theme <N> → apply theme number N (1-16)
|
|
6
|
+
/theme <name> → apply by name (ocean, forest, sunset, vaporwave,
|
|
7
|
+
bubblegum-pink, purple-puppy, mocha, latte,
|
|
8
|
+
tokyo-night, green-screen, deep-black, solarized-light,
|
|
9
|
+
github-light, rose-pine-dawn, surprise, default)
|
|
10
|
+
/theme reset → restore Code Puppy defaults (alias of /theme default)
|
|
11
|
+
/theme show → show current banner → color mapping
|
|
12
|
+
|
|
13
|
+
The 15th option (Surprise Me) re-rolls a random palette every time.
|
|
14
|
+
The 16th option (Restore Defaults) puts everything back to factory.
|
|
15
|
+
|
|
16
|
+
Plays nice with /colors — same color pool, same config keys.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import asyncio
|
|
22
|
+
import concurrent.futures
|
|
23
|
+
from typing import TYPE_CHECKING
|
|
24
|
+
|
|
25
|
+
from code_puppy.callbacks import register_callback
|
|
26
|
+
|
|
27
|
+
# NOTE: Keep heavy theme/TUI imports inside callers so plugin discovery stays
|
|
28
|
+
# fast; the deferred style import saves startup time. Caveat: theme/__init__.py
|
|
29
|
+
# still eagerly imports style modules/reapplies config, so prompt_toolkit remains
|
|
30
|
+
# on the startup path until that sweep is deferred too.
|
|
31
|
+
|
|
32
|
+
_INTERACTIVE_TIMEOUT_SECONDS = 300 # 5 min — generous; user is browsing
|
|
33
|
+
_ACTIVE_THEME_CONFIG_KEY = "theme_active_theme"
|
|
34
|
+
_DEFAULT_THEME_NAME = "tokyo-night"
|
|
35
|
+
_LEGACY_THEME_NAME = "legacy-custom"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _custom_help():
|
|
39
|
+
return [
|
|
40
|
+
("theme", "Pick a curated banner+content color theme (interactive: /theme)"),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Rendering helpers: emit_info escapes Rich markup, while picker previews use Rich.
|
|
45
|
+
def _format_banner_mapping(mapping: dict[str, str]) -> str:
|
|
46
|
+
from code_puppy.command_line.colors_menu import BANNER_DISPLAY_INFO
|
|
47
|
+
|
|
48
|
+
lines = []
|
|
49
|
+
for banner, color in mapping.items():
|
|
50
|
+
display, icon = BANNER_DISPLAY_INFO.get(banner, (banner, ""))
|
|
51
|
+
prefix = f"{icon} " if icon else " "
|
|
52
|
+
lines.append(f" {prefix}{display:<24} -> {color}")
|
|
53
|
+
return "\n".join(lines)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _format_content_mapping(mapping: dict[str, str]) -> str:
|
|
57
|
+
lines = []
|
|
58
|
+
for key, style in mapping.items():
|
|
59
|
+
lines.append(f" {key:<14} -> {style}")
|
|
60
|
+
return "\n".join(lines)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _announce_applied(theme_name: str) -> None:
|
|
64
|
+
"""Quietly confirm the theme is applied. Mappings available via /theme show."""
|
|
65
|
+
from code_puppy.messaging import emit_info
|
|
66
|
+
|
|
67
|
+
from .themes import MENU_BY_NAME
|
|
68
|
+
|
|
69
|
+
theme = MENU_BY_NAME[theme_name]
|
|
70
|
+
emit_info(
|
|
71
|
+
f"{theme['icon']} {theme['label']} theme applied. "
|
|
72
|
+
f"(/theme show to inspect, /theme default to undo)"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# --- Interactive flow -------------------------------------------------------
|
|
77
|
+
def _run_interactive_picker() -> str | None:
|
|
78
|
+
"""Run the async TUI from a sync command handler."""
|
|
79
|
+
from .picker import interactive_theme_picker
|
|
80
|
+
|
|
81
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
82
|
+
future = executor.submit(lambda: asyncio.run(interactive_theme_picker()))
|
|
83
|
+
return future.result(timeout=_INTERACTIVE_TIMEOUT_SECONDS)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _apply_theme(theme_name: str, *, announce: bool = True) -> None:
|
|
87
|
+
"""Apply banner colors + content styles + inline remap + terminal palette.
|
|
88
|
+
|
|
89
|
+
`default` is special: resets banner config, content styles, Rich color
|
|
90
|
+
remap, AND the terminal-level OSC palette.
|
|
91
|
+
"""
|
|
92
|
+
from code_puppy.config import reset_all_banner_colors, set_config_value
|
|
93
|
+
|
|
94
|
+
from . import content_styles as cs
|
|
95
|
+
from . import osc_palette as osc
|
|
96
|
+
from . import rich_themes as rt
|
|
97
|
+
from .themes import (
|
|
98
|
+
apply,
|
|
99
|
+
color_remap_for,
|
|
100
|
+
colors_for,
|
|
101
|
+
content_styles_for,
|
|
102
|
+
terminal_palette_for,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if theme_name == "default":
|
|
106
|
+
reset_all_banner_colors()
|
|
107
|
+
cs.restore_defaults()
|
|
108
|
+
rt.restore()
|
|
109
|
+
osc.reset_palette()
|
|
110
|
+
else:
|
|
111
|
+
banner_mapping = colors_for(theme_name)
|
|
112
|
+
content_mapping = content_styles_for(theme_name)
|
|
113
|
+
remap = color_remap_for(theme_name)
|
|
114
|
+
terminal_palette = terminal_palette_for(theme_name)
|
|
115
|
+
apply(banner_mapping)
|
|
116
|
+
cs.apply_content_styles(content_mapping)
|
|
117
|
+
rt.apply_remap(remap)
|
|
118
|
+
if terminal_palette:
|
|
119
|
+
osc.apply_palette(terminal_palette)
|
|
120
|
+
|
|
121
|
+
set_config_value(_ACTIVE_THEME_CONFIG_KEY, theme_name)
|
|
122
|
+
if announce:
|
|
123
|
+
_announce_applied(theme_name)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _active_terminal_palette() -> tuple[str, dict] | None:
|
|
127
|
+
"""Return the active curated theme and its complete persisted palette."""
|
|
128
|
+
from code_puppy.config import get_value
|
|
129
|
+
|
|
130
|
+
from . import osc_palette as osc
|
|
131
|
+
|
|
132
|
+
active_theme = get_value(_ACTIVE_THEME_CONFIG_KEY)
|
|
133
|
+
if not active_theme or active_theme in {"default", _LEGACY_THEME_NAME}:
|
|
134
|
+
return None
|
|
135
|
+
palette = osc.get_saved_palette()
|
|
136
|
+
if not palette or len(palette.get("ansi") or []) < 16:
|
|
137
|
+
return None
|
|
138
|
+
return active_theme, palette
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _termflow_style(default_style):
|
|
142
|
+
"""Derive Termflow's truecolor Markdown chrome from the active theme."""
|
|
143
|
+
active = _active_terminal_palette()
|
|
144
|
+
if active is None:
|
|
145
|
+
return default_style
|
|
146
|
+
_, palette = active
|
|
147
|
+
ansi = palette["ansi"]
|
|
148
|
+
|
|
149
|
+
from termflow.render.style import RenderStyle
|
|
150
|
+
|
|
151
|
+
return RenderStyle(
|
|
152
|
+
bright=ansi[14],
|
|
153
|
+
head=ansi[10],
|
|
154
|
+
symbol=ansi[13],
|
|
155
|
+
grey=ansi[8],
|
|
156
|
+
dark=palette.get("bg", ansi[0]),
|
|
157
|
+
mid=ansi[8],
|
|
158
|
+
light=ansi[7],
|
|
159
|
+
link=ansi[12],
|
|
160
|
+
error=ansi[9],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _termflow_highlighter(default_highlighter):
|
|
165
|
+
"""Build syntax colors from the active theme instead of Monokai."""
|
|
166
|
+
active = _active_terminal_palette()
|
|
167
|
+
if active is None:
|
|
168
|
+
return default_highlighter
|
|
169
|
+
active_theme, palette = active
|
|
170
|
+
ansi = palette["ansi"]
|
|
171
|
+
|
|
172
|
+
from pygments.formatters.terminal256 import TerminalTrueColorFormatter
|
|
173
|
+
from pygments.style import Style
|
|
174
|
+
from pygments.token import (
|
|
175
|
+
Comment,
|
|
176
|
+
Error,
|
|
177
|
+
Keyword,
|
|
178
|
+
Name,
|
|
179
|
+
Number,
|
|
180
|
+
Operator,
|
|
181
|
+
String,
|
|
182
|
+
Token,
|
|
183
|
+
)
|
|
184
|
+
from termflow.syntax import Highlighter
|
|
185
|
+
|
|
186
|
+
if active_theme in {"green-screen", "green", "crt"}:
|
|
187
|
+
# Preserve monochrome phosphor while giving token classes enough
|
|
188
|
+
# separation to remain useful on both addition and deletion lines.
|
|
189
|
+
token_styles = {
|
|
190
|
+
Token: "#72a85b",
|
|
191
|
+
Comment: "#456b4f",
|
|
192
|
+
Error: "#7dff68",
|
|
193
|
+
Keyword: "#39e75f",
|
|
194
|
+
Name.Function: "#75ff87",
|
|
195
|
+
Number: "#8acb72",
|
|
196
|
+
Operator: "#63b96a",
|
|
197
|
+
String: "#9bdc79",
|
|
198
|
+
}
|
|
199
|
+
elif active_theme in {"solarized-light", "solarized"}:
|
|
200
|
+
token_styles = {
|
|
201
|
+
Token: "#657b83",
|
|
202
|
+
Comment: "#586e75",
|
|
203
|
+
Error: "#dc322f",
|
|
204
|
+
Keyword: "#859900",
|
|
205
|
+
Name.Function: "#268bd2",
|
|
206
|
+
Number: "#2aa198",
|
|
207
|
+
Operator: "#657b83",
|
|
208
|
+
String: "#2aa198",
|
|
209
|
+
}
|
|
210
|
+
else:
|
|
211
|
+
token_styles = {
|
|
212
|
+
Token: ansi[7],
|
|
213
|
+
Comment: ansi[8],
|
|
214
|
+
Error: ansi[9],
|
|
215
|
+
Keyword: ansi[13],
|
|
216
|
+
Name.Function: ansi[14],
|
|
217
|
+
Number: ansi[11],
|
|
218
|
+
Operator: ansi[6],
|
|
219
|
+
String: ansi[10],
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
theme_style = type(
|
|
223
|
+
"CodePuppyThemeStyle",
|
|
224
|
+
(Style,),
|
|
225
|
+
{"background_color": palette.get("bg"), "styles": token_styles},
|
|
226
|
+
)
|
|
227
|
+
highlighter = Highlighter()
|
|
228
|
+
highlighter._formatter = TerminalTrueColorFormatter(style=theme_style)
|
|
229
|
+
if active_theme in {"green-screen", "green", "crt"}:
|
|
230
|
+
# Added lines lean brighter/yellower; removed lines become cooler and
|
|
231
|
+
# more muted. Small shifts retain the token palette's internal contrast.
|
|
232
|
+
highlighter.diff_line_tints = {
|
|
233
|
+
"added": (10, 14, -8),
|
|
234
|
+
"removed": (-18, -4, 10),
|
|
235
|
+
}
|
|
236
|
+
return highlighter
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _prompt_text_color(default_color):
|
|
240
|
+
"""Use the active terminal foreground for the persistent prompt buffer."""
|
|
241
|
+
active = _active_terminal_palette()
|
|
242
|
+
return active[1].get("fg", default_color) if active else default_color
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
if TYPE_CHECKING:
|
|
246
|
+
from prompt_toolkit.styles import BaseStyle
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _prompt_toolkit_style(style: "BaseStyle | None" = None) -> "BaseStyle":
|
|
250
|
+
"""Lazy shim for prompt_toolkit_theme.merge_with_active_style.
|
|
251
|
+
|
|
252
|
+
The real implementation lives in .prompt_toolkit_theme which pulls in
|
|
253
|
+
prompt_toolkit.styles at import time. Deferring the import until the
|
|
254
|
+
prompt_toolkit_style callback actually fires (during REPL init, well
|
|
255
|
+
after startup) keeps that cost off the launch-time critical path.
|
|
256
|
+
|
|
257
|
+
Matches the real callable's `(style) -> BaseStyle` shape so a caller
|
|
258
|
+
passing an unexpected kwarg still gets a TypeError instead of being
|
|
259
|
+
silently swallowed.
|
|
260
|
+
"""
|
|
261
|
+
from .prompt_toolkit_theme import merge_with_active_style
|
|
262
|
+
|
|
263
|
+
return merge_with_active_style(style)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# Preserve the callback name for failure logs; the real symbol is more useful than
|
|
267
|
+
# "_prompt_toolkit_style failed".
|
|
268
|
+
_prompt_toolkit_style.__name__ = "merge_with_active_style"
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _apply_default_theme_on_first_run() -> None:
|
|
272
|
+
"""Apply Tokyo Night once, preserving explicit and legacy theme choices."""
|
|
273
|
+
from code_puppy.config import get_value
|
|
274
|
+
|
|
275
|
+
if get_value(_ACTIVE_THEME_CONFIG_KEY):
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
from code_puppy.config import set_config_value
|
|
279
|
+
|
|
280
|
+
from . import osc_palette as osc
|
|
281
|
+
|
|
282
|
+
if osc.get_saved_palette():
|
|
283
|
+
# Theme persistence predates the active-theme marker. Treat an existing
|
|
284
|
+
# palette as an intentional choice and migrate without changing it.
|
|
285
|
+
set_config_value(_ACTIVE_THEME_CONFIG_KEY, _LEGACY_THEME_NAME)
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
_apply_theme(_DEFAULT_THEME_NAME, announce=False)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# --- Command handler --------------------------------------------------------
|
|
292
|
+
def _handle_theme(command: str, name: str):
|
|
293
|
+
if name != "theme":
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
from code_puppy.config import get_all_banner_colors
|
|
297
|
+
from code_puppy.messaging import emit_error, emit_info, emit_warning
|
|
298
|
+
|
|
299
|
+
from . import content_styles as cs
|
|
300
|
+
from .themes import MENU_BY_NAME, resolve_theme_arg
|
|
301
|
+
|
|
302
|
+
parts = command.split()
|
|
303
|
+
sub = parts[1].lower() if len(parts) > 1 else ""
|
|
304
|
+
|
|
305
|
+
if sub == "":
|
|
306
|
+
try:
|
|
307
|
+
chosen = _run_interactive_picker()
|
|
308
|
+
except Exception as e: # pragma: no cover — defensive UX
|
|
309
|
+
emit_error(f"Theme picker failed: {e}")
|
|
310
|
+
return True
|
|
311
|
+
if chosen is None:
|
|
312
|
+
emit_info("🎨 Theme unchanged.")
|
|
313
|
+
return True
|
|
314
|
+
_apply_theme(chosen)
|
|
315
|
+
return True
|
|
316
|
+
|
|
317
|
+
if sub == "show":
|
|
318
|
+
emit_info(
|
|
319
|
+
"🎨 Current theme:\n"
|
|
320
|
+
"Banners:\n"
|
|
321
|
+
+ _format_banner_mapping(get_all_banner_colors())
|
|
322
|
+
+ "\nContent text:\n"
|
|
323
|
+
+ _format_content_mapping(cs.get_all_content_styles())
|
|
324
|
+
)
|
|
325
|
+
return True
|
|
326
|
+
|
|
327
|
+
theme_name = resolve_theme_arg(sub)
|
|
328
|
+
if theme_name is None:
|
|
329
|
+
valid = ", ".join(
|
|
330
|
+
k for k in MENU_BY_NAME if k not in ("random", "reset", "defaults")
|
|
331
|
+
)
|
|
332
|
+
emit_warning(
|
|
333
|
+
f"Unknown theme '{sub}'. Try /theme for the picker, "
|
|
334
|
+
f"or pick one of: {valid}."
|
|
335
|
+
)
|
|
336
|
+
return True
|
|
337
|
+
|
|
338
|
+
_apply_theme(theme_name)
|
|
339
|
+
return True
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
register_callback("startup", _apply_default_theme_on_first_run)
|
|
343
|
+
register_callback("termflow_style", _termflow_style)
|
|
344
|
+
register_callback("termflow_highlighter", _termflow_highlighter)
|
|
345
|
+
register_callback("prompt_text_color", _prompt_text_color)
|
|
346
|
+
register_callback("prompt_toolkit_style", _prompt_toolkit_style)
|
|
347
|
+
register_callback("custom_command_help", _custom_help)
|
|
348
|
+
register_callback("custom_command", _handle_theme)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Level 2 theming: live remap of inline Rich color names.
|
|
2
|
+
|
|
3
|
+
The renderer is full of hardcoded inline markup like `[bold cyan]`,
|
|
4
|
+
`[dim cyan]`, `[dim white]`, etc. Rich's stock `Theme` class can intercept
|
|
5
|
+
top-level *named styles* (`[my_style]`) but it does NOT remap base color
|
|
6
|
+
names embedded inside complex styles (`[bold cyan]` → still cyan).
|
|
7
|
+
|
|
8
|
+
So we go one level deeper: monkey-patch `Console.get_style()` on live console
|
|
9
|
+
instances. Every parsed style flows through it; we inspect the resolved
|
|
10
|
+
`Style.color` (and `bgcolor`) and swap it out if it's in our remap dict.
|
|
11
|
+
|
|
12
|
+
What we DO remap by default: "decorative" colors (cyan, blue, magenta,
|
|
13
|
+
bright_*). What we DON'T touch:
|
|
14
|
+
- red (errors must look angry)
|
|
15
|
+
- yellow (warnings)
|
|
16
|
+
- green (success / diff add)
|
|
17
|
+
- white (high-contrast text)
|
|
18
|
+
|
|
19
|
+
That keeps semantic meaning intact across all themes.
|
|
20
|
+
|
|
21
|
+
Persisted via config so the patch survives Code Puppy restarts.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import gc
|
|
27
|
+
import json
|
|
28
|
+
import weakref
|
|
29
|
+
from typing import Callable, Optional
|
|
30
|
+
|
|
31
|
+
from rich.color import Color
|
|
32
|
+
from rich.console import Console
|
|
33
|
+
from rich.style import Style
|
|
34
|
+
|
|
35
|
+
from code_puppy.config import get_value, set_config_value
|
|
36
|
+
from code_puppy.messaging import rich_renderer
|
|
37
|
+
|
|
38
|
+
# Remap registry: weak per-console records retain no dead consoles.
|
|
39
|
+
_PATCHED: "weakref.WeakKeyDictionary[Console, Callable]" = weakref.WeakKeyDictionary()
|
|
40
|
+
|
|
41
|
+
_CONFIG_KEY = "rich_color_remap_json"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# --- Color-swap mechanics ---------------------------------------------------
|
|
45
|
+
def _safe_parse(name: str) -> Optional[Color]:
|
|
46
|
+
"""Parse a color name, returning None if Rich can't handle it.
|
|
47
|
+
|
|
48
|
+
Rich's named-color set is a strict subset of what some palettes use
|
|
49
|
+
(e.g. ``cyan4`` and ``dark_orchid`` exist as banner backgrounds but
|
|
50
|
+
aren't parseable as standalone Colors). Never let one bad name take
|
|
51
|
+
down rendering.
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
return Color.parse(name)
|
|
55
|
+
except Exception:
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _swap_color(style: Style, remap: dict[str, str]) -> Style:
|
|
60
|
+
"""Return a new Style with color/bgcolor remapped if names match."""
|
|
61
|
+
changes = {}
|
|
62
|
+
if style.color is not None and style.color.name in remap:
|
|
63
|
+
new = _safe_parse(remap[style.color.name])
|
|
64
|
+
if new is not None:
|
|
65
|
+
changes["color"] = new
|
|
66
|
+
if style.bgcolor is not None and style.bgcolor.name in remap:
|
|
67
|
+
new = _safe_parse(remap[style.bgcolor.name])
|
|
68
|
+
if new is not None:
|
|
69
|
+
changes["bgcolor"] = new
|
|
70
|
+
if not changes:
|
|
71
|
+
return style
|
|
72
|
+
return style + Style(**changes)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _install_patch(console: Console, remap: dict[str, str]) -> None:
|
|
76
|
+
"""Patch a console's get_style to apply the remap. Idempotent."""
|
|
77
|
+
if not remap:
|
|
78
|
+
_uninstall_patch(console)
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
if console in _PATCHED:
|
|
82
|
+
# Already patched — just swap the remap (closure captures it).
|
|
83
|
+
# Re-install to refresh the captured remap dict.
|
|
84
|
+
_uninstall_patch(console)
|
|
85
|
+
|
|
86
|
+
original = console.get_style
|
|
87
|
+
|
|
88
|
+
def patched(name, *, default=None):
|
|
89
|
+
style = original(name, default=default)
|
|
90
|
+
return _swap_color(style, remap)
|
|
91
|
+
|
|
92
|
+
console.get_style = patched # type: ignore[method-assign]
|
|
93
|
+
_PATCHED[console] = original
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _uninstall_patch(console: Console) -> None:
|
|
97
|
+
"""Restore a console's original get_style. Safe if not patched."""
|
|
98
|
+
original = _PATCHED.pop(console, None)
|
|
99
|
+
if original is not None:
|
|
100
|
+
try:
|
|
101
|
+
console.get_style = original # type: ignore[method-assign]
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# --- Live-console discovery -------------------------------------------------
|
|
107
|
+
def _live_consoles() -> list[Console]:
|
|
108
|
+
"""Find every live rich.console.Console instance via gc.
|
|
109
|
+
|
|
110
|
+
Cheap heuristic but reliable. We patch them all so subagent renderers
|
|
111
|
+
and the interactive renderer get themed alongside the bus renderer.
|
|
112
|
+
"""
|
|
113
|
+
consoles: list[Console] = []
|
|
114
|
+
try:
|
|
115
|
+
for obj in gc.get_objects():
|
|
116
|
+
if isinstance(obj, Console):
|
|
117
|
+
consoles.append(obj)
|
|
118
|
+
# Also grab any Console hanging off a live RichConsoleRenderer
|
|
119
|
+
# (belt-and-suspenders; usually already covered by the above).
|
|
120
|
+
for obj in gc.get_objects():
|
|
121
|
+
if isinstance(obj, rich_renderer.RichConsoleRenderer):
|
|
122
|
+
c = getattr(obj, "_console", None)
|
|
123
|
+
if isinstance(c, Console) and c not in consoles:
|
|
124
|
+
consoles.append(c)
|
|
125
|
+
except Exception:
|
|
126
|
+
pass
|
|
127
|
+
return consoles
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# --- Public API -------------------------------------------------------------
|
|
131
|
+
def apply_remap(remap: dict[str, str], persist: bool = True) -> int:
|
|
132
|
+
"""Apply a color remap to every live Console. Returns how many got patched.
|
|
133
|
+
|
|
134
|
+
Empty remap = restore (un-patch everything).
|
|
135
|
+
"""
|
|
136
|
+
consoles = _live_consoles()
|
|
137
|
+
if remap:
|
|
138
|
+
for c in consoles:
|
|
139
|
+
_install_patch(c, remap)
|
|
140
|
+
else:
|
|
141
|
+
for c in consoles:
|
|
142
|
+
_uninstall_patch(c)
|
|
143
|
+
|
|
144
|
+
if persist:
|
|
145
|
+
try:
|
|
146
|
+
set_config_value(_CONFIG_KEY, json.dumps(remap))
|
|
147
|
+
except Exception:
|
|
148
|
+
pass
|
|
149
|
+
return len(consoles)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def restore() -> int:
|
|
153
|
+
"""Remove the color remap from every live console."""
|
|
154
|
+
return apply_remap({}, persist=True)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_saved_remap() -> dict[str, str]:
|
|
158
|
+
"""Read the persisted remap from config (or {} if none)."""
|
|
159
|
+
raw = get_value(_CONFIG_KEY)
|
|
160
|
+
if not raw:
|
|
161
|
+
return {}
|
|
162
|
+
try:
|
|
163
|
+
data = json.loads(raw)
|
|
164
|
+
if isinstance(data, dict):
|
|
165
|
+
return {str(k): str(v) for k, v in data.items()}
|
|
166
|
+
except Exception:
|
|
167
|
+
pass
|
|
168
|
+
return {}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def reapply_from_config() -> None:
|
|
172
|
+
"""Push any persisted remap back into live consoles. Safe to call repeatedly."""
|
|
173
|
+
remap = get_saved_remap()
|
|
174
|
+
if remap:
|
|
175
|
+
apply_remap(remap, persist=False)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# --- Reasonable default palette presets -------------------------------------
|
|
179
|
+
# Used by themes.py. Keep semantic colors (red/yellow/green) untouched.
|
|
180
|
+
def make_remap(
|
|
181
|
+
cyan: Optional[str] = None,
|
|
182
|
+
blue: Optional[str] = None,
|
|
183
|
+
magenta: Optional[str] = None,
|
|
184
|
+
bright_cyan: Optional[str] = None,
|
|
185
|
+
bright_blue: Optional[str] = None,
|
|
186
|
+
bright_magenta: Optional[str] = None,
|
|
187
|
+
white: Optional[str] = None,
|
|
188
|
+
bright_white: Optional[str] = None,
|
|
189
|
+
) -> dict[str, str]:
|
|
190
|
+
"""Build a clean remap dict from optional kwargs (None = skip)."""
|
|
191
|
+
mapping = {
|
|
192
|
+
"cyan": cyan,
|
|
193
|
+
"blue": blue,
|
|
194
|
+
"magenta": magenta,
|
|
195
|
+
"bright_cyan": bright_cyan,
|
|
196
|
+
"bright_blue": bright_blue,
|
|
197
|
+
"bright_magenta": bright_magenta,
|
|
198
|
+
"white": white,
|
|
199
|
+
"bright_white": bright_white,
|
|
200
|
+
}
|
|
201
|
+
# Drop entries Rich can't parse so a typo in a theme never crashes the UI.
|
|
202
|
+
return {k: v for k, v in mapping.items() if v and _safe_parse(v) is not None}
|