DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/IPC/WindServiceHandlers/Terminal/SerializeTerminalState.rs
1#![allow(non_snake_case)]
2
3//! Serialise all active terminals to the `ISerializedTerminalState[]` shape
4//! that VS Code's `ILocalPtyService.serializeTerminalProcesses` contract
5//! requires.
6//!
7//! VS Code calls this immediately before a window reload to snapshot running
8//! PTY state. The result is written to storage and later passed back via
9//! `localPty:reviveTerminalProcesses` so the workbench can restore the panel
10//! without the user losing their shell sessions.
11//!
12//! ## Output shape per terminal
13//! ```json
14//! {
15//! "id": 1,
16//! "shellLaunchConfig": { "name": "zsh", "executable": "/bin/zsh", "args": [] },
17//! "processDetails": { "cwd": "/...", "pid": 1234, "title": "zsh" },
18//! "orphanQuestionReply": false,
19//! "replayEvent": { "events": [] },
20//! "timestamp": 1716134400000
21//! }
22//! ```
23//!
24//! Runtime handles (`PTYMaster`, `PTYInputTransmitter`, task `JoinHandle`s)
25//! are `#[serde(skip)]` in `TerminalStateDTO` and are intentionally absent
26//! from the wire payload - only the configuration fields needed to respawn
27//! the shell are serialised.
28
29use std::sync::Arc;
30
31use serde_json::{Value, json};
32
33use crate::RunTime::ApplicationRunTime::ApplicationRunTime;
34
35pub async fn SerializeTerminalState(RunTime:Arc<ApplicationRunTime>) -> Result<Value, String> {
36 let Terminals = RunTime
37 .Environment
38 .ApplicationState
39 .Feature
40 .Terminals
41 .ActiveTerminals
42 .lock()
43 .map_err(|Error| format!("SerializeTerminalState: lock poisoned: {}", Error))?;
44
45 let NowMs = std::time::SystemTime::now()
46 .duration_since(std::time::UNIX_EPOCH)
47 .map(|D| D.as_millis() as u64)
48 .unwrap_or(0);
49
50 let Serialized:Vec<Value> = Terminals
51 .iter()
52 .filter_map(|(TerminalId, ArcState)| {
53 let State = ArcState.lock().ok()?;
54
55 let Cwd = State.GetWorkingDirectory();
56
57 let Pid = State.OSProcessIdentifier.unwrap_or(0) as u64;
58
59 Some(json!({
60 "id": TerminalId,
61 "shellLaunchConfig": {
62 "name": State.Name,
63 "executable": State.ShellPath,
64 "args": State.ShellArguments,
65 "cwd": Cwd,
66 },
67 "processDetails": {
68 "cwd": Cwd,
69 "pid": Pid,
70 "title": State.Name,
71 },
72 // False means the orphan-question dialog was NOT shown;
73 // revived terminals start fresh without a stale prompt.
74 "orphanQuestionReply": false,
75 // Empty replay - the xterm buffer will be restored from the
76 // output replay buffer separately via `sky:replay-events`.
77 "replayEvent": { "events": [] },
78 "timestamp": NowMs,
79 }))
80 })
81 .collect();
82
83 Ok(Value::Array(Serialized))
84}