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.
Files changed (313) hide show
  1. code_puppy_core_plugins/__init__.py +5 -0
  2. code_puppy_core_plugins/acp/README.md +266 -0
  3. code_puppy_core_plugins/acp/__init__.py +8 -0
  4. code_puppy_core_plugins/acp/agent.py +494 -0
  5. code_puppy_core_plugins/acp/bridge.py +309 -0
  6. code_puppy_core_plugins/acp/capabilities.py +73 -0
  7. code_puppy_core_plugins/acp/commands.py +116 -0
  8. code_puppy_core_plugins/acp/content.py +115 -0
  9. code_puppy_core_plugins/acp/io_delegation.py +231 -0
  10. code_puppy_core_plugins/acp/mcp_config.py +66 -0
  11. code_puppy_core_plugins/acp/permissions.py +159 -0
  12. code_puppy_core_plugins/acp/persistence.py +197 -0
  13. code_puppy_core_plugins/acp/register_callbacks.py +110 -0
  14. code_puppy_core_plugins/acp/replay.py +114 -0
  15. code_puppy_core_plugins/acp/session.py +329 -0
  16. code_puppy_core_plugins/acp/session_config.py +179 -0
  17. code_puppy_core_plugins/acp/state.py +135 -0
  18. code_puppy_core_plugins/agent_skills/__init__.py +22 -0
  19. code_puppy_core_plugins/agent_skills/config.py +208 -0
  20. code_puppy_core_plugins/agent_skills/discovery.py +337 -0
  21. code_puppy_core_plugins/agent_skills/downloader.py +392 -0
  22. code_puppy_core_plugins/agent_skills/enabled_skills.py +82 -0
  23. code_puppy_core_plugins/agent_skills/installer.py +22 -0
  24. code_puppy_core_plugins/agent_skills/metadata.py +219 -0
  25. code_puppy_core_plugins/agent_skills/prompt_builder.py +49 -0
  26. code_puppy_core_plugins/agent_skills/provider.py +52 -0
  27. code_puppy_core_plugins/agent_skills/register_callbacks.py +309 -0
  28. code_puppy_core_plugins/agent_skills/remote_catalog.py +322 -0
  29. code_puppy_core_plugins/agent_skills/skill_catalog.py +257 -0
  30. code_puppy_core_plugins/agent_skills/skill_commands.py +102 -0
  31. code_puppy_core_plugins/agent_skills/skills_install_menu.py +698 -0
  32. code_puppy_core_plugins/agent_skills/skills_menu.py +794 -0
  33. code_puppy_core_plugins/aws_bedrock/__init__.py +14 -0
  34. code_puppy_core_plugins/aws_bedrock/config.py +101 -0
  35. code_puppy_core_plugins/aws_bedrock/register_callbacks.py +243 -0
  36. code_puppy_core_plugins/aws_bedrock/utils.py +186 -0
  37. code_puppy_core_plugins/azure_foundry/README.md +238 -0
  38. code_puppy_core_plugins/azure_foundry/__init__.py +15 -0
  39. code_puppy_core_plugins/azure_foundry/config.py +126 -0
  40. code_puppy_core_plugins/azure_foundry/discovery.py +189 -0
  41. code_puppy_core_plugins/azure_foundry/register_callbacks.py +506 -0
  42. code_puppy_core_plugins/azure_foundry/token.py +182 -0
  43. code_puppy_core_plugins/azure_foundry/utils.py +375 -0
  44. code_puppy_core_plugins/btw/__init__.py +1 -0
  45. code_puppy_core_plugins/btw/inline_view.py +135 -0
  46. code_puppy_core_plugins/btw/register_callbacks.py +106 -0
  47. code_puppy_core_plugins/btw/side_query.py +91 -0
  48. code_puppy_core_plugins/chatgpt_oauth/IMAGEGEN_SKILL.md +83 -0
  49. code_puppy_core_plugins/chatgpt_oauth/__init__.py +8 -0
  50. code_puppy_core_plugins/chatgpt_oauth/config.py +52 -0
  51. code_puppy_core_plugins/chatgpt_oauth/image_generation.py +253 -0
  52. code_puppy_core_plugins/chatgpt_oauth/image_tool.py +70 -0
  53. code_puppy_core_plugins/chatgpt_oauth/oauth_flow.py +461 -0
  54. code_puppy_core_plugins/chatgpt_oauth/register_callbacks.py +288 -0
  55. code_puppy_core_plugins/chatgpt_oauth/test_plugin.py +663 -0
  56. code_puppy_core_plugins/chatgpt_oauth/usage.py +113 -0
  57. code_puppy_core_plugins/chatgpt_oauth/utils.py +534 -0
  58. code_puppy_core_plugins/claude_code_hooks/__init__.py +1 -0
  59. code_puppy_core_plugins/claude_code_hooks/config.py +137 -0
  60. code_puppy_core_plugins/claude_code_hooks/register_callbacks.py +383 -0
  61. code_puppy_core_plugins/claude_code_oauth/README.md +167 -0
  62. code_puppy_core_plugins/claude_code_oauth/SETUP.md +93 -0
  63. code_puppy_core_plugins/claude_code_oauth/__init__.py +25 -0
  64. code_puppy_core_plugins/claude_code_oauth/config.py +59 -0
  65. code_puppy_core_plugins/claude_code_oauth/fast_mode.py +122 -0
  66. code_puppy_core_plugins/claude_code_oauth/prompt_handler.py +64 -0
  67. code_puppy_core_plugins/claude_code_oauth/register_callbacks.py +719 -0
  68. code_puppy_core_plugins/claude_code_oauth/test_plugin.py +285 -0
  69. code_puppy_core_plugins/claude_code_oauth/token_refresh_heartbeat.py +240 -0
  70. code_puppy_core_plugins/claude_code_oauth/utils.py +663 -0
  71. code_puppy_core_plugins/code_puppy_agent/AGENTS_AND_TOOLS.md +155 -0
  72. code_puppy_core_plugins/code_puppy_agent/MODELS_AND_MCP.md +104 -0
  73. code_puppy_core_plugins/code_puppy_agent/PLUGINS_AND_CALLBACKS.md +147 -0
  74. code_puppy_core_plugins/code_puppy_agent/SESSIONS_AND_HISTORY.md +39 -0
  75. code_puppy_core_plugins/code_puppy_agent/SKILL.md +180 -0
  76. code_puppy_core_plugins/code_puppy_agent/SKILLS_SYSTEM.md +136 -0
  77. code_puppy_core_plugins/code_puppy_agent/SYSTEM_PROMPT_CONFIG_AND_I18N.md +160 -0
  78. code_puppy_core_plugins/code_puppy_agent/__init__.py +5 -0
  79. code_puppy_core_plugins/code_puppy_agent/register_callbacks.py +46 -0
  80. code_puppy_core_plugins/computer_use/NativeCapture.swift +123 -0
  81. code_puppy_core_plugins/computer_use/README.md +109 -0
  82. code_puppy_core_plugins/computer_use/__init__.py +1 -0
  83. code_puppy_core_plugins/computer_use/accessibility.py +163 -0
  84. code_puppy_core_plugins/computer_use/activation.py +75 -0
  85. code_puppy_core_plugins/computer_use/backend.py +584 -0
  86. code_puppy_core_plugins/computer_use/backend_types.py +5 -0
  87. code_puppy_core_plugins/computer_use/capture.py +110 -0
  88. code_puppy_core_plugins/computer_use/commands.py +62 -0
  89. code_puppy_core_plugins/computer_use/geometry.py +81 -0
  90. code_puppy_core_plugins/computer_use/inline_image.py +56 -0
  91. code_puppy_core_plugins/computer_use/keycodes.py +47 -0
  92. code_puppy_core_plugins/computer_use/policy.py +144 -0
  93. code_puppy_core_plugins/computer_use/register_callbacks.py +96 -0
  94. code_puppy_core_plugins/computer_use/safety.py +18 -0
  95. code_puppy_core_plugins/computer_use/settle.py +64 -0
  96. code_puppy_core_plugins/computer_use/state.py +86 -0
  97. code_puppy_core_plugins/computer_use/tools.py +469 -0
  98. code_puppy_core_plugins/context_indicator/__init__.py +14 -0
  99. code_puppy_core_plugins/context_indicator/register_callbacks.py +249 -0
  100. code_puppy_core_plugins/context_indicator/usage.py +40 -0
  101. code_puppy_core_plugins/copilot_auth/__init__.py +11 -0
  102. code_puppy_core_plugins/copilot_auth/config.py +93 -0
  103. code_puppy_core_plugins/copilot_auth/reasoning_client.py +409 -0
  104. code_puppy_core_plugins/copilot_auth/register_callbacks.py +460 -0
  105. code_puppy_core_plugins/copilot_auth/utils.py +587 -0
  106. code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
  107. code_puppy_core_plugins/customizable_commands/register_callbacks.py +464 -0
  108. code_puppy_core_plugins/dbos_durable_exec/__init__.py +1 -0
  109. code_puppy_core_plugins/dbos_durable_exec/cancel.py +15 -0
  110. code_puppy_core_plugins/dbos_durable_exec/commands.py +31 -0
  111. code_puppy_core_plugins/dbos_durable_exec/config.py +31 -0
  112. code_puppy_core_plugins/dbos_durable_exec/lifecycle.py +83 -0
  113. code_puppy_core_plugins/dbos_durable_exec/register_callbacks.py +45 -0
  114. code_puppy_core_plugins/dbos_durable_exec/runtime.py +65 -0
  115. code_puppy_core_plugins/dbos_durable_exec/startup_lock.py +155 -0
  116. code_puppy_core_plugins/dbos_durable_exec/workflow_ids.py +16 -0
  117. code_puppy_core_plugins/dbos_durable_exec/wrapper.py +58 -0
  118. code_puppy_core_plugins/destructive_command_guard/AGENTS.md +79 -0
  119. code_puppy_core_plugins/destructive_command_guard/__init__.py +14 -0
  120. code_puppy_core_plugins/destructive_command_guard/detector.py +374 -0
  121. code_puppy_core_plugins/destructive_command_guard/register_callbacks.py +165 -0
  122. code_puppy_core_plugins/emoji_filter/__init__.py +12 -0
  123. code_puppy_core_plugins/emoji_filter/config.py +26 -0
  124. code_puppy_core_plugins/emoji_filter/register_callbacks.py +238 -0
  125. code_puppy_core_plugins/emoji_filter/stripper.py +45 -0
  126. code_puppy_core_plugins/empty_html_comment_filter/register_callbacks.py +116 -0
  127. code_puppy_core_plugins/example_custom_command/README.md +328 -0
  128. code_puppy_core_plugins/example_custom_command/register_callbacks.py +66 -0
  129. code_puppy_core_plugins/file_permission_handler/__init__.py +4 -0
  130. code_puppy_core_plugins/file_permission_handler/register_callbacks.py +575 -0
  131. code_puppy_core_plugins/flux_bootstrap/__init__.py +5 -0
  132. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/README.md +173 -0
  133. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/cheatsheet.md +86 -0
  134. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/pipeline.md +167 -0
  135. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/synopsis.md +392 -0
  136. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/about.md +51 -0
  137. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/address-feedback.md +129 -0
  138. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/ask.md +211 -0
  139. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/aug.md +181 -0
  140. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/auto-pilot.md +71 -0
  141. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/cheatsheet.md +16 -0
  142. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/commit.md +103 -0
  143. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/config.md +108 -0
  144. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/create-pr.md +195 -0
  145. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/exec.md +221 -0
  146. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/new.md +151 -0
  147. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/qa.md +208 -0
  148. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/rebase.md +180 -0
  149. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/review.md +304 -0
  150. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/split.md +120 -0
  151. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/squash-commits.md +179 -0
  152. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/status.md +46 -0
  153. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/tests.md +155 -0
  154. code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_about.py +154 -0
  155. code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_cheatsheet.py +248 -0
  156. code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_status.py +345 -0
  157. code_puppy_core_plugins/flux_bootstrap/installer.py +256 -0
  158. code_puppy_core_plugins/flux_bootstrap/register_callbacks.py +71 -0
  159. code_puppy_core_plugins/force_push_guard/__init__.py +5 -0
  160. code_puppy_core_plugins/force_push_guard/detector.py +96 -0
  161. code_puppy_core_plugins/force_push_guard/register_callbacks.py +161 -0
  162. code_puppy_core_plugins/fork/__init__.py +7 -0
  163. code_puppy_core_plugins/fork/register_callbacks.py +445 -0
  164. code_puppy_core_plugins/frontend_emitter/__init__.py +25 -0
  165. code_puppy_core_plugins/frontend_emitter/emitter.py +249 -0
  166. code_puppy_core_plugins/frontend_emitter/register_callbacks.py +412 -0
  167. code_puppy_core_plugins/frontend_emitter/session_context.py +50 -0
  168. code_puppy_core_plugins/grok_oauth/__init__.py +6 -0
  169. code_puppy_core_plugins/grok_oauth/config.py +49 -0
  170. code_puppy_core_plugins/grok_oauth/oauth_flow.py +213 -0
  171. code_puppy_core_plugins/grok_oauth/register_callbacks.py +132 -0
  172. code_puppy_core_plugins/grok_oauth/utils.py +195 -0
  173. code_puppy_core_plugins/herdr/README.md +168 -0
  174. code_puppy_core_plugins/herdr/__init__.py +9 -0
  175. code_puppy_core_plugins/herdr/client.py +339 -0
  176. code_puppy_core_plugins/herdr/register_callbacks.py +140 -0
  177. code_puppy_core_plugins/herdr/reporter.py +212 -0
  178. code_puppy_core_plugins/herdr/smoke.py +143 -0
  179. code_puppy_core_plugins/herdr/sources.py +133 -0
  180. code_puppy_core_plugins/hook_creator/__init__.py +1 -0
  181. code_puppy_core_plugins/hook_creator/register_callbacks.py +33 -0
  182. code_puppy_core_plugins/hook_manager/__init__.py +1 -0
  183. code_puppy_core_plugins/hook_manager/config.py +290 -0
  184. code_puppy_core_plugins/hook_manager/hooks_menu.py +571 -0
  185. code_puppy_core_plugins/hook_manager/register_callbacks.py +227 -0
  186. code_puppy_core_plugins/meta_oauth/__init__.py +1 -0
  187. code_puppy_core_plugins/meta_oauth/config.py +55 -0
  188. code_puppy_core_plugins/meta_oauth/oauth_flow.py +109 -0
  189. code_puppy_core_plugins/meta_oauth/register_callbacks.py +154 -0
  190. code_puppy_core_plugins/meta_oauth/utils.py +252 -0
  191. code_puppy_core_plugins/namespace_skill_search/README.md +118 -0
  192. code_puppy_core_plugins/namespace_skill_search/__init__.py +15 -0
  193. code_puppy_core_plugins/namespace_skill_search/namespaces.py +125 -0
  194. code_puppy_core_plugins/namespace_skill_search/register_callbacks.py +99 -0
  195. code_puppy_core_plugins/namespace_skill_search/search_tool.py +158 -0
  196. code_puppy_core_plugins/no_tools/__init__.py +0 -0
  197. code_puppy_core_plugins/no_tools/register_callbacks.py +42 -0
  198. code_puppy_core_plugins/oauth_pasteback.py +110 -0
  199. code_puppy_core_plugins/oauth_puppy_html.py +194 -0
  200. code_puppy_core_plugins/obsidian_agent/README.md +52 -0
  201. code_puppy_core_plugins/obsidian_agent/__init__.py +8 -0
  202. code_puppy_core_plugins/obsidian_agent/agent_obsidian.py +147 -0
  203. code_puppy_core_plugins/obsidian_agent/register_callbacks.py +13 -0
  204. code_puppy_core_plugins/ollama/__init__.py +1 -0
  205. code_puppy_core_plugins/ollama/register_callbacks.py +127 -0
  206. code_puppy_core_plugins/ollama_setup/__init__.py +5 -0
  207. code_puppy_core_plugins/ollama_setup/completer.py +38 -0
  208. code_puppy_core_plugins/ollama_setup/register_callbacks.py +419 -0
  209. code_puppy_core_plugins/plugin_list/__init__.py +0 -0
  210. code_puppy_core_plugins/plugin_list/plugin_contributions.py +348 -0
  211. code_puppy_core_plugins/plugin_list/plugin_meta.py +67 -0
  212. code_puppy_core_plugins/plugin_list/plugin_text_utils.py +173 -0
  213. code_puppy_core_plugins/plugin_list/plugins_menu.py +455 -0
  214. code_puppy_core_plugins/plugin_list/plugins_menu_layout.py +194 -0
  215. code_puppy_core_plugins/plugin_list/plugins_menu_render.py +431 -0
  216. code_puppy_core_plugins/plugin_list/project_trust_flow.py +162 -0
  217. code_puppy_core_plugins/plugin_list/register_callbacks.py +281 -0
  218. code_puppy_core_plugins/pop_command/__init__.py +1 -0
  219. code_puppy_core_plugins/pop_command/register_callbacks.py +191 -0
  220. code_puppy_core_plugins/prompt_newline/__init__.py +13 -0
  221. code_puppy_core_plugins/prompt_newline/config.py +21 -0
  222. code_puppy_core_plugins/prompt_newline/register_callbacks.py +163 -0
  223. code_puppy_core_plugins/prune/__init__.py +1 -0
  224. code_puppy_core_plugins/prune/prune_menu.py +308 -0
  225. code_puppy_core_plugins/prune/prune_model.py +517 -0
  226. code_puppy_core_plugins/prune/prune_render.py +354 -0
  227. code_puppy_core_plugins/prune/register_callbacks.py +388 -0
  228. code_puppy_core_plugins/puppy_kennel/README.md +203 -0
  229. code_puppy_core_plugins/puppy_kennel/__init__.py +6 -0
  230. code_puppy_core_plugins/puppy_kennel/commands.py +206 -0
  231. code_puppy_core_plugins/puppy_kennel/config.py +36 -0
  232. code_puppy_core_plugins/puppy_kennel/kennel.py +368 -0
  233. code_puppy_core_plugins/puppy_kennel/packer.py +152 -0
  234. code_puppy_core_plugins/puppy_kennel/recorder.py +83 -0
  235. code_puppy_core_plugins/puppy_kennel/register_callbacks.py +109 -0
  236. code_puppy_core_plugins/puppy_kennel/retriever.py +28 -0
  237. code_puppy_core_plugins/puppy_kennel/schema.py +78 -0
  238. code_puppy_core_plugins/puppy_kennel/state.py +68 -0
  239. code_puppy_core_plugins/puppy_kennel/tools.py +449 -0
  240. code_puppy_core_plugins/puppy_kennel/wings.py +110 -0
  241. code_puppy_core_plugins/puppy_spinner/README.md +93 -0
  242. code_puppy_core_plugins/puppy_spinner/__init__.py +11 -0
  243. code_puppy_core_plugins/puppy_spinner/builtin_frames.py +172 -0
  244. code_puppy_core_plugins/puppy_spinner/commands.py +116 -0
  245. code_puppy_core_plugins/puppy_spinner/picker.py +379 -0
  246. code_puppy_core_plugins/puppy_spinner/register_callbacks.py +193 -0
  247. code_puppy_core_plugins/puppy_spinner/spinners.py +444 -0
  248. code_puppy_core_plugins/quick_resume/__init__.py +0 -0
  249. code_puppy_core_plugins/quick_resume/register_callbacks.py +77 -0
  250. code_puppy_core_plugins/review_pr/__init__.py +1 -0
  251. code_puppy_core_plugins/review_pr/register_callbacks.py +162 -0
  252. code_puppy_core_plugins/shell_safety/__init__.py +6 -0
  253. code_puppy_core_plugins/shell_safety/agent_shell_safety.py +69 -0
  254. code_puppy_core_plugins/shell_safety/command_cache.py +156 -0
  255. code_puppy_core_plugins/shell_safety/register_callbacks.py +203 -0
  256. code_puppy_core_plugins/stack_dump/__init__.py +1 -0
  257. code_puppy_core_plugins/stack_dump/register_callbacks.py +79 -0
  258. code_puppy_core_plugins/statusline/__init__.py +14 -0
  259. code_puppy_core_plugins/statusline/config.py +68 -0
  260. code_puppy_core_plugins/statusline/payload.py +138 -0
  261. code_puppy_core_plugins/statusline/prompt_patch.py +76 -0
  262. code_puppy_core_plugins/statusline/register_callbacks.py +45 -0
  263. code_puppy_core_plugins/statusline/runner.py +122 -0
  264. code_puppy_core_plugins/statusline/statusline_command.py +197 -0
  265. code_puppy_core_plugins/steer_queue/__init__.py +10 -0
  266. code_puppy_core_plugins/steer_queue/queue_menu.py +444 -0
  267. code_puppy_core_plugins/steer_queue/register_callbacks.py +138 -0
  268. code_puppy_core_plugins/subagent_panel/README.md +102 -0
  269. code_puppy_core_plugins/subagent_panel/__init__.py +24 -0
  270. code_puppy_core_plugins/subagent_panel/coalesce_patch.py +242 -0
  271. code_puppy_core_plugins/subagent_panel/panel_render.py +145 -0
  272. code_puppy_core_plugins/subagent_panel/register_callbacks.py +535 -0
  273. code_puppy_core_plugins/subagent_panel/resume_repaint.py +112 -0
  274. code_puppy_core_plugins/subagent_panel/state.py +231 -0
  275. code_puppy_core_plugins/switch_agent_resume/__init__.py +5 -0
  276. code_puppy_core_plugins/switch_agent_resume/register_callbacks.py +314 -0
  277. code_puppy_core_plugins/theme/README.md +86 -0
  278. code_puppy_core_plugins/theme/__init__.py +14 -0
  279. code_puppy_core_plugins/theme/bundled_palettes.py +346 -0
  280. code_puppy_core_plugins/theme/content_styles.py +146 -0
  281. code_puppy_core_plugins/theme/osc_palette.py +178 -0
  282. code_puppy_core_plugins/theme/picker.py +358 -0
  283. code_puppy_core_plugins/theme/prompt_toolkit_theme.py +113 -0
  284. code_puppy_core_plugins/theme/register_callbacks.py +348 -0
  285. code_puppy_core_plugins/theme/rich_themes.py +202 -0
  286. code_puppy_core_plugins/theme/themes.py +720 -0
  287. code_puppy_core_plugins/timestamp_heartbeat/__init__.py +1 -0
  288. code_puppy_core_plugins/timestamp_heartbeat/register_callbacks.py +114 -0
  289. code_puppy_core_plugins/token_ratio_learner/__init__.py +5 -0
  290. code_puppy_core_plugins/token_ratio_learner/ratios.py +208 -0
  291. code_puppy_core_plugins/token_ratio_learner/register_callbacks.py +213 -0
  292. code_puppy_core_plugins/universal_constructor/__init__.py +13 -0
  293. code_puppy_core_plugins/universal_constructor/models.py +138 -0
  294. code_puppy_core_plugins/universal_constructor/provider.py +62 -0
  295. code_puppy_core_plugins/universal_constructor/register_callbacks.py +75 -0
  296. code_puppy_core_plugins/universal_constructor/registry.py +302 -0
  297. code_puppy_core_plugins/universal_constructor/sandbox.py +584 -0
  298. code_puppy_core_plugins/wide_completion_menu/__init__.py +6 -0
  299. code_puppy_core_plugins/wide_completion_menu/register_callbacks.py +165 -0
  300. code_puppy_core_plugins/wiggum/__init__.py +1 -0
  301. code_puppy_core_plugins/wiggum/goal_runs.py +91 -0
  302. code_puppy_core_plugins/wiggum/judge.py +299 -0
  303. code_puppy_core_plugins/wiggum/judge_config.py +249 -0
  304. code_puppy_core_plugins/wiggum/judges_menu.py +814 -0
  305. code_puppy_core_plugins/wiggum/register_callbacks.py +569 -0
  306. code_puppy_core_plugins/wiggum/state.py +89 -0
  307. code_puppy_core_plugins/yolo_cli/__init__.py +1 -0
  308. code_puppy_core_plugins/yolo_cli/register_callbacks.py +41 -0
  309. code_puppy_core_plugins-0.0.2.dist-info/METADATA +64 -0
  310. code_puppy_core_plugins-0.0.2.dist-info/RECORD +313 -0
  311. code_puppy_core_plugins-0.0.2.dist-info/WHEEL +4 -0
  312. code_puppy_core_plugins-0.0.2.dist-info/entry_points.txt +55 -0
  313. code_puppy_core_plugins-0.0.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,720 @@
1
+ """Theme definitions and application logic.
2
+
3
+ Pure module: no I/O beyond reading/writing config via code_puppy.config and
4
+ content_styles. Testable in isolation. Zen: simple is better than complex.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import random
10
+ from itertools import cycle
11
+ from typing import Callable
12
+
13
+ from code_puppy.command_line.colors_menu import BANNER_COLORS, BANNER_DISPLAY_INFO
14
+ from code_puppy.config import set_banner_color
15
+
16
+ from . import bundled_palettes as bp
17
+ from . import content_styles as cs
18
+ from . import rich_themes as rt
19
+
20
+ # Palette = the Rich color values from /colors (deduped, sorted for determinism)
21
+ PALETTE: list[str] = sorted(set(BANNER_COLORS.values()))
22
+ BANNER_KEYS: list[str] = list(BANNER_DISPLAY_INFO.keys())
23
+
24
+
25
+ # Foreground-safe palette: exclude dark or unparseable Rich colors that work only
26
+ # as background tags.
27
+ def _parseable(name: str) -> bool:
28
+ from rich.color import Color
29
+
30
+ try:
31
+ Color.parse(name)
32
+ return True
33
+ except Exception:
34
+ return False
35
+
36
+
37
+ TEXT_PALETTE: list[str] = sorted(
38
+ {
39
+ c
40
+ for c in PALETTE
41
+ if _parseable(c)
42
+ and not any(bad in c for bad in ("black", "navy_blue", "dark_red", "grey0"))
43
+ }
44
+ )
45
+
46
+ # Curated themes cycle a small, opinionated color list across banners.
47
+ CURATED_THEMES: dict[str, dict] = {
48
+ "ocean": {
49
+ "icon": "🌊",
50
+ "label": "Ocean",
51
+ "blurb": "cool blues, cyans & teals",
52
+ "colors": [
53
+ "deep_sky_blue4",
54
+ "cyan4",
55
+ "dodger_blue3",
56
+ "dark_turquoise",
57
+ "steel_blue",
58
+ "blue",
59
+ "navy_blue",
60
+ "dark_cyan",
61
+ "aquamarine1",
62
+ ],
63
+ "content_styles": {
64
+ "info": "cyan",
65
+ "warning": "yellow",
66
+ "success": "bright_cyan",
67
+ "error": "bold red",
68
+ "debug": "dim cyan",
69
+ "diff_add": "bright_cyan",
70
+ "diff_remove": "red",
71
+ "diff_context": "dim blue",
72
+ },
73
+ "color_remap": rt.make_remap(
74
+ cyan="deep_sky_blue4",
75
+ blue="dodger_blue3",
76
+ magenta="dark_turquoise",
77
+ bright_cyan="aquamarine1",
78
+ bright_blue="steel_blue",
79
+ bright_magenta="dark_cyan",
80
+ ),
81
+ "terminal_palette": bp.OCEAN,
82
+ },
83
+ "forest": {
84
+ "icon": "🌲",
85
+ "label": "Forest",
86
+ "blurb": "earthy greens & olives",
87
+ "colors": [
88
+ "green4",
89
+ "dark_green",
90
+ "dark_sea_green4",
91
+ "spring_green4",
92
+ "chartreuse4",
93
+ "dark_olive_green3",
94
+ "dark_goldenrod",
95
+ ],
96
+ "content_styles": {
97
+ "info": "green",
98
+ "warning": "dark_goldenrod",
99
+ "success": "bright_green",
100
+ "error": "bold red",
101
+ "debug": "dim green",
102
+ "diff_add": "bright_green",
103
+ "diff_remove": "red",
104
+ "diff_context": "dim green",
105
+ },
106
+ "color_remap": rt.make_remap(
107
+ cyan="spring_green4",
108
+ blue="green4",
109
+ magenta="dark_sea_green4",
110
+ bright_cyan="chartreuse4",
111
+ bright_blue="dark_green",
112
+ bright_magenta="dark_olive_green3",
113
+ ),
114
+ "terminal_palette": bp.FOREST,
115
+ },
116
+ "sunset": {
117
+ "icon": "🌅",
118
+ "label": "Sunset",
119
+ "blurb": "warm reds, oranges & gold",
120
+ "colors": [
121
+ "orange_red1",
122
+ "dark_orange3",
123
+ "gold3",
124
+ "red3",
125
+ "indian_red",
126
+ "dark_red",
127
+ "hot_pink3",
128
+ ],
129
+ "content_styles": {
130
+ "info": "gold3",
131
+ "warning": "dark_orange3",
132
+ "success": "orange_red1",
133
+ "error": "bold red",
134
+ "debug": "dim yellow",
135
+ "diff_add": "gold3",
136
+ "diff_remove": "red3",
137
+ "diff_context": "dim yellow",
138
+ },
139
+ "color_remap": rt.make_remap(
140
+ cyan="gold3",
141
+ blue="orange_red1",
142
+ magenta="hot_pink3",
143
+ bright_cyan="dark_orange3",
144
+ bright_blue="indian_red",
145
+ bright_magenta="hot_pink3",
146
+ ),
147
+ "terminal_palette": bp.SUNSET,
148
+ },
149
+ "vaporwave": {
150
+ "icon": "🪩",
151
+ "label": "Vaporwave",
152
+ "blurb": "neon pinks & purples",
153
+ "colors": [
154
+ "hot_pink3",
155
+ "dark_magenta",
156
+ "purple",
157
+ "dark_violet",
158
+ "medium_purple4",
159
+ "dark_orchid",
160
+ "deep_pink4",
161
+ "pale_violet_red1",
162
+ ],
163
+ "content_styles": {
164
+ "info": "magenta",
165
+ "warning": "hot_pink3",
166
+ "success": "bright_magenta",
167
+ "error": "bold red",
168
+ "debug": "dim magenta",
169
+ "diff_add": "bright_magenta",
170
+ "diff_remove": "red",
171
+ "diff_context": "dim magenta",
172
+ },
173
+ "color_remap": rt.make_remap(
174
+ cyan="hot_pink3",
175
+ blue="purple",
176
+ magenta="dark_magenta",
177
+ bright_cyan="pale_violet_red1",
178
+ bright_blue="dark_violet",
179
+ bright_magenta="medium_orchid",
180
+ ),
181
+ "terminal_palette": bp.VAPORWAVE,
182
+ },
183
+ "bubblegum-pink": {
184
+ "icon": "🫧",
185
+ "label": "Bubblegum Pink",
186
+ "blurb": "sweet pinks, candy neon & glow",
187
+ "colors": [
188
+ "hot_pink3",
189
+ "deep_pink4",
190
+ "pale_violet_red1",
191
+ "magenta",
192
+ "bright_magenta",
193
+ "dark_orchid",
194
+ "medium_purple4",
195
+ "violet",
196
+ ],
197
+ "content_styles": {
198
+ "info": "hot_pink3",
199
+ "warning": "deep_pink4",
200
+ "success": "bright_magenta",
201
+ "error": "bold red",
202
+ "debug": "dim magenta",
203
+ "diff_add": "bright_magenta",
204
+ "diff_remove": "red",
205
+ "diff_context": "dim magenta",
206
+ },
207
+ "color_remap": rt.make_remap(
208
+ cyan="hot_pink3",
209
+ blue="deep_pink4",
210
+ magenta="pale_violet_red1",
211
+ bright_cyan="#ff69b4",
212
+ bright_blue="medium_purple4",
213
+ bright_magenta="violet",
214
+ ),
215
+ "terminal_palette": bp.BUBBLEGUM_PINK,
216
+ },
217
+ "purple-puppy": {
218
+ "icon": "\U0001f436", # dog face
219
+ "label": "Purple Puppy",
220
+ "blurb": "vivid violet fur, white muzzle & pink tongue",
221
+ "colors": [
222
+ "#9b30d9", # highlight fur
223
+ "#8408b0", # body fur
224
+ "#b06be8", # light fur
225
+ "#6a0dad", # shade fur
226
+ "#d9a7f5", # lilac glow
227
+ "#ff7fa8", # tongue pink
228
+ "#e8ccff", # muzzle lavender
229
+ "#4b1a6e", # deep shade
230
+ ],
231
+ "content_styles": {
232
+ "info": "#c9a0f0",
233
+ "warning": "#f5c26b",
234
+ "success": "#ff8fb3",
235
+ "error": "bold red",
236
+ "debug": "dim #b8a0d0",
237
+ "diff_add": "#ff8fb3",
238
+ "diff_remove": "red",
239
+ "diff_context": "dim #9b7fc0",
240
+ },
241
+ "color_remap": rt.make_remap(
242
+ cyan="#c9a0f0",
243
+ blue="#9b30d9",
244
+ magenta="#ff7fa8",
245
+ bright_cyan="#e8ccff",
246
+ bright_blue="#b06be8",
247
+ bright_magenta="#ff9fd2",
248
+ ),
249
+ "terminal_palette": bp.PURPLE_PUPPY,
250
+ },
251
+ # Palette-first themes use OSC ANSI slots so Rich tags follow the new palette;
252
+ # their Rich-level color_remap remains empty.
253
+ "catppuccin-mocha": {
254
+ "icon": "🐱",
255
+ "label": "Catppuccin Mocha",
256
+ "blurb": "soothing pastel dark",
257
+ "colors": [
258
+ "cyan",
259
+ "magenta",
260
+ "blue",
261
+ "green",
262
+ "yellow",
263
+ "red",
264
+ "bright_cyan",
265
+ "bright_magenta",
266
+ ],
267
+ "content_styles": {
268
+ "info": "cyan",
269
+ "warning": "yellow",
270
+ "success": "green",
271
+ "error": "bold red",
272
+ "debug": "dim white",
273
+ "diff_add": "green",
274
+ "diff_remove": "red",
275
+ "diff_context": "dim white",
276
+ },
277
+ "color_remap": {},
278
+ "terminal_palette": bp.CATPPUCCIN_MOCHA,
279
+ },
280
+ "catppuccin-latte": {
281
+ "icon": "☕",
282
+ "label": "Catppuccin Latte",
283
+ "blurb": "soft pastel light with lavender & rose",
284
+ "colors": [
285
+ "#1e66f5",
286
+ "#8839ef",
287
+ "#40a02b",
288
+ "#df8e1d",
289
+ "#04a5e5",
290
+ "#d20f39",
291
+ "#7287fd",
292
+ "#ea76cb",
293
+ ],
294
+ "content_styles": {
295
+ "info": "#1e66f5",
296
+ "warning": "#df8e1d",
297
+ "success": "#40a02b",
298
+ "error": "bold #d20f39",
299
+ "debug": "dim #4c4f69",
300
+ "diff_add": "#40a02b",
301
+ "diff_remove": "#d20f39",
302
+ "diff_context": "dim #5c5f77",
303
+ },
304
+ "color_remap": rt.make_remap(
305
+ cyan="#04a5e5",
306
+ blue="#1e66f5",
307
+ magenta="#8839ef",
308
+ bright_cyan="#179299",
309
+ bright_blue="#7287fd",
310
+ bright_magenta="#ea76cb",
311
+ ),
312
+ "terminal_palette": bp.CATPPUCCIN_LATTE,
313
+ },
314
+ "tokyo-night": {
315
+ "icon": "🌃",
316
+ "label": "Tokyo Night",
317
+ "blurb": "neon-on-navy night",
318
+ "colors": [
319
+ "blue",
320
+ "cyan",
321
+ "magenta",
322
+ "green",
323
+ "yellow",
324
+ "red",
325
+ "bright_blue",
326
+ "bright_cyan",
327
+ ],
328
+ "content_styles": {
329
+ "info": "cyan",
330
+ "warning": "yellow",
331
+ "success": "green",
332
+ "error": "bold red",
333
+ "debug": "dim white",
334
+ "diff_add": "green",
335
+ "diff_remove": "red",
336
+ "diff_context": "dim white",
337
+ },
338
+ "color_remap": {},
339
+ "terminal_palette": bp.TOKYO_NIGHT,
340
+ },
341
+ "green-screen": {
342
+ "icon": "[CRT]",
343
+ "label": "Green Screen",
344
+ "blurb": "llxprt's radioactive green phosphor CRT",
345
+ # Banner labels render as white, which this theme remaps to #6a9955.
346
+ # Keep their backgrounds dark enough for readable phosphor-on-glass.
347
+ "colors": [
348
+ "#071507",
349
+ "#0b1f0b",
350
+ "#102510",
351
+ ],
352
+ "content_styles": {
353
+ "info": "#6a9955",
354
+ "warning": "#6a9955",
355
+ "success": "#00ff00",
356
+ "error": "bold #6a9955",
357
+ "debug": "dim #4a7035",
358
+ "diff_add": "#00ff00",
359
+ "diff_remove": "#6a9955",
360
+ "diff_context": "dim #4a7035",
361
+ },
362
+ "color_remap": rt.make_remap(
363
+ cyan="#6a9955",
364
+ blue="#6a9955",
365
+ magenta="#6a9955",
366
+ bright_cyan="#6a9955",
367
+ bright_blue="#6a9955",
368
+ bright_magenta="#6a9955",
369
+ white="#6a9955",
370
+ bright_white="#00ff00",
371
+ ),
372
+ "terminal_palette": bp.GREEN_SCREEN,
373
+ },
374
+ "deep-black": {
375
+ "icon": "🌑",
376
+ "label": "Deep Black",
377
+ "blurb": "inky noir with subtle neon edge",
378
+ "colors": [
379
+ "#050505",
380
+ "#1f1f1f",
381
+ "#2b2b2b",
382
+ "#3a3a3a",
383
+ "#4dabf7",
384
+ "#b197fc",
385
+ "#63e6be",
386
+ "#ffd166",
387
+ ],
388
+ "content_styles": {
389
+ "info": "#cfd8dc",
390
+ "warning": "#ffd166",
391
+ "success": "#96f2d7",
392
+ "error": "bold #ff6b6b",
393
+ "debug": "dim #6c757d",
394
+ "diff_add": "#96f2d7",
395
+ "diff_remove": "#ff6b6b",
396
+ "diff_context": "dim #adb5bd",
397
+ },
398
+ "color_remap": rt.make_remap(
399
+ cyan="#cfd8dc",
400
+ blue="#4dabf7",
401
+ magenta="#b197fc",
402
+ bright_cyan="#96f2d7",
403
+ bright_blue="#74c0fc",
404
+ bright_magenta="#d0bfff",
405
+ ),
406
+ "terminal_palette": bp.DEEP_BLACK,
407
+ },
408
+ # Light themes use dim black for debug text so it remains visible.
409
+ "solarized-light": {
410
+ "icon": "☀️",
411
+ "label": "Solarized Light",
412
+ "blurb": "classic warm beige with calm accents",
413
+ "colors": [
414
+ "blue",
415
+ "magenta",
416
+ "green",
417
+ "yellow",
418
+ "cyan",
419
+ "red",
420
+ "bright_blue",
421
+ "bright_magenta",
422
+ ],
423
+ "content_styles": {
424
+ "info": "blue",
425
+ "warning": "yellow",
426
+ "success": "green",
427
+ "error": "bold red",
428
+ "debug": "dim black",
429
+ "diff_add": "green",
430
+ "diff_remove": "red",
431
+ "diff_context": "dim black",
432
+ },
433
+ "color_remap": {},
434
+ "terminal_palette": bp.SOLARIZED_LIGHT,
435
+ },
436
+ "github-light": {
437
+ "icon": "📄",
438
+ "label": "GitHub Light",
439
+ "blurb": "crisp white, familiar code colors",
440
+ "colors": [
441
+ "blue",
442
+ "magenta",
443
+ "green",
444
+ "yellow",
445
+ "cyan",
446
+ "red",
447
+ "bright_blue",
448
+ "bright_magenta",
449
+ ],
450
+ "content_styles": {
451
+ "info": "blue",
452
+ "warning": "yellow",
453
+ "success": "green",
454
+ "error": "bold red",
455
+ "debug": "dim black",
456
+ "diff_add": "green",
457
+ "diff_remove": "red",
458
+ "diff_context": "dim black",
459
+ },
460
+ "color_remap": {},
461
+ "terminal_palette": bp.GITHUB_LIGHT,
462
+ },
463
+ "rose-pine-dawn": {
464
+ "icon": "🌸",
465
+ "label": "Rose Pine Dawn",
466
+ "blurb": "soft pastel rose light",
467
+ "colors": [
468
+ "magenta",
469
+ "blue",
470
+ "cyan",
471
+ "yellow",
472
+ "green",
473
+ "red",
474
+ "bright_magenta",
475
+ "bright_blue",
476
+ ],
477
+ "content_styles": {
478
+ "info": "blue",
479
+ "warning": "yellow",
480
+ "success": "green",
481
+ "error": "bold red",
482
+ "debug": "dim black",
483
+ "diff_add": "green",
484
+ "diff_remove": "red",
485
+ "diff_context": "dim black",
486
+ },
487
+ "color_remap": {},
488
+ "terminal_palette": bp.ROSE_PINE_DAWN,
489
+ },
490
+ }
491
+
492
+ # Surprise Me is a special case, regenerated each preview/apply.
493
+ SURPRISE = {
494
+ "icon": "🎲",
495
+ "label": "Surprise Me",
496
+ "blurb": "a fresh random remix every time",
497
+ "colors": None,
498
+ "content_styles": None, # generated dynamically
499
+ "color_remap": None, # generated dynamically
500
+ "terminal_palette": None, # randomized at apply time
501
+ }
502
+
503
+ # Restore Code Puppy defaults (banners + content).
504
+ DEFAULT = {
505
+ "icon": "🔄",
506
+ "label": "Restore Defaults",
507
+ "blurb": "back to Code Puppy factory colors",
508
+ "colors": None,
509
+ "content_styles": None, # handled specially
510
+ "color_remap": None, # handled specially (empty)
511
+ "terminal_palette": None, # handled specially (OSC reset)
512
+ }
513
+
514
+ # Ordered menu: 7 vivid/dark themes, 7 palette-first/light themes, surprise, default.
515
+ MENU: list[tuple[str, dict]] = [
516
+ ("ocean", CURATED_THEMES["ocean"]),
517
+ ("forest", CURATED_THEMES["forest"]),
518
+ ("sunset", CURATED_THEMES["sunset"]),
519
+ ("vaporwave", CURATED_THEMES["vaporwave"]),
520
+ ("bubblegum-pink", CURATED_THEMES["bubblegum-pink"]),
521
+ ("purple-puppy", CURATED_THEMES["purple-puppy"]),
522
+ ("catppuccin-mocha", CURATED_THEMES["catppuccin-mocha"]),
523
+ ("catppuccin-latte", CURATED_THEMES["catppuccin-latte"]),
524
+ ("tokyo-night", CURATED_THEMES["tokyo-night"]),
525
+ ("green-screen", CURATED_THEMES["green-screen"]),
526
+ ("deep-black", CURATED_THEMES["deep-black"]),
527
+ ("solarized-light", CURATED_THEMES["solarized-light"]),
528
+ ("github-light", CURATED_THEMES["github-light"]),
529
+ ("rose-pine-dawn", CURATED_THEMES["rose-pine-dawn"]),
530
+ ("surprise", SURPRISE),
531
+ ("default", DEFAULT),
532
+ ]
533
+ MENU_BY_NAME: dict[str, dict] = {name: theme for name, theme in MENU}
534
+ MENU_BY_INDEX: dict[str, str] = {str(i + 1): name for i, (name, _) in enumerate(MENU)}
535
+
536
+ # Friendly aliases (no spaces, alt names).
537
+ MENU_BY_NAME["random"] = SURPRISE
538
+ MENU_BY_NAME["reset"] = DEFAULT
539
+ MENU_BY_NAME["defaults"] = DEFAULT
540
+ MENU_BY_NAME["mocha"] = CURATED_THEMES["catppuccin-mocha"]
541
+ MENU_BY_NAME["latte"] = CURATED_THEMES["catppuccin-latte"]
542
+ MENU_BY_NAME["tokyo"] = CURATED_THEMES["tokyo-night"]
543
+ MENU_BY_NAME["green"] = CURATED_THEMES["green-screen"]
544
+ MENU_BY_NAME["crt"] = CURATED_THEMES["green-screen"]
545
+ MENU_BY_NAME["bubblegum"] = CURATED_THEMES["bubblegum-pink"]
546
+ MENU_BY_NAME["pink"] = CURATED_THEMES["bubblegum-pink"]
547
+ MENU_BY_NAME["puppy"] = CURATED_THEMES["purple-puppy"]
548
+ MENU_BY_NAME["purple"] = CURATED_THEMES["purple-puppy"]
549
+ MENU_BY_NAME["solarized"] = CURATED_THEMES["solarized-light"]
550
+ MENU_BY_NAME["github"] = CURATED_THEMES["github-light"]
551
+ MENU_BY_NAME["rose-pine"] = CURATED_THEMES["rose-pine-dawn"]
552
+ MENU_BY_NAME["dawn"] = CURATED_THEMES["rose-pine-dawn"]
553
+
554
+
555
+ def colors_for(theme_name: str, rng: random.Random | None = None) -> dict[str, str]:
556
+ """Build a {banner: color} mapping for the named theme.
557
+
558
+ For curated themes, cycles through the theme palette deterministically.
559
+ For ``surprise``, samples randomly from the full PALETTE.
560
+ For ``default``, returns the Code Puppy factory banner colors.
561
+ """
562
+ if theme_name not in MENU_BY_NAME:
563
+ raise KeyError(f"Unknown theme: {theme_name!r}")
564
+
565
+ if theme_name == "default":
566
+ from code_puppy.config import DEFAULT_BANNER_COLORS
567
+
568
+ return dict(DEFAULT_BANNER_COLORS)
569
+
570
+ if theme_name in ("surprise", "random"):
571
+ chooser = rng.choice if rng is not None else random.choice
572
+ return {banner: chooser(PALETTE) for banner in BANNER_KEYS}
573
+
574
+ palette = cycle(MENU_BY_NAME[theme_name]["colors"])
575
+ return {banner: next(palette) for banner in BANNER_KEYS}
576
+
577
+
578
+ def content_styles_for(
579
+ theme_name: str, rng: random.Random | None = None
580
+ ) -> dict[str, str]:
581
+ """Build a {content_key: style} mapping for the named theme.
582
+
583
+ For curated themes, returns the hand-picked palette.
584
+ For ``surprise``, generates a random remix (error stays red — it's a UX
585
+ contract that errors look angry).
586
+ For ``default``, returns the factory defaults.
587
+ """
588
+ if theme_name not in MENU_BY_NAME:
589
+ raise KeyError(f"Unknown theme: {theme_name!r}")
590
+
591
+ if theme_name == "default":
592
+ return dict(cs.DEFAULT_CONTENT_STYLES)
593
+
594
+ if theme_name in ("surprise", "random"):
595
+ chooser = rng.choice if rng is not None else random.choice
596
+ mapping = {key: chooser(TEXT_PALETTE) for key in cs.CONTENT_KEYS}
597
+ # Errors should always be visually distinct + alarming.
598
+ mapping["error"] = "bold red"
599
+ return mapping
600
+
601
+ return dict(MENU_BY_NAME[theme_name]["content_styles"])
602
+
603
+
604
+ def color_remap_for(
605
+ theme_name: str, rng: random.Random | None = None
606
+ ) -> dict[str, str]:
607
+ """Build a Rich color remap dict for the named theme (Level 2 theming).
608
+
609
+ For curated themes, returns the hand-picked remap.
610
+ For ``surprise``, picks random replacements (semantic colors untouched).
611
+ For ``default``, returns an empty dict (= no remap, restore).
612
+ """
613
+ if theme_name not in MENU_BY_NAME:
614
+ raise KeyError(f"Unknown theme: {theme_name!r}")
615
+
616
+ if theme_name == "default":
617
+ return {}
618
+
619
+ if theme_name in ("surprise", "random"):
620
+ chooser = rng.choice if rng is not None else random.choice
621
+ return rt.make_remap(
622
+ cyan=chooser(TEXT_PALETTE),
623
+ blue=chooser(TEXT_PALETTE),
624
+ magenta=chooser(TEXT_PALETTE),
625
+ bright_cyan=chooser(TEXT_PALETTE),
626
+ bright_blue=chooser(TEXT_PALETTE),
627
+ bright_magenta=chooser(TEXT_PALETTE),
628
+ )
629
+
630
+ return dict(MENU_BY_NAME[theme_name]["color_remap"])
631
+
632
+
633
+ def terminal_palette_for(
634
+ theme_name: str, rng: random.Random | None = None
635
+ ) -> dict | None:
636
+ """Build an OSC terminal palette for the named theme.
637
+
638
+ Returns None if the theme has no terminal palette (rare). For
639
+ ``default``, returns None (caller is expected to call osc_palette.reset).
640
+ For ``surprise``, generates a random bg/fg pair (no full ANSI swap).
641
+ """
642
+ if theme_name not in MENU_BY_NAME:
643
+ raise KeyError(f"Unknown theme: {theme_name!r}")
644
+
645
+ if theme_name == "default":
646
+ return None
647
+
648
+ if theme_name in ("surprise", "random"):
649
+ chooser = rng.choice if rng is not None else random.choice
650
+ # Random bg/fg pair with enough contrast to read text.
651
+ LIGHT_BGS = [
652
+ "#fdf6e3",
653
+ "#ffffff",
654
+ "#faf4ed",
655
+ "#eff1f5",
656
+ "#f5f5f5",
657
+ "#f8f0e3",
658
+ ]
659
+ DARK_FGS = [
660
+ "#657b83",
661
+ "#24292e",
662
+ "#575279",
663
+ "#4c4f69",
664
+ "#2d2d2d",
665
+ "#3c3c3c",
666
+ ]
667
+ DARK_BGS = [
668
+ "#0a1929",
669
+ "#1a2310",
670
+ "#2d1b0e",
671
+ "#16002a",
672
+ "#1e1e2e",
673
+ "#1a1b26",
674
+ "#282828",
675
+ "#0e0e2c",
676
+ ]
677
+ LIGHT_FGS = [
678
+ "#d6eaf8",
679
+ "#e3eecc",
680
+ "#ffe4cc",
681
+ "#ffe0ff",
682
+ "#cdd6f4",
683
+ "#c0caf5",
684
+ "#ebdbb2",
685
+ "#f5f5f5",
686
+ ]
687
+ # 30% chance of a light surprise, 70% dark (most users prefer dark TUI).
688
+ if (rng or random).random() < 0.3:
689
+ return {"bg": chooser(LIGHT_BGS), "fg": chooser(DARK_FGS)}
690
+ return {"bg": chooser(DARK_BGS), "fg": chooser(LIGHT_FGS)}
691
+
692
+ return MENU_BY_NAME[theme_name].get("terminal_palette")
693
+
694
+
695
+ def apply(
696
+ mapping: dict[str, str], setter: Callable[[str, str], None] = set_banner_color
697
+ ) -> None:
698
+ """Persist a banner→color mapping via the config layer.
699
+
700
+ ``setter`` is injectable for tests.
701
+ """
702
+ for banner, color in mapping.items():
703
+ setter(banner, color)
704
+
705
+
706
+ def resolve_theme_arg(arg: str) -> str | None:
707
+ """Resolve menu numbers or a theme name to a canonical theme key.
708
+
709
+ Returns None if the argument is not recognized.
710
+ """
711
+ if arg in MENU_BY_INDEX:
712
+ return MENU_BY_INDEX[arg]
713
+ if arg in MENU_BY_NAME:
714
+ # Normalize aliases to canonical keys.
715
+ if arg == "random":
716
+ return "surprise"
717
+ if arg in ("reset", "defaults"):
718
+ return "default"
719
+ return arg
720
+ return None