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.
Files changed (394) hide show
  1. code_muse/__init__.py +26 -0
  2. code_muse/__main__.py +10 -0
  3. code_muse/agents/__init__.py +31 -0
  4. code_muse/agents/_builder.py +214 -0
  5. code_muse/agents/_compaction.py +506 -0
  6. code_muse/agents/_diagnostics.py +171 -0
  7. code_muse/agents/_history.py +382 -0
  8. code_muse/agents/_key_listeners.py +148 -0
  9. code_muse/agents/_non_streaming_render.py +148 -0
  10. code_muse/agents/_runtime.py +596 -0
  11. code_muse/agents/agent_creator_agent.py +603 -0
  12. code_muse/agents/agent_helios.py +47 -0
  13. code_muse/agents/agent_manager.py +740 -0
  14. code_muse/agents/agent_muse.py +78 -0
  15. code_muse/agents/agent_planning.py +44 -0
  16. code_muse/agents/agent_qa_melpomene.py +207 -0
  17. code_muse/agents/base_agent.py +194 -0
  18. code_muse/agents/event_stream_handler.py +361 -0
  19. code_muse/agents/json_agent.py +201 -0
  20. code_muse/agents/prompt_v3.py +521 -0
  21. code_muse/agents/subagent_stream_handler.py +273 -0
  22. code_muse/callbacks.py +941 -0
  23. code_muse/chatgpt_codex_client.py +333 -0
  24. code_muse/claude_cache_client.py +853 -0
  25. code_muse/cli_runner/__init__.py +319 -0
  26. code_muse/cli_runner/args.py +63 -0
  27. code_muse/cli_runner/loop.py +510 -0
  28. code_muse/cli_runner/resume.py +72 -0
  29. code_muse/cli_runner/runner.py +161 -0
  30. code_muse/command_line/__init__.py +1 -0
  31. code_muse/command_line/add_model_menu.py +1331 -0
  32. code_muse/command_line/agent_menu.py +674 -0
  33. code_muse/command_line/attachments.py +397 -0
  34. code_muse/command_line/autosave_menu.py +709 -0
  35. code_muse/command_line/clipboard.py +528 -0
  36. code_muse/command_line/colors_menu.py +530 -0
  37. code_muse/command_line/command_handler.py +262 -0
  38. code_muse/command_line/command_registry.py +150 -0
  39. code_muse/command_line/config_commands.py +711 -0
  40. code_muse/command_line/core_commands.py +740 -0
  41. code_muse/command_line/diff_menu.py +865 -0
  42. code_muse/command_line/file_path_completion.py +73 -0
  43. code_muse/command_line/load_context_completion.py +57 -0
  44. code_muse/command_line/model_picker_completion.py +512 -0
  45. code_muse/command_line/model_settings_menu.py +983 -0
  46. code_muse/command_line/onboarding_slides.py +162 -0
  47. code_muse/command_line/onboarding_wizard.py +337 -0
  48. code_muse/command_line/pagination.py +41 -0
  49. code_muse/command_line/pin_command_completion.py +329 -0
  50. code_muse/command_line/prompt_toolkit_completion.py +886 -0
  51. code_muse/command_line/session_commands.py +304 -0
  52. code_muse/command_line/shell_passthrough.py +145 -0
  53. code_muse/command_line/skills_completion.py +158 -0
  54. code_muse/command_line/types.py +18 -0
  55. code_muse/command_line/uc_menu.py +908 -0
  56. code_muse/command_line/utils.py +105 -0
  57. code_muse/command_line/wiggum_state.py +77 -0
  58. code_muse/config.py +1138 -0
  59. code_muse/config_agent.py +168 -0
  60. code_muse/config_appearance.py +241 -0
  61. code_muse/config_model.py +357 -0
  62. code_muse/config_security.py +73 -0
  63. code_muse/error_logging.py +132 -0
  64. code_muse/evals/__init__.py +35 -0
  65. code_muse/evals/eval_helpers.py +81 -0
  66. code_muse/evals/eval_runner.py +299 -0
  67. code_muse/evals/sample_evals/__init__.py +1 -0
  68. code_muse/evals/sample_evals/eval_frugal_reads.py +59 -0
  69. code_muse/evals/sample_evals/eval_memory_planning.py +31 -0
  70. code_muse/evals/sample_evals/eval_shell_efficiency.py +39 -0
  71. code_muse/evals/sample_evals/eval_tool_masking.py +33 -0
  72. code_muse/fs_scan_cache/__init__.py +31 -0
  73. code_muse/fs_scan_cache/invalidation_hooks.py +89 -0
  74. code_muse/fs_scan_cache/scan_cache_core.cpython-314-darwin.so +0 -0
  75. code_muse/fs_scan_cache/scan_cache_core.pyx +203 -0
  76. code_muse/fs_scan_cache/tool_integration.py +309 -0
  77. code_muse/fs_scan_cache/ttl_policy.py +44 -0
  78. code_muse/gemini_code_assist.py +383 -0
  79. code_muse/gemini_model.py +838 -0
  80. code_muse/hook_engine/README.md +105 -0
  81. code_muse/hook_engine/__init__.py +21 -0
  82. code_muse/hook_engine/aliases.py +153 -0
  83. code_muse/hook_engine/engine.py +221 -0
  84. code_muse/hook_engine/executor.py +347 -0
  85. code_muse/hook_engine/matcher.py +154 -0
  86. code_muse/hook_engine/models.py +245 -0
  87. code_muse/hook_engine/registry.py +114 -0
  88. code_muse/hook_engine/trust.py +268 -0
  89. code_muse/hook_engine/validator.py +144 -0
  90. code_muse/http_utils.py +360 -0
  91. code_muse/keymap.py +128 -0
  92. code_muse/list_filtering.py +26 -0
  93. code_muse/main.py +10 -0
  94. code_muse/messaging/__init__.py +259 -0
  95. code_muse/messaging/bus.py +621 -0
  96. code_muse/messaging/commands.py +166 -0
  97. code_muse/messaging/markdown_patches.py +57 -0
  98. code_muse/messaging/message_queue.py +397 -0
  99. code_muse/messaging/messages.py +591 -0
  100. code_muse/messaging/queue_console.py +269 -0
  101. code_muse/messaging/renderers.py +308 -0
  102. code_muse/messaging/rich_renderer.py +1158 -0
  103. code_muse/messaging/shimmer.py +154 -0
  104. code_muse/messaging/spinner/__init__.py +87 -0
  105. code_muse/messaging/spinner/console_spinner.py +250 -0
  106. code_muse/messaging/spinner/spinner_base.py +82 -0
  107. code_muse/messaging/subagent_console.py +458 -0
  108. code_muse/model_factory.py +1203 -0
  109. code_muse/model_switching.py +59 -0
  110. code_muse/model_utils.py +156 -0
  111. code_muse/models.json +66 -0
  112. code_muse/models_cache/__init__.py +26 -0
  113. code_muse/models_cache/blocking_lru_cache.py +98 -0
  114. code_muse/models_cache/cache_writer.py +86 -0
  115. code_muse/models_cache/sha256_hash.cpython-314-darwin.so +0 -0
  116. code_muse/models_cache/sha256_hash.pyx +34 -0
  117. code_muse/models_cache/startup_integration.py +75 -0
  118. code_muse/models_dev_api.json +1 -0
  119. code_muse/models_dev_parser.py +590 -0
  120. code_muse/motion.py +126 -0
  121. code_muse/plugins/__init__.py +471 -0
  122. code_muse/plugins/agent_skills/__init__.py +32 -0
  123. code_muse/plugins/agent_skills/config.py +176 -0
  124. code_muse/plugins/agent_skills/discovery.py +309 -0
  125. code_muse/plugins/agent_skills/downloader.py +389 -0
  126. code_muse/plugins/agent_skills/installer.py +19 -0
  127. code_muse/plugins/agent_skills/metadata.py +293 -0
  128. code_muse/plugins/agent_skills/prompt_builder.py +66 -0
  129. code_muse/plugins/agent_skills/register_callbacks.py +298 -0
  130. code_muse/plugins/agent_skills/remote_catalog.py +320 -0
  131. code_muse/plugins/agent_skills/skill_catalog.py +254 -0
  132. code_muse/plugins/agent_skills/skills_install_menu.py +690 -0
  133. code_muse/plugins/agent_skills/skills_menu.py +791 -0
  134. code_muse/plugins/autonomous_memory/__init__.py +39 -0
  135. code_muse/plugins/autonomous_memory/bm25_scorer.cpython-314-darwin.so +0 -0
  136. code_muse/plugins/autonomous_memory/bm25_scorer.cpython-314-x86_64-linux-gnu.so +0 -0
  137. code_muse/plugins/autonomous_memory/bm25_scorer.pyx +291 -0
  138. code_muse/plugins/autonomous_memory/consolidation.py +82 -0
  139. code_muse/plugins/autonomous_memory/extraction.py +382 -0
  140. code_muse/plugins/autonomous_memory/lease_lock.py +105 -0
  141. code_muse/plugins/autonomous_memory/memory_injection.py +59 -0
  142. code_muse/plugins/autonomous_memory/register_callbacks.py +268 -0
  143. code_muse/plugins/autonomous_memory/secret_scanner.py +62 -0
  144. code_muse/plugins/autonomous_memory/session_scanner.py +163 -0
  145. code_muse/plugins/aws_bedrock/__init__.py +14 -0
  146. code_muse/plugins/aws_bedrock/config.py +99 -0
  147. code_muse/plugins/aws_bedrock/register_callbacks.py +241 -0
  148. code_muse/plugins/aws_bedrock/utils.py +153 -0
  149. code_muse/plugins/azure_foundry/README.md +238 -0
  150. code_muse/plugins/azure_foundry/__init__.py +15 -0
  151. code_muse/plugins/azure_foundry/config.py +125 -0
  152. code_muse/plugins/azure_foundry/discovery.py +187 -0
  153. code_muse/plugins/azure_foundry/register_callbacks.py +495 -0
  154. code_muse/plugins/azure_foundry/token.py +180 -0
  155. code_muse/plugins/azure_foundry/utils.py +345 -0
  156. code_muse/plugins/build_filter/__init__.py +1 -0
  157. code_muse/plugins/build_filter/register_callbacks.py +201 -0
  158. code_muse/plugins/build_filter/strategies/__init__.py +1 -0
  159. code_muse/plugins/build_filter/strategies/build.py +397 -0
  160. code_muse/plugins/chatgpt_oauth/__init__.py +6 -0
  161. code_muse/plugins/chatgpt_oauth/config.py +52 -0
  162. code_muse/plugins/chatgpt_oauth/oauth_flow.py +338 -0
  163. code_muse/plugins/chatgpt_oauth/register_callbacks.py +172 -0
  164. code_muse/plugins/chatgpt_oauth/test_plugin.py +301 -0
  165. code_muse/plugins/chatgpt_oauth/utils.py +538 -0
  166. code_muse/plugins/checkpointing/__init__.py +29 -0
  167. code_muse/plugins/checkpointing/checkpoint_hook.py +51 -0
  168. code_muse/plugins/checkpointing/conversation_snapshots.py +117 -0
  169. code_muse/plugins/checkpointing/register_callbacks.py +51 -0
  170. code_muse/plugins/checkpointing/restore_command.py +263 -0
  171. code_muse/plugins/checkpointing/rewind_shortcut.py +88 -0
  172. code_muse/plugins/checkpointing/shadow_git.py +90 -0
  173. code_muse/plugins/claude_code_hooks/__init__.py +1 -0
  174. code_muse/plugins/claude_code_hooks/config.py +188 -0
  175. code_muse/plugins/claude_code_hooks/register_callbacks.py +208 -0
  176. code_muse/plugins/claude_code_oauth/README.md +167 -0
  177. code_muse/plugins/claude_code_oauth/SETUP.md +93 -0
  178. code_muse/plugins/claude_code_oauth/__init__.py +25 -0
  179. code_muse/plugins/claude_code_oauth/config.py +52 -0
  180. code_muse/plugins/claude_code_oauth/fast_mode.py +124 -0
  181. code_muse/plugins/claude_code_oauth/prompt_handler.py +63 -0
  182. code_muse/plugins/claude_code_oauth/register_callbacks.py +547 -0
  183. code_muse/plugins/claude_code_oauth/test_fast_mode.py +165 -0
  184. code_muse/plugins/claude_code_oauth/test_plugin.py +283 -0
  185. code_muse/plugins/claude_code_oauth/token_refresh_heartbeat.py +237 -0
  186. code_muse/plugins/claude_code_oauth/utils.py +664 -0
  187. code_muse/plugins/copilot_auth/__init__.py +11 -0
  188. code_muse/plugins/copilot_auth/config.py +91 -0
  189. code_muse/plugins/copilot_auth/reasoning_client.py +409 -0
  190. code_muse/plugins/copilot_auth/register_callbacks.py +461 -0
  191. code_muse/plugins/copilot_auth/utils.py +584 -0
  192. code_muse/plugins/custom_commands/__init__.py +14 -0
  193. code_muse/plugins/custom_commands/args_injection.py +82 -0
  194. code_muse/plugins/custom_commands/command_discovery.py +89 -0
  195. code_muse/plugins/custom_commands/command_toml_schema.py +71 -0
  196. code_muse/plugins/custom_commands/register_callbacks.py +176 -0
  197. code_muse/plugins/customizable_commands/__init__.py +0 -0
  198. code_muse/plugins/customizable_commands/register_callbacks.py +136 -0
  199. code_muse/plugins/destructive_command_guard/__init__.py +14 -0
  200. code_muse/plugins/destructive_command_guard/detector.py +375 -0
  201. code_muse/plugins/destructive_command_guard/register_callbacks.py +148 -0
  202. code_muse/plugins/example_custom_command/README.md +280 -0
  203. code_muse/plugins/example_custom_command/register_callbacks.py +51 -0
  204. code_muse/plugins/file_permission_handler/__init__.py +4 -0
  205. code_muse/plugins/file_permission_handler/register_callbacks.py +441 -0
  206. code_muse/plugins/filter_engine/__init__.py +30 -0
  207. code_muse/plugins/filter_engine/classifier.py +153 -0
  208. code_muse/plugins/filter_engine/content_detector.py +184 -0
  209. code_muse/plugins/filter_engine/dispatcher.py +244 -0
  210. code_muse/plugins/filter_engine/register_callbacks.py +188 -0
  211. code_muse/plugins/filter_engine/registry.py +279 -0
  212. code_muse/plugins/filter_engine/strategies/__init__.py +8 -0
  213. code_muse/plugins/filter_engine/strategies/ast_compressor.cpython-314-darwin.so +0 -0
  214. code_muse/plugins/filter_engine/strategies/ast_compressor.cpython-314-x86_64-linux-gnu.so +0 -0
  215. code_muse/plugins/filter_engine/strategies/ast_compressor.pyx +348 -0
  216. code_muse/plugins/filter_engine/strategies/ast_parser.py +167 -0
  217. code_muse/plugins/filter_engine/strategies/code.cpython-314-darwin.so +0 -0
  218. code_muse/plugins/filter_engine/strategies/code.cpython-314-x86_64-linux-gnu.so +0 -0
  219. code_muse/plugins/filter_engine/strategies/code.pyx +584 -0
  220. code_muse/plugins/filter_engine/strategies/git.cpython-314-darwin.so +0 -0
  221. code_muse/plugins/filter_engine/strategies/git.cpython-314-x86_64-linux-gnu.so +0 -0
  222. code_muse/plugins/filter_engine/strategies/git.pyx +438 -0
  223. code_muse/plugins/filter_engine/strategies/json_compressor.cpython-314-darwin.so +0 -0
  224. code_muse/plugins/filter_engine/strategies/json_compressor.pyx +253 -0
  225. code_muse/plugins/filter_engine/strategies/json_patterns.cpython-314-darwin.so +0 -0
  226. code_muse/plugins/filter_engine/strategies/json_patterns.pyx +178 -0
  227. code_muse/plugins/filter_engine/strategies/lint.cpython-314-darwin.so +0 -0
  228. code_muse/plugins/filter_engine/strategies/lint.cpython-314-x86_64-linux-gnu.so +0 -0
  229. code_muse/plugins/filter_engine/strategies/lint.pyx +626 -0
  230. code_muse/plugins/filter_engine/strategies/test.cpython-314-darwin.so +0 -0
  231. code_muse/plugins/filter_engine/strategies/test.cpython-314-x86_64-linux-gnu.so +0 -0
  232. code_muse/plugins/filter_engine/strategies/test.pyx +431 -0
  233. code_muse/plugins/filter_engine/verbosity.py +63 -0
  234. code_muse/plugins/force_push_guard/__init__.py +5 -0
  235. code_muse/plugins/force_push_guard/detector.py +96 -0
  236. code_muse/plugins/force_push_guard/register_callbacks.py +144 -0
  237. code_muse/plugins/force_push_guard/test_detector.py +143 -0
  238. code_muse/plugins/frontend_emitter/__init__.py +25 -0
  239. code_muse/plugins/frontend_emitter/emitter.py +121 -0
  240. code_muse/plugins/frontend_emitter/register_callbacks.py +259 -0
  241. code_muse/plugins/gac/__init__.py +4 -0
  242. code_muse/plugins/gac/git_ops.py +136 -0
  243. code_muse/plugins/gac/prompt.py +191 -0
  244. code_muse/plugins/gac/register_callbacks.py +82 -0
  245. code_muse/plugins/hook_creator/__init__.py +1 -0
  246. code_muse/plugins/hook_creator/register_callbacks.py +34 -0
  247. code_muse/plugins/hook_manager/__init__.py +1 -0
  248. code_muse/plugins/hook_manager/config.py +289 -0
  249. code_muse/plugins/hook_manager/hooks_menu.py +563 -0
  250. code_muse/plugins/hook_manager/register_callbacks.py +227 -0
  251. code_muse/plugins/hook_monitor/register_callbacks.py +36 -0
  252. code_muse/plugins/mindpack/__init__.py +0 -0
  253. code_muse/plugins/mindpack/factory.py +930 -0
  254. code_muse/plugins/mindpack/judge.py +573 -0
  255. code_muse/plugins/mindpack/memory.py +100 -0
  256. code_muse/plugins/mindpack/mindpack_menu.py +1552 -0
  257. code_muse/plugins/mindpack/orchestration.py +605 -0
  258. code_muse/plugins/mindpack/register_callbacks.py +175 -0
  259. code_muse/plugins/mindpack/schemas.py +358 -0
  260. code_muse/plugins/mindpack/tools.py +387 -0
  261. code_muse/plugins/oauth_muse_html.py +226 -0
  262. code_muse/plugins/ollama_setup/__init__.py +5 -0
  263. code_muse/plugins/ollama_setup/completer.py +36 -0
  264. code_muse/plugins/ollama_setup/register_callbacks.py +410 -0
  265. code_muse/plugins/plan_command/__init__.py +0 -0
  266. code_muse/plugins/plan_command/register_callbacks.py +206 -0
  267. code_muse/plugins/plan_mode/__init__.py +37 -0
  268. code_muse/plugins/plan_mode/mode_cycling.py +40 -0
  269. code_muse/plugins/plan_mode/plan_generation.py +68 -0
  270. code_muse/plugins/plan_mode/plan_hooks.py +74 -0
  271. code_muse/plugins/plan_mode/plan_mode_tools.py +138 -0
  272. code_muse/plugins/plan_mode/register_callbacks.py +121 -0
  273. code_muse/plugins/plugin_trust/register_callbacks.py +140 -0
  274. code_muse/plugins/policy_engine/__init__.py +46 -0
  275. code_muse/plugins/policy_engine/approval_flow_integration.py +59 -0
  276. code_muse/plugins/policy_engine/policy_evaluator.py +75 -0
  277. code_muse/plugins/policy_engine/policy_file_discovery.py +90 -0
  278. code_muse/plugins/policy_engine/policy_toml_schema.py +115 -0
  279. code_muse/plugins/policy_engine/register_callbacks.py +112 -0
  280. code_muse/plugins/pop_command/__init__.py +1 -0
  281. code_muse/plugins/pop_command/register_callbacks.py +189 -0
  282. code_muse/plugins/prompt_newline/__init__.py +13 -0
  283. code_muse/plugins/prompt_newline/config.py +19 -0
  284. code_muse/plugins/prompt_newline/register_callbacks.py +159 -0
  285. code_muse/plugins/safety_status/__init__.py +0 -0
  286. code_muse/plugins/safety_status/register_callbacks.py +113 -0
  287. code_muse/plugins/semantic_compression/__init__.py +6 -0
  288. code_muse/plugins/semantic_compression/compressor.py +295 -0
  289. code_muse/plugins/semantic_compression/config.py +123 -0
  290. code_muse/plugins/semantic_compression/register_callbacks.py +320 -0
  291. code_muse/plugins/shell_minimizer/__init__.py +50 -0
  292. code_muse/plugins/shell_minimizer/builtin_filters.toml +393 -0
  293. code_muse/plugins/shell_minimizer/pipeline.py +556 -0
  294. code_muse/plugins/shell_minimizer/primitives.py +482 -0
  295. code_muse/plugins/shell_minimizer/register_callbacks.py +276 -0
  296. code_muse/plugins/shell_safety/__init__.py +6 -0
  297. code_muse/plugins/shell_safety/agent_shell_safety.py +69 -0
  298. code_muse/plugins/shell_safety/command_cache.py +149 -0
  299. code_muse/plugins/shell_safety/register_callbacks.py +202 -0
  300. code_muse/plugins/synthetic_status/__init__.py +1 -0
  301. code_muse/plugins/synthetic_status/register_callbacks.py +128 -0
  302. code_muse/plugins/synthetic_status/status_api.py +145 -0
  303. code_muse/plugins/token_caching/__init__.py +21 -0
  304. code_muse/plugins/token_caching/cache_hit_tracking.py +128 -0
  305. code_muse/plugins/token_caching/cacheable_prefix_detection.py +28 -0
  306. code_muse/plugins/token_caching/register_callbacks.py +54 -0
  307. code_muse/plugins/token_caching/stats_display.py +35 -0
  308. code_muse/plugins/token_tracking/__init__.py +26 -0
  309. code_muse/plugins/token_tracking/database.py +381 -0
  310. code_muse/plugins/token_tracking/edit_analyzer.py +97 -0
  311. code_muse/plugins/token_tracking/record.py +55 -0
  312. code_muse/plugins/token_tracking/register_callbacks.py +277 -0
  313. code_muse/plugins/token_tracking/reports.py +329 -0
  314. code_muse/plugins/universal_constructor/__init__.py +13 -0
  315. code_muse/plugins/universal_constructor/models.py +136 -0
  316. code_muse/plugins/universal_constructor/register_callbacks.py +47 -0
  317. code_muse/plugins/universal_constructor/registry.py +390 -0
  318. code_muse/plugins/universal_constructor/runner.py +474 -0
  319. code_muse/plugins/universal_constructor/safety.py +440 -0
  320. code_muse/plugins/universal_constructor/sandbox.py +584 -0
  321. code_muse/provider_identity.py +105 -0
  322. code_muse/pydantic_patches.py +410 -0
  323. code_muse/reopenable_async_client.py +233 -0
  324. code_muse/round_robin_model.py +151 -0
  325. code_muse/secret_storage.py +74 -0
  326. code_muse/security/__init__.py +1 -0
  327. code_muse/security/redaction.cpython-314-darwin.so +0 -0
  328. code_muse/security/redaction.cpython-314-x86_64-linux-gnu.so +0 -0
  329. code_muse/security/redaction.pyx +135 -0
  330. code_muse/session_storage.py +565 -0
  331. code_muse/status_display.py +261 -0
  332. code_muse/stream_parser/__init__.py +76 -0
  333. code_muse/stream_parser/assistant_text_parser.py +90 -0
  334. code_muse/stream_parser/citation_parser.py +76 -0
  335. code_muse/stream_parser/inline_hidden_tag_parser.py +236 -0
  336. code_muse/stream_parser/proposed_plan_parser.py +158 -0
  337. code_muse/stream_parser/stream_text_chunk.py +23 -0
  338. code_muse/stream_parser/stream_text_parser.py +27 -0
  339. code_muse/stream_parser/tagged_line_parser.cpython-314-darwin.so +0 -0
  340. code_muse/stream_parser/tagged_line_parser.pyx +251 -0
  341. code_muse/stream_parser/utf8_stream_parser.cpython-314-darwin.so +0 -0
  342. code_muse/stream_parser/utf8_stream_parser.pyx +206 -0
  343. code_muse/summarization_agent.py +308 -0
  344. code_muse/terminal_utils.cpython-314-darwin.so +0 -0
  345. code_muse/terminal_utils.cpython-314-x86_64-linux-gnu.so +0 -0
  346. code_muse/terminal_utils.pyx +483 -0
  347. code_muse/tools/__init__.py +459 -0
  348. code_muse/tools/agent_tools.py +613 -0
  349. code_muse/tools/ask_user_question/__init__.py +26 -0
  350. code_muse/tools/ask_user_question/constants.py +73 -0
  351. code_muse/tools/ask_user_question/demo_tui.py +55 -0
  352. code_muse/tools/ask_user_question/handler.py +232 -0
  353. code_muse/tools/ask_user_question/models.py +302 -0
  354. code_muse/tools/ask_user_question/registration.py +37 -0
  355. code_muse/tools/ask_user_question/renderers.py +336 -0
  356. code_muse/tools/ask_user_question/terminal_ui.py +327 -0
  357. code_muse/tools/ask_user_question/theme.py +156 -0
  358. code_muse/tools/ask_user_question/tui_loop.py +422 -0
  359. code_muse/tools/background_jobs.py +99 -0
  360. code_muse/tools/browser/__init__.py +37 -0
  361. code_muse/tools/browser/browser_control.py +289 -0
  362. code_muse/tools/browser/browser_interactions.py +545 -0
  363. code_muse/tools/browser/browser_locators.py +640 -0
  364. code_muse/tools/browser/browser_manager.py +376 -0
  365. code_muse/tools/browser/browser_navigation.py +251 -0
  366. code_muse/tools/browser/browser_screenshot.py +180 -0
  367. code_muse/tools/browser/browser_scripts.py +462 -0
  368. code_muse/tools/browser/browser_workflows.py +222 -0
  369. code_muse/tools/chrome_cdp/__init__.py +1070 -0
  370. code_muse/tools/chrome_cdp/register_callbacks.py +61 -0
  371. code_muse/tools/command_runner.py +1401 -0
  372. code_muse/tools/common.py +1407 -0
  373. code_muse/tools/display.py +87 -0
  374. code_muse/tools/file_modifications.py +1099 -0
  375. code_muse/tools/file_operations.py +860 -0
  376. code_muse/tools/image_tools.py +185 -0
  377. code_muse/tools/meetin_proxy/__init__.py +243 -0
  378. code_muse/tools/meetin_proxy/capture_addon.py +82 -0
  379. code_muse/tools/meetin_proxy/proxy_manager.py +326 -0
  380. code_muse/tools/meetin_proxy/register_callbacks.py +45 -0
  381. code_muse/tools/path_policy.py +219 -0
  382. code_muse/tools/skills_tools.py +586 -0
  383. code_muse/tools/subagent_context.py +158 -0
  384. code_muse/tools/tools_content.py +50 -0
  385. code_muse/tools/universal_constructor.py +965 -0
  386. code_muse/uvx_detection.py +241 -0
  387. code_muse/version_checker.py +86 -0
  388. code_muse-0.0.1.data/data/code_muse/models.json +66 -0
  389. code_muse-0.0.1.data/data/code_muse/models_dev_api.json +1 -0
  390. code_muse-0.0.1.dist-info/METADATA +845 -0
  391. code_muse-0.0.1.dist-info/RECORD +394 -0
  392. code_muse-0.0.1.dist-info/WHEEL +4 -0
  393. code_muse-0.0.1.dist-info/entry_points.txt +2 -0
  394. code_muse-0.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,711 @@
1
+ """Command handlers for Muse - CONFIG commands.
2
+
3
+ This module contains @register_command decorated handlers that are automatically
4
+ discovered by the command registry system.
5
+ """
6
+
7
+ import json
8
+
9
+ from code_muse.command_line.command_registry import register_command
10
+ from code_muse.config import get_config_keys
11
+
12
+
13
+ # Import get_commands_help from command_handler to avoid circular imports
14
+ # This will be defined in command_handler.py
15
+ def get_commands_help():
16
+ """Lazy import to avoid circular dependency."""
17
+ from code_muse.command_line.command_handler import get_commands_help as _gch
18
+
19
+ return _gch()
20
+
21
+
22
+ @register_command(
23
+ name="show",
24
+ description="Show muse config key-values",
25
+ usage="/show",
26
+ category="config",
27
+ )
28
+ def handle_show_command(command: str) -> bool:
29
+ """Show current muse configuration."""
30
+ from rich.text import Text
31
+
32
+ from code_muse.agents import get_current_agent
33
+ from code_muse.command_line.model_picker_completion import get_active_model
34
+ from code_muse.config import (
35
+ get_auto_save_session,
36
+ get_compaction_strategy,
37
+ get_compaction_threshold,
38
+ get_default_agent,
39
+ get_effective_temperature,
40
+ get_openai_reasoning_effort,
41
+ get_openai_verbosity,
42
+ get_owner_name,
43
+ get_protected_token_count,
44
+ get_agent_name,
45
+ get_resume_message_count,
46
+ get_temperature,
47
+ get_yolo_mode,
48
+ )
49
+ from code_muse.keymap import (
50
+ get_cancel_agent_display_name,
51
+ )
52
+ from code_muse.messaging import emit_info
53
+
54
+ agent_name = get_agent_name()
55
+ owner_name = get_owner_name()
56
+ model = get_active_model()
57
+ yolo_mode = get_yolo_mode()
58
+ auto_save = get_auto_save_session()
59
+ protected_tokens = get_protected_token_count()
60
+ compaction_threshold = get_compaction_threshold()
61
+ compaction_strategy = get_compaction_strategy()
62
+ global_temperature = get_temperature()
63
+ effective_temperature = get_effective_temperature(model)
64
+
65
+ # Get current agent info
66
+ current_agent = get_current_agent()
67
+ default_agent = get_default_agent()
68
+
69
+ status_msg = f"""[bold magenta]Status[/bold magenta]
70
+
71
+ [bold]agent_name:[/bold] [cyan]{agent_name}[/cyan]
72
+ [bold]owner_name:[/bold] [cyan]{owner_name}[/cyan]
73
+ [bold]current_agent:[/bold] [magenta]{current_agent.display_name}[/magenta]
74
+ [bold]default_agent:[/bold] [cyan]{default_agent}[/cyan]
75
+ [bold]model:[/bold] [green]{model}[/green]
76
+ [bold]YOLO_MODE:[/bold] {"[red]ON[/red]" if yolo_mode else "[yellow]off[/yellow]"}
77
+ [bold]auto_save_session:[/bold] {"[green]enabled[/green]" if auto_save else "[yellow]disabled[/yellow]"}
78
+ [bold]protected_tokens:[/bold] [cyan]{protected_tokens:,}[/cyan] recent tokens preserved
79
+ [bold]compaction_threshold:[/bold] [cyan]{compaction_threshold:.1%}[/cyan] context usage triggers compaction
80
+ [bold]compaction_strategy:[/bold] [cyan]{compaction_strategy}[/cyan] (summarization or truncation)
81
+ [bold]resume_message_count:[/bold] [cyan]{get_resume_message_count()}[/cyan] messages shown on /resume
82
+ [bold]reasoning_effort:[/bold] [cyan]{get_openai_reasoning_effort()}[/cyan]
83
+ [bold]verbosity:[/bold] [cyan]{get_openai_verbosity()}[/cyan]
84
+ [bold]temperature:[/bold] [cyan]{effective_temperature if effective_temperature is not None else "(model default)"}[/cyan]{" (per-model)" if effective_temperature != global_temperature and effective_temperature is not None else ""}
85
+ [bold]cancel_agent_key:[/bold] [cyan]{get_cancel_agent_display_name()}[/cyan] (options: ctrl+c, ctrl+k, ctrl+q)
86
+
87
+ """
88
+ emit_info(Text.from_markup(status_msg))
89
+ return True
90
+
91
+
92
+ @register_command(
93
+ name="reasoning",
94
+ description="Set OpenAI reasoning effort for GPT-5 models (e.g., /reasoning high)",
95
+ usage="/reasoning <minimal|low|medium|high|xhigh>",
96
+ category="config",
97
+ )
98
+ def handle_reasoning_command(command: str) -> bool:
99
+ """Set OpenAI reasoning effort level."""
100
+ from code_muse.messaging import emit_error, emit_success, emit_warning
101
+
102
+ tokens = command.split()
103
+ if len(tokens) != 2:
104
+ emit_warning("Usage: /reasoning <minimal|low|medium|high|xhigh>")
105
+ return True
106
+
107
+ effort = tokens[1]
108
+ try:
109
+ from code_muse.config import set_openai_reasoning_effort
110
+
111
+ set_openai_reasoning_effort(effort)
112
+ except ValueError as exc:
113
+ emit_error(str(exc))
114
+ return True
115
+
116
+ from code_muse.config import get_openai_reasoning_effort
117
+
118
+ normalized_effort = get_openai_reasoning_effort()
119
+
120
+ from code_muse.agents.agent_manager import get_current_agent
121
+
122
+ agent = get_current_agent()
123
+ agent.reload_code_generation_agent()
124
+ emit_success(
125
+ f"Reasoning effort set to '{normalized_effort}' and active agent reloaded"
126
+ )
127
+ return True
128
+
129
+
130
+ @register_command(
131
+ name="verbosity",
132
+ description="Set OpenAI verbosity for GPT-5 models (e.g., /verbosity high)",
133
+ usage="/verbosity <low|medium|high>",
134
+ category="config",
135
+ )
136
+ def handle_verbosity_command(command: str) -> bool:
137
+ """Set OpenAI verbosity level.
138
+
139
+ Controls how concise vs. verbose the model's responses are:
140
+ - low: more concise responses
141
+ - medium: balanced (default)
142
+ - high: more verbose responses
143
+ """
144
+ from code_muse.messaging import emit_error, emit_success, emit_warning
145
+
146
+ tokens = command.split()
147
+ if len(tokens) != 2:
148
+ emit_warning("Usage: /verbosity <low|medium|high>")
149
+ return True
150
+
151
+ verbosity = tokens[1]
152
+ try:
153
+ from code_muse.config import set_openai_verbosity
154
+
155
+ set_openai_verbosity(verbosity)
156
+ except ValueError as exc:
157
+ emit_error(str(exc))
158
+ return True
159
+
160
+ from code_muse.config import get_openai_verbosity
161
+
162
+ normalized_verbosity = get_openai_verbosity()
163
+
164
+ from code_muse.agents.agent_manager import get_current_agent
165
+
166
+ agent = get_current_agent()
167
+ agent.reload_code_generation_agent()
168
+ emit_success(f"Verbosity set to '{normalized_verbosity}' and active agent reloaded")
169
+ return True
170
+
171
+
172
+ @register_command(
173
+ name="set",
174
+ description="Set muse config (e.g., /set yolo_mode true)",
175
+ usage="/set <key> <value>",
176
+ category="config",
177
+ )
178
+ def handle_set_command(command: str) -> bool:
179
+ """Set configuration values."""
180
+ from rich.text import Text
181
+
182
+ from code_muse.config import set_config_value
183
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
184
+
185
+ tokens = command.split(None, 2)
186
+ argstr = command[len("/set") :].strip()
187
+ key = None
188
+ value = None
189
+ if "=" in argstr:
190
+ key, value = argstr.split("=", 1)
191
+ key = key.strip()
192
+ value = value.strip()
193
+ elif len(tokens) >= 3:
194
+ key = tokens[1]
195
+ value = tokens[2]
196
+ elif len(tokens) == 2:
197
+ key = tokens[1]
198
+ value = ""
199
+ else:
200
+ config_keys = get_config_keys()
201
+ if "compaction_strategy" not in config_keys:
202
+ config_keys.append("compaction_strategy")
203
+ session_help = (
204
+ "\n[yellow]Session Management[/yellow]"
205
+ "\n [cyan]auto_save_session[/cyan] Auto-save chat after every response (true/false)"
206
+ )
207
+ keymap_help = (
208
+ "\n[yellow]Keyboard Shortcuts[/yellow]"
209
+ "\n [cyan]cancel_agent_key[/cyan] Key to cancel agent tasks (ctrl+c, ctrl+k, or ctrl+q)"
210
+ )
211
+ emit_warning(
212
+ Text.from_markup(
213
+ f"Usage: /set KEY=VALUE or /set KEY VALUE\nConfig keys: {', '.join(config_keys)}\n[dim]Note: compaction_strategy can be 'summarization' or 'truncation'[/dim]{session_help}{keymap_help}"
214
+ )
215
+ )
216
+ return True
217
+ if key:
218
+ # Validate cancel_agent_key before setting
219
+ if key == "cancel_agent_key":
220
+ from code_muse.keymap import VALID_CANCEL_KEYS
221
+
222
+ normalized_value = value.strip().lower()
223
+ if normalized_value not in VALID_CANCEL_KEYS:
224
+ emit_error(
225
+ f"Invalid cancel_agent_key '{value}'. Valid options: {', '.join(sorted(VALID_CANCEL_KEYS))}"
226
+ )
227
+ return True
228
+ value = normalized_value # Use normalized value
229
+ emit_info(
230
+ Text.from_markup(
231
+ "[yellow]āš ļø cancel_agent_key changed. Please restart Muse for this change to take effect.[/yellow]"
232
+ )
233
+ )
234
+
235
+ set_config_value(key, value)
236
+ emit_success(f'Set {key} = "{value}" in muse.cfg!')
237
+
238
+ # Reload the current agent to pick up the new config
239
+ from code_muse.agents import get_current_agent
240
+
241
+ try:
242
+ current_agent = get_current_agent()
243
+ current_agent.reload_code_generation_agent()
244
+ emit_info("Agent reloaded with updated config")
245
+ except Exception as reload_error:
246
+ emit_warning(f"Config saved but agent reload failed: {reload_error}")
247
+ else:
248
+ emit_error("You must supply a key.")
249
+ return True
250
+
251
+
252
+ def _get_json_agents_pinned_to_model(model_name: str) -> list:
253
+ """Get JSON agents that have this model pinned in their JSON file."""
254
+ from code_muse.agents.json_agent import discover_json_agents
255
+
256
+ pinned = []
257
+ json_agents = discover_json_agents()
258
+ for agent_name, agent_path in json_agents.items():
259
+ try:
260
+ with open(agent_path) as f:
261
+ agent_data = json.load(f)
262
+ if agent_data.get("model") == model_name:
263
+ pinned.append(agent_name)
264
+ except Exception:
265
+ continue
266
+ return pinned
267
+
268
+
269
+ @register_command(
270
+ name="pin_model",
271
+ description="Pin a specific model to an agent",
272
+ usage="/pin_model <agent> <model>",
273
+ category="config",
274
+ )
275
+ def handle_pin_model_command(command: str) -> bool:
276
+ """Pin a specific model to an agent."""
277
+ from code_muse.agents.json_agent import discover_json_agents
278
+ from code_muse.command_line.model_picker_completion import load_model_names
279
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
280
+
281
+ tokens = command.split()
282
+
283
+ if len(tokens) != 3:
284
+ emit_warning("Usage: /pin_model <agent-name> <model-name>")
285
+
286
+ # Show available models and agents
287
+ available_models = load_model_names()
288
+ json_agents = discover_json_agents()
289
+
290
+ # Get built-in agents
291
+ from code_muse.agents.agent_manager import get_agent_descriptions
292
+
293
+ builtin_agents = get_agent_descriptions()
294
+
295
+ emit_info("Available models:")
296
+ for model in available_models:
297
+ emit_info(f" {model}")
298
+
299
+ if builtin_agents:
300
+ emit_info("\nAvailable built-in agents:")
301
+ for agent_name, description in builtin_agents.items():
302
+ emit_info(f" {agent_name} - {description}")
303
+
304
+ if json_agents:
305
+ emit_info("\nAvailable JSON agents:")
306
+ for agent_name, agent_path in json_agents.items():
307
+ emit_info(f" {agent_name} ({agent_path})")
308
+ return True
309
+
310
+ agent_name = tokens[1].lower()
311
+ model_name = tokens[2]
312
+
313
+ # Handle special case: (unpin) option (case-insensitive)
314
+ if model_name.lower() == "(unpin)":
315
+ # Delegate to unpin command
316
+ return handle_unpin_command(f"/unpin {agent_name}")
317
+
318
+ # Check if model exists
319
+ available_models = load_model_names()
320
+ if model_name not in available_models:
321
+ emit_error(f"Model '{model_name}' not found")
322
+ emit_warning(f"Available models: {', '.join(available_models)}")
323
+ return True
324
+
325
+ # Check if this is a JSON agent or a built-in Python agent
326
+ json_agents = discover_json_agents()
327
+
328
+ # Get list of available built-in agents
329
+ from code_muse.agents.agent_manager import get_agent_descriptions
330
+
331
+ builtin_agents = get_agent_descriptions()
332
+
333
+ is_json_agent = agent_name in json_agents
334
+ is_builtin_agent = agent_name in builtin_agents
335
+
336
+ if not is_json_agent and not is_builtin_agent:
337
+ emit_error(f"Agent '{agent_name}' not found")
338
+
339
+ # Show available agents
340
+ if builtin_agents:
341
+ emit_info("Available built-in agents:")
342
+ for name, desc in builtin_agents.items():
343
+ emit_info(f" {name} - {desc}")
344
+
345
+ if json_agents:
346
+ emit_info("\nAvailable JSON agents:")
347
+ for name, path in json_agents.items():
348
+ emit_info(f" {name} ({path})")
349
+ return True
350
+
351
+ # Handle different agent types
352
+ try:
353
+ if is_json_agent:
354
+ # Handle JSON agent - modify the JSON file
355
+ agent_file_path = json_agents[agent_name]
356
+
357
+ with open(agent_file_path, encoding="utf-8") as f:
358
+ agent_config = json.load(f)
359
+
360
+ # Set the model
361
+ agent_config["model"] = model_name
362
+
363
+ # Save the updated configuration
364
+ with open(agent_file_path, "w", encoding="utf-8") as f:
365
+ json.dump(agent_config, f, indent=2, ensure_ascii=False)
366
+
367
+ else:
368
+ # Handle built-in Python agent - store in config
369
+ from code_muse.config import set_agent_pinned_model
370
+
371
+ set_agent_pinned_model(agent_name, model_name)
372
+
373
+ emit_success(f"Model '{model_name}' pinned to agent '{agent_name}'")
374
+
375
+ # If this is the current agent, refresh it so the prompt updates immediately
376
+ from code_muse.agents import get_current_agent
377
+
378
+ current_agent = get_current_agent()
379
+ if current_agent.name == agent_name:
380
+ try:
381
+ if is_json_agent and hasattr(current_agent, "refresh_config"):
382
+ current_agent.refresh_config()
383
+ current_agent.reload_code_generation_agent()
384
+ emit_info(f"Active agent reloaded with pinned model '{model_name}'")
385
+ except Exception as reload_error:
386
+ emit_warning(f"Pinned model applied but reload failed: {reload_error}")
387
+
388
+ return True
389
+
390
+ except Exception as e:
391
+ emit_error(f"Failed to pin model to agent '{agent_name}': {e}")
392
+ return True
393
+
394
+
395
+ @register_command(
396
+ name="unpin",
397
+ description="Unpin a model from an agent (resets to default)",
398
+ usage="/unpin <agent>",
399
+ category="config",
400
+ )
401
+ def handle_unpin_command(command: str) -> bool:
402
+ """Unpin a model from an agent (resets to default)."""
403
+ from code_muse.agents.json_agent import discover_json_agents
404
+ from code_muse.config import get_agent_pinned_model
405
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
406
+
407
+ tokens = command.split()
408
+
409
+ if len(tokens) != 2:
410
+ emit_warning("Usage: /unpin <agent-name>")
411
+
412
+ # Show available agents
413
+ json_agents = discover_json_agents()
414
+
415
+ # Get built-in agents
416
+ from code_muse.agents.agent_manager import get_agent_descriptions
417
+
418
+ builtin_agents = get_agent_descriptions()
419
+
420
+ if builtin_agents:
421
+ emit_info("Available built-in agents:")
422
+ for agent_name, description in builtin_agents.items():
423
+ pinned_model = get_agent_pinned_model(agent_name)
424
+ if pinned_model:
425
+ emit_info(f" {agent_name} - {description} [→ {pinned_model}]")
426
+ else:
427
+ emit_info(f" {agent_name} - {description}")
428
+
429
+ if json_agents:
430
+ emit_info("\nAvailable JSON agents:")
431
+ for agent_name, agent_path in json_agents.items():
432
+ # Read the JSON file to check for pinned model
433
+ try:
434
+ with open(agent_path) as f:
435
+ agent_config = json.load(f)
436
+ pinned_model = agent_config.get("model")
437
+ if pinned_model:
438
+ emit_info(f" {agent_name} ({agent_path}) [→ {pinned_model}]")
439
+ else:
440
+ emit_info(f" {agent_name} ({agent_path})")
441
+ except Exception:
442
+ emit_info(f" {agent_name} ({agent_path})")
443
+ return True
444
+
445
+ agent_name_input = tokens[1].lower()
446
+
447
+ # Check if this is a JSON agent or a built-in Python agent
448
+ json_agents = discover_json_agents()
449
+
450
+ # Get list of available built-in agents
451
+ from code_muse.agents.agent_manager import get_agent_descriptions
452
+
453
+ builtin_agents = get_agent_descriptions()
454
+
455
+ # Find matching agent (case-insensitive)
456
+ agent_name = None
457
+ is_json_agent = False
458
+ is_builtin_agent = False
459
+
460
+ # Check JSON agents (case-insensitive)
461
+ for json_agent_name in json_agents:
462
+ if json_agent_name.lower() == agent_name_input:
463
+ agent_name = json_agent_name
464
+ is_json_agent = True
465
+ break
466
+
467
+ # Check built-in agents (case-insensitive)
468
+ if not is_json_agent:
469
+ for builtin_agent_name in builtin_agents:
470
+ if builtin_agent_name.lower() == agent_name_input:
471
+ agent_name = builtin_agent_name
472
+ is_builtin_agent = True
473
+ break
474
+
475
+ if not is_json_agent and not is_builtin_agent:
476
+ emit_error(f"Agent '{agent_name_input}' not found")
477
+
478
+ # Show available agents
479
+ if builtin_agents:
480
+ emit_info("Available built-in agents:")
481
+ for name, desc in builtin_agents.items():
482
+ emit_info(f" {name} - {desc}")
483
+
484
+ if json_agents:
485
+ emit_info("\nAvailable JSON agents:")
486
+ for name, path in json_agents.items():
487
+ emit_info(f" {name} ({path})")
488
+ return True
489
+
490
+ try:
491
+ if is_json_agent:
492
+ # Handle JSON agent - remove the model from JSON file
493
+ agent_file_path = json_agents[agent_name]
494
+
495
+ with open(agent_file_path, encoding="utf-8") as f:
496
+ agent_config = json.load(f)
497
+
498
+ # Remove the model key if it exists
499
+ if "model" in agent_config:
500
+ del agent_config["model"]
501
+
502
+ # Save the updated configuration
503
+ with open(agent_file_path, "w", encoding="utf-8") as f:
504
+ json.dump(agent_config, f, indent=2, ensure_ascii=False)
505
+
506
+ else:
507
+ # Handle built-in Python agent - clear from config
508
+ from code_muse.config import clear_agent_pinned_model
509
+
510
+ clear_agent_pinned_model(agent_name)
511
+
512
+ emit_success(f"Model unpinned from agent '{agent_name}' (reset to default)")
513
+
514
+ # If this is the current agent, refresh it so the prompt updates immediately
515
+ from code_muse.agents import get_current_agent
516
+
517
+ current_agent = get_current_agent()
518
+ if current_agent.name == agent_name:
519
+ try:
520
+ if is_json_agent and hasattr(current_agent, "refresh_config"):
521
+ current_agent.refresh_config()
522
+ current_agent.reload_code_generation_agent()
523
+ emit_info("Active agent reloaded with default model")
524
+ except Exception as reload_error:
525
+ emit_warning(f"Model unpinned but reload failed: {reload_error}")
526
+
527
+ return True
528
+
529
+ except Exception as e:
530
+ emit_error(f"Failed to unpin model from agent '{agent_name}': {e}")
531
+ return True
532
+
533
+
534
+ @register_command(
535
+ name="diff",
536
+ description="Configure diff highlighting colors (additions, deletions)",
537
+ usage="/diff",
538
+ category="config",
539
+ )
540
+ def handle_diff_command(command: str) -> bool:
541
+ """Configure diff highlighting colors."""
542
+ import asyncio
543
+ import concurrent.futures
544
+
545
+ from code_muse.command_line.diff_menu import interactive_diff_picker
546
+ from code_muse.config import (
547
+ set_diff_addition_color,
548
+ set_diff_deletion_color,
549
+ )
550
+ from code_muse.messaging import emit_error
551
+
552
+ # Show interactive picker for diff configuration.
553
+ # FREE-THREADED: ThreadPoolExecutor is compatible with free-threaded Python 3.14.
554
+ with concurrent.futures.ThreadPoolExecutor() as executor:
555
+ future = executor.submit(lambda: asyncio.run(interactive_diff_picker()))
556
+ result = future.result(timeout=300) # 5 min timeout
557
+
558
+ if result:
559
+ # Apply the changes silently (no console output)
560
+ try:
561
+ set_diff_addition_color(result["add_color"])
562
+ set_diff_deletion_color(result["del_color"])
563
+ except Exception as e:
564
+ emit_error(f"Failed to apply diff settings: {e}")
565
+ return True
566
+
567
+
568
+ @register_command(
569
+ name="colors",
570
+ description="Configure banner colors for tool outputs (THINKING, SHELL COMMAND, etc.)",
571
+ usage="/colors",
572
+ category="config",
573
+ )
574
+ def handle_colors_command(command: str) -> bool:
575
+ """Configure banner colors via interactive TUI."""
576
+ import asyncio
577
+ import concurrent.futures
578
+
579
+ from code_muse.command_line.colors_menu import interactive_colors_picker
580
+ from code_muse.config import set_banner_color
581
+ from code_muse.messaging import emit_error, emit_success
582
+
583
+ # Show interactive picker for banner color configuration.
584
+ # FREE-THREADED: ThreadPoolExecutor is compatible with free-threaded Python 3.14.
585
+ with concurrent.futures.ThreadPoolExecutor() as executor:
586
+ future = executor.submit(lambda: asyncio.run(interactive_colors_picker()))
587
+ result = future.result(timeout=300) # 5 min timeout
588
+
589
+ if result:
590
+ # Apply the changes
591
+ try:
592
+ for banner_name, color in result.items():
593
+ set_banner_color(banner_name, color)
594
+ emit_success("Banner colors saved! šŸŽØ")
595
+ except Exception as e:
596
+ emit_error(f"Failed to apply banner color settings: {e}")
597
+ return True
598
+
599
+
600
+ # ============================================================================
601
+ # UTILITY FUNCTIONS
602
+ # ============================================================================
603
+
604
+
605
+ def _show_color_options(color_type: str):
606
+ # ============================================================================
607
+ # UTILITY FUNCTIONS
608
+ # ============================================================================
609
+
610
+ """Show available Rich color options organized by category."""
611
+ from rich.text import Text
612
+
613
+ from code_muse.messaging import emit_info
614
+
615
+ # Standard Rich colors organized by category
616
+ color_categories = {
617
+ "Basic Colors": [
618
+ ("black", "⚫"),
619
+ ("red", "šŸ”“"),
620
+ ("green", "🟢"),
621
+ ("yellow", "🟔"),
622
+ ("blue", "šŸ”µ"),
623
+ ("magenta", "🟣"),
624
+ ("cyan", "šŸ”·"),
625
+ ("white", "⚪"),
626
+ ],
627
+ "Bright Colors": [
628
+ ("bright_black", "⚫"),
629
+ ("bright_red", "šŸ”“"),
630
+ ("bright_green", "🟢"),
631
+ ("bright_yellow", "🟔"),
632
+ ("bright_blue", "šŸ”µ"),
633
+ ("bright_magenta", "🟣"),
634
+ ("bright_cyan", "šŸ”·"),
635
+ ("bright_white", "⚪"),
636
+ ],
637
+ "Special Colors": [
638
+ ("orange1", "🟠"),
639
+ ("orange3", "🟠"),
640
+ ("orange4", "🟠"),
641
+ ("deep_sky_blue1", "šŸ”·"),
642
+ ("deep_sky_blue2", "šŸ”·"),
643
+ ("deep_sky_blue3", "šŸ”·"),
644
+ ("deep_sky_blue4", "šŸ”·"),
645
+ ("turquoise2", "šŸ”·"),
646
+ ("turquoise4", "šŸ”·"),
647
+ ("steel_blue1", "šŸ”·"),
648
+ ("steel_blue3", "šŸ”·"),
649
+ ("chartreuse1", "🟢"),
650
+ ("chartreuse2", "🟢"),
651
+ ("chartreuse3", "🟢"),
652
+ ("chartreuse4", "🟢"),
653
+ ("gold1", "🟔"),
654
+ ("gold3", "🟔"),
655
+ ("rosy_brown", "šŸ”“"),
656
+ ("indian_red", "šŸ”“"),
657
+ ],
658
+ }
659
+
660
+ # Suggested colors for each type
661
+ if color_type == "additions":
662
+ suggestions = [
663
+ ("green", "🟢"),
664
+ ("bright_green", "🟢"),
665
+ ("chartreuse1", "🟢"),
666
+ ("green3", "🟢"),
667
+ ("sea_green1", "🟢"),
668
+ ]
669
+ emit_info(
670
+ Text.from_markup(
671
+ "[bold white on green]šŸŽØ Recommended Colors for Additions:[/bold white on green]"
672
+ )
673
+ )
674
+ for color, emoji in suggestions:
675
+ emit_info(
676
+ Text.from_markup(
677
+ f" [cyan]{color:<16}[/cyan] [white on {color}]ā– ā– ā– ā– ā– ā– ā– ā– ā– ā– [/white on {color}] {emoji}"
678
+ )
679
+ )
680
+ elif color_type == "deletions":
681
+ suggestions = [
682
+ ("orange1", "🟠"),
683
+ ("red", "šŸ”“"),
684
+ ("bright_red", "šŸ”“"),
685
+ ("indian_red", "šŸ”“"),
686
+ ("dark_red", "šŸ”“"),
687
+ ]
688
+ emit_info(
689
+ Text.from_markup(
690
+ "[bold white on orange1]šŸŽØ Recommended Colors for Deletions:[/bold white on orange1]"
691
+ )
692
+ )
693
+ for color, emoji in suggestions:
694
+ emit_info(
695
+ Text.from_markup(
696
+ f" [cyan]{color:<16}[/cyan] [white on {color}]ā– ā– ā– ā– ā– ā– ā– ā– ā– ā– [/white on {color}] {emoji}"
697
+ )
698
+ )
699
+
700
+ emit_info("\nšŸŽØ All Available Rich Colors:")
701
+ for category, colors in color_categories.items():
702
+ emit_info(f"\n{category}:")
703
+ # Display in columns for better readability
704
+ for i in range(0, len(colors), 4):
705
+ row = colors[i : i + 4]
706
+ row_text = " ".join([f"[{color}]ā– [/{color}] {color}" for color, _ in row])
707
+ emit_info(Text.from_markup(f" {row_text}"))
708
+
709
+ emit_info("\nUsage: /diff {color_type} <color_name>")
710
+ emit_info("All diffs use white text on your chosen background colors")
711
+ emit_info("You can also use hex colors like #ff0000 or rgb(255,0,0)")