soothe-cli 0.3.8__tar.gz → 0.4.0__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 (114) hide show
  1. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/PKG-INFO +3 -3
  2. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/README.md +1 -1
  3. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/pyproject.toml +1 -1
  4. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/thread_cmd.py +1 -1
  5. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/execution/headless.py +2 -4
  6. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/main.py +1 -1
  7. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/renderer.py +23 -3
  8. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/stream/context.py +4 -0
  9. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/stream/formatter.py +51 -22
  10. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/stream/pipeline.py +238 -77
  11. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/loop_commands.py +1 -1
  12. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/display_policy.py +1 -1
  13. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/event_processor.py +7 -21
  14. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/message_processing.py +24 -43
  15. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/presentation_engine.py +1 -1
  16. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/slash_commands.py +6 -0
  17. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/subagent_routing.py +1 -0
  18. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/suppression_state.py +1 -1
  19. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/web.py +3 -3
  20. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_output_formatter.py +4 -28
  21. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/app.py +3 -2
  22. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/command_registry.py +6 -0
  23. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/daemon_session.py +1 -1
  24. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/file_ops.py +8 -4
  25. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/message_display_filter.py +1 -1
  26. soothe_cli-0.4.0/src/soothe_cli/tui/preview_limits.py +42 -0
  27. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/sessions.py +3 -3
  28. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/textual_adapter.py +49 -28
  29. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/tool_display.py +50 -49
  30. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/approval.py +16 -14
  31. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/autopilot_dashboard.py +14 -5
  32. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/clipboard.py +3 -4
  33. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/diff.py +3 -2
  34. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/messages.py +65 -60
  35. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/tool_widgets.py +18 -16
  36. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/.gitignore +0 -0
  37. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/__init__.py +0 -0
  38. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/__init__.py +0 -0
  39. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/__init__.py +0 -0
  40. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/autopilot_cmd.py +0 -0
  41. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/config_cmd.py +0 -0
  42. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
  43. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/status_cmd.py +0 -0
  44. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/commands/subagent_names.py +0 -0
  45. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/execution/__init__.py +0 -0
  46. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/execution/daemon.py +0 -0
  47. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/execution/launcher.py +0 -0
  48. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/stream/__init__.py +0 -0
  49. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/stream/display_line.py +0 -0
  50. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/cli/utils.py +0 -0
  51. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/config/__init__.py +0 -0
  52. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/config/cli_config.py +0 -0
  53. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/plan/__init__.py +0 -0
  54. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/plan/rich_tree.py +0 -0
  55. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/__init__.py +0 -0
  56. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/command_router.py +0 -0
  57. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/config_loader.py +0 -0
  58. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/essential_events.py +0 -0
  59. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/processor_state.py +0 -0
  60. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/renderer_protocol.py +0 -0
  61. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/rendering.py +0 -0
  62. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_call_resolution.py +0 -0
  63. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_card_payload.py +0 -0
  64. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/__init__.py +0 -0
  65. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/base.py +0 -0
  66. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/execution.py +0 -0
  67. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/fallback.py +0 -0
  68. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/file_ops.py +0 -0
  69. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/goal_formatter.py +0 -0
  70. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/media.py +0 -0
  71. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_formatters/structured.py +0 -0
  72. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tool_message_format.py +0 -0
  73. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/shared/tui_trace_log.py +0 -0
  74. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/__init__.py +0 -0
  75. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/_ask_user_types.py +0 -0
  76. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/_cli_context.py +0 -0
  77. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/_env_vars.py +0 -0
  78. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/_session_stats.py +0 -0
  79. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/_version.py +0 -0
  80. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/app.tcss +0 -0
  81. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/config.py +0 -0
  82. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/formatting.py +0 -0
  83. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/hooks.py +0 -0
  84. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/input.py +0 -0
  85. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/media_utils.py +0 -0
  86. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/model_config.py +0 -0
  87. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/output.py +0 -0
  88. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/project_utils.py +0 -0
  89. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/skills/__init__.py +0 -0
  90. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/skills/invocation.py +0 -0
  91. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/skills/load.py +0 -0
  92. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/theme.py +0 -0
  93. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/unicode_security.py +0 -0
  94. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/update_check.py +0 -0
  95. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/__init__.py +0 -0
  96. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/_links.py +0 -0
  97. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/ask_user.py +0 -0
  98. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
  99. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/autopilot_screen.py +0 -0
  100. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
  101. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/editor.py +0 -0
  102. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/history.py +0 -0
  103. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/loading.py +0 -0
  104. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
  105. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
  106. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/message_store.py +0 -0
  107. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
  108. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
  109. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/status.py +0 -0
  110. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
  111. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/thread_selector.py +0 -0
  112. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/tool_renderers.py +0 -0
  113. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/tools.py +0 -0
  114. {soothe_cli-0.3.8 → soothe_cli-0.4.0}/src/soothe_cli/tui/widgets/welcome.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soothe-cli
3
- Version: 0.3.8
3
+ Version: 0.4.0
4
4
  Summary: Soothe CLI client - communicates with daemon via WebSocket
5
5
  Project-URL: Homepage, https://github.com/OpenSoothe/soothe
6
6
  Project-URL: Documentation, https://soothe.readthedocs.io
@@ -21,7 +21,7 @@ Requires-Python: <3.15,>=3.11
21
21
  Requires-Dist: python-dotenv<2.0.0,>=1.0.0
22
22
  Requires-Dist: pyyaml<7.0.0,>=6.0.0
23
23
  Requires-Dist: rich>=13.0.0
24
- Requires-Dist: soothe-sdk<1.0.0,>=0.3.3
24
+ Requires-Dist: soothe-sdk<1.0.0,>=0.4.0
25
25
  Requires-Dist: textual>=0.40.0
26
26
  Requires-Dist: typer<1.0.0,>=0.9.0
27
27
  Requires-Dist: websockets>=12.0
@@ -96,5 +96,5 @@ tui:
96
96
 
97
97
  ## Related Packages
98
98
 
99
- - **soothe-daemon**: Server package (agent runtime)
99
+ - **soothed**: Server package (agent runtime)
100
100
  - **soothe-sdk**: Shared SDK (WebSocket client, types)
@@ -61,5 +61,5 @@ tui:
61
61
 
62
62
  ## Related Packages
63
63
 
64
- - **soothe-daemon**: Server package (agent runtime)
64
+ - **soothed**: Server package (agent runtime)
65
65
  - **soothe-sdk**: Shared SDK (WebSocket client, types)
@@ -23,7 +23,7 @@ classifiers = [
23
23
  "Topic :: Software Development :: Libraries :: Python Modules",
24
24
  ]
25
25
  dependencies = [
26
- "soothe-sdk>=0.3.3,<1.0.0", # WebSocket client, protocol, types
26
+ "soothe-sdk>=0.4.0,<1.0.0", # WebSocket client, protocol, types
27
27
  "typer>=0.9.0,<1.0.0", # CLI framework
28
28
  "textual>=0.40.0", # TUI framework
29
29
  "rich>=13.0.0", # Console output
@@ -31,7 +31,7 @@ def _require_daemon(ws_url: str) -> None:
31
31
  live = asyncio.run(_check_daemon(ws_url))
32
32
  if not live:
33
33
  typer.echo(
34
- "Error: Daemon not running. Start with 'soothe daemon start'.",
34
+ "Error: Daemon not running. Start with 'soothed start'.",
35
35
  err=True,
36
36
  )
37
37
  sys.exit(1)
@@ -32,7 +32,7 @@ def run_headless(
32
32
  Connects to running daemon via WebSocket if available to avoid RocksDB lock conflicts.
33
33
  Auto-starts daemon if not running (RFC-0013 daemon lifecycle).
34
34
 
35
- Note (RFC-0013): Daemon persists after request completion. Use 'soothe-daemon stop'
35
+ Note (RFC-0013): Daemon persists after request completion. Use 'soothed stop'
36
36
  to explicitly shutdown the daemon.
37
37
  """
38
38
  from soothe_cli.cli.execution.daemon import run_headless_via_daemon
@@ -91,9 +91,7 @@ def run_headless(
91
91
 
92
92
  # Handle daemon fallback (unresponsive daemon)
93
93
  if daemon_exit_code == _DAEMON_FALLBACK_EXIT_CODE:
94
- typer.echo(
95
- "Error: Daemon is unresponsive. Please restart with 'soothe-daemon restart'", err=True
96
- )
94
+ typer.echo("Error: Daemon is unresponsive. Please restart with 'soothed restart'", err=True)
97
95
  sys.exit(1)
98
96
 
99
97
  sys.exit(daemon_exit_code)
@@ -87,7 +87,7 @@ def main(
87
87
 
88
88
  Run without arguments for interactive TUI mode, or provide a prompt via --prompt/-p option.
89
89
 
90
- Note: This is the CLI client. Use 'soothe-daemon' command to manage the daemon server.
90
+ Note: This is the CLI client. Use 'soothed' command to manage the daemon server.
91
91
 
92
92
  Examples:
93
93
  soothe # Interactive TUI mode
@@ -12,8 +12,8 @@ import time
12
12
  from dataclasses import dataclass, field
13
13
  from typing import TYPE_CHECKING, Any
14
14
 
15
- from soothe_sdk.utils import get_tool_display_name
16
- from soothe_sdk.verbosity import VerbosityTier
15
+ from soothe_sdk.core.verbosity import VerbosityTier
16
+ from soothe_sdk.utils import get_tool_pascal_name
17
17
 
18
18
  from soothe_cli.cli.stream import DisplayLine, StreamDisplayPipeline
19
19
  from soothe_cli.cli.utils import make_tool_block
@@ -111,6 +111,16 @@ class CliRenderer:
111
111
  """Shared presentation policy used with StreamDisplayPipeline and EventProcessor."""
112
112
  return self._presentation
113
113
 
114
+ def _is_inside_step_context(self) -> bool:
115
+ """Check if we're inside an active step (for indentation).
116
+
117
+ IG-257: Used to determine if tool calls/results should be indented as tree children.
118
+
119
+ Returns:
120
+ True if current_step_id is set in pipeline context.
121
+ """
122
+ return self._pipeline._context.current_step_id is not None
123
+
114
124
  def write_lines(self, lines: list[DisplayLine]) -> None:
115
125
  """Write display lines to stderr.
116
126
 
@@ -213,7 +223,7 @@ class CliRenderer:
213
223
 
214
224
  self._stderr_begin_icon_block()
215
225
 
216
- display_name = get_tool_display_name(name)
226
+ display_name = get_tool_pascal_name(name)
217
227
 
218
228
  # Pass args directly, including any _raw fallback
219
229
  args_str = format_tool_call_args(name, {"args": args, "_raw": args.get("_raw", "")})
@@ -221,6 +231,11 @@ class CliRenderer:
221
231
  # Use display helper for consistency with TUI (RFC-0020 Principle 5)
222
232
  tool_block = make_tool_block(display_name, args_str, status="running")
223
233
 
234
+ # IG-257: Add indentation when inside step context
235
+ # Unicode U+2514 "└─" (Box Drawings Light Up and Right) for tree branch
236
+ if self._is_inside_step_context():
237
+ tool_block = f" └─ {tool_block}"
238
+
224
239
  # Track start time for duration display (RFC-0020)
225
240
  if tool_call_id:
226
241
  self._state.tool_call_start_times[tool_call_id] = time.time()
@@ -272,6 +287,11 @@ class CliRenderer:
272
287
  if duration_ms > 0:
273
288
  result_line += f" ({duration_ms}ms)"
274
289
 
290
+ # IG-257: Add indentation when inside step context
291
+ # Unicode U+2514 "└─" (Box Drawings Light Up and Right) for tree branch
292
+ if self._is_inside_step_context():
293
+ result_line = f" └─ {result_line}"
294
+
275
295
  sys.stderr.write(result_line + "\n")
276
296
  sys.stderr.flush()
277
297
 
@@ -62,6 +62,8 @@ class PipelineContext:
62
62
  # Subagent tracking
63
63
  subagent_name: str | None = None
64
64
  subagent_milestones: list[str] = field(default_factory=list)
65
+ subagent_completion_shown: bool = False # IG-255: Track if completion already displayed
66
+ subagent_result_preview: str = "" # IG-255: Cache result preview for deduplication
65
67
 
66
68
  def reset_goal(self) -> None:
67
69
  """Reset goal-related state."""
@@ -84,6 +86,8 @@ class PipelineContext:
84
86
  self.parallel_header_emitted = False
85
87
  self.subagent_name = None
86
88
  self.subagent_milestones.clear()
89
+ self.subagent_completion_shown = False # IG-255: Reset completion flag
90
+ self.subagent_result_preview = "" # IG-255: Reset result preview
87
91
  # Don't clear _active_step_ids here - it's cleared when steps complete
88
92
 
89
93
  def complete_step(self, step_id: str) -> None:
@@ -2,7 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from soothe_sdk.verbosity import VerbosityTier
5
+ from soothe_sdk.core.verbosity import VerbosityTier
6
+ from soothe_sdk.utils import get_tool_pascal_name
6
7
 
7
8
  from soothe_cli.cli.stream.display_line import DisplayLine, indent_for_level
8
9
 
@@ -143,24 +144,33 @@ def format_tool_call(
143
144
  namespace: tuple[str, ...] = (),
144
145
  verbosity_tier: VerbosityTier = VerbosityTier.NORMAL,
145
146
  ) -> DisplayLine:
146
- """Format a tool call line.
147
+ """Format a tool/subagent call line.
148
+
149
+ IG-256: Restored uniform tool display - no subagent differentiation.
150
+ All tools/subagents use same wrench emoji and gear icon.
147
151
 
148
152
  Args:
149
- name: Tool name.
150
- args_summary: Truncated args.
151
- running: Whether tool is in parallel mode.
153
+ name: Tool or subagent name.
154
+ args_summary: Truncated args or query preview.
155
+ running: Whether tool/subagent is running.
152
156
  namespace: Event namespace.
153
157
  verbosity_tier: Current verbosity tier.
154
158
 
155
159
  Returns:
156
- DisplayLine for tool call.
160
+ DisplayLine for tool/subagent call with uniform wrench icon.
157
161
  """
158
- # Add inline symbol for tool execution
159
- content = f"🔧 {name}({args_summary})"
162
+ # Transform to PascalCase for display
163
+ display_name = get_tool_pascal_name(name)
164
+
165
+ # IG-256: No differentiation - use wrench for all tools/subagents
166
+ icon_emoji = "🔧"
167
+ icon_char = "⚙"
168
+
169
+ content = f"{icon_emoji} {display_name}({args_summary})"
160
170
  return DisplayLine(
161
171
  level=2,
162
172
  content=content,
163
- icon="⚙",
173
+ icon=icon_char,
164
174
  indent=indent_for_level(2),
165
175
  status="running" if running else None,
166
176
  source_prefix=_derive_source_prefix(namespace, verbosity_tier),
@@ -206,17 +216,19 @@ def format_subagent_milestone(
206
216
  namespace: tuple[str, ...] = (),
207
217
  verbosity_tier: VerbosityTier = VerbosityTier.NORMAL,
208
218
  ) -> DisplayLine:
209
- """Format a subagent milestone line.
219
+ """Format a subagent milestone line showing progress.
220
+
221
+ IG-256: Restored detective emoji for subagent milestones.
210
222
 
211
223
  Args:
212
- brief: Milestone description.
224
+ brief: Milestone description (e.g., "Step 3: click on login").
213
225
  namespace: Event namespace.
214
226
  verbosity_tier: Current verbosity tier.
215
227
 
216
228
  Returns:
217
- DisplayLine for milestone.
229
+ DisplayLine for milestone with detective emoji.
218
230
  """
219
- # Add inline symbol for subagent investigation
231
+ # IG-256: Use detective emoji for milestones (restored from IG-255)
220
232
  content = f"🕵🏻‍♂️ {brief}"
221
233
  return DisplayLine(
222
234
  level=3,
@@ -230,24 +242,33 @@ def format_subagent_milestone(
230
242
  def format_subagent_done(
231
243
  summary: str,
232
244
  duration_s: float,
245
+ result_preview: str = "",
233
246
  *,
234
247
  namespace: tuple[str, ...] = (),
235
248
  verbosity_tier: VerbosityTier = VerbosityTier.NORMAL,
236
249
  ) -> DisplayLine:
237
- """Format a subagent completion line.
250
+ """Format a subagent completion line with metrics.
251
+
252
+ IG-256: Restored verbose format with triple success markers and separate result display.
253
+ Result preview parameter is ignored - results show via separate tool events.
238
254
 
239
255
  Args:
240
- summary: Completion summary.
256
+ summary: Completion summary with subagent-specific metrics (e.g., "success", "$1.23").
241
257
  duration_s: Duration in seconds.
258
+ result_preview: Ignored (kept for backward compatibility).
242
259
  namespace: Event namespace.
243
260
  verbosity_tier: Current verbosity tier.
244
261
 
245
262
  Returns:
246
- DisplayLine for subagent done.
263
+ DisplayLine for subagent done with verbose triple markers.
247
264
  """
248
265
  duration_ms = int(duration_s * 1000)
249
- # Add inline symbol for subagent investigation complete
250
- content = f"🕵🏻‍♂️ Done: {summary}"
266
+
267
+ # IG-256: Verbose format restored - triple success markers, result shows separately
268
+ # Format: "✓ ✅ ✓ {summary}"
269
+ # result_preview is ignored - let result show via separate tool execution events
270
+ content = f"✓ ✅ ✓ {summary}"
271
+
251
272
  return DisplayLine(
252
273
  level=3,
253
274
  content=content,
@@ -269,8 +290,14 @@ def format_plan_phase_reasoning(
269
290
 
270
291
  IG-225: Uses level=2 (flat, no indent) for prominent visibility alongside step headers.
271
292
  Uses solid bullet ● (matching goal) to indicate reasoning phase is active.
293
+
294
+ IG-257: When label is empty, shows text without prefix (just emoji + text).
272
295
  """
273
- content = f"💭 {label}: {text}"
296
+ # IG-257: Handle empty label (no prefix)
297
+ if label:
298
+ content = f"💭 {label}: {text}"
299
+ else:
300
+ content = f"💭 {text}"
274
301
  return DisplayLine(
275
302
  level=2,
276
303
  content=content,
@@ -366,6 +393,8 @@ def format_step_done(
366
393
  IG-159/IG-182: Shows brief "Done"/"Failed" with tree connector as child of step header.
367
394
  No description repeat - user already saw it in the step header above.
368
395
 
396
+ IG-257: Uses Unicode tree branch "└─" (U+2514) for cleaner visual tree.
397
+
369
398
  Args:
370
399
  duration_s: Duration in seconds.
371
400
  tool_call_count: Number of tool calls made during step execution.
@@ -387,7 +416,7 @@ def format_step_done(
387
416
  DisplayLine(
388
417
  level=3, # Child node of step header (level 2)
389
418
  content=content,
390
- icon="|__", # Tree connector (IG-159)
419
+ icon="└─", # IG-257: Unicode tree branch (U+2514)
391
420
  indent=indent_for_level(3),
392
421
  duration_ms=duration_ms,
393
422
  source_prefix=_derive_source_prefix(namespace, verbosity_tier),
@@ -399,7 +428,7 @@ def format_step_done(
399
428
  DisplayLine(
400
429
  level=3,
401
430
  content=f"Failed{tool_info}",
402
- icon="|__",
431
+ icon="└─", # IG-257: Unicode tree branch (U+2514)
403
432
  indent=indent_for_level(3),
404
433
  duration_ms=duration_ms,
405
434
  source_prefix=_derive_source_prefix(namespace, verbosity_tier),
@@ -412,7 +441,7 @@ def format_step_done(
412
441
  DisplayLine(
413
442
  level=4, # Error detail as child of failed result
414
443
  content=f"Error: {error_msg}",
415
- icon="|__",
444
+ icon="└─", # IG-257: Unicode tree branch (U+2514)
416
445
  indent=indent_for_level(4),
417
446
  source_prefix=_derive_source_prefix(namespace, verbosity_tier),
418
447
  )