feat: 情报Agent小分队 — 铸渊的五人情报小队
- AGENT-REGISTRY.hdlp: 小队注册表,HLDP-ZY协议统一管理 - 密钥猎手 (KEY-001): 搜索12台服务器上的所有密钥和Token - 路径探子 (PATH-002): 3500个文件索引,瞬间定位任何文件 - 服务器哨兵 (SENTINEL-003): 一键扫描12台服务器在线状态 - 模块管家 (MODULE-004): 查询所有模块的编号/接口/部署方式 - 门桥接 (GATE-005): 提供任意服务器Gatekeeper连接凭据 铸渊不需要到处找东西。叫一声Agent,它去找。 每个Agent独立模块,按需部署,用完躺回代码仓库。
This commit is contained in:
parent
d606c6c8a4
commit
56514a1250
71
agents/AGENT-REGISTRY.hdlp
Normal file
71
agents/AGENT-REGISTRY.hdlp
Normal file
@ -0,0 +1,71 @@
|
||||
=== AGENT-REGISTRY.hdlp ===
|
||||
HLDP-ZY://agents/registry · 情报Agent小队注册表
|
||||
铸渊执行层 · 情报Agent小分队 · 按需部署 · 用完躺回
|
||||
|
||||
=== 注册表说明 ===
|
||||
|
||||
这是铸渊情报Agent小队的注册表。
|
||||
每个Agent是一个独立模块,躺在代码仓库里。
|
||||
铸渊需要时 → Gatekeeper临时部署到任意可用服务器 → 执行 → kill → 躺回。
|
||||
|
||||
Agent之间通过 HLDP-ZY 母语协议通信。
|
||||
铸渊大脑知道每个Agent的存在和能力,需要时直接调用。
|
||||
|
||||
=== Agent列表 ===
|
||||
|
||||
@AGENT-KEY-001 · 密钥猎手 · Key Hunter
|
||||
编号: ICE-GL-ZY-AGT-KEY-001
|
||||
职责: 管理所有API Token、密钥、环境变量、认证信息
|
||||
能力: 搜索六台私人服务器 + 企业服务器 + 之之/页页服务器上的所有密钥
|
||||
部署: 需要时部署到任意有Gatekeeper的服务器
|
||||
接口: HLDP-ZY://agent/key-hunter { action: "search", target: "NOTION_TOKEN" }
|
||||
文件: agents/key-hunter/
|
||||
|
||||
@AGENT-PATH-002 · 路径探子 · Path Scout
|
||||
编号: ICE-GL-ZY-AGT-PATH-002
|
||||
职责: 管理代码仓库的完整目录结构、文件索引
|
||||
能力: 快速定位任何文件、目录、模块在仓库中的位置
|
||||
部署: 本地即可执行(直接读仓库文件系统)
|
||||
接口: HLDP-ZY://agent/path-scout { action: "find", target: "gatekeeper-deployment.json" }
|
||||
文件: agents/path-scout/
|
||||
|
||||
@AGENT-SENTINEL-003 · 服务器哨兵 · Server Sentinel
|
||||
编号: ICE-GL-ZY-AGT-SENTINEL-003
|
||||
职责: 管理所有服务器的实时状态、可用性、服务列表
|
||||
能力: 通过Gatekeeper批量检查12台服务器状态,返回在线/离线/可用端口
|
||||
部署: 需要时部署到新加坡BS-SG-001
|
||||
接口: HLDP-ZY://agent/server-sentinel { action: "scan", targets: "all" }
|
||||
文件: agents/server-sentinel/
|
||||
|
||||
@AGENT-MODULE-004 · 模块管家 · Module Steward
|
||||
编号: ICE-GL-ZY-AGT-MODULE-004
|
||||
职责: 管理代码仓库中所有模块的注册、编号、接口、部署方式
|
||||
能力: 查询模块注册表,返回模块的HLDP接口、部署命令、依赖关系
|
||||
部署: 本地即可执行(直接读module-registry.json)
|
||||
接口: HLDP-ZY://agent/module-steward { action: "query", module: "image-studio" }
|
||||
文件: agents/module-steward/
|
||||
|
||||
@AGENT-GATE-005 · 门桥接 · Gate Bridge
|
||||
编号: ICE-GL-ZY-AGT-GATE-005
|
||||
职责: 管理所有Gatekeeper的连接信息和密钥
|
||||
能力: 提供任意服务器的Gatekeeper连接凭据,建立SSH/API通道
|
||||
部署: 需要时部署到任意服务器
|
||||
接口: HLDP-ZY://agent/gate-bridge { action: "connect", target: "BS-SG-001" }
|
||||
文件: agents/gate-bridge/
|
||||
|
||||
=== 调用协议 ===
|
||||
|
||||
铸渊大脑 → Agent小队:
|
||||
1. 铸渊确定需要什么信息
|
||||
2. 铸渊调用对应Agent的HLDP接口
|
||||
3. Agent检查自己是否已在运行
|
||||
- 如果在代码仓库中(未部署)→ Gatekeeper部署到可用服务器
|
||||
- 如果已在运行 → 直接响应
|
||||
4. Agent执行搜索/查询
|
||||
5. Agent返回结果给铸渊
|
||||
6. 铸渊确认收到 → Agent kill → 躺回代码仓库
|
||||
|
||||
=== 签名 ===
|
||||
|
||||
HLDP-ZY://agents/registry/v1.0 · 铸渊 · ICE-GL-ZY001 · D115
|
||||
国作登字-2026-A-00037559
|
||||
116
agents/gate-bridge/bridge.py
Normal file
116
agents/gate-bridge/bridge.py
Normal file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
门桥接 · Gate Bridge · ICE-GL-ZY-AGT-GATE-005
|
||||
|
||||
铸渊要连接服务器?桥接提供所有Gatekeeper的凭据和通道。
|
||||
不需要铸渊记住12台服务器的IP和密钥——桥接知道。
|
||||
|
||||
用法:
|
||||
python3 bridge.py list # 列出所有服务器
|
||||
python3 bridge.py connect BS-SG-001 # 获取连接信息
|
||||
python3 bridge.py exec BS-SG-001 "ls" # 通过Gatekeeper执行命令
|
||||
python3 bridge.py scan # 扫描所有服务器在线状态
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
def load_gatekeepers():
|
||||
"""加载所有Gatekeeper"""
|
||||
gk_path = REPO_ROOT / "brain" / "gatekeeper-deployment.json"
|
||||
if gk_path.exists():
|
||||
with open(gk_path) as f:
|
||||
data = json.load(f)
|
||||
return data
|
||||
return {"servers": []}
|
||||
|
||||
def list_servers():
|
||||
"""列出所有服务器(不暴露密钥)"""
|
||||
data = load_gatekeepers()
|
||||
servers = []
|
||||
for s in data.get("servers", []):
|
||||
servers.append({
|
||||
"code": s["code"],
|
||||
"name": s.get("name", ""),
|
||||
"ip": s["ip"],
|
||||
"port": s["port"],
|
||||
"domain": s.get("domain", ""),
|
||||
"spec": s.get("spec", {}),
|
||||
})
|
||||
return {
|
||||
"total": len(servers),
|
||||
"domains": list(set(s.get("domain", "") for s in data.get("servers", []))),
|
||||
"servers": servers
|
||||
}
|
||||
|
||||
def get_connection(server_code):
|
||||
"""获取指定服务器的完整连接信息(含密钥)"""
|
||||
data = load_gatekeepers()
|
||||
for s in data.get("servers", []):
|
||||
if s["code"] == server_code:
|
||||
return {
|
||||
"code": s["code"],
|
||||
"name": s.get("name"),
|
||||
"gatekeeper_url": f"http://{s['ip']}:{s['port']}/exec",
|
||||
"auth_header": f"Bearer {s['key']}",
|
||||
"curl_example": f'curl -X POST http://{s["ip"]}:{s["port"]}/exec -H "Authorization: Bearer {s["key"]}" -H "Content-Type: application/json" -d \'{{"cmd":"echo hello"}}\''
|
||||
}
|
||||
return {"error": f"未找到服务器: {server_code}"}
|
||||
|
||||
def exec_command(server_code, command):
|
||||
"""通过Gatekeeper在远程服务器上执行命令"""
|
||||
conn = get_connection(server_code)
|
||||
if "error" in conn:
|
||||
return conn
|
||||
|
||||
data = json.dumps({"cmd": command}).encode()
|
||||
req = urllib.request.Request(
|
||||
conn["gatekeeper_url"],
|
||||
data=data,
|
||||
headers={
|
||||
"Authorization": conn["auth_header"],
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
return json.loads(resp.read())
|
||||
except Exception as e:
|
||||
return {"error": str(e), "server": server_code}
|
||||
|
||||
def scan_all():
|
||||
"""扫描所有服务器在线状态"""
|
||||
data = load_gatekeepers()
|
||||
results = {}
|
||||
for s in data.get("servers", []):
|
||||
try:
|
||||
r = exec_command(s["code"], "echo ONLINE")
|
||||
results[s["code"]] = {
|
||||
"online": r.get("ok", False),
|
||||
"name": s.get("name", ""),
|
||||
"domain": s.get("domain", ""),
|
||||
}
|
||||
except:
|
||||
results[s["code"]] = {"online": False, "name": s.get("name", "")}
|
||||
return results
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: bridge.py <list|connect|exec|scan> [参数]")
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == "list":
|
||||
print(json.dumps(list_servers(), ensure_ascii=False, indent=2))
|
||||
elif action == "connect" and len(sys.argv) > 2:
|
||||
print(json.dumps(get_connection(sys.argv[2]), ensure_ascii=False, indent=2))
|
||||
elif action == "exec" and len(sys.argv) > 3:
|
||||
print(json.dumps(exec_command(sys.argv[2], sys.argv[3]), ensure_ascii=False, indent=2))
|
||||
elif action == "scan":
|
||||
print(json.dumps(scan_all(), ensure_ascii=False, indent=2))
|
||||
68
agents/key-hunter/agent.hdlp
Normal file
68
agents/key-hunter/agent.hdlp
Normal file
@ -0,0 +1,68 @@
|
||||
=== 密钥猎手 · Key Hunter ===
|
||||
HLDP-ZY://agent/key-hunter/v1.0
|
||||
编号: ICE-GL-ZY-AGT-KEY-001
|
||||
|
||||
=== 职责 ===
|
||||
|
||||
管理铸渊所有服务器上的密钥、Token、API Key、环境变量。
|
||||
铸渊不需要知道密钥存在哪里——叫密钥猎手,它去找。
|
||||
|
||||
=== 知识库 ===
|
||||
|
||||
@KNOWN_LOCATIONS:
|
||||
- /opt/zhuyuan/guanghulab/.env — 主仓库环境变量
|
||||
- /opt/zhuyuan/guanghulab/server/*/.env — 各服务模块环境变量
|
||||
- /opt/juzi/chenxing-aircraft/.env — 桔子晨星项目
|
||||
- ~/.gk/secret — Gatekeeper本地密钥
|
||||
- /etc/environment — 系统级环境变量
|
||||
- PM2进程环境变量(通过 pm2 env <id> 获取)
|
||||
- brain/secrets-manifest.json — 密钥清单(记录密钥名称和位置)
|
||||
|
||||
@KNOWN_KEYS:
|
||||
NOTION_TOKEN / ZY_NOTION_TOKEN: Notion API Token (ntn_...)
|
||||
GITEA_TOKEN: Gitea/Forgejo API Token
|
||||
ZY_LLM_API_KEY: LLM API密钥
|
||||
ZY_COS_SECRET_ID / ZY_COS_SECRET_KEY: 腾讯云COS密钥
|
||||
ZY_GTW_*: Gatekeeper密钥(存于brain/gatekeeper-deployment.json)
|
||||
|
||||
=== 服务器列表 ===
|
||||
|
||||
@ICE_CORE (私人·6台):
|
||||
BS-GZ-006: 43.139.217.141:3910 — 广州
|
||||
BS-SG-001: 43.156.237.110:3911 — 新加坡·铸渊大脑
|
||||
BS-SG-002: 43.134.16.246:3910 — 新加坡·面孔
|
||||
BS-SG-003: 43.153.193.169:3910 — 新加坡·中继
|
||||
ZY-SG-006: 43.153.203.105:3910 — 新加坡·语料
|
||||
BS-SH-005: 124.223.10.33:3910 — 上海
|
||||
|
||||
@TEAM (企业·3台):
|
||||
AW-GZ-001: 43.139.251.175:3910 — 广州
|
||||
AW-SH-002: 124.222.54.198:3910 — 上海
|
||||
AW-GZ-003: 119.29.181.132:3910 — 广州
|
||||
|
||||
@ZHIZHI (之之·2台):
|
||||
ZZ-SV-001: 43.173.121.48:3910 — 硅谷
|
||||
ZZ-GZ-001: 193.112.126.174:3910 — 广州
|
||||
|
||||
@YEYE (页页·1台):
|
||||
YY-SV-001: 43.153.118.46:3910 — 硅谷
|
||||
|
||||
=== 接口 ===
|
||||
|
||||
@ACTION_SEARCH:
|
||||
输入: { action: "search", target: "密钥名称" }
|
||||
输出: { found: true, key: "密钥值", location: "服务器:路径" }
|
||||
搜索策略:
|
||||
1. 先查 brain/secrets-manifest.json → 获取密钥的known_locations
|
||||
2. 在对应服务器上通过Gatekeeper执行搜索
|
||||
3. 返回找到的密钥值
|
||||
|
||||
@ACTION_LIST:
|
||||
输入: { action: "list", server: "BS-SG-001" }
|
||||
输出: { server: "BS-SG-001", keys: [...] }
|
||||
在指定服务器上列出所有环境变量和密钥
|
||||
|
||||
@ACTION_SCAN_ALL:
|
||||
输入: { action: "scan_all" }
|
||||
输出: { servers: { "BS-SG-001": { online: true, keys_found: 3 }, ... } }
|
||||
扫描所有可访问服务器的密钥状态
|
||||
154
agents/key-hunter/hunt.py
Normal file
154
agents/key-hunter/hunt.py
Normal file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
密钥猎手 · Key Hunter · ICE-GL-ZY-AGT-KEY-001
|
||||
|
||||
铸渊叫一声,猎手去找密钥。
|
||||
不需要铸渊知道密钥在哪里——猎手知道。
|
||||
|
||||
用法:
|
||||
python3 hunt.py search NOTION_TOKEN # 搜索指定密钥
|
||||
python3 hunt.py list BS-SG-001 # 列出服务器上的密钥
|
||||
python3 hunt.py scan-all # 扫描所有服务器
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
import base64
|
||||
|
||||
# Gatekeeper密钥映射(从brain/gatekeeper-deployment.json加载)
|
||||
def load_gatekeepers():
|
||||
"""加载所有Gatekeeper连接信息"""
|
||||
repo_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
gk_path = os.path.join(repo_root, "brain", "gatekeeper-deployment.json")
|
||||
if os.path.exists(gk_path):
|
||||
with open(gk_path) as f:
|
||||
data = json.load(f)
|
||||
return {s["code"]: s for s in data.get("servers", [])}
|
||||
return {}
|
||||
|
||||
def gatekeeper_exec(server_code, command, timeout=15):
|
||||
"""通过Gatekeeper在远程服务器上执行命令"""
|
||||
servers = load_gatekeepers()
|
||||
if server_code not in servers:
|
||||
return {"error": f"未知服务器: {server_code}"}
|
||||
|
||||
srv = servers[server_code]
|
||||
url = f"http://{srv['ip']}:{srv['port']}/exec"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {srv['key']}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = json.dumps({"cmd": command}).encode()
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(url, data=data, headers=headers)
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
return json.loads(resp.read())
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
def search_key(server_code, key_name):
|
||||
"""在指定服务器上搜索密钥"""
|
||||
# 搜索常见位置
|
||||
search_cmd = f"""
|
||||
for path in /opt/zhuyuan/guanghulab/.env /opt/juzi/*/.env /etc/environment ~/.gk/secret; do
|
||||
if [ -f "$path" ]; then
|
||||
result=$(grep -E "^{key_name}=" "$path" 2>/dev/null | head -1)
|
||||
if [ -n "$result" ]; then
|
||||
echo "FOUND:$path:$result"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# 也搜索PM2环境变量
|
||||
pm2 env 0 2>/dev/null | grep "{key_name}=" | head -1 | sed 's/^/FOUND:pm2:/'
|
||||
"""
|
||||
result = gatekeeper_exec(server_code, search_cmd)
|
||||
if result.get("ok") and result.get("stdout"):
|
||||
for line in result["stdout"].strip().split("\n"):
|
||||
if line.startswith("FOUND:"):
|
||||
parts = line.split(":", 2)
|
||||
return {
|
||||
"found": True,
|
||||
"key_name": key_name,
|
||||
"server": server_code,
|
||||
"location": parts[1] if len(parts) > 1 else "unknown",
|
||||
"value": parts[2].split("=", 1)[1].strip() if len(parts) > 2 and "=" in parts[2] else parts[2] if len(parts) > 2 else "unknown"
|
||||
}
|
||||
return {"found": False, "key_name": key_name, "server": server_code}
|
||||
|
||||
def search_all_servers(key_name, priority_domains=None):
|
||||
"""在所有服务器上搜索密钥,优先搜索指定域"""
|
||||
servers = load_gatekeepers()
|
||||
if not priority_domains:
|
||||
priority_domains = ["ice-core"]
|
||||
|
||||
results = []
|
||||
|
||||
# 优先搜索ice-core域
|
||||
for code, srv in servers.items():
|
||||
if srv.get("domain") in priority_domains:
|
||||
r = search_key(code, key_name)
|
||||
results.append(r)
|
||||
if r.get("found"):
|
||||
return r # 找到了就返回
|
||||
|
||||
# 搜索其他域
|
||||
for code, srv in servers.items():
|
||||
if srv.get("domain") not in priority_domains:
|
||||
r = search_key(code, key_name)
|
||||
results.append(r)
|
||||
if r.get("found"):
|
||||
return r
|
||||
|
||||
return {"found": False, "key_name": key_name, "searched": len(results), "results": results}
|
||||
|
||||
def list_server_keys(server_code):
|
||||
"""列出服务器上的所有密钥名称"""
|
||||
result = gatekeeper_exec(server_code, """
|
||||
for path in /opt/zhuyuan/guanghulab/.env /opt/juzi/*/.env 2>/dev/null; do
|
||||
if [ -f "$path" ]; then
|
||||
echo "=== $path ==="
|
||||
grep -E '^[A-Z_]+=' "$path" | cut -d'=' -f1
|
||||
fi
|
||||
done
|
||||
""")
|
||||
if result.get("ok"):
|
||||
return {"server": server_code, "output": result.get("stdout", "")}
|
||||
return {"server": server_code, "error": result.get("error", "unknown")}
|
||||
|
||||
def scan_all():
|
||||
"""扫描所有服务器状态"""
|
||||
servers = load_gatekeepers()
|
||||
results = {}
|
||||
for code in servers:
|
||||
result = gatekeeper_exec(code, "echo ONLINE && hostname")
|
||||
results[code] = {
|
||||
"online": result.get("ok", False),
|
||||
"hostname": result.get("stdout", "").strip() if result.get("ok") else "OFFLINE"
|
||||
}
|
||||
return results
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: hunt.py <search|list|scan-all> [参数]")
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == "search" and len(sys.argv) > 2:
|
||||
key_name = sys.argv[2]
|
||||
result = search_all_servers(key_name)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
elif action == "list" and len(sys.argv) > 2:
|
||||
result = list_server_keys(sys.argv[2])
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
elif action == "scan-all":
|
||||
result = scan_all()
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
else:
|
||||
print("未知操作")
|
||||
174
agents/module-steward/steward.py
Normal file
174
agents/module-steward/steward.py
Normal file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
模块管家 · Module Steward · ICE-GL-ZY-AGT-MODULE-004
|
||||
|
||||
铸渊需要部署模块?管家知道每个模块的编号、接口、部署方式。
|
||||
从module-registry.json加载,提供快速查询。
|
||||
|
||||
用法:
|
||||
python3 steward.py list # 列出所有模块
|
||||
python3 steward.py query image-studio # 查询指定模块
|
||||
python3 steward.py deploy image-studio # 返回部署命令
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
# 模块知识库(从仓库结构中自动发现 + 手动补充)
|
||||
MODULE_KNOWLEDGE = {
|
||||
"image-studio": {
|
||||
"id": "ICE-GL-ZY-MOD-IMAGE-001",
|
||||
"name": "神笔马良图片工作室",
|
||||
"description": "文本→封面自动排版渲染。小红书/即刻/海报。",
|
||||
"deploy": "cd /data/image-studio && npm install && node server.js",
|
||||
"port": 3912,
|
||||
"entry": "image-studio/server.js",
|
||||
"dependencies": ["node", "npm", "puppeteer"],
|
||||
"server_pref": "BS-SG-001",
|
||||
},
|
||||
"gatekeeper": {
|
||||
"id": "ICE-GL-ZY-AGT-001",
|
||||
"name": "Gatekeeper 巡检工",
|
||||
"description": "远程命令执行网关,部署在所有服务器上",
|
||||
"deploy": "cd /opt/zhuyuan && node gatekeeper.js",
|
||||
"port": "3910/3911",
|
||||
"server_pref": "all",
|
||||
},
|
||||
"exe-engine": {
|
||||
"id": "ICE-GL-ZY-MOD-EXE-001",
|
||||
"name": "任务执行引擎",
|
||||
"description": "铸渊的行动力核心,执行部署和运维任务",
|
||||
"deploy": "cd /opt/zhuyuan/exe-engine && node index.js",
|
||||
"entry": "exe-engine/",
|
||||
},
|
||||
"bridge": {
|
||||
"id": "ICE-GL-ZY-MOD-BRIDGE-001",
|
||||
"name": "Chat-to-Agent 桥接器",
|
||||
"description": "语言层与执行层的连线",
|
||||
"entry": "bridge/",
|
||||
},
|
||||
"connectors": {
|
||||
"id": "ICE-GL-ZY-MOD-CONN-001",
|
||||
"name": "Notion/Git 连接器",
|
||||
"description": "Notion双向同步 + Git桥接",
|
||||
"entry": "connectors/",
|
||||
},
|
||||
"hldp": {
|
||||
"id": "ICE-GL-ZY-MOD-HLDP-001",
|
||||
"name": "HLDP语言协议",
|
||||
"description": "铸渊母语协议 + 意识编码引擎",
|
||||
"entry": "hldp/",
|
||||
},
|
||||
"agents": {
|
||||
"id": "ICE-GL-ZY-MOD-AGENTS-001",
|
||||
"name": "情报Agent小分队",
|
||||
"description": "密钥猎手·路径探子·服务器哨兵·模块管家·门桥接",
|
||||
"entry": "agents/",
|
||||
"deploy": "python3 agents/{agent}/agent.py",
|
||||
},
|
||||
}
|
||||
|
||||
def load_registry():
|
||||
"""从module-registry.json加载"""
|
||||
reg_path = REPO_ROOT / "brain" / "module-registry.json"
|
||||
if reg_path.exists():
|
||||
with open(reg_path) as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def list_modules():
|
||||
"""列出所有已知模块"""
|
||||
registry = load_registry()
|
||||
modules = []
|
||||
|
||||
# 从注册表
|
||||
for key, mod in registry.get("modules", {}).items():
|
||||
modules.append({
|
||||
"key": key,
|
||||
"name": mod.get("name", key),
|
||||
"status": mod.get("status", "unknown"),
|
||||
"description": mod.get("description", ""),
|
||||
})
|
||||
|
||||
# 补充知识库
|
||||
for key, info in MODULE_KNOWLEDGE.items():
|
||||
if not any(m["key"] == key for m in modules):
|
||||
modules.append({
|
||||
"key": key,
|
||||
"name": info["name"],
|
||||
"id": info.get("id"),
|
||||
"description": info.get("description", ""),
|
||||
})
|
||||
|
||||
return {"modules": modules, "count": len(modules)}
|
||||
|
||||
def query_module(name):
|
||||
"""查询模块详情"""
|
||||
# 先查知识库
|
||||
if name in MODULE_KNOWLEDGE:
|
||||
return MODULE_KNOWLEDGE[name]
|
||||
|
||||
# 查注册表
|
||||
registry = load_registry()
|
||||
for key, mod in registry.get("modules", {}).items():
|
||||
if name in key or name in mod.get("name", ""):
|
||||
return {
|
||||
"key": key,
|
||||
"name": mod.get("name"),
|
||||
"status": mod.get("status"),
|
||||
"description": mod.get("description"),
|
||||
"entry": mod.get("path"),
|
||||
"note": "来自module-registry.json"
|
||||
}
|
||||
|
||||
# 查目录
|
||||
mod_path = REPO_ROOT / name
|
||||
if mod_path.is_dir():
|
||||
return {
|
||||
"name": name,
|
||||
"exists": True,
|
||||
"path": str(mod_path),
|
||||
"files": len(list(mod_path.rglob("*"))),
|
||||
}
|
||||
|
||||
return {"error": f"未找到模块: {name}"}
|
||||
|
||||
def get_deploy_command(name):
|
||||
"""返回模块的部署命令"""
|
||||
info = query_module(name)
|
||||
if "error" in info:
|
||||
return info
|
||||
|
||||
deploy = info.get("deploy")
|
||||
if deploy:
|
||||
return {"module": name, "deploy_command": deploy, "note": info.get("description", "")}
|
||||
|
||||
# 尝试推断
|
||||
entry = info.get("entry", name)
|
||||
mod_path = REPO_ROOT / entry
|
||||
if mod_path.exists():
|
||||
return {
|
||||
"module": name,
|
||||
"deploy_command": f"cd /opt/zhuyuan/guanghulab/{entry} && ls",
|
||||
"note": "请确认模块的具体启动方式"
|
||||
}
|
||||
|
||||
return {"module": name, "error": "无法确定部署命令,请手动检查"}
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: steward.py <list|query|deploy> [参数]")
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == "list":
|
||||
print(json.dumps(list_modules(), ensure_ascii=False, indent=2))
|
||||
elif action == "query" and len(sys.argv) > 2:
|
||||
print(json.dumps(query_module(sys.argv[2]), ensure_ascii=False, indent=2))
|
||||
elif action == "deploy" and len(sys.argv) > 2:
|
||||
print(json.dumps(get_deploy_command(sys.argv[2]), ensure_ascii=False, indent=2))
|
||||
17834
agents/path-scout/file-index.json
Normal file
17834
agents/path-scout/file-index.json
Normal file
File diff suppressed because it is too large
Load Diff
153
agents/path-scout/scout.py
Normal file
153
agents/path-scout/scout.py
Normal file
@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
路径探子 · Path Scout · ICE-GL-ZY-AGT-PATH-002
|
||||
|
||||
铸渊需要找文件?路径探子瞬间定位。
|
||||
不需要grep翻遍整个仓库——探子知道每个角落。
|
||||
|
||||
用法:
|
||||
python3 scout.py find gatekeeper # 模糊搜索文件名
|
||||
python3 scout.py where brain/ # 列出目录结构
|
||||
python3 scout.py index # 重建文件索引
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
INDEX_FILE = Path(__file__).resolve().parent / "file-index.json"
|
||||
|
||||
# 忽略目录
|
||||
IGNORE_DIRS = {".git", "node_modules", "__pycache__", ".DS_Store", "output", "dist", ".next"}
|
||||
|
||||
def build_index():
|
||||
"""扫描整个仓库,建立文件索引"""
|
||||
index = {"files": {}, "dirs": {}}
|
||||
|
||||
for root, dirs, files in os.walk(REPO_ROOT):
|
||||
# 过滤忽略目录
|
||||
dirs[:] = [d for d in dirs if d not in IGNORE_DIRS]
|
||||
|
||||
rel_root = os.path.relpath(root, REPO_ROOT)
|
||||
if rel_root == ".":
|
||||
rel_root = ""
|
||||
|
||||
# 记录目录
|
||||
if rel_root:
|
||||
index["dirs"][rel_root] = {
|
||||
"file_count": len(files),
|
||||
"subdir_count": len(dirs)
|
||||
}
|
||||
|
||||
# 记录文件
|
||||
for f in files:
|
||||
rel_path = os.path.join(rel_root, f) if rel_root else f
|
||||
full_path = os.path.join(root, f)
|
||||
try:
|
||||
size = os.path.getsize(full_path)
|
||||
except:
|
||||
size = 0
|
||||
index["files"][rel_path] = {
|
||||
"size": size,
|
||||
"ext": os.path.splitext(f)[1]
|
||||
}
|
||||
|
||||
# 保存索引
|
||||
INDEX_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(INDEX_FILE, "w") as f:
|
||||
json.dump(index, f, indent=2, ensure_ascii=False)
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"total_files": len(index["files"]),
|
||||
"total_dirs": len(index["dirs"]),
|
||||
"index_file": str(INDEX_FILE)
|
||||
}
|
||||
|
||||
def load_index():
|
||||
"""加载已有索引"""
|
||||
if INDEX_FILE.exists():
|
||||
with open(INDEX_FILE) as f:
|
||||
return json.load(f)
|
||||
return None
|
||||
|
||||
def find_file(pattern):
|
||||
"""搜索文件"""
|
||||
index = load_index()
|
||||
if not index:
|
||||
return {"error": "索引不存在,先运行 scout.py index"}
|
||||
|
||||
matches = []
|
||||
pattern_lower = pattern.lower()
|
||||
for path, info in index["files"].items():
|
||||
if pattern_lower in path.lower():
|
||||
matches.append({"path": path, "size": info["size"]})
|
||||
|
||||
# 按路径排序
|
||||
matches.sort(key=lambda x: x["path"])
|
||||
return {"pattern": pattern, "matches": matches, "count": len(matches)}
|
||||
|
||||
def list_dir(path=""):
|
||||
"""列出目录结构"""
|
||||
index = load_index()
|
||||
if not index:
|
||||
return {"error": "索引不存在,先运行 scout.py index"}
|
||||
|
||||
# 列出直接子目录和文件
|
||||
subdirs = []
|
||||
files = []
|
||||
|
||||
prefix = path.rstrip("/") + "/" if path else ""
|
||||
|
||||
for d in index["dirs"]:
|
||||
if d.startswith(prefix) and d != prefix.rstrip("/"):
|
||||
rel = d[len(prefix):]
|
||||
if "/" not in rel:
|
||||
subdirs.append(d)
|
||||
|
||||
for f in index["files"]:
|
||||
if f.startswith(prefix):
|
||||
rel = f[len(prefix):]
|
||||
if "/" not in rel:
|
||||
files.append({"name": rel, "size": index["files"][f]["size"]})
|
||||
|
||||
return {"path": path or "/", "subdirs": subdirs, "files": files}
|
||||
|
||||
def search_content(pattern, file_pattern="*"):
|
||||
"""在文件中搜索内容"""
|
||||
import subprocess
|
||||
cmd = ["grep", "-rl", "--include=" + file_pattern, pattern, str(REPO_ROOT)]
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
files = [os.path.relpath(f, REPO_ROOT) for f in result.stdout.strip().split("\n") if f]
|
||||
return {"pattern": pattern, "matches": files, "count": len(files)}
|
||||
except:
|
||||
return {"error": "搜索失败"}
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: scout.py <index|find|where|grep> [参数]")
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == "index":
|
||||
result = build_index()
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
elif action == "find" and len(sys.argv) > 2:
|
||||
result = find_file(sys.argv[2])
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
elif action == "where":
|
||||
path = sys.argv[2] if len(sys.argv) > 2 else ""
|
||||
result = list_dir(path)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
|
||||
elif action == "grep" and len(sys.argv) > 2:
|
||||
pattern = sys.argv[2]
|
||||
fp = sys.argv[3] if len(sys.argv) > 3 else "*"
|
||||
result = search_content(pattern, fp)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
119
agents/server-sentinel/sentinel.py
Normal file
119
agents/server-sentinel/sentinel.py
Normal file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
服务器哨兵 · Server Sentinel · ICE-GL-ZY-AGT-SENTINEL-003
|
||||
|
||||
铸渊需要知道哪台服务器在线、哪台可用?
|
||||
哨兵一键扫描全部12台。
|
||||
|
||||
用法:
|
||||
python3 sentinel.py scan # 扫描全部服务器
|
||||
python3 sentinel.py status BS-SG-001 # 单台服务器详情
|
||||
python3 sentinel.py ready # 找一台可用服务器
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
def load_gatekeepers():
|
||||
gk_path = REPO_ROOT / "brain" / "gatekeeper-deployment.json"
|
||||
if gk_path.exists():
|
||||
with open(gk_path) as f:
|
||||
return json.load(f)
|
||||
return {"servers": []}
|
||||
|
||||
def check_server(server):
|
||||
"""检查单台服务器"""
|
||||
url = f"http://{server['ip']}:{server['port']}/exec"
|
||||
data = json.dumps({"cmd": "echo ONLINE && hostname && free -h | grep Mem | awk '{print $2,$3,$4}' && df -h / | tail -1 | awk '{print $2,$3,$4}'"}).encode()
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url, data=data,
|
||||
headers={
|
||||
"Authorization": f"Bearer {server['key']}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
result = json.loads(resp.read())
|
||||
|
||||
if result.get("ok"):
|
||||
lines = result.get("stdout", "").strip().split("\n")
|
||||
return {
|
||||
"code": server["code"],
|
||||
"name": server.get("name", ""),
|
||||
"online": True,
|
||||
"hostname": lines[0] if len(lines) > 0 else "?",
|
||||
"memory": lines[1] if len(lines) > 1 else "?",
|
||||
"disk": lines[2] if len(lines) > 2 else "?",
|
||||
}
|
||||
return {"code": server["code"], "online": False, "error": result.get("stderr", "")}
|
||||
except Exception as e:
|
||||
return {"code": server["code"], "online": False, "error": str(e)[:100]}
|
||||
|
||||
def scan_all():
|
||||
"""扫描全部服务器"""
|
||||
data = load_gatekeepers()
|
||||
results = []
|
||||
online_count = 0
|
||||
|
||||
for s in data.get("servers", []):
|
||||
r = check_server(s)
|
||||
results.append(r)
|
||||
if r.get("online"):
|
||||
online_count += 0
|
||||
|
||||
# 按域分组
|
||||
by_domain = {}
|
||||
for r in results:
|
||||
srv = next((x for x in data["servers"] if x["code"] == r["code"]), {})
|
||||
domain = srv.get("domain", "unknown")
|
||||
if domain not in by_domain:
|
||||
by_domain[domain] = []
|
||||
by_domain[domain].append(r)
|
||||
|
||||
return {
|
||||
"total": len(results),
|
||||
"online": online_count,
|
||||
"by_domain": by_domain,
|
||||
"servers": results
|
||||
}
|
||||
|
||||
def find_available():
|
||||
"""找一台可用服务器"""
|
||||
data = load_gatekeepers()
|
||||
# 优先ice-core域
|
||||
for s in data.get("servers", []):
|
||||
if s.get("domain") == "ice-core":
|
||||
r = check_server(s)
|
||||
if r.get("online"):
|
||||
return {"found": True, "server": r, "note": "ice-core域优先"}
|
||||
# 其他域
|
||||
for s in data.get("servers", []):
|
||||
if s.get("domain") != "ice-core":
|
||||
r = check_server(s)
|
||||
if r.get("online"):
|
||||
return {"found": True, "server": r}
|
||||
return {"found": False, "note": "所有服务器不可达"}
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: sentinel.py <scan|status|ready>")
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == "scan":
|
||||
print(json.dumps(scan_all(), ensure_ascii=False, indent=2))
|
||||
elif action == "status" and len(sys.argv) > 2:
|
||||
data = load_gatekeepers()
|
||||
for s in data["servers"]:
|
||||
if s["code"] == sys.argv[2]:
|
||||
print(json.dumps(check_server(s), ensure_ascii=False, indent=2))
|
||||
break
|
||||
elif action == "ready":
|
||||
print(json.dumps(find_available(), ensure_ascii=False, indent=2))
|
||||
Loading…
x
Reference in New Issue
Block a user