soothe-cli 1.0.16__tar.gz → 1.0.18__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 (146) hide show
  1. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/PKG-INFO +1 -1
  2. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_execution.py +7 -11
  3. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/textual_adapter.py +26 -14
  4. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/.gitignore +0 -0
  5. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/README.md +0 -0
  6. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/pyproject.toml +0 -0
  7. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/__init__.py +0 -0
  8. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/_cli_context.py +0 -0
  9. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/_env_vars.py +0 -0
  10. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/_version.py +0 -0
  11. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/card_wire.py +0 -0
  12. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/__init__.py +0 -0
  13. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/commands/__init__.py +0 -0
  14. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/commands/config_cmd.py +0 -0
  15. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/commands/cron_cmd.py +0 -0
  16. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/commands/loop_cmd.py +0 -0
  17. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
  18. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/commands/status_cmd.py +0 -0
  19. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/execution/__init__.py +0 -0
  20. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/execution/daemon.py +0 -0
  21. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/execution/daemon_errors.py +0 -0
  22. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/execution/headless.py +0 -0
  23. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/execution/headless_renderer.py +0 -0
  24. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/execution/launcher.py +0 -0
  25. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/main.py +0 -0
  26. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/cli/soothecli.py +0 -0
  27. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/commands/__init__.py +0 -0
  28. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/commands/binding.py +0 -0
  29. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/commands/command_registry.py +0 -0
  30. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/commands/command_router.py +0 -0
  31. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/commands/slash_commands.py +0 -0
  32. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/commands/subagent_routing.py +0 -0
  33. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/config/__init__.py +0 -0
  34. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/config/cli_config.py +0 -0
  35. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/config/loader.py +0 -0
  36. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/config/logging_setup.py +0 -0
  37. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/__init__.py +0 -0
  38. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/card.py +0 -0
  39. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/markdown_theme.py +0 -0
  40. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/media_utils.py +0 -0
  41. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/mermaid_render.py +0 -0
  42. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/path_utils.py +0 -0
  43. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/preview_limits.py +0 -0
  44. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/shell_color.py +0 -0
  45. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/spinner_labels.py +0 -0
  46. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/theme.py +0 -0
  47. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/tips.py +0 -0
  48. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/tool_display.py +0 -0
  49. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/display/unicode_security.py +0 -0
  50. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/loops/__init__.py +0 -0
  51. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/loops/sessions.py +0 -0
  52. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/model_config.py +0 -0
  53. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/project_utils.py +0 -0
  54. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/__init__.py +0 -0
  55. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/headless/processor.py +0 -0
  56. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/headless/processor_state.py +0 -0
  57. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/parse/tool_call_resolution.py +0 -0
  58. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/policy/tui_trace_log.py +0 -0
  59. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/duration_format.py +0 -0
  60. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/engine.py +0 -0
  61. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/id_format.py +0 -0
  62. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/renderer_base.py +0 -0
  63. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/renderer_protocol.py +0 -0
  64. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/step_id_format.py +0 -0
  65. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/presentation/subagent_task_display.py +0 -0
  66. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/state/file_tracker.py +0 -0
  67. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/state/session_stats.py +0 -0
  68. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/state/step_router.py +0 -0
  69. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/state/stream_accumulator.py +0 -0
  70. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/token_events_debug.py +0 -0
  71. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/token_usage.py +0 -0
  72. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/transport/session.py +0 -0
  73. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/turn/prepare.py +0 -0
  74. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/wire/chunk_filter.py +0 -0
  75. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/wire/message_text.py +0 -0
  76. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/runtime/wire/messages.py +0 -0
  77. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/__init__.py +0 -0
  78. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/_console_impl.py +0 -0
  79. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/bootstrap.py +0 -0
  80. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/core.py +0 -0
  81. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/glyphs.py +0 -0
  82. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/provider.py +0 -0
  83. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/shell_allow.py +0 -0
  84. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/skills_dirs.py +0 -0
  85. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/settings/stream_config.py +0 -0
  86. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/__init__.py +0 -0
  87. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/__init__.py +0 -0
  88. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_app.py +0 -0
  89. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_clarification.py +0 -0
  90. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_entrypoints.py +0 -0
  91. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_history.py +0 -0
  92. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_messages_mixin.py +0 -0
  93. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_model.py +0 -0
  94. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_model_params.py +0 -0
  95. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_startup.py +0 -0
  96. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_terminal.py +0 -0
  97. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_theme_prefs.py +0 -0
  98. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_types.py +0 -0
  99. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/_ui.py +0 -0
  100. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/app/app.tcss +0 -0
  101. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/composer_mode.py +0 -0
  102. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/file_change_notify.py +0 -0
  103. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/file_change_renderers.py +0 -0
  104. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/input.py +0 -0
  105. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/skills/__init__.py +0 -0
  106. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/skills/invocation.py +0 -0
  107. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/skills/load.py +0 -0
  108. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/__init__.py +0 -0
  109. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/_links.py +0 -0
  110. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
  111. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
  112. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/clipboard.py +0 -0
  113. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/context_data.py +0 -0
  114. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/context_viewer.py +0 -0
  115. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/diff.py +0 -0
  116. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/editor.py +0 -0
  117. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/file_change_preview.py +0 -0
  118. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/help_screen.py +0 -0
  119. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/history.py +0 -0
  120. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/loading.py +0 -0
  121. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
  122. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
  123. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/message_store.py +0 -0
  124. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/__init__.py +0 -0
  125. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/_helpers.py +0 -0
  126. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/app.py +0 -0
  127. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/assistant.py +0 -0
  128. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/cognition_goal_tree.py +0 -0
  129. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/cognition_reason.py +0 -0
  130. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/cognition_step.py +0 -0
  131. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/cognition_step_activity.py +0 -0
  132. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/diff_message.py +0 -0
  133. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/error.py +0 -0
  134. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/skill.py +0 -0
  135. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/structured_ask_user.py +0 -0
  136. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/messages/user.py +0 -0
  137. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
  138. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
  139. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/pinned_goal_bar.py +0 -0
  140. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/plan_quick_view_overlay.py +0 -0
  141. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/queued_goals_bar.py +0 -0
  142. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/router_profile_selector.py +0 -0
  143. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/status.py +0 -0
  144. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
  145. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/tui/widgets/welcome.py +0 -0
  146. {soothe_cli-1.0.16 → soothe_cli-1.0.18}/src/soothe_cli/update_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: soothe-cli
3
- Version: 1.0.16
3
+ Version: 1.0.18
4
4
  Summary: Soothe CLI client - communicates with daemon via WebSocket
5
5
  Project-URL: Homepage, https://github.com/mirasoth/soothe
6
6
  Project-URL: Documentation, https://soothe.readthedocs.io
@@ -232,13 +232,7 @@ class _ExecutionMixin:
232
232
  answers: list[str],
233
233
  origin_node: str = "",
234
234
  ) -> None:
235
- """Shared clarification-answer forwarding.
236
-
237
- Renders the answers on the matching step card, disarms stale inline
238
- widgets, and hands the answers to `_send_to_agent` so the daemon
239
- resumes the suspended loop graph with one answer per question
240
- instead of starting a new turn.
241
- """
235
+ """Forward clarification answers to the daemon so the loop graph resumes."""
242
236
  adapter = self._ui_adapter
243
237
  if adapter is None:
244
238
  return
@@ -258,9 +252,12 @@ class _ExecutionMixin:
258
252
  except Exception: # noqa: BLE001
259
253
  logger.debug("Failed to render clarification answers on step card", exc_info=True)
260
254
 
261
- # Drop tracking; the inline widget itself stays mounted (disabled) so
262
- # the user can still see what they answered.
263
- adapter._clarification_input_by_step.pop(step_id, None)
255
+ # Mark the submitted widget so a late re-emit deduplicates against it
256
+ # instead of mounting a second card. The widget stays mounted (disabled).
257
+ submitted_widget = adapter._clarification_input_by_step.get(step_id)
258
+ if submitted_widget is not None:
259
+ submitted_widget._submitted = True # noqa: SLF001
260
+ submitted_widget.add_class("is-submitted")
264
261
 
265
262
  # A stale empty remount (resume re-emit) can leave another interactive
266
263
  # plan-review card. Disable extras so a second click cannot fire a
@@ -282,7 +279,6 @@ class _ExecutionMixin:
282
279
  inp.disabled = True
283
280
  except Exception: # noqa: BLE001
284
281
  logger.debug("Failed to disarm leftover clarification widget", exc_info=True)
285
- adapter._clarification_input_by_step.pop(sid, None)
286
282
 
287
283
  non_empty = [a for a in answers if a.strip()]
288
284
  if not non_empty:
@@ -2928,10 +2928,10 @@ async def _mount_manual_clarification_input(
2928
2928
  ) -> str:
2929
2929
  """Mount (or reuse) the inline clarification answer widget.
2930
2930
 
2931
- Prefers the paused step id from the wire event, then a running step card,
2932
- then an active orphan SubAgent card, then a synthetic key from
2933
- `origin_node`. HITL origins get `allow_custom=False` and an optional plan
2934
- body; structured dicts render structured mode, plain strings degraded mode.
2931
+ Reuses an existing widget for the same `origin_node` (including one already
2932
+ submitted) to avoid duplicate cards on late re-emits. Otherwise resolves a
2933
+ target step id from the wire event, a running step card, an active orphan
2934
+ SubAgent card, or a synthetic key from `origin_node`.
2935
2935
 
2936
2936
  Returns:
2937
2937
  The step/key used for `adapter._clarification_input_by_step`.
@@ -2948,16 +2948,18 @@ async def _mount_manual_clarification_input(
2948
2948
  if not questions_list:
2949
2949
  return ""
2950
2950
 
2951
- # Reuse an already-mounted, unanswered widget for this origin. A single
2952
- # clarification can be announced more than once, and the first mount flips
2953
- # the step card to "pending", so a re-emit would otherwise resolve a
2954
- # different key and mount a duplicate question card.
2951
+ # Reuse an already-mounted widget for this origin so a late re-emit does
2952
+ # not mount a duplicate. When the wire event carries a step_id, scope reuse
2953
+ # to the same step so a stale (already-answered) card from a prior step
2954
+ # does not suppress a fresh approval prompt for a different step.
2955
+ target_origin = str(origin_node or "").strip()
2956
+ incoming_step = str(step_id or "").strip()
2955
2957
  for _key, _w in adapter._clarification_input_by_step.items():
2956
- if (
2957
- not getattr(_w, "_submitted", False)
2958
- and getattr(_w, "_origin_node", "") == str(origin_node or "").strip()
2959
- ):
2960
- return _key
2958
+ if getattr(_w, "_origin_node", "") != target_origin:
2959
+ continue
2960
+ if incoming_step and getattr(_w, "_step_id", "") != incoming_step:
2961
+ continue
2962
+ return _key
2961
2963
 
2962
2964
  target_step_id = str(step_id or "").strip()
2963
2965
  if target_step_id and target_step_id in adapter._current_step_messages:
@@ -3012,7 +3014,7 @@ async def _mount_manual_clarification_input(
3012
3014
  mount_result = adapter._mount_message(input_widget)
3013
3015
  if mount_result is not None:
3014
3016
  await mount_result
3015
- return target_step_id
3017
+ return target_step_id
3016
3018
 
3017
3019
 
3018
3020
  async def execute_task_textual(
@@ -4243,6 +4245,16 @@ async def execute_task_textual(
4243
4245
  if event_type == LOOP_CLARIFICATION_ANSWERED:
4244
4246
  clarification_pending = False
4245
4247
  adapter._clarification_pending = False
4248
+ # Evict already-submitted clarification cards so a
4249
+ # later approval for a different step is not
4250
+ # deduped against this answered one (the loop
4251
+ # would otherwise park in await_clarification
4252
+ # with no visible prompt).
4253
+ adapter._clarification_input_by_step = {
4254
+ _k: _w
4255
+ for _k, _w in adapter._clarification_input_by_step.items()
4256
+ if not getattr(_w, "_submitted", False)
4257
+ }
4246
4258
  if adapter._resume_spinner:
4247
4259
  await adapter._resume_spinner()
4248
4260
  continue
File without changes
File without changes
File without changes