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,461 @@
1
+ """GitHub Copilot auth plugin — callback registrations.
2
+
3
+ Provides:
4
+ - ``/copilot-login`` — browser-based GitHub Device Flow auth
5
+ - ``/copilot-status`` — show auth & model status
6
+ - ``/copilot-logout`` — remove tokens and registered Copilot models
7
+ - ``copilot`` model-type handler for ``model_factory``
8
+ """
9
+
10
+ import logging
11
+ from typing import Any
12
+
13
+ from code_muse.callbacks import register_callback
14
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
15
+
16
+ from .config import COPILOT_AUTH_CONFIG
17
+ from .utils import (
18
+ add_models_to_config,
19
+ clear_caches,
20
+ fetch_copilot_models,
21
+ get_api_endpoint_for_host,
22
+ get_token_for_host,
23
+ get_valid_session_token,
24
+ load_copilot_models,
25
+ load_device_tokens,
26
+ poll_for_token,
27
+ remove_copilot_models,
28
+ save_device_token,
29
+ start_device_flow,
30
+ )
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ # ---------------------------------------------------------------------------
36
+ # /help entries
37
+ # ---------------------------------------------------------------------------
38
+
39
+
40
+ def _custom_help() -> list[tuple[str, str]]:
41
+ return [
42
+ (
43
+ "copilot-login",
44
+ "Authenticate with GitHub/GitHub Enterprise Copilot via browser",
45
+ ),
46
+ ("copilot-status", "Show GitHub Copilot authentication status and models"),
47
+ ("copilot-logout", "Remove Copilot tokens and registered models"),
48
+ ]
49
+
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # /copilot-status
53
+ # ---------------------------------------------------------------------------
54
+
55
+
56
+ def _handle_copilot_status() -> None:
57
+ tokens = load_device_tokens()
58
+
59
+ if not tokens:
60
+ emit_warning(
61
+ "🔓 GitHub Copilot: Not authenticated.\n"
62
+ " Run /copilot-login to sign in via your browser."
63
+ )
64
+ return
65
+
66
+ emit_success("🔐 GitHub Copilot: Authenticated")
67
+ for t in tokens:
68
+ host_label = t.host
69
+ user_label = f" ({t.user})" if t.user else ""
70
+ emit_info(f" • {host_label}{user_label}")
71
+
72
+ # Check session token for each host
73
+ for t in tokens:
74
+ session = get_valid_session_token(t.oauth_token, t.host)
75
+ if session:
76
+ emit_info(f" ✅ {t.host}: active session (auto-refreshes on expiry)")
77
+ else:
78
+ emit_warning(
79
+ f" ⚠️ {t.host}: could not obtain a session token — may be expired"
80
+ )
81
+ emit_info(f" Run /copilot-login {t.host} to re-authenticate.")
82
+
83
+ # Registered models
84
+ models = load_copilot_models()
85
+ copilot_models = [
86
+ name
87
+ for name, cfg in models.items()
88
+ if cfg.get("oauth_source") == "copilot-auth-plugin"
89
+ ]
90
+ if copilot_models:
91
+ emit_info(f"🎯 Registered Copilot models: {', '.join(sorted(copilot_models))}")
92
+ else:
93
+ emit_warning(
94
+ "⚠️ No Copilot models registered yet. Run /copilot-login to set up."
95
+ )
96
+
97
+
98
+ # ---------------------------------------------------------------------------
99
+ # /copilot-logout
100
+ # ---------------------------------------------------------------------------
101
+
102
+
103
+ def _handle_copilot_logout() -> None:
104
+ errors: list[str] = []
105
+
106
+ # 1. Remove registered models from copilot_models.json
107
+ removed = remove_copilot_models()
108
+ if removed:
109
+ emit_info(f"Removed {removed} Copilot model(s) from configuration")
110
+ else:
111
+ emit_info("No Copilot models were registered")
112
+
113
+ # 2. Delete on-disk token/session caches
114
+ from .config import get_device_token_storage_path, get_session_cache_path
115
+
116
+ for path in (get_session_cache_path(), get_device_token_storage_path()):
117
+ if path.exists():
118
+ try:
119
+ path.unlink()
120
+ except Exception as exc:
121
+ errors.append(f"Could not remove {path.name}: {exc}")
122
+
123
+ # 3. Clear in-memory session and endpoint caches
124
+ clear_caches()
125
+
126
+ # 4. If the active model was a copilot model, reset it so the app
127
+ # doesn't keep trying to use a model whose tokens are gone.
128
+ try:
129
+ from code_muse.config import (
130
+ clear_model_cache,
131
+ get_model_name,
132
+ reset_session_model,
133
+ )
134
+
135
+ current = get_model_name()
136
+ if current and current.startswith(COPILOT_AUTH_CONFIG["prefix"]):
137
+ reset_session_model()
138
+ clear_model_cache()
139
+ emit_info(f"Reset active model (was {current})")
140
+ except Exception:
141
+ pass # Non-critical — worst case the next prompt will error and user switches
142
+
143
+ # 5. Report outcome
144
+ if errors:
145
+ for err in errors:
146
+ emit_warning(err)
147
+ emit_warning("Copilot logout completed with errors (see above)")
148
+ else:
149
+ emit_success("Copilot logout complete — all tokens removed")
150
+
151
+
152
+ # ---------------------------------------------------------------------------
153
+ # /copilot-login — browser-based GitHub Device Flow
154
+ # ---------------------------------------------------------------------------
155
+
156
+
157
+ def _normalize_github_host(raw_host: str) -> str | None:
158
+ """Validate and normalize a GitHub hostname for safe URL interpolation.
159
+
160
+ The hostname is interpolated into URLs like
161
+ ``https://{host}/login/device/code``, so we must reject anything that
162
+ could alter the URL structure (schemes, paths, credentials, etc.).
163
+
164
+ Returns:
165
+ The cleaned lowercase hostname on success, or ``None`` if the input
166
+ is invalid.
167
+
168
+ Rejects inputs containing:
169
+ - URL schemes (``://``) — e.g. ``https://evil.com``
170
+ - Path segments (``/``, ``\\``) — e.g. ``github.com/evil``
171
+ - Credentials (``@``) — e.g. ``user@attacker.tld``
172
+ - Query strings (``?``) — e.g. ``host?q=1``
173
+ - Fragments (``#``) — e.g. ``host#frag``
174
+ """
175
+ host = raw_host.strip().lower()
176
+ if not host:
177
+ return "github.com"
178
+
179
+ # Block characters that would alter URL structure when interpolated
180
+ unsafe_chars = ("://", "/", "\\", "@", "?", "#")
181
+ for marker in unsafe_chars:
182
+ if marker in host:
183
+ return None
184
+
185
+ # Strip trailing dots (DNS allows them but they're not meaningful here)
186
+ return host.rstrip(".")
187
+
188
+
189
+ def _handle_copilot_login(command: str) -> None:
190
+ """Authenticate with GitHub Copilot via the GitHub Device Flow.
191
+
192
+ Opens a browser for the user to enter a one-time code. Supports
193
+ GitHub Enterprise by passing the hostname:
194
+ ``/copilot-login ghes.example.com``
195
+
196
+ When no hostname is given the user is prompted (default: github.com).
197
+ """
198
+ # Parse optional GHE hostname from command arguments
199
+ parts = command.strip().split()
200
+ host: str | None = None
201
+ if len(parts) > 1:
202
+ host = parts[1].strip()
203
+
204
+ # If no host was provided as an argument, prompt the user
205
+ if not host:
206
+ emit_info(
207
+ "🌐 Enter your GitHub hostname — just the domain, no https:// or path.\n"
208
+ " Examples: github.com, ghe.mycompany.com\n"
209
+ " Press Enter to use github.com."
210
+ )
211
+ try:
212
+ from prompt_toolkit import prompt as pt_prompt
213
+
214
+ raw = pt_prompt("GitHub host: ", default="github.com").strip()
215
+ host = raw if raw else "github.com"
216
+ except ImportError:
217
+ host = "github.com"
218
+ except EOFError, KeyboardInterrupt:
219
+ emit_warning("Copilot login cancelled.")
220
+ return
221
+
222
+ # Validate the hostname before interpolating it into any URLs
223
+ host = _normalize_github_host(host)
224
+ if not host:
225
+ emit_error(
226
+ "Invalid hostname — expected a bare domain like github.com or ghe.mycompany.com.\n"
227
+ " Do not include https://, paths, or special characters."
228
+ )
229
+ return
230
+
231
+ if host != "github.com":
232
+ emit_info(f"Using GitHub Enterprise host: {host}")
233
+
234
+ emit_info(f"🔑 Starting GitHub Device Flow for {host}…")
235
+
236
+ device_resp = start_device_flow(host)
237
+ if not device_resp:
238
+ emit_error(
239
+ "Failed to start Device Flow. Check your network connection "
240
+ "and ensure the host is reachable."
241
+ )
242
+ return
243
+
244
+ user_code = device_resp["user_code"]
245
+ verification_uri = device_resp.get(
246
+ "verification_uri", f"https://{host}/login/device"
247
+ )
248
+ expires_in = int(device_resp.get("expires_in", 900))
249
+ interval = int(device_resp.get("interval", 5))
250
+
251
+ # Show the code prominently
252
+ emit_success(f"🔗 Your one-time code: {user_code}")
253
+ emit_info(f" Open {verification_uri} and enter the code above.")
254
+
255
+ # Try to open the browser
256
+ try:
257
+ import webbrowser
258
+
259
+ from code_muse.tools.common import should_suppress_browser
260
+
261
+ if should_suppress_browser():
262
+ emit_info(f"[HEADLESS MODE] Visit: {verification_uri}")
263
+ else:
264
+ webbrowser.open(verification_uri)
265
+ except Exception as exc:
266
+ logger.debug("Could not open browser: %s", exc)
267
+ emit_info(f"Please open this URL manually: {verification_uri}")
268
+
269
+ emit_info("⏳ Waiting for you to authorize in the browser…")
270
+
271
+ oauth_token = poll_for_token(
272
+ device_code=device_resp["device_code"],
273
+ host=host,
274
+ interval=interval,
275
+ expires_in=expires_in,
276
+ )
277
+
278
+ if not oauth_token:
279
+ emit_error(
280
+ "Authorization was not completed in time, or was denied. "
281
+ "Please try /copilot-login again."
282
+ )
283
+ return
284
+
285
+ emit_success("✅ GitHub authorization successful!")
286
+
287
+ # Persist the token
288
+ if not save_device_token(host, oauth_token):
289
+ emit_warning("Token obtained but could not be saved to disk.")
290
+
291
+ # Exchange for Copilot session token & register models
292
+ emit_info("Exchanging for Copilot session token…")
293
+ session = get_valid_session_token(oauth_token, host)
294
+ if not session:
295
+ emit_warning(
296
+ "Got a GitHub token but could not obtain a Copilot session token.\n"
297
+ " Your GitHub account may not have Copilot access."
298
+ )
299
+ return
300
+
301
+ emit_success("✅ Copilot session token obtained")
302
+
303
+ emit_info("Fetching available Copilot models…")
304
+ model_list = fetch_copilot_models(session, host)
305
+ if model_list and add_models_to_config(model_list, host):
306
+ emit_success(
307
+ f"Registered {len(model_list)} Copilot model(s). "
308
+ "Use the `copilot-` prefix with /model."
309
+ )
310
+ try:
311
+ from code_muse.model_switching import set_model_and_reload_agent
312
+
313
+ default_model = f"{COPILOT_AUTH_CONFIG['prefix']}{model_list[0]}"
314
+ set_model_and_reload_agent(default_model)
315
+ except Exception as exc:
316
+ logger.debug("Could not auto-switch to Copilot model: %s", exc)
317
+ else:
318
+ emit_warning("Could not register Copilot models.")
319
+
320
+
321
+ # ---------------------------------------------------------------------------
322
+ # custom_command dispatcher
323
+ # ---------------------------------------------------------------------------
324
+
325
+
326
+ def _handle_custom_command(command: str, name: str) -> bool | None:
327
+ if not name:
328
+ return None
329
+ if name == "copilot-login":
330
+ _handle_copilot_login(command)
331
+ return True
332
+ if name == "copilot-status":
333
+ _handle_copilot_status()
334
+ return True
335
+ if name == "copilot-logout":
336
+ _handle_copilot_logout()
337
+ return True
338
+ return None
339
+
340
+
341
+ # ---------------------------------------------------------------------------
342
+ # Model-type handler — creates OpenAI-compatible model for Copilot API
343
+ # ---------------------------------------------------------------------------
344
+
345
+
346
+ def _create_copilot_model(model_name: str, model_config: dict, config: dict) -> Any:
347
+ """Create an OpenAI-compatible model backed by GitHub Copilot API.
348
+
349
+ Called by ``model_factory`` when ``type == "copilot"``.
350
+
351
+ Uses a dynamic auth flow that refreshes the short-lived Copilot session
352
+ token automatically before each API request, preventing mid-conversation
353
+ token expiry errors.
354
+ """
355
+ import httpx
356
+ from pydantic_ai.models.openai import OpenAIChatModel
357
+ from pydantic_ai.providers.openai import OpenAIProvider
358
+
359
+ from code_muse.http_utils import create_async_client
360
+
361
+ # Discover token — match against the host stored in the model config
362
+ host = model_config.get("copilot_host", "github.com")
363
+ preferred = get_token_for_host(host)
364
+ if not preferred:
365
+ emit_warning(
366
+ f"No Copilot token available for host '{host}'; skipping model '{model_config.get('name')}'. "
367
+ "Run /copilot-login first."
368
+ )
369
+ return None
370
+
371
+ # Verify we can get an initial session token
372
+ session_token = get_valid_session_token(preferred.oauth_token, preferred.host)
373
+ if not session_token:
374
+ emit_warning(
375
+ f"Could not obtain Copilot session token; skipping model '{model_config.get('name')}'. "
376
+ "Run /copilot-login to re-authenticate."
377
+ )
378
+ return None
379
+
380
+ # Build HTTP client with Copilot-required headers and dynamic token refresh.
381
+ # The CopilotAuth flow replaces the Authorization header before every request,
382
+ # so the session token is always fresh even for long-running conversations.
383
+ copilot_headers = {
384
+ "Editor-Version": COPILOT_AUTH_CONFIG["editor_version"],
385
+ "Editor-Plugin-Version": COPILOT_AUTH_CONFIG["editor_plugin_version"],
386
+ "Copilot-Integration-Id": COPILOT_AUTH_CONFIG["copilot_integration_id"],
387
+ "Openai-Intent": COPILOT_AUTH_CONFIG["openai_intent"],
388
+ }
389
+
390
+ class _CopilotAuth(httpx.Auth):
391
+ """httpx auth flow that refreshes the Copilot session token per-request."""
392
+
393
+ def __init__(self, oauth_token: str, token_host: str):
394
+ self._oauth_token = oauth_token
395
+ self._host = token_host
396
+
397
+ def auth_flow(self, request: httpx.Request):
398
+ token = get_valid_session_token(self._oauth_token, self._host)
399
+ if token:
400
+ request.headers["Authorization"] = f"Bearer {token}"
401
+ yield request
402
+
403
+ client = create_async_client(headers=copilot_headers)
404
+ # Attach the dynamic auth so every request gets a fresh token
405
+ client.auth = _CopilotAuth(preferred.oauth_token, preferred.host)
406
+
407
+ # Use the API endpoint discovered during session-token exchange.
408
+ # Falls back to whatever was stored in the model config at registration.
409
+ base_url = get_api_endpoint_for_host(host)
410
+ if base_url == COPILOT_AUTH_CONFIG["api_base_url"]:
411
+ config_url = model_config.get("custom_endpoint", {}).get("url")
412
+ if config_url:
413
+ base_url = config_url
414
+
415
+ # Use a placeholder API key — the actual token is injected by _CopilotAuth
416
+ provider = OpenAIProvider(
417
+ api_key="copilot-session-managed",
418
+ base_url=base_url,
419
+ http_client=client,
420
+ )
421
+
422
+ # Build a model profile that tells pydantic-ai how to handle thinking.
423
+ # Claude models behind the Copilot API return thinking in a custom field
424
+ # called "reasoning_text" (and encrypted round-trip data in "reasoning_opaque").
425
+ profile = None
426
+ underlying_name = model_config.get("name", "").lower()
427
+ if underlying_name.startswith("claude-"):
428
+ from pydantic_ai.profiles.openai import OpenAIModelProfile
429
+
430
+ from .reasoning_client import patch_client_for_reasoning_opaque
431
+
432
+ # Enable field-mode so thinking persists across tool calls.
433
+ # The reasoning_opaque round-trip interceptor (patched onto the
434
+ # httpx client below) captures the encrypted blob from responses
435
+ # and re-injects it into subsequent requests, preventing 400s.
436
+ profile = OpenAIModelProfile(
437
+ openai_chat_thinking_field="reasoning_text",
438
+ openai_supports_reasoning=True,
439
+ openai_chat_send_back_thinking_parts="field",
440
+ )
441
+ patch_client_for_reasoning_opaque(client, thinking_field="reasoning_text")
442
+
443
+ return OpenAIChatModel(
444
+ model_name=model_config["name"],
445
+ provider=provider,
446
+ profile=profile,
447
+ )
448
+
449
+
450
+ def _register_model_types() -> list[dict[str, Any]]:
451
+ """Register the ``copilot`` model type handler."""
452
+ return [{"type": "copilot", "handler": _create_copilot_model}]
453
+
454
+
455
+ # ---------------------------------------------------------------------------
456
+ # Hook registrations — executed at module import time
457
+ # ---------------------------------------------------------------------------
458
+
459
+ register_callback("custom_command_help", _custom_help)
460
+ register_callback("custom_command", _handle_custom_command)
461
+ register_callback("register_model_type", _register_model_types)