Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/cli/src/commands/agent_ps.rs
13383 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
use ahp_types::commands::{ListSessionsParams, ListSessionsResult};
7
use ahp_types::state::{SessionStatus, SessionSummary};
8
9
use crate::util::errors::AnyError;
10
11
use super::agent;
12
use super::args::AgentPsArgs;
13
use super::output::{self, Styles};
14
use super::CommandContext;
15
16
/// Lists active sessions on a running agent host.
17
pub async fn agent_ps(ctx: CommandContext, args: AgentPsArgs) -> Result<i32, AnyError> {
18
let client = agent::connect(&ctx, args.address.as_deref(), args.tunnel.as_deref()).await?;
19
20
let result: ListSessionsResult =
21
agent::request_with_auth(&ctx, &client, "listSessions", ListSessionsParams::default())
22
.await?;
23
24
client.shutdown().await;
25
26
let mut items: Vec<&SessionSummary> = if args.all {
27
result.items.iter().collect()
28
} else {
29
result
30
.items
31
.iter()
32
.filter(|s| is_active(s.status))
33
.collect()
34
};
35
36
// Most-recently-modified first.
37
items.sort_by_key(|b| std::cmp::Reverse(b.modified_at));
38
39
if args.json {
40
let json = serde_json::to_string_pretty(&items)
41
.map_err(|e| crate::util::errors::wrap(e, "Failed to serialize sessions"))?;
42
output::print_paged(&json);
43
} else if items.is_empty() {
44
ctx.log.result("No active sessions.");
45
} else {
46
let out = format_sessions_list(&items);
47
output::print_paged(&out);
48
}
49
50
Ok(0)
51
}
52
53
/// A session is "active" if it is in-progress, needs input, or errored
54
/// (i.e. not just idle/archived).
55
fn is_active(status: u32) -> bool {
56
let dominated = SessionStatus::IsRead as u32
57
| SessionStatus::IsArchived as u32
58
| SessionStatus::Idle as u32;
59
status & !dominated != 0
60
}
61
62
fn format_sessions_list(sessions: &[&SessionSummary]) -> String {
63
let title_style = Styles::title();
64
let label_style = Styles::label();
65
let uri_style = Styles::uri();
66
67
let mut out = String::new();
68
69
for (i, s) in sessions.iter().enumerate() {
70
if i > 0 {
71
out.push('\n');
72
}
73
74
let status = status_styled(s.status);
75
let title = if s.title.is_empty() {
76
"(untitled)".to_string()
77
} else {
78
s.title.clone()
79
};
80
out.push_str(&format!(" {} {}\n", title_style.apply_to(&title), status));
81
82
out.push_str(&format!(
83
" {} {}\n",
84
label_style.apply_to("uri:"),
85
uri_style.apply_to(&s.resource),
86
));
87
88
out.push_str(&format!(
89
" {} {}\n",
90
label_style.apply_to("provider:"),
91
s.provider,
92
));
93
94
if let Some(activity) = &s.activity {
95
if !activity.is_empty() {
96
out.push_str(&format!(
97
" {} {}\n",
98
label_style.apply_to("activity:"),
99
activity,
100
));
101
}
102
}
103
104
if let Some(wd) = &s.working_directory {
105
out.push_str(&format!(" {} {}\n", label_style.apply_to("cwd:"), wd,));
106
}
107
}
108
109
out
110
}
111
112
fn status_styled(status: u32) -> console::StyledObject<String> {
113
if status & (SessionStatus::InputNeeded as u32) == (SessionStatus::InputNeeded as u32) {
114
Styles::warning().apply_to("● input needed".to_string())
115
} else if status & (SessionStatus::InProgress as u32) != 0 {
116
Styles::success().apply_to("● in progress".to_string())
117
} else if status & (SessionStatus::Error as u32) != 0 {
118
Styles::error().apply_to("● error".to_string())
119
} else if status & (SessionStatus::Idle as u32) != 0 {
120
Styles::muted().apply_to("○ idle".to_string())
121
} else {
122
Styles::muted().apply_to(format!("? unknown ({status})"))
123
}
124
}
125
126