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,347 @@
1
+ """
2
+ Command execution engine for hooks.
3
+
4
+ Handles async command execution with timeout, variable substitution,
5
+ and comprehensive error handling.
6
+
7
+ Claude Code Hook Compatibility:
8
+ - Input is passed via STDIN as JSON (primary method, Claude Code standard)
9
+ - Input is also available via CLAUDE_TOOL_INPUT env var (legacy/convenience)
10
+ - Exit code 0 => success, stdout shown in transcript
11
+ - Exit code 1 => block the operation (stderr used as reason)
12
+ - Exit code 2 => error feedback to Claude (stderr fed back as tool error)
13
+ """
14
+
15
+ import asyncio
16
+ import json
17
+ import logging
18
+ import os
19
+ import re
20
+ import time
21
+ from typing import Any
22
+
23
+ from .matcher import _extract_file_path
24
+ from .models import EventData, ExecutionResult, HookConfig
25
+ from .trust import build_minimal_hook_env, cap_hook_output
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ # Max output from hooks to feed into model context
30
+ _MAX_HOOK_STDOUT = 4096
31
+ _MAX_HOOK_STDERR = 2048
32
+ _MAX_HOOK_STDOUT_LINES = 256
33
+ _MAX_HOOK_STDERR_LINES = 128
34
+
35
+
36
+ def _build_stdin_payload(event_data: EventData) -> bytes:
37
+ """
38
+ Build the JSON payload sent to hook scripts via stdin.
39
+
40
+ Matches the Claude Code hook input format:
41
+ {
42
+ "session_id": "...",
43
+ "hook_event_name": "PreToolUse",
44
+ "tool_name": "Bash",
45
+ "tool_input": { ... },
46
+ "cwd": "/path/to/project",
47
+ "permission_mode": "default"
48
+ }
49
+ """
50
+
51
+ def _make_serializable(obj: Any) -> Any:
52
+ if isinstance(obj, dict):
53
+ return {k: _make_serializable(v) for k, v in obj.items()}
54
+ if isinstance(obj, (list, tuple)):
55
+ return [_make_serializable(v) for v in obj]
56
+ if isinstance(obj, (str, int, float, bool, type(None))):
57
+ return obj
58
+ try:
59
+ return str(obj)
60
+ except Exception:
61
+ return "<unserializable>"
62
+
63
+ payload = {
64
+ "session_id": event_data.context.get("session_id", "muse-session"),
65
+ "hook_event_name": event_data.event_type,
66
+ "tool_name": event_data.tool_name,
67
+ "tool_input": _make_serializable(event_data.tool_args),
68
+ "cwd": os.getcwd(),
69
+ "permission_mode": "default",
70
+ }
71
+ if "result" in event_data.context:
72
+ payload["tool_result"] = _make_serializable(event_data.context["result"])
73
+ if "duration_ms" in event_data.context:
74
+ payload["tool_duration_ms"] = event_data.context["duration_ms"]
75
+
76
+ return json.dumps(payload, ensure_ascii=False).encode("utf-8")
77
+
78
+
79
+ async def execute_hook(
80
+ hook: HookConfig,
81
+ event_data: EventData,
82
+ env_vars: dict[str, str | None] = None,
83
+ ) -> ExecutionResult:
84
+ """
85
+ Execute a hook command with timeout and variable substitution.
86
+
87
+ Trust enforcement:
88
+ - Project hooks (source="project") that are not trusted are blocked
89
+ with a clear skipped/blocked result.
90
+
91
+ Input to the hook script:
92
+ - stdin: JSON object (Claude Code compatible format)
93
+ - env CLAUDE_TOOL_INPUT: JSON string of tool_args (legacy)
94
+ - env CLAUDE_PROJECT_DIR: current working directory
95
+
96
+ Exit code semantics:
97
+ - 0: success (stdout shown in transcript)
98
+ - 1: block operation (stderr becomes block reason)
99
+ - 2: error feedback to Claude without blocking
100
+ """
101
+ # Trust check: project hooks must be explicitly trusted
102
+ if hook.source == "project" and not hook.trusted:
103
+ return ExecutionResult(
104
+ blocked=True,
105
+ hook_command=hook.command,
106
+ stdout="",
107
+ stderr="Hook blocked: project hook not trusted. Run /trust-hooks or approve in settings.",
108
+ exit_code=1,
109
+ duration_ms=0.0,
110
+ error="Project hook blocked: not explicitly trusted",
111
+ hook_id=hook.id,
112
+ )
113
+
114
+ if hook.type == "prompt":
115
+ return ExecutionResult(
116
+ blocked=False,
117
+ hook_command=hook.command,
118
+ stdout=hook.command,
119
+ exit_code=0,
120
+ duration_ms=0.0,
121
+ hook_id=hook.id,
122
+ )
123
+
124
+ command = _substitute_variables(hook.command, event_data, env_vars or {})
125
+ stdin_payload = _build_stdin_payload(event_data)
126
+ start_time = time.perf_counter()
127
+
128
+ try:
129
+ env = _build_environment(event_data, env_vars, hook_source=hook.source)
130
+
131
+ proc = await asyncio.create_subprocess_shell(
132
+ command,
133
+ stdin=asyncio.subprocess.PIPE,
134
+ stdout=asyncio.subprocess.PIPE,
135
+ stderr=asyncio.subprocess.PIPE,
136
+ cwd=os.getcwd(),
137
+ env=env,
138
+ )
139
+
140
+ try:
141
+ stdout, stderr = await asyncio.wait_for(
142
+ proc.communicate(input=stdin_payload),
143
+ timeout=hook.timeout / 1000.0,
144
+ )
145
+ except TimeoutError:
146
+ try:
147
+ proc.kill()
148
+ await proc.wait()
149
+ except Exception:
150
+ pass
151
+
152
+ duration_ms = (time.perf_counter() - start_time) * 1000
153
+ return ExecutionResult(
154
+ blocked=True,
155
+ hook_command=command,
156
+ stdout="",
157
+ stderr=f"Command timed out after {hook.timeout}ms",
158
+ exit_code=-1,
159
+ duration_ms=duration_ms,
160
+ error=f"Hook execution timed out after {hook.timeout}ms",
161
+ hook_id=hook.id,
162
+ )
163
+
164
+ duration_ms = (time.perf_counter() - start_time) * 1000
165
+ stdout_str = stdout.decode("utf-8", errors="replace") if stdout else ""
166
+ stderr_str = stderr.decode("utf-8", errors="replace") if stderr else ""
167
+
168
+ # Cap output to prevent unbounded model context growth
169
+ stdout_str = cap_hook_output(
170
+ stdout_str, _MAX_HOOK_STDOUT, _MAX_HOOK_STDOUT_LINES
171
+ )
172
+ stderr_str = cap_hook_output(
173
+ stderr_str, _MAX_HOOK_STDERR, _MAX_HOOK_STDERR_LINES
174
+ )
175
+
176
+ exit_code = proc.returncode or 0
177
+
178
+ blocked = exit_code == 1
179
+ error = stderr_str if exit_code != 0 and stderr_str else None
180
+
181
+ return ExecutionResult(
182
+ blocked=blocked,
183
+ hook_command=command,
184
+ stdout=stdout_str,
185
+ stderr=stderr_str,
186
+ exit_code=exit_code,
187
+ duration_ms=duration_ms,
188
+ error=error,
189
+ hook_id=hook.id,
190
+ )
191
+
192
+ except Exception as e:
193
+ duration_ms = (time.perf_counter() - start_time) * 1000
194
+ logger.error(f"Hook execution failed: {e}", exc_info=True)
195
+ return ExecutionResult(
196
+ blocked=False,
197
+ hook_command=command,
198
+ stdout="",
199
+ stderr=str(e),
200
+ exit_code=-1,
201
+ duration_ms=duration_ms,
202
+ error=f"Hook execution error: {e}",
203
+ hook_id=hook.id,
204
+ )
205
+
206
+
207
+ def _substitute_variables(
208
+ command: str,
209
+ event_data: EventData,
210
+ env_vars: dict[str, str],
211
+ ) -> str:
212
+ substitutions = {
213
+ "CLAUDE_PROJECT_DIR": os.getcwd(),
214
+ "tool_name": event_data.tool_name,
215
+ "event_type": event_data.event_type,
216
+ "file": _extract_file_path(event_data.tool_args) or "",
217
+ "CLAUDE_TOOL_INPUT": json.dumps(event_data.tool_args),
218
+ }
219
+ if event_data.context:
220
+ if "result" in event_data.context:
221
+ substitutions["result"] = str(event_data.context["result"])
222
+ if "duration_ms" in event_data.context:
223
+ substitutions["duration_ms"] = str(event_data.context["duration_ms"])
224
+ substitutions.update(env_vars)
225
+
226
+ result = command
227
+ for var, value in substitutions.items():
228
+ result = result.replace(f"${{{var}}}", str(value))
229
+ result = re.sub(
230
+ rf"\${re.escape(var)}(?=\W|$)", lambda m, value=value: str(value), result
231
+ )
232
+ return result
233
+
234
+
235
+ def _build_environment(
236
+ event_data: EventData,
237
+ env_vars: dict[str, str | None] = None,
238
+ hook_source: str = "global",
239
+ ) -> dict[str, str]:
240
+ """Build environment for hook execution.
241
+
242
+ Project hooks receive a stripped-down environment with secret-like
243
+ variables removed. Global hooks receive the full environment.
244
+ """
245
+ env = build_minimal_hook_env() if hook_source == "project" else os.environ.copy()
246
+
247
+ env["CLAUDE_PROJECT_DIR"] = os.getcwd()
248
+ env["CLAUDE_TOOL_INPUT"] = json.dumps(event_data.tool_args)
249
+ env["CLAUDE_TOOL_NAME"] = event_data.tool_name
250
+ env["CLAUDE_HOOK_EVENT"] = event_data.event_type
251
+ env["CLAUDE_CODE_HOOK"] = "1"
252
+
253
+ file_path = _extract_file_path(event_data.tool_args)
254
+ if file_path:
255
+ env["CLAUDE_FILE_PATH"] = file_path
256
+
257
+ if env_vars:
258
+ env.update(env_vars)
259
+ return env
260
+
261
+
262
+ async def execute_hooks_parallel(
263
+ hooks: list[HookConfig],
264
+ event_data: EventData,
265
+ env_vars: dict[str, str | None] = None,
266
+ ) -> list[ExecutionResult]:
267
+ if not hooks:
268
+ return []
269
+ tg_tasks: list[asyncio.Task[ExecutionResult]] = []
270
+ try:
271
+ async with asyncio.TaskGroup() as tg:
272
+ for hook in hooks:
273
+ tg_tasks.append(
274
+ tg.create_task(execute_hook(hook, event_data, env_vars))
275
+ )
276
+ except* Exception:
277
+ pass # exceptions captured per-task below
278
+
279
+ final_results = []
280
+ for i, task in enumerate(tg_tasks):
281
+ exc = task.exception()
282
+ if exc is not None:
283
+ final_results.append(
284
+ ExecutionResult(
285
+ blocked=False,
286
+ hook_command=hooks[i].command,
287
+ stdout="",
288
+ stderr=str(exc),
289
+ exit_code=-1,
290
+ duration_ms=0.0,
291
+ error=f"Hook execution failed: {exc}",
292
+ hook_id=hooks[i].id,
293
+ )
294
+ )
295
+ else:
296
+ final_results.append(task.result())
297
+ return final_results
298
+
299
+
300
+ async def execute_hooks_sequential(
301
+ hooks: list[HookConfig],
302
+ event_data: EventData,
303
+ env_vars: dict[str, str | None] = None,
304
+ stop_on_block: bool = True,
305
+ ) -> list[ExecutionResult]:
306
+ results = []
307
+ for hook in hooks:
308
+ result = await execute_hook(hook, event_data, env_vars)
309
+ results.append(result)
310
+ if stop_on_block and result.blocked:
311
+ logger.debug(f"Hook blocked operation, stopping: {hook.command}")
312
+ break
313
+ return results
314
+
315
+
316
+ def get_blocking_result(results: list[ExecutionResult]) -> ExecutionResult | None:
317
+ for result in results:
318
+ if result.blocked:
319
+ return result
320
+ return None
321
+
322
+
323
+ def get_failed_results(results: list[ExecutionResult]) -> list[ExecutionResult]:
324
+ return [result for result in results if not result.success]
325
+
326
+
327
+ def format_execution_summary(results: list[ExecutionResult]) -> str:
328
+ if not results:
329
+ return "No hooks executed"
330
+ total = len(results)
331
+ successful = sum(1 for r in results if r.success)
332
+ blocked = sum(1 for r in results if r.blocked)
333
+ total_duration = sum(r.duration_ms for r in results)
334
+ summary = [
335
+ f"Executed {total} hook(s)",
336
+ f"Successful: {successful}",
337
+ f"Blocked: {blocked}",
338
+ f"Total duration: {total_duration:.2f}ms",
339
+ ]
340
+ if blocked > 0:
341
+ blocking_hooks = [r for r in results if r.blocked]
342
+ summary.append("\nBlocking hooks:")
343
+ for result in blocking_hooks:
344
+ summary.append(f" - {result.hook_command}")
345
+ if result.error:
346
+ summary.append(f" Error: {result.error}")
347
+ return "\n".join(summary)
@@ -0,0 +1,154 @@
1
+ """
2
+ Pattern matching engine for hook filters.
3
+
4
+ Provides flexible pattern matching to determine if a hook should execute
5
+ based on tool name, arguments, and other event data.
6
+ """
7
+
8
+ import re
9
+ from typing import Any
10
+
11
+ from .aliases import get_aliases
12
+
13
+
14
+ def matches(matcher: str, tool_name: str, tool_args: dict[str, Any]) -> bool:
15
+ """
16
+ Evaluate if a matcher pattern matches the tool call.
17
+
18
+ Matcher Syntax:
19
+ - "*" - Matches all tools
20
+ - "ToolName" - Exact tool name match
21
+ - ".ext" - File extension match (e.g., ".py", ".ts")
22
+ - "Pattern1 && Pattern2" - AND condition (all must match)
23
+ - "Pattern1 || Pattern2" - OR condition (any must match)
24
+ """
25
+ if not matcher:
26
+ return False
27
+
28
+ if matcher.strip() == "*":
29
+ return True
30
+
31
+ if "||" in matcher:
32
+ parts = [p.strip() for p in matcher.split("||")]
33
+ return any(matches(part, tool_name, tool_args) for part in parts)
34
+
35
+ if "&&" in matcher:
36
+ parts = [p.strip() for p in matcher.split("&&")]
37
+ return all(matches(part, tool_name, tool_args) for part in parts)
38
+
39
+ return _match_single(matcher.strip(), tool_name, tool_args)
40
+
41
+
42
+ def _match_single(pattern: str, tool_name: str, tool_args: dict[str, Any]) -> bool:
43
+ if pattern == tool_name:
44
+ return True
45
+
46
+ if pattern.lower() == tool_name.lower():
47
+ return True
48
+
49
+ # Check cross-provider aliases: a hook written for "Bash" (Claude Code) should
50
+ # fire when code_muse calls "agent_run_shell_command", and vice-versa.
51
+ tool_aliases = get_aliases(tool_name)
52
+ pattern_aliases = get_aliases(pattern)
53
+ if tool_aliases & pattern_aliases: # non-empty intersection → same logical tool
54
+ return True
55
+
56
+ if pattern.startswith("."):
57
+ file_path = _extract_file_path(tool_args)
58
+ if file_path:
59
+ return file_path.endswith(pattern)
60
+ return False
61
+
62
+ if "*" in pattern:
63
+ parts = pattern.split("*")
64
+ regex_pattern = ".*".join(re.escape(part) for part in parts)
65
+ if re.match(f"^{regex_pattern}$", tool_name, re.IGNORECASE):
66
+ return True
67
+
68
+ if _is_regex_pattern(pattern):
69
+ try:
70
+ if re.search(pattern, tool_name, re.IGNORECASE):
71
+ return True
72
+ file_path = _extract_file_path(tool_args)
73
+ if file_path and re.search(pattern, file_path, re.IGNORECASE):
74
+ return True
75
+ except re.error:
76
+ pass
77
+
78
+ return False
79
+
80
+
81
+ def _extract_file_path(tool_args: dict[str, Any]) -> str | None:
82
+ file_keys = [
83
+ "file_path",
84
+ "file",
85
+ "path",
86
+ "target",
87
+ "input_file",
88
+ "output_file",
89
+ "source",
90
+ "destination",
91
+ "src",
92
+ "dest",
93
+ "filename",
94
+ ]
95
+ for key in file_keys:
96
+ if key in tool_args:
97
+ value = tool_args[key]
98
+ if isinstance(value, str):
99
+ return value
100
+ if hasattr(value, "__fspath__"):
101
+ return str(value)
102
+ for value in tool_args.values():
103
+ if isinstance(value, str) and _looks_like_file_path(value):
104
+ return value
105
+ return None
106
+
107
+
108
+ def _looks_like_file_path(value: str) -> bool:
109
+ if not value:
110
+ return False
111
+ if "." in value and not value.startswith("."):
112
+ parts = value.rsplit(".", 1)
113
+ if len(parts) == 2 and len(parts[1]) <= 10 and parts[1].isalnum():
114
+ return True
115
+ return bool("/" in value or "\\" in value)
116
+
117
+
118
+ def _is_regex_pattern(pattern: str) -> bool:
119
+ regex_chars = ["^", "$", ".", "+", "?", "[", "]", "(", ")", "{", "}", "|", "\\"]
120
+ return any(char in pattern for char in regex_chars)
121
+
122
+
123
+ def extract_file_extension(file_path: str) -> str | None:
124
+ if not file_path or "." not in file_path:
125
+ return None
126
+ if "/" in file_path:
127
+ file_path = file_path.rsplit("/", 1)[-1]
128
+ if "\\" in file_path:
129
+ file_path = file_path.rsplit("\\", 1)[-1]
130
+ if "." in file_path:
131
+ return "." + file_path.rsplit(".", 1)[-1]
132
+ return None
133
+
134
+
135
+ def matches_tool(tool_name: str, *names: str) -> bool:
136
+ return tool_name.lower() in [name.lower() for name in names]
137
+
138
+
139
+ def matches_file_extension(tool_args: dict[str, Any], *extensions: str) -> bool:
140
+ file_path = _extract_file_path(tool_args)
141
+ if not file_path:
142
+ return False
143
+ ext = extract_file_extension(file_path)
144
+ return ext in extensions
145
+
146
+
147
+ def matches_file_pattern(tool_args: dict[str, Any], pattern: str) -> bool:
148
+ file_path = _extract_file_path(tool_args)
149
+ if not file_path:
150
+ return False
151
+ try:
152
+ return bool(re.search(pattern, file_path, re.IGNORECASE))
153
+ except re.error:
154
+ return False