comate-cli 0.4.4__tar.gz → 0.4.5__tar.gz

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 (130) hide show
  1. {comate_cli-0.4.4 → comate_cli-0.4.5}/.gitignore +1 -1
  2. {comate_cli-0.4.4 → comate_cli-0.4.5}/PKG-INFO +1 -1
  3. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/animations.py +216 -23
  4. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/event_renderer.py +35 -7
  5. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/history_printer.py +7 -2
  6. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/mention_completer.py +10 -14
  7. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tool_view.py +4 -12
  8. comate_cli-0.4.5/docs/superpowers/plans/2026-04-03-phrase-shuffle.md +187 -0
  9. comate_cli-0.4.5/docs/superpowers/specs/2026-04-03-phrase-shuffle-design.md +55 -0
  10. {comate_cli-0.4.4 → comate_cli-0.4.5}/pyproject.toml +1 -1
  11. comate_cli-0.4.5/tests/test_animator_shuffle.py +76 -0
  12. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_event_renderer.py +3 -3
  13. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_mention_completer.py +46 -0
  14. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tool_view.py +11 -13
  15. {comate_cli-0.4.4 → comate_cli-0.4.5}/uv.lock +2 -2
  16. {comate_cli-0.4.4 → comate_cli-0.4.5}/README.md +0 -0
  17. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/__init__.py +0 -0
  18. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/__main__.py +0 -0
  19. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/main.py +0 -0
  20. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/mcp_cli.py +0 -0
  21. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/__init__.py +0 -0
  22. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/app.py +0 -0
  23. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/assistant_render.py +0 -0
  24. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/codenames.py +0 -0
  25. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/custom_slash_commands.py +0 -0
  26. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/env_utils.py +0 -0
  27. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/error_display.py +0 -0
  28. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/fragment_utils.py +0 -0
  29. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/input_geometry.py +0 -0
  30. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/layout_coordinator.py +0 -0
  31. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/logging_adapter.py +0 -0
  32. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/logo.py +0 -0
  33. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/markdown_render.py +0 -0
  34. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/message_style.py +0 -0
  35. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/models.py +0 -0
  36. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/path_context_hint.py +0 -0
  37. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/__init__.py +0 -0
  38. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/__init__.py +0 -0
  39. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/detail_view.py +0 -0
  40. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/plugin_list.py +0 -0
  41. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/search_box.py +0 -0
  42. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/tab_bar.py +0 -0
  43. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/marketplace_install_view.py +0 -0
  44. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/plugin_picker.py +0 -0
  45. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/__init__.py +0 -0
  46. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/discover_tab.py +0 -0
  47. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/errors_tab.py +0 -0
  48. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/installed_tab.py +0 -0
  49. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/marketplaces_tab.py +0 -0
  50. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/preflight.py +0 -0
  51. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/question_view.py +0 -0
  52. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/resume_selector.py +0 -0
  53. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/rewind_store.py +0 -0
  54. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/rpc_protocol.py +0 -0
  55. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/rpc_stdio.py +0 -0
  56. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/selection_menu.py +0 -0
  57. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/session_view.py +0 -0
  58. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/slash_commands.py +0 -0
  59. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/startup.py +0 -0
  60. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/status_bar.py +0 -0
  61. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/text_effects.py +0 -0
  62. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tips.py +0 -0
  63. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui.py +0 -0
  64. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/__init__.py +0 -0
  65. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/commands.py +0 -0
  66. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/history_sync.py +0 -0
  67. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/input_behavior.py +0 -0
  68. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/key_bindings.py +0 -0
  69. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/mcp_connecting_view.py +0 -0
  70. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/render_panels.py +0 -0
  71. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/slash_command_registry.py +0 -0
  72. {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/ui_mode.py +0 -0
  73. {comate_cli-0.4.4 → comate_cli-0.4.5}/docs/superpowers/specs/2026-04-01-conditional-diff-subtitle-design.md +0 -0
  74. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/conftest.py +0 -0
  75. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_mcp_preload.py +0 -0
  76. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_preflight_gate.py +0 -0
  77. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_print_mode.py +0 -0
  78. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_shutdown.py +0 -0
  79. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_usage_line.py +0 -0
  80. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_cli_project_root.py +0 -0
  81. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_compact_command_semantics.py +0 -0
  82. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_completion_context_activation.py +0 -0
  83. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_completion_status_panel.py +0 -0
  84. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_context_command.py +0 -0
  85. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_custom_slash_commands.py +0 -0
  86. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_discover_tab.py +0 -0
  87. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_errors_tab.py +0 -0
  88. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_format_error.py +0 -0
  89. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_handle_error.py +0 -0
  90. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_history_printer.py +0 -0
  91. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_history_sync.py +0 -0
  92. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_input_behavior.py +0 -0
  93. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_input_history.py +0 -0
  94. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_installed_tab.py +0 -0
  95. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_interrupt_exit_semantics.py +0 -0
  96. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_layout_coordinator.py +0 -0
  97. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_logging_adapter.py +0 -0
  98. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_logo.py +0 -0
  99. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_main_args.py +0 -0
  100. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_marketplaces_tab.py +0 -0
  101. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_mcp_cli.py +0 -0
  102. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_mcp_slash_command.py +0 -0
  103. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_path_context_hint.py +0 -0
  104. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_plugin_slash_commands.py +0 -0
  105. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_plugin_tui_components.py +0 -0
  106. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_preflight.py +0 -0
  107. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_preflight_copilot.py +0 -0
  108. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_question_key_bindings.py +0 -0
  109. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_question_view.py +0 -0
  110. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_resume_selector.py +0 -0
  111. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rewind_command_semantics.py +0 -0
  112. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rewind_store.py +0 -0
  113. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rpc_protocol.py +0 -0
  114. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rpc_stdio_bridge.py +0 -0
  115. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_selection_menu.py +0 -0
  116. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_skills_slash_command.py +0 -0
  117. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_slash_argument_hint.py +0 -0
  118. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_slash_completer.py +0 -0
  119. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_slash_registry.py +0 -0
  120. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_status_bar.py +0 -0
  121. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_status_bar_transient.py +0 -0
  122. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_panel_format.py +0 -0
  123. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_panel_key_bindings.py +0 -0
  124. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_panel_rendering.py +0 -0
  125. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_poll.py +0 -0
  126. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_elapsed_status.py +0 -0
  127. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_mcp_init_gate.py +0 -0
  128. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_paste_placeholder.py +0 -0
  129. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_split_invariance.py +0 -0
  130. {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_update_check.py +0 -0
@@ -8,7 +8,7 @@ set_env.sh
8
8
  .worktrees/
9
9
  # C extensions
10
10
  *.so
11
-
11
+ claude_code_codebase/
12
12
  .claude/
13
13
  # Distribution / packaging
14
14
  .Python
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comate-cli
3
- Version: 0.4.4
3
+ Version: 0.4.5
4
4
  Summary: Comate terminal CLI built on comate-agent-sdk
5
5
  Project-URL: Homepage, https://github.com/AndyLee1024/agent-sdk
6
6
  Project-URL: Repository, https://github.com/AndyLee1024/agent-sdk
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import random
4
5
  import time
5
6
  from collections.abc import Sequence
6
7
  from enum import Enum
@@ -11,27 +12,215 @@ from rich.text import Text
11
12
  from comate_agent_sdk.agent.events import StopEvent, TextEvent, ToolCallEvent, ToolResultEvent, UserQuestionEvent
12
13
 
13
14
  DEFAULT_STATUS_PHRASES: tuple[str, ...] = (
14
- "Embellishing",
15
- "Vibing",
16
- "Thinking",
17
- "Reasoning",
18
- "Planning next move",
19
- "Reading context",
20
- "Connecting dots",
21
- "Synthesizing signal",
22
- "Spotting edge cases",
23
- "Checking assumptions",
24
- "Tracing dependencies",
25
- "Drafting response",
26
- "Polishing details",
27
- "Validating flow",
28
- "Cross-checking facts",
29
- "Refining intent",
30
- "Mapping tools",
31
- "Building confidence",
32
- "Stitching answer",
33
- "Finalizing output",
34
- "Almost there",
15
+ "Embellishing",
16
+ "Vibing",
17
+ "Thinking",
18
+ "Reasoning",
19
+ "Planning next move",
20
+ "Reading context",
21
+ "Connecting dots",
22
+ "Synthesizing signal",
23
+ "Spotting edge cases",
24
+ "Checking assumptions",
25
+ "Tracing dependencies",
26
+ "Drafting response",
27
+ "Polishing details",
28
+ "Validating flow",
29
+ "Cross-checking facts",
30
+ "Refining intent",
31
+ "Mapping tools",
32
+ "Building confidence",
33
+ "Stitching answer",
34
+ "Finalizing output",
35
+ "Almost there",
36
+ 'Accomplishing',
37
+ 'Comating',
38
+ 'Actioning',
39
+ 'Actualizing',
40
+ 'Architecting',
41
+ 'Baking',
42
+ 'Beaming',
43
+ "Beboppin'",
44
+ 'Befuddling',
45
+ 'Billowing',
46
+ 'Blanching',
47
+ 'Bloviating',
48
+ 'Boogieing',
49
+ 'Boondoggling',
50
+ 'Booping',
51
+ 'Bootstrapping',
52
+ 'Brewing',
53
+ 'Bunning',
54
+ 'Burrowing',
55
+ 'Calculating',
56
+ 'Canoodling',
57
+ 'Caramelizing',
58
+ 'Cascading',
59
+ 'Catapulting',
60
+ 'Cerebrating',
61
+ 'Channeling',
62
+ 'Channelling',
63
+ 'Choreographing',
64
+ 'Churning',
65
+ 'Clauding',
66
+ 'Coalescing',
67
+ 'Cogitating',
68
+ 'Combobulating',
69
+ 'Composing',
70
+ 'Computing',
71
+ 'Concocting',
72
+ 'Considering',
73
+ 'Contemplating',
74
+ 'Cooking',
75
+ 'Crafting',
76
+ 'Creating',
77
+ 'Crunching',
78
+ 'Crystallizing',
79
+ 'Cultivating',
80
+ 'Deciphering',
81
+ 'Deliberating',
82
+ 'Determining',
83
+ 'Dilly-dallying',
84
+ 'Discombobulating',
85
+ 'Doing',
86
+ 'Doodling',
87
+ 'Drizzling',
88
+ 'Ebbing',
89
+ 'Effecting',
90
+ 'Elucidating',
91
+ 'Embellishing',
92
+ 'Enchanting',
93
+ 'Envisioning',
94
+ 'Evaporating',
95
+ 'Fermenting',
96
+ 'Fiddle-faddling',
97
+ 'Finagling',
98
+ 'Flambéing',
99
+ 'Flibbertigibbeting',
100
+ 'Flowing',
101
+ 'Flummoxing',
102
+ 'Fluttering',
103
+ 'Forging',
104
+ 'Forming',
105
+ 'Frolicking',
106
+ 'Frosting',
107
+ 'Gallivanting',
108
+ 'Galloping',
109
+ 'Garnishing',
110
+ 'Generating',
111
+ 'Gesticulating',
112
+ 'Germinating',
113
+ 'Gitifying',
114
+ 'Grooving',
115
+ 'Gusting',
116
+ 'Harmonizing',
117
+ 'Hashing',
118
+ 'Hatching',
119
+ 'Herding',
120
+ 'Honking',
121
+ 'Hullaballooing',
122
+ 'Hyperspacing',
123
+ 'Ideating',
124
+ 'Imagining',
125
+ 'Improvising',
126
+ 'Incubating',
127
+ 'Inferring',
128
+ 'Infusing',
129
+ 'Ionizing',
130
+ 'Jitterbugging',
131
+ 'Julienning',
132
+ 'Kneading',
133
+ 'Leavening',
134
+ 'Levitating',
135
+ 'Lollygagging',
136
+ 'Manifesting',
137
+ 'Marinating',
138
+ 'Meandering',
139
+ 'Metamorphosing',
140
+ 'Misting',
141
+ 'Moonwalking',
142
+ 'Moseying',
143
+ 'Mulling',
144
+ 'Mustering',
145
+ 'Musing',
146
+ 'Nebulizing',
147
+ 'Nesting',
148
+ 'Newspapering',
149
+ 'Noodling',
150
+ 'Nucleating',
151
+ 'Orbiting',
152
+ 'Orchestrating',
153
+ 'Osmosing',
154
+ 'Perambulating',
155
+ 'Percolating',
156
+ 'Perusing',
157
+ 'Philosophising',
158
+ 'Photosynthesizing',
159
+ 'Pollinating',
160
+ 'Pondering',
161
+ 'Pontificating',
162
+ 'Pouncing',
163
+ 'Precipitating',
164
+ 'Prestidigitating',
165
+ 'Processing',
166
+ 'Proofing',
167
+ 'Propagating',
168
+ 'Puttering',
169
+ 'Puzzling',
170
+ 'Quantumizing',
171
+ 'Razzle-dazzling',
172
+ 'Razzmatazzing',
173
+ 'Recombobulating',
174
+ 'Reticulating',
175
+ 'Roosting',
176
+ 'Ruminating',
177
+ 'Sautéing',
178
+ 'Scampering',
179
+ 'Schlepping',
180
+ 'Scurrying',
181
+ 'Seasoning',
182
+ 'Shenaniganing',
183
+ 'Shimmying',
184
+ 'Simmering',
185
+ 'Skedaddling',
186
+ 'Sketching',
187
+ 'Slithering',
188
+ 'Smooshing',
189
+ 'Sock-hopping',
190
+ 'Spelunking',
191
+ 'Spinning',
192
+ 'Sprouting',
193
+ 'Stewing',
194
+ 'Sublimating',
195
+ 'Swirling',
196
+ 'Swooping',
197
+ 'Symbioting',
198
+ 'Synthesizing',
199
+ 'Tempering',
200
+ 'Thinking',
201
+ 'Thundering',
202
+ 'Tinkering',
203
+ 'Tomfoolering',
204
+ 'Topsy-turvying',
205
+ 'Transfiguring',
206
+ 'Transmuting',
207
+ 'Twisting',
208
+ 'Undulating',
209
+ 'Unfurling',
210
+ 'Unravelling',
211
+ 'Vibing',
212
+ 'Waddling',
213
+ 'Wandering',
214
+ 'Warping',
215
+ 'Whatchamacalliting',
216
+ 'Whirlpooling',
217
+ 'Whirring',
218
+ 'Whisking',
219
+ 'Wibbling',
220
+ 'Working',
221
+ 'Wrangling',
222
+ 'Zesting',
223
+ 'Zigzagging',
35
224
  )
36
225
 
37
226
  BREATH_DOT_COLORS: tuple[str, ...] = (
@@ -117,6 +306,7 @@ class SubmissionAnimator:
117
306
  ) -> None:
118
307
  del console
119
308
  self._phrases = tuple(phrases) if phrases else DEFAULT_STATUS_PHRASES
309
+ self._shuffled: tuple[str, ...] = tuple(self._phrases)
120
310
  self._refresh_interval = refresh_interval
121
311
  self._min_phrase_seconds = max(0.6, min_phrase_seconds)
122
312
  self._max_phrase_seconds = max(self._min_phrase_seconds, max_phrase_seconds)
@@ -146,6 +336,9 @@ class SubmissionAnimator:
146
336
  self._phrase_idx = 0
147
337
  self._phrase_started_at_monotonic = time.monotonic()
148
338
  self._phrase_duration_seconds = self._phrase_duration_for_idx(0)
339
+ shuffled = list(self._phrases)
340
+ random.shuffle(shuffled)
341
+ self._shuffled = tuple(shuffled)
149
342
  self._is_active = True
150
343
  self._dirty = True
151
344
  self._stop_event = asyncio.Event()
@@ -189,7 +382,7 @@ class SubmissionAnimator:
189
382
  if not self._is_active:
190
383
  return Text("")
191
384
 
192
- phrase = self._status_hint if self._status_hint else self._phrases[self._phrase_idx]
385
+ phrase = self._status_hint if self._status_hint else (self._shuffled[self._phrase_idx] + "…")
193
386
  dot_color = breathing_dot_color(self._frame)
194
387
  now_monotonic = time.monotonic()
195
388
  dot = Text(
@@ -204,7 +397,7 @@ class SubmissionAnimator:
204
397
  while not self._stop_event.is_set():
205
398
  now = time.monotonic()
206
399
  if now - self._phrase_started_at_monotonic >= self._phrase_duration_seconds:
207
- self._phrase_idx = (self._phrase_idx + 1) % len(self._phrases)
400
+ self._phrase_idx = (self._phrase_idx + 1) % len(self._shuffled)
208
401
  self._phrase_started_at_monotonic = now
209
402
  self._phrase_duration_seconds = self._phrase_duration_for_idx(self._phrase_idx)
210
403
  self._frame += 1
@@ -510,13 +510,13 @@ class EventRenderer:
510
510
  child_display = resolve_display_tool_name(child_tool.tool_name, {})
511
511
  signature = _tool_signature(child_display, child_tool.args_summary)
512
512
  if child_tool.status == "running":
513
- entries.append((1, f"|_ {signature}"))
513
+ entries.append((1, f" {signature}"))
514
514
  else:
515
515
  icon = "✓" if child_tool.status == "completed" else "✗"
516
- entries.append((1, f"|_ {icon} {signature}"))
516
+ entries.append((1, f" {icon} {signature}"))
517
517
 
518
518
  if state.show_init:
519
- entries.append((1, "|_ init"))
519
+ entries.append((1, " init"))
520
520
  else:
521
521
  display_name = state.display_tool_name or state.tool_name
522
522
  signature = _tool_signature(display_name, state.args_summary)
@@ -564,7 +564,8 @@ class EventRenderer:
564
564
  self._running_tools[tool_call_id] = self._make_running_tool(tool_name, args)
565
565
 
566
566
  def _build_tool_subtitle(
567
- self, tool_name: str, result: str, metadata: dict[str, Any] | None = None
567
+ self, tool_name: str, result: str, metadata: dict[str, Any] | None = None,
568
+ output: Any = None,
568
569
  ) -> str | None:
569
570
  """Build a subtitle string for tool result display.
570
571
 
@@ -574,6 +575,31 @@ class EventRenderer:
574
575
 
575
576
  lowered = tool_name.lower()
576
577
 
578
+ # ── typed output 优先路径 ──
579
+ if output is not None:
580
+ try:
581
+ from comate_agent_sdk.tool_schemas.write import WriteOutput
582
+ from comate_agent_sdk.tool_schemas.read import ReadOutput
583
+ from comate_agent_sdk.tool_schemas.bash import BashOutput
584
+ from comate_agent_sdk.tool_schemas.search import GlobOutput, GrepOutput, LSOutput
585
+
586
+ if lowered == "write" and isinstance(output, WriteOutput):
587
+ return f"Write {output.lines_written} lines"
588
+
589
+ if lowered == "read" and isinstance(output, ReadOutput):
590
+ return f"Read {output.lines_returned} lines of {output.total_lines}"
591
+
592
+ if lowered == "bash" and isinstance(output, BashOutput):
593
+ return f"Exit code {output.exit_code}"
594
+
595
+ if lowered in ("glob", "ls") and isinstance(output, (GlobOutput, LSOutput)):
596
+ return f"Found {output.count} files"
597
+
598
+ if lowered == "grep" and isinstance(output, GrepOutput):
599
+ return f"Found {output.total_matches} matches"
600
+ except ImportError:
601
+ pass # SDK not available, fall through to legacy
602
+
577
603
  if lowered == "skill":
578
604
  return "Successfully loaded skill"
579
605
 
@@ -603,7 +629,7 @@ class EventRenderer:
603
629
  lines = result.split("\n") if result else []
604
630
  if lines and lines[-1] == "":
605
631
  lines = lines[:-1]
606
- return f"Wrote {len(lines)} lines"
632
+ return f"Write {len(lines)} lines"
607
633
 
608
634
  if lowered in ("edit", "multiedit"):
609
635
  if not metadata:
@@ -719,12 +745,13 @@ class EventRenderer:
719
745
  is_error: bool,
720
746
  result: Any,
721
747
  metadata: dict[str, Any] | None = None,
748
+ output: Any = None,
722
749
  ) -> None:
723
750
  sev: Literal["info", "warning", "error"] = "error" if is_error else "info"
724
751
  if is_error:
725
752
  subtitle = _truncate(_one_line(result), self._tool_error_summary_max_len)
726
753
  else:
727
- subtitle = self._build_tool_subtitle(tool_name, str(result), metadata)
754
+ subtitle = self._build_tool_subtitle(tool_name, str(result), metadata, output)
728
755
  state = self._running_tools.pop(tool_call_id, None)
729
756
  if state is None:
730
757
  display_name = resolve_display_tool_name(tool_name, {})
@@ -1054,7 +1081,7 @@ class EventRenderer:
1054
1081
  self._rebuild_loading_line()
1055
1082
  return (False, None)
1056
1083
  self._append_tool_call(tool_name, args_dict, tool_call_id)
1057
- case ToolResultEvent(tool=tool_name, result=result, tool_call_id=tool_call_id, is_error=is_error, metadata=metadata):
1084
+ case ToolResultEvent(tool=tool_name, result=result, tool_call_id=tool_call_id, is_error=is_error, metadata=metadata, output=output):
1058
1085
  stored_args = self._tool_call_args.pop(tool_call_id, {})
1059
1086
  if not should_show_tool_in_scrollback(tool_name, stored_args, is_result=True, is_error=is_error):
1060
1087
  self._running_tools.pop(tool_call_id, None)
@@ -1066,6 +1093,7 @@ class EventRenderer:
1066
1093
  is_error=is_error,
1067
1094
  result=result,
1068
1095
  metadata=metadata,
1096
+ output=output,
1069
1097
  )
1070
1098
  case UsageDeltaEvent(
1071
1099
  source=_,
@@ -82,7 +82,7 @@ def render_history_group(
82
82
  renderables.append(Text(""))
83
83
  continue
84
84
 
85
- # System entries: 按 severity 区分视觉样式
85
+ # System entries: 按 severity 区分视觉样式,缩进 2 空格与消息内容列对齐
86
86
  if entry.entry_type == "system":
87
87
  if entry.severity == "error":
88
88
  text_style = "bold #FF6B6B"
@@ -90,8 +90,13 @@ def render_history_group(
90
90
  text_style = "#E8B830"
91
91
  else:
92
92
  text_style = "dim"
93
+ content = str(entry.text)
94
+ content_lines = content.splitlines() or [""]
93
95
  line_text = Text()
94
- line_text.append(str(entry.text), style=text_style)
96
+ line_text.append(f" {content_lines[0]}", style=text_style)
97
+ for line in content_lines[1:]:
98
+ line_text.append("\n")
99
+ line_text.append(f" {line}", style=text_style)
95
100
  renderables.append(line_text)
96
101
  renderables.append(Text(""))
97
102
  continue
@@ -146,6 +146,10 @@ class LocalFileMentionCompleter(Completer):
146
146
  if self._is_completed_file(context.fragment):
147
147
  return None
148
148
 
149
+ result_limit = max(max_items, 1)
150
+ if self._limit > 0:
151
+ result_limit = min(result_limit, self._limit)
152
+
149
153
  fragment_lower = context.fragment.lower()
150
154
  directory_source = self._get_directory_candidates(context.fragment)
151
155
  if directory_source is not None:
@@ -175,17 +179,20 @@ class LocalFileMentionCompleter(Completer):
175
179
  return None
176
180
 
177
181
  def _rank(path: str) -> tuple[int, str]:
178
- basename = path.rstrip("/").split("/")[-1].lower()
182
+ normalized = path.rstrip("/")
183
+ basename = normalized.split("/")[-1].lower()
184
+ depth = normalized.count("/")
185
+ is_directory = path.endswith("/")
179
186
  if basename.startswith(fragment_lower):
180
187
  category = 0
181
188
  elif fragment_lower in basename:
182
189
  category = 1
183
190
  else:
184
191
  category = 2
185
- return (category, path.lower())
192
+ return (category, depth, 1 if is_directory else 0, len(normalized), path.lower())
186
193
 
187
194
  matched.sort(key=_rank)
188
- return context, matched[: max(max_items, 1)]
195
+ return context, matched[:result_limit]
189
196
 
190
197
  def apply_completion(
191
198
  self,
@@ -253,8 +260,6 @@ class LocalFileMentionCompleter(Completer):
253
260
  if self._is_ignored(name):
254
261
  continue
255
262
  entries.append(f"{prefix}{name}/" if entry.is_dir() else f"{prefix}{name}")
256
- if len(entries) >= self._limit:
257
- break
258
263
  except OSError as exc:
259
264
  logger.debug("directory mention scan failed for %s: %s", directory_fragment, exc)
260
265
  return cached[1] if cached is not None else []
@@ -284,8 +289,6 @@ class LocalFileMentionCompleter(Completer):
284
289
  if self._is_ignored(name):
285
290
  continue
286
291
  entries.append(f"{name}/" if entry.is_dir() else name)
287
- if len(entries) >= self._limit:
288
- break
289
292
  except OSError as exc:
290
293
  logger.debug("top-level mention scan failed: %s", exc)
291
294
  return self._top_cached_paths
@@ -311,8 +314,6 @@ class LocalFileMentionCompleter(Completer):
311
314
 
312
315
  if relative_root.parts:
313
316
  paths.append(relative_root.as_posix() + "/")
314
- if len(paths) >= self._limit:
315
- break
316
317
 
317
318
  for file_name in sorted(files):
318
319
  if self._is_ignored(file_name):
@@ -321,11 +322,6 @@ class LocalFileMentionCompleter(Completer):
321
322
  if not relative:
322
323
  continue
323
324
  paths.append(relative)
324
- if len(paths) >= self._limit:
325
- break
326
-
327
- if len(paths) >= self._limit:
328
- break
329
325
  except OSError as exc:
330
326
  logger.debug("deep mention scan failed: %s", exc)
331
327
  return self._deep_cached_paths
@@ -64,7 +64,9 @@ _ALLOWED_PRIORITY = {"high", "medium", "low"}
64
64
  _ALWAYS_HIDDEN_TOOLS: frozenset[str] = frozenset({"askuserquestion", "exitplanmode"})
65
65
 
66
66
  # Task coordination tools hidden from scrollback unless erroring.
67
- _SILENT_TASK_TOOLS: frozenset[str] = frozenset({"tasklist", "taskget"})
67
+ _SILENT_TASK_TOOLS: frozenset[str] = frozenset({
68
+ "taskcreate", "taskupdate", "tasklist", "taskget",
69
+ })
68
70
 
69
71
 
70
72
  def should_show_tool_in_scrollback(
@@ -85,17 +87,7 @@ def should_show_tool_in_scrollback(
85
87
  if lowered in _ALWAYS_HIDDEN_TOOLS:
86
88
  return is_result and is_error
87
89
 
88
- # TaskCreate: always visible.
89
- if lowered == "taskcreate":
90
- return True
91
-
92
- # TaskUpdate: visible only when status=completed, or on error.
93
- if lowered == "taskupdate":
94
- if str(args.get("status", "")).lower() == "completed":
95
- return True
96
- return is_result and is_error
97
-
98
- # TaskList / TaskGet: only show errors.
90
+ # Task tools: only show errors.
99
91
  if lowered in _SILENT_TASK_TOOLS:
100
92
  return is_result and is_error
101
93