running-process 4.0.1__tar.gz → 4.0.2__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.
- {running_process-4.0.1 → running_process-4.0.2}/Cargo.lock +2 -2
- {running_process-4.0.1 → running_process-4.0.2}/Cargo.toml +1 -1
- {running_process-4.0.1 → running_process-4.0.2}/PKG-INFO +28 -7
- {running_process-4.0.1 → running_process-4.0.2}/README.md +27 -6
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/Cargo.toml +4 -2
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/proto/daemon.proto +83 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/client/mod.rs +6 -0
- running_process-4.0.2/crates/running-process/src/client/telemetry.rs +264 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/containment.rs +2 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/attach_stream.rs +67 -6
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/mod.rs +4 -0
- running_process-4.0.2/crates/running-process/src/daemon/handlers/telemetry.rs +403 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers_tests.rs +193 -2
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/mod.rs +1 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/pipe_attach_stream.rs +67 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/pipe_sessions.rs +222 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/pty_sessions.rs +158 -1
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/runtime_gc.rs +97 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/server.rs +12 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/shadow.rs +73 -0
- running_process-4.0.2/crates/running-process/src/daemon/telemetry.rs +937 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/lib.rs +77 -2
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/backend.rs +1 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/conpty_passthrough/mod.rs +3 -3
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/mod.rs +1 -1
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/native_pty_process.rs +3 -1
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/types.rs +10 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_pipe_session_attach_test.rs +75 -0
- running_process-4.0.2/crates/running-process/tests/daemon_tee_ring_test.rs +337 -0
- running_process-4.0.2/crates/running-process/tests/interactive_pty_session_test.rs +171 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/originator_test.rs +9 -7
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/process_core_test.rs +79 -2
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/pty_master_public_api_test.rs +1 -1
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/Cargo.toml +1 -1
- {running_process-4.0.1 → running_process-4.0.2}/pyproject.toml +1 -1
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/__init__.py +1 -1
- {running_process-4.0.1 → running_process-4.0.2}/LICENSE +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/build.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/bin/daemon.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/bin/runpm.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/bin/trampoline.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/client/client.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/client/paths.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/client/pipe_session.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/client/pty_session.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/console_detect.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/config.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/core.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/kill.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/maintenance.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/pipe_sessions_handlers.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/process_tree.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/pty_sessions_handlers.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/registry_handlers.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/services.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/spawn.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/util.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/idle.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/platform/mod.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/platform/unix.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/platform/windows.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/reaper.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/registry.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/helpers.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/originator.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/conpty_passthrough/child.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/conpty_passthrough/pipes.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/conpty_passthrough/proc_thread_attr.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/conpty_passthrough/pseudoconsole.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/pty_posix.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/pty_windows.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/pty/terminal_input.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/public_symbols.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/rust_debug.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/spawn.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/spawn_imp_unix.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/spawn_imp_windows.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/tests.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/unix.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/windows.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/containment_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_autostart_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_backlog_accumulation_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_cross_process_pty_attach_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_fast_ctrl_c_handoff_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_integration/compiler_wrap_seam_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_integration/env_replace_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_integration/main.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_integration/more_tests.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_integration/stdout_seam_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_non_tty_attach_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_pty_session_attach_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_resize_rpc_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_runpm_service_stubs.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_sessions_bulk_ops_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_sessions_log_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_termination_outcome_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_tree_kill_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/daemon_tui_repaint_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/fs_adversarial_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/pty_conhost_job_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process/tests/spawn_test.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/containment.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/daemon_client.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/debug_traces.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/helpers.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/idle_detector.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/lib.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/metrics.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/originator.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/pid_tracking.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/priority.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/process.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/process_tree.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/pty_buffer.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/pty_process.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/public_symbols.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/py_native_process.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/registry.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/signal_bool.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/terminal_input.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/control_churn.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/expect_match.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/idle_detector.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/mod.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/parse_command.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/process_tree.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/pty_buffer.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/pty_process.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/registry.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/signal_bool.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/running-process-py/src/tests/terminal_input.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/test-watchdog/Cargo.toml +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/crates/test-watchdog/src/lib.rs +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/assets/example.txt +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/cli.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/command_render.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/compat.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/console_encoding.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/daemon.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/dashboard.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/exit_status.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/expect.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/interrupt_handler.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/launch.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/line_iterator.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/output_formatter.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/priority.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/process_utils.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/processor_cli.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/__init__.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_command.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_console_io.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_errors.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_idle_helpers.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_idle_state.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_interactive.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_process_helpers.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_pseudo_terminal.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_pty_expect.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_pty_idle_waiter.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_pty_input_relay.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_pty_reader.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_pty_wait_for.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_terminal_strip.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_types.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/pty/_wait_input.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/__init__.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_classmethod_api.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_core.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_helpers.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_iter.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_subprocess.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_types.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/src/running_process/running_process/_wait_methods.py +0 -0
- {running_process-4.0.1 → running_process-4.0.2}/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.
|
|
1029
|
+
version = "4.0.2"
|
|
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.
|
|
1061
|
+
version = "4.0.2"
|
|
1062
1062
|
dependencies = [
|
|
1063
1063
|
"interprocess",
|
|
1064
1064
|
"libc",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: running_process
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.2
|
|
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
|
|
@@ -200,6 +200,11 @@ PTY behavior:
|
|
|
200
200
|
|
|
201
201
|
There is also a compatibility alias: `RunningProcess.psuedo_terminal(...)`.
|
|
202
202
|
|
|
203
|
+
Rust consumers should make the same transport choice explicitly: use
|
|
204
|
+
`NativeProcess` for one-shot noninteractive work and
|
|
205
|
+
`InteractivePtySession` / `NativePtyProcess` only for real terminal sessions.
|
|
206
|
+
See [Rust PTY guidance](docs/RUST_PTY.md).
|
|
207
|
+
|
|
203
208
|
You can also inspect the intended interactive launch semantics without launching a child:
|
|
204
209
|
|
|
205
210
|
```python
|
|
@@ -283,7 +288,7 @@ PTY mode is intentionally more conservative:
|
|
|
283
288
|
./test
|
|
284
289
|
```
|
|
285
290
|
|
|
286
|
-
`./install` bootstraps `rustup` into the shared user locations (`~/.cargo` and `~/.rustup`, or `CARGO_HOME` / `RUSTUP_HOME` if you override them), then installs the exact toolchain pinned in `rust-toolchain.toml`. Toolchain installs are serialized with a lock so concurrent repo bootstraps do not race the same shared version.
|
|
291
|
+
`./install` bootstraps `rustup` into the shared user locations (`~/.cargo` and `~/.rustup`, or `CARGO_HOME` / `RUSTUP_HOME` if you override them), then installs the exact toolchain pinned in `rust-toolchain.toml`. Toolchain installs are serialized with a lock so concurrent repo bootstraps do not race the same shared version. Rust build commands run through `uvx soldr`, so there is no separate `soldr` install step to maintain.
|
|
287
292
|
|
|
288
293
|
`./lint` applies `cargo fmt` and Ruff autofixes before running the remaining lint checks, so fixable issues are rewritten in place.
|
|
289
294
|
|
|
@@ -291,16 +296,32 @@ PTY mode is intentionally more conservative:
|
|
|
291
296
|
|
|
292
297
|
On local developer machines, `./test` also runs the Linux Docker preflight so Windows and macOS development catches Linux wheel, lint, and non-live pytest regressions before push. GitHub-hosted Actions skip that Docker-only preflight and run the native platform suite directly.
|
|
293
298
|
|
|
294
|
-
|
|
299
|
+
For a live-only test run with the timeout crash watchdog and automatic thread
|
|
300
|
+
dumps still enabled, use:
|
|
295
301
|
|
|
296
|
-
|
|
302
|
+
```bash
|
|
303
|
+
uv run -m ci.test --live-only
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
For a narrower live-only selection, pass pytest targets and selectors through
|
|
307
|
+
the same entrypoint:
|
|
297
308
|
|
|
298
309
|
```bash
|
|
299
|
-
|
|
300
|
-
./_cargo fmt --all --check
|
|
301
|
-
./_cargo clippy --workspace --all-targets -- -D warnings
|
|
310
|
+
uv run -m ci.test --live-only tests/test_pty_support.py interrupt
|
|
302
311
|
```
|
|
303
312
|
|
|
313
|
+
For direct Cargo build commands, use `uvx soldr` directly:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
uvx soldr cargo check --workspace
|
|
317
|
+
uvx soldr cargo test --workspace
|
|
318
|
+
uvx soldr cargo package -p running-process --no-verify
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Keep `maturin`, `cargo fmt`, and `cargo clippy` on their normal entrypoints.
|
|
322
|
+
This repo's high-level scripts already choose the compatible path for those
|
|
323
|
+
tools.
|
|
324
|
+
|
|
304
325
|
On Windows, native rebuilds that compile bundled C code should run from a Visual Studio developer shell. When the environment is ambiguous, point `maturin` at the MSVC toolchain binaries directly rather than relying on the generic cargo proxy.
|
|
305
326
|
|
|
306
327
|
For local extension rebuilds, prefer:
|
|
@@ -186,6 +186,11 @@ PTY behavior:
|
|
|
186
186
|
|
|
187
187
|
There is also a compatibility alias: `RunningProcess.psuedo_terminal(...)`.
|
|
188
188
|
|
|
189
|
+
Rust consumers should make the same transport choice explicitly: use
|
|
190
|
+
`NativeProcess` for one-shot noninteractive work and
|
|
191
|
+
`InteractivePtySession` / `NativePtyProcess` only for real terminal sessions.
|
|
192
|
+
See [Rust PTY guidance](docs/RUST_PTY.md).
|
|
193
|
+
|
|
189
194
|
You can also inspect the intended interactive launch semantics without launching a child:
|
|
190
195
|
|
|
191
196
|
```python
|
|
@@ -269,7 +274,7 @@ PTY mode is intentionally more conservative:
|
|
|
269
274
|
./test
|
|
270
275
|
```
|
|
271
276
|
|
|
272
|
-
`./install` bootstraps `rustup` into the shared user locations (`~/.cargo` and `~/.rustup`, or `CARGO_HOME` / `RUSTUP_HOME` if you override them), then installs the exact toolchain pinned in `rust-toolchain.toml`. Toolchain installs are serialized with a lock so concurrent repo bootstraps do not race the same shared version.
|
|
277
|
+
`./install` bootstraps `rustup` into the shared user locations (`~/.cargo` and `~/.rustup`, or `CARGO_HOME` / `RUSTUP_HOME` if you override them), then installs the exact toolchain pinned in `rust-toolchain.toml`. Toolchain installs are serialized with a lock so concurrent repo bootstraps do not race the same shared version. Rust build commands run through `uvx soldr`, so there is no separate `soldr` install step to maintain.
|
|
273
278
|
|
|
274
279
|
`./lint` applies `cargo fmt` and Ruff autofixes before running the remaining lint checks, so fixable issues are rewritten in place.
|
|
275
280
|
|
|
@@ -277,16 +282,32 @@ PTY mode is intentionally more conservative:
|
|
|
277
282
|
|
|
278
283
|
On local developer machines, `./test` also runs the Linux Docker preflight so Windows and macOS development catches Linux wheel, lint, and non-live pytest regressions before push. GitHub-hosted Actions skip that Docker-only preflight and run the native platform suite directly.
|
|
279
284
|
|
|
280
|
-
|
|
285
|
+
For a live-only test run with the timeout crash watchdog and automatic thread
|
|
286
|
+
dumps still enabled, use:
|
|
281
287
|
|
|
282
|
-
|
|
288
|
+
```bash
|
|
289
|
+
uv run -m ci.test --live-only
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
For a narrower live-only selection, pass pytest targets and selectors through
|
|
293
|
+
the same entrypoint:
|
|
283
294
|
|
|
284
295
|
```bash
|
|
285
|
-
|
|
286
|
-
./_cargo fmt --all --check
|
|
287
|
-
./_cargo clippy --workspace --all-targets -- -D warnings
|
|
296
|
+
uv run -m ci.test --live-only tests/test_pty_support.py interrupt
|
|
288
297
|
```
|
|
289
298
|
|
|
299
|
+
For direct Cargo build commands, use `uvx soldr` directly:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
uvx soldr cargo check --workspace
|
|
303
|
+
uvx soldr cargo test --workspace
|
|
304
|
+
uvx soldr cargo package -p running-process --no-verify
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Keep `maturin`, `cargo fmt`, and `cargo clippy` on their normal entrypoints.
|
|
308
|
+
This repo's high-level scripts already choose the compatible path for those
|
|
309
|
+
tools.
|
|
310
|
+
|
|
290
311
|
On Windows, native rebuilds that compile bundled C code should run from a Visual Studio developer shell. When the environment is ambiguous, point `maturin` at the MSVC toolchain binaries directly rather than relying on the generic cargo proxy.
|
|
291
312
|
|
|
292
313
|
For local extension rebuilds, prefer:
|
|
@@ -35,13 +35,15 @@ path = "src/bin/trampoline.rs"
|
|
|
35
35
|
# Final feature scheme per #165:
|
|
36
36
|
# * `core` — always-available API (spawn / pty / containment).
|
|
37
37
|
# * `client` — adds proto types + IPC client (prost, interprocess, dirs).
|
|
38
|
-
# * `
|
|
39
|
-
#
|
|
38
|
+
# * `telemetry` — tee sink primitives without the full daemon runtime.
|
|
39
|
+
# * `daemon` — superset of client; adds the full daemon runtime
|
|
40
|
+
# (tokio, rusqlite, tracing, etc.).
|
|
40
41
|
# Default ships `client` so `cargo install running-process` installs
|
|
41
42
|
# the `runpm` binary out of the box (per Q1 resolution in #165:
|
|
42
43
|
# `required-features` are not auto-activated by cargo install).
|
|
43
44
|
default = ["client"]
|
|
44
45
|
core = []
|
|
46
|
+
telemetry = []
|
|
45
47
|
client = ["dep:prost", "dep:prost-types", "dep:interprocess", "dep:dirs", "dep:anyhow", "dep:clap"]
|
|
46
48
|
daemon = [
|
|
47
49
|
"client",
|
|
@@ -63,6 +63,10 @@ enum RequestType {
|
|
|
63
63
|
REQUEST_TYPE_BULK_TERMINATE_SESSIONS = 73;
|
|
64
64
|
// Resize a PTY session without attaching (#130 M5 follow-up).
|
|
65
65
|
REQUEST_TYPE_RESIZE_PTY_SESSION = 74;
|
|
66
|
+
// Optional daemon-owned tee telemetry (#131).
|
|
67
|
+
REQUEST_TYPE_REGISTER_SESSION_TEE = 75;
|
|
68
|
+
REQUEST_TYPE_UNREGISTER_SESSION_TEE = 76;
|
|
69
|
+
REQUEST_TYPE_GET_SESSION_TEE_STATUS = 77;
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
enum StatusCode {
|
|
@@ -133,6 +137,9 @@ message DaemonRequest {
|
|
|
133
137
|
PurgeExitedSessionsRequest purge_exited_sessions = 72;
|
|
134
138
|
BulkTerminateSessionsRequest bulk_terminate_sessions = 73;
|
|
135
139
|
ResizePtySessionRequest resize_pty_session = 74;
|
|
140
|
+
RegisterSessionTeeRequest register_session_tee = 75;
|
|
141
|
+
UnregisterSessionTeeRequest unregister_session_tee = 76;
|
|
142
|
+
GetSessionTeeStatusRequest get_session_tee_status = 77;
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
message DaemonResponse {
|
|
@@ -177,6 +184,9 @@ message DaemonResponse {
|
|
|
177
184
|
PurgeExitedSessionsResponse purge_exited_sessions = 72;
|
|
178
185
|
BulkTerminateSessionsResponse bulk_terminate_sessions = 73;
|
|
179
186
|
ResizePtySessionResponse resize_pty_session = 74;
|
|
187
|
+
RegisterSessionTeeResponse register_session_tee = 75;
|
|
188
|
+
UnregisterSessionTeeResponse unregister_session_tee = 76;
|
|
189
|
+
GetSessionTeeStatusResponse get_session_tee_status = 77;
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
// ---------------------------------------------------------------------------
|
|
@@ -763,6 +773,79 @@ message ResizePtySessionRequest {
|
|
|
763
773
|
}
|
|
764
774
|
message ResizePtySessionResponse {}
|
|
765
775
|
|
|
776
|
+
// ---------------------------------------------------------------------------
|
|
777
|
+
// Optional session tee telemetry (#131).
|
|
778
|
+
// ---------------------------------------------------------------------------
|
|
779
|
+
|
|
780
|
+
enum TeeSessionKind {
|
|
781
|
+
TEE_SESSION_KIND_UNSPECIFIED = 0;
|
|
782
|
+
TEE_SESSION_KIND_PTY = 1;
|
|
783
|
+
TEE_SESSION_KIND_PIPE = 2;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
enum TeeStreamKind {
|
|
787
|
+
TEE_STREAM_KIND_UNSPECIFIED = 0;
|
|
788
|
+
TEE_STREAM_KIND_PTY_OUTPUT = 1;
|
|
789
|
+
TEE_STREAM_KIND_STDOUT = 2;
|
|
790
|
+
TEE_STREAM_KIND_STDERR = 3;
|
|
791
|
+
TEE_STREAM_KIND_STDIN = 4;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
enum TeeSinkKind {
|
|
795
|
+
TEE_SINK_KIND_UNSPECIFIED = 0;
|
|
796
|
+
// Daemon opens the path and owns the file descriptor until the tee is
|
|
797
|
+
// removed or the session ends. Path bytes are OS-native, not UTF-8.
|
|
798
|
+
TEE_SINK_KIND_FILE = 1;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
enum TeeFileMode {
|
|
802
|
+
TEE_FILE_MODE_APPEND = 0;
|
|
803
|
+
TEE_FILE_MODE_TRUNCATE = 1;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
enum TeeBackpressure {
|
|
807
|
+
TEE_BACKPRESSURE_DROP_OLDEST = 0;
|
|
808
|
+
TEE_BACKPRESSURE_BLOCK = 1;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
message RegisterSessionTeeRequest {
|
|
812
|
+
string session_id = 1;
|
|
813
|
+
TeeSessionKind session_kind = 2;
|
|
814
|
+
TeeStreamKind stream = 3;
|
|
815
|
+
TeeSinkKind sink_kind = 4;
|
|
816
|
+
// OS-native path bytes: Unix = OsStr bytes; Windows = little-endian UTF-16.
|
|
817
|
+
bytes file_path = 5;
|
|
818
|
+
TeeFileMode file_mode = 6;
|
|
819
|
+
// 0 means use the daemon default.
|
|
820
|
+
uint32 queue_capacity = 7;
|
|
821
|
+
// false means write missed-byte markers, matching the Rust default.
|
|
822
|
+
bool suppress_missed_markers = 8;
|
|
823
|
+
TeeBackpressure backpressure = 9;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
message RegisterSessionTeeResponse {
|
|
827
|
+
uint64 tee_handle = 1;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
message UnregisterSessionTeeRequest {
|
|
831
|
+
string session_id = 1;
|
|
832
|
+
TeeSessionKind session_kind = 2;
|
|
833
|
+
uint64 tee_handle = 3;
|
|
834
|
+
}
|
|
835
|
+
message UnregisterSessionTeeResponse {}
|
|
836
|
+
|
|
837
|
+
message GetSessionTeeStatusRequest {
|
|
838
|
+
string session_id = 1;
|
|
839
|
+
TeeSessionKind session_kind = 2;
|
|
840
|
+
uint64 tee_handle = 3;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
message GetSessionTeeStatusResponse {
|
|
844
|
+
TeeStreamKind stream = 1;
|
|
845
|
+
uint64 missed_bytes = 2;
|
|
846
|
+
bool disconnected = 3;
|
|
847
|
+
}
|
|
848
|
+
|
|
766
849
|
// Daemon -> client stream frame for an attached stdout/stderr.
|
|
767
850
|
message PipeStreamFrame {
|
|
768
851
|
oneof frame {
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
//! previously imported from `running_process_client::*` keeps working
|
|
6
6
|
//! when it switches to `running_process::client::*`.
|
|
7
7
|
|
|
8
|
+
#[allow(clippy::module_inception)]
|
|
8
9
|
pub mod client;
|
|
9
10
|
pub mod paths;
|
|
10
11
|
pub mod pipe_session;
|
|
11
12
|
pub mod pty_session;
|
|
13
|
+
pub mod telemetry;
|
|
12
14
|
|
|
13
15
|
pub use client::{
|
|
14
16
|
connect_or_start, daemonize_command, launch_detached, ClientError, DaemonClient,
|
|
@@ -16,3 +18,7 @@ pub use client::{
|
|
|
16
18
|
};
|
|
17
19
|
pub use pipe_session::{PipeSpawnRequest, PipeStreamAttachment, SpawnedPipeSession};
|
|
18
20
|
pub use pty_session::{AttachError, PtyAttachment, PtySpawnRequest, SpawnedPtySession};
|
|
21
|
+
pub use telemetry::{
|
|
22
|
+
SessionTeeBackpressure, SessionTeeFileMode, SessionTeeFileRequest, SessionTeeKind,
|
|
23
|
+
SessionTeeStatus, SessionTeeStream,
|
|
24
|
+
};
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
//! Client helpers for daemon-owned session tee telemetry.
|
|
2
|
+
|
|
3
|
+
use std::path::{Path, PathBuf};
|
|
4
|
+
|
|
5
|
+
#[cfg(unix)]
|
|
6
|
+
use std::os::unix::ffi::OsStrExt;
|
|
7
|
+
#[cfg(windows)]
|
|
8
|
+
use std::os::windows::ffi::OsStrExt;
|
|
9
|
+
|
|
10
|
+
use crate::client::{ClientError, DaemonClient};
|
|
11
|
+
use crate::proto::daemon::{
|
|
12
|
+
DaemonRequest, GetSessionTeeStatusRequest, RegisterSessionTeeRequest, RequestType, StatusCode,
|
|
13
|
+
TeeBackpressure as ProtoTeeBackpressure, TeeFileMode as ProtoTeeFileMode,
|
|
14
|
+
TeeSessionKind as ProtoTeeSessionKind, TeeSinkKind, TeeStreamKind as ProtoTeeStreamKind,
|
|
15
|
+
UnregisterSessionTeeRequest,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
19
|
+
pub enum SessionTeeKind {
|
|
20
|
+
Pty,
|
|
21
|
+
Pipe,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
25
|
+
pub enum SessionTeeStream {
|
|
26
|
+
PtyOutput,
|
|
27
|
+
Stdout,
|
|
28
|
+
Stderr,
|
|
29
|
+
Stdin,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
33
|
+
pub enum SessionTeeFileMode {
|
|
34
|
+
Append,
|
|
35
|
+
Truncate,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
39
|
+
pub enum SessionTeeBackpressure {
|
|
40
|
+
DropOldest,
|
|
41
|
+
Block,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
45
|
+
pub struct SessionTeeFileRequest {
|
|
46
|
+
pub session_id: String,
|
|
47
|
+
pub session_kind: SessionTeeKind,
|
|
48
|
+
pub stream: SessionTeeStream,
|
|
49
|
+
pub path: PathBuf,
|
|
50
|
+
pub mode: SessionTeeFileMode,
|
|
51
|
+
/// 0 means use the daemon default.
|
|
52
|
+
pub queue_capacity: u32,
|
|
53
|
+
pub write_missed_markers: bool,
|
|
54
|
+
pub backpressure: SessionTeeBackpressure,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
impl SessionTeeFileRequest {
|
|
58
|
+
pub fn new<P>(
|
|
59
|
+
session_id: impl Into<String>,
|
|
60
|
+
session_kind: SessionTeeKind,
|
|
61
|
+
stream: SessionTeeStream,
|
|
62
|
+
path: P,
|
|
63
|
+
) -> Self
|
|
64
|
+
where
|
|
65
|
+
P: AsRef<Path>,
|
|
66
|
+
{
|
|
67
|
+
Self {
|
|
68
|
+
session_id: session_id.into(),
|
|
69
|
+
session_kind,
|
|
70
|
+
stream,
|
|
71
|
+
path: path.as_ref().to_path_buf(),
|
|
72
|
+
mode: SessionTeeFileMode::Append,
|
|
73
|
+
queue_capacity: 0,
|
|
74
|
+
write_missed_markers: true,
|
|
75
|
+
backpressure: SessionTeeBackpressure::DropOldest,
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub fn truncate(mut self) -> Self {
|
|
80
|
+
self.mode = SessionTeeFileMode::Truncate;
|
|
81
|
+
self
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pub fn queue_capacity(mut self, capacity: u32) -> Self {
|
|
85
|
+
self.queue_capacity = capacity;
|
|
86
|
+
self
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn suppress_missed_markers(mut self) -> Self {
|
|
90
|
+
self.write_missed_markers = false;
|
|
91
|
+
self
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
pub fn backpressure(mut self, backpressure: SessionTeeBackpressure) -> Self {
|
|
95
|
+
self.backpressure = backpressure;
|
|
96
|
+
self
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
101
|
+
pub struct SessionTeeStatus {
|
|
102
|
+
pub stream: SessionTeeStream,
|
|
103
|
+
pub missed_bytes: u64,
|
|
104
|
+
pub disconnected: bool,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
impl DaemonClient {
|
|
108
|
+
pub fn register_session_file_tee(
|
|
109
|
+
&mut self,
|
|
110
|
+
request: &SessionTeeFileRequest,
|
|
111
|
+
) -> Result<u64, ClientError> {
|
|
112
|
+
let daemon_request = DaemonRequest {
|
|
113
|
+
id: self.next_request_id(),
|
|
114
|
+
r#type: RequestType::RegisterSessionTee.into(),
|
|
115
|
+
protocol_version: 1,
|
|
116
|
+
register_session_tee: Some(RegisterSessionTeeRequest {
|
|
117
|
+
session_id: request.session_id.clone(),
|
|
118
|
+
session_kind: proto_session_kind(request.session_kind) as i32,
|
|
119
|
+
stream: proto_stream_kind(request.stream) as i32,
|
|
120
|
+
sink_kind: TeeSinkKind::File as i32,
|
|
121
|
+
file_path: encode_os_path(&request.path),
|
|
122
|
+
file_mode: proto_file_mode(request.mode) as i32,
|
|
123
|
+
queue_capacity: request.queue_capacity,
|
|
124
|
+
suppress_missed_markers: !request.write_missed_markers,
|
|
125
|
+
backpressure: proto_backpressure(request.backpressure) as i32,
|
|
126
|
+
}),
|
|
127
|
+
..Default::default()
|
|
128
|
+
};
|
|
129
|
+
let response = self.send_request(daemon_request)?;
|
|
130
|
+
ensure_ok(&response)?;
|
|
131
|
+
let payload = response
|
|
132
|
+
.register_session_tee
|
|
133
|
+
.ok_or_else(|| ClientError::Server {
|
|
134
|
+
code: StatusCode::Internal,
|
|
135
|
+
message: "register_session_tee response missing payload".into(),
|
|
136
|
+
})?;
|
|
137
|
+
Ok(payload.tee_handle)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
pub fn unregister_session_tee(
|
|
141
|
+
&mut self,
|
|
142
|
+
session_kind: SessionTeeKind,
|
|
143
|
+
session_id: &str,
|
|
144
|
+
tee_handle: u64,
|
|
145
|
+
) -> Result<(), ClientError> {
|
|
146
|
+
let daemon_request = DaemonRequest {
|
|
147
|
+
id: self.next_request_id(),
|
|
148
|
+
r#type: RequestType::UnregisterSessionTee.into(),
|
|
149
|
+
protocol_version: 1,
|
|
150
|
+
unregister_session_tee: Some(UnregisterSessionTeeRequest {
|
|
151
|
+
session_id: session_id.to_string(),
|
|
152
|
+
session_kind: proto_session_kind(session_kind) as i32,
|
|
153
|
+
tee_handle,
|
|
154
|
+
}),
|
|
155
|
+
..Default::default()
|
|
156
|
+
};
|
|
157
|
+
let response = self.send_request(daemon_request)?;
|
|
158
|
+
ensure_ok(&response)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
pub fn get_session_tee_status(
|
|
162
|
+
&mut self,
|
|
163
|
+
session_kind: SessionTeeKind,
|
|
164
|
+
session_id: &str,
|
|
165
|
+
tee_handle: u64,
|
|
166
|
+
) -> Result<SessionTeeStatus, ClientError> {
|
|
167
|
+
let daemon_request = DaemonRequest {
|
|
168
|
+
id: self.next_request_id(),
|
|
169
|
+
r#type: RequestType::GetSessionTeeStatus.into(),
|
|
170
|
+
protocol_version: 1,
|
|
171
|
+
get_session_tee_status: Some(GetSessionTeeStatusRequest {
|
|
172
|
+
session_id: session_id.to_string(),
|
|
173
|
+
session_kind: proto_session_kind(session_kind) as i32,
|
|
174
|
+
tee_handle,
|
|
175
|
+
}),
|
|
176
|
+
..Default::default()
|
|
177
|
+
};
|
|
178
|
+
let response = self.send_request(daemon_request)?;
|
|
179
|
+
ensure_ok(&response)?;
|
|
180
|
+
let payload = response
|
|
181
|
+
.get_session_tee_status
|
|
182
|
+
.ok_or_else(|| ClientError::Server {
|
|
183
|
+
code: StatusCode::Internal,
|
|
184
|
+
message: "get_session_tee_status response missing payload".into(),
|
|
185
|
+
})?;
|
|
186
|
+
let stream =
|
|
187
|
+
ProtoTeeStreamKind::try_from(payload.stream).map_err(|_| ClientError::Server {
|
|
188
|
+
code: StatusCode::Internal,
|
|
189
|
+
message: "get_session_tee_status response has invalid stream".into(),
|
|
190
|
+
})?;
|
|
191
|
+
Ok(SessionTeeStatus {
|
|
192
|
+
stream: client_stream_kind(stream)?,
|
|
193
|
+
missed_bytes: payload.missed_bytes,
|
|
194
|
+
disconnected: payload.disconnected,
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
fn ensure_ok(response: &crate::proto::daemon::DaemonResponse) -> Result<(), ClientError> {
|
|
200
|
+
if response.code == StatusCode::Ok as i32 {
|
|
201
|
+
return Ok(());
|
|
202
|
+
}
|
|
203
|
+
let code = StatusCode::try_from(response.code).unwrap_or(StatusCode::UnknownRequest);
|
|
204
|
+
Err(ClientError::Server {
|
|
205
|
+
code,
|
|
206
|
+
message: response.message.clone(),
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fn proto_session_kind(kind: SessionTeeKind) -> ProtoTeeSessionKind {
|
|
211
|
+
match kind {
|
|
212
|
+
SessionTeeKind::Pty => ProtoTeeSessionKind::Pty,
|
|
213
|
+
SessionTeeKind::Pipe => ProtoTeeSessionKind::Pipe,
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
fn proto_stream_kind(stream: SessionTeeStream) -> ProtoTeeStreamKind {
|
|
218
|
+
match stream {
|
|
219
|
+
SessionTeeStream::PtyOutput => ProtoTeeStreamKind::PtyOutput,
|
|
220
|
+
SessionTeeStream::Stdout => ProtoTeeStreamKind::Stdout,
|
|
221
|
+
SessionTeeStream::Stderr => ProtoTeeStreamKind::Stderr,
|
|
222
|
+
SessionTeeStream::Stdin => ProtoTeeStreamKind::Stdin,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
fn client_stream_kind(stream: ProtoTeeStreamKind) -> Result<SessionTeeStream, ClientError> {
|
|
227
|
+
match stream {
|
|
228
|
+
ProtoTeeStreamKind::PtyOutput => Ok(SessionTeeStream::PtyOutput),
|
|
229
|
+
ProtoTeeStreamKind::Stdout => Ok(SessionTeeStream::Stdout),
|
|
230
|
+
ProtoTeeStreamKind::Stderr => Ok(SessionTeeStream::Stderr),
|
|
231
|
+
ProtoTeeStreamKind::Stdin => Ok(SessionTeeStream::Stdin),
|
|
232
|
+
ProtoTeeStreamKind::Unspecified => Err(ClientError::Server {
|
|
233
|
+
code: StatusCode::Internal,
|
|
234
|
+
message: "get_session_tee_status response has unspecified stream".into(),
|
|
235
|
+
}),
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
fn proto_file_mode(mode: SessionTeeFileMode) -> ProtoTeeFileMode {
|
|
240
|
+
match mode {
|
|
241
|
+
SessionTeeFileMode::Append => ProtoTeeFileMode::Append,
|
|
242
|
+
SessionTeeFileMode::Truncate => ProtoTeeFileMode::Truncate,
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
fn proto_backpressure(backpressure: SessionTeeBackpressure) -> ProtoTeeBackpressure {
|
|
247
|
+
match backpressure {
|
|
248
|
+
SessionTeeBackpressure::DropOldest => ProtoTeeBackpressure::DropOldest,
|
|
249
|
+
SessionTeeBackpressure::Block => ProtoTeeBackpressure::Block,
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#[cfg(unix)]
|
|
254
|
+
fn encode_os_path(path: &Path) -> Vec<u8> {
|
|
255
|
+
path.as_os_str().as_bytes().to_vec()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#[cfg(windows)]
|
|
259
|
+
fn encode_os_path(path: &Path) -> Vec<u8> {
|
|
260
|
+
path.as_os_str()
|
|
261
|
+
.encode_wide()
|
|
262
|
+
.flat_map(u16::to_le_bytes)
|
|
263
|
+
.collect()
|
|
264
|
+
}
|
|
@@ -86,6 +86,8 @@ impl ContainedProcessGroup {
|
|
|
86
86
|
fn inject_originator_env(&self, command: &mut Command) {
|
|
87
87
|
if let Some(ref originator) = self.originator {
|
|
88
88
|
command.env(ORIGINATOR_ENV_VAR, format_originator_value(originator));
|
|
89
|
+
} else {
|
|
90
|
+
command.env_remove(ORIGINATOR_ENV_VAR);
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
|
{running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/attach_stream.rs
RENAMED
|
@@ -222,12 +222,7 @@ fn encode_outbound(frame: OutboundFrame) -> (bool, PtyStreamFrame) {
|
|
|
222
222
|
}
|
|
223
223
|
AttachmentEnded::Detached => StreamOneof::Error("detached".into()),
|
|
224
224
|
};
|
|
225
|
-
(
|
|
226
|
-
true,
|
|
227
|
-
PtyStreamFrame {
|
|
228
|
-
frame: Some(oneof),
|
|
229
|
-
},
|
|
230
|
-
)
|
|
225
|
+
(true, PtyStreamFrame { frame: Some(oneof) })
|
|
231
226
|
}
|
|
232
227
|
}
|
|
233
228
|
}
|
|
@@ -289,3 +284,69 @@ where
|
|
|
289
284
|
framed.send(Bytes::from(encoded)).await?;
|
|
290
285
|
Ok(())
|
|
291
286
|
}
|
|
287
|
+
|
|
288
|
+
#[cfg(test)]
|
|
289
|
+
mod tests {
|
|
290
|
+
use super::*;
|
|
291
|
+
|
|
292
|
+
#[test]
|
|
293
|
+
fn encode_outbound_maps_non_terminal_frames() {
|
|
294
|
+
let (terminal, output) = encode_outbound(OutboundFrame::Output(b"abc".to_vec()));
|
|
295
|
+
assert!(!terminal);
|
|
296
|
+
assert!(matches!(
|
|
297
|
+
output.frame,
|
|
298
|
+
Some(StreamOneof::Output(bytes)) if bytes == b"abc"
|
|
299
|
+
));
|
|
300
|
+
|
|
301
|
+
let (terminal, missed) = encode_outbound(OutboundFrame::MissedBytes(42));
|
|
302
|
+
assert!(!terminal);
|
|
303
|
+
assert!(matches!(missed.frame, Some(StreamOneof::MissedBytes(42))));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
#[test]
|
|
307
|
+
fn encode_outbound_maps_terminal_frames() {
|
|
308
|
+
let (terminal, exit) = encode_outbound(OutboundFrame::Exit(7));
|
|
309
|
+
assert!(terminal);
|
|
310
|
+
assert!(matches!(exit.frame, Some(StreamOneof::ExitCode(7))));
|
|
311
|
+
|
|
312
|
+
let (terminal, stolen) = encode_outbound(OutboundFrame::Ended(AttachmentEnded::Stolen));
|
|
313
|
+
assert!(terminal);
|
|
314
|
+
assert!(matches!(
|
|
315
|
+
stolen.frame,
|
|
316
|
+
Some(StreamOneof::StolenBy(peer)) if peer == "peer"
|
|
317
|
+
));
|
|
318
|
+
|
|
319
|
+
let (terminal, exited) =
|
|
320
|
+
encode_outbound(OutboundFrame::Ended(AttachmentEnded::SessionExited));
|
|
321
|
+
assert!(terminal);
|
|
322
|
+
assert!(matches!(
|
|
323
|
+
exited.frame,
|
|
324
|
+
Some(StreamOneof::Error(message)) if message == "session exited"
|
|
325
|
+
));
|
|
326
|
+
|
|
327
|
+
let (terminal, terminated) =
|
|
328
|
+
encode_outbound(OutboundFrame::Ended(AttachmentEnded::Terminated));
|
|
329
|
+
assert!(terminal);
|
|
330
|
+
assert!(matches!(
|
|
331
|
+
terminated.frame,
|
|
332
|
+
Some(StreamOneof::Error(message)) if message == "session terminated by request"
|
|
333
|
+
));
|
|
334
|
+
|
|
335
|
+
let (terminal, detached) = encode_outbound(OutboundFrame::Ended(AttachmentEnded::Detached));
|
|
336
|
+
assert!(terminal);
|
|
337
|
+
assert!(matches!(
|
|
338
|
+
detached.frame,
|
|
339
|
+
Some(StreamOneof::Error(message)) if message == "detached"
|
|
340
|
+
));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
#[test]
|
|
344
|
+
fn error_attach_response_uses_attach_payload() {
|
|
345
|
+
let response = error_attach_response(99, StatusCode::NotFound, "missing".into());
|
|
346
|
+
|
|
347
|
+
assert_eq!(response.request_id, 99);
|
|
348
|
+
assert_eq!(response.code, StatusCode::NotFound as i32);
|
|
349
|
+
assert_eq!(response.message, "missing");
|
|
350
|
+
assert!(response.attach_pty_session.is_some());
|
|
351
|
+
}
|
|
352
|
+
}
|
{running_process-4.0.1 → running_process-4.0.2}/crates/running-process/src/daemon/handlers/mod.rs
RENAMED
|
@@ -28,6 +28,7 @@ mod pty_sessions_handlers;
|
|
|
28
28
|
mod registry_handlers;
|
|
29
29
|
mod services;
|
|
30
30
|
mod spawn;
|
|
31
|
+
mod telemetry;
|
|
31
32
|
mod util;
|
|
32
33
|
|
|
33
34
|
pub use self::core::{handle_ping, handle_shutdown, handle_status};
|
|
@@ -53,6 +54,9 @@ pub use self::services::{
|
|
|
53
54
|
handle_service_start, handle_service_stop,
|
|
54
55
|
};
|
|
55
56
|
pub use self::spawn::handle_spawn_daemon;
|
|
57
|
+
pub use self::telemetry::{
|
|
58
|
+
handle_get_session_tee_status, handle_register_session_tee, handle_unregister_session_tee,
|
|
59
|
+
};
|
|
56
60
|
|
|
57
61
|
// ---------------------------------------------------------------------------
|
|
58
62
|
// Shared daemon state
|