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,510 @@
1
+ """Interactive mode loop for Muse."""
2
+
3
+ import asyncio
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from code_muse.agents import get_current_agent
9
+ from code_muse.cli_runner.runner import _render_response, run_prompt_with_attachments
10
+ from code_muse.command_line.attachments import parse_prompt_attachments
11
+ from code_muse.command_line.clipboard import get_clipboard_manager
12
+ from code_muse.command_line.command_handler import handle_command
13
+ from code_muse.command_line.shell_passthrough import (
14
+ execute_shell_passthrough,
15
+ is_shell_passthrough,
16
+ )
17
+ from code_muse.command_line.wiggum_state import (
18
+ get_wiggum_prompt,
19
+ increment_wiggum_count,
20
+ is_wiggum_active,
21
+ stop_wiggum,
22
+ )
23
+ from code_muse.config import (
24
+ AUTOSAVE_DIR,
25
+ COMMAND_HISTORY_FILE,
26
+ auto_save_session_if_enabled,
27
+ finalize_autosave_session,
28
+ save_command_to_history,
29
+ )
30
+ from code_muse.keymap import get_cancel_agent_display_name
31
+ from code_muse.messaging import (
32
+ emit_error,
33
+ emit_info,
34
+ emit_success,
35
+ emit_system_message,
36
+ emit_warning,
37
+ )
38
+ from code_muse.terminal_utils import (
39
+ print_truecolor_warning,
40
+ reset_windows_terminal_ansi,
41
+ reset_windows_terminal_full,
42
+ )
43
+
44
+
45
+ def _show_startup_info(display_console) -> None:
46
+ """Display startup messages and terminal capability warnings."""
47
+ emit_system_message(
48
+ "Type '/exit', '/quit', or press Ctrl+D to exit the interactive mode."
49
+ )
50
+ emit_system_message("Type 'clear' to reset the conversation history.")
51
+ emit_system_message("Type /help to view all commands")
52
+ emit_system_message(
53
+ "Type @ for path completion, or /model to pick a model. "
54
+ "Toggle multiline with Alt+M or F2; newline: Ctrl+J."
55
+ )
56
+ emit_system_message("Paste images: Ctrl+V (even on Mac!), F3, or /paste command.")
57
+ import platform
58
+
59
+ if platform.system() == "Darwin":
60
+ emit_system_message(
61
+ "šŸ’” macOS tip: Use Ctrl+V (not Cmd+V) to paste images in terminal."
62
+ )
63
+ cancel_key = get_cancel_agent_display_name()
64
+ emit_system_message(
65
+ f"Press {cancel_key} during processing to cancel the current task "
66
+ f"or inference. Use Ctrl+X to interrupt running shell commands."
67
+ )
68
+ emit_system_message(
69
+ "Use /autosave_load to manually load a previous autosave session."
70
+ )
71
+ emit_system_message(
72
+ "Use /diff to configure diff highlighting colors for file changes."
73
+ )
74
+ emit_system_message("To re-run the tutorial, use /tutorial.")
75
+ emit_system_message(
76
+ "!<command> to run shell commands directly (e.g., !git status)",
77
+ )
78
+ # Print truecolor warning LAST so it's the most visible thing on startup
79
+ # Big ugly red box should be impossible to miss! šŸ”“
80
+ print_truecolor_warning(display_console)
81
+
82
+
83
+ async def _handle_initial_command(initial_command: str, agent, display_console) -> bool:
84
+ """Process an initial command passed on the CLI before entering the main loop.
85
+
86
+ Returns True if the initial command was fully handled, False otherwise.
87
+ """
88
+ if is_shell_passthrough(initial_command):
89
+ execute_shell_passthrough(initial_command)
90
+ return True
91
+
92
+ emit_info(f"Processing initial command: {initial_command}")
93
+
94
+ try:
95
+ # Check if any tool is waiting for user input before showing spinner
96
+ try:
97
+ from code_muse.tools.command_runner import is_awaiting_user_input
98
+
99
+ awaiting_input = is_awaiting_user_input()
100
+ except ImportError:
101
+ awaiting_input = False
102
+
103
+ # Run with or without spinner based on whether we're awaiting input
104
+ response, agent_task = await run_prompt_with_attachments(
105
+ agent,
106
+ initial_command,
107
+ spinner_console=display_console,
108
+ use_spinner=not awaiting_input,
109
+ )
110
+ if response is not None:
111
+ agent_response = response.output
112
+
113
+ # Update the agent's message history with the complete conversation
114
+ # including the final assistant response
115
+ if hasattr(response, "all_messages"):
116
+ agent.set_message_history(list(response.all_messages()))
117
+
118
+ # Emit structured message for proper markdown rendering
119
+ from code_muse.messaging import get_message_bus
120
+ from code_muse.messaging.messages import AgentResponseMessage
121
+
122
+ response_msg = AgentResponseMessage(
123
+ content=agent_response,
124
+ is_markdown=True,
125
+ )
126
+ get_message_bus().emit(response_msg)
127
+
128
+ emit_success("Continuing in Interactive Mode")
129
+ emit_system_message(
130
+ "Your command and response are preserved in the conversation history."
131
+ )
132
+
133
+ except Exception as e:
134
+ emit_error(f"Error processing initial command: {str(e)}")
135
+ return False
136
+
137
+ return True
138
+
139
+
140
+ def _ensure_prompt_toolkit() -> None:
141
+ """Ensure prompt_toolkit is installed, installing it if missing."""
142
+ try:
143
+ from code_muse.command_line.prompt_toolkit_completion import (
144
+ get_input_with_combined_completion, # noqa: F401
145
+ get_prompt_with_active_model, # noqa: F401
146
+ )
147
+ except ImportError:
148
+ emit_warning("Warning: prompt_toolkit not installed. Installing now...")
149
+ try:
150
+ import subprocess
151
+
152
+ subprocess.check_call(
153
+ [sys.executable, "-m", "pip", "install", "--quiet", "prompt_toolkit"]
154
+ )
155
+
156
+ emit_success("Successfully installed prompt_toolkit")
157
+ except Exception as e:
158
+ emit_error(f"Error installing prompt_toolkit: {e}")
159
+ emit_warning("Falling back to basic input without tab completion")
160
+
161
+
162
+ def _maybe_run_onboarding() -> None:
163
+ """Run the onboarding tutorial on first startup if needed."""
164
+ try:
165
+ from code_muse.command_line.onboarding_wizard import should_show_onboarding
166
+
167
+ if should_show_onboarding():
168
+ import concurrent.futures
169
+
170
+ from code_muse.command_line.onboarding_wizard import run_onboarding_wizard
171
+ from code_muse.config import set_model_name
172
+
173
+ # FREE-THREADED: ThreadPoolExecutor works with free-threaded Python 3.14.
174
+ with concurrent.futures.ThreadPoolExecutor() as executor:
175
+ future = executor.submit(lambda: asyncio.run(run_onboarding_wizard()))
176
+ result = future.result(timeout=300)
177
+
178
+ if result == "chatgpt":
179
+ emit_info("šŸ” Starting ChatGPT OAuth flow...")
180
+ from code_muse.plugins.chatgpt_oauth.oauth_flow import run_oauth_flow
181
+
182
+ run_oauth_flow()
183
+ set_model_name("chatgpt-gpt-5.4")
184
+ elif result == "claude":
185
+ emit_info("šŸ” Starting Claude Code OAuth flow...")
186
+ from code_muse.plugins.claude_code_oauth.register_callbacks import (
187
+ _perform_authentication,
188
+ )
189
+
190
+ _perform_authentication()
191
+ set_model_name("claude-code-claude-opus-4-7")
192
+ elif result == "completed":
193
+ emit_info("šŸŽ‰ Tutorial complete! Happy coding!")
194
+ elif result == "skipped":
195
+ emit_info("ā­ļø Tutorial skipped. Run /tutorial anytime!")
196
+ except Exception as e:
197
+ emit_warning(f"Tutorial auto-start failed: {e}")
198
+
199
+
200
+ async def _read_user_input(message_renderer, display_console) -> str:
201
+ """Read user input via prompt_toolkit or fallback to basic input."""
202
+ try:
203
+ from code_muse.command_line.prompt_toolkit_completion import (
204
+ get_input_with_combined_completion,
205
+ get_prompt_with_active_model,
206
+ )
207
+
208
+ reset_windows_terminal_ansi()
209
+ task = await get_input_with_combined_completion(
210
+ get_prompt_with_active_model(), history_file=COMMAND_HISTORY_FILE
211
+ )
212
+ try:
213
+ from code_muse.terminal_utils import ensure_ctrl_c_disabled
214
+
215
+ ensure_ctrl_c_disabled()
216
+ except ImportError:
217
+ pass
218
+ return task
219
+ except ImportError:
220
+ return input(">>> ")
221
+
222
+
223
+ def _handle_keyboard_interrupt(display_console) -> None:
224
+ """Handle Ctrl+C during input by resetting terminal and stopping wiggum."""
225
+ reset_windows_terminal_full()
226
+
227
+ if is_wiggum_active():
228
+ stop_wiggum()
229
+ emit_warning("\nšŸ© Wiggum loop stopped!")
230
+ else:
231
+ emit_warning("\nInput cancelled")
232
+
233
+
234
+ async def _cancel_agent_task_if_running(current_agent_task) -> None:
235
+ """Cancel a running agent task and await its completion."""
236
+ if current_agent_task and not current_agent_task.done():
237
+ emit_info("Cancelling running agent task...")
238
+ current_agent_task.cancel()
239
+ try: # noqa: SIM105
240
+ await current_agent_task
241
+ except asyncio.CancelledError:
242
+ pass
243
+
244
+
245
+ async def _handle_eof() -> None:
246
+ """Handle Ctrl+D by printing goodbye."""
247
+ emit_success("\nGoodbye! (Ctrl+D)")
248
+
249
+
250
+ def _is_shell_passthrough_and_execute(task: str) -> bool:
251
+ """If the task is a shell passthrough, execute it and return True."""
252
+
253
+ if is_shell_passthrough(task):
254
+ execute_shell_passthrough(task)
255
+ return True
256
+ return False
257
+
258
+
259
+ async def _is_exit_command(task: str) -> bool:
260
+ """Check for exit commands and return True if exiting."""
261
+ if task.strip().lower() in ["exit", "quit"] or task.strip().lower() in [
262
+ "/exit",
263
+ "/quit",
264
+ ]:
265
+ emit_success("Goodbye!")
266
+ return True
267
+ return False
268
+
269
+
270
+ def _is_clear_command(task: str) -> bool:
271
+ """Check for clear commands, rotate session and clear history if matched."""
272
+ if task.strip().lower() in ("clear", "/clear"):
273
+ agent = get_current_agent()
274
+ new_session_id = finalize_autosave_session()
275
+ agent.clear_message_history()
276
+ emit_warning("Conversation history cleared!")
277
+ emit_system_message("The agent will not remember previous interactions.")
278
+ emit_info(f"Auto-save session rotated to: {new_session_id}")
279
+ clipboard_manager = get_clipboard_manager()
280
+ clipboard_count = clipboard_manager.get_pending_count()
281
+ clipboard_manager.clear_pending()
282
+ if clipboard_count > 0:
283
+ emit_info(f"Cleared {clipboard_count} pending clipboard image(s)")
284
+ return True
285
+ return False
286
+
287
+
288
+ async def _handle_slash_command(cleaned: str):
289
+ """Route a slash command and return a sentinel or the prompt to execute."""
290
+
291
+ try:
292
+ command_result = handle_command(cleaned)
293
+ except Exception as e:
294
+ emit_error(f"Command error: {e}")
295
+ return "__CONTINUE__"
296
+ if command_result is True:
297
+ return "__CONTINUE__"
298
+ elif isinstance(command_result, str):
299
+ if command_result == "__AUTOSAVE_LOAD__":
300
+ try:
301
+ use_interactive_picker = sys.stdin.isatty() and sys.stdout.isatty()
302
+ if os.getenv("MUSE_NO_TUI") == "1":
303
+ use_interactive_picker = False
304
+ if use_interactive_picker:
305
+ from code_muse.command_line.autosave_menu import (
306
+ interactive_autosave_picker,
307
+ )
308
+ from code_muse.config import set_current_autosave_from_session_name
309
+ from code_muse.session_storage import (
310
+ load_session,
311
+ restore_autosave_interactively,
312
+ )
313
+
314
+ chosen_session = await interactive_autosave_picker()
315
+ if not chosen_session:
316
+ emit_warning("Autosave load cancelled")
317
+ return "__CONTINUE__"
318
+ base_dir = Path(AUTOSAVE_DIR)
319
+ history = load_session(chosen_session, base_dir)
320
+ agent = get_current_agent()
321
+ agent.set_message_history(history)
322
+ set_current_autosave_from_session_name(chosen_session)
323
+ total_tokens = sum(
324
+ agent.estimate_tokens_for_message(msg) for msg in history
325
+ )
326
+ session_path = base_dir / f"{chosen_session}.json"
327
+ emit_success(
328
+ f"āœ… Autosave loaded: {len(history)} messages "
329
+ f"({total_tokens} tokens)\nšŸ“ From: {session_path}"
330
+ )
331
+ from code_muse.command_line.autosave_menu import (
332
+ display_resumed_history,
333
+ )
334
+
335
+ display_resumed_history(history)
336
+ else:
337
+ await restore_autosave_interactively(Path(AUTOSAVE_DIR))
338
+ except Exception as e:
339
+ emit_error(f"Failed to load autosave: {e}")
340
+ return "__CONTINUE__"
341
+ else:
342
+ return command_result
343
+ elif command_result is False:
344
+ return None
345
+ return None
346
+
347
+
348
+ async def _run_main_input_loop(message_renderer, display_console):
349
+ """Gather and process user input until a non-command task is ready."""
350
+ while True:
351
+ current_agent = get_current_agent()
352
+ user_prompt = current_agent.get_user_prompt() or "Enter your coding task:"
353
+ emit_info(f"{user_prompt}\n")
354
+
355
+ try:
356
+ task = await _read_user_input(message_renderer, display_console)
357
+ except KeyboardInterrupt, asyncio.CancelledError:
358
+ _handle_keyboard_interrupt(display_console)
359
+ continue
360
+ except EOFError:
361
+ await _handle_eof()
362
+ return None
363
+
364
+ if _is_shell_passthrough_and_execute(task):
365
+ continue
366
+ if await _is_exit_command(task):
367
+ return None
368
+ if _is_clear_command(task):
369
+ continue
370
+
371
+ processed = parse_prompt_attachments(task)
372
+ cleaned = (processed.prompt or "").strip()
373
+ if cleaned.startswith("/"):
374
+ action = await _handle_slash_command(cleaned)
375
+ if action == "__CONTINUE__":
376
+ continue
377
+ if isinstance(action, str):
378
+ task = action
379
+
380
+ if task.strip():
381
+ save_command_to_history(task)
382
+ return task
383
+
384
+
385
+ def _handle_agent_cancellation(display_console) -> None:
386
+ """Reset terminal state after an agent task is cancelled."""
387
+ reset_windows_terminal_ansi()
388
+ try:
389
+ from code_muse.terminal_utils import ensure_ctrl_c_disabled
390
+
391
+ ensure_ctrl_c_disabled()
392
+ except ImportError:
393
+ pass
394
+
395
+ if is_wiggum_active():
396
+ stop_wiggum()
397
+ emit_warning("šŸ© Wiggum loop stopped due to cancellation")
398
+
399
+
400
+ async def _render_and_autosave(result, current_agent, display_console) -> None:
401
+ """Render agent response and autosave session."""
402
+ _render_response(result, current_agent, display_console)
403
+ # Brief pause to ensure all messages are rendered
404
+ await asyncio.sleep(0.1)
405
+ auto_save_session_if_enabled()
406
+
407
+
408
+ async def _wiggum_loop(current_agent, message_renderer, display_console):
409
+ """Run the wiggum re-loop until it completes or is cancelled.
410
+
411
+ Returns the current agent after the wiggum loop completes.
412
+ """
413
+ while is_wiggum_active():
414
+ wiggum_prompt = get_wiggum_prompt()
415
+ if not wiggum_prompt:
416
+ stop_wiggum()
417
+ break
418
+
419
+ loop_num = increment_wiggum_count()
420
+ emit_warning(f"\nšŸ© WIGGUM RELOOPING! (Loop #{loop_num})")
421
+ emit_system_message(f"Re-running prompt: {wiggum_prompt}")
422
+
423
+ new_session_id = finalize_autosave_session()
424
+ current_agent.clear_message_history()
425
+ emit_system_message(f"Context cleared. Session rotated to: {new_session_id}")
426
+
427
+ await asyncio.sleep(0.5)
428
+
429
+ try:
430
+ result, _ = await run_prompt_with_attachments(
431
+ current_agent,
432
+ wiggum_prompt,
433
+ spinner_console=message_renderer.console,
434
+ )
435
+
436
+ if result is None:
437
+ emit_warning("Wiggum loop cancelled by user")
438
+ stop_wiggum()
439
+ break
440
+
441
+ await _render_and_autosave(result, current_agent, display_console)
442
+
443
+ except KeyboardInterrupt:
444
+ emit_warning("\nšŸ© Wiggum loop interrupted by Ctrl+C")
445
+ stop_wiggum()
446
+ break
447
+ except Exception as e:
448
+ emit_error(f"Wiggum loop error: {e}")
449
+ stop_wiggum()
450
+ break
451
+
452
+ return current_agent
453
+
454
+
455
+ async def interactive_mode(message_renderer, initial_command: str = None) -> None:
456
+ """Run the agent in interactive mode."""
457
+
458
+ display_console = message_renderer.console
459
+ current_agent = get_current_agent()
460
+
461
+ _show_startup_info(display_console)
462
+
463
+ if initial_command:
464
+ await _handle_initial_command(initial_command, current_agent, display_console)
465
+
466
+ _ensure_prompt_toolkit()
467
+
468
+ # Autosave loading is now manual - use /autosave_load command
469
+
470
+ _maybe_run_onboarding()
471
+
472
+ # Track the current agent task for cancellation on quit
473
+ current_agent_task = None
474
+
475
+ while True:
476
+ task = await _run_main_input_loop(message_renderer, display_console)
477
+ if task is None:
478
+ await _cancel_agent_task_if_running(current_agent_task)
479
+ break
480
+
481
+ current_agent = get_current_agent()
482
+
483
+ try:
484
+ result, current_agent_task = await run_prompt_with_attachments(
485
+ current_agent,
486
+ task,
487
+ spinner_console=message_renderer.console,
488
+ )
489
+ if result is None:
490
+ _handle_agent_cancellation(display_console)
491
+ continue
492
+ await _render_and_autosave(result, current_agent, display_console)
493
+ except Exception:
494
+ from code_muse.messaging.queue_console import get_queue_console
495
+
496
+ get_queue_console().print_exception()
497
+ auto_save_session_if_enabled()
498
+
499
+ current_agent = await _wiggum_loop(
500
+ current_agent, message_renderer, display_console
501
+ )
502
+
503
+ # Re-disable Ctrl+C if needed (uvx mode) - must be done after
504
+ # each iteration as various operations may restore console mode
505
+ try:
506
+ from code_muse.terminal_utils import ensure_ctrl_c_disabled
507
+
508
+ ensure_ctrl_c_disabled()
509
+ except ImportError:
510
+ pass
@@ -0,0 +1,72 @@
1
+ """Resume session logic for Muse."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from code_muse.agents import get_current_agent
7
+ from code_muse.messaging import emit_error, emit_success, emit_warning
8
+ from code_muse.session_storage import load_session
9
+
10
+
11
+ def _resume_session_from_path(raw_path: str, *, allow_legacy: bool = False) -> None:
12
+ """Restore agent message history from a saved session file.
13
+
14
+ Accepts any path (autosaves, contexts, somewhere weird on disk). We don't
15
+ care where it lives — we just decompose into (parent_dir, stem) and reuse
16
+ ``session_storage.load_session`` so we stay DRY.
17
+ """
18
+
19
+ session_path = Path(raw_path).expanduser().resolve()
20
+
21
+ if not session_path.exists():
22
+ emit_error(f"--resume: session file not found: {session_path}")
23
+ sys.exit(1)
24
+
25
+ if session_path.suffix == ".json":
26
+ pass # preferred format
27
+ elif session_path.suffix == ".pkl":
28
+ if not allow_legacy:
29
+ emit_error(
30
+ f"--resume: legacy pickle sessions are blocked by default. "
31
+ f"Use --import-legacy-pickle-session if you "
32
+ f"really need to load {session_path}"
33
+ )
34
+ sys.exit(1)
35
+ emit_warning(
36
+ "DANGER: loading legacy pickle session — this can execute arbitrary code!"
37
+ )
38
+ else:
39
+ emit_error(
40
+ f"--resume: expected a .json session file, "
41
+ f"got '{session_path.suffix}': {session_path}"
42
+ )
43
+ sys.exit(1)
44
+
45
+ try:
46
+ history = load_session(
47
+ session_path.stem, session_path.parent, allow_legacy=allow_legacy
48
+ )
49
+ except Exception as exc:
50
+ emit_error(f"--resume: failed to load session: {exc}")
51
+ sys.exit(1)
52
+
53
+ try:
54
+ agent = get_current_agent()
55
+ agent.set_message_history(history)
56
+ except Exception as exc:
57
+ emit_error(f"--resume: failed to attach history to agent: {exc}")
58
+ sys.exit(1)
59
+
60
+ # Rotate autosave id so we don't clobber the original file we just resumed.
61
+ try:
62
+ from code_muse.config import rotate_autosave_id
63
+
64
+ rotate_autosave_id()
65
+ except Exception:
66
+ pass # autosave rotation is best-effort
67
+
68
+ total_tokens = sum(agent.estimate_tokens_for_message(m) for m in history)
69
+ emit_success(
70
+ f"āœ… Resumed session: {len(history)} messages ({total_tokens} tokens)\n"
71
+ f"šŸ“ From: {session_path}"
72
+ )