feat: deploy Codeg multi-agent workspace, Gitea hot/cold storage hub, and grill-me skill

Browse Source
This commit is contained in:
Yin Kou committed 2026-11-07 01:41:54 +08:00
1 parent c4f54203a4
commit 01a4681f98
18 files changed
+1238 -252

No files matched your search

+122 -1
View File
@@ -268,24 +268,134 @@ def get_network_and_edge_stats() -> dict:
} }
def _codeg_call(endpoint: str, payload=None) -> object:
try:
req = urllib.request.Request(
f"http://127.0.0.1:3080/api/{endpoint}",
data=json.dumps(payload or {}).encode("utf-8"),
headers={
"Authorization": "Bearer homelab2026",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req, timeout=2.0) as r:
return json.loads(r.read().decode("utf-8"))
except Exception:
return None
def get_agents_and_git_overview() -> dict:
codeg_ok, codeg_ms = check_tcp("127.0.0.1", 3080)
gitea_ok, gitea_ms = check_tcp("127.0.0.1", 3005)
assistants = _codeg_call("assistant_list") if codeg_ok else []
folders = _codeg_call("list_folders") if codeg_ok else []
conversations = _codeg_call("list_conversations") if codeg_ok else []
stats = _codeg_call("get_stats") if codeg_ok else {}
# Query local Gitea repositories
repos = []
if gitea_ok:
try:
with urllib.request.urlopen("http://127.0.0.1:3005/api/v1/repos/search?limit=10", timeout=2.0) as r:
rdata = json.loads(r.read().decode("utf-8"))
for item in rdata.get("data", []):
repos.append(
{
"name": item.get("full_name"),
"description": item.get("description", ""),
"default_branch": item.get("default_branch", "main"),
"updated_at": item.get("updated_at", ""),
"size_kb": item.get("size", 0),
"html_url": item.get("html_url", ""),
"clone_url": item.get("clone_url", ""),
"ssh_url": item.get("ssh_url", ""),
}
)
except Exception:
pass
# Query active tmux windows in 'agy' session
tmux_windows = []
try:
out = run_cmd("/opt/homebrew/bin/tmux list-windows -t agy -F '#{window_index}|#{window_name}|#{window_active}|#{pane_current_command}'", timeout=1.5)
for line in out.splitlines():
parts = line.split("|")
if len(parts) >= 4:
tmux_windows.append(
{
"index": parts[0],
"name": parts[1],
"active": parts[2] == "1",
"command": parts[3],
}
)
except Exception:
pass
# Check ZSpace NAS Git Cold Storage bundles
cold_dir = Path("/Users/ixvii0iv/nas/个人空间/Git_Cold_Storage/bundles")
cold_bundles = []
try:
if cold_dir.exists():
for f in sorted(cold_dir.glob("*.bundle")):
st = f.stat()
cold_bundles.append(
{
"name": f.name,
"size_mb": round(st.st_size / (1024 * 1024), 2),
"mtime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(st.st_mtime)),
}
)
except Exception:
pass
return {
"codeg": {
"online": codeg_ok,
"latency_ms": codeg_ms,
"version": "0.42.0",
"assistants": assistants if isinstance(assistants, list) else [],
"folders": folders if isinstance(folders, list) else [],
"conversations": conversations if isinstance(conversations, list) else [],
"stats": stats if isinstance(stats, dict) else {},
},
"gitea": {
"online": gitea_ok,
"latency_ms": gitea_ms,
"version": "28.3.0",
"hot_path": "/Users/ixvii0iv/homelab/stacks/git/data",
"cold_path": "/Users/ixvii0iv/nas/个人空间/Git_Cold_Storage",
"repos": repos,
"cold_bundles": cold_bundles,
},
"tmux_windows": tmux_windows,
}
def collect_telemetry() -> dict: def collect_telemetry() -> dict:
now = time.time() now = time.time()
with _cache_lock: with _cache_lock:
if _cache["data"] and (now - _cache["ts"] < 2.0): if _cache["data"] and (now - _cache["ts"] < 2.0):
return _cache["data"] return _cache["data"]
with ThreadPoolExecutor(max_workers=4) as pool: with ThreadPoolExecutor(max_workers=6) as pool:
f_mini = pool.submit(get_mac_mini_stats) f_mini = pool.submit(get_mac_mini_stats)
f_nas = pool.submit(get_nas_stats) f_nas = pool.submit(get_nas_stats)
f_net = pool.submit(get_network_and_edge_stats) f_net = pool.submit(get_network_and_edge_stats)
f_agy = pool.submit(check_tcp, "127.0.0.1", 7681) f_agy = pool.submit(check_tcp, "127.0.0.1", 7681)
f_vw = pool.submit(check_tcp, "127.0.0.1", 8222) f_vw = pool.submit(check_tcp, "127.0.0.1", 8222)
f_codeg = pool.submit(check_tcp, "127.0.0.1", 3080)
f_gitea = pool.submit(check_tcp, "127.0.0.1", 3005)
mini = f_mini.result() mini = f_mini.result()
nas = f_nas.result() nas = f_nas.result()
net = f_net.result() net = f_net.result()
agy_ok, _ = f_agy.result() agy_ok, _ = f_agy.result()
vw_ok, _ = f_vw.result() vw_ok, _ = f_vw.result()
codeg_ok, _ = f_codeg.result()
gitea_ok, _ = f_gitea.result()
data = { data = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
@@ -294,6 +404,8 @@ def collect_telemetry() -> dict:
"network": net, "network": net,
"services": { "services": {
"agy": agy_ok, "agy": agy_ok,
"codeg": codeg_ok,
"gitea": gitea_ok,
"vaultwarden": vw_ok, "vaultwarden": vw_ok,
"nas": nas["online"], "nas": nas["online"],
"clash": net["router_online"], "clash": net["router_online"],
@@ -394,6 +506,11 @@ class PortalHandler(BaseHTTPRequestHandler):
self._send_json(clawbot_mgr.get_public_status()) self._send_json(clawbot_mgr.get_public_status())
return return
# 3c. Agent Orchestrator & Gitea Cold/Hot Storage overview (/api/agents/overview)
if self.path.startswith("/api/agents/overview"):
self._send_json(get_agents_and_git_overview())
return
# 4. Serve static assets from Vite build output (dist/) if available # 4. Serve static assets from Vite build output (dist/) if available
clean_path = self.path.split("?", 1)[0].lstrip("/") clean_path = self.path.split("?", 1)[0].lstrip("/")
if clean_path and DIST_DIR.exists(): if clean_path and DIST_DIR.exists():
@@ -506,6 +623,10 @@ class PortalHandler(BaseHTTPRequestHandler):
_cache["ts"] = 0.0 _cache["ts"] = 0.0
self._send_json({"ok": True, "message": out or "Cloudflare DDNS 已刷新"}) self._send_json({"ok": True, "message": out or "Cloudflare DDNS 已刷新"})
return return
if self.path == "/api/action/sync_git_nas":
out = run_cmd("/Users/ixvii0iv/homelab/scripts/sync-git-to-nas.sh", timeout=20.0)
self._send_json({"ok": True, "message": out or "Git 热层与极空间 20TB 冷备归档已同步"})
return
self._send_json({"ok": False, "message": "Unknown action"}, status=404) self._send_json({"ok": False, "message": "Unknown action"}, status=404)