devtools-hub 2.6.0__tar.gz → 2.7.0__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.
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/PKG-INFO +1 -1
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/README.md +7 -6
- devtools_hub-2.7.0/devtools_hub/cli.py +527 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub.egg-info/PKG-INFO +1 -1
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/pyproject.toml +1 -1
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/setup.py +1 -1
- devtools_hub-2.6.0/devtools_hub/cli.py +0 -150
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub/__init__.py +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub/scanner.py +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub/server.py +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub.egg-info/SOURCES.txt +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub.egg-info/dependency_links.txt +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub.egg-info/entry_points.txt +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub.egg-info/requires.txt +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/devtools_hub.egg-info/top_level.txt +0 -0
- {devtools_hub-2.6.0 → devtools_hub-2.7.0}/setup.cfg +0 -0
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
## 📦 Installation | 安装
|
|
9
9
|
|
|
10
|
+
### Homebrew (macOS)
|
|
10
11
|
```bash
|
|
11
|
-
|
|
12
|
+
brew tap jingjing737/tap
|
|
13
|
+
brew install devtools-hub
|
|
12
14
|
```
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
### pip
|
|
15
17
|
```bash
|
|
16
|
-
|
|
17
|
-
cd devtools-hub
|
|
18
|
-
pip install -e .
|
|
18
|
+
pip install devtools-hub
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
### 从源码安装
|
|
22
22
|
```bash
|
|
23
23
|
git clone https://github.com/jingjing737/devtools-hub.git
|
|
24
24
|
cd devtools-hub
|
|
@@ -162,5 +162,6 @@ MIT License
|
|
|
162
162
|
---
|
|
163
163
|
|
|
164
164
|
**GitHub**: https://github.com/jingjing737/devtools-hub
|
|
165
|
+
**Homebrew**: https://github.com/jingjing737/homebrew-tap
|
|
165
166
|
**PyPI**: https://pypi.org/project/devtools-hub/
|
|
166
167
|
**Version**: v2.6.0
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""DevTools Hub CLI v2.7.0 - 开发者工具集"""
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
5
|
+
import json
|
|
6
|
+
import time
|
|
7
|
+
import platform
|
|
8
|
+
import os
|
|
9
|
+
import hashlib
|
|
10
|
+
import base64
|
|
11
|
+
import socket
|
|
12
|
+
import re
|
|
13
|
+
import urllib.request
|
|
14
|
+
import urllib.error
|
|
15
|
+
|
|
16
|
+
PORT = 5001
|
|
17
|
+
URL = f"http://localhost:{PORT}"
|
|
18
|
+
|
|
19
|
+
def check():
|
|
20
|
+
try:
|
|
21
|
+
import requests
|
|
22
|
+
r = requests.get(f"{URL}/api/health", timeout=1)
|
|
23
|
+
return r.ok
|
|
24
|
+
except:
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
def main():
|
|
28
|
+
if len(sys.argv) < 2:
|
|
29
|
+
print("""
|
|
30
|
+
🔧 DevTools Hub v2.7.0 - 开发者工具集
|
|
31
|
+
|
|
32
|
+
用法: devtools <命令>
|
|
33
|
+
|
|
34
|
+
系统监控:
|
|
35
|
+
status 系统状态
|
|
36
|
+
cpu CPU 信息
|
|
37
|
+
cpu-usage CPU 使用率趋势
|
|
38
|
+
mem 内存信息
|
|
39
|
+
disk 磁盘信息
|
|
40
|
+
battery 电池状态
|
|
41
|
+
temp 温度监控
|
|
42
|
+
uptime 运行时间
|
|
43
|
+
load 系统负载
|
|
44
|
+
|
|
45
|
+
网络工具:
|
|
46
|
+
ip 本机 IP
|
|
47
|
+
publicip 公网 IP
|
|
48
|
+
ping Ping 测试
|
|
49
|
+
dns DNS 查询
|
|
50
|
+
speed 网速测试
|
|
51
|
+
wifi WiFi 信息
|
|
52
|
+
tracert 路由追踪
|
|
53
|
+
|
|
54
|
+
进程管理:
|
|
55
|
+
top 高占用进程
|
|
56
|
+
ps 进程列表
|
|
57
|
+
kill 结束进程
|
|
58
|
+
zombie 僵尸进程
|
|
59
|
+
|
|
60
|
+
文件工具:
|
|
61
|
+
du 磁盘使用
|
|
62
|
+
find 查找文件
|
|
63
|
+
hash 计算哈希
|
|
64
|
+
json JSON 工具
|
|
65
|
+
base64 Base64 编解码
|
|
66
|
+
env 环境变量
|
|
67
|
+
|
|
68
|
+
开发工具:
|
|
69
|
+
ports 端口扫描
|
|
70
|
+
services 系统服务
|
|
71
|
+
git Git 状态
|
|
72
|
+
node Node.js 信息
|
|
73
|
+
python Python 版本
|
|
74
|
+
|
|
75
|
+
系统:
|
|
76
|
+
info 系统信息
|
|
77
|
+
bench 性能测试
|
|
78
|
+
clean 清理缓存
|
|
79
|
+
update 检查更新
|
|
80
|
+
start 启动服务
|
|
81
|
+
stop 停止服务
|
|
82
|
+
""")
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
cmd = sys.argv[1]
|
|
86
|
+
args = sys.argv[2:]
|
|
87
|
+
|
|
88
|
+
# ========== 系统监控 ==========
|
|
89
|
+
if cmd == "status":
|
|
90
|
+
if check():
|
|
91
|
+
import requests
|
|
92
|
+
r = requests.get(f"{URL}/api/health")
|
|
93
|
+
print(json.dumps(r.json(), indent=2))
|
|
94
|
+
else:
|
|
95
|
+
print("❌ 服务未运行,请先 devtools start")
|
|
96
|
+
|
|
97
|
+
elif cmd == "cpu":
|
|
98
|
+
import psutil
|
|
99
|
+
print(f"CPU: {psutil.cpu_percent()}% 核心: {psutil.cpu_count()} 物理核心: {psutil.cpu_count(logical=False)}")
|
|
100
|
+
|
|
101
|
+
elif cmd == "cpu-usage":
|
|
102
|
+
import psutil
|
|
103
|
+
print("📊 CPU 使用率(5秒采样)...")
|
|
104
|
+
for i in range(5):
|
|
105
|
+
print(f" {psutil.cpu_percent(interval=1)}%", end=" ", flush=True)
|
|
106
|
+
print()
|
|
107
|
+
|
|
108
|
+
elif cmd == "mem":
|
|
109
|
+
import psutil
|
|
110
|
+
m = psutil.virtual_memory()
|
|
111
|
+
print(f"内存: {m.percent}% 已用: {m.used/1024**3:.1f}GB 可用: {m.available/1024**3:.1f}GB 总计: {m.total/1024**3:.1f}GB")
|
|
112
|
+
# Swap
|
|
113
|
+
s = psutil.swap_memory()
|
|
114
|
+
print(f"Swap: {s.percent}% 已用: {s.used/1024**3:.1f}GB")
|
|
115
|
+
|
|
116
|
+
elif cmd == "disk":
|
|
117
|
+
import psutil
|
|
118
|
+
for p in [('/', '/System/Volumes/Data', '/Users')]:
|
|
119
|
+
try:
|
|
120
|
+
d = psutil.disk_usage(p)
|
|
121
|
+
print(f"{p}: {d.percent}% 已用: {d.used/1024**3:.1f}GB 可用: {d.free/1024**3:.1f}GB")
|
|
122
|
+
except:
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
elif cmd == "battery":
|
|
126
|
+
import psutil
|
|
127
|
+
try:
|
|
128
|
+
b = psutil.sensors_battery()
|
|
129
|
+
if b:
|
|
130
|
+
print(f"电池: {b.percent}% {'🔌 充电中' if b.power_plugged else '🔋 使用电池'}")
|
|
131
|
+
if b.secsleft and b.secsleft > 0:
|
|
132
|
+
h = b.secsleft // 3600
|
|
133
|
+
m = (b.secsleft % 3600) // 60
|
|
134
|
+
print(f"剩余时间: {h}h {m}m")
|
|
135
|
+
else:
|
|
136
|
+
print("❌ 无电池(台式机)")
|
|
137
|
+
except:
|
|
138
|
+
print("❌ 电池信息不可用")
|
|
139
|
+
|
|
140
|
+
elif cmd == "temp":
|
|
141
|
+
import psutil
|
|
142
|
+
temps = getattr(psutil, 'sensors_temperatures', lambda: {})()
|
|
143
|
+
if temps:
|
|
144
|
+
for name, entries in temps.items():
|
|
145
|
+
for entry in entries:
|
|
146
|
+
label = entry.label or name
|
|
147
|
+
current = entry.current
|
|
148
|
+
high = entry.high or "N/A"
|
|
149
|
+
print(f"🌡️ {label}: {current:.1f}°C 最高: {high}°C")
|
|
150
|
+
else:
|
|
151
|
+
print("❌ 温度信息不可用(虚拟机或权限不足)")
|
|
152
|
+
|
|
153
|
+
elif cmd == "uptime":
|
|
154
|
+
import psutil
|
|
155
|
+
boot = psutil.boot_time()
|
|
156
|
+
import datetime
|
|
157
|
+
now = datetime.datetime.now()
|
|
158
|
+
boot_time = datetime.datetime.fromtimestamp(boot)
|
|
159
|
+
delta = now - boot_time
|
|
160
|
+
print(f"系统运行: {delta.days}天 {delta.seconds//3600}小时 {(delta.seconds%3600)//60}分钟")
|
|
161
|
+
print(f"启动时间: {boot_time.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
162
|
+
|
|
163
|
+
elif cmd == "load":
|
|
164
|
+
import os
|
|
165
|
+
load = os.getloadavg() if hasattr(os, 'getloadavg') else (0, 0, 0)
|
|
166
|
+
print(f"负载: {load[0]:.2f} {load[1]:.2f} {load[2]:.2f} (1/5/15分钟)")
|
|
167
|
+
|
|
168
|
+
# ========== 网络工具 ==========
|
|
169
|
+
elif cmd == "ip":
|
|
170
|
+
import socket
|
|
171
|
+
try:
|
|
172
|
+
hostname = socket.gethostname()
|
|
173
|
+
ip = socket.gethostbyname(hostname)
|
|
174
|
+
print(f"主机: {hostname}")
|
|
175
|
+
print(f"IP: {ip}")
|
|
176
|
+
except:
|
|
177
|
+
print(f"IP: {socket.gethostbyname(socket.gethostname())}")
|
|
178
|
+
|
|
179
|
+
elif cmd == "publicip":
|
|
180
|
+
try:
|
|
181
|
+
ip = urllib.request.urlopen('https://api.ipify.org', timeout=5).read().decode()
|
|
182
|
+
print(f"🌐 公网IP: {ip}")
|
|
183
|
+
# 获取位置
|
|
184
|
+
try:
|
|
185
|
+
data = urllib.request.urlopen(f'https://ipapi.co/{ip}/json/', timeout=5).read().decode()
|
|
186
|
+
loc = json.loads(data)
|
|
187
|
+
print(f"📍 位置: {loc.get('city', '')}, {loc.get('country_name', '')}")
|
|
188
|
+
print(f"🏢 运营商: {loc.get('org', '')}")
|
|
189
|
+
except:
|
|
190
|
+
pass
|
|
191
|
+
except Exception as e:
|
|
192
|
+
print(f"❌ 获取失败: {e}")
|
|
193
|
+
|
|
194
|
+
elif cmd == "ping":
|
|
195
|
+
if not args:
|
|
196
|
+
args = ['8.8.8.8']
|
|
197
|
+
host = args[0]
|
|
198
|
+
print(f"📡 Ping {host}...")
|
|
199
|
+
result = subprocess.run(['ping', '-c', '4', host], capture_output=True, text=True)
|
|
200
|
+
lines = result.stdout.split('\n')
|
|
201
|
+
for line in lines[-5:]:
|
|
202
|
+
if line.strip():
|
|
203
|
+
print(line)
|
|
204
|
+
if result.returncode != 0:
|
|
205
|
+
print("❌ Ping 失败")
|
|
206
|
+
|
|
207
|
+
elif cmd == "dns":
|
|
208
|
+
if not args:
|
|
209
|
+
print("用法: devtools dns <域名>")
|
|
210
|
+
return
|
|
211
|
+
domain = args[0]
|
|
212
|
+
print(f"🔍 DNS 查询: {domain}")
|
|
213
|
+
try:
|
|
214
|
+
ip = socket.gethostbyname(domain)
|
|
215
|
+
print(f"✅ 解析: {ip}")
|
|
216
|
+
except Exception as e:
|
|
217
|
+
print(f"❌ 解析失败: {e}")
|
|
218
|
+
|
|
219
|
+
elif cmd == "speed":
|
|
220
|
+
print("📊 测速中(下载测试)...")
|
|
221
|
+
try:
|
|
222
|
+
start = time.time()
|
|
223
|
+
urllib.request.urlopen('https://speed.cloudflare.com/__down?bytes=10000000', timeout=30)
|
|
224
|
+
elapsed = time.time() - start
|
|
225
|
+
speed = 10 / elapsed # MB/s
|
|
226
|
+
print(f"⚡ 网速: {speed:.1f} MB/s ({(speed*8):.1f} Mbps)")
|
|
227
|
+
except Exception as e:
|
|
228
|
+
print(f"❌ 测速失败: {e}")
|
|
229
|
+
|
|
230
|
+
elif cmd == "wifi":
|
|
231
|
+
try:
|
|
232
|
+
result = subprocess.run(['networksetup', '-listallhardwareports'], capture_output=True, text=True)
|
|
233
|
+
print(result.stdout)
|
|
234
|
+
except:
|
|
235
|
+
print("❌ WiFi 信息不可用")
|
|
236
|
+
|
|
237
|
+
elif cmd == "tracert":
|
|
238
|
+
if not args:
|
|
239
|
+
args = ['8.8.8.8']
|
|
240
|
+
host = args[0]
|
|
241
|
+
print(f"🛤️ 路由追踪: {host}")
|
|
242
|
+
result = subprocess.run(['traceroute', '-m', '15', host], capture_output=True, text=True)
|
|
243
|
+
print(result.stdout[:2000])
|
|
244
|
+
|
|
245
|
+
# ========== 进程管理 ==========
|
|
246
|
+
elif cmd == "top":
|
|
247
|
+
import psutil
|
|
248
|
+
procs = []
|
|
249
|
+
for p in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'username']):
|
|
250
|
+
try:
|
|
251
|
+
procs.append(p.info)
|
|
252
|
+
except:
|
|
253
|
+
pass
|
|
254
|
+
by_cpu = sorted(procs, key=lambda x: x['cpu_percent'] or 0, reverse=True)[:8]
|
|
255
|
+
by_mem = sorted(procs, key=lambda x: x['memory_percent'] or 0, reverse=True)[:5]
|
|
256
|
+
print("🔥 CPU 高占用:")
|
|
257
|
+
for p in by_cpu:
|
|
258
|
+
print(f" PID {p['pid']:>6} | {p['name'][:25]:<25} | {p['cpu_percent']:>5}% | {p.get('username', '')[:15]}")
|
|
259
|
+
print("\n💾 内存高占用:")
|
|
260
|
+
for p in by_mem:
|
|
261
|
+
print(f" PID {p['pid']:>6} | {p['name'][:25]:<25} | {p['memory_percent']:>5}%")
|
|
262
|
+
|
|
263
|
+
elif cmd == "ps":
|
|
264
|
+
import psutil
|
|
265
|
+
procs = []
|
|
266
|
+
for p in psutil.process_iter(['pid', 'name', 'status', 'cpu_percent']):
|
|
267
|
+
try:
|
|
268
|
+
procs.append(p.info)
|
|
269
|
+
except:
|
|
270
|
+
pass
|
|
271
|
+
print(f"📋 总进程数: {len(procs)}")
|
|
272
|
+
running = sum(1 for p in procs if p.get('status') == 'running')
|
|
273
|
+
sleeping = sum(1 for p in procs if p.get('status') == 'sleeping')
|
|
274
|
+
print(f" 运行中: {running} 睡眠中: {sleeping}")
|
|
275
|
+
|
|
276
|
+
elif cmd == "kill":
|
|
277
|
+
if not args:
|
|
278
|
+
print("用法: devtools kill <进程名或PID>")
|
|
279
|
+
return
|
|
280
|
+
target = args[0]
|
|
281
|
+
try:
|
|
282
|
+
pid = int(target)
|
|
283
|
+
p = psutil.Process(pid)
|
|
284
|
+
name = p.name()
|
|
285
|
+
p.kill()
|
|
286
|
+
print(f"✅ 已结束进程: {name} (PID: {pid})")
|
|
287
|
+
except ValueError:
|
|
288
|
+
# 按名称结束
|
|
289
|
+
killed = 0
|
|
290
|
+
for p in psutil.process_iter(['pid', 'name']):
|
|
291
|
+
try:
|
|
292
|
+
if target.lower() in p.info['name'].lower():
|
|
293
|
+
p.kill()
|
|
294
|
+
killed += 1
|
|
295
|
+
except:
|
|
296
|
+
pass
|
|
297
|
+
print(f"✅ 已结束 {killed} 个进程: {target}")
|
|
298
|
+
except Exception as e:
|
|
299
|
+
print(f"❌ 结束进程失败: {e}")
|
|
300
|
+
|
|
301
|
+
elif cmd == "zombie":
|
|
302
|
+
import psutil
|
|
303
|
+
zombies = []
|
|
304
|
+
for p in psutil.process_iter(['pid', 'name', 'status']):
|
|
305
|
+
try:
|
|
306
|
+
if p.info['status'] == 'zombie':
|
|
307
|
+
zombies.append(p.info)
|
|
308
|
+
except:
|
|
309
|
+
pass
|
|
310
|
+
if zombies:
|
|
311
|
+
print(f"🧟 僵尸进程 ({len(zombies)}):")
|
|
312
|
+
for z in zombies:
|
|
313
|
+
print(f" PID {z['pid']}: {z['name']}")
|
|
314
|
+
else:
|
|
315
|
+
print("✅ 无僵尸进程")
|
|
316
|
+
|
|
317
|
+
# ========== 文件工具 ==========
|
|
318
|
+
elif cmd == "du":
|
|
319
|
+
if not args:
|
|
320
|
+
path = os.path.expanduser('~')
|
|
321
|
+
else:
|
|
322
|
+
path = args[0]
|
|
323
|
+
print(f"📁 磁盘使用: {path}")
|
|
324
|
+
import subprocess
|
|
325
|
+
result = subprocess.run(['du', '-sh', path], capture_output=True, text=True)
|
|
326
|
+
print(result.stdout.strip())
|
|
327
|
+
|
|
328
|
+
elif cmd == "find":
|
|
329
|
+
print("🔍 查找大文件...")
|
|
330
|
+
import psutil
|
|
331
|
+
import os
|
|
332
|
+
home = os.path.expanduser('~')
|
|
333
|
+
files = []
|
|
334
|
+
for root, dirs, filenames in os.walk(home):
|
|
335
|
+
# 跳过隐藏目录
|
|
336
|
+
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
|
337
|
+
for f in filenames:
|
|
338
|
+
fp = os.path.join(root, f)
|
|
339
|
+
try:
|
|
340
|
+
size = os.path.getsize(fp)
|
|
341
|
+
if size > 100 * 1024 * 1024: # > 100MB
|
|
342
|
+
files.append((size, fp))
|
|
343
|
+
except:
|
|
344
|
+
pass
|
|
345
|
+
files.sort(reverse=True)
|
|
346
|
+
print(f"找到 {len(files)} 个大文件 (>100MB):")
|
|
347
|
+
for size, fp in files[:20]:
|
|
348
|
+
print(f" {size/1024**3:.2f}GB {fp[:80]}")
|
|
349
|
+
|
|
350
|
+
elif cmd == "hash":
|
|
351
|
+
if not args:
|
|
352
|
+
print("用法: devtools hash <文件路径>")
|
|
353
|
+
return
|
|
354
|
+
filepath = os.path.expanduser(args[0])
|
|
355
|
+
if not os.path.exists(filepath):
|
|
356
|
+
print(f"❌ 文件不存在: {filepath}")
|
|
357
|
+
return
|
|
358
|
+
print(f"🔐 计算哈希: {filepath}")
|
|
359
|
+
with open(filepath, 'rb') as f:
|
|
360
|
+
md5 = hashlib.md5(f.read()).hexdigest()
|
|
361
|
+
with open(filepath, 'rb') as f:
|
|
362
|
+
sha1 = hashlib.sha1(f.read()).hexdigest()
|
|
363
|
+
with open(filepath, 'rb') as f:
|
|
364
|
+
sha256 = hashlib.sha256(f.read()).hexdigest()
|
|
365
|
+
print(f"MD5: {md5}")
|
|
366
|
+
print(f"SHA1: {sha1}")
|
|
367
|
+
print(f"SHA256: {sha256}")
|
|
368
|
+
|
|
369
|
+
elif cmd == "json":
|
|
370
|
+
if not args:
|
|
371
|
+
print("用法: devtools json <JSON字符串或文件路径>")
|
|
372
|
+
return
|
|
373
|
+
text = args[0]
|
|
374
|
+
if os.path.exists(os.path.expanduser(text)):
|
|
375
|
+
with open(os.path.expanduser(text)) as f:
|
|
376
|
+
text = f.read()
|
|
377
|
+
try:
|
|
378
|
+
obj = json.loads(text)
|
|
379
|
+
print(json.dumps(obj, indent=2, ensure_ascii=False))
|
|
380
|
+
except json.JSONDecodeError as e:
|
|
381
|
+
print(f"❌ JSON 解析错误: {e}")
|
|
382
|
+
|
|
383
|
+
elif cmd == "base64":
|
|
384
|
+
if len(args) < 2:
|
|
385
|
+
print("用法: devtools base64 <encode|decode> <文本或文件路径>")
|
|
386
|
+
return
|
|
387
|
+
mode = args[0]
|
|
388
|
+
text = args[1]
|
|
389
|
+
if os.path.exists(os.path.expanduser(text)):
|
|
390
|
+
with open(os.path.expanduser(text), 'rb') as f:
|
|
391
|
+
text = f.read()
|
|
392
|
+
if mode == 'encode':
|
|
393
|
+
print(base64.b64encode(text).decode())
|
|
394
|
+
elif mode == 'decode':
|
|
395
|
+
print(base64.b64decode(text).decode(errors='ignore'))
|
|
396
|
+
else:
|
|
397
|
+
text = text.encode()
|
|
398
|
+
if mode == 'encode':
|
|
399
|
+
print(base64.b64encode(text).decode())
|
|
400
|
+
elif mode == 'decode':
|
|
401
|
+
try:
|
|
402
|
+
print(base64.b64decode(text).decode(errors='ignore'))
|
|
403
|
+
except:
|
|
404
|
+
print("❌ 解码失败")
|
|
405
|
+
|
|
406
|
+
elif cmd == "env":
|
|
407
|
+
if args:
|
|
408
|
+
key = args[0]
|
|
409
|
+
print(f"{key}={os.environ.get(key, '❌ 未设置')}")
|
|
410
|
+
else:
|
|
411
|
+
print("🔧 环境变量:")
|
|
412
|
+
for k, v in sorted(os.environ.items()):
|
|
413
|
+
if args and args[0].lower() in k.lower():
|
|
414
|
+
print(f" {k}={v}")
|
|
415
|
+
|
|
416
|
+
# ========== 开发工具 ==========
|
|
417
|
+
elif cmd == "ports":
|
|
418
|
+
from devtools_hub.scanner import scan_common_ports
|
|
419
|
+
print("🔍 扫描常用端口...")
|
|
420
|
+
ports = scan_common_ports()
|
|
421
|
+
if ports:
|
|
422
|
+
for p in ports:
|
|
423
|
+
print(f" ✅ {p['port']} ({p['name']}) - 开放")
|
|
424
|
+
else:
|
|
425
|
+
print(" 未发现开放端口")
|
|
426
|
+
|
|
427
|
+
elif cmd == "services":
|
|
428
|
+
from devtools_hub.scanner import get_services
|
|
429
|
+
print("📋 系统服务:")
|
|
430
|
+
services = get_services()
|
|
431
|
+
for s in services[:20]:
|
|
432
|
+
pid_str = str(s['pid']) if s['pid'] else '-'
|
|
433
|
+
print(f" [{pid_str:>6}] {s['name']}")
|
|
434
|
+
|
|
435
|
+
elif cmd == "git":
|
|
436
|
+
try:
|
|
437
|
+
result = subprocess.run(['git', 'status'], capture_output=True, text=True, cwd=os.path.dirname(os.path.dirname(__file__)))
|
|
438
|
+
print(result.stdout)
|
|
439
|
+
if result.returncode != 0:
|
|
440
|
+
print(result.stderr)
|
|
441
|
+
except FileNotFoundError:
|
|
442
|
+
print("❌ Git 未安装")
|
|
443
|
+
|
|
444
|
+
elif cmd == "node":
|
|
445
|
+
try:
|
|
446
|
+
v = subprocess.run(['node', '--version'], capture_output=True, text=True)
|
|
447
|
+
npm = subprocess.run(['npm', '--version'], capture_output=True, text=True)
|
|
448
|
+
print(f"Node.js: {v.stdout.strip()}")
|
|
449
|
+
print(f"npm: {npm.stdout.strip()}")
|
|
450
|
+
except FileNotFoundError:
|
|
451
|
+
print("❌ Node.js 未安装")
|
|
452
|
+
|
|
453
|
+
elif cmd == "python":
|
|
454
|
+
v = sys.version_info
|
|
455
|
+
print(f"Python: {v.major}.{v.minor}.{v.micro}")
|
|
456
|
+
try:
|
|
457
|
+
import pip
|
|
458
|
+
print(f"pip: {pip.__version__}")
|
|
459
|
+
except:
|
|
460
|
+
pass
|
|
461
|
+
|
|
462
|
+
# ========== 系统 ==========
|
|
463
|
+
elif cmd == "info":
|
|
464
|
+
print(f"""
|
|
465
|
+
🖥️ 系统信息:
|
|
466
|
+
系统: {platform.system()} {platform.release()} {platform.machine()}
|
|
467
|
+
主机: {platform.node()}
|
|
468
|
+
处理器: {platform.processor()}
|
|
469
|
+
Python: {platform.python_version()}
|
|
470
|
+
macOS: {platform.mac_ver()[0]}
|
|
471
|
+
""")
|
|
472
|
+
|
|
473
|
+
elif cmd == "bench":
|
|
474
|
+
if check():
|
|
475
|
+
import requests
|
|
476
|
+
r = requests.get(f"{URL}/api/benchmark/full")
|
|
477
|
+
print(json.dumps(r.json(), indent=2))
|
|
478
|
+
else:
|
|
479
|
+
print("❌ 服务未运行,请先 devtools start")
|
|
480
|
+
print("💡 或直接运行: devtools cpu")
|
|
481
|
+
|
|
482
|
+
elif cmd == "clean":
|
|
483
|
+
print("🧹 清理缓存...")
|
|
484
|
+
dirs = [
|
|
485
|
+
'~/Library/Caches/com.apple.nsurlsessiond',
|
|
486
|
+
'~/.cache',
|
|
487
|
+
]
|
|
488
|
+
cleaned = 0
|
|
489
|
+
for d in dirs:
|
|
490
|
+
path = os.path.expanduser(d)
|
|
491
|
+
if os.path.exists(path):
|
|
492
|
+
size = sum(os.path.getsize(os.path.join(r, f)) for r, _, fs in os.walk(path) for f in fs)
|
|
493
|
+
cleaned += size
|
|
494
|
+
print(f" 清理: {d} ({size/1024**2:.1f}MB)")
|
|
495
|
+
print(f"✅ 可释放: {cleaned/1024**2:.1f}MB(手动清理更彻底)")
|
|
496
|
+
print("💡 提示: 使用 'sudo periodic daily weekly monthly' 清理系统缓存")
|
|
497
|
+
|
|
498
|
+
elif cmd == "update":
|
|
499
|
+
print("🔄 检查更新...")
|
|
500
|
+
try:
|
|
501
|
+
latest = urllib.request.urlopen('https://pypi.org/pypi/devtools-hub/json', timeout=5)
|
|
502
|
+
data = json.loads(latest.read())
|
|
503
|
+
version = data['info']['version']
|
|
504
|
+
print(f"PyPI 最新版本: {version}")
|
|
505
|
+
if version != '2.7.0':
|
|
506
|
+
print(f"📦 可更新,运行: pip install --upgrade devtools-hub")
|
|
507
|
+
else:
|
|
508
|
+
print("✅ 已是最新版本")
|
|
509
|
+
except Exception as e:
|
|
510
|
+
print(f"❌ 检查失败: {e}")
|
|
511
|
+
|
|
512
|
+
elif cmd == "start":
|
|
513
|
+
print("🚀 启动服务...")
|
|
514
|
+
subprocess.Popen([sys.executable, "-m", "devtools_hub.server"],
|
|
515
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
516
|
+
time.sleep(2)
|
|
517
|
+
print(f"✅ 已启动: {URL}")
|
|
518
|
+
|
|
519
|
+
elif cmd == "stop":
|
|
520
|
+
subprocess.run(["pkill", "-f", "devtools_hub.server"])
|
|
521
|
+
print("✅ 已停止")
|
|
522
|
+
|
|
523
|
+
else:
|
|
524
|
+
print(f"❌ 未知命令: {cmd}")
|
|
525
|
+
|
|
526
|
+
if __name__ == "__main__":
|
|
527
|
+
main()
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""DevTools Hub CLI"""
|
|
3
|
-
import sys
|
|
4
|
-
import subprocess
|
|
5
|
-
import json
|
|
6
|
-
import time
|
|
7
|
-
import platform
|
|
8
|
-
|
|
9
|
-
PORT = 5001
|
|
10
|
-
URL = f"http://localhost:{PORT}"
|
|
11
|
-
|
|
12
|
-
def check():
|
|
13
|
-
try:
|
|
14
|
-
import requests
|
|
15
|
-
r = requests.get(f"{URL}/api/health", timeout=1)
|
|
16
|
-
return r.ok
|
|
17
|
-
except:
|
|
18
|
-
return False
|
|
19
|
-
|
|
20
|
-
def main():
|
|
21
|
-
if len(sys.argv) < 2:
|
|
22
|
-
print("""
|
|
23
|
-
🔧 DevTools Hub - 开发者工具集
|
|
24
|
-
|
|
25
|
-
用法: devtools <命令>
|
|
26
|
-
|
|
27
|
-
命令:
|
|
28
|
-
start 启动服务
|
|
29
|
-
stop 停止服务
|
|
30
|
-
status 系统状态
|
|
31
|
-
cpu CPU 信息
|
|
32
|
-
mem 内存信息
|
|
33
|
-
disk 磁盘信息
|
|
34
|
-
net 网络速度
|
|
35
|
-
top 高占用进程
|
|
36
|
-
ports 端口扫描
|
|
37
|
-
services 系统服务
|
|
38
|
-
info 系统信息
|
|
39
|
-
ip IP 地址
|
|
40
|
-
bench 性能测试
|
|
41
|
-
""")
|
|
42
|
-
return
|
|
43
|
-
|
|
44
|
-
cmd = sys.argv[1]
|
|
45
|
-
|
|
46
|
-
if cmd == "start":
|
|
47
|
-
print("🚀 启动服务...")
|
|
48
|
-
subprocess.Popen([sys.executable, "-m", "devtools_hub.server"],
|
|
49
|
-
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
50
|
-
time.sleep(2)
|
|
51
|
-
print(f"✅ 已启动: {URL}")
|
|
52
|
-
|
|
53
|
-
elif cmd == "stop":
|
|
54
|
-
subprocess.run(["pkill", "-f", "devtools_hub.server"])
|
|
55
|
-
print("✅ 已停止")
|
|
56
|
-
|
|
57
|
-
elif cmd == "status":
|
|
58
|
-
if check():
|
|
59
|
-
import requests
|
|
60
|
-
r = requests.get(f"{URL}/api/health")
|
|
61
|
-
print(json.dumps(r.json(), indent=2))
|
|
62
|
-
else:
|
|
63
|
-
print("❌ 服务未运行,请先 devtools start")
|
|
64
|
-
|
|
65
|
-
elif cmd == "cpu":
|
|
66
|
-
import psutil
|
|
67
|
-
print(f"CPU: {psutil.cpu_percent()}% 核心: {psutil.cpu_count()}")
|
|
68
|
-
|
|
69
|
-
elif cmd == "mem":
|
|
70
|
-
import psutil
|
|
71
|
-
m = psutil.virtual_memory()
|
|
72
|
-
print(f"内存: {m.percent}% 可用: {m.available/1024**3:.1f}GB")
|
|
73
|
-
|
|
74
|
-
elif cmd == "disk":
|
|
75
|
-
import psutil
|
|
76
|
-
d = psutil.disk_usage('/')
|
|
77
|
-
print(f"磁盘: {d.percent}% 可用: {d.free/1024**3:.1f}GB")
|
|
78
|
-
|
|
79
|
-
elif cmd == "net":
|
|
80
|
-
if check():
|
|
81
|
-
import requests
|
|
82
|
-
r = requests.get(f"{URL}/api/network/bandwidth")
|
|
83
|
-
d = r.json()
|
|
84
|
-
print(f"↑{d.get('upload_mbps', 0)} Mbps ↓{d.get('download_mbps', 0)} Mbps")
|
|
85
|
-
else:
|
|
86
|
-
print("❌ 服务未运行")
|
|
87
|
-
|
|
88
|
-
elif cmd == "top":
|
|
89
|
-
import psutil
|
|
90
|
-
procs = []
|
|
91
|
-
for p in psutil.process_iter(['name', 'cpu_percent', 'memory_percent']):
|
|
92
|
-
try:
|
|
93
|
-
procs.append(p.info)
|
|
94
|
-
except:
|
|
95
|
-
pass
|
|
96
|
-
by_cpu = sorted(procs, key=lambda x: x['cpu_percent'] or 0, reverse=True)[:5]
|
|
97
|
-
by_mem = sorted(procs, key=lambda x: x['memory_percent'] or 0, reverse=True)[:5]
|
|
98
|
-
print("🔥 CPU:")
|
|
99
|
-
for p in by_cpu:
|
|
100
|
-
print(f" {p['name']}: {p['cpu_percent']}%")
|
|
101
|
-
print("💾 内存:")
|
|
102
|
-
for p in by_mem:
|
|
103
|
-
print(f" {p['name']}: {p['memory_percent']}%")
|
|
104
|
-
|
|
105
|
-
elif cmd == "ports":
|
|
106
|
-
from devtools_hub.scanner import scan_common_ports
|
|
107
|
-
print("🔍 扫描常用端口...")
|
|
108
|
-
ports = scan_common_ports()
|
|
109
|
-
if ports:
|
|
110
|
-
for p in ports:
|
|
111
|
-
print(f" ✅ {p['port']} ({p['name']}) - 开放")
|
|
112
|
-
else:
|
|
113
|
-
print(" 未发现开放端口")
|
|
114
|
-
|
|
115
|
-
elif cmd == "services":
|
|
116
|
-
from devtools_hub.scanner import get_services
|
|
117
|
-
print("📋 系统服务:")
|
|
118
|
-
services = get_services()
|
|
119
|
-
for s in services[:10]:
|
|
120
|
-
print(f" [{s['pid']}] {s['name']}")
|
|
121
|
-
|
|
122
|
-
elif cmd == "info":
|
|
123
|
-
print(f"""
|
|
124
|
-
系统信息:
|
|
125
|
-
系统: {platform.system()} {platform.release()}
|
|
126
|
-
主机: {platform.node()}
|
|
127
|
-
处理器: {platform.processor()}
|
|
128
|
-
Python: {platform.python_version()}
|
|
129
|
-
""")
|
|
130
|
-
|
|
131
|
-
elif cmd == "ip":
|
|
132
|
-
import socket
|
|
133
|
-
hostname = socket.gethostname()
|
|
134
|
-
ip = socket.gethostbyname(hostname)
|
|
135
|
-
print(f"主机: {hostname}")
|
|
136
|
-
print(f"IP: {ip}")
|
|
137
|
-
|
|
138
|
-
elif cmd == "bench":
|
|
139
|
-
if check():
|
|
140
|
-
import requests
|
|
141
|
-
r = requests.get(f"{URL}/api/benchmark/full")
|
|
142
|
-
print(json.dumps(r.json(), indent=2))
|
|
143
|
-
else:
|
|
144
|
-
print("❌ 服务未运行")
|
|
145
|
-
|
|
146
|
-
else:
|
|
147
|
-
print(f"❌ 未知命令: {cmd}")
|
|
148
|
-
|
|
149
|
-
if __name__ == "__main__":
|
|
150
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|