comate-cli 0.7.0a6__tar.gz → 0.7.0a7__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 (163) hide show
  1. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/PKG-INFO +1 -1
  2. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/input_behavior.py +32 -4
  3. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/key_bindings.py +1 -1
  4. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/pyproject.toml +1 -1
  5. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_paste_newline_guard.py +62 -0
  6. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/.gitignore +0 -0
  7. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/CHANGELOG.md +0 -0
  8. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/README.md +0 -0
  9. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/bash-exit-code-green-dot-bug.md +0 -0
  10. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/__init__.py +0 -0
  11. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/__main__.py +0 -0
  12. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/main.py +0 -0
  13. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/mcp_cli.py +0 -0
  14. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/__init__.py +0 -0
  15. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/animations.py +0 -0
  16. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/app.py +0 -0
  17. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/assistant_render.py +0 -0
  18. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/codenames.py +0 -0
  19. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/custom_slash_commands.py +0 -0
  20. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/env_utils.py +0 -0
  21. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/error_display.py +0 -0
  22. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/event_renderer.py +0 -0
  23. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/figures.py +0 -0
  24. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/fragment_utils.py +0 -0
  25. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/history_printer.py +0 -0
  26. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/input_geometry.py +0 -0
  27. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/layout_coordinator.py +0 -0
  28. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/logging_adapter.py +0 -0
  29. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/logo.py +0 -0
  30. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/markdown_render.py +0 -0
  31. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/mention_completer.py +0 -0
  32. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/message_style.py +0 -0
  33. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/models.py +0 -0
  34. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/path_context_hint.py +0 -0
  35. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/__init__.py +0 -0
  36. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/components/__init__.py +0 -0
  37. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/components/detail_view.py +0 -0
  38. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/components/plugin_list.py +0 -0
  39. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/components/search_box.py +0 -0
  40. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/components/tab_bar.py +0 -0
  41. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/marketplace_install_view.py +0 -0
  42. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/plugin_picker.py +0 -0
  43. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/tabs/__init__.py +0 -0
  44. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/tabs/discover_tab.py +0 -0
  45. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/tabs/errors_tab.py +0 -0
  46. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/tabs/installed_tab.py +0 -0
  47. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/plugins/tabs/marketplaces_tab.py +0 -0
  48. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/preflight.py +0 -0
  49. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/question_view.py +0 -0
  50. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/resume_picker.py +0 -0
  51. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/resume_preview.py +0 -0
  52. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/resume_selector.py +0 -0
  53. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/rpc_protocol.py +0 -0
  54. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/rpc_stdio.py +0 -0
  55. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/selection_menu.py +0 -0
  56. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/slash_commands.py +0 -0
  57. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/startup.py +0 -0
  58. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/status_bar.py +0 -0
  59. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/text_effects.py +0 -0
  60. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tips.py +0 -0
  61. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tool_result_formatters.py +0 -0
  62. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tool_result_store.py +0 -0
  63. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tool_result_viewer.py +0 -0
  64. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tool_view.py +0 -0
  65. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/transcript_viewer.py +0 -0
  66. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui.py +0 -0
  67. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/__init__.py +0 -0
  68. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/btw_view.py +0 -0
  69. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/commands.py +0 -0
  70. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/history_sync.py +0 -0
  71. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/mcp_connecting_view.py +0 -0
  72. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/render_panels.py +0 -0
  73. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/slash_command_registry.py +0 -0
  74. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/comate_cli/terminal_agent/tui_parts/ui_mode.py +0 -0
  75. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/docs/hooks.md +0 -0
  76. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/docs/superpowers/plans/2026-04-03-phrase-shuffle.md +0 -0
  77. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/docs/superpowers/specs/2026-04-01-conditional-diff-subtitle-design.md +0 -0
  78. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/docs/superpowers/specs/2026-04-03-phrase-shuffle-design.md +0 -0
  79. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/conftest.py +0 -0
  80. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/fixtures/fake_mcp_misbehaving_stdout.py +0 -0
  81. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_animator_shuffle.py +0 -0
  82. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_app_mcp_preload.py +0 -0
  83. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_app_preflight_gate.py +0 -0
  84. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_app_print_mode.py +0 -0
  85. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_app_shutdown.py +0 -0
  86. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_app_usage_line.py +0 -0
  87. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_btw_slash_command.py +0 -0
  88. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_cli_project_root.py +0 -0
  89. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_compact_command_semantics.py +0 -0
  90. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_completion_context_activation.py +0 -0
  91. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_completion_status_panel.py +0 -0
  92. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_context_command.py +0 -0
  93. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_custom_slash_commands.py +0 -0
  94. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_discover_tab.py +0 -0
  95. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_errors_tab.py +0 -0
  96. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_event_renderer.py +0 -0
  97. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_event_renderer_boundary.py +0 -0
  98. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_event_renderer_e2e.py +0 -0
  99. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_event_renderer_log_boundary.py +0 -0
  100. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_event_renderer_log_queue.py +0 -0
  101. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_event_renderer_streaming.py +0 -0
  102. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_format_error.py +0 -0
  103. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_handle_error.py +0 -0
  104. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_history_printer.py +0 -0
  105. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_history_printer_log.py +0 -0
  106. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_history_sync.py +0 -0
  107. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_input_behavior.py +0 -0
  108. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_input_history.py +0 -0
  109. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_installed_tab.py +0 -0
  110. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_interrupt_exit_semantics.py +0 -0
  111. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_layout_coordinator.py +0 -0
  112. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_logging_adapter.py +0 -0
  113. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_logo.py +0 -0
  114. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_main_args.py +0 -0
  115. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_markdown_render.py +0 -0
  116. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_marketplaces_tab.py +0 -0
  117. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_mcp_cli.py +0 -0
  118. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_mcp_slash_command.py +0 -0
  119. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_mention_completer.py +0 -0
  120. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_path_context_hint.py +0 -0
  121. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_plugin_slash_commands.py +0 -0
  122. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_plugin_tui_components.py +0 -0
  123. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_preflight.py +0 -0
  124. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_preflight_copilot.py +0 -0
  125. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_question_key_bindings.py +0 -0
  126. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_question_view.py +0 -0
  127. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_resume_picker.py +0 -0
  128. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_resume_preview.py +0 -0
  129. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_resume_selector.py +0 -0
  130. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_rewind_command_semantics.py +0 -0
  131. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_rpc_protocol.py +0 -0
  132. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_rpc_stdio_bridge.py +0 -0
  133. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_selection_menu.py +0 -0
  134. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_session_query_token_summary.py +0 -0
  135. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_shutdown_noise_guard.py +0 -0
  136. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_shutdown_noise_integration.py +0 -0
  137. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_skills_slash_command.py +0 -0
  138. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_slash_argument_hint.py +0 -0
  139. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_slash_completer.py +0 -0
  140. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_slash_registry.py +0 -0
  141. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_status_bar.py +0 -0
  142. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_status_bar_transient.py +0 -0
  143. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_task_panel_format.py +0 -0
  144. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_task_panel_key_bindings.py +0 -0
  145. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_task_panel_rendering.py +0 -0
  146. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_task_poll.py +0 -0
  147. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tool_result_formatters.py +0 -0
  148. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tool_result_store.py +0 -0
  149. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tool_result_viewer.py +0 -0
  150. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tool_result_viewer_key_bindings.py +0 -0
  151. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tool_view.py +0 -0
  152. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_transcript_viewer.py +0 -0
  153. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_elapsed_status.py +0 -0
  154. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_esc_queue.py +0 -0
  155. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_mcp_init_gate.py +0 -0
  156. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_paste_placeholder.py +0 -0
  157. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_queue_preview.py +0 -0
  158. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_queue_sdk_source.py +0 -0
  159. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_split_invariance.py +0 -0
  160. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_team_messages.py +0 -0
  161. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_tui_tool_result_registry_lifecycle.py +0 -0
  162. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/tests/test_update_check.py +0 -0
  163. {comate_cli-0.7.0a6 → comate_cli-0.7.0a7}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comate-cli
3
- Version: 0.7.0a6
3
+ Version: 0.7.0a7
4
4
  Summary: Comate terminal CLI built on comate-agent-sdk
5
5
  Project-URL: Homepage, https://github.com/AndyLee1024/agent-sdk
6
6
  Project-URL: Repository, https://github.com/AndyLee1024/agent-sdk
@@ -5,6 +5,7 @@ from bisect import bisect_right
5
5
  from typing import Any
6
6
 
7
7
  from prompt_toolkit.document import Document
8
+ from prompt_toolkit.keys import Keys
8
9
 
9
10
  from comate_agent_sdk.agent.chat_session import ChatSessionQueueFullError
10
11
 
@@ -229,15 +230,42 @@ class InputBehaviorMixin:
229
230
  getattr(self, "_paste_guard_active_until", 0.0)
230
231
  )
231
232
 
232
- def _should_treat_enter_as_pasted_newline(self, buffer: Any) -> bool:
233
- if not self._is_paste_guard_active():
233
+ @staticmethod
234
+ def _key_press_looks_like_paste_continuation(key_press: Any) -> bool:
235
+ key = getattr(key_press, "key", None)
236
+ if isinstance(key, Keys):
237
+ return False
238
+ return isinstance(key, str) and len(key) == 1
239
+
240
+ def _event_has_queued_paste_continuation(self, event: Any | None) -> bool:
241
+ if event is None:
234
242
  return False
243
+ try:
244
+ queued_keys = tuple(event.key_processor.input_queue)
245
+ except Exception:
246
+ return False
247
+ return any(
248
+ self._key_press_looks_like_paste_continuation(key_press)
249
+ for key_press in queued_keys
250
+ )
251
+
252
+ def _should_treat_enter_as_pasted_newline(
253
+ self,
254
+ buffer: Any,
255
+ event: Any | None = None,
256
+ ) -> bool:
235
257
  if getattr(buffer, "complete_state", None) is not None:
236
258
  return False
259
+ if not self._is_paste_guard_active():
260
+ return self._event_has_queued_paste_continuation(event)
237
261
  return True
238
262
 
239
- def _handle_normal_enter_key(self, buffer: Any) -> bool:
240
- if not self._should_treat_enter_as_pasted_newline(buffer):
263
+ def _handle_normal_enter_key(
264
+ self,
265
+ buffer: Any,
266
+ event: Any | None = None,
267
+ ) -> bool:
268
+ if not self._should_treat_enter_as_pasted_newline(buffer, event):
241
269
  return False
242
270
  buffer.insert_text("\n")
243
271
  self._extend_paste_guard()
@@ -411,7 +411,7 @@ class KeyBindingsMixin:
411
411
  @bindings.add("enter", filter=normal_mode, eager=True)
412
412
  def _enter(event) -> None:
413
413
  buffer = event.current_buffer
414
- if self._handle_normal_enter_key(buffer):
414
+ if self._handle_normal_enter_key(buffer, event):
415
415
  return
416
416
 
417
417
  cs = buffer.complete_state
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "comate-cli"
7
- version = "0.7.0a6"
7
+ version = "0.7.0a7"
8
8
  description = "Comate terminal CLI built on comate-agent-sdk"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -2,6 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import time
4
4
  import unittest
5
+ from collections import deque
6
+
7
+ from prompt_toolkit.key_binding.key_processor import KeyPress
8
+ from prompt_toolkit.keys import Keys
5
9
 
6
10
  from comate_cli.terminal_agent.tui import TerminalAgentTUI, UIMode
7
11
 
@@ -38,6 +42,16 @@ class _FakeInputArea:
38
42
  self.buffer = _FakeBuffer(text)
39
43
 
40
44
 
45
+ class _FakeKeyProcessor:
46
+ def __init__(self, queued_keys: list[KeyPress]) -> None:
47
+ self.input_queue = deque(queued_keys)
48
+
49
+
50
+ class _FakeEvent:
51
+ def __init__(self, queued_keys: list[KeyPress]) -> None:
52
+ self.key_processor = _FakeKeyProcessor(queued_keys)
53
+
54
+
41
55
  def _build_tui() -> TerminalAgentTUI:
42
56
  tui = TerminalAgentTUI.__new__(TerminalAgentTUI)
43
57
  tui._ui_mode = UIMode.NORMAL
@@ -155,6 +169,54 @@ class TestTUIPasteNewlineGuard(unittest.TestCase):
155
169
  self.assertFalse(handled)
156
170
  self.assertEqual(buffer.text, "hello")
157
171
 
172
+ def test_queued_printable_input_after_enter_is_treated_as_paste_newline(
173
+ self,
174
+ ) -> None:
175
+ tui = _build_tui()
176
+ buffer = _FakeBuffer("line1")
177
+ event = _FakeEvent([KeyPress("l", "l"), KeyPress("i", "i")])
178
+
179
+ handled = tui._handle_normal_enter_key(buffer, event)
180
+
181
+ self.assertTrue(handled)
182
+ self.assertEqual(buffer.text, "line1\n")
183
+ self.assertTrue(tui._is_paste_guard_active())
184
+
185
+ def test_queued_newline_then_text_after_enter_is_treated_as_paste_newline(
186
+ self,
187
+ ) -> None:
188
+ tui = _build_tui()
189
+ buffer = _FakeBuffer("line1")
190
+ event = _FakeEvent([KeyPress(Keys.ControlM, "\r"), KeyPress("l", "l")])
191
+
192
+ handled = tui._handle_normal_enter_key(buffer, event)
193
+
194
+ self.assertTrue(handled)
195
+ self.assertEqual(buffer.text, "line1\n")
196
+ self.assertTrue(tui._is_paste_guard_active())
197
+
198
+ def test_queued_newline_only_after_enter_does_not_arm_guard(self) -> None:
199
+ tui = _build_tui()
200
+ buffer = _FakeBuffer("hello")
201
+ event = _FakeEvent([KeyPress(Keys.ControlM, "\r")])
202
+
203
+ handled = tui._handle_normal_enter_key(buffer, event)
204
+
205
+ self.assertFalse(handled)
206
+ self.assertEqual(buffer.text, "hello")
207
+ self.assertFalse(tui._is_paste_guard_active())
208
+
209
+ def test_queued_non_text_input_after_enter_does_not_arm_guard(self) -> None:
210
+ tui = _build_tui()
211
+ buffer = _FakeBuffer("hello")
212
+ event = _FakeEvent([KeyPress(Keys.Up, "\x1b[A")])
213
+
214
+ handled = tui._handle_normal_enter_key(buffer, event)
215
+
216
+ self.assertFalse(handled)
217
+ self.assertEqual(buffer.text, "hello")
218
+ self.assertFalse(tui._is_paste_guard_active())
219
+
158
220
  def test_completion_menu_enter_is_not_intercepted_by_guard(self) -> None:
159
221
  tui = _build_tui()
160
222
  buffer = _FakeBuffer("/he")
File without changes
File without changes
File without changes
File without changes
File without changes