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,304 @@
1
+ """Command handlers for Muse - SESSION commands.
2
+
3
+ This module contains @register_command decorated handlers that are automatically
4
+ discovered by the command registry system.
5
+ """
6
+
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+
10
+ from code_muse.command_line.command_registry import register_command
11
+ from code_muse.config import CONTEXTS_DIR
12
+ from code_muse.session_storage import list_sessions, load_session, save_session
13
+
14
+
15
+ # Import get_commands_help from command_handler to avoid circular imports
16
+ # This will be defined in command_handler.py
17
+ def get_commands_help():
18
+ """Lazy import to avoid circular dependency."""
19
+ from code_muse.command_line.command_handler import get_commands_help as _gch
20
+
21
+ return _gch()
22
+
23
+
24
+ @register_command(
25
+ name="session",
26
+ description="Show or rotate autosave session ID",
27
+ usage="/session [id|new]",
28
+ aliases=["s"],
29
+ category="session",
30
+ detailed_help="""
31
+ Manage autosave sessions.
32
+
33
+ Commands:
34
+ /session Show current session ID
35
+ /session id Show current session ID
36
+ /session new Create new session and rotate ID
37
+
38
+ Sessions are used for auto-saving conversation history.
39
+ """,
40
+ )
41
+ def handle_session_command(command: str) -> bool:
42
+ """Handle /session command."""
43
+ from code_muse.config import (
44
+ AUTOSAVE_DIR,
45
+ get_current_autosave_id,
46
+ get_current_autosave_session_name,
47
+ rotate_autosave_id,
48
+ )
49
+ from code_muse.messaging import emit_info, emit_success, emit_warning
50
+
51
+ tokens = command.split()
52
+
53
+ if len(tokens) == 1 or tokens[1] == "id":
54
+ sid = get_current_autosave_id()
55
+ emit_info(
56
+ f"[bold magenta]Autosave Session[/bold magenta]: {sid}\n"
57
+ f"Files prefix: {Path(AUTOSAVE_DIR) / get_current_autosave_session_name()}"
58
+ )
59
+ return True
60
+ if tokens[1] == "new":
61
+ new_sid = rotate_autosave_id()
62
+ emit_success(f"New autosave session id: {new_sid}")
63
+ return True
64
+ emit_warning("Usage: /session [id|new]")
65
+ return True
66
+
67
+
68
+ @register_command(
69
+ name="compact",
70
+ description="Summarize and compact current chat history (uses compaction_strategy config)",
71
+ usage="/compact",
72
+ category="session",
73
+ )
74
+ def handle_compact_command(command: str) -> bool:
75
+ """Compact message history using configured strategy."""
76
+ from code_muse.agents.agent_manager import get_current_agent
77
+ from code_muse.config import get_compaction_strategy, get_protected_token_count
78
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
79
+
80
+ try:
81
+ agent = get_current_agent()
82
+ history = agent.get_message_history()
83
+ if not history:
84
+ emit_warning("No history to compact yet. Ask me something first!")
85
+ return True
86
+
87
+ current_agent = get_current_agent()
88
+ before_tokens = sum(
89
+ current_agent.estimate_tokens_for_message(m) for m in history
90
+ )
91
+ compaction_strategy = get_compaction_strategy()
92
+ protected_tokens = get_protected_token_count()
93
+ emit_info(
94
+ f"🤔 Compacting {len(history)} messages using {compaction_strategy} strategy... (~{before_tokens} tokens)"
95
+ )
96
+
97
+ current_agent = get_current_agent()
98
+ if compaction_strategy == "truncation":
99
+ from code_muse.agents._compaction import truncate
100
+
101
+ compacted = truncate(history, protected_tokens)
102
+ summarized_messages = [] # No summarization in truncation mode
103
+ else:
104
+ # Default to summarization
105
+ compacted, summarized_messages = current_agent.summarize_messages(
106
+ history, with_protection=True
107
+ )
108
+
109
+ if not compacted:
110
+ emit_error("Compaction failed. History unchanged.")
111
+ return True
112
+
113
+ agent.set_message_history(compacted)
114
+
115
+ current_agent = get_current_agent()
116
+ after_tokens = sum(
117
+ current_agent.estimate_tokens_for_message(m) for m in compacted
118
+ )
119
+ reduction_pct = (
120
+ ((before_tokens - after_tokens) / before_tokens * 100)
121
+ if before_tokens > 0
122
+ else 0
123
+ )
124
+
125
+ strategy_info = (
126
+ f"using {compaction_strategy} strategy"
127
+ if compaction_strategy == "truncation"
128
+ else "via summarization"
129
+ )
130
+ emit_success(
131
+ f"✨ Done! History: {len(history)} → {len(compacted)} messages {strategy_info}\n"
132
+ f"🏦 Tokens: {before_tokens:,} → {after_tokens:,} ({reduction_pct:.1f}% reduction)"
133
+ )
134
+ return True
135
+ except Exception as e:
136
+ emit_error(f"/compact error: {e}")
137
+ return True
138
+
139
+
140
+ @register_command(
141
+ name="truncate",
142
+ description="Truncate history to N most recent messages (e.g., /truncate 10)",
143
+ usage="/truncate <N>",
144
+ category="session",
145
+ )
146
+ def handle_truncate_command(command: str) -> bool:
147
+ """Truncate message history to N most recent messages."""
148
+ from code_muse.agents.agent_manager import get_current_agent
149
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
150
+
151
+ tokens = command.split()
152
+ if len(tokens) != 2:
153
+ emit_error("Usage: /truncate <N> (where N is the number of messages to keep)")
154
+ return True
155
+
156
+ try:
157
+ n = int(tokens[1])
158
+ if n < 1:
159
+ emit_error("N must be a positive integer")
160
+ return True
161
+ except ValueError:
162
+ emit_error("N must be a valid integer")
163
+ return True
164
+
165
+ agent = get_current_agent()
166
+ history = agent.get_message_history()
167
+ if not history:
168
+ emit_warning("No history to truncate yet. Ask me something first!")
169
+ return True
170
+
171
+ if len(history) <= n:
172
+ emit_info(
173
+ f"History already has {len(history)} messages, which is <= {n}. Nothing to truncate."
174
+ )
175
+ return True
176
+
177
+ # Always keep the first message (system message) and then keep the N-1 most recent messages
178
+ truncated_history = [history[0]] + history[-(n - 1) :] if n > 1 else [history[0]]
179
+
180
+ agent.set_message_history(truncated_history)
181
+ emit_success(
182
+ f"Truncated message history from {len(history)} to {len(truncated_history)} messages (keeping system message and {n - 1} most recent)"
183
+ )
184
+ return True
185
+
186
+
187
+ @register_command(
188
+ name="autosave_load",
189
+ description="Load an autosave session interactively",
190
+ usage="/autosave_load",
191
+ aliases=["resume"],
192
+ category="session",
193
+ )
194
+ def handle_autosave_load_command(command: str) -> bool:
195
+ """Load an autosave session."""
196
+ # Return a special marker to indicate we need to run async autosave loading
197
+ return "__AUTOSAVE_LOAD__"
198
+
199
+
200
+ @register_command(
201
+ name="dump_context",
202
+ description="Save current message history to file",
203
+ usage="/dump_context <name>",
204
+ category="session",
205
+ )
206
+ def handle_dump_context_command(command: str) -> bool:
207
+ """Dump message history to a file."""
208
+ from code_muse.agents.agent_manager import get_current_agent
209
+ from code_muse.messaging import emit_error, emit_success, emit_warning
210
+
211
+ tokens = command.split()
212
+ if len(tokens) != 2:
213
+ emit_warning("Usage: /dump_context <session_name>")
214
+ return True
215
+
216
+ session_name = tokens[1]
217
+ agent = get_current_agent()
218
+ history = agent.get_message_history()
219
+
220
+ if not history:
221
+ emit_warning("No message history to dump!")
222
+ return True
223
+
224
+ try:
225
+ metadata = save_session(
226
+ history=history,
227
+ session_name=session_name,
228
+ base_dir=Path(CONTEXTS_DIR),
229
+ timestamp=datetime.now().isoformat(),
230
+ token_estimator=agent.estimate_tokens_for_message,
231
+ )
232
+ emit_success(
233
+ f"✅ Context saved: {metadata.message_count} messages ({metadata.total_tokens} tokens)\n"
234
+ f"📁 Files: {metadata.pickle_path}, {metadata.metadata_path}"
235
+ )
236
+ return True
237
+
238
+ except Exception as exc:
239
+ emit_error(f"Failed to dump context: {exc}")
240
+ return True
241
+
242
+
243
+ @register_command(
244
+ name="load_context",
245
+ description="Load message history from file",
246
+ usage="/load_context <name>",
247
+ category="session",
248
+ )
249
+ def handle_load_context_command(command: str) -> bool:
250
+ """Load message history from a file."""
251
+ from rich.text import Text
252
+
253
+ from code_muse.agents.agent_manager import get_current_agent
254
+ from code_muse.config import rotate_autosave_id
255
+ from code_muse.messaging import emit_error, emit_info, emit_success, emit_warning
256
+
257
+ tokens = command.split()
258
+ if len(tokens) != 2:
259
+ emit_warning("Usage: /load_context <session_name>")
260
+ return True
261
+
262
+ session_name = tokens[1]
263
+ contexts_dir = Path(CONTEXTS_DIR)
264
+ session_path = contexts_dir / f"{session_name}.json"
265
+
266
+ try:
267
+ history = load_session(session_name, contexts_dir)
268
+ except FileNotFoundError:
269
+ emit_error(f"Context file not found: {session_path}")
270
+ available = list_sessions(contexts_dir)
271
+ if available:
272
+ emit_info(f"Available contexts: {', '.join(available)}")
273
+ return True
274
+ except Exception as exc:
275
+ emit_error(f"Failed to load context: {exc}")
276
+ return True
277
+
278
+ agent = get_current_agent()
279
+ agent.set_message_history(history)
280
+ total_tokens = sum(agent.estimate_tokens_for_message(m) for m in history)
281
+
282
+ # Rotate autosave id to avoid overwriting any existing autosave
283
+ try:
284
+ new_id = rotate_autosave_id()
285
+ autosave_info = Text.from_markup(
286
+ f"\n[dim]Autosave session rotated to: {new_id}[/dim]"
287
+ )
288
+ except Exception:
289
+ autosave_info = Text("")
290
+
291
+ # Build the success message with proper Text concatenation
292
+ success_msg = Text(
293
+ f"✅ Context loaded: {len(history)} messages ({total_tokens} tokens)\n"
294
+ f"📁 From: {session_path}"
295
+ )
296
+ success_msg.append_text(autosave_info)
297
+ emit_success(success_msg)
298
+
299
+ # Display recent message history for context
300
+ from code_muse.command_line.autosave_menu import display_resumed_history
301
+
302
+ display_resumed_history(history)
303
+
304
+ return True
@@ -0,0 +1,145 @@
1
+ """Shell pass-through for direct command execution.
2
+
3
+ Prepend a prompt with `!` to execute it as a shell command directly,
4
+ bypassing the agent entirely. Inspired by Claude Code's `!` prefix.
5
+
6
+ Examples:
7
+ !ls -la
8
+ !git status
9
+ !python --version
10
+ """
11
+
12
+ import os
13
+ import subprocess
14
+ import sys
15
+ import time
16
+
17
+ from rich.console import Console
18
+ from rich.markup import escape as escape_rich_markup
19
+
20
+ from code_muse.config import get_banner_color
21
+
22
+ # The prefix character that triggers shell pass-through
23
+ SHELL_PASSTHROUGH_PREFIX = "!"
24
+
25
+ # Banner identifier — matches the key in DEFAULT_BANNER_COLORS
26
+ _BANNER_NAME = "shell_passthrough"
27
+
28
+
29
+ def _get_console() -> Console:
30
+ """Get a Rich console for direct output.
31
+
32
+ Separated for testability — tests can mock this to capture output.
33
+ """
34
+ return Console()
35
+
36
+
37
+ def _format_banner() -> str:
38
+ """Format the SHELL PASSTHROUGH banner using the configured color.
39
+
40
+ Uses the same `[bold white on {color}]` pattern as rich_renderer.py
41
+ so the banner looks consistent with SHELL COMMAND, EDIT FILE, etc.
42
+
43
+ Returns:
44
+ Rich markup string for the banner.
45
+ """
46
+ color = get_banner_color(_BANNER_NAME)
47
+ return f"[bold white on {color}] 🐚 SHELL PASSTHROUGH [/bold white on {color}]"
48
+
49
+
50
+ def is_shell_passthrough(task: str) -> bool:
51
+ """Check if user input is a shell pass-through command.
52
+
53
+ A pass-through command starts with `!` followed by a non-empty command.
54
+ A bare `!` with nothing after it is NOT a pass-through.
55
+
56
+ Args:
57
+ task: Raw user input string.
58
+
59
+ Returns:
60
+ True if the input is a shell pass-through command.
61
+ """
62
+ stripped = task.strip()
63
+ return (
64
+ stripped.startswith(SHELL_PASSTHROUGH_PREFIX)
65
+ and len(stripped) > len(SHELL_PASSTHROUGH_PREFIX)
66
+ and not stripped[len(SHELL_PASSTHROUGH_PREFIX) :].isspace()
67
+ )
68
+
69
+
70
+ def extract_command(task: str) -> str:
71
+ """Extract the shell command from a pass-through input.
72
+
73
+ Strips the leading `!` prefix and any surrounding whitespace.
74
+
75
+ Args:
76
+ task: Raw user input (must pass `is_shell_passthrough` check).
77
+
78
+ Returns:
79
+ The shell command to execute.
80
+ """
81
+ return task.strip()[len(SHELL_PASSTHROUGH_PREFIX) :].strip()
82
+
83
+
84
+ def execute_shell_passthrough(task: str) -> None:
85
+ """Execute a shell command directly, bypassing the agent.
86
+
87
+ Renders a colored banner (matching the codebase banner system) so the
88
+ user instantly sees they're in pass-through mode, then inherits stdio
89
+ for raw terminal output.
90
+
91
+ Ctrl+C during execution kills the subprocess, not Muse.
92
+
93
+ Args:
94
+ task: Raw user input starting with `!`.
95
+ """
96
+ console = _get_console()
97
+ command = extract_command(task)
98
+
99
+ if not command:
100
+ console.print(
101
+ "[yellow]Empty command. Usage: !<command> (e.g., !ls -la)[/yellow]"
102
+ )
103
+ return
104
+
105
+ # Escape command to prevent Rich markup injection
106
+ safe_command = escape_rich_markup(command)
107
+
108
+ # Banner + command on one line, context hint below
109
+ banner = _format_banner()
110
+ console.print(f"\n{banner} [dim]$ {safe_command}[/dim]")
111
+ console.print("[dim]↳ Direct shell · Bypassing AI agent[/dim]")
112
+
113
+ start_time = time.monotonic()
114
+
115
+ try:
116
+ result = subprocess.run(
117
+ command,
118
+ shell=True,
119
+ cwd=os.getcwd(),
120
+ # Inherit stdio — output goes straight to the terminal
121
+ stdin=sys.stdin,
122
+ stdout=sys.stdout,
123
+ stderr=sys.stderr,
124
+ )
125
+ elapsed = time.monotonic() - start_time
126
+
127
+ if result.returncode == 0:
128
+ console.print(
129
+ f"[bold green]✅ Done[/bold green] [dim]({elapsed:.1f}s)[/dim]"
130
+ )
131
+ else:
132
+ console.print(
133
+ f"[bold red]❌ Exit code {result.returncode}[/bold red] "
134
+ f"[dim]({elapsed:.1f}s)[/dim]"
135
+ )
136
+
137
+ except KeyboardInterrupt:
138
+ elapsed = time.monotonic() - start_time
139
+ console.print(
140
+ f"\n[bold yellow]⚡ Interrupted[/bold yellow] [dim]({elapsed:.1f}s)[/dim]"
141
+ )
142
+
143
+ except Exception as e:
144
+ safe_error = escape_rich_markup(str(e))
145
+ console.print(f"[bold red]Shell error:[/bold red] {safe_error}")
@@ -0,0 +1,158 @@
1
+ """Prompt-toolkit completion for `/skills`.
2
+
3
+ Mirrors generic completer but simpler:
4
+ - Completes subcommands for `/skills ...`
5
+ - For `/skills install ...`, completes skill ids from the remote catalog
6
+
7
+ This module is intentionally defensive: if the remote catalog isn't available,
8
+ completion simply returns no skill ids.
9
+ """
10
+
11
+ import logging
12
+ import time
13
+ from collections.abc import Iterable
14
+
15
+ from prompt_toolkit.completion import Completer, Completion
16
+ from prompt_toolkit.document import Document
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def load_catalog_skill_ids() -> list[str]:
22
+ """Load skill ids from the remote catalog (lazy, cached)."""
23
+
24
+ try:
25
+ from code_muse.plugins.agent_skills.skill_catalog import catalog
26
+
27
+ return [entry.id for entry in catalog.get_all()]
28
+ except Exception as e:
29
+ logger.debug(f"Could not load skill ids: {e}")
30
+ return []
31
+
32
+
33
+ class SkillsCompleter(Completer):
34
+ """Completer for /skills subcommands."""
35
+
36
+ def __init__(self, trigger: str = "/skills"):
37
+ """Initialize the skills completer.
38
+
39
+ Args:
40
+ trigger: The slash command prefix to trigger completion.
41
+ """
42
+
43
+ self.trigger = trigger
44
+ self.subcommands = {
45
+ "list": "List all installed skills",
46
+ "install": "Browse & install from catalog",
47
+ "enable": "Enable skills integration globally",
48
+ "disable": "Disable skills integration globally",
49
+ "toggle": "Toggle skills system on/off",
50
+ "refresh": "Refresh skill cache",
51
+ "help": "Show skills help",
52
+ }
53
+
54
+ self._skill_ids_cache: list[str] | None = None
55
+ self._cache_timestamp: float | None = None
56
+
57
+ def _get_skill_ids(self) -> list[str]:
58
+ """Get skill ids with 30-second cache."""
59
+
60
+ current_time = time.time()
61
+ if (
62
+ self._skill_ids_cache is None
63
+ or self._cache_timestamp is None
64
+ or current_time - self._cache_timestamp > 30
65
+ ):
66
+ self._skill_ids_cache = load_catalog_skill_ids()
67
+ self._cache_timestamp = current_time
68
+
69
+ return self._skill_ids_cache or []
70
+
71
+ def get_completions(
72
+ self, document: Document, complete_event
73
+ ) -> Iterable[Completion]:
74
+ """Yield completions for /skills subcommands and skill ids."""
75
+
76
+ text = document.text
77
+ cursor_position = document.cursor_position
78
+ text_before_cursor = text[:cursor_position]
79
+
80
+ # Only trigger if /skills is at the very beginning of the line
81
+ stripped_text = text_before_cursor.lstrip()
82
+ if not stripped_text.startswith(self.trigger):
83
+ return
84
+
85
+ # Find where /skills starts (after any leading whitespace)
86
+ skills_pos = text_before_cursor.find(self.trigger)
87
+ skills_end = skills_pos + len(self.trigger)
88
+
89
+ # Require a space after /skills before showing completions
90
+ if (
91
+ skills_end >= len(text_before_cursor)
92
+ or text_before_cursor[skills_end] != " "
93
+ ):
94
+ return
95
+
96
+ # Everything after /skills (after the space)
97
+ after_skills = text_before_cursor[skills_end + 1 :].strip()
98
+
99
+ # If nothing after /skills, show all subcommands
100
+ if not after_skills:
101
+ for subcommand, description in sorted(self.subcommands.items()):
102
+ yield Completion(
103
+ subcommand,
104
+ start_position=0,
105
+ display=subcommand,
106
+ display_meta=description,
107
+ )
108
+ return
109
+
110
+ parts = after_skills.split()
111
+
112
+ # Special-case: /skills install <skill-id>
113
+ if len(parts) >= 1:
114
+ subcommand = parts[0].lower()
115
+
116
+ if subcommand == "install":
117
+ # Case 1: exactly `install ` -> show all ids
118
+ if len(parts) == 1 and text.endswith(" "):
119
+ for skill_id in sorted(self._get_skill_ids()):
120
+ yield Completion(
121
+ skill_id,
122
+ start_position=0,
123
+ display=skill_id,
124
+ display_meta="Skill",
125
+ )
126
+ return
127
+
128
+ # Case 2: `install <partial>` -> filter ids
129
+ if len(parts) == 2 and cursor_position > (
130
+ skills_end + 1 + len(subcommand) + 1
131
+ ):
132
+ partial = parts[1]
133
+ start_position = -len(partial)
134
+ for skill_id in sorted(self._get_skill_ids()):
135
+ if skill_id.lower().startswith(partial.lower()):
136
+ yield Completion(
137
+ skill_id,
138
+ start_position=start_position,
139
+ display=skill_id,
140
+ display_meta="Skill",
141
+ )
142
+ return
143
+
144
+ # If we only have one part and no trailing space, complete subcommands
145
+ if len(parts) == 1 and not text.endswith(" "):
146
+ partial = parts[0]
147
+ for subcommand, description in sorted(self.subcommands.items()):
148
+ if subcommand.startswith(partial):
149
+ yield Completion(
150
+ subcommand,
151
+ start_position=-(len(partial)),
152
+ display=subcommand,
153
+ display_meta=description,
154
+ )
155
+ return
156
+
157
+ # Otherwise, no further completion.
158
+ return
@@ -0,0 +1,18 @@
1
+ """Shared type definitions for the command-line subsystem."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+
8
+ @dataclass
9
+ class MarkdownCommandResult:
10
+ """Result of a custom command that should be rendered as markdown.
11
+
12
+ Attributes:
13
+ content: The markdown string to display
14
+ is_markdown: Always True for this type
15
+ """
16
+
17
+ content: str
18
+ is_markdown: bool = True