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,176 @@
1
+ """Plugin-level config helpers for agent_skills."""
2
+
3
+ import json
4
+ import logging
5
+ from pathlib import Path
6
+
7
+ from code_muse.config import get_value, set_value
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def get_skill_directories() -> list[Path]:
13
+ """Get configured skill directories.
14
+
15
+ Returns:
16
+ List of skill directory paths from configuration.
17
+ Reads from muse.cfg [muse] section under 'skill_directories' key.
18
+ Default: ['~/.muse/skills', './.muse/skills', './skills']
19
+
20
+ The directories are stored as a JSON list in the config.
21
+ """
22
+ # Try to read from config first
23
+ config_value = get_value("skill_directories")
24
+
25
+ if config_value:
26
+ try:
27
+ # Parse as JSON
28
+ directories = json.loads(config_value)
29
+ # Ensure it's a list
30
+ if isinstance(directories, list):
31
+ return [Path(d) for d in directories]
32
+ except json.JSONDecodeError as e:
33
+ logger.error(f"Failed to parse skill_directories config: {e}")
34
+
35
+ # Fallback to defaults
36
+ home_skills = Path.home() / ".muse" / "skills"
37
+ project_config_skills = Path.cwd() / ".muse" / "skills"
38
+ local_skills = Path.cwd() / "skills"
39
+ return [
40
+ home_skills,
41
+ project_config_skills,
42
+ local_skills,
43
+ ]
44
+
45
+
46
+ def add_skill_directory(path: str | Path) -> bool:
47
+ """Add a directory to the skills search path.
48
+
49
+ Args:
50
+ path: Path to add to the skill directories list.
51
+
52
+ Returns:
53
+ True if the directory was added successfully, False otherwise.
54
+ """
55
+ directories = [Path(d) for d in get_skill_directories()]
56
+ path = Path(path)
57
+
58
+ # Check if already exists
59
+ if path in directories:
60
+ logger.info(f"Skill directory already exists: {path}")
61
+ return False
62
+
63
+ # Add the new directory
64
+ directories.append(path)
65
+
66
+ try:
67
+ # Save back to config as JSON
68
+ set_value("skill_directories", json.dumps([str(d) for d in directories]))
69
+ logger.info(f"Added skill directory: {path}")
70
+ return True
71
+ except Exception as e:
72
+ logger.error(f"Failed to add skill directory: {e}")
73
+ return False
74
+
75
+
76
+ def remove_skill_directory(path: str | Path) -> bool:
77
+ """Remove a directory from the skills search path.
78
+
79
+ Args:
80
+ path: Path to remove from the skill directories list.
81
+
82
+ Returns:
83
+ True if the directory was removed successfully, False otherwise.
84
+ """
85
+ directories = [Path(d) for d in get_skill_directories()]
86
+ path = Path(path)
87
+
88
+ # Check if exists
89
+ if path not in directories:
90
+ logger.info(f"Skill directory not found: {path}")
91
+ return False
92
+
93
+ # Remove the directory
94
+ directories.remove(path)
95
+
96
+ try:
97
+ # Save back to config as JSON
98
+ set_value("skill_directories", json.dumps([str(d) for d in directories]))
99
+ logger.info(f"Removed skill directory: {path}")
100
+ return True
101
+ except Exception as e:
102
+ logger.error(f"Failed to remove skill directory: {e}")
103
+ return False
104
+
105
+
106
+ def get_skills_enabled() -> bool:
107
+ """Check if skills integration is globally enabled.
108
+
109
+ Returns:
110
+ True if skills are globally enabled, False otherwise.
111
+ Reads from 'skills_enabled' config key (default: True).
112
+ """
113
+ cfg_val = get_value("skills_enabled")
114
+ if cfg_val is None:
115
+ return True # Enabled by default
116
+ return str(cfg_val).strip().lower() in {"1", "true", "yes", "on"}
117
+
118
+
119
+ def set_skills_enabled(enabled: bool) -> None:
120
+ """Enable or disable skills integration globally.
121
+
122
+ Args:
123
+ enabled: True to enable, False to disable.
124
+ """
125
+ set_value("skills_enabled", "true" if enabled else "false")
126
+ logger.info(f"Skills integration {'enabled' if enabled else 'disabled'}")
127
+
128
+
129
+ def get_disabled_skills() -> set[str]:
130
+ """Get set of explicitly disabled skill names.
131
+
132
+ Returns:
133
+ Set of skill names that are disabled.
134
+ Reads from 'disabled_skills' config key as a JSON list.
135
+ """
136
+ config_value = get_value("disabled_skills")
137
+
138
+ if config_value:
139
+ try:
140
+ # Parse as JSON
141
+ disabled_list = json.loads(config_value)
142
+ # Ensure it's a list and convert to set
143
+ if isinstance(disabled_list, list):
144
+ return set(disabled_list)
145
+ except json.JSONDecodeError as e:
146
+ logger.error(f"Failed to parse disabled_skills config: {e}")
147
+
148
+ return set()
149
+
150
+
151
+ def set_skill_disabled(skill_name: str, disabled: bool) -> None:
152
+ """Disable or re-enable a specific skill.
153
+
154
+ Args:
155
+ skill_name: Name of the skill to disable/enable.
156
+ disabled: True to disable, False to enable.
157
+ """
158
+ disabled_skills = get_disabled_skills()
159
+
160
+ if disabled:
161
+ # Add to disabled set
162
+ if skill_name in disabled_skills:
163
+ logger.info(f"Skill already disabled: {skill_name}")
164
+ return
165
+ disabled_skills.add(skill_name)
166
+ logger.info(f"Disabled skill: {skill_name}")
167
+ else:
168
+ # Remove from disabled set
169
+ if skill_name not in disabled_skills:
170
+ logger.info(f"Skill already enabled: {skill_name}")
171
+ return
172
+ disabled_skills.remove(skill_name)
173
+ logger.info(f"Enabled skill: {skill_name}")
174
+
175
+ # Save back to config as JSON
176
+ set_value("disabled_skills", json.dumps(list(disabled_skills)))
@@ -0,0 +1,309 @@
1
+ """Skill discovery - scans directories for valid skills.
2
+
3
+ Includes safety checks for symlink escapes, hidden directories,
4
+ SKILL.md size validation, and executable file awareness.
5
+ """
6
+
7
+ import contextlib
8
+ import logging
9
+ import stat
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+
13
+ from code_muse.plugins.agent_skills.config import get_skill_directories
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Max SKILL.md file size before we refuse to read (256 KiB)
18
+ MAX_SKILL_MD_BYTES = 256 * 1024
19
+
20
+ # Cap for skill content injected into model context (chars)
21
+ SKILL_CONTEXT_CAP = 64_000
22
+
23
+
24
+ @dataclass
25
+ class SkillInfo:
26
+ """Basic skill information from discovery."""
27
+
28
+ name: str
29
+ path: Path
30
+ has_skill_md: bool
31
+ skill_md_size: int | None = None
32
+ skill_md_hash: str | None = None
33
+ source: str | None = None
34
+ trust: str | None = None # "builtin" | "user" | None
35
+
36
+
37
+ # Global cache for discovered skills
38
+ _skill_cache: list[SkillInfo | None] = None
39
+
40
+
41
+ def _is_symlink_escape(child: Path, parent: Path) -> bool:
42
+ """Return True if *child* resolves outside *parent* (symlink escape)."""
43
+ try:
44
+ child.resolve().relative_to(parent.resolve())
45
+ return False
46
+ except ValueError:
47
+ return True
48
+
49
+
50
+ def _has_unexpected_executables(skill_dir: Path) -> bool:
51
+ """Return True if *skill_dir* contains unexpected executable files.
52
+
53
+ We expect only .md, .txt, .json, .yaml, .yml, .py, .toml files in
54
+ skill directories. Anything with the execute bit set (beyond
55
+ directory traversal) is flagged.
56
+ """
57
+ safe_extensions = {
58
+ ".md",
59
+ ".txt",
60
+ ".json",
61
+ ".yaml",
62
+ ".yml",
63
+ ".py",
64
+ ".toml",
65
+ ".cfg",
66
+ ".ini",
67
+ ".rst",
68
+ ".html",
69
+ ".css",
70
+ ".js",
71
+ }
72
+ try:
73
+ for item in skill_dir.iterdir():
74
+ if not item.is_file():
75
+ continue
76
+ # Skip symlinks that escape
77
+ if item.is_symlink() and _is_symlink_escape(item, skill_dir):
78
+ return True
79
+ # Check for executable bit on non-standard files
80
+ if item.suffix.lower() not in safe_extensions:
81
+ try:
82
+ mode = item.stat().st_mode
83
+ if mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
84
+ logger.warning(
85
+ "Unexpected executable file in skill dir %s: %s",
86
+ skill_dir.name,
87
+ item.name,
88
+ )
89
+ return True
90
+ except OSError:
91
+ pass
92
+ except OSError:
93
+ pass
94
+ return False
95
+
96
+
97
+ def get_default_skill_directories() -> list[Path]:
98
+ """Return default directories to scan for skills.
99
+
100
+ Returns:
101
+ - ~/.muse/skills (user skills)
102
+ - ./.muse/skills (project config skills)
103
+ - ./skills (project skills)
104
+ """
105
+ return [
106
+ Path.home() / ".muse" / "skills",
107
+ Path.cwd() / ".muse" / "skills",
108
+ Path.cwd() / "skills",
109
+ ]
110
+
111
+
112
+ def is_valid_skill_directory(path: Path) -> bool:
113
+ """Check if a directory contains a valid SKILL.md file.
114
+
115
+ Also validates that SKILL.md is not oversized and that
116
+ the directory does not contain unexpected executables.
117
+
118
+ Args:
119
+ path: Directory path to check.
120
+
121
+ Returns:
122
+ True if the directory is a valid skill directory, False otherwise.
123
+ """
124
+ if not path.is_dir():
125
+ return False
126
+
127
+ skill_md_path = path / "SKILL.md"
128
+ if not skill_md_path.is_file():
129
+ return False
130
+
131
+ # Check for symlink escape on SKILL.md
132
+ if _is_symlink_escape(skill_md_path, path):
133
+ logger.warning("SKILL.md in %s is a symlink escape, skipping", path.name)
134
+ return False
135
+
136
+ # Validate SKILL.md size before we ever read it
137
+ try:
138
+ size = skill_md_path.stat().st_size
139
+ if size > MAX_SKILL_MD_BYTES:
140
+ logger.warning(
141
+ "SKILL.md in %s is too large (%d bytes, max %d), skipping",
142
+ path.name,
143
+ size,
144
+ MAX_SKILL_MD_BYTES,
145
+ )
146
+ return False
147
+ except OSError:
148
+ return False
149
+
150
+ # Check for unexpected executable files
151
+ if _has_unexpected_executables(path):
152
+ logger.warning(
153
+ "Skill directory %s contains unexpected executable files, skipping",
154
+ path.name,
155
+ )
156
+ return False
157
+
158
+ return True
159
+
160
+
161
+ def _compute_skill_md_hash(skill_md_path: Path) -> str | None:
162
+ """Compute SHA-256 hash of a SKILL.md file."""
163
+ import hashlib
164
+
165
+ try:
166
+ content = skill_md_path.read_bytes()
167
+ return hashlib.sha256(content).hexdigest()
168
+ except OSError:
169
+ return None
170
+
171
+
172
+ def _classify_skill_source(skill_dir: Path) -> str:
173
+ """Classify a skill directory as 'builtin' or 'user'."""
174
+ home_skills = Path.home() / ".muse" / "skills"
175
+ try:
176
+ skill_dir.resolve().relative_to(home_skills.resolve())
177
+ return "user"
178
+ except ValueError:
179
+ pass
180
+ # Check if it's under CWD
181
+ try:
182
+ skill_dir.resolve().relative_to(Path.cwd().resolve())
183
+ return "project"
184
+ except ValueError:
185
+ pass
186
+ return "unknown"
187
+
188
+
189
+ def discover_skills(directories: list[Path | None] = None) -> list[SkillInfo]:
190
+ """Scan directories for valid skills.
191
+
192
+ Args:
193
+ directories: Directories to scan. If None, uses configured
194
+ directories (which includes user-added ones from /skills menu).
195
+
196
+ Returns:
197
+ List of discovered SkillInfo objects.
198
+ """
199
+ global _skill_cache
200
+
201
+ if directories is None:
202
+ # Use configured directories (respects user-added dirs from /skills menu)
203
+ # then merge with defaults to ensure we always check the standard locations
204
+ configured = [Path(d) for d in get_skill_directories()]
205
+ defaults = get_default_skill_directories()
206
+ # Merge: configured first, then any defaults not already covered
207
+ seen = {p.resolve() for p in configured}
208
+ directories = list(configured)
209
+ for d in defaults:
210
+ if d.resolve() not in seen:
211
+ directories.append(d)
212
+
213
+ discovered_skills: list[SkillInfo] = []
214
+
215
+ for directory in directories:
216
+ if not directory.exists():
217
+ logger.debug("Skill directory does not exist: %s", directory)
218
+ continue
219
+
220
+ if not directory.is_dir():
221
+ logger.warning("Skill path is not a directory: %s", directory)
222
+ continue
223
+
224
+ # Scan subdirectories within the skill directory
225
+ for skill_dir in directory.iterdir():
226
+ if not skill_dir.is_dir():
227
+ continue
228
+
229
+ # Skip hidden directories
230
+ if skill_dir.name.startswith(".") or skill_dir.name.startswith("_"):
231
+ continue
232
+
233
+ # Skip symlink escapes
234
+ if _is_symlink_escape(skill_dir, directory):
235
+ logger.warning(
236
+ "Skipping skill dir %s: symlink escape from %s",
237
+ skill_dir.name,
238
+ directory,
239
+ )
240
+ continue
241
+
242
+ has_skill_md = is_valid_skill_directory(skill_dir)
243
+
244
+ # Compute metadata for valid skills
245
+ skill_md_size = None
246
+ skill_md_hash = None
247
+ if has_skill_md:
248
+ skill_md_path = skill_dir / "SKILL.md"
249
+ with contextlib.suppress(OSError):
250
+ skill_md_size = skill_md_path.stat().st_size
251
+ skill_md_hash = _compute_skill_md_hash(skill_md_path)
252
+
253
+ source = _classify_skill_source(skill_dir)
254
+ # Built-in skills from the package are always trusted
255
+ trust = "builtin" if source == "unknown" else source
256
+
257
+ skill_info = SkillInfo(
258
+ name=skill_dir.name,
259
+ path=skill_dir,
260
+ has_skill_md=has_skill_md,
261
+ skill_md_size=skill_md_size,
262
+ skill_md_hash=skill_md_hash,
263
+ source=source,
264
+ trust=trust,
265
+ )
266
+ discovered_skills.append(skill_info)
267
+
268
+ if has_skill_md:
269
+ logger.debug(
270
+ "Discovered valid skill: %s at %s", skill_dir.name, skill_dir
271
+ )
272
+ else:
273
+ logger.debug(
274
+ "Found skill directory without SKILL.md: %s", skill_dir.name
275
+ )
276
+
277
+ # Update cache
278
+ _skill_cache = discovered_skills
279
+
280
+ logger.info(
281
+ "Discovered %d skills from %d directories",
282
+ len(discovered_skills),
283
+ len(directories),
284
+ )
285
+ return discovered_skills
286
+
287
+
288
+ def refresh_skill_cache() -> list[SkillInfo]:
289
+ """Force re-discovery of all skills.
290
+
291
+ This clears the cache and performs a fresh scan of all default
292
+ skill directories.
293
+
294
+ Returns:
295
+ List of freshly discovered SkillInfo objects.
296
+ """
297
+ global _skill_cache
298
+ _skill_cache = None
299
+ return discover_skills()
300
+
301
+
302
+ def cap_skill_content(content: str, cap: int = SKILL_CONTEXT_CAP) -> str:
303
+ """Cap skill content to prevent model-context blowup.
304
+
305
+ If content exceeds *cap* characters, it is truncated with a marker.
306
+ """
307
+ if len(content) <= cap:
308
+ return content
309
+ return content[:cap] + "\n... [skill content truncated]"