@aight-cool/aight-utils 0.1.17 → 0.1.19
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.
- package/{src/bootstrap.ts → dist/hooks/aight-bootstrap/handler.js} +54 -58
- package/dist/hooks/aight-bootstrap/handler.js.map +1 -0
- package/dist/index.js +3805 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +7 -5
- package/hooks/aight-bootstrap/handler.ts +0 -34
- package/index.ts +0 -78
- package/src/config.ts +0 -126
- package/src/defaults.ts +0 -5
- package/src/groups.ts +0 -71
- package/src/health.ts +0 -95
- package/src/items.ts +0 -252
- package/src/notif-prefs.ts +0 -115
- package/src/push-hook.ts +0 -162
- package/src/push.ts +0 -242
- package/src/reminders.ts +0 -91
- package/src/version.ts +0 -95
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aight-cool/aight-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "OpenClaw gateway plugin for Aight App: push notifications, Today items, config RPC, and agent bootstrap",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"hooks/",
|
|
7
|
+
"dist/",
|
|
8
|
+
"hooks/**/HOOK.md",
|
|
10
9
|
"openclaw.plugin.json",
|
|
11
10
|
"README.md",
|
|
12
11
|
"LICENSE"
|
|
@@ -29,6 +28,8 @@
|
|
|
29
28
|
"lint": "eslint . --ext .ts",
|
|
30
29
|
"format": "prettier --check .",
|
|
31
30
|
"format:fix": "prettier --write .",
|
|
31
|
+
"build": "tsup",
|
|
32
|
+
"prepublishOnly": "npm run build",
|
|
32
33
|
"ci": "npm run typecheck && npm run lint && npm run format && npm test"
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
@@ -45,13 +46,14 @@
|
|
|
45
46
|
"eslint": "^9.39.2",
|
|
46
47
|
"openclaw": "*",
|
|
47
48
|
"prettier": "^3.8.1",
|
|
49
|
+
"tsup": "^8.5.1",
|
|
48
50
|
"typescript": "^5.7.0",
|
|
49
51
|
"typescript-eslint": "^8.55.0",
|
|
50
52
|
"vitest": "^3.0.0"
|
|
51
53
|
},
|
|
52
54
|
"openclaw": {
|
|
53
55
|
"extensions": [
|
|
54
|
-
"./index.
|
|
56
|
+
"./dist/index.js"
|
|
55
57
|
]
|
|
56
58
|
}
|
|
57
59
|
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Aight bootstrap hook — injects AIGHT.md into agent bootstrap context
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { getBootstrapContent } from "../../src/bootstrap.js";
|
|
6
|
-
|
|
7
|
-
interface HookEvent {
|
|
8
|
-
type: string;
|
|
9
|
-
action: string;
|
|
10
|
-
sessionKey: string;
|
|
11
|
-
timestamp: Date;
|
|
12
|
-
messages: string[];
|
|
13
|
-
context: {
|
|
14
|
-
bootstrapFiles?: Array<{ basename: string; content: string }>;
|
|
15
|
-
[key: string]: unknown;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const handler = async (event: HookEvent) => {
|
|
20
|
-
if (event.type !== "agent" || event.action !== "bootstrap") {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!event.context.bootstrapFiles) {
|
|
25
|
-
event.context.bootstrapFiles = [];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
event.context.bootstrapFiles.push({
|
|
29
|
-
basename: "AIGHT.md",
|
|
30
|
-
content: getBootstrapContent(),
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default handler;
|
package/index.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @aight/utils — OpenClaw gateway plugin
|
|
3
|
-
*
|
|
4
|
-
* Push notifications, Today items, config RPC, and agent bootstrap for the Aight app.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
8
|
-
import { registerConfig, getPluginConfig } from "./src/config.js";
|
|
9
|
-
import { registerItems } from "./src/items.js";
|
|
10
|
-
import { registerPush } from "./src/push.js";
|
|
11
|
-
import { registerReminders } from "./src/reminders.js";
|
|
12
|
-
import { registerBootstrap } from "./src/bootstrap.js";
|
|
13
|
-
import { registerPushHook } from "./src/push-hook.js";
|
|
14
|
-
import { registerHealth } from "./src/health.js";
|
|
15
|
-
import { registerVersion } from "./src/version.js";
|
|
16
|
-
import { registerGroupRpc } from "./src/groups.js";
|
|
17
|
-
import { registerNotifPrefsRPC } from "./src/notif-prefs.js";
|
|
18
|
-
|
|
19
|
-
const aightPlugin = {
|
|
20
|
-
id: "aight-utils",
|
|
21
|
-
name: "Aight Utilities",
|
|
22
|
-
description: "Push notifications, Today items, config RPC, and agent bootstrap for the Aight app",
|
|
23
|
-
|
|
24
|
-
configSchema: {
|
|
25
|
-
parse(value: unknown) {
|
|
26
|
-
const raw =
|
|
27
|
-
value && typeof value === "object" && !Array.isArray(value)
|
|
28
|
-
? (value as Record<string, unknown>)
|
|
29
|
-
: {};
|
|
30
|
-
return {
|
|
31
|
-
push: {
|
|
32
|
-
mode: (raw.push as any)?.mode ?? "private",
|
|
33
|
-
relayUrl: (raw.push as any)?.relayUrl ?? "https://push.aight.app",
|
|
34
|
-
relaySecret: (raw.push as any)?.relaySecret,
|
|
35
|
-
},
|
|
36
|
-
today: {
|
|
37
|
-
enabled: (raw.today as any)?.enabled ?? true,
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
uiHints: {
|
|
42
|
-
"push.mode": {
|
|
43
|
-
label: "Notification Mode",
|
|
44
|
-
help: "Private = silent wake. Rich = preview text in notification.",
|
|
45
|
-
},
|
|
46
|
-
"push.relayUrl": {
|
|
47
|
-
label: "Push Relay URL",
|
|
48
|
-
placeholder: "https://push.aight.app",
|
|
49
|
-
},
|
|
50
|
-
"push.relaySecret": {
|
|
51
|
-
label: "Relay Shared Secret",
|
|
52
|
-
sensitive: true,
|
|
53
|
-
},
|
|
54
|
-
"today.enabled": {
|
|
55
|
-
label: "Today View",
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
register(api: OpenClawPluginApi) {
|
|
61
|
-
const cfg = getPluginConfig(api);
|
|
62
|
-
|
|
63
|
-
registerConfig(api);
|
|
64
|
-
registerItems(api);
|
|
65
|
-
registerPush(api, cfg);
|
|
66
|
-
registerReminders(api, cfg);
|
|
67
|
-
registerBootstrap(api);
|
|
68
|
-
registerPushHook(api);
|
|
69
|
-
registerHealth(api);
|
|
70
|
-
registerVersion(api);
|
|
71
|
-
registerGroupRpc(api);
|
|
72
|
-
registerNotifPrefsRPC(api);
|
|
73
|
-
|
|
74
|
-
api.logger.info("[aight-utils] Plugin loaded");
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export default aightPlugin;
|
package/src/config.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config RPC module — aight.config.get, aight.config.patch, aight.status
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { OpenClawPluginApi, GatewayRequestHandlerOptions } from "openclaw/plugin-sdk";
|
|
6
|
-
import { DEFAULT_PUSH_MODE } from "./defaults.js";
|
|
7
|
-
|
|
8
|
-
export interface AightConfig {
|
|
9
|
-
push?: {
|
|
10
|
-
mode?: "private" | "rich";
|
|
11
|
-
relayUrl?: string;
|
|
12
|
-
relaySecret?: string;
|
|
13
|
-
};
|
|
14
|
-
today?: {
|
|
15
|
-
enabled?: boolean;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Strict allowlist of keys this plugin owns — anything else is rejected */
|
|
20
|
-
const PLUGIN_CONFIG_KEYS = new Set(["push", "today"]);
|
|
21
|
-
|
|
22
|
-
/** Secret keys that must never be returned to clients via RPC */
|
|
23
|
-
const SECRET_KEYS: string[] = ["relaySecret"];
|
|
24
|
-
|
|
25
|
-
/** Returns a sanitized copy of the config with secrets redacted */
|
|
26
|
-
export function getClientSafeConfig(config: AightConfig): Record<string, unknown> {
|
|
27
|
-
const safe = JSON.parse(JSON.stringify(config));
|
|
28
|
-
if (safe.push) {
|
|
29
|
-
for (const key of SECRET_KEYS) {
|
|
30
|
-
if (key in safe.push) {
|
|
31
|
-
safe.push[key] = safe.push[key] ? "[REDACTED]" : undefined;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return safe;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function getPluginConfig(api: OpenClawPluginApi): AightConfig {
|
|
39
|
-
const raw = api.pluginConfig;
|
|
40
|
-
return raw && typeof raw === "object" && !Array.isArray(raw) ? (raw as AightConfig) : {};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function registerConfig(api: OpenClawPluginApi) {
|
|
44
|
-
api.registerGatewayMethod("aight.config.get", ({ respond }: GatewayRequestHandlerOptions) => {
|
|
45
|
-
respond(true, getClientSafeConfig(getPluginConfig(api)));
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
api.registerGatewayMethod(
|
|
49
|
-
"aight.config.patch",
|
|
50
|
-
async ({ params, respond }: GatewayRequestHandlerOptions) => {
|
|
51
|
-
if (!params || typeof params !== "object") {
|
|
52
|
-
respond(false, { error: "params must be an object" });
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
// Reject any keys not in the plugin allowlist — never touch root gateway config
|
|
57
|
-
const incoming = params as Record<string, unknown>;
|
|
58
|
-
for (const key of Object.keys(incoming)) {
|
|
59
|
-
if (!PLUGIN_CONFIG_KEYS.has(key)) {
|
|
60
|
-
respond(false, { error: `Key "${key}" is not allowed in config.patch` });
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Load current config
|
|
66
|
-
const currentConfig = await api.runtime.config.loadConfig();
|
|
67
|
-
const pluginEntry = (currentConfig as any)?.plugins?.entries?.["aight-utils"] ?? {};
|
|
68
|
-
const currentPluginConfig = pluginEntry.config ?? {};
|
|
69
|
-
|
|
70
|
-
// Deep merge allowed plugin-level keys into plugin config
|
|
71
|
-
const merged = { ...currentPluginConfig };
|
|
72
|
-
for (const [key, value] of Object.entries(incoming)) {
|
|
73
|
-
if (
|
|
74
|
-
value &&
|
|
75
|
-
typeof value === "object" &&
|
|
76
|
-
!Array.isArray(value) &&
|
|
77
|
-
merged[key] &&
|
|
78
|
-
typeof merged[key] === "object"
|
|
79
|
-
) {
|
|
80
|
-
merged[key] = { ...merged[key], ...value };
|
|
81
|
-
} else {
|
|
82
|
-
merged[key] = value;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Build updated config — only the plugin's own config section is modified;
|
|
87
|
-
// root gateway config is preserved as-is and never overwritten by client input.
|
|
88
|
-
const updatedConfig: Record<string, unknown> = {
|
|
89
|
-
...(currentConfig as Record<string, unknown>),
|
|
90
|
-
plugins: {
|
|
91
|
-
...((currentConfig as any)?.plugins ?? {}),
|
|
92
|
-
entries: {
|
|
93
|
-
...((currentConfig as any)?.plugins?.entries ?? {}),
|
|
94
|
-
"aight-utils": {
|
|
95
|
-
...pluginEntry,
|
|
96
|
-
config: merged,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
await api.runtime.config.writeConfigFile(updatedConfig as any);
|
|
103
|
-
respond(true, { ok: true, config: getClientSafeConfig(merged as AightConfig) });
|
|
104
|
-
} catch (err) {
|
|
105
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
106
|
-
api.logger.error(`[aight-utils] config.patch failed: ${msg}`);
|
|
107
|
-
respond(false, { error: msg });
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
api.registerGatewayMethod("aight.status", ({ respond }: GatewayRequestHandlerOptions) => {
|
|
113
|
-
const cfg = getPluginConfig(api);
|
|
114
|
-
respond(true, {
|
|
115
|
-
ok: true,
|
|
116
|
-
version: "0.1.0",
|
|
117
|
-
push: {
|
|
118
|
-
mode: cfg.push?.mode ?? DEFAULT_PUSH_MODE,
|
|
119
|
-
relayUrl: cfg.push?.relayUrl ?? "https://push.aight.app",
|
|
120
|
-
},
|
|
121
|
-
today: {
|
|
122
|
-
enabled: cfg.today?.enabled ?? true,
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
}
|
package/src/defaults.ts
DELETED
package/src/groups.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Group name store — simple mapping of groupId → display name.
|
|
3
|
-
* The app registers group names via RPC so push notifications
|
|
4
|
-
* can show friendly titles instead of raw IDs.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
8
|
-
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
9
|
-
import { join } from "path";
|
|
10
|
-
|
|
11
|
-
const FILENAME = "group-names.json";
|
|
12
|
-
|
|
13
|
-
function filePath(api: OpenClawPluginApi): string {
|
|
14
|
-
const dir =
|
|
15
|
-
(api as any).dataDir ??
|
|
16
|
-
join(process.env.HOME ?? "/tmp", ".openclaw", "plugin-data", "aight-utils");
|
|
17
|
-
mkdirSync(dir, { recursive: true });
|
|
18
|
-
return join(dir, FILENAME);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function loadAll(api: OpenClawPluginApi): Record<string, string> {
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(readFileSync(filePath(api), "utf-8"));
|
|
24
|
-
} catch {
|
|
25
|
-
return {};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function saveAll(api: OpenClawPluginApi, data: Record<string, string>): void {
|
|
30
|
-
writeFileSync(filePath(api), JSON.stringify(data), "utf-8");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function loadGroupName(api: OpenClawPluginApi, groupId: string): string | undefined {
|
|
34
|
-
return loadAll(api)[groupId];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function registerGroupName(api: OpenClawPluginApi, groupId: string, name: string): void {
|
|
38
|
-
const data = loadAll(api);
|
|
39
|
-
data[groupId] = name;
|
|
40
|
-
saveAll(api, data);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function removeGroupName(api: OpenClawPluginApi, groupId: string): void {
|
|
44
|
-
const data = loadAll(api);
|
|
45
|
-
delete data[groupId];
|
|
46
|
-
saveAll(api, data);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function registerGroupRpc(api: OpenClawPluginApi): void {
|
|
50
|
-
api.registerGatewayMethod("aight.groups.setName", ({ params, respond }: any) => {
|
|
51
|
-
const { groupId, name } = (params ?? {}) as { groupId?: string; name?: string };
|
|
52
|
-
if (!groupId || !name) {
|
|
53
|
-
respond(false, { error: "groupId and name are required" });
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
registerGroupName(api, groupId, name);
|
|
57
|
-
respond(true, { ok: true });
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
api.registerGatewayMethod("aight.groups.removeName", ({ params, respond }: any) => {
|
|
61
|
-
const { groupId } = (params ?? {}) as { groupId?: string };
|
|
62
|
-
if (!groupId) {
|
|
63
|
-
respond(false, { error: "groupId is required" });
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
removeGroupName(api, groupId);
|
|
67
|
-
respond(true, { ok: true });
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
api.logger.info("[aight-utils] Group name RPC registered");
|
|
71
|
-
}
|
package/src/health.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* System health RPC — aight.health
|
|
3
|
-
*
|
|
4
|
-
* Returns memory, CPU, disk stats without needing an LLM call.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { execSync } from "child_process";
|
|
8
|
-
import { platform } from "os";
|
|
9
|
-
import type { OpenClawPluginApi, GatewayRequestHandlerOptions } from "openclaw/plugin-sdk";
|
|
10
|
-
|
|
11
|
-
interface HealthStats {
|
|
12
|
-
memory: { usedGB: number; totalGB: number; percent: number } | null;
|
|
13
|
-
cpu: { percent: number } | null;
|
|
14
|
-
disk: { usedGB: number; totalGB: number; percent: number } | null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function getStats(): HealthStats {
|
|
18
|
-
const os = platform();
|
|
19
|
-
let memory: HealthStats["memory"] = null;
|
|
20
|
-
let cpu: HealthStats["cpu"] = null;
|
|
21
|
-
let disk: HealthStats["disk"] = null;
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
if (os === "darwin") {
|
|
25
|
-
// Memory
|
|
26
|
-
const totalBytes = parseInt(
|
|
27
|
-
execSync("/usr/sbin/sysctl -n hw.memsize", { encoding: "utf8", timeout: 5000 }).trim(),
|
|
28
|
-
);
|
|
29
|
-
const top = execSync("top -l 1 -n 0", { encoding: "utf8", timeout: 5000 });
|
|
30
|
-
const memMatch = top.match(/PhysMem:\s*(\d+)([GM])\s*used/);
|
|
31
|
-
const usedGB = memMatch ? parseInt(memMatch[1]) * (memMatch[2] === "G" ? 1 : 1 / 1024) : 0;
|
|
32
|
-
const totalGB = totalBytes / 1073741824;
|
|
33
|
-
memory = {
|
|
34
|
-
usedGB: Math.round(usedGB * 10) / 10,
|
|
35
|
-
totalGB: Math.round(totalGB * 10) / 10,
|
|
36
|
-
percent: Math.round((usedGB / totalGB) * 100),
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// CPU
|
|
40
|
-
const idleMatch = top.match(/([\d.]+)% idle/);
|
|
41
|
-
cpu = {
|
|
42
|
-
percent: idleMatch ? Math.round(100 - parseFloat(idleMatch[1])) : 0,
|
|
43
|
-
};
|
|
44
|
-
} else {
|
|
45
|
-
// Linux memory
|
|
46
|
-
const meminfo = execSync("cat /proc/meminfo", { encoding: "utf8", timeout: 5000 });
|
|
47
|
-
const totalKB = parseInt(meminfo.match(/MemTotal:\s*(\d+)/)?.[1] ?? "0");
|
|
48
|
-
const availKB = parseInt(meminfo.match(/MemAvailable:\s*(\d+)/)?.[1] ?? "0");
|
|
49
|
-
const totalGB = (totalKB * 1024) / 1073741824;
|
|
50
|
-
const usedGB = ((totalKB - availKB) * 1024) / 1073741824;
|
|
51
|
-
memory = {
|
|
52
|
-
usedGB: Math.round(usedGB * 10) / 10,
|
|
53
|
-
totalGB: Math.round(totalGB * 10) / 10,
|
|
54
|
-
percent: Math.round((usedGB / totalGB) * 100),
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// Linux CPU
|
|
58
|
-
const loadavg = execSync("cat /proc/loadavg", { encoding: "utf8", timeout: 5000 });
|
|
59
|
-
const load1m = parseFloat(loadavg.split(" ")[0]);
|
|
60
|
-
const cores = parseInt(execSync("nproc", { encoding: "utf8", timeout: 5000 }).trim());
|
|
61
|
-
cpu = { percent: Math.round(Math.min((load1m / cores) * 100, 100)) };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Disk (cross-platform via df)
|
|
65
|
-
const df = execSync("df -k /", { encoding: "utf8", timeout: 5000 });
|
|
66
|
-
const dfLine = df.split("\n")[1];
|
|
67
|
-
const dfParts = dfLine?.split(/\s+/);
|
|
68
|
-
if (dfParts && dfParts.length >= 4) {
|
|
69
|
-
const totalKB = parseInt(dfParts[1]);
|
|
70
|
-
const usedKB = parseInt(dfParts[2]);
|
|
71
|
-
disk = {
|
|
72
|
-
totalGB: Math.round(totalKB / 1048576),
|
|
73
|
-
usedGB: Math.round(usedKB / 1048576),
|
|
74
|
-
percent: Math.round((usedKB / totalKB) * 100),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
// Best effort — return whatever we got
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return { memory, cpu, disk };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function registerHealth(api: OpenClawPluginApi) {
|
|
85
|
-
api.registerGatewayMethod("aight.health", async ({ respond }: GatewayRequestHandlerOptions) => {
|
|
86
|
-
try {
|
|
87
|
-
const stats = getStats();
|
|
88
|
-
respond(true, stats);
|
|
89
|
-
} catch (err) {
|
|
90
|
-
respond(false, {
|
|
91
|
-
error: err instanceof Error ? err.message : String(err),
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|