-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProcessInfo.cs
More file actions
107 lines (92 loc) · 3.78 KB
/
Copy pathProcessInfo.cs
File metadata and controls
107 lines (92 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ClaudeGuardian.Models;
/// <summary>被监控的 CLI 工具种类</summary>
public enum ToolKind
{
Claude,
Codex
}
/// <summary>进程的来源渠道,用于筛选——同一 CLI 工具可能被不同宿主拉起</summary>
public enum SourceKind
{
/// <summary>父进程是 VSCode(Code.exe),来自插件面板/标签页</summary>
VsCodePlugin,
/// <summary>父进程是 node_repl.exe 等网关/子代理宿主,来自常驻服务调度</summary>
GatewayAgent,
/// <summary>父进程已退出或无法识别</summary>
Other
}
public sealed class ProcessInfo : INotifyPropertyChanged
{
public int Pid { get; init; }
public int ParentPid { get; init; }
public string Name { get; init; } = string.Empty;
public ToolKind Tool { get; init; }
public SourceKind Source { get; init; }
public string ParentName { get; init; } = string.Empty;
public DateTime CreatedAt { get; init; }
public string PluginVersion { get; init; } = string.Empty;
public string WorkspaceHint { get; init; } = string.Empty;
public string CommandLineShort { get; init; } = string.Empty;
public string ToolDisplay
{
get
{
if (Name.Equals("claude.exe", StringComparison.OrdinalIgnoreCase)) return "Claude";
if (Name.Equals("codex.exe", StringComparison.OrdinalIgnoreCase)) return "Codex";
return Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) ? Name[..^4] : Name;
}
}
public string SourceDisplay => Source switch
{
SourceKind.VsCodePlugin => "VSCode 插件",
SourceKind.GatewayAgent => "网关子代理",
_ => "未知来源"
};
private double _memoryMb;
public double MemoryMb
{
get => _memoryMb;
set { if (_memoryMb != value) { _memoryMb = value; OnPropertyChanged(); OnPropertyChanged(nameof(MemoryDisplay)); } }
}
private double _cpuSeconds;
public double CpuSeconds
{
get => _cpuSeconds;
set { if (_cpuSeconds != value) { _cpuSeconds = value; OnPropertyChanged(); OnPropertyChanged(nameof(CpuDisplay)); } }
}
private double _cpuDeltaLastPoll;
public double CpuDeltaLastPoll
{
get => _cpuDeltaLastPoll;
set { if (_cpuDeltaLastPoll != value) { _cpuDeltaLastPoll = value; OnPropertyChanged(); OnPropertyChanged(nameof(IsIdle)); } }
}
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set { if (_isSelected != value) { _isSelected = value; OnPropertyChanged(); } }
}
public TimeSpan Age => DateTime.Now - CreatedAt;
public string AgeDisplay
{
get
{
var age = Age;
if (age.TotalDays >= 1) return $"{(int)age.TotalDays} 天前";
if (age.TotalHours >= 1) return $"{(int)age.TotalHours} 小时前";
return $"{Math.Max(1, (int)age.TotalMinutes)} 分钟前";
}
}
public string MemoryDisplay => MemoryMb >= 1024 ? $"{MemoryMb / 1024:0.00} GB" : $"{MemoryMb:0} MB";
public string CpuDisplay => CpuSeconds >= 60 ? $"{CpuSeconds / 60:0.0} 分钟" : $"{CpuSeconds:0.0} 秒";
/// <summary>判定阈值由外部(设置面板)注入,默认沿用旧行为(12 小时 / 0.05)。</summary>
public double StaleIdleHours { get; set; } = 12;
public double StaleCpuDeltaThreshold { get; set; } = 0.05;
public bool IsIdle => CpuDeltaLastPoll < StaleCpuDeltaThreshold;
public bool IsStaleCandidate => Age.TotalHours >= StaleIdleHours && IsIdle;
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}