soothe-cli 1.0.0__tar.gz → 1.0.3__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.
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/PKG-INFO +1 -1
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/commands/binding.py +3 -3
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_execution.py +4 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_messages_mixin.py +21 -28
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/context_data.py +1 -1
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_goal_tree.py +5 -5
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_step.py +3 -3
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/structured_ask_user.py +118 -57
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/plan_quick_view_overlay.py +1 -1
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/.gitignore +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/README.md +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/pyproject.toml +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/_cli_context.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/_env_vars.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/_version.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/card_wire.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/autopilot_cmd.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/config_cmd.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/cron_cmd.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/loop_cmd.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/commands/status_cmd.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/execution/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/execution/daemon.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/execution/daemon_errors.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/execution/headless.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/execution/headless_renderer.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/execution/launcher.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/main.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/cli/soothecli.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/commands/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/commands/command_registry.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/commands/command_router.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/commands/slash_commands.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/commands/subagent_routing.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/config/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/config/cli_config.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/config/loader.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/config/logging_setup.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/markdown_theme.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/media_utils.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/mermaid_render.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/path_utils.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/preview_limits.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/shell_color.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/spinner_labels.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/theme.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/tips.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/tool_display.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/display/unicode_security.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/loops/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/loops/sessions.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/model_config.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/project_utils.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/headless/processor.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/headless/processor_state.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/parse/tool_call_resolution.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/policy/tui_trace_log.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/duration_format.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/engine.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/id_format.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/renderer_base.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/renderer_protocol.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/step_id_format.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/subagent_task_display.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/state/file_tracker.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/state/session_stats.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/state/step_router.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/state/stream_accumulator.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/token_events_debug.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/token_usage.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/transport/session.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/turn/prepare.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/wire/chunk_filter.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/wire/message_text.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/wire/messages.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/_console_impl.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/bootstrap.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/core.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/glyphs.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/provider.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/shell_allow.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/skills_dirs.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/settings/stream_config.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_app.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_clarification.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_entrypoints.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_history.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_model.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_model_params.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_startup.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_terminal.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_theme_prefs.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_types.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/_ui.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/app/app.tcss +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/composer_mode.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/file_change_notify.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/file_change_renderers.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/input.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/skills/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/skills/invocation.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/skills/load.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/textual_adapter.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/_links.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/clipboard.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/context_viewer.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/diff.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/editor.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/file_change_preview.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/help_screen.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/history.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/loading.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/message_store.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/__init__.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/_helpers.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/app.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/assistant.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_reason.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_step_activity.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/diff_message.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/error.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/skill.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/user.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/pinned_goal_bar.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/router_profile_selector.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/status.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/welcome.py +0 -0
- {soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/update_check.py +0 -0
|
@@ -155,14 +155,14 @@ def message_to_widget(data: MessageData) -> Widget:
|
|
|
155
155
|
is_tool_approval = origin == "tool_approval"
|
|
156
156
|
refine_label = "Edit" if is_tool_approval else "Refine"
|
|
157
157
|
question_spec = {
|
|
158
|
-
"question": "Action for this plan: Approve,
|
|
158
|
+
"question": "Action for this plan: Approve, Reject, or Refine?"
|
|
159
159
|
if not is_tool_approval
|
|
160
160
|
else "Approve this tool call?",
|
|
161
161
|
"header": "Plan review" if not is_tool_approval else "Tool approval",
|
|
162
162
|
"options": [
|
|
163
163
|
{"label": "Approve", "description": "Accept and proceed."},
|
|
164
|
-
{"label": refine_label, "description": "Request changes."},
|
|
165
164
|
{"label": "Reject", "description": "Reject."},
|
|
165
|
+
{"label": refine_label, "description": "Request changes."},
|
|
166
166
|
],
|
|
167
167
|
}
|
|
168
168
|
w = StructuredAskUserWidget(
|
|
@@ -261,7 +261,7 @@ def message_from_widget(widget: Widget) -> MessageData:
|
|
|
261
261
|
# Awaiting state for HITL origins.
|
|
262
262
|
if is_hitl and not widget._submitted: # noqa: SLF001
|
|
263
263
|
if is_plan_review:
|
|
264
|
-
content = "Plan review: awaiting Approve /
|
|
264
|
+
content = "Plan review: awaiting Approve / Reject / Refine"
|
|
265
265
|
else:
|
|
266
266
|
content = "Tool approval: awaiting Approve / Edit / Reject"
|
|
267
267
|
return MessageData(type=MessageType.APP, content=content, id=widget_id)
|
|
@@ -341,6 +341,10 @@ class _ExecutionMixin:
|
|
|
341
341
|
# next pauses, which freezes scrolling and chat-input focus.
|
|
342
342
|
await self._send_to_agent(payload_text)
|
|
343
343
|
|
|
344
|
+
# Return focus to the chat input so the user can type immediately.
|
|
345
|
+
with suppress(Exception):
|
|
346
|
+
self.focus_primary_input()
|
|
347
|
+
|
|
344
348
|
async def _resolve_default_clarification_mode(self) -> str:
|
|
345
349
|
"""Fetch the daemon's default clarification mode for plan approval.
|
|
346
350
|
|
|
@@ -793,20 +793,22 @@ class _MessagesMixin:
|
|
|
793
793
|
def action_quit_or_interrupt(self) -> None:
|
|
794
794
|
"""Handle Ctrl+C — clear input, interrupt work, or exit on double-press.
|
|
795
795
|
|
|
796
|
-
Priority order
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
Interrupting a task resets the idle double-press exit state.
|
|
800
|
-
|
|
801
|
-
When idle, Ctrl+C arms a double-press exit:
|
|
802
|
-
1. First press clears any pending draft and shows a hint.
|
|
803
|
-
2. Second press within the timeout window exits the TUI.
|
|
804
|
-
|
|
805
|
-
Note: Copying selected text is bound to Ctrl+Y (`action_copy_selection`)
|
|
806
|
-
so Ctrl+C is reserved for interrupt/exit behavior.
|
|
796
|
+
Priority order: HITL review card (abandon + focus chat) → running
|
|
797
|
+
task (clear input, then interrupt) → idle double-press exit.
|
|
798
|
+
Ctrl+Y copies selection, so Ctrl+C stays reserved for this path.
|
|
807
799
|
"""
|
|
808
800
|
current_time = time.monotonic()
|
|
809
801
|
|
|
802
|
+
# HITL review card (plan/tool): abandon and return focus to chat.
|
|
803
|
+
if self._has_active_qa_widget():
|
|
804
|
+
widget = self._active_plan_review_widget()
|
|
805
|
+
if widget is not None and not getattr(widget, "_submitted", False):
|
|
806
|
+
widget._abandon()
|
|
807
|
+
self._ctrl_c_pressed_time = None
|
|
808
|
+
if self._chat_input:
|
|
809
|
+
self._chat_input.focus_input()
|
|
810
|
+
return
|
|
811
|
+
|
|
810
812
|
# Check if input has pending content (text, mode, or completion).
|
|
811
813
|
has_pending_input = self._has_pending_chat_input()
|
|
812
814
|
|
|
@@ -1072,25 +1074,21 @@ class _MessagesMixin:
|
|
|
1072
1074
|
inputs.append(inp)
|
|
1073
1075
|
return inputs
|
|
1074
1076
|
|
|
1075
|
-
def
|
|
1076
|
-
"""
|
|
1077
|
+
def _active_plan_review_widget(self) -> Widget | None:
|
|
1078
|
+
"""Return the active unsubmitted HITL review card, if any."""
|
|
1077
1079
|
adapter = getattr(self, "_ui_adapter", None)
|
|
1078
1080
|
if adapter is None:
|
|
1079
1081
|
return None
|
|
1080
1082
|
by_step = getattr(adapter, "_clarification_input_by_step", None) or {}
|
|
1081
|
-
# Both option-selector origins render Approve / Refine(Edit) / Reject buttons.
|
|
1082
1083
|
for message in by_step.values():
|
|
1083
1084
|
if getattr(message, "_submitted", False):
|
|
1084
1085
|
continue
|
|
1085
1086
|
# String compare — avoid MagicMock truthiness on property access in tests.
|
|
1086
|
-
if getattr(message, "_origin_node", None)
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
approve = buttons.get("approve")
|
|
1092
|
-
if approve is not None and not getattr(approve, "disabled", False):
|
|
1093
|
-
return approve
|
|
1087
|
+
if getattr(message, "_origin_node", None) in (
|
|
1088
|
+
"plan_mode_review",
|
|
1089
|
+
"tool_approval",
|
|
1090
|
+
):
|
|
1091
|
+
return message
|
|
1094
1092
|
return None
|
|
1095
1093
|
|
|
1096
1094
|
def _non_chat_focusable_inputs(self) -> list[Input]:
|
|
@@ -1107,18 +1105,13 @@ class _MessagesMixin:
|
|
|
1107
1105
|
"""Return the single input that should receive typing focus, if unambiguous.
|
|
1108
1106
|
|
|
1109
1107
|
When an inline clarification card is active, its answer field takes
|
|
1110
|
-
precedence over the bottom chat prompt.
|
|
1111
|
-
focuses the Approve action. On modal screens, a lone
|
|
1108
|
+
precedence over the bottom chat prompt. On modal screens, a lone
|
|
1112
1109
|
filter box is focused automatically.
|
|
1113
1110
|
"""
|
|
1114
1111
|
clar_inputs = self._active_clarification_inputs()
|
|
1115
1112
|
if clar_inputs:
|
|
1116
1113
|
return clar_inputs[0]
|
|
1117
1114
|
|
|
1118
|
-
plan_action = self._active_plan_review_action_focus()
|
|
1119
|
-
if plan_action is not None:
|
|
1120
|
-
return plan_action
|
|
1121
|
-
|
|
1122
1115
|
non_chat = self._non_chat_focusable_inputs()
|
|
1123
1116
|
if len(non_chat) == 1:
|
|
1124
1117
|
return non_chat[0]
|
|
@@ -138,7 +138,7 @@ def format_token_usage(snapshot: TokenUsageSnapshot) -> str:
|
|
|
138
138
|
formatted = format_token_count(count)
|
|
139
139
|
usage = f"{formatted}{suffix} tokens used this loop"
|
|
140
140
|
if in_count > 0 or out_count > 0:
|
|
141
|
-
usage += f" (
|
|
141
|
+
usage += f" (↑{format_token_count(in_count)} · ↓{format_token_count(out_count)})"
|
|
142
142
|
|
|
143
143
|
msg = f"{usage} · {model_name}" if model_name else usage
|
|
144
144
|
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_goal_tree.py
RENAMED
|
@@ -331,7 +331,7 @@ class CognitionGoalTreeMessage(Vertical):
|
|
|
331
331
|
self._goal_out_tokens += out_t
|
|
332
332
|
|
|
333
333
|
def goal_token_suffix(self) -> str:
|
|
334
|
-
"""Compact
|
|
334
|
+
"""Compact `↑1.2K ↓345` suffix for the plan panel title.
|
|
335
335
|
|
|
336
336
|
Returns an empty string when no step has recorded any tokens.
|
|
337
337
|
"""
|
|
@@ -340,7 +340,7 @@ class CognitionGoalTreeMessage(Vertical):
|
|
|
340
340
|
return ""
|
|
341
341
|
from soothe_cli.runtime.state.session_stats import format_token_count
|
|
342
342
|
|
|
343
|
-
return f"
|
|
343
|
+
return f"↑{format_token_count(total_in)} ↓{format_token_count(total_out)}"
|
|
344
344
|
|
|
345
345
|
def mark_loop_started(self, started_at: float | None = None) -> None:
|
|
346
346
|
"""Anchor plan-level elapsed time (matches thinking-row turn start)."""
|
|
@@ -390,14 +390,14 @@ class CognitionGoalTreeMessage(Vertical):
|
|
|
390
390
|
|
|
391
391
|
@staticmethod
|
|
392
392
|
def _step_token_parts(st: _StepLineState) -> list[str]:
|
|
393
|
-
"""
|
|
393
|
+
"""Arrow token labels for a step row, e.g. `↑1.2K ↓345`."""
|
|
394
394
|
if not (st.input_tokens or st.output_tokens):
|
|
395
395
|
return []
|
|
396
396
|
from soothe_cli.runtime.state.session_stats import format_token_count
|
|
397
397
|
|
|
398
398
|
return [
|
|
399
|
-
f"
|
|
400
|
-
f"
|
|
399
|
+
f"↑{format_token_count(st.input_tokens)}",
|
|
400
|
+
f"↓{format_token_count(st.output_tokens)}",
|
|
401
401
|
]
|
|
402
402
|
|
|
403
403
|
def _step_summary_suffix(self, st: _StepLineState) -> str:
|
|
@@ -251,14 +251,14 @@ class CognitionStepMessage(Vertical):
|
|
|
251
251
|
self._sync_step_card_surface()
|
|
252
252
|
|
|
253
253
|
def _token_budget_suffix(self) -> str:
|
|
254
|
-
"""Token budget suffix for status lines, e.g.
|
|
254
|
+
"""Token budget suffix for status lines, e.g. `↑1.2K ↓345`."""
|
|
255
255
|
if not (self._input_tokens or self._output_tokens):
|
|
256
256
|
return ""
|
|
257
257
|
from soothe_cli.runtime.state.session_stats import format_token_count
|
|
258
258
|
|
|
259
259
|
parts: list[str] = []
|
|
260
|
-
parts.append(f"
|
|
261
|
-
parts.append(f"
|
|
260
|
+
parts.append(f"↑{format_token_count(self._input_tokens)}")
|
|
261
|
+
parts.append(f"↓{format_token_count(self._output_tokens)}")
|
|
262
262
|
return " · " + " ".join(parts)
|
|
263
263
|
|
|
264
264
|
def _compact_title_meta_suffix(self) -> str:
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/structured_ask_user.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Unifies the generic ``ask_user`` (execute origin) and the HITL plan-review /
|
|
4
4
|
tool-approval origins into one widget. HITL origins differ only in that their
|
|
5
|
-
options are system-prefilled (Approve / Refine or Edit
|
|
5
|
+
options are system-prefilled (Approve / Reject / Refine or Edit), the ``Other``
|
|
6
6
|
free-text row is suppressed, and the Refine/Edit option shows a comment input.
|
|
7
7
|
"""
|
|
8
8
|
|
|
@@ -214,17 +214,21 @@ class StructuredAskUserWidget(Vertical):
|
|
|
214
214
|
display: none;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
/* ── Inline option inputs (shared by custom + comment) ────────── */
|
|
218
|
+
|
|
219
|
+
/* `!important` beats Textual's default Input `:focus` border + height. */
|
|
220
|
+
StructuredAskUserWidget .saq-inline-input {
|
|
221
|
+
margin: 0;
|
|
219
222
|
width: 1fr;
|
|
220
|
-
height:
|
|
221
|
-
padding: 0
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
height: auto !important;
|
|
224
|
+
padding: 0 !important;
|
|
225
|
+
border: none !important;
|
|
226
|
+
background: transparent !important;
|
|
227
|
+
color: $foreground !important;
|
|
224
228
|
}
|
|
225
229
|
|
|
226
|
-
StructuredAskUserWidget .saq-
|
|
227
|
-
|
|
230
|
+
StructuredAskUserWidget .saq-inline-input:disabled {
|
|
231
|
+
color: $text-muted;
|
|
228
232
|
}
|
|
229
233
|
|
|
230
234
|
StructuredAskUserWidget .saq-custom-hint {
|
|
@@ -351,7 +355,8 @@ class StructuredAskUserWidget(Vertical):
|
|
|
351
355
|
StructuredAskUserWidget.is-submitted .saq-footer,
|
|
352
356
|
StructuredAskUserWidget.is-submitted .saq-hint,
|
|
353
357
|
StructuredAskUserWidget.is-submitted .saq-recap,
|
|
354
|
-
StructuredAskUserWidget.is-submitted .saq-separator
|
|
358
|
+
StructuredAskUserWidget.is-submitted .saq-separator,
|
|
359
|
+
StructuredAskUserWidget.is-submitted .saq-body-path {
|
|
355
360
|
display: none;
|
|
356
361
|
}
|
|
357
362
|
|
|
@@ -414,17 +419,19 @@ class StructuredAskUserWidget(Vertical):
|
|
|
414
419
|
min-width: 0;
|
|
415
420
|
}
|
|
416
421
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
422
|
+
/* `❯` prefix before the comment input — same line height as the row.
|
|
423
|
+
Hidden unless the Refine/Edit option is highlighted. */
|
|
424
|
+
StructuredAskUserWidget .saq-comment-prefix {
|
|
425
|
+
width: auto;
|
|
420
426
|
height: 1;
|
|
421
|
-
padding: 0
|
|
422
|
-
|
|
423
|
-
|
|
427
|
+
padding: 0;
|
|
428
|
+
margin: 0 1 0 1;
|
|
429
|
+
color: $primary;
|
|
430
|
+
visibility: hidden;
|
|
424
431
|
}
|
|
425
432
|
|
|
426
|
-
StructuredAskUserWidget .saq-comment-
|
|
427
|
-
|
|
433
|
+
StructuredAskUserWidget .saq-comment-prefix.is-visible {
|
|
434
|
+
visibility: visible;
|
|
428
435
|
}
|
|
429
436
|
|
|
430
437
|
/* ── HITL: expand/collapse plan body in answered view ──────────── */
|
|
@@ -437,6 +444,11 @@ class StructuredAskUserWidget(Vertical):
|
|
|
437
444
|
margin: 0;
|
|
438
445
|
}
|
|
439
446
|
|
|
447
|
+
/* After submit, hide the plan body preview unless expanded via toggle. */
|
|
448
|
+
StructuredAskUserWidget.is-submitted .saq-body-box {
|
|
449
|
+
display: none;
|
|
450
|
+
}
|
|
451
|
+
|
|
440
452
|
StructuredAskUserWidget.is-submitted .saq-body-box.is-expanded {
|
|
441
453
|
display: block;
|
|
442
454
|
}
|
|
@@ -767,13 +779,19 @@ class StructuredAskUserWidget(Vertical):
|
|
|
767
779
|
classes="saq-option-row",
|
|
768
780
|
markup=False,
|
|
769
781
|
)
|
|
782
|
+
yield Static(
|
|
783
|
+
"❯",
|
|
784
|
+
id="saq-comment-prefix",
|
|
785
|
+
classes="saq-comment-prefix",
|
|
786
|
+
markup=False,
|
|
787
|
+
)
|
|
770
788
|
comment_placeholder = (
|
|
771
789
|
"Revised args…" if self._is_tool_approval else "Comments…"
|
|
772
790
|
)
|
|
773
791
|
self._comment_input = Input(
|
|
774
792
|
placeholder=comment_placeholder,
|
|
775
793
|
id="saq-comment-input",
|
|
776
|
-
classes="saq-
|
|
794
|
+
classes="saq-inline-input",
|
|
777
795
|
disabled=True,
|
|
778
796
|
)
|
|
779
797
|
yield self._comment_input
|
|
@@ -804,7 +822,7 @@ class StructuredAskUserWidget(Vertical):
|
|
|
804
822
|
self._custom_input = Input(
|
|
805
823
|
placeholder="Type a custom answer…",
|
|
806
824
|
id="saq-custom-input",
|
|
807
|
-
classes="saq-
|
|
825
|
+
classes="saq-inline-input",
|
|
808
826
|
disabled=_has_renderable_opts,
|
|
809
827
|
)
|
|
810
828
|
yield self._custom_input
|
|
@@ -962,8 +980,6 @@ class StructuredAskUserWidget(Vertical):
|
|
|
962
980
|
def _start_focus_guard(self) -> None:
|
|
963
981
|
"""Poll every 200 ms and recapture focus if it drifted from the widget.
|
|
964
982
|
|
|
965
|
-
Scrollbar clicks, hydration re-layouts, and lifecycle events can
|
|
966
|
-
move focus to the chat input, the scroll container, or ``None``.
|
|
967
983
|
Stopped on submit/abandon.
|
|
968
984
|
"""
|
|
969
985
|
|
|
@@ -974,16 +990,9 @@ class StructuredAskUserWidget(Vertical):
|
|
|
974
990
|
focused = self.app.focused
|
|
975
991
|
except Exception: # noqa: BLE001
|
|
976
992
|
return
|
|
977
|
-
# Recapture whenever focus has left the widget and its
|
|
978
|
-
# descendants. The chat input is the most common culprit, but
|
|
979
|
-
# scrollbar clicks, hydration re-layouts, and other events can
|
|
980
|
-
# also move focus to None or the scroll container.
|
|
981
993
|
if not self._focus_drifted(focused):
|
|
982
994
|
return
|
|
983
|
-
|
|
984
|
-
self.app.set_focus(self)
|
|
985
|
-
except Exception: # noqa: BLE001
|
|
986
|
-
pass
|
|
995
|
+
self._refocus_self_no_scroll()
|
|
987
996
|
|
|
988
997
|
try:
|
|
989
998
|
self._focus_guard_timer = self.set_interval(0.2, _tick)
|
|
@@ -1001,12 +1010,7 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1001
1010
|
self._focus_guard_timer = None
|
|
1002
1011
|
|
|
1003
1012
|
def _schedule_robust_focus(self) -> None:
|
|
1004
|
-
"""Pin focus to the widget for ~600 ms after mount.
|
|
1005
|
-
|
|
1006
|
-
Textual's post-mount layout can re-focus the chat input after
|
|
1007
|
-
`call_after_refresh` fires; staggered re-focus calls win that race
|
|
1008
|
-
so arrow keys / Enter work immediately on appear.
|
|
1009
|
-
"""
|
|
1013
|
+
"""Pin focus to the widget for ~600 ms after mount."""
|
|
1010
1014
|
|
|
1011
1015
|
def _refocus() -> None:
|
|
1012
1016
|
try:
|
|
@@ -1017,10 +1021,7 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1017
1021
|
return
|
|
1018
1022
|
except Exception: # noqa: BLE001
|
|
1019
1023
|
pass
|
|
1020
|
-
|
|
1021
|
-
self.app.set_focus(self)
|
|
1022
|
-
except Exception: # noqa: BLE001
|
|
1023
|
-
pass
|
|
1024
|
+
self._refocus_self_no_scroll()
|
|
1024
1025
|
|
|
1025
1026
|
try:
|
|
1026
1027
|
self.set_timer(0.05, _refocus)
|
|
@@ -1030,6 +1031,13 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1030
1031
|
except Exception: # noqa: BLE001
|
|
1031
1032
|
pass
|
|
1032
1033
|
|
|
1034
|
+
def _refocus_self_no_scroll(self) -> None:
|
|
1035
|
+
"""Focus the container without scrolling (prevents plan-header jump)."""
|
|
1036
|
+
try:
|
|
1037
|
+
self.app.set_focus(self, scroll_visible=False)
|
|
1038
|
+
except Exception: # noqa: BLE001
|
|
1039
|
+
pass
|
|
1040
|
+
|
|
1033
1041
|
def _focus_drifted(self, focused: Any) -> bool:
|
|
1034
1042
|
"""Return True if focus left the widget and its descendants.
|
|
1035
1043
|
|
|
@@ -1075,16 +1083,12 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1075
1083
|
self._toggle_body_expanded()
|
|
1076
1084
|
|
|
1077
1085
|
def on_descendant_focus(self, event: DescendantFocus) -> None:
|
|
1078
|
-
"""
|
|
1079
|
-
|
|
1080
|
-
if
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
):
|
|
1085
|
-
sel = self._selected.get(self._current_q)
|
|
1086
|
-
if sel != self._comment_option_index:
|
|
1087
|
-
self.screen.set_focus(self)
|
|
1086
|
+
"""An inline input holds focus only while its option is highlighted."""
|
|
1087
|
+
allowed = self._inline_input_for_highlight()
|
|
1088
|
+
if allowed is not None and event.widget is allowed:
|
|
1089
|
+
return
|
|
1090
|
+
if event.widget in self._inline_inputs():
|
|
1091
|
+
self.screen.set_focus(self)
|
|
1088
1092
|
|
|
1089
1093
|
# ── Rendering updates ──────────────────────────────────────────
|
|
1090
1094
|
|
|
@@ -1197,6 +1201,15 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1197
1201
|
# HITL: enable/disable comment input based on the selected option.
|
|
1198
1202
|
if self._comment_input is not None and self._comment_option_index is not None:
|
|
1199
1203
|
self._update_comment_input_state()
|
|
1204
|
+
# Show the `❯` prefix only when the comment option is highlighted.
|
|
1205
|
+
try:
|
|
1206
|
+
prefix = self.query_one("#saq-comment-prefix", Static)
|
|
1207
|
+
if self._highlighted == self._comment_option_index:
|
|
1208
|
+
prefix.add_class("is-visible")
|
|
1209
|
+
else:
|
|
1210
|
+
prefix.remove_class("is-visible")
|
|
1211
|
+
except Exception: # noqa: BLE001
|
|
1212
|
+
pass
|
|
1200
1213
|
|
|
1201
1214
|
def _update_custom_row_highlight(self, custom_idx: int) -> None:
|
|
1202
1215
|
"""Apply highlight/selected classes and refresh the custom-row text."""
|
|
@@ -1244,12 +1257,47 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1244
1257
|
pass
|
|
1245
1258
|
|
|
1246
1259
|
def _update_comment_input_state(self) -> None:
|
|
1247
|
-
"""Enable
|
|
1260
|
+
"""Enable the comment input when Refine/Edit is highlighted."""
|
|
1248
1261
|
if self._comment_input is None or self._comment_option_index is None:
|
|
1249
1262
|
return
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1263
|
+
self._comment_input.disabled = self._highlighted != self._comment_option_index
|
|
1264
|
+
|
|
1265
|
+
# ── Inline-input helpers (shared by custom + comment) ───────────
|
|
1266
|
+
|
|
1267
|
+
def _inline_inputs(self) -> tuple[Input, ...]:
|
|
1268
|
+
"""Existing inline `Input`s attached to option rows."""
|
|
1269
|
+
return tuple(inp for inp in (self._custom_input, self._comment_input) if inp is not None)
|
|
1270
|
+
|
|
1271
|
+
def _inline_input_for_highlight(self) -> Input | None:
|
|
1272
|
+
"""The inline input whose option is highlighted, else None."""
|
|
1273
|
+
if (
|
|
1274
|
+
self._comment_option_index is not None
|
|
1275
|
+
and self._highlighted == self._comment_option_index
|
|
1276
|
+
):
|
|
1277
|
+
return self._comment_input
|
|
1278
|
+
if self._allow_custom:
|
|
1279
|
+
custom_idx = len(self._question_options(self._current_q))
|
|
1280
|
+
if self._highlighted == custom_idx:
|
|
1281
|
+
return self._custom_input
|
|
1282
|
+
return None
|
|
1283
|
+
|
|
1284
|
+
def _focus_inline_input_or_container(self) -> None:
|
|
1285
|
+
"""Focus the highlighted option's inline input, or the container.
|
|
1286
|
+
|
|
1287
|
+
When leaving an inline input (Refine→Approve/Reject), the input is
|
|
1288
|
+
disabled by `_update_comment_input_state`, which makes Textual drop
|
|
1289
|
+
focus to None. Proactively re-focus the container without scrolling
|
|
1290
|
+
so the 200 ms guard doesn't recapture and scroll to the plan header.
|
|
1291
|
+
"""
|
|
1292
|
+
target = self._inline_input_for_highlight()
|
|
1293
|
+
if target is not None and not target.disabled:
|
|
1294
|
+
try:
|
|
1295
|
+
self.app.set_focus(target)
|
|
1296
|
+
return
|
|
1297
|
+
except Exception: # noqa: BLE001
|
|
1298
|
+
pass
|
|
1299
|
+
# No inline input — keep focus on the container without scrolling.
|
|
1300
|
+
self._refocus_self_no_scroll()
|
|
1253
1301
|
|
|
1254
1302
|
def _update_tab_highlight(self) -> None:
|
|
1255
1303
|
"""Update tab labels to reflect current question and answered state."""
|
|
@@ -1444,6 +1492,7 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1444
1492
|
total = num_opts + (1 if self._allow_custom else 0)
|
|
1445
1493
|
self._highlighted = (self._highlighted - 1) % total
|
|
1446
1494
|
self._update_option_highlight()
|
|
1495
|
+
self._focus_inline_input_or_container()
|
|
1447
1496
|
|
|
1448
1497
|
def action_next_option(self) -> None:
|
|
1449
1498
|
if self._degraded or self._submitted or self._submit_review_open:
|
|
@@ -1452,6 +1501,7 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1452
1501
|
total = num_opts + (1 if self._allow_custom else 0)
|
|
1453
1502
|
self._highlighted = (self._highlighted + 1) % total
|
|
1454
1503
|
self._update_option_highlight()
|
|
1504
|
+
self._focus_inline_input_or_container()
|
|
1455
1505
|
|
|
1456
1506
|
def action_confirm(self) -> None:
|
|
1457
1507
|
"""Enter: select highlighted option, or finalize submit review."""
|
|
@@ -1471,7 +1521,10 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1471
1521
|
if self._allow_custom and self._highlighted == custom_idx:
|
|
1472
1522
|
# Custom row — focus the input if not yet selected
|
|
1473
1523
|
if self._custom_input is not None and not self._custom_input.disabled:
|
|
1474
|
-
|
|
1524
|
+
try:
|
|
1525
|
+
self.app.set_focus(self._custom_input)
|
|
1526
|
+
except Exception: # noqa: BLE001
|
|
1527
|
+
self._schedule_focus(self._custom_input)
|
|
1475
1528
|
return
|
|
1476
1529
|
# Select the highlighted option
|
|
1477
1530
|
self._selected[self._current_q] = self._highlighted
|
|
@@ -1484,7 +1537,10 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1484
1537
|
and self._highlighted == self._comment_option_index
|
|
1485
1538
|
and self._comment_input is not None
|
|
1486
1539
|
):
|
|
1487
|
-
|
|
1540
|
+
try:
|
|
1541
|
+
self.app.set_focus(self._comment_input)
|
|
1542
|
+
except Exception: # noqa: BLE001
|
|
1543
|
+
self._schedule_focus(self._comment_input)
|
|
1488
1544
|
return
|
|
1489
1545
|
# HITL: immediate submit on action selection (Approve/Reject).
|
|
1490
1546
|
if self._is_hitl:
|
|
@@ -1600,7 +1656,12 @@ class StructuredAskUserWidget(Vertical):
|
|
|
1600
1656
|
# HITL: comment input — Enter submits with the comment.
|
|
1601
1657
|
if event.input is self._comment_input:
|
|
1602
1658
|
event.stop()
|
|
1603
|
-
|
|
1659
|
+
text = str(event.input.value or "").strip()
|
|
1660
|
+
if not text:
|
|
1661
|
+
return
|
|
1662
|
+
self._comment_text = text
|
|
1663
|
+
# Select Refine/Edit so _answers_collected appends the comment.
|
|
1664
|
+
self._selected[self._current_q] = self._comment_option_index
|
|
1604
1665
|
self._finalize()
|
|
1605
1666
|
return
|
|
1606
1667
|
if self._degraded:
|
|
@@ -37,7 +37,7 @@ def _plan_quick_view_title(
|
|
|
37
37
|
elapsed: str | None = None,
|
|
38
38
|
tokens: str | None = None,
|
|
39
39
|
) -> str:
|
|
40
|
-
"""Compose the panel title: `Orchestrating [8d26] · complex · 37s ·
|
|
40
|
+
"""Compose the panel title: `Orchestrating [8d26] · complex · 37s · ↑1.2K ↓345`."""
|
|
41
41
|
title = "Orchestrating"
|
|
42
42
|
short_id = compact_id_suffix(loop_id or "")
|
|
43
43
|
if short_id:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/duration_format.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/renderer_protocol.py
RENAMED
|
File without changes
|
|
File without changes
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/runtime/presentation/subagent_task_display.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_reason.py
RENAMED
|
File without changes
|
{soothe_cli-1.0.0 → soothe_cli-1.0.3}/src/soothe_cli/tui/widgets/messages/cognition_step_activity.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|