soothe-cli 0.3.8__tar.gz → 0.4.1__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 (115) hide show
  1. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/PKG-INFO +3 -3
  2. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/README.md +1 -1
  3. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/pyproject.toml +1 -1
  4. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/thread_cmd.py +1 -1
  5. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/execution/headless.py +2 -4
  6. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/main.py +1 -1
  7. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/renderer.py +21 -1
  8. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/stream/context.py +4 -0
  9. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/stream/formatter.py +64 -35
  10. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/stream/pipeline.py +248 -80
  11. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/loop_commands.py +1 -1
  12. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/display_policy.py +1 -1
  13. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/event_processor.py +7 -21
  14. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/message_processing.py +35 -44
  15. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/presentation_engine.py +1 -1
  16. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/slash_commands.py +6 -0
  17. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/subagent_routing.py +1 -0
  18. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/suppression_state.py +1 -1
  19. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/__init__.py +2 -0
  20. soothe_cli-0.4.1/src/soothe_cli/shared/tool_formatters/subagent.py +122 -0
  21. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/web.py +3 -3
  22. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_output_formatter.py +8 -28
  23. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/app.py +3 -2
  24. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/command_registry.py +6 -0
  25. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/daemon_session.py +1 -1
  26. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/file_ops.py +8 -4
  27. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/message_display_filter.py +1 -1
  28. soothe_cli-0.4.1/src/soothe_cli/tui/preview_limits.py +42 -0
  29. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/sessions.py +3 -3
  30. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/textual_adapter.py +49 -28
  31. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/tool_display.py +50 -49
  32. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/approval.py +16 -14
  33. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/autopilot_dashboard.py +14 -5
  34. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/clipboard.py +3 -4
  35. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/diff.py +3 -2
  36. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/messages.py +65 -60
  37. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/tool_widgets.py +18 -16
  38. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/.gitignore +0 -0
  39. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/__init__.py +0 -0
  40. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/__init__.py +0 -0
  41. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/__init__.py +0 -0
  42. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/autopilot_cmd.py +0 -0
  43. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/config_cmd.py +0 -0
  44. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
  45. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/status_cmd.py +0 -0
  46. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/commands/subagent_names.py +0 -0
  47. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/execution/__init__.py +0 -0
  48. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/execution/daemon.py +0 -0
  49. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/execution/launcher.py +0 -0
  50. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/stream/__init__.py +0 -0
  51. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/stream/display_line.py +0 -0
  52. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/cli/utils.py +0 -0
  53. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/config/__init__.py +0 -0
  54. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/config/cli_config.py +0 -0
  55. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/plan/__init__.py +0 -0
  56. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/plan/rich_tree.py +0 -0
  57. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/__init__.py +0 -0
  58. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/command_router.py +0 -0
  59. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/config_loader.py +0 -0
  60. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/essential_events.py +0 -0
  61. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/processor_state.py +0 -0
  62. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/renderer_protocol.py +0 -0
  63. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/rendering.py +0 -0
  64. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_call_resolution.py +0 -0
  65. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_card_payload.py +0 -0
  66. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/base.py +0 -0
  67. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/execution.py +0 -0
  68. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/fallback.py +0 -0
  69. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/file_ops.py +0 -0
  70. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/goal_formatter.py +0 -0
  71. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/media.py +0 -0
  72. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_formatters/structured.py +0 -0
  73. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tool_message_format.py +0 -0
  74. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/shared/tui_trace_log.py +0 -0
  75. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/__init__.py +0 -0
  76. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/_ask_user_types.py +0 -0
  77. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/_cli_context.py +0 -0
  78. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/_env_vars.py +0 -0
  79. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/_session_stats.py +0 -0
  80. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/_version.py +0 -0
  81. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/app.tcss +0 -0
  82. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/config.py +0 -0
  83. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/formatting.py +0 -0
  84. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/hooks.py +0 -0
  85. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/input.py +0 -0
  86. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/media_utils.py +0 -0
  87. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/model_config.py +0 -0
  88. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/output.py +0 -0
  89. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/project_utils.py +0 -0
  90. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/skills/__init__.py +0 -0
  91. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/skills/invocation.py +0 -0
  92. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/skills/load.py +0 -0
  93. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/theme.py +0 -0
  94. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/unicode_security.py +0 -0
  95. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/update_check.py +0 -0
  96. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/__init__.py +0 -0
  97. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/_links.py +0 -0
  98. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/ask_user.py +0 -0
  99. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
  100. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/autopilot_screen.py +0 -0
  101. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
  102. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/editor.py +0 -0
  103. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/history.py +0 -0
  104. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/loading.py +0 -0
  105. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
  106. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
  107. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/message_store.py +0 -0
  108. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
  109. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
  110. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/status.py +0 -0
  111. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
  112. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/thread_selector.py +0 -0
  113. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/tool_renderers.py +0 -0
  114. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/src/soothe_cli/tui/widgets/tools.py +0 -0
  115. {soothe_cli-0.3.8 → soothe_cli-0.4.1}/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.1
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.core.verbosity import VerbosityTier
15
16
  from soothe_sdk.utils import get_tool_display_name
16
- from soothe_sdk.verbosity import VerbosityTier
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
 
@@ -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_display_name
6
7
 
7
8
  from soothe_cli.cli.stream.display_line import DisplayLine, indent_for_level
8
9
 
@@ -95,7 +96,7 @@ def format_goal_header(
95
96
  DisplayLine for goal header.
96
97
  """
97
98
  # Add inline symbol for goal marker
98
- content = f"⌯⌲ {goal}"
99
+ content = f"{goal}"
99
100
  return DisplayLine(
100
101
  level=1,
101
102
  content=content,
@@ -125,7 +126,7 @@ def format_step_header(
125
126
  """
126
127
  suffix = " (parallel)" if parallel else ""
127
128
  # Add inline symbol for step progression
128
- content = f" {description}{suffix}"
129
+ content = f"❇️ {description}{suffix}"
129
130
  return DisplayLine(
130
131
  level=2,
131
132
  content=content,
@@ -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_display_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,
@@ -291,6 +318,9 @@ def format_reasoning(
291
318
  IG-XXX: Shows technical reasoning with "Reasoning:" prefix for clarity.
292
319
  Uses solid bullet ● (matching goal) to indicate reasoning is active phase.
293
320
 
321
+ IG-262: Uses level=2 (flat layout) for consistency with judgement lines.
322
+ Reasoning is a sibling to judgement, not a child.
323
+
294
324
  Args:
295
325
  reasoning: Internal technical analysis text.
296
326
  namespace: Event namespace.
@@ -303,10 +333,10 @@ def format_reasoning(
303
333
  content = f"💭 {reasoning}"
304
334
 
305
335
  return DisplayLine(
306
- level=3, # Use level 3 for less prominence (subordinate to next_action)
336
+ level=2, # IG-262: Use level 2 for flat layout (sibling to judgement, not child)
307
337
  content=content,
308
338
  icon="●", # Solid bullet matching goal icon (polish)
309
- indent=indent_for_level(3),
339
+ indent=indent_for_level(2),
310
340
  source_prefix=_derive_source_prefix(namespace, verbosity_tier),
311
341
  )
312
342
 
@@ -323,11 +353,12 @@ def format_judgement(
323
353
 
324
354
  IG-089: Shows meaningful judgement info without raw intermediate data.
325
355
  IG-XXX: Prominent reasoning display with "Reason:" prefix for clarity.
356
+ IG-265: Removed [new]/[keep] badge from CLI display (kept in event data for logs).
326
357
 
327
358
  Args:
328
359
  judgement: Human-readable summary of the decision.
329
360
  action: Action taken ("continue" or "complete").
330
- plan_action: When set, show ``[keep]`` or ``[new]`` before the judgement text.
361
+ plan_action: Ignored (kept for backward compatibility, appears in logs only).
331
362
  namespace: Event namespace.
332
363
  verbosity_tier: Current verbosity tier.
333
364
 
@@ -336,12 +367,8 @@ def format_judgement(
336
367
  """
337
368
  action_icon = "○" if action == "continue" else "●" # Polish: ○ for continue, ● for complete
338
369
 
339
- badge = ""
340
- if plan_action in ("keep", "new"):
341
- badge = f"[{plan_action}] "
342
-
343
- # Polish: Add "Reason:" prefix to make LLM reasoning prominent
344
- content = f"🌀 {badge}{judgement}"
370
+ # IG-265: Remove badge from CLI display (plan_action kept in event data for logs)
371
+ content = f"🌟 {judgement}"
345
372
 
346
373
  return DisplayLine(
347
374
  level=2, # Use level 2 for more prominence (like step headers)
@@ -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.
@@ -382,12 +411,12 @@ def format_step_done(
382
411
 
383
412
  # Success case: single line
384
413
  if success:
385
- content = f"Done{tool_info}"
414
+ content = f"Done{tool_info}"
386
415
  return [
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),
@@ -398,8 +427,8 @@ def format_step_done(
398
427
  lines = [
399
428
  DisplayLine(
400
429
  level=3,
401
- content=f"Failed{tool_info}",
402
- icon="|__",
430
+ content=f"Failed{tool_info}",
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
  )