diff --git a/README.md b/README.md index 2c9bfdc..41ed680 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,80 @@ # HarborForge OpenClaw Plugin -OpenClaw 插件,将服务器遥测数据流式传输到 HarborForge Monitor。 +OpenClaw 插件:向 HarborForge Monitor 暴露 OpenClaw 侧元数据,并提供可选的本地桥接能力;安装时也可顺带安装 `hf` CLI。 + +## 当前状态 + +- 插件注册名:`harbor-forge` +- 旧 sidecar `server/` 架构已移除 +- 监控桥接走本地 `monitor_port` +- 安装脚本支持 `--install-cli` +- `skills/hf/` 仅在 `--install-cli` 时一并安装 ## 项目结构 -``` +```text HarborForge.OpenclawPlugin/ -├── package.json # 根 package.json -├── README.md # 本文档 -├── plugin/ # OpenClaw 插件代码 -│ ├── openclaw.plugin.json # 插件定义 -│ ├── index.ts # 插件入口 -│ ├── package.json # 插件依赖 -│ └── tsconfig.json # TypeScript 配置 -├── server/ # Sidecar 服务器 -│ └── telemetry.mjs # 遥测数据收集和发送 -├── skills/ # OpenClaw 技能 -│ └── (技能文件) +├── package.json +├── README.md +├── plugin/ +│ ├── openclaw.plugin.json +│ ├── index.ts +│ ├── core/ +│ │ ├── live-config.ts +│ │ └── monitor-bridge.ts +│ └── package.json +├── skills/ +│ └── hf/ +│ └── SKILL.md └── scripts/ - └── install.mjs # 安装脚本 -``` - -## 架构 - -``` -┌─────────────────────────────────────────────────┐ -│ OpenClaw Gateway │ -│ ┌───────────────────────────────────────────┐ │ -│ │ HarborForge.OpenclawPlugin/plugin/ │ │ -│ │ - 生命周期管理 (启动/停止) │ │ -│ │ - 配置管理 │ │ -│ └───────────────────────────────────────────┘ │ -│ │ │ -│ ▼ 启动 telemetry server │ -│ ┌───────────────────────────────────────────┐ │ -│ │ HarborForge.OpenclawPlugin/server/ │ │ -│ │ - 独立 Node 进程 │ │ -│ │ - 收集系统指标 │ │ -│ │ - 收集 OpenClaw 状态 │ │ -│ │ - 发送到 HarborForge Monitor │ │ -│ └───────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────┘ - │ - ▼ HTTP - ┌─────────────────────┐ - │ HarborForge Monitor │ - └─────────────────────┘ + └── install.mjs ``` ## 安装 -### 快速安装 +### 普通安装 ```bash -# 克隆仓库 -git clone https://git.hangman-lab.top/zhi/HarborForge.OpenclawPlugin.git -cd HarborForge.OpenclawPlugin - -# 运行安装脚本 node scripts/install.mjs ``` -### 开发安装 +这会: +- 构建并安装 OpenClaw 插件 +- 复制常规 skills +- **不会**安装 `hf` 二进制 +- **不会**复制 `skills/hf/` + +### 安装插件 + `hf` CLI ```bash -# 仅构建不安装 +node scripts/install.mjs --install-cli +``` + +这会额外: +- 构建 `HarborForge.Cli` +- 安装 `hf` 到 `~/.openclaw/bin/hf` +- `chmod +x ~/.openclaw/bin/hf` +- 复制 `skills/hf/` 到 OpenClaw profile skills 目录 + +### 常用选项 + +```bash +# 仅构建 node scripts/install.mjs --build-only -# 指定 OpenClaw 路径 +# 指定 OpenClaw profile node scripts/install.mjs --openclaw-profile-path /custom/path/.openclaw -# 详细输出 +# 详细日志 node scripts/install.mjs --verbose + +# 卸载 +node scripts/install.mjs --uninstall ``` ## 配置 -1. 在 HarborForge Monitor 中注册服务器,并生成 `apiKey` - -2. 编辑 `~/.openclaw/openclaw.json`: +编辑 `~/.openclaw/openclaw.json`: ```json { @@ -91,7 +87,7 @@ node scripts/install.mjs --verbose "backendUrl": "https://monitor.hangman-lab.top", "identifier": "my-server-01", "apiKey": "your-api-key-here", - "monitorPort": 9100, + "monitor_port": 9100, "reportIntervalSec": 30, "httpFallbackIntervalSec": 60, "logLevel": "info" @@ -102,84 +98,68 @@ node scripts/install.mjs --verbose } ``` -3. 重启 OpenClaw Gateway: +> 说明:`monitor_port` 是当前主字段;为兼容旧配置,插件仍接受 `monitorPort`。 + +然后重启: ```bash openclaw gateway restart ``` -## 配置选项 +## 配置项 | 选项 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `enabled` | boolean | `true` | 是否启用插件 | -| `backendUrl` | string | `https://monitor.hangman-lab.top` | Monitor 后端地址 | -| `identifier` | string | 自动检测 hostname | 服务器标识符 | -| `apiKey` | string | 必填 | HarborForge Monitor 生成的服务器 API Key | -| `monitorPort` | number | `9100`(示例) | 本地桥接端口;插件通过 `127.0.0.1:` 与 HarborForge.Monitor 通信 | +| `backendUrl` | string | `https://monitor.hangman-lab.top` | HarborForge Monitor 后端地址 | +| `identifier` | string | 主机名 | 服务器标识符 | +| `apiKey` | string | 无 | HarborForge Monitor 生成的服务器 API Key | +| `monitor_port` | number | 无 | 本地桥接端口;插件通过 `127.0.0.1:` 与 HarborForge.Monitor 通信 | | `reportIntervalSec` | number | `30` | 报告间隔(秒) | | `httpFallbackIntervalSec` | number | `60` | HTTP 回退间隔(秒) | -| `logLevel` | string | `"info"` | 日志级别: debug/info/warn/error | +| `logLevel` | string | `info` | 日志级别:`debug` / `info` / `warn` / `error` | -## Monitor 本地桥接 +## 本地桥接说明 -当插件配置了 `monitorPort`,并且 HarborForge.Monitor 也以相同的 `MONITOR_PORT` 启动时: +当插件配置了 `monitor_port`,并且 HarborForge.Monitor 也使用相同的 `MONITOR_PORT` 时: -- Monitor 会在 `127.0.0.1:` 暴露本地桥接服务 +- Monitor 在 `127.0.0.1:` 提供本地桥接服务 - 插件可探测 `GET /health` - 插件工具 `harborforge_monitor_telemetry` 可读取 `GET /telemetry` -- 若桥接端口未配置或不可达,插件仍然正常工作,只是不会拿到 Monitor 的宿主机遥测补充数据 +- 如果桥接端口未配置或不可达,插件仍可正常运行 -这条链路是**可选增强**,不是插件或 Monitor 心跳上报的前置依赖。 +也就是说,这条链路是**可选增强**,不是插件启动或 Monitor 心跳的前置条件。 -## 收集的指标 +## 插件提供的信息 -### 系统指标 -- CPU 使用率 (%) -- 内存使用率 (%)、已用/总量 (MB) -- 磁盘使用率 (%)、已用/总量 (GB) -- 交换分区使用率 (%) -- 系统运行时间 (秒) -- 1分钟平均负载 -- 平台 (linux/darwin/win32) -- 主机名 +### OpenClaw 元数据 +- OpenClaw version +- plugin version +- 标识符 / 主机名 +- 时间戳 -### OpenClaw 指标 -- OpenClaw 版本 -- Agent 数量 -- Agent 列表 (id, name, status) - -## 卸载 - -```bash -node scripts/install.mjs --uninstall -``` +### 系统快照 +- uptime +- memory total/free/used/usagePercent +- load avg1/avg5/avg15 +- platform ## 开发 -### 构建插件 - ```bash cd plugin npm install npm run build ``` -### 本地测试 telemetry server - -```bash -cd server -HF_MONITOR_API_KEY=test-api-key \ -HF_MONITOR_BACKEND_URL=http://localhost:8000 \ -HF_MONITOR_LOG_LEVEL=debug \ -node telemetry.mjs -``` - ## 依赖 - Node.js 18+ - OpenClaw Gateway +- Go 1.20+(仅 `--install-cli` 需要) -## 文档 +## 相关提示 -- [监控连接器规划](./docs/monitor-server-connector-plan.md) - 原始设计文档 +- 安装 `hf` 后,建议把 `~/.openclaw/bin` 加到 `PATH` +- Agent 使用 `hf` 时,优先试 `hf --help-brief` +- 完整命令树看 `hf --help` diff --git a/plugin/core/live-config.d.ts b/plugin/core/live-config.d.ts index e455432..3f78c43 100644 --- a/plugin/core/live-config.d.ts +++ b/plugin/core/live-config.d.ts @@ -3,6 +3,7 @@ export interface HarborForgeMonitorConfig { backendUrl?: string; identifier?: string; apiKey?: string; + monitor_port?: number; monitorPort?: number; reportIntervalSec?: number; httpFallbackIntervalSec?: number; diff --git a/plugin/core/live-config.d.ts.map b/plugin/core/live-config.d.ts.map index 26a5054..074ffc5 100644 --- a/plugin/core/live-config.d.ts.map +++ b/plugin/core/live-config.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"live-config.d.ts","sourceRoot":"","sources":["live-config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD;AAED,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,qBAAqB,EAC1B,QAAQ,EAAE,wBAAwB,GACjC,wBAAwB,CAqB1B"} \ No newline at end of file +{"version":3,"file":"live-config.d.ts","sourceRoot":"","sources":["live-config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD;AAED,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,qBAAqB,EAC1B,QAAQ,EAAE,wBAAwB,GACjC,wBAAwB,CAgC1B"} \ No newline at end of file diff --git a/plugin/core/live-config.js b/plugin/core/live-config.js index b3201d3..463dc7c 100644 --- a/plugin/core/live-config.js +++ b/plugin/core/live-config.js @@ -8,9 +8,18 @@ function getLivePluginConfig(api, fallback) { const entry = entries['harbor-forge'] || {}; const cfg = entry.config || {}; if (Object.keys(cfg).length > 0 || Object.keys(entry).length > 0) { + const monitorPort = typeof cfg.monitor_port === 'number' + ? cfg.monitor_port + : typeof cfg.monitorPort === 'number' + ? cfg.monitorPort + : typeof fallback.monitor_port === 'number' + ? fallback.monitor_port + : fallback.monitorPort; return { ...fallback, ...cfg, + monitor_port: monitorPort, + monitorPort, enabled: typeof cfg.enabled === 'boolean' ? cfg.enabled : typeof entry.enabled === 'boolean' diff --git a/plugin/core/live-config.js.map b/plugin/core/live-config.js.map index 650d6ac..e0573e7 100644 --- a/plugin/core/live-config.js.map +++ b/plugin/core/live-config.js.map @@ -1 +1 @@ -{"version":3,"file":"live-config.js","sourceRoot":"","sources":["live-config.ts"],"names":[],"mappings":";;AAeA,kDAwBC;AAxBD,SAAgB,mBAAmB,CACjC,GAA0B,EAC1B,QAAkC;IAElC,MAAM,IAAI,GAAI,GAAG,CAAC,MAAkC,IAAI,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAI,IAAI,CAAC,OAAmC,IAAI,EAAE,CAAC;IAChE,MAAM,OAAO,GAAI,OAAO,CAAC,OAAmC,IAAI,EAAE,CAAC;IACnE,MAAM,KAAK,GAAI,OAAO,CAAC,cAAc,CAA6B,IAAI,EAAE,CAAC;IACzE,MAAM,GAAG,GAAI,KAAK,CAAC,MAAkC,IAAI,EAAE,CAAC;IAE5D,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjE,OAAO;YACL,GAAG,QAAQ;YACX,GAAG,GAAG;YACN,OAAO,EACL,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS;gBAC9B,CAAC,CAAC,GAAG,CAAC,OAAO;gBACb,CAAC,CAAC,OAAO,KAAK,CAAC,OAAO,KAAK,SAAS;oBAClC,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,QAAQ,CAAC,OAAO;SACG,CAAC;IAChC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"} \ No newline at end of file +{"version":3,"file":"live-config.js","sourceRoot":"","sources":["live-config.ts"],"names":[],"mappings":";;AAgBA,kDAmCC;AAnCD,SAAgB,mBAAmB,CACjC,GAA0B,EAC1B,QAAkC;IAElC,MAAM,IAAI,GAAI,GAAG,CAAC,MAAkC,IAAI,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAI,IAAI,CAAC,OAAmC,IAAI,EAAE,CAAC;IAChE,MAAM,OAAO,GAAI,OAAO,CAAC,OAAmC,IAAI,EAAE,CAAC;IACnE,MAAM,KAAK,GAAI,OAAO,CAAC,cAAc,CAA6B,IAAI,EAAE,CAAC;IACzE,MAAM,GAAG,GAAI,KAAK,CAAC,MAAkC,IAAI,EAAE,CAAC;IAE5D,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjE,MAAM,WAAW,GACf,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ;YAClC,CAAC,CAAC,GAAG,CAAC,YAAY;YAClB,CAAC,CAAC,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ;gBACnC,CAAC,CAAC,GAAG,CAAC,WAAW;gBACjB,CAAC,CAAC,OAAO,QAAQ,CAAC,YAAY,KAAK,QAAQ;oBACzC,CAAC,CAAC,QAAQ,CAAC,YAAY;oBACvB,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;QAE/B,OAAO;YACL,GAAG,QAAQ;YACX,GAAG,GAAG;YACN,YAAY,EAAE,WAAW;YACzB,WAAW;YACX,OAAO,EACL,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS;gBAC9B,CAAC,CAAC,GAAG,CAAC,OAAO;gBACb,CAAC,CAAC,OAAO,KAAK,CAAC,OAAO,KAAK,SAAS;oBAClC,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,QAAQ,CAAC,OAAO;SACG,CAAC;IAChC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"} \ No newline at end of file diff --git a/plugin/core/live-config.ts b/plugin/core/live-config.ts index a3bc3c3..6e3de73 100644 --- a/plugin/core/live-config.ts +++ b/plugin/core/live-config.ts @@ -3,6 +3,7 @@ export interface HarborForgeMonitorConfig { backendUrl?: string; identifier?: string; apiKey?: string; + monitor_port?: number; monitorPort?: number; reportIntervalSec?: number; httpFallbackIntervalSec?: number; @@ -24,9 +25,20 @@ export function getLivePluginConfig( const cfg = (entry.config as Record) || {}; if (Object.keys(cfg).length > 0 || Object.keys(entry).length > 0) { + const monitorPort = + typeof cfg.monitor_port === 'number' + ? cfg.monitor_port + : typeof cfg.monitorPort === 'number' + ? cfg.monitorPort + : typeof fallback.monitor_port === 'number' + ? fallback.monitor_port + : fallback.monitorPort; + return { ...fallback, ...cfg, + monitor_port: monitorPort, + monitorPort, enabled: typeof cfg.enabled === 'boolean' ? cfg.enabled diff --git a/plugin/index.ts b/plugin/index.ts index 7781950..b71fbdd 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -52,11 +52,12 @@ export default { } /** - * Get the monitor bridge client if monitorPort is configured. + * Get the monitor bridge client if monitor_port is configured. + * Legacy alias monitorPort is still accepted. */ function getBridgeClient(): MonitorBridgeClient | null { const live = resolveConfig() as any; - const port = live.monitorPort; + const port = live.monitor_port ?? live.monitorPort; if (!port || port <= 0) return null; return new MonitorBridgeClient(port); } @@ -125,7 +126,7 @@ export default { config: { backendUrl: live.backendUrl, identifier: live.identifier || hostname(), - monitorPort: (live as any).monitorPort || null, + monitorPort: (live as any).monitor_port ?? (live as any).monitorPort ?? null, reportIntervalSec: live.reportIntervalSec, hasApiKey: Boolean(live.apiKey), }, @@ -160,7 +161,7 @@ export default { const bridgeClient = getBridgeClient(); if (!bridgeClient) { return { - error: 'Monitor bridge not configured (monitorPort not set or 0)', + error: 'Monitor bridge not configured (monitor_port not set or 0)', }; } diff --git a/plugin/openclaw.plugin.json b/plugin/openclaw.plugin.json index cba0d12..fe9fbc9 100644 --- a/plugin/openclaw.plugin.json +++ b/plugin/openclaw.plugin.json @@ -26,7 +26,7 @@ "type": "string", "description": "API Key from HarborForge Monitor admin panel (optional but required for authentication)" }, - "monitorPort": { + "monitor_port": { "type": "number", "description": "Local port for communication between HarborForge Monitor and this plugin" }, diff --git a/plugin/package-lock.json b/plugin/package-lock.json index 23f5869..d57e993 100644 --- a/plugin/package-lock.json +++ b/plugin/package-lock.json @@ -1,12 +1,12 @@ { - "name": "harborforge-monitor-plugin", - "version": "0.1.0", + "name": "harbor-forge-plugin", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "harborforge-monitor-plugin", - "version": "0.1.0", + "name": "harbor-forge-plugin", + "version": "0.2.0", "license": "MIT", "devDependencies": { "@types/node": "^20.0.0", diff --git a/plugin/package.json b/plugin/package.json index d3cd063..0e17992 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,7 +1,7 @@ { - "name": "harborforge-monitor-plugin", - "version": "0.1.0", - "description": "OpenClaw plugin for HarborForge Monitor", + "name": "harbor-forge-plugin", + "version": "0.2.0", + "description": "OpenClaw plugin for HarborForge monitor bridge and CLI integration", "main": "index.js", "scripts": { "build": "tsc", diff --git a/scripts/install.mjs b/scripts/install.mjs index 718dabf..12a9bfb 100644 --- a/scripts/install.mjs +++ b/scripts/install.mjs @@ -354,6 +354,7 @@ function summary() { log('Next steps:', 'blue'); log(' 1. Register server in HarborForge Monitor to get apiKey', 'cyan'); log(' 2. Edit ~/.openclaw/openclaw.json under plugins.entries.harbor-forge.config:', 'cyan'); + log(' (prefer monitor_port; legacy monitorPort is still accepted)', 'cyan'); log(' {', 'cyan'); log(' "plugins": {', 'cyan'); log(' "entries": {', 'cyan');