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.
- {comate_cli-0.4.4 → comate_cli-0.4.5}/.gitignore +1 -1
- {comate_cli-0.4.4 → comate_cli-0.4.5}/PKG-INFO +1 -1
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/animations.py +216 -23
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/event_renderer.py +35 -7
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/history_printer.py +7 -2
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/mention_completer.py +10 -14
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tool_view.py +4 -12
- comate_cli-0.4.5/docs/superpowers/plans/2026-04-03-phrase-shuffle.md +187 -0
- comate_cli-0.4.5/docs/superpowers/specs/2026-04-03-phrase-shuffle-design.md +55 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/pyproject.toml +1 -1
- comate_cli-0.4.5/tests/test_animator_shuffle.py +76 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_event_renderer.py +3 -3
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_mention_completer.py +46 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tool_view.py +11 -13
- {comate_cli-0.4.4 → comate_cli-0.4.5}/uv.lock +2 -2
- {comate_cli-0.4.4 → comate_cli-0.4.5}/README.md +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/__init__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/__main__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/main.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/mcp_cli.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/__init__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/app.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/assistant_render.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/codenames.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/custom_slash_commands.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/env_utils.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/error_display.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/fragment_utils.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/input_geometry.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/layout_coordinator.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/logging_adapter.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/logo.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/markdown_render.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/message_style.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/models.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/path_context_hint.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/__init__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/__init__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/detail_view.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/plugin_list.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/search_box.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/components/tab_bar.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/marketplace_install_view.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/plugin_picker.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/__init__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/discover_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/errors_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/installed_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/plugins/tabs/marketplaces_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/preflight.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/question_view.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/resume_selector.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/rewind_store.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/rpc_protocol.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/rpc_stdio.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/selection_menu.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/session_view.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/slash_commands.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/startup.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/status_bar.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/text_effects.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tips.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/__init__.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/commands.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/history_sync.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/input_behavior.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/key_bindings.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/mcp_connecting_view.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/render_panels.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/slash_command_registry.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/comate_cli/terminal_agent/tui_parts/ui_mode.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/docs/superpowers/specs/2026-04-01-conditional-diff-subtitle-design.md +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/conftest.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_mcp_preload.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_preflight_gate.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_print_mode.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_shutdown.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_app_usage_line.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_cli_project_root.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_compact_command_semantics.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_completion_context_activation.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_completion_status_panel.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_context_command.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_custom_slash_commands.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_discover_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_errors_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_format_error.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_handle_error.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_history_printer.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_history_sync.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_input_behavior.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_input_history.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_installed_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_interrupt_exit_semantics.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_layout_coordinator.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_logging_adapter.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_logo.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_main_args.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_marketplaces_tab.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_mcp_cli.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_mcp_slash_command.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_path_context_hint.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_plugin_slash_commands.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_plugin_tui_components.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_preflight.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_preflight_copilot.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_question_key_bindings.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_question_view.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_resume_selector.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rewind_command_semantics.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rewind_store.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rpc_protocol.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_rpc_stdio_bridge.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_selection_menu.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_skills_slash_command.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_slash_argument_hint.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_slash_completer.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_slash_registry.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_status_bar.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_status_bar_transient.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_panel_format.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_panel_key_bindings.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_panel_rendering.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_task_poll.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_elapsed_status.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_mcp_init_gate.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_paste_placeholder.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_tui_split_invariance.py +0 -0
- {comate_cli-0.4.4 → comate_cli-0.4.5}/tests/test_update_check.py +0 -0
|
@@ -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.
|
|
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.
|
|
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"
|
|
513
|
+
entries.append((1, f"⎿ {signature}"))
|
|
514
514
|
else:
|
|
515
515
|
icon = "✓" if child_tool.status == "completed" else "✗"
|
|
516
|
-
entries.append((1, f"
|
|
516
|
+
entries.append((1, f"⎿ {icon} {signature}"))
|
|
517
517
|
|
|
518
518
|
if state.show_init:
|
|
519
|
-
entries.append((1, "
|
|
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"
|
|
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(
|
|
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
|
-
|
|
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[:
|
|
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({
|
|
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
|
-
#
|
|
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
|
|