running-process 4.0.2__tar.gz → 4.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.
Files changed (178) hide show
  1. {running_process-4.0.2 → running_process-4.0.3}/Cargo.lock +2 -2
  2. {running_process-4.0.2 → running_process-4.0.3}/Cargo.toml +1 -1
  3. {running_process-4.0.2 → running_process-4.0.3}/PKG-INFO +17 -1
  4. {running_process-4.0.2 → running_process-4.0.3}/README.md +16 -0
  5. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/proto/daemon.proto +41 -0
  6. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/client/pty_session.rs +58 -24
  7. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/attach_stream.rs +8 -0
  8. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/pty_sessions_handlers.rs +21 -9
  9. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/pty_sessions.rs +26 -1
  10. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/lib.rs +9 -6
  11. running_process-4.0.3/crates/running-process/src/terminal_graphics.rs +725 -0
  12. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_non_tty_attach_test.rs +38 -2
  13. running_process-4.0.3/crates/running-process/tests/terminal_graphics_capabilities_test.rs +218 -0
  14. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/Cargo.toml +1 -1
  15. {running_process-4.0.2 → running_process-4.0.3}/pyproject.toml +1 -1
  16. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/__init__.py +1 -1
  17. {running_process-4.0.2 → running_process-4.0.3}/LICENSE +0 -0
  18. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/Cargo.toml +0 -0
  19. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/build.rs +0 -0
  20. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/bin/daemon.rs +0 -0
  21. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/bin/runpm.rs +0 -0
  22. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/bin/trampoline.rs +0 -0
  23. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/client/client.rs +0 -0
  24. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/client/mod.rs +0 -0
  25. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/client/paths.rs +0 -0
  26. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/client/pipe_session.rs +0 -0
  27. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/client/telemetry.rs +0 -0
  28. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/console_detect.rs +0 -0
  29. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/containment.rs +0 -0
  30. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/config.rs +0 -0
  31. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/core.rs +0 -0
  32. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/kill.rs +0 -0
  33. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/maintenance.rs +0 -0
  34. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/mod.rs +0 -0
  35. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/pipe_sessions_handlers.rs +0 -0
  36. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/process_tree.rs +0 -0
  37. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/registry_handlers.rs +0 -0
  38. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/services.rs +0 -0
  39. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/spawn.rs +0 -0
  40. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/telemetry.rs +0 -0
  41. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers/util.rs +0 -0
  42. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/handlers_tests.rs +0 -0
  43. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/idle.rs +0 -0
  44. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/mod.rs +0 -0
  45. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/pipe_attach_stream.rs +0 -0
  46. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/pipe_sessions.rs +0 -0
  47. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/platform/mod.rs +0 -0
  48. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/platform/unix.rs +0 -0
  49. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/platform/windows.rs +0 -0
  50. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/reaper.rs +0 -0
  51. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/registry.rs +0 -0
  52. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/runtime_gc.rs +0 -0
  53. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/server.rs +0 -0
  54. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/shadow.rs +0 -0
  55. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/daemon/telemetry.rs +0 -0
  56. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/helpers.rs +0 -0
  57. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/originator.rs +0 -0
  58. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/backend.rs +0 -0
  59. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/conpty_passthrough/child.rs +0 -0
  60. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/conpty_passthrough/mod.rs +0 -0
  61. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/conpty_passthrough/pipes.rs +0 -0
  62. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/conpty_passthrough/proc_thread_attr.rs +0 -0
  63. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/conpty_passthrough/pseudoconsole.rs +0 -0
  64. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/mod.rs +0 -0
  65. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/native_pty_process.rs +0 -0
  66. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/pty_posix.rs +0 -0
  67. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/pty_windows.rs +0 -0
  68. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/pty/terminal_input.rs +0 -0
  69. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/public_symbols.rs +0 -0
  70. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/rust_debug.rs +0 -0
  71. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/spawn.rs +0 -0
  72. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/spawn_imp_unix.rs +0 -0
  73. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/spawn_imp_windows.rs +0 -0
  74. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/tests.rs +0 -0
  75. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/types.rs +0 -0
  76. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/unix.rs +0 -0
  77. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/src/windows.rs +0 -0
  78. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/containment_test.rs +0 -0
  79. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_autostart_test.rs +0 -0
  80. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_backlog_accumulation_test.rs +0 -0
  81. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_cross_process_pty_attach_test.rs +0 -0
  82. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_fast_ctrl_c_handoff_test.rs +0 -0
  83. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_integration/compiler_wrap_seam_test.rs +0 -0
  84. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_integration/env_replace_test.rs +0 -0
  85. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_integration/main.rs +0 -0
  86. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_integration/more_tests.rs +0 -0
  87. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_integration/stdout_seam_test.rs +0 -0
  88. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_pipe_session_attach_test.rs +0 -0
  89. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_pty_session_attach_test.rs +0 -0
  90. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_resize_rpc_test.rs +0 -0
  91. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_runpm_service_stubs.rs +0 -0
  92. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_sessions_bulk_ops_test.rs +0 -0
  93. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_sessions_log_test.rs +0 -0
  94. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_tee_ring_test.rs +0 -0
  95. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_termination_outcome_test.rs +0 -0
  96. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_tree_kill_test.rs +0 -0
  97. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/daemon_tui_repaint_test.rs +0 -0
  98. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/fs_adversarial_test.rs +0 -0
  99. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/interactive_pty_session_test.rs +0 -0
  100. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/originator_test.rs +0 -0
  101. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/process_core_test.rs +0 -0
  102. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/pty_conhost_job_test.rs +0 -0
  103. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/pty_master_public_api_test.rs +0 -0
  104. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process/tests/spawn_test.rs +0 -0
  105. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/containment.rs +0 -0
  106. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/daemon_client.rs +0 -0
  107. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/debug_traces.rs +0 -0
  108. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/helpers.rs +0 -0
  109. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/idle_detector.rs +0 -0
  110. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/lib.rs +0 -0
  111. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/metrics.rs +0 -0
  112. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/originator.rs +0 -0
  113. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/pid_tracking.rs +0 -0
  114. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/priority.rs +0 -0
  115. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/process.rs +0 -0
  116. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/process_tree.rs +0 -0
  117. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/pty_buffer.rs +0 -0
  118. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/pty_process.rs +0 -0
  119. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/public_symbols.rs +0 -0
  120. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/py_native_process.rs +0 -0
  121. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/registry.rs +0 -0
  122. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/signal_bool.rs +0 -0
  123. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/terminal_input.rs +0 -0
  124. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/control_churn.rs +0 -0
  125. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/expect_match.rs +0 -0
  126. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/idle_detector.rs +0 -0
  127. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/mod.rs +0 -0
  128. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/parse_command.rs +0 -0
  129. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/process_tree.rs +0 -0
  130. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/pty_buffer.rs +0 -0
  131. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/pty_process.rs +0 -0
  132. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/registry.rs +0 -0
  133. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/signal_bool.rs +0 -0
  134. {running_process-4.0.2 → running_process-4.0.3}/crates/running-process-py/src/tests/terminal_input.rs +0 -0
  135. {running_process-4.0.2 → running_process-4.0.3}/crates/test-watchdog/Cargo.toml +0 -0
  136. {running_process-4.0.2 → running_process-4.0.3}/crates/test-watchdog/src/lib.rs +0 -0
  137. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/assets/example.txt +0 -0
  138. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/cli.py +0 -0
  139. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/command_render.py +0 -0
  140. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/compat.py +0 -0
  141. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/console_encoding.py +0 -0
  142. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/daemon.py +0 -0
  143. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/dashboard.py +0 -0
  144. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/exit_status.py +0 -0
  145. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/expect.py +0 -0
  146. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/interrupt_handler.py +0 -0
  147. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/launch.py +0 -0
  148. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/line_iterator.py +0 -0
  149. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/output_formatter.py +0 -0
  150. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/priority.py +0 -0
  151. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/process_utils.py +0 -0
  152. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/processor_cli.py +0 -0
  153. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/__init__.py +0 -0
  154. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_command.py +0 -0
  155. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_console_io.py +0 -0
  156. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_errors.py +0 -0
  157. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_idle_helpers.py +0 -0
  158. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_idle_state.py +0 -0
  159. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_interactive.py +0 -0
  160. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_process_helpers.py +0 -0
  161. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_pseudo_terminal.py +0 -0
  162. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_pty_expect.py +0 -0
  163. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_pty_idle_waiter.py +0 -0
  164. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_pty_input_relay.py +0 -0
  165. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_pty_reader.py +0 -0
  166. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_pty_wait_for.py +0 -0
  167. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_terminal_strip.py +0 -0
  168. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_types.py +0 -0
  169. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/pty/_wait_input.py +0 -0
  170. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/__init__.py +0 -0
  171. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_classmethod_api.py +0 -0
  172. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_core.py +0 -0
  173. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_helpers.py +0 -0
  174. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_iter.py +0 -0
  175. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_subprocess.py +0 -0
  176. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_types.py +0 -0
  177. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process/_wait_methods.py +0 -0
  178. {running_process-4.0.2 → running_process-4.0.3}/src/running_process/running_process_manager.py +0 -0
@@ -1026,7 +1026,7 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
1026
1026
 
1027
1027
  [[package]]
1028
1028
  name = "running-process"
1029
- version = "4.0.2"
1029
+ version = "4.0.3"
1030
1030
  dependencies = [
1031
1031
  "anyhow",
1032
1032
  "bytes",
@@ -1058,7 +1058,7 @@ dependencies = [
1058
1058
 
1059
1059
  [[package]]
1060
1060
  name = "running-process-py"
1061
- version = "4.0.2"
1061
+ version = "4.0.3"
1062
1062
  dependencies = [
1063
1063
  "interprocess",
1064
1064
  "libc",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/running-process", "crates/running-process-py", "crates/test-watchdog"]
4
4
 
5
5
  [workspace.package]
6
- version = "4.0.2"
6
+ version = "4.0.3"
7
7
  edition = "2021"
8
8
  rust-version = "1.85"
9
9
  license = "BSD-3-Clause"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: running_process
3
- Version: 4.0.2
3
+ Version: 4.0.3
4
4
  License-File: LICENSE
5
5
  Summary: A Rust-backed subprocess wrapper with split stdout/stderr streaming
6
6
  Home-Page: https://github.com/zackees/running-process
@@ -47,6 +47,22 @@ On those platforms, `RunningProcess.pseudo_terminal(...)`, `wait_for_expect(...)
47
47
 
48
48
  `Pty.is_available()` remains as a compatibility shim and only reports `False` on unsupported platforms.
49
49
 
50
+ ## Terminal Graphics Capabilities
51
+
52
+ Rust callers can inspect terminal graphics support with
53
+ `running_process::current_terminal_capabilities()` or the pure
54
+ `running_process::detect_terminal_capabilities(...)` helper. The result reports
55
+ Sixel, Kitty graphics, and iTerm2 `File=` image support as structured
56
+ capability records with `status`, `evidence`, `source`, and `risks` metadata.
57
+
58
+ The detector intentionally distinguishes terminal hosts from shells. `cmd.exe`,
59
+ PowerShell, Git Bash, bash, zsh, and fish are command interpreters; they do not
60
+ prove graphics support. The terminal host or multiplexer does: Windows
61
+ Terminal, xterm, foot, Konsole, WezTerm, Kitty, iTerm2, tmux, GNU screen, and
62
+ similar programs provide the relevant evidence. Weak aliases such as
63
+ `TERM=xterm-256color` are reported as unknown unless a live probe or stronger
64
+ host signal confirms support.
65
+
50
66
  ## CLI Helpers
51
67
 
52
68
  The package installs a `running-process` wrapper CLI for supervised command execution:
@@ -33,6 +33,22 @@ On those platforms, `RunningProcess.pseudo_terminal(...)`, `wait_for_expect(...)
33
33
 
34
34
  `Pty.is_available()` remains as a compatibility shim and only reports `False` on unsupported platforms.
35
35
 
36
+ ## Terminal Graphics Capabilities
37
+
38
+ Rust callers can inspect terminal graphics support with
39
+ `running_process::current_terminal_capabilities()` or the pure
40
+ `running_process::detect_terminal_capabilities(...)` helper. The result reports
41
+ Sixel, Kitty graphics, and iTerm2 `File=` image support as structured
42
+ capability records with `status`, `evidence`, `source`, and `risks` metadata.
43
+
44
+ The detector intentionally distinguishes terminal hosts from shells. `cmd.exe`,
45
+ PowerShell, Git Bash, bash, zsh, and fish are command interpreters; they do not
46
+ prove graphics support. The terminal host or multiplexer does: Windows
47
+ Terminal, xterm, foot, Konsole, WezTerm, Kitty, iTerm2, tmux, GNU screen, and
48
+ similar programs provide the relevant evidence. Weak aliases such as
49
+ `TERM=xterm-256color` are reported as unknown unless a live probe or stronger
50
+ host signal confirms support.
51
+
36
52
  ## CLI Helpers
37
53
 
38
54
  The package installs a `running-process` wrapper CLI for supervised command execution:
@@ -90,6 +90,30 @@ enum ProcessState {
90
90
  PROCESS_STATE_ZOMBIE = 3;
91
91
  }
92
92
 
93
+ enum GraphicsProtocol {
94
+ GRAPHICS_PROTOCOL_UNSPECIFIED = 0;
95
+ GRAPHICS_PROTOCOL_SIXEL = 1;
96
+ GRAPHICS_PROTOCOL_KITTY = 2;
97
+ GRAPHICS_PROTOCOL_ITERM2_FILE = 3;
98
+ }
99
+
100
+ enum CapabilityStatus {
101
+ CAPABILITY_STATUS_UNSPECIFIED = 0;
102
+ CAPABILITY_STATUS_SUPPORTED = 1;
103
+ CAPABILITY_STATUS_UNSUPPORTED = 2;
104
+ CAPABILITY_STATUS_UNKNOWN = 3;
105
+ CAPABILITY_STATUS_BLOCKED = 4;
106
+ }
107
+
108
+ enum EvidenceStrength {
109
+ EVIDENCE_STRENGTH_UNSPECIFIED = 0;
110
+ EVIDENCE_STRENGTH_PROBE = 1;
111
+ EVIDENCE_STRENGTH_STRONG_HOST_SIGNAL = 2;
112
+ EVIDENCE_STRENGTH_TERMINFO = 3;
113
+ EVIDENCE_STRENGTH_WEAK_ENV = 4;
114
+ EVIDENCE_STRENGTH_USER_OVERRIDE = 5;
115
+ }
116
+
93
117
  // ---------------------------------------------------------------------------
94
118
  // Envelope messages
95
119
  // ---------------------------------------------------------------------------
@@ -201,6 +225,19 @@ message KeyValue {
201
225
  string value = 2;
202
226
  }
203
227
 
228
+ message TerminalGraphicsCapability {
229
+ GraphicsProtocol protocol = 1;
230
+ CapabilityStatus status = 2;
231
+ EvidenceStrength evidence = 3;
232
+ string source = 4;
233
+ repeated string risks = 5;
234
+ }
235
+
236
+ message TerminalGraphicsCapabilities {
237
+ repeated TerminalGraphicsCapability protocols = 1;
238
+ GraphicsProtocol preferred = 2;
239
+ }
240
+
204
241
  message RegisterRequest {
205
242
  uint32 pid = 1;
206
243
  double created_at = 2;
@@ -494,6 +531,7 @@ message AttachPtySessionRequest {
494
531
  // Terminal capabilities for renegotiation; informational only for now.
495
532
  string term = 5;
496
533
  bool is_tty = 6;
534
+ TerminalGraphicsCapabilities graphics_capabilities = 7;
497
535
  }
498
536
 
499
537
  message AttachPtySessionResponse {
@@ -552,6 +590,9 @@ message PtySessionInfo {
552
590
  // child's environment (you cannot change a live child's TERM).
553
591
  // Empty when no client is attached.
554
592
  string attached_term = 15;
593
+ // Graphics capability metadata supplied by the currently attached
594
+ // client. Missing metadata from older clients is treated as unknown.
595
+ TerminalGraphicsCapabilities attached_graphics_capabilities = 16;
555
596
  }
556
597
 
557
598
  message TerminatePtySessionRequest {
@@ -10,17 +10,21 @@
10
10
  //! send/receive helpers suitable for tests and small clients. Async
11
11
  //! clients can build on top of [`DaemonClient::attach_pty_session_raw`].
12
12
 
13
- use crate::client::{ClientError, DaemonClient};
14
13
  use crate::client::paths;
15
- use interprocess::local_socket::Stream;
16
- use interprocess::TryClone;
17
- use prost::Message;
14
+ use crate::client::{ClientError, DaemonClient};
18
15
  use crate::proto::daemon::{
19
16
  pty_input_frame::Frame as InputOneof, AttachPtySessionRequest, AttachPtySessionResponse,
20
17
  DaemonRequest, DaemonResponse, DetachPtySessionRequest, KeyValue, ListPtySessionsRequest,
21
18
  ListPtySessionsResponse, PtyInputFrame, PtyResize, PtySessionInfo, PtyStreamFrame, RequestType,
22
19
  SpawnPtySessionRequest, SpawnPtySessionResponse, StatusCode, TerminatePtySessionRequest,
23
20
  };
21
+ use crate::terminal_graphics::{
22
+ current_terminal_capabilities, terminal_graphics_capabilities_to_proto, TerminalCapabilities,
23
+ TerminalGraphicsCapabilities,
24
+ };
25
+ use interprocess::local_socket::Stream;
26
+ use interprocess::TryClone;
27
+ use prost::Message;
24
28
  use std::io::{BufReader, BufWriter, Read, Write};
25
29
  use std::path::PathBuf;
26
30
  use std::time::Duration;
@@ -76,10 +80,7 @@ impl PtySpawnRequest {
76
80
  K: Into<String>,
77
81
  V: Into<String>,
78
82
  {
79
- self.env = env
80
- .into_iter()
81
- .map(|(k, v)| (k.into(), v.into()))
82
- .collect();
83
+ self.env = env.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
83
84
  self
84
85
  }
85
86
  }
@@ -131,10 +132,12 @@ impl DaemonClient {
131
132
  let response = self.send_request(daemon_request)?;
132
133
  ensure_ok(&response)?;
133
134
  let payload: SpawnPtySessionResponse =
134
- response.spawn_pty_session.ok_or_else(|| ClientError::Server {
135
- code: StatusCode::Internal,
136
- message: "spawn_pty_session response missing payload".into(),
137
- })?;
135
+ response
136
+ .spawn_pty_session
137
+ .ok_or_else(|| ClientError::Server {
138
+ code: StatusCode::Internal,
139
+ message: "spawn_pty_session response missing payload".into(),
140
+ })?;
138
141
  Ok(SpawnedPtySession {
139
142
  session_id: payload.session_id,
140
143
  pid: payload.pid,
@@ -160,12 +163,13 @@ impl DaemonClient {
160
163
  };
161
164
  let response = self.send_request(req)?;
162
165
  ensure_ok(&response)?;
163
- let payload: ListPtySessionsResponse = response
164
- .list_pty_sessions
165
- .ok_or_else(|| ClientError::Server {
166
- code: StatusCode::Internal,
167
- message: "list_pty_sessions response missing payload".into(),
168
- })?;
166
+ let payload: ListPtySessionsResponse =
167
+ response
168
+ .list_pty_sessions
169
+ .ok_or_else(|| ClientError::Server {
170
+ code: StatusCode::Internal,
171
+ message: "list_pty_sessions response missing payload".into(),
172
+ })?;
169
173
  Ok(payload.sessions)
170
174
  }
171
175
 
@@ -210,7 +214,6 @@ impl DaemonClient {
210
214
  ensure_ok(&response)?;
211
215
  Ok(())
212
216
  }
213
-
214
217
  }
215
218
 
216
219
  fn ensure_ok(response: &DaemonResponse) -> Result<(), ClientError> {
@@ -249,7 +252,10 @@ pub enum AttachError {
249
252
  Connect(std::io::Error),
250
253
  Io(std::io::Error),
251
254
  Decode(prost::DecodeError),
252
- Server { code: StatusCode, message: String },
255
+ Server {
256
+ code: StatusCode,
257
+ message: String,
258
+ },
253
259
  /// The daemon never sent an AttachPtySessionResponse payload.
254
260
  MissingPayload,
255
261
  }
@@ -290,6 +296,32 @@ impl PtyAttachment {
290
296
  rows: u16,
291
297
  cols: u16,
292
298
  steal: bool,
299
+ ) -> Result<Self, AttachError> {
300
+ let mut terminal_capabilities = current_terminal_capabilities();
301
+ if !terminal_capabilities.is_tty {
302
+ terminal_capabilities.is_tty = true;
303
+ terminal_capabilities.graphics = TerminalGraphicsCapabilities::unknown();
304
+ }
305
+ Self::attach_to_with_terminal_capabilities(
306
+ socket_path,
307
+ session_id,
308
+ rows,
309
+ cols,
310
+ steal,
311
+ terminal_capabilities,
312
+ )
313
+ }
314
+
315
+ /// Attach with explicit terminal metadata. This is useful for tests,
316
+ /// non-interactive attach clients, and callers that already performed
317
+ /// capability probing before opening the daemon socket.
318
+ pub fn attach_to_with_terminal_capabilities(
319
+ socket_path: &str,
320
+ session_id: &str,
321
+ rows: u16,
322
+ cols: u16,
323
+ steal: bool,
324
+ terminal_capabilities: TerminalCapabilities,
293
325
  ) -> Result<Self, AttachError> {
294
326
  let name = paths::make_socket_name(socket_path).map_err(AttachError::Connect)?;
295
327
  use interprocess::local_socket::traits::Stream as _;
@@ -309,8 +341,11 @@ impl PtyAttachment {
309
341
  rows: rows as u32,
310
342
  cols: cols as u32,
311
343
  steal,
312
- term: std::env::var("TERM").unwrap_or_default(),
313
- is_tty: true,
344
+ term: terminal_capabilities.term.unwrap_or_default(),
345
+ is_tty: terminal_capabilities.is_tty,
346
+ graphics_capabilities: Some(terminal_graphics_capabilities_to_proto(
347
+ &terminal_capabilities.graphics,
348
+ )),
314
349
  }),
315
350
  ..Default::default()
316
351
  };
@@ -319,8 +354,7 @@ impl PtyAttachment {
319
354
 
320
355
  // Read the initial response.
321
356
  let response_bytes = read_length_prefixed(&mut reader).map_err(AttachError::Io)?;
322
- let response =
323
- DaemonResponse::decode(&response_bytes[..]).map_err(AttachError::Decode)?;
357
+ let response = DaemonResponse::decode(&response_bytes[..]).map_err(AttachError::Decode)?;
324
358
  if response.code != StatusCode::Ok as i32 {
325
359
  let code = StatusCode::try_from(response.code).unwrap_or(StatusCode::UnknownRequest);
326
360
  return Err(AttachError::Server {
@@ -25,6 +25,9 @@ use crate::proto::daemon::{
25
25
 
26
26
  use crate::daemon::handlers::DaemonState;
27
27
  use crate::daemon::pty_sessions::{AttachError, AttachmentEnded, OutboundFrame};
28
+ use crate::terminal_graphics::{
29
+ terminal_graphics_capabilities_from_proto, TerminalGraphicsCapabilities,
30
+ };
28
31
 
29
32
  /// Drive the attach stream for the lifetime of one client connection.
30
33
  ///
@@ -73,6 +76,11 @@ where
73
76
  cols,
74
77
  attach_req.is_tty,
75
78
  attach_req.term.clone(),
79
+ attach_req
80
+ .graphics_capabilities
81
+ .as_ref()
82
+ .map(terminal_graphics_capabilities_from_proto)
83
+ .unwrap_or_else(TerminalGraphicsCapabilities::unknown),
76
84
  ) {
77
85
  Ok(h) => h,
78
86
  Err(AttachError::AlreadyAttached) => {
@@ -11,6 +11,7 @@ use crate::proto::daemon::{
11
11
  ListPtySessionsResponse, PtySessionInfo, ResizePtySessionResponse, SpawnPtySessionResponse,
12
12
  StatusCode, TerminatePtySessionResponse,
13
13
  };
14
+ use crate::terminal_graphics::terminal_graphics_capabilities_to_proto;
14
15
 
15
16
  use super::util::{error_pty_response, termination_outcome_to_proto};
16
17
  use super::DaemonState;
@@ -167,6 +168,9 @@ pub fn handle_list_pty_sessions(request: &DaemonRequest, state: &DaemonState) ->
167
168
  termination_outcome: termination_outcome_to_proto(outcome) as i32,
168
169
  attached_is_tty: session.attached_is_tty(),
169
170
  attached_term: session.attached_term(),
171
+ attached_graphics_capabilities: Some(terminal_graphics_capabilities_to_proto(
172
+ &session.attached_graphics_capabilities(),
173
+ )),
170
174
  });
171
175
  }
172
176
 
@@ -208,7 +212,11 @@ pub fn handle_terminate_pty_session(
208
212
  // M4 will turn this into a configurable soft-then-hard schedule.
209
213
  // For M2 we issue an immediate terminate and let the reader thread
210
214
  // observe the exit + record exit state.
211
- let grace_ms = if req.grace_ms == 0 { 2000 } else { req.grace_ms };
215
+ let grace_ms = if req.grace_ms == 0 {
216
+ 2000
217
+ } else {
218
+ req.grace_ms
219
+ };
212
220
  if let Err(e) = session.terminate(std::time::Duration::from_millis(grace_ms as u64)) {
213
221
  return error_pty_response(request.id, StatusCode::Internal, e.to_string());
214
222
  }
@@ -237,8 +245,7 @@ pub fn handle_attach_pty_session(request: &DaemonRequest, _state: &DaemonState)
237
245
  DaemonResponse {
238
246
  request_id: request.id,
239
247
  code: StatusCode::Internal as i32,
240
- message: "attach_pty_session must be intercepted by the streaming server path"
241
- .into(),
248
+ message: "attach_pty_session must be intercepted by the streaming server path".into(),
242
249
  attach_pty_session: Some(AttachPtySessionResponse::default()),
243
250
  ..Default::default()
244
251
  }
@@ -248,10 +255,7 @@ pub fn handle_attach_pty_session(request: &DaemonRequest, _state: &DaemonState)
248
255
  /// follow-up). The new size persists for the lifetime of the session
249
256
  /// and overrides any per-attach size passed by future attach requests
250
257
  /// (they can still override it again by sending their own rows/cols).
251
- pub fn handle_resize_pty_session(
252
- request: &DaemonRequest,
253
- state: &DaemonState,
254
- ) -> DaemonResponse {
258
+ pub fn handle_resize_pty_session(request: &DaemonRequest, state: &DaemonState) -> DaemonResponse {
255
259
  let req = match request.resize_pty_session.as_ref() {
256
260
  Some(r) => r,
257
261
  None => {
@@ -272,8 +276,16 @@ pub fn handle_resize_pty_session(
272
276
  )
273
277
  }
274
278
  };
275
- let rows = if req.rows == 0 { session.rows() } else { req.rows as u16 };
276
- let cols = if req.cols == 0 { session.cols() } else { req.cols as u16 };
279
+ let rows = if req.rows == 0 {
280
+ session.rows()
281
+ } else {
282
+ req.rows as u16
283
+ };
284
+ let cols = if req.cols == 0 {
285
+ session.cols()
286
+ } else {
287
+ req.cols as u16
288
+ };
277
289
  if let Err(e) = session.resize(rows, cols) {
278
290
  return error_pty_response(request.id, StatusCode::Internal, e.to_string());
279
291
  }
@@ -25,6 +25,7 @@ use std::thread;
25
25
  use std::time::{Duration, SystemTime, UNIX_EPOCH};
26
26
 
27
27
  use crate::pty::NativePtyProcess;
28
+ use crate::terminal_graphics::TerminalGraphicsCapabilities;
28
29
  use tokio::sync::mpsc;
29
30
  use tracing::{debug, warn};
30
31
 
@@ -154,6 +155,9 @@ struct AttachedClient {
154
155
  /// Client-supplied TERM value. Recorded for the session's lifetime
155
156
  /// so list/snapshot can surface it.
156
157
  term: String,
158
+ /// Client-supplied terminal graphics capability metadata. Missing
159
+ /// metadata from older clients is represented as unknown.
160
+ graphics_capabilities: TerminalGraphicsCapabilities,
157
161
  }
158
162
 
159
163
  /// Final state once the child exits.
@@ -395,6 +399,18 @@ impl OwnedPtySession {
395
399
  .unwrap_or_default()
396
400
  }
397
401
 
402
+ /// Graphics capability metadata supplied by the currently attached
403
+ /// client. Missing metadata from older clients is represented as
404
+ /// unknown rather than inferred from daemon environment.
405
+ pub fn attached_graphics_capabilities(&self) -> TerminalGraphicsCapabilities {
406
+ self.attached
407
+ .lock()
408
+ .unwrap()
409
+ .as_ref()
410
+ .map(|c| c.graphics_capabilities.clone())
411
+ .unwrap_or_else(TerminalGraphicsCapabilities::unknown)
412
+ }
413
+
398
414
  /// Install an attached client. Returns the receiver half + a snapshot of
399
415
  /// the current backlog (with the cumulative bytes-dropped counter).
400
416
  ///
@@ -408,7 +424,14 @@ impl OwnedPtySession {
408
424
  rows: u16,
409
425
  cols: u16,
410
426
  ) -> Result<(AttachmentHandle, Vec<u8>, u64), AttachError> {
411
- self.attach_with_terminal_info(steal, rows, cols, true, String::new())
427
+ self.attach_with_terminal_info(
428
+ steal,
429
+ rows,
430
+ cols,
431
+ true,
432
+ String::new(),
433
+ TerminalGraphicsCapabilities::unknown(),
434
+ )
412
435
  }
413
436
 
414
437
  /// Like [`Self::attach`] but lets the caller record whether the
@@ -422,6 +445,7 @@ impl OwnedPtySession {
422
445
  cols: u16,
423
446
  is_tty: bool,
424
447
  term: String,
448
+ graphics_capabilities: TerminalGraphicsCapabilities,
425
449
  ) -> Result<(AttachmentHandle, Vec<u8>, u64), AttachError> {
426
450
  // If the session has already exited, surface that immediately rather
427
451
  // than handing out an attachment for a corpse.
@@ -461,6 +485,7 @@ impl OwnedPtySession {
461
485
  sender: tx,
462
486
  is_tty,
463
487
  term,
488
+ graphics_capabilities,
464
489
  });
465
490
  Ok((AttachmentHandle { receiver: rx }, backlog, dropped))
466
491
  }
@@ -39,6 +39,7 @@ pub mod pty;
39
39
  mod public_symbols;
40
40
  mod rust_debug;
41
41
  pub mod spawn;
42
+ pub mod terminal_graphics;
42
43
  mod types;
43
44
  #[cfg(unix)]
44
45
  mod unix;
@@ -54,6 +55,12 @@ pub use spawn::{
54
55
  spawn, spawn_daemon, spawn_daemon_with_clear_env, DaemonChild, SpawnStdio, SpawnedChild,
55
56
  StdioSource,
56
57
  };
58
+ pub use terminal_graphics::{
59
+ current_terminal_capabilities, current_terminal_capabilities_with_timeout,
60
+ detect_terminal_capabilities, CapabilityStatus, EvidenceStrength, GraphicsCapability,
61
+ GraphicsProtocol, TerminalCapabilities, TerminalCapabilityInput, TerminalGraphicsCapabilities,
62
+ TerminalProbeEvidence,
63
+ };
57
64
  pub use types::{
58
65
  CommandSpec, ProcessConfig, ProcessError, ReadStatus, RunOutput, StderrMode, StdinMode,
59
66
  StreamEvent, StreamKind,
@@ -877,9 +884,7 @@ impl NativeProcess {
877
884
  fn pipe_done_callback(&self, stream: StreamKind) -> Box<dyn FnOnce() + Send> {
878
885
  let handles = Arc::clone(&self.capture_pipe_handles);
879
886
  Box::new(move || {
880
- let mut guard = handles
881
- .lock()
882
- .expect("capture pipe handles mutex poisoned");
887
+ let mut guard = handles.lock().expect("capture pipe handles mutex poisoned");
883
888
  match stream {
884
889
  StreamKind::Stdout => guard.stdout = None,
885
890
  StreamKind::Stderr => guard.stderr = None,
@@ -930,9 +935,7 @@ impl NativeProcess {
930
935
  }
931
936
 
932
937
  fn wait_for_capture_completion_impl(&self) {
933
- crate::rp_rust_debug_scope!(
934
- "running_process::NativeProcess::wait_for_capture_completion"
935
- );
938
+ crate::rp_rust_debug_scope!("running_process::NativeProcess::wait_for_capture_completion");
936
939
  if !self.config.capture {
937
940
  return;
938
941
  }