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,528 @@
1
+ """Clipboard image reading and management utilities.
2
+
3
+ Provides cross-platform clipboard image capture:
4
+ - Windows/macOS: Uses PIL.ImageGrab (native)
5
+ - Linux: Falls back to xclip or wl-paste via subprocess
6
+
7
+ Also provides a thread-safe ClipboardAttachmentManager for managing
8
+ pending clipboard image attachments in the CLI.
9
+ """
10
+
11
+ import io
12
+ import logging
13
+ import subprocess
14
+ import sys
15
+ import threading
16
+ import time
17
+
18
+ # Try to import PIL - it's optional but needed for clipboard image support
19
+ try:
20
+ from PIL import Image, ImageGrab
21
+
22
+ PIL_AVAILABLE = True
23
+ # SEC-CLIP-002: Protect against decompression bombs
24
+ # Set explicit limit (PIL default) to prevent memory exhaustion from malicious images
25
+ Image.MAX_IMAGE_PIXELS = 178956970
26
+ except ImportError:
27
+ PIL_AVAILABLE = False
28
+ Image = None # type: ignore[misc, assignment]
29
+ ImageGrab = None # type: ignore[misc, assignment]
30
+
31
+ # Import BinaryContent for pydantic-ai integration
32
+ try:
33
+ from pydantic_ai import BinaryContent
34
+
35
+ BINARY_CONTENT_AVAILABLE = True
36
+ except ImportError:
37
+ BINARY_CONTENT_AVAILABLE = False
38
+ BinaryContent = None # type: ignore[misc, assignment]
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+ # Constants
43
+ MAX_IMAGE_SIZE_BYTES = 10 * 1024 * 1024 # 10MB
44
+ MAX_IMAGE_DIMENSION = 4096 # Max width/height for resize
45
+ MAX_PENDING_IMAGES = (
46
+ 10 # SEC-CLIP-001: Limit pending images to prevent memory exhaustion
47
+ )
48
+ CLIPBOARD_RATE_LIMIT_SECONDS: float = 0.5 # SEC-CLIP-004: Max 2 captures per second
49
+
50
+ # Rate limiting state
51
+ _last_clipboard_capture: float = 0.0
52
+
53
+
54
+ def _safe_open_image(image_bytes: bytes) -> Image.Image | None:
55
+ """Safely open and verify an image from bytes.
56
+
57
+ Verifies image integrity to protect against malicious images.
58
+
59
+ Args:
60
+ image_bytes: Raw image bytes to open.
61
+
62
+ Returns:
63
+ PIL Image if valid, None if verification fails.
64
+ """
65
+ if not PIL_AVAILABLE or Image is None:
66
+ return None
67
+
68
+ try:
69
+ # First pass: verify integrity without fully loading
70
+ verify_image = Image.open(io.BytesIO(image_bytes))
71
+ verify_image.verify() # Checks for corruption/malicious data
72
+
73
+ # Re-open after verify (verify() closes the image)
74
+ image = Image.open(io.BytesIO(image_bytes))
75
+ return image
76
+ except Image.DecompressionBombError as e:
77
+ logger.warning(f"Rejected decompression bomb image: {e}")
78
+ return None
79
+ except Image.UnidentifiedImageError as e:
80
+ logger.warning(f"Rejected unidentified image format: {e}")
81
+ return None
82
+ except OSError as e:
83
+ logger.warning(f"Rejected potentially malicious image: {e}")
84
+ return None
85
+ except Exception as e:
86
+ logger.warning(f"Failed to open/verify image: {type(e).__name__}: {e}")
87
+ return None
88
+
89
+
90
+ def _check_linux_clipboard_tool() -> str | None:
91
+ """Check which Linux clipboard tool is available.
92
+
93
+ Returns:
94
+ 'xclip', 'wl-paste', or None if neither is available.
95
+ """
96
+ # Check for wl-paste first (Wayland)
97
+ try:
98
+ subprocess.run(
99
+ ["wl-paste", "--version"],
100
+ capture_output=True,
101
+ timeout=5,
102
+ )
103
+ return "wl-paste"
104
+ except FileNotFoundError, subprocess.TimeoutExpired:
105
+ pass
106
+
107
+ # Check for xclip (X11)
108
+ try:
109
+ subprocess.run(
110
+ ["xclip", "-version"],
111
+ capture_output=True,
112
+ timeout=5,
113
+ )
114
+ return "xclip"
115
+ except FileNotFoundError, subprocess.TimeoutExpired:
116
+ pass
117
+
118
+ return None
119
+
120
+
121
+ def _get_linux_clipboard_image() -> bytes | None:
122
+ """Get clipboard image on Linux using xclip or wl-paste.
123
+
124
+ Returns:
125
+ PNG bytes if image found, None otherwise.
126
+ """
127
+ tool = _check_linux_clipboard_tool()
128
+
129
+ if tool is None:
130
+ logger.warning(
131
+ "No clipboard tool found on Linux. "
132
+ "Install 'xclip' (X11) or 'wl-clipboard' (Wayland) for clipboard image support."
133
+ )
134
+ return None
135
+
136
+ try:
137
+ if tool == "wl-paste":
138
+ # wl-paste for Wayland
139
+ result = subprocess.run(
140
+ ["wl-paste", "--type", "image/png"],
141
+ capture_output=True,
142
+ timeout=10,
143
+ )
144
+ if result.returncode == 0 and result.stdout:
145
+ return result.stdout
146
+ elif tool == "xclip":
147
+ # xclip for X11
148
+ result = subprocess.run(
149
+ ["xclip", "-selection", "clipboard", "-t", "image/png", "-o"],
150
+ capture_output=True,
151
+ timeout=10,
152
+ )
153
+ if result.returncode == 0 and result.stdout:
154
+ return result.stdout
155
+ except subprocess.TimeoutExpired:
156
+ logger.warning(f"Timeout reading clipboard with {tool}")
157
+ except Exception as e:
158
+ logger.warning(f"Error reading clipboard with {tool}: {e}")
159
+
160
+ return None
161
+
162
+
163
+ def _resize_image_if_needed(image: Image.Image, max_bytes: int) -> Image.Image:
164
+ """Resize image if it exceeds max size when saved as PNG.
165
+
166
+ Args:
167
+ image: PIL Image to potentially resize.
168
+ max_bytes: Maximum allowed size in bytes.
169
+
170
+ Returns:
171
+ Original or resized image.
172
+ """
173
+ if Image is None:
174
+ return image
175
+
176
+ # Check current size
177
+ buffer = io.BytesIO()
178
+ image.save(buffer, format="PNG", optimize=True)
179
+ current_size = buffer.tell()
180
+
181
+ if current_size <= max_bytes:
182
+ return image
183
+
184
+ logger.info(
185
+ f"Image size ({current_size / 1024 / 1024:.2f}MB) exceeds limit "
186
+ f"({max_bytes / 1024 / 1024:.2f}MB), resizing..."
187
+ )
188
+
189
+ # Calculate scale factor to reduce size
190
+ # Rough estimate: size scales with area (width * height)
191
+ scale_factor = (max_bytes / current_size) ** 0.5 * 0.9 # 0.9 for safety margin
192
+
193
+ new_width = int(image.width * scale_factor)
194
+ new_height = int(image.height * scale_factor)
195
+
196
+ # Ensure we don't go below minimum dimensions
197
+ new_width = max(new_width, 100)
198
+ new_height = max(new_height, 100)
199
+
200
+ # Also cap at max dimension
201
+ if new_width > MAX_IMAGE_DIMENSION:
202
+ ratio = MAX_IMAGE_DIMENSION / new_width
203
+ new_width = MAX_IMAGE_DIMENSION
204
+ new_height = int(new_height * ratio)
205
+ if new_height > MAX_IMAGE_DIMENSION:
206
+ ratio = MAX_IMAGE_DIMENSION / new_height
207
+ new_height = MAX_IMAGE_DIMENSION
208
+ new_width = int(new_width * ratio)
209
+
210
+ resized = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
211
+ logger.info(
212
+ f"Resized image from {image.width}x{image.height} to {new_width}x{new_height}"
213
+ )
214
+
215
+ return resized
216
+
217
+
218
+ def has_image_in_clipboard() -> bool:
219
+ """Check if clipboard contains an image.
220
+
221
+ Returns:
222
+ True if clipboard contains an image, False otherwise.
223
+ """
224
+ if sys.platform == "linux":
225
+ # For Linux, we need to actually try to get the image
226
+ # since there's no lightweight "check" method
227
+ tool = _check_linux_clipboard_tool()
228
+ if tool is None:
229
+ return False
230
+
231
+ try:
232
+ if tool == "wl-paste":
233
+ result = subprocess.run(
234
+ ["wl-paste", "--list-types"],
235
+ capture_output=True,
236
+ timeout=5,
237
+ text=True,
238
+ )
239
+ return "image/png" in result.stdout or "image/" in result.stdout
240
+ elif tool == "xclip":
241
+ result = subprocess.run(
242
+ ["xclip", "-selection", "clipboard", "-t", "TARGETS", "-o"],
243
+ capture_output=True,
244
+ timeout=5,
245
+ text=True,
246
+ )
247
+ return "image/png" in result.stdout or "image/" in result.stdout
248
+ except Exception:
249
+ return False
250
+
251
+ return False
252
+
253
+ # Windows/macOS - use PIL
254
+ if not PIL_AVAILABLE:
255
+ return False
256
+
257
+ try:
258
+ image = ImageGrab.grabclipboard()
259
+ return image is not None and isinstance(image, Image.Image)
260
+ except Exception as e:
261
+ logger.debug(f"Error checking clipboard: {e}")
262
+ return False
263
+
264
+
265
+ def get_clipboard_image() -> bytes | None:
266
+ """Get clipboard image as PNG bytes.
267
+
268
+ Handles cross-platform clipboard access:
269
+ - Windows/macOS: Uses PIL.ImageGrab
270
+ - Linux: Uses xclip or wl-paste
271
+
272
+ Images larger than 10MB are automatically resized.
273
+
274
+ Returns:
275
+ PNG bytes if clipboard contains an image, None otherwise.
276
+ """
277
+ image_bytes: bytes | None = None
278
+
279
+ # Linux path - use command line tools
280
+ if sys.platform == "linux":
281
+ image_bytes = _get_linux_clipboard_image()
282
+ if image_bytes is None:
283
+ return None
284
+
285
+ # Check size and resize if needed
286
+ if len(image_bytes) > MAX_IMAGE_SIZE_BYTES:
287
+ if not PIL_AVAILABLE:
288
+ logger.warning(
289
+ f"Image size ({len(image_bytes) / 1024 / 1024:.2f}MB) exceeds limit, "
290
+ "but PIL not available for resizing."
291
+ )
292
+ return None
293
+
294
+ try:
295
+ # Use safe image opening with verification
296
+ image = _safe_open_image(image_bytes)
297
+ if image is None:
298
+ logger.warning(
299
+ "Image verification failed for Linux clipboard image"
300
+ )
301
+ return None
302
+ image = _resize_image_if_needed(image, MAX_IMAGE_SIZE_BYTES)
303
+ buffer = io.BytesIO()
304
+ image.save(buffer, format="PNG", optimize=True)
305
+ image_bytes = buffer.getvalue()
306
+ except Exception as e:
307
+ logger.warning(f"Error resizing Linux clipboard image: {e}")
308
+ return None
309
+ else:
310
+ # Verify even small images for safety
311
+ if PIL_AVAILABLE:
312
+ image = _safe_open_image(image_bytes)
313
+ if image is None:
314
+ logger.warning(
315
+ "Image verification failed for Linux clipboard image"
316
+ )
317
+ return None
318
+
319
+ return image_bytes
320
+
321
+ # Windows/macOS path - use PIL
322
+ if not PIL_AVAILABLE:
323
+ logger.warning("PIL/Pillow not available. Install with: pip install Pillow")
324
+ return None
325
+
326
+ try:
327
+ image = ImageGrab.grabclipboard()
328
+
329
+ if image is None:
330
+ return None
331
+
332
+ if not isinstance(image, Image.Image):
333
+ # Could be a list of file paths on some systems
334
+ logger.debug(f"Clipboard contains non-image data: {type(image)}")
335
+ return None
336
+
337
+ # Log original dimensions
338
+ logger.info(f"Captured clipboard image: {image.width}x{image.height}")
339
+
340
+ # Convert to RGB if necessary (handles RGBA, P mode, etc.)
341
+ if image.mode in ("RGBA", "LA") or (
342
+ image.mode == "P" and "transparency" in image.info
343
+ ):
344
+ # Keep alpha channel for PNG
345
+ pass
346
+ elif image.mode != "RGB":
347
+ image = image.convert("RGB")
348
+
349
+ # Resize if needed
350
+ image = _resize_image_if_needed(image, MAX_IMAGE_SIZE_BYTES)
351
+
352
+ # Convert to PNG bytes
353
+ buffer = io.BytesIO()
354
+ image.save(buffer, format="PNG", optimize=True)
355
+ image_bytes = buffer.getvalue()
356
+
357
+ logger.info(f"Clipboard image size: {len(image_bytes) / 1024:.1f}KB")
358
+ return image_bytes
359
+
360
+ except Exception as e:
361
+ logger.warning(f"Error reading clipboard image: {e}")
362
+ return None
363
+
364
+
365
+ def get_clipboard_image_as_binary_content() -> BinaryContent | None:
366
+ """Get clipboard image as pydantic-ai BinaryContent.
367
+
368
+ This is the preferred method for integrating clipboard images
369
+ with pydantic-ai agents.
370
+
371
+ Returns:
372
+ BinaryContent with PNG image if available, None otherwise.
373
+ """
374
+ if not BINARY_CONTENT_AVAILABLE:
375
+ logger.warning("pydantic-ai BinaryContent not available")
376
+ return None
377
+
378
+ image_bytes = get_clipboard_image()
379
+ if image_bytes is None:
380
+ return None
381
+
382
+ return BinaryContent(data=image_bytes, media_type="image/png")
383
+
384
+
385
+ class ClipboardAttachmentManager:
386
+ """Thread-safe manager for pending clipboard image attachments.
387
+
388
+ This class manages clipboard images that have been captured but not yet
389
+ sent to the AI model. It provides a simple interface for adding images,
390
+ retrieving them as BinaryContent, and clearing the queue.
391
+
392
+ Usage:
393
+ manager = get_clipboard_manager()
394
+ placeholder = manager.add_image(image_bytes)
395
+ # Later, when sending to AI:
396
+ images = manager.get_pending_images()
397
+ manager.clear_pending()
398
+ """
399
+
400
+ def __init__(self) -> None:
401
+ """Initialize the clipboard attachment manager."""
402
+ self._pending_images: list[bytes] = []
403
+ # FREE-THREADED: Clipboard manager is sync-only; keep threading.Lock.
404
+ self._lock = threading.Lock()
405
+ self._counter = 0
406
+
407
+ def add_image(self, image_bytes: bytes) -> str:
408
+ """Add image bytes to pending attachments.
409
+
410
+ Args:
411
+ image_bytes: PNG image bytes to add.
412
+
413
+ Returns:
414
+ Placeholder ID string like '[📋 clipboard image 1]'
415
+
416
+ Raises:
417
+ ValueError: If MAX_PENDING_IMAGES limit is reached.
418
+ """
419
+ with self._lock:
420
+ # SEC-CLIP-001: Check limit BEFORE adding to prevent memory exhaustion
421
+ if len(self._pending_images) >= MAX_PENDING_IMAGES:
422
+ raise ValueError(
423
+ f"Maximum of {MAX_PENDING_IMAGES} pending images reached. "
424
+ "Send your message to clear the queue, or use /paste clear."
425
+ )
426
+ self._counter += 1
427
+ self._pending_images.append(image_bytes)
428
+ placeholder = f"[📋 clipboard image {self._counter}]"
429
+ logger.debug(
430
+ f"Added clipboard image {self._counter} "
431
+ f"({len(image_bytes) / 1024:.1f}KB)"
432
+ )
433
+ return placeholder
434
+
435
+ def get_pending_images(self) -> list[BinaryContent]:
436
+ """Get all pending images as BinaryContent list.
437
+
438
+ Returns:
439
+ List of BinaryContent objects for each pending image.
440
+ Returns empty list if BinaryContent not available.
441
+ """
442
+ if not BINARY_CONTENT_AVAILABLE:
443
+ logger.warning("BinaryContent not available, returning empty list")
444
+ return []
445
+
446
+ with self._lock:
447
+ return [
448
+ BinaryContent(data=img_bytes, media_type="image/png")
449
+ for img_bytes in self._pending_images
450
+ ]
451
+
452
+ def clear_pending(self) -> None:
453
+ """Clear all pending images."""
454
+ with self._lock:
455
+ count = len(self._pending_images)
456
+ self._pending_images.clear()
457
+ if count > 0:
458
+ logger.debug(f"Cleared {count} pending clipboard image(s)")
459
+
460
+ def get_pending_count(self) -> int:
461
+ """Get count of pending images.
462
+
463
+ Returns:
464
+ Number of images currently pending.
465
+ """
466
+ with self._lock:
467
+ return len(self._pending_images)
468
+
469
+ def has_pending(self) -> bool:
470
+ """Check if there are any pending images.
471
+
472
+ Returns:
473
+ True if there are pending images, False otherwise.
474
+ """
475
+ with self._lock:
476
+ return len(self._pending_images) > 0
477
+
478
+
479
+ # Global singleton instance
480
+ _clipboard_manager: ClipboardAttachmentManager | None = None
481
+ # FREE-THREADED: _manager_lock guards sync-only singleton creation.
482
+ _manager_lock = threading.Lock()
483
+
484
+
485
+ def get_clipboard_manager() -> ClipboardAttachmentManager:
486
+ """Get or create the global clipboard manager singleton.
487
+
488
+ Returns:
489
+ The global ClipboardAttachmentManager instance.
490
+ """
491
+ global _clipboard_manager
492
+
493
+ if _clipboard_manager is None:
494
+ with _manager_lock:
495
+ # Double-check locking pattern
496
+ if _clipboard_manager is None:
497
+ _clipboard_manager = ClipboardAttachmentManager()
498
+
499
+ return _clipboard_manager
500
+
501
+
502
+ def capture_clipboard_image_to_pending() -> str | None:
503
+ """Convenience function to capture clipboard image and add to pending.
504
+
505
+ This combines get_clipboard_image() and add_image() into a single call.
506
+ Includes rate limiting to prevent rapid captures (SEC-CLIP-004).
507
+
508
+ Returns:
509
+ Placeholder string if image captured, None if no image or rate limited.
510
+ """
511
+ global _last_clipboard_capture
512
+
513
+ # SEC-CLIP-004: Rate limiting to prevent rapid captures
514
+ now = time.monotonic()
515
+ if now - _last_clipboard_capture < CLIPBOARD_RATE_LIMIT_SECONDS:
516
+ logger.debug("Clipboard capture rate limited")
517
+ return None # Rate limited, silently ignore
518
+
519
+ image_bytes = get_clipboard_image()
520
+ if image_bytes is None:
521
+ return None
522
+
523
+ manager = get_clipboard_manager()
524
+ placeholder = manager.add_image(image_bytes)
525
+
526
+ # Update timestamp on successful capture
527
+ _last_clipboard_capture = now
528
+ return placeholder