openclaw-sc 5.38.0

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.
Files changed (48) hide show
  1. package/.env.example +13 -0
  2. package/INSTALL.md +13 -0
  3. package/LICENSE +233 -0
  4. package/README.md +123 -0
  5. package/SECURITY.md +27 -0
  6. package/index.js +3479 -0
  7. package/lib/code-review-shared.js +164 -0
  8. package/lib/config.js +164 -0
  9. package/lib/constants.js +438 -0
  10. package/lib/decomposer.js +896 -0
  11. package/lib/dialog-recall.js +389 -0
  12. package/lib/env.js +59 -0
  13. package/lib/level-rules.js +72 -0
  14. package/lib/log-manager.js +258 -0
  15. package/lib/preemption.js +278 -0
  16. package/lib/priority-calc.js +134 -0
  17. package/lib/prompt-injection.js +748 -0
  18. package/lib/route-evidence.js +701 -0
  19. package/lib/shared-fs.js +244 -0
  20. package/lib/steward-rules.js +648 -0
  21. package/lib/task-center.js +602 -0
  22. package/lib/task-chain.js +713 -0
  23. package/lib/task-checker.js +317 -0
  24. package/lib/task-profiles.js +255 -0
  25. package/lib/tcell.js +411 -0
  26. package/lib/tool-auto-discover.js +522 -0
  27. package/lib/tool-enrich-subagent.js +375 -0
  28. package/lib/tool-handlers.js +178 -0
  29. package/lib/tool-selector.js +459 -0
  30. package/openclaw.plugin.json +55 -0
  31. package/package.json +63 -0
  32. package/security.js +141 -0
  33. package/tools/bridge.js +3288 -0
  34. package/tools/dashboard/tk-dashboard.py +262 -0
  35. package/tools/hippocampus-multi-search.js +1038 -0
  36. package/tools/hippocampus-sqlite.js +738 -0
  37. package/tools/hippocampus-store.js +262 -0
  38. package/tools/mcp-tools.config.json +653 -0
  39. package/tools/pipeline-engine.js +667 -0
  40. package/tools/sidecar/_check_tools.py +34 -0
  41. package/tools/sidecar/sidecar-server.cjs +1360 -0
  42. package/tools/sidecar/subagent-runner.cjs +1471 -0
  43. package/tools/system-tools.js +619 -0
  44. package/vector/README.md +100 -0
  45. package/vector/usearch-bridge.js +639 -0
  46. package/vector/usearch-http.js +74 -0
  47. package/vector/usearch-serve.js +156 -0
  48. package/workers/worker.js +1419 -0
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 杉杉CPU · 丝滑动画悬浮窗 (340×420)
4
+ 数据源: http://127.0.0.1:18790/health
5
+ 零依赖,仅 Python 标准库
6
+ """
7
+
8
+ import tkinter as tk
9
+ import ctypes
10
+ import json
11
+ import urllib.request
12
+ import threading
13
+ import os
14
+ import platform
15
+
16
+ # MCP 端口:优先从环境变量读取,否则默认 18790
17
+ MCP_HOST = os.environ.get("MCP_HOST", "127.0.0.1")
18
+ MCP_PORT = os.environ.get("MCP_PORT", "18790")
19
+ HEALTH_URL = f"http://{MCP_HOST}:{MCP_PORT}/health"
20
+ REFRESH_MS = 3000 # 3秒刷新,避免1秒一次太频繁
21
+
22
+ # 连接状态
23
+ _connection_ok = True
24
+
25
+ try:
26
+ ctypes.windll.shcore.SetProcessDpiAwareness(2)
27
+ except:
28
+ try:
29
+ ctypes.windll.user32.SetProcessDPIAware()
30
+ except:
31
+ pass
32
+
33
+ class LobsterSmoothAnimationUI:
34
+ def __init__(self):
35
+ self.root = tk.Tk()
36
+ self.width = 340
37
+ self.collapsed_height = 42
38
+ self.expanded_height = 420
39
+ self.current_height = self.collapsed_height
40
+ self.is_expanding = False
41
+ self.animation_timer = None
42
+ self.data = {}
43
+
44
+ # 窗口初始位置:屏幕居中偏右上(根据不同分辨率自适应)
45
+ screen_w = self.root.winfo_screenwidth()
46
+ screen_h = self.root.winfo_screenheight()
47
+ init_x = min(screen_w - self.width - 20, screen_w - 380)
48
+ init_y = 20
49
+ self.root.geometry(f"{self.width}x{self.collapsed_height}+{init_x}+{init_y}")
50
+ self.root.overrideredirect(True)
51
+ self.root.config(bg='#020202')
52
+ self.root.attributes("-transparentcolor", "#020202")
53
+ self.root.attributes("-topmost", True)
54
+
55
+ self.canvas = tk.Canvas(self.root, bg="#020202", bd=0, highlightthickness=0)
56
+ self.canvas.place(x=0, y=0, width=self.width, height=self.expanded_height)
57
+
58
+ self.main_container = tk.Frame(self.root, bg="#12131A", bd=0)
59
+ self.main_container.place(x=1, y=1, width=self.width-2, height=self.expanded_height-2)
60
+ self.refresh_bg(self.collapsed_height)
61
+ self.setup_widgets()
62
+
63
+ self.main_container.bind("<Enter>", self.on_mouse_enter)
64
+ self.main_container.bind("<Leave>", self.on_mouse_leave)
65
+ self.main_container.bind("<Button-1>", self.start_drag)
66
+ self.main_container.bind("<B1-Motion>", self.drag)
67
+ self.root.bind("<Escape>", lambda e: self.root.destroy())
68
+
69
+ def refresh_bg(self, current_height):
70
+ self.canvas.delete("all")
71
+ radius = 14
72
+ x1, y1, x2, y2 = 0, 0, self.width, current_height
73
+ pts = [x1+radius,y1, x2-radius,y1, x2,y1, x2,y1+radius, x2,y2-radius, x2,y2, x2-radius,y2, x1+radius,y2, x1,y2, x1,y2-radius, x1,y1+radius, x1,y1]
74
+ self.canvas.create_polygon(pts, fill="#12131A", outline="#2A2B36", width=1, smooth=True)
75
+
76
+ def animate_size(self, target_height):
77
+ if self.animation_timer:
78
+ self.root.after_cancel(self.animation_timer)
79
+ diff = target_height - self.current_height
80
+ if abs(diff) > 2:
81
+ step = int(diff * 0.35)
82
+ if step == 0: step = 1 if diff > 0 else -1
83
+ self.current_height += step
84
+ x, y = self.root.winfo_x(), self.root.winfo_y()
85
+ self.root.geometry(f"{self.width}x{self.current_height}+{x}+{y}")
86
+ self.refresh_bg(self.current_height)
87
+ self.animation_timer = self.root.after(10, lambda: self.animate_size(target_height))
88
+ else:
89
+ self.current_height = target_height
90
+ x, y = self.root.winfo_x(), self.root.winfo_y()
91
+ self.root.geometry(f"{self.width}x{self.current_height}+{x}+{y}")
92
+ self.refresh_bg(self.current_height)
93
+ if target_height == self.expanded_height:
94
+ self.content_frame.pack(fill="both", expand=True, padx=12, pady=(0,10))
95
+
96
+ def on_mouse_enter(self, event):
97
+ self.is_expanding = True
98
+ self.animate_size(self.expanded_height)
99
+
100
+ def on_mouse_leave(self, event):
101
+ x, y = self.root.winfo_pointerxy()
102
+ wx, wy = self.root.winfo_x(), self.root.winfo_y()
103
+ if not (wx <= x <= wx + self.width and wy <= y <= wy + self.expanded_height):
104
+ self.is_expanding = False
105
+ self.content_frame.pack_forget()
106
+ self.animate_size(self.collapsed_height)
107
+
108
+ def setup_widgets(self):
109
+ self.top_bar = tk.Frame(self.main_container, bg="#12131A")
110
+ self.top_bar.pack(fill="x", padx=14, pady=(10,4))
111
+ self.top_bar.bind("<Button-1>", self.start_drag)
112
+ self.top_bar.bind("<B1-Motion>", self.drag)
113
+
114
+ title = tk.Label(self.top_bar, text="杉杉CPU · 📊 仪表盘",
115
+ bg="#12131A", fg="#A0A5B5",
116
+ font=("Microsoft YaHei", 9, "bold"))
117
+ title.pack(side="left")
118
+ title.bind("<Button-1>", self.start_drag)
119
+ title.bind("<B1-Motion>", self.drag)
120
+
121
+ top_tip = tk.Label(self.top_bar, text="[自动展开]",
122
+ bg="#12131A", fg="#707585",
123
+ font=("Microsoft YaHei", 8))
124
+ top_tip.pack(side="right")
125
+
126
+ self.content_frame = tk.Frame(self.main_container, bg="#12131A")
127
+
128
+ # B. 核心卡片
129
+ core = tk.Frame(self.content_frame, bg="#12131A")
130
+ core.pack(fill="x", pady=6)
131
+
132
+ f_eff = tk.Frame(core, bg="#1A1B24", width=150, height=68)
133
+ f_eff.pack_propagate(False)
134
+ f_eff.pack(side="left", expand=True, padx=(0,4))
135
+ tk.Label(f_eff, text="N 效率因子", bg="#1A1B24", fg="#707585",
136
+ font=("Microsoft YaHei", 8)).pack(anchor="w", padx=10, pady=(6,0))
137
+ self.lbl_eff = tk.Label(f_eff, text="0.00", bg="#1A1B24", fg="#FFB84D",
138
+ font=("Arial", 16, "bold"))
139
+ self.lbl_eff.pack(anchor="w", padx=10)
140
+
141
+ f_meta = tk.Frame(core, bg="#1A1B24", width=150, height=68)
142
+ f_meta.pack_propagate(False)
143
+ f_meta.pack(side="right", expand=True, padx=(4,0))
144
+ tk.Label(f_meta, text="H 代谢率", bg="#1A1B24", fg="#707585",
145
+ font=("Microsoft YaHei", 8)).pack(anchor="w", padx=10, pady=(6,0))
146
+ self.lbl_meta = tk.Label(f_meta, text="0 /s", bg="#1A1B24", fg="#FFFFFF",
147
+ font=("Arial", 16, "bold"))
148
+ self.lbl_meta.pack(anchor="w", padx=10)
149
+
150
+ # C. Worker
151
+ f_worker = tk.Frame(self.content_frame, bg="#1A1B24", height=72)
152
+ f_worker.pack_propagate(False)
153
+ f_worker.pack(fill="x", pady=6)
154
+ tk.Label(f_worker, text="WORKER 池 & 队列", bg="#1A1B24", fg="#707585",
155
+ font=("Microsoft YaHei", 8)).pack(anchor="w", padx=12, pady=(6,0))
156
+ self.lbl_worker_stat = tk.Label(f_worker, text="0 / 12", bg="#1A1B24", fg="#00FF66",
157
+ font=("Arial", 14, "bold"))
158
+ self.lbl_worker_stat.pack(side="left", padx=12, pady=(0,4))
159
+ self.lbl_queue_detail = tk.Label(f_worker, text="等待: 0 | 高: 0 | 普: 0",
160
+ bg="#1A1B24", fg="#A0A5B5",
161
+ font=("Microsoft YaHei", 8))
162
+ self.lbl_queue_detail.pack(side="right", padx=12, pady=(0,4))
163
+
164
+ # D. 内存
165
+ f_mem = tk.Frame(self.content_frame, bg="#1A1B24")
166
+ f_mem.pack(fill="x", pady=6)
167
+ self.lbl_mem_title = tk.Label(f_mem, text="内存水位 (状态: 充足)",
168
+ bg="#1A1B24", fg="#707585",
169
+ font=("Microsoft YaHei", 8))
170
+ self.lbl_mem_title.pack(anchor="w", padx=12, pady=(8,2))
171
+ self.lbl_mem_val = tk.Label(f_mem, text="-- GB", bg="#1A1B24", fg="#00FF66",
172
+ font=("Arial", 18, "bold"))
173
+ self.lbl_mem_val.pack(anchor="w", padx=12)
174
+ self.lbl_mem_detail = tk.Label(f_mem, text="已使用 --% | 总计 -- GB",
175
+ bg="#1A1B24", fg="#505565",
176
+ font=("Microsoft YaHei", 8))
177
+ self.lbl_mem_detail.pack(anchor="w", padx=12, pady=(2,10))
178
+
179
+ # E. 底部
180
+ self.lbl_status = tk.Label(self.content_frame,
181
+ text="🤖 子 AGENT:0 活跃 / 0 总计",
182
+ bg="#12131A", fg="#00FF66",
183
+ font=("Microsoft YaHei", 8, "bold"))
184
+ self.lbl_status.pack(side="bottom", pady=(10,2))
185
+
186
+ # 连接状态指示(显示在 status 下方)
187
+ self.lbl_conn = tk.Label(self.content_frame,
188
+ text="", bg="#12131A", fg="#FF5555",
189
+ font=("Microsoft YaHei", 7))
190
+ self.lbl_conn.pack(side="bottom", pady=(0,4))
191
+
192
+ # 数据更新
193
+ self._tick()
194
+
195
+ def _tick(self):
196
+ threading.Thread(target=self._fetch, daemon=True).start()
197
+ self.root.after(REFRESH_MS, self._tick)
198
+
199
+ def _fetch(self):
200
+ global _connection_ok
201
+ try:
202
+ req = urllib.request.Request(HEALTH_URL, headers={"User-Agent":"SmoothDash"})
203
+ with urllib.request.urlopen(req, timeout=3) as r:
204
+ self.data = json.loads(r.read().decode())
205
+ _connection_ok = True
206
+ except Exception as e:
207
+ self.data = {}
208
+ _connection_ok = False
209
+ self._last_error = str(e)
210
+ self.root.after(0, self._upd)
211
+
212
+ def _upd(self):
213
+ d, p = self.data, self.data.get("pool", {})
214
+ total, busy = p.get("total", 0), p.get("busy", 0)
215
+ nu = busy / max(total, 1)
216
+ self.lbl_eff.config(text=f"{nu:.2f}")
217
+ eta = busy + p.get("inFlight", 0)
218
+ self.lbl_meta.config(text=f"{eta} /s")
219
+ self.lbl_worker_stat.config(text=f"{busy} / {p.get('maxWorkers',12)}")
220
+ qd, qh, qn = p.get("queueDepth",0), p.get("queueHigh",0), p.get("queueNormal",0)
221
+ self.lbl_queue_detail.config(text=f"等待: {qd} | 高: {qh} | 普: {qn}")
222
+ mem = d.get("memory", {})
223
+ free_gb = mem.get("freeGB", "--")
224
+ used_pct = mem.get("usedPct", "--")
225
+ total_gb = mem.get("totalGB", "--")
226
+ level = mem.get("level", "green")
227
+ label = mem.get("label", "充足")
228
+ self.lbl_mem_title.config(text=f"内存水位 (状态: {label})")
229
+ mem_c = "#FF5555" if level in ("red","meltdown") else "#FFB84D" if level=="yellow" else "#00FF66"
230
+ self.lbl_mem_val.config(text=f"{free_gb} GB", fg=mem_c)
231
+ self.lbl_mem_detail.config(text=f"已使用 {used_pct}% | 总计 {total_gb} GB")
232
+ active = d.get("userActive")
233
+ if active is True:
234
+ self.lbl_status.config(text="🟢 用户:在线", fg="#00FF66")
235
+ elif active is False:
236
+ self.lbl_status.config(text="🔴 用户:离线", fg="#FF5555")
237
+
238
+ # 连接状态
239
+ if not _connection_ok:
240
+ self.lbl_conn.config(text=f"⚠ MCP 连接失败 ({MCP_HOST}:{MCP_PORT})", fg="#FF5555")
241
+ else:
242
+ self.lbl_conn.config(text="")
243
+
244
+ def start_drag(self, event):
245
+ self.x, self.y = event.x, event.y
246
+
247
+ def drag(self, event):
248
+ x = self.root.winfo_x() + event.x - self.x
249
+ y = self.root.winfo_y() + event.y - self.y
250
+ # 防拖出屏幕外(保留最小可见区域)
251
+ screen_w = self.root.winfo_screenwidth()
252
+ screen_h = self.root.winfo_screenheight()
253
+ x = max(-self.width + 40, min(x, screen_w - 40))
254
+ y = max(0, min(y, screen_h - 40))
255
+ self.root.geometry(f"+{x}+{y}")
256
+
257
+ def run(self):
258
+ self.root.mainloop()
259
+
260
+ if __name__ == "__main__":
261
+ app = LobsterSmoothAnimationUI()
262
+ app.run()