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,277 @@
1
+ """Register slash commands and startup hook for the token-tracking plugin.
2
+
3
+ Commands:
4
+ /tracking gain [today|week|month|all]
5
+ /tracking cc-economics [today|week|month|all]
6
+ /tracking session [N]
7
+ /tracking edit-efficiency [today|week|month|all]
8
+ /tracking help
9
+ """
10
+
11
+ import logging
12
+ from typing import Any
13
+
14
+ from code_muse.callbacks import register_callback
15
+ from code_muse.config import get_current_autosave_id
16
+ from code_muse.messaging import emit_info
17
+ from code_muse.plugins.token_tracking.database import TrackingDatabase, get_tracking_db
18
+ from code_muse.plugins.token_tracking.edit_analyzer import analyze_replacement
19
+ from code_muse.plugins.token_tracking.reports import (
20
+ cc_economics_report,
21
+ edit_efficiency_report,
22
+ gain_report,
23
+ session_report,
24
+ )
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ def _get_db() -> TrackingDatabase:
30
+ """Return the shared ``TrackingDatabase`` instance."""
31
+ return get_tracking_db()
32
+
33
+
34
+ # ------------------------------------------------------------------
35
+ # Startup hook
36
+ # ------------------------------------------------------------------
37
+
38
+
39
+ def _on_startup() -> None:
40
+ """Run database cleanup on application startup."""
41
+ try:
42
+ db = _get_db()
43
+ removed = db.cleanup()
44
+ logger.debug("Token tracking startup cleanup removed %s rows", removed)
45
+ except Exception:
46
+ pass
47
+
48
+
49
+ # ------------------------------------------------------------------
50
+ # Post-tool-call hook (edit efficiency tracking)
51
+ # ------------------------------------------------------------------
52
+
53
+
54
+ def _on_post_tool_call(
55
+ tool_name: str,
56
+ tool_args: dict[str, Any],
57
+ result: Any,
58
+ duration_ms: float,
59
+ context: Any = None,
60
+ ) -> Any:
61
+ """Intercept file-edit tools to measure context inflation.
62
+
63
+ Analyses ``create_file``, ``replace_in_file``, and ``delete_snippet``
64
+ calls, stores byte-level metrics, and returns *None* so the tool
65
+ result is left untouched.
66
+ """
67
+ if tool_name not in ("create_file", "replace_in_file", "delete_snippet"):
68
+ return None
69
+
70
+ try:
71
+ file_path = tool_args.get("file_path", "")
72
+ success = True
73
+ if isinstance(result, dict) and result.get("error"):
74
+ success = False
75
+
76
+ if tool_name == "create_file":
77
+ old_text = ""
78
+ new_text = tool_args.get("content", "")
79
+ _store_edit_analysis(tool_name, file_path, old_text, new_text, success)
80
+
81
+ elif tool_name == "delete_snippet":
82
+ old_text = tool_args.get("snippet", "")
83
+ new_text = ""
84
+ _store_edit_analysis(tool_name, file_path, old_text, new_text, success)
85
+
86
+ elif tool_name == "replace_in_file":
87
+ replacements = tool_args.get("replacements", [])
88
+ if not replacements:
89
+ return None
90
+
91
+ # Aggregate across all replacements in this call (Pi style)
92
+ totals: dict[str, int] = {
93
+ "old_bytes": 0,
94
+ "new_bytes": 0,
95
+ "total_edit_bytes": 0,
96
+ "shared_prefix_bytes": 0,
97
+ "shared_suffix_bytes": 0,
98
+ "shared_context_bytes": 0,
99
+ "core_old_bytes": 0,
100
+ "core_new_bytes": 0,
101
+ "core_bytes": 0,
102
+ "wrapper_payload_bytes": 0,
103
+ }
104
+ has_core_change = False
105
+ total_core = 0
106
+ total_edit = 0
107
+
108
+ for rep in replacements:
109
+ old_text = rep.get("old_text", "")
110
+ new_text = rep.get("new_text", "")
111
+ analysis = analyze_replacement(old_text, new_text)
112
+
113
+ for key in totals:
114
+ totals[key] += analysis[key]
115
+
116
+ if not analysis["no_core_change"]:
117
+ has_core_change = True
118
+ total_core += analysis["core_bytes"]
119
+ total_edit += analysis["total_edit_bytes"]
120
+
121
+ no_core_change = not has_core_change
122
+ inflation_ratio = (
123
+ None
124
+ if no_core_change
125
+ else (total_edit / total_core if total_core else None)
126
+ )
127
+
128
+ db = _get_db()
129
+ db.insert_edit_analysis(
130
+ tool_name=tool_name,
131
+ file_path=file_path,
132
+ old_bytes=totals["old_bytes"],
133
+ new_bytes=totals["new_bytes"],
134
+ total_edit_bytes=totals["total_edit_bytes"],
135
+ shared_prefix_bytes=totals["shared_prefix_bytes"],
136
+ shared_suffix_bytes=totals["shared_suffix_bytes"],
137
+ shared_context_bytes=totals["shared_context_bytes"],
138
+ core_old_bytes=totals["core_old_bytes"],
139
+ core_new_bytes=totals["core_new_bytes"],
140
+ core_bytes=totals["core_bytes"],
141
+ wrapper_payload_bytes=totals["wrapper_payload_bytes"],
142
+ inflation_ratio=inflation_ratio,
143
+ no_core_change=no_core_change,
144
+ success=success,
145
+ session_id=get_current_autosave_id(),
146
+ )
147
+
148
+ except Exception:
149
+ logger.debug("Edit efficiency tracking failed for %s", tool_name, exc_info=True)
150
+
151
+ return None
152
+
153
+
154
+ def _store_edit_analysis(
155
+ tool_name: str,
156
+ file_path: str,
157
+ old_text: str,
158
+ new_text: str,
159
+ success: bool,
160
+ ) -> None:
161
+ """Analyze a single replacement and store it in the database."""
162
+ analysis = analyze_replacement(old_text, new_text)
163
+ db = _get_db()
164
+ db.insert_edit_analysis(
165
+ tool_name=tool_name,
166
+ file_path=file_path,
167
+ old_bytes=analysis["old_bytes"],
168
+ new_bytes=analysis["new_bytes"],
169
+ total_edit_bytes=analysis["total_edit_bytes"],
170
+ shared_prefix_bytes=analysis["shared_prefix_bytes"],
171
+ shared_suffix_bytes=analysis["shared_suffix_bytes"],
172
+ shared_context_bytes=analysis["shared_context_bytes"],
173
+ core_old_bytes=analysis["core_old_bytes"],
174
+ core_new_bytes=analysis["core_new_bytes"],
175
+ core_bytes=analysis["core_bytes"],
176
+ wrapper_payload_bytes=analysis["wrapper_payload_bytes"],
177
+ inflation_ratio=analysis["inflation_ratio"],
178
+ no_core_change=analysis["no_core_change"],
179
+ success=success,
180
+ session_id=get_current_autosave_id(),
181
+ )
182
+
183
+
184
+ # ------------------------------------------------------------------
185
+ # Help
186
+ # ------------------------------------------------------------------
187
+
188
+
189
+ def _on_custom_command_help() -> list[tuple[str, str]]:
190
+ """Provide help entries for /help display."""
191
+ return [
192
+ ("tracking gain [time]", "Token savings report (today/week/month/all)"),
193
+ ("tracking cc-economics [time]", "Estimated Claude Code dollar savings"),
194
+ ("tracking session [N]", "Per-session adoption stats (default 10)"),
195
+ (
196
+ "tracking edit-efficiency [time]",
197
+ "Edit context-inflation / efficiency report",
198
+ ),
199
+ ]
200
+
201
+
202
+ # ------------------------------------------------------------------
203
+ # Slash-command handler
204
+ # ------------------------------------------------------------------
205
+
206
+
207
+ async def _on_custom_command(command: str, name: str) -> bool | None:
208
+ """Handle ``/tracking …`` slash commands.
209
+
210
+ Args:
211
+ command: Full command string (e.g. ``/tracking gain week``).
212
+ name: First token after the slash (always ``tracking`` here).
213
+
214
+ Returns:
215
+ ``True`` if handled, ``None`` if not a tracking command.
216
+ """
217
+ if name != "tracking":
218
+ return None
219
+
220
+ tokens = command.strip().split()
221
+ subcommand = tokens[1] if len(tokens) > 1 else "help"
222
+ arg = tokens[2] if len(tokens) > 2 else None
223
+
224
+ db = _get_db()
225
+
226
+ if subcommand in ("help",):
227
+ emit_info(
228
+ "Available /tracking commands:\n"
229
+ " /tracking gain [today|week|month|all]\n"
230
+ " /tracking cc-economics [today|week|month|all]\n"
231
+ " /tracking session [N]\n"
232
+ " /tracking help"
233
+ )
234
+ return True
235
+
236
+ if subcommand == "gain":
237
+ time_range = arg or "all"
238
+ report = gain_report(db, time_range)
239
+ emit_info(report)
240
+ return True
241
+
242
+ if subcommand == "cc-economics":
243
+ time_range = arg or "all"
244
+ report = cc_economics_report(db, time_range)
245
+ emit_info(report)
246
+ return True
247
+
248
+ if subcommand == "session":
249
+ limit = int(arg) if arg is not None and arg.isdigit() else 10
250
+ report = session_report(db, limit)
251
+ emit_info(report)
252
+ return True
253
+
254
+ if subcommand == "edit-efficiency":
255
+ time_range = arg or "all"
256
+ report = edit_efficiency_report(db, time_range)
257
+ emit_info(report)
258
+ return True
259
+
260
+ # Unknown subcommand — still consumed by this plugin
261
+ emit_info(
262
+ f"Unknown /tracking subcommand: {subcommand}\n"
263
+ "Try /tracking help for available commands."
264
+ )
265
+ return True
266
+
267
+
268
+ # ------------------------------------------------------------------
269
+ # Register
270
+ # ------------------------------------------------------------------
271
+
272
+ register_callback("startup", _on_startup)
273
+ register_callback("custom_command_help", _on_custom_command_help)
274
+ register_callback("custom_command", _on_custom_command)
275
+ register_callback("post_tool_call", _on_post_tool_call)
276
+
277
+ logger.debug("Token Tracking plugin callbacks registered")
@@ -0,0 +1,329 @@
1
+ """Query and formatting functions for token tracking reports.
2
+
3
+ Provides ``gain_report``, ``cc_economics_report``, and ``session_report``.
4
+ """
5
+
6
+ from code_muse.plugins.token_tracking.database import TrackingDatabase
7
+
8
+ # ------------------------------------------------------------------
9
+ # Time-range helpers
10
+ # ------------------------------------------------------------------
11
+
12
+ _TIME_RANGE_SQL = {
13
+ "today": "date(timestamp) = date('now')",
14
+ "week": "timestamp >= datetime('now', '-7 days')",
15
+ "month": "timestamp >= datetime('now', '-30 days')",
16
+ "all": "1=1",
17
+ }
18
+
19
+
20
+ def _time_filter(time_range: str) -> str:
21
+ """Return a SQLite WHERE clause fragment for the given range."""
22
+ return _TIME_RANGE_SQL.get(time_range, "1=1")
23
+
24
+
25
+ # ------------------------------------------------------------------
26
+ # Cost estimation
27
+ # ------------------------------------------------------------------
28
+
29
+
30
+ def _estimate_tokens_to_cost(input_tokens: int, output_tokens: int = 0) -> float:
31
+ """Estimate Claude 3.5 Sonnet cost in USD.
32
+
33
+ Pricing:
34
+ * $3 / 1M input tokens
35
+ * $15 / 1M output tokens
36
+ """
37
+ input_cost = input_tokens * 3.0 / 1_000_000
38
+ output_cost = output_tokens * 15.0 / 1_000_000
39
+ return input_cost + output_cost
40
+
41
+
42
+ # ------------------------------------------------------------------
43
+ # Reports
44
+ # ------------------------------------------------------------------
45
+
46
+
47
+ def gain_report(db: TrackingDatabase, time_range: str = "all") -> str:
48
+ """Format a token-savings report.
49
+
50
+ Args:
51
+ db: A ``TrackingDatabase`` instance.
52
+ time_range: One of ``today``, ``week``, ``month``, ``all``.
53
+
54
+ Returns:
55
+ Multi-line string suitable for display in the UI.
56
+ """
57
+ where = _time_filter(time_range)
58
+
59
+ row = db.query_one(
60
+ f"""
61
+ SELECT
62
+ COALESCE(SUM(raw_tokens), 0),
63
+ COALESCE(SUM(compressed_tokens), 0),
64
+ COUNT(*)
65
+ FROM executions
66
+ WHERE {where}
67
+ """
68
+ )
69
+ total_raw, total_compressed, total_commands = row or (0, 0, 0)
70
+ total_raw = int(total_raw)
71
+ total_compressed = int(total_compressed)
72
+ total_commands = int(total_commands)
73
+
74
+ saved = total_raw - total_compressed
75
+ savings_pct = (saved / max(total_raw, 1) * 100.0) if total_raw else 0.0
76
+
77
+ top_strategies = db.query_all(
78
+ f"""
79
+ SELECT
80
+ strategy,
81
+ COUNT(*) AS cmd_count,
82
+ COALESCE(SUM(raw_tokens - compressed_tokens), 0) AS saved_tokens
83
+ FROM executions
84
+ WHERE {where}
85
+ GROUP BY strategy
86
+ ORDER BY saved_tokens DESC
87
+ LIMIT 5
88
+ """
89
+ )
90
+
91
+ lines = [
92
+ "Token Savings Report",
93
+ f"Time range: {time_range}",
94
+ f"Total commands: {total_commands}",
95
+ f"Raw tokens: {total_raw} → Compressed tokens: {total_compressed}",
96
+ f"Savings: {saved} tokens ({savings_pct:.1f}%)",
97
+ "Top 5 strategies:",
98
+ ]
99
+ if top_strategies:
100
+ for strategy, cmd_count, saved_tokens in top_strategies:
101
+ lines.append(
102
+ f" {strategy}: {cmd_count} commands, {int(saved_tokens)} tokens saved"
103
+ )
104
+ else:
105
+ lines.append(" (no data)")
106
+
107
+ return "\n".join(lines)
108
+
109
+
110
+ def cc_economics_report(db: TrackingDatabase, time_range: str = "all") -> str:
111
+ """Estimate dollar savings using Claude Code pricing.
112
+
113
+ Treats raw tokens as "uncompressed input" and compressed tokens as
114
+ "actual input after filtering". Output tokens are not tracked
115
+ separately so we only show input-side economics.
116
+
117
+ Args:
118
+ db: A ``TrackingDatabase`` instance.
119
+ time_range: One of ``today``, ``week``, ``month``, ``all``.
120
+
121
+ Returns:
122
+ Compact, LLM-readable summary string.
123
+ """
124
+ where = _time_filter(time_range)
125
+
126
+ row = db.query_one(
127
+ f"""
128
+ SELECT COALESCE(SUM(raw_tokens), 0), COALESCE(SUM(compressed_tokens), 0)
129
+ FROM executions
130
+ WHERE {where}
131
+ """
132
+ )
133
+ total_raw, total_compressed = row or (0, 0)
134
+ total_raw = int(total_raw)
135
+ total_compressed = int(total_compressed)
136
+
137
+ cost_uncompressed = _estimate_tokens_to_cost(total_raw, 0)
138
+ cost_compressed = _estimate_tokens_to_cost(total_compressed, 0)
139
+ savings = cost_uncompressed - cost_compressed
140
+
141
+ lines = [
142
+ "Claude Code Economics Report",
143
+ f"Time range: {time_range}",
144
+ f"Uncompressed input cost: ${cost_uncompressed:.4f}",
145
+ f"Compressed input cost: ${cost_compressed:.4f}",
146
+ f"Estimated savings: ${savings:.4f}",
147
+ ]
148
+ return "\n".join(lines)
149
+
150
+
151
+ def session_report(db: TrackingDatabase, limit: int = 10) -> str:
152
+ """Report per-session adoption statistics.
153
+
154
+ Args:
155
+ db: A ``TrackingDatabase`` instance.
156
+ limit: Maximum number of recent sessions to show.
157
+
158
+ Returns:
159
+ Multi-line string with adoption metrics per session.
160
+ """
161
+ sessions = db.query_all(
162
+ """
163
+ SELECT
164
+ session_id,
165
+ COUNT(*) AS total_commands,
166
+ SUM(CASE WHEN strategy != 'unknown' THEN 1 ELSE 0 END) AS filtered_commands,
167
+ MIN(timestamp) AS first_ts,
168
+ MAX(timestamp) AS last_ts
169
+ FROM executions
170
+ GROUP BY session_id
171
+ ORDER BY first_ts DESC
172
+ LIMIT ?
173
+ """,
174
+ (limit,),
175
+ )
176
+
177
+ if not sessions:
178
+ return "Session Report\n(no tracking data)"
179
+
180
+ lines = ["Session Report"]
181
+ total_adoption_sum = 0.0
182
+ total_sessions = len(sessions)
183
+
184
+ for session_id, total_cmds, filtered_cmds, first_ts, last_ts in sessions:
185
+ total_cmds = int(total_cmds)
186
+ filtered_cmds = int(filtered_cmds)
187
+ adoption = (filtered_cmds / max(total_cmds, 1)) * 100.0
188
+ total_adoption_sum += adoption
189
+
190
+ flag = " ⚠️ low adoption" if adoption < 50 else ""
191
+ lines.append(
192
+ f"\nSession {session_id[:8]}…"
193
+ f"\n Commands: {total_cmds} total, {filtered_cmds} filtered"
194
+ f"\n Adoption: {adoption:.1f}%{flag}"
195
+ f"\n First: {first_ts}"
196
+ f"\n Last: {last_ts}"
197
+ )
198
+
199
+ overall_avg = total_adoption_sum / max(total_sessions, 1)
200
+ lines.append(f"\nOverall average adoption: {overall_avg:.1f}%")
201
+
202
+ return "\n".join(lines)
203
+
204
+
205
+ # ------------------------------------------------------------------
206
+ # Edit efficiency report
207
+ # ------------------------------------------------------------------
208
+
209
+
210
+ def edit_efficiency_report(db: TrackingDatabase, time_range: str = "all") -> str:
211
+ """Format an edit-efficiency / context-inflation report.
212
+
213
+ Args:
214
+ db: A ``TrackingDatabase`` instance.
215
+ time_range: One of ``today``, ``week``, ``month``, ``all``.
216
+
217
+ Returns:
218
+ Multi-line string suitable for display in the UI.
219
+ """
220
+ edits = db.query_edit_summary(time_range)
221
+
222
+ if not edits:
223
+ range_label = {
224
+ "today": "today",
225
+ "week": "last 7 days",
226
+ "month": "last 30 days",
227
+ "all": "all time",
228
+ }.get(time_range, time_range)
229
+ return f"Edit Efficiency Report ({range_label})\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n(no edit tracking data)"
230
+
231
+ total = len(edits)
232
+ tool_counts: dict[str, int] = {}
233
+ inflation_values: list[float] = []
234
+ no_core_count = 0
235
+ edits_with_inflation: list[tuple[float, str, int, int]] = []
236
+ bucket_success: dict[str, list[tuple[int, int]]] = {
237
+ "<4x": [],
238
+ "4-10x": [],
239
+ "10-25x": [],
240
+ "25x+": [],
241
+ }
242
+
243
+ for edit in edits:
244
+ tool = edit["tool_name"]
245
+ tool_counts[tool] = tool_counts.get(tool, 0) + 1
246
+
247
+ if edit["no_core_change"]:
248
+ no_core_count += 1
249
+
250
+ ratio = edit["inflation_ratio"]
251
+ if ratio is not None:
252
+ inflation_values.append(ratio)
253
+ edits_with_inflation.append(
254
+ (ratio, edit["file_path"], edit["total_edit_bytes"], edit["core_bytes"])
255
+ )
256
+
257
+ success = 1 if edit["success"] else 0
258
+ if ratio < 4:
259
+ bucket_success["<4x"].append((success, 1))
260
+ elif ratio < 10:
261
+ bucket_success["4-10x"].append((success, 1))
262
+ elif ratio < 25:
263
+ bucket_success["10-25x"].append((success, 1))
264
+ else:
265
+ bucket_success["25x+"].append((success, 1))
266
+ else:
267
+ # No core change — count in no_core bucket but don't show inflation
268
+ pass
269
+
270
+ range_label = {
271
+ "today": "today",
272
+ "week": "last 7 days",
273
+ "month": "last 30 days",
274
+ "all": "all time",
275
+ }.get(time_range, time_range)
276
+
277
+ lines = [
278
+ f"Edit Efficiency Report ({range_label})",
279
+ "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
280
+ f"Total edit calls: {total}",
281
+ ]
282
+ for tool, count in sorted(tool_counts.items(), key=lambda x: -x[1]):
283
+ lines.append(f" • {tool}: {count}")
284
+
285
+ lines.append("")
286
+ lines.append("Context inflation:")
287
+
288
+ if inflation_values:
289
+ inflation_values.sort()
290
+ median = inflation_values[len(inflation_values) // 2]
291
+ p95_idx = int(len(inflation_values) * 0.95)
292
+ p95 = inflation_values[min(p95_idx, len(inflation_values) - 1)]
293
+ lines.append(f" median inflation: {median:.2f}x")
294
+ lines.append(f" p95 inflation: {p95:.2f}x")
295
+ else:
296
+ lines.append(" median inflation: N/A")
297
+ lines.append(" p95 inflation: N/A")
298
+
299
+ lines.append(
300
+ f" no-core-change: {no_core_count} edits ({no_core_count / max(total, 1) * 100:.1f}%)"
301
+ )
302
+
303
+ # Worst offenders
304
+ worst = sorted(edits_with_inflation, key=lambda x: -x[0])[:10]
305
+ worst = [w for w in worst if w[0] > 20]
306
+ if worst:
307
+ lines.append("")
308
+ lines.append("Worst offenders (>20x inflation):")
309
+ for i, (ratio, path, total_bytes, core_bytes) in enumerate(worst, 1):
310
+ lines.append(
311
+ f" {i}. {path} — {ratio:.1f}x ({total_bytes:,} bytes → {core_bytes:,} bytes core)"
312
+ )
313
+
314
+ # Failure rate by bucket
315
+ lines.append("")
316
+ lines.append("Failure rate by inflation bucket:")
317
+ for bucket in ("<4x", "4-10x", "10-25x", "25x+"):
318
+ entries = bucket_success[bucket]
319
+ if entries:
320
+ successes = sum(s for s, _ in entries)
321
+ total_bucket = len(entries)
322
+ rate = successes / total_bucket * 100
323
+ lines.append(
324
+ f" {bucket}: {rate:.1f}% success ({successes}/{total_bucket})"
325
+ )
326
+ else:
327
+ lines.append(f" {bucket}: N/A")
328
+
329
+ return "\n".join(lines)
@@ -0,0 +1,13 @@
1
+ """Universal Constructor - Dynamic tool creation and management plugin.
2
+
3
+ This plugin enables users to create, manage, and deploy custom tools
4
+ that extend Muse's capabilities. Tools are stored in the user's
5
+ config directory and can be organized into namespaces via subdirectories.
6
+ """
7
+
8
+ from pathlib import Path
9
+
10
+ # User tools directory - where user-created UC tools live
11
+ USER_UC_DIR = Path.home() / ".muse" / "plugins" / "universal_constructor"
12
+
13
+ __all__ = ["USER_UC_DIR"]