Integrate plugin with local monitor bridge
This commit is contained in:
15
README.md
15
README.md
@@ -84,13 +84,14 @@ node scripts/install.mjs --verbose
|
|||||||
{
|
{
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"entries": {
|
"entries": {
|
||||||
"harborforge-monitor": {
|
"harbor-forge": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"backendUrl": "https://monitor.hangman-lab.top",
|
"backendUrl": "https://monitor.hangman-lab.top",
|
||||||
"identifier": "my-server-01",
|
"identifier": "my-server-01",
|
||||||
"apiKey": "your-api-key-here",
|
"apiKey": "your-api-key-here",
|
||||||
|
"monitorPort": 9100,
|
||||||
"reportIntervalSec": 30,
|
"reportIntervalSec": 30,
|
||||||
"httpFallbackIntervalSec": 60,
|
"httpFallbackIntervalSec": 60,
|
||||||
"logLevel": "info"
|
"logLevel": "info"
|
||||||
@@ -115,10 +116,22 @@ openclaw gateway restart
|
|||||||
| `backendUrl` | string | `https://monitor.hangman-lab.top` | Monitor 后端地址 |
|
| `backendUrl` | string | `https://monitor.hangman-lab.top` | Monitor 后端地址 |
|
||||||
| `identifier` | string | 自动检测 hostname | 服务器标识符 |
|
| `identifier` | string | 自动检测 hostname | 服务器标识符 |
|
||||||
| `apiKey` | string | 必填 | HarborForge Monitor 生成的服务器 API Key |
|
| `apiKey` | string | 必填 | HarborForge Monitor 生成的服务器 API Key |
|
||||||
|
| `monitorPort` | number | `9100`(示例) | 本地桥接端口;插件通过 `127.0.0.1:<monitorPort>` 与 HarborForge.Monitor 通信 |
|
||||||
| `reportIntervalSec` | number | `30` | 报告间隔(秒) |
|
| `reportIntervalSec` | number | `30` | 报告间隔(秒) |
|
||||||
| `httpFallbackIntervalSec` | number | `60` | HTTP 回退间隔(秒) |
|
| `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 会在 `127.0.0.1:<monitorPort>` 暴露本地桥接服务
|
||||||
|
- 插件可探测 `GET /health`
|
||||||
|
- 插件工具 `harborforge_monitor_telemetry` 可读取 `GET /telemetry`
|
||||||
|
- 若桥接端口未配置或不可达,插件仍然正常工作,只是不会拿到 Monitor 的宿主机遥测补充数据
|
||||||
|
|
||||||
|
这条链路是**可选增强**,不是插件或 Monitor 心跳上报的前置依赖。
|
||||||
|
|
||||||
## 收集的指标
|
## 收集的指标
|
||||||
|
|
||||||
### 系统指标
|
### 系统指标
|
||||||
|
|||||||
1
plugin/core/live-config.d.ts
vendored
1
plugin/core/live-config.d.ts
vendored
@@ -3,6 +3,7 @@ export interface HarborForgeMonitorConfig {
|
|||||||
backendUrl?: string;
|
backendUrl?: string;
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
|
monitorPort?: number;
|
||||||
reportIntervalSec?: number;
|
reportIntervalSec?: number;
|
||||||
httpFallbackIntervalSec?: number;
|
httpFallbackIntervalSec?: number;
|
||||||
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
||||||
|
|||||||
@@ -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,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"}
|
{"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"}
|
||||||
@@ -5,7 +5,7 @@ function getLivePluginConfig(api, fallback) {
|
|||||||
const root = api.config || {};
|
const root = api.config || {};
|
||||||
const plugins = root.plugins || {};
|
const plugins = root.plugins || {};
|
||||||
const entries = plugins.entries || {};
|
const entries = plugins.entries || {};
|
||||||
const entry = entries['harborforge-monitor'] || {};
|
const entry = entries['harbor-forge'] || {};
|
||||||
const cfg = entry.config || {};
|
const cfg = entry.config || {};
|
||||||
if (Object.keys(cfg).length > 0 || Object.keys(entry).length > 0) {
|
if (Object.keys(cfg).length > 0 || Object.keys(entry).length > 0) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"live-config.js","sourceRoot":"","sources":["live-config.ts"],"names":[],"mappings":";;AAcA,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,qBAAqB,CAA6B,IAAI,EAAE,CAAC;IAChF,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"}
|
{"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"}
|
||||||
@@ -3,6 +3,7 @@ export interface HarborForgeMonitorConfig {
|
|||||||
backendUrl?: string;
|
backendUrl?: string;
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
|
monitorPort?: number;
|
||||||
reportIntervalSec?: number;
|
reportIntervalSec?: number;
|
||||||
httpFallbackIntervalSec?: number;
|
httpFallbackIntervalSec?: number;
|
||||||
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
||||||
@@ -19,7 +20,7 @@ export function getLivePluginConfig(
|
|||||||
const root = (api.config as Record<string, unknown>) || {};
|
const root = (api.config as Record<string, unknown>) || {};
|
||||||
const plugins = (root.plugins as Record<string, unknown>) || {};
|
const plugins = (root.plugins as Record<string, unknown>) || {};
|
||||||
const entries = (plugins.entries as Record<string, unknown>) || {};
|
const entries = (plugins.entries as Record<string, unknown>) || {};
|
||||||
const entry = (entries['harborforge-monitor'] as Record<string, unknown>) || {};
|
const entry = (entries['harbor-forge'] as Record<string, unknown>) || {};
|
||||||
const cfg = (entry.config as Record<string, unknown>) || {};
|
const cfg = (entry.config as Record<string, unknown>) || {};
|
||||||
|
|
||||||
if (Object.keys(cfg).length > 0 || Object.keys(entry).length > 0) {
|
if (Object.keys(cfg).length > 0 || Object.keys(entry).length > 0) {
|
||||||
|
|||||||
41
plugin/core/monitor-bridge.d.ts
vendored
Normal file
41
plugin/core/monitor-bridge.d.ts
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Monitor Bridge Client
|
||||||
|
*
|
||||||
|
* Queries the local HarborForge.Monitor bridge endpoint on MONITOR_PORT
|
||||||
|
* to enrich plugin telemetry with host/hardware data.
|
||||||
|
*
|
||||||
|
* If the bridge is unreachable, all methods return null gracefully —
|
||||||
|
* the plugin continues to function without Monitor data.
|
||||||
|
*/
|
||||||
|
export interface MonitorHealth {
|
||||||
|
status: string;
|
||||||
|
monitor_version: string;
|
||||||
|
identifier: string;
|
||||||
|
}
|
||||||
|
export interface MonitorTelemetryResponse {
|
||||||
|
status: string;
|
||||||
|
monitor_version: string;
|
||||||
|
identifier: string;
|
||||||
|
telemetry?: {
|
||||||
|
identifier: string;
|
||||||
|
plugin_version: string;
|
||||||
|
cpu_pct: number;
|
||||||
|
mem_pct: number;
|
||||||
|
disk_pct: number;
|
||||||
|
swap_pct: number;
|
||||||
|
load_avg: number[];
|
||||||
|
uptime_seconds: number;
|
||||||
|
nginx_installed: boolean;
|
||||||
|
nginx_sites: string[];
|
||||||
|
};
|
||||||
|
last_updated?: string;
|
||||||
|
}
|
||||||
|
export declare class MonitorBridgeClient {
|
||||||
|
private baseUrl;
|
||||||
|
private timeoutMs;
|
||||||
|
constructor(port: number, timeoutMs?: number);
|
||||||
|
health(): Promise<MonitorHealth | null>;
|
||||||
|
telemetry(): Promise<MonitorTelemetryResponse | null>;
|
||||||
|
private fetchJson;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=monitor-bridge.d.ts.map
|
||||||
1
plugin/core/monitor-bridge.d.ts.map
Normal file
1
plugin/core/monitor-bridge.d.ts.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"monitor-bridge.d.ts","sourceRoot":"","sources":["monitor-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;QACzB,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,EAAE,MAAM,EAAE,SAAS,SAAO;IAKpC,MAAM,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIvC,SAAS,IAAI,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC;YAI7C,SAAS;CAgBxB"}
|
||||||
44
plugin/core/monitor-bridge.js
Normal file
44
plugin/core/monitor-bridge.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* Monitor Bridge Client
|
||||||
|
*
|
||||||
|
* Queries the local HarborForge.Monitor bridge endpoint on MONITOR_PORT
|
||||||
|
* to enrich plugin telemetry with host/hardware data.
|
||||||
|
*
|
||||||
|
* If the bridge is unreachable, all methods return null gracefully —
|
||||||
|
* the plugin continues to function without Monitor data.
|
||||||
|
*/
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.MonitorBridgeClient = void 0;
|
||||||
|
class MonitorBridgeClient {
|
||||||
|
baseUrl;
|
||||||
|
timeoutMs;
|
||||||
|
constructor(port, timeoutMs = 3000) {
|
||||||
|
this.baseUrl = `http://127.0.0.1:${port}`;
|
||||||
|
this.timeoutMs = timeoutMs;
|
||||||
|
}
|
||||||
|
async health() {
|
||||||
|
return this.fetchJson('/health');
|
||||||
|
}
|
||||||
|
async telemetry() {
|
||||||
|
return this.fetchJson('/telemetry');
|
||||||
|
}
|
||||||
|
async fetchJson(path) {
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
||||||
|
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
clearTimeout(timeout);
|
||||||
|
if (!response.ok)
|
||||||
|
return null;
|
||||||
|
return (await response.json());
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.MonitorBridgeClient = MonitorBridgeClient;
|
||||||
|
//# sourceMappingURL=monitor-bridge.js.map
|
||||||
1
plugin/core/monitor-bridge.js.map
Normal file
1
plugin/core/monitor-bridge.js.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"monitor-bridge.js","sourceRoot":"","sources":["monitor-bridge.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AA2BH,MAAa,mBAAmB;IACtB,OAAO,CAAS;IAChB,SAAS,CAAS;IAE1B,YAAY,IAAY,EAAE,SAAS,GAAG,IAAI;QACxC,IAAI,CAAC,OAAO,GAAG,oBAAoB,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM;QACV,OAAO,IAAI,CAAC,SAAS,CAAgB,SAAS,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,IAAI,CAAC,SAAS,CAA2B,YAAY,CAAC,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,SAAS,CAAI,IAAY;QACrC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAErE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;gBACrD,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YACH,YAAY,CAAC,OAAO,CAAC,CAAC;YAEtB,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;YAC9B,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAjCD,kDAiCC"}
|
||||||
69
plugin/core/monitor-bridge.ts
Normal file
69
plugin/core/monitor-bridge.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Monitor Bridge Client
|
||||||
|
*
|
||||||
|
* Queries the local HarborForge.Monitor bridge endpoint on MONITOR_PORT
|
||||||
|
* to enrich plugin telemetry with host/hardware data.
|
||||||
|
*
|
||||||
|
* If the bridge is unreachable, all methods return null gracefully —
|
||||||
|
* the plugin continues to function without Monitor data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface MonitorHealth {
|
||||||
|
status: string;
|
||||||
|
monitor_version: string;
|
||||||
|
identifier: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonitorTelemetryResponse {
|
||||||
|
status: string;
|
||||||
|
monitor_version: string;
|
||||||
|
identifier: string;
|
||||||
|
telemetry?: {
|
||||||
|
identifier: string;
|
||||||
|
plugin_version: string;
|
||||||
|
cpu_pct: number;
|
||||||
|
mem_pct: number;
|
||||||
|
disk_pct: number;
|
||||||
|
swap_pct: number;
|
||||||
|
load_avg: number[];
|
||||||
|
uptime_seconds: number;
|
||||||
|
nginx_installed: boolean;
|
||||||
|
nginx_sites: string[];
|
||||||
|
};
|
||||||
|
last_updated?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MonitorBridgeClient {
|
||||||
|
private baseUrl: string;
|
||||||
|
private timeoutMs: number;
|
||||||
|
|
||||||
|
constructor(port: number, timeoutMs = 3000) {
|
||||||
|
this.baseUrl = `http://127.0.0.1:${port}`;
|
||||||
|
this.timeoutMs = timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
async health(): Promise<MonitorHealth | null> {
|
||||||
|
return this.fetchJson<MonitorHealth>('/health');
|
||||||
|
}
|
||||||
|
|
||||||
|
async telemetry(): Promise<MonitorTelemetryResponse | null> {
|
||||||
|
return this.fetchJson<MonitorTelemetryResponse>('/telemetry');
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchJson<T>(path: string): Promise<T | null> {
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
||||||
|
|
||||||
|
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
clearTimeout(timeout);
|
||||||
|
|
||||||
|
if (!response.ok) return null;
|
||||||
|
return (await response.json()) as T;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
import { hostname, freemem, totalmem, uptime, loadavg, platform } from 'os';
|
import { hostname, freemem, totalmem, uptime, loadavg, platform } from 'os';
|
||||||
import { getLivePluginConfig, type HarborForgeMonitorConfig } from './core/live-config';
|
import { getLivePluginConfig, type HarborForgeMonitorConfig } from './core/live-config';
|
||||||
|
import { MonitorBridgeClient } from './core/monitor-bridge';
|
||||||
|
|
||||||
interface PluginAPI {
|
interface PluginAPI {
|
||||||
logger: {
|
logger: {
|
||||||
@@ -50,6 +51,16 @@ export default {
|
|||||||
return getLivePluginConfig(api, baseConfig);
|
return getLivePluginConfig(api, baseConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the monitor bridge client if monitorPort is configured.
|
||||||
|
*/
|
||||||
|
function getBridgeClient(): MonitorBridgeClient | null {
|
||||||
|
const live = resolveConfig() as any;
|
||||||
|
const port = live.monitorPort;
|
||||||
|
if (!port || port <= 0) return null;
|
||||||
|
return new MonitorBridgeClient(port);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect current system telemetry snapshot.
|
* Collect current system telemetry snapshot.
|
||||||
* This data is exposed to the Monitor bridge when it queries the plugin.
|
* This data is exposed to the Monitor bridge when it queries the plugin.
|
||||||
@@ -99,6 +110,16 @@ export default {
|
|||||||
},
|
},
|
||||||
async execute() {
|
async execute() {
|
||||||
const live = resolveConfig();
|
const live = resolveConfig();
|
||||||
|
const bridgeClient = getBridgeClient();
|
||||||
|
let monitorBridge = null;
|
||||||
|
|
||||||
|
if (bridgeClient) {
|
||||||
|
const health = await bridgeClient.health();
|
||||||
|
monitorBridge = health
|
||||||
|
? { connected: true, ...health }
|
||||||
|
: { connected: false, error: 'Monitor bridge unreachable' };
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled: live.enabled !== false,
|
enabled: live.enabled !== false,
|
||||||
config: {
|
config: {
|
||||||
@@ -108,6 +129,7 @@ export default {
|
|||||||
reportIntervalSec: live.reportIntervalSec,
|
reportIntervalSec: live.reportIntervalSec,
|
||||||
hasApiKey: Boolean(live.apiKey),
|
hasApiKey: Boolean(live.apiKey),
|
||||||
},
|
},
|
||||||
|
monitorBridge,
|
||||||
telemetry: collectTelemetry(),
|
telemetry: collectTelemetry(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -126,6 +148,33 @@ export default {
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Tool: query Monitor bridge for host hardware telemetry
|
||||||
|
api.registerTool(() => ({
|
||||||
|
name: 'harborforge_monitor_telemetry',
|
||||||
|
description: 'Query HarborForge Monitor bridge for host hardware telemetry (CPU, memory, disk, etc.)',
|
||||||
|
parameters: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
async execute() {
|
||||||
|
const bridgeClient = getBridgeClient();
|
||||||
|
if (!bridgeClient) {
|
||||||
|
return {
|
||||||
|
error: 'Monitor bridge not configured (monitorPort not set or 0)',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await bridgeClient.telemetry();
|
||||||
|
if (!data) {
|
||||||
|
return {
|
||||||
|
error: 'Monitor bridge unreachable',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
logger.info('HarborForge plugin registered (id: harbor-forge)');
|
logger.info('HarborForge plugin registered (id: harbor-forge)');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user