openclaw-molymemos 1.0.0

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/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # MolyMemos OpenClaw Plugin
2
+
3
+ OpenClaw 插件,通过 WebSocket 连接到服务器,接收推送的内容并写入 memory 文件夹。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install
9
+ npm run build
10
+ ```
11
+
12
+ ## 配置
13
+
14
+ 在 OpenClaw 配置文件中添加插件配置:
15
+
16
+ ```json5
17
+ {
18
+ plugins: {
19
+ entries: {
20
+ "molymemos": {
21
+ enabled: true,
22
+ config: {
23
+ serverUrl: "ws://localhost:8080", // 必填,WebSocket 服务器地址
24
+ apiKey: "your-api-key", // 可选,认证密钥
25
+ reconnectInterval: 5000 // 可选,重连间隔(ms),默认 5000
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ### 配置项
34
+
35
+ | 参数 | 类型 | 必填 | 说明 |
36
+ |------|------|------|------|
37
+ | `serverUrl` | string | 是 | WebSocket 服务器地址 |
38
+ | `apiKey` | string | 否 | API 认证密钥 |
39
+ | `reconnectInterval` | number | 否 | 重连间隔(ms),默认 5000 |
40
+
41
+ ## 工作原理
42
+
43
+ 1. 插件启动时建立 WebSocket 连接到配置的服务器
44
+ 2. 监听服务器推送的消息
45
+ 3. 收到消息后将内容 append 到 `{workspaceDir}/memory/molymemos/{filepath}`
46
+ 4. 连接断开后自动重连
47
+
48
+ ## 服务器消息格式
49
+
50
+ 服务器推送的消息需要符合以下 JSON 格式:
51
+
52
+ ```json
53
+ {
54
+ "type": "memo",
55
+ "content": "要追加的内容",
56
+ "filepath": "notes/daily.md"
57
+ }
58
+ ```
59
+
60
+ ## 接口
61
+
62
+ ### Gateway RPC 方法
63
+
64
+ #### `molymemos.append`
65
+
66
+ 手动追加内容到文件。
67
+
68
+ 参数:
69
+ ```json
70
+ {
71
+ "content": "要追加的内容",
72
+ "filepath": "相对路径,如 notes/2024/01/15.md"
73
+ }
74
+ ```
75
+
76
+ #### `molymemos.status`
77
+
78
+ 获取插件状态。
79
+
80
+ 响应:
81
+ ```json
82
+ {
83
+ "serverUrl": "ws://localhost:8080",
84
+ "connected": true,
85
+ "workspaceDir": "~/.openclaw/workspace",
86
+ "molyMemosDir": "~/.openclaw/workspace/memory/molymemos"
87
+ }
88
+ ```
89
+
90
+ ### HTTP 路由
91
+
92
+ #### `POST /molymemos/append`
93
+
94
+ 手动追加内容到文件。
95
+
96
+ ```bash
97
+ curl -X POST http://localhost:port/molymemos/append \
98
+ -H "Content-Type: application/json" \
99
+ -d '{"content": "Hello World", "filepath": "test.md"}'
100
+ ```
101
+
102
+ #### `GET /molymemos/status`
103
+
104
+ 获取插件状态。
105
+
106
+ ### Agent 工具
107
+
108
+ #### `append_memo`
109
+
110
+ Agent 可调用的工具,用于追加内容到记忆文件夹。
111
+
112
+ 参数:
113
+ - `content`: 要追加的内容
114
+ - `filepath`: 相对文件路径
115
+
116
+ ## 文件结构
117
+
118
+ 内容会被追加到 `{workspaceDir}/memory/molymemos/{filepath}` 路径下。
119
+
120
+ 例如,如果 `workspaceDir` 是 `~/.openclaw/workspace`,`filepath` 是 `notes/daily.md`,
121
+ 那么内容会追加到 `~/.openclaw/workspace/memory/molymemos/notes/daily.md`。
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
3
+ declare const molyMemosPlugin: {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ configSchema: z.ZodObject<{
8
+ serverUrl: z.ZodString;
9
+ apiKey: z.ZodOptional<z.ZodString>;
10
+ reconnectInterval: z.ZodOptional<z.ZodNumber>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ serverUrl: string;
13
+ apiKey?: string | undefined;
14
+ reconnectInterval?: number | undefined;
15
+ }, {
16
+ serverUrl: string;
17
+ apiKey?: string | undefined;
18
+ reconnectInterval?: number | undefined;
19
+ }>;
20
+ register(api: OpenClawPluginApi): void;
21
+ };
22
+ export default molyMemosPlugin;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAW7D,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;kBAML,iBAAiB;CAyHhC,CAAC;AAEF,eAAe,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,120 @@
1
+ import { z } from "zod";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { MolyMemosServerClient } from "./server-client.js";
5
+ const configSchema = z.object({
6
+ serverUrl: z.string(),
7
+ apiKey: z.string().optional(),
8
+ reconnectInterval: z.number().optional(),
9
+ });
10
+ const molyMemosPlugin = {
11
+ id: "molymemos",
12
+ name: "MolyMemos",
13
+ description: "Receive content from server via WebSocket and append to memory folder",
14
+ configSchema,
15
+ register(api) {
16
+ const config = configSchema.parse(api.pluginConfig);
17
+ const logger = api.logger;
18
+ const serverClient = new MolyMemosServerClient({
19
+ serverUrl: config.serverUrl,
20
+ apiKey: config.apiKey,
21
+ reconnectInterval: config.reconnectInterval,
22
+ });
23
+ serverClient.setLogger(logger);
24
+ const resolveWorkspaceDir = () => {
25
+ const stateDir = api.runtime.state.resolveStateDir();
26
+ return path.join(stateDir, "workspace");
27
+ };
28
+ const getMolyMemosPath = (filepath) => {
29
+ const wsDir = resolveWorkspaceDir();
30
+ return path.join(wsDir, "memory", "molymemos", filepath);
31
+ };
32
+ const ensureDirectoryExists = (filePath) => {
33
+ const dir = path.dirname(filePath);
34
+ if (!fs.existsSync(dir)) {
35
+ fs.mkdirSync(dir, { recursive: true });
36
+ }
37
+ };
38
+ const appendToFile = (content, filepath) => {
39
+ const fullPath = getMolyMemosPath(filepath);
40
+ ensureDirectoryExists(fullPath);
41
+ try {
42
+ fs.appendFileSync(fullPath, content + "\n", "utf-8");
43
+ logger.info(`Content appended to ${fullPath}`);
44
+ return {
45
+ success: true,
46
+ message: `Content successfully appended to ${filepath}`,
47
+ fullPath,
48
+ };
49
+ }
50
+ catch (error) {
51
+ const errorMessage = error instanceof Error ? error.message : String(error);
52
+ logger.error(`Failed to append content to ${fullPath}: ${errorMessage}`);
53
+ return {
54
+ success: false,
55
+ message: `Failed to append content: ${errorMessage}`,
56
+ fullPath,
57
+ };
58
+ }
59
+ };
60
+ const handleServerMessage = async (message) => {
61
+ const result = appendToFile(message.content, message.filepath);
62
+ if (!result.success) {
63
+ logger.error(`Failed to handle server message: ${result.message}`);
64
+ }
65
+ };
66
+ serverClient.setMessageHandler(handleServerMessage);
67
+ api.registerGatewayMethod("molymemos.append", async ({ params, respond }) => {
68
+ try {
69
+ const parsed = z.object({
70
+ content: z.string(),
71
+ filepath: z.string(),
72
+ }).parse(params);
73
+ const result = appendToFile(parsed.content, parsed.filepath);
74
+ if (result.success) {
75
+ respond(true, result);
76
+ }
77
+ else {
78
+ respond(false, { error: result.message });
79
+ }
80
+ }
81
+ catch (error) {
82
+ const errorMessage = error instanceof Error ? error.message : String(error);
83
+ logger.error(`molymemos.append error: ${errorMessage}`);
84
+ respond(false, { error: errorMessage });
85
+ }
86
+ });
87
+ api.registerGatewayMethod("molymemos.status", async ({ respond }) => {
88
+ const wsDir = resolveWorkspaceDir();
89
+ respond(true, {
90
+ serverUrl: config.serverUrl,
91
+ connected: serverClient.isConnected(),
92
+ workspaceDir: wsDir,
93
+ molyMemosDir: path.join(wsDir, "memory", "molymemos"),
94
+ });
95
+ });
96
+ api.registerService({
97
+ id: "molymemos",
98
+ start: async () => {
99
+ logger.info("MolyMemos service starting...");
100
+ logger.info(`Connecting to server: ${config.serverUrl}`);
101
+ const connected = await serverClient.connect();
102
+ if (connected) {
103
+ logger.info("Connected to MolyMemos server");
104
+ }
105
+ else {
106
+ logger.warn("Failed to connect to server, will retry...");
107
+ }
108
+ },
109
+ stop: async () => {
110
+ logger.info("MolyMemos service stopping...");
111
+ await serverClient.disconnect();
112
+ },
113
+ });
114
+ const defaultWsDir = resolveWorkspaceDir();
115
+ logger.info(`MolyMemos plugin registered, molymemos path: ${path.join(defaultWsDir, "memory", "molymemos")}`);
116
+ logger.info(`Server URL: ${config.serverUrl}`);
117
+ },
118
+ };
119
+ export default molyMemosPlugin;
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ {
2
+ "id": "molymemos",
3
+ "name": "MolyMemos",
4
+ "description": "Receive content from server via WebSocket and append to memory folder",
5
+ "version": "1.0.0",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "serverUrl": {
11
+ "type": "string",
12
+ "description": "WebSocket server URL to connect to (e.g. ws://localhost:8080 or wss://example.com)"
13
+ },
14
+ "apiKey": {
15
+ "type": "string",
16
+ "description": "API key for authentication"
17
+ },
18
+ "reconnectInterval": {
19
+ "type": "number",
20
+ "description": "Reconnect interval in milliseconds",
21
+ "default": 5000
22
+ }
23
+ },
24
+ "required": ["serverUrl"]
25
+ }
26
+ }
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ export interface PluginLogger {
3
+ debug?: (message: string) => void;
4
+ info: (message: string) => void;
5
+ warn: (message: string) => void;
6
+ error: (message: string) => void;
7
+ }
8
+ export interface ServerConfig {
9
+ serverUrl: string;
10
+ apiKey?: string;
11
+ reconnectInterval?: number;
12
+ }
13
+ declare const memoMessageSchema: z.ZodObject<{
14
+ type: z.ZodLiteral<"memo">;
15
+ content: z.ZodString;
16
+ filepath: z.ZodString;
17
+ }, "strip", z.ZodTypeAny, {
18
+ type: "memo";
19
+ content: string;
20
+ filepath: string;
21
+ }, {
22
+ type: "memo";
23
+ content: string;
24
+ filepath: string;
25
+ }>;
26
+ export type MemoMessage = z.infer<typeof memoMessageSchema>;
27
+ export type MessageHandler = (message: MemoMessage) => Promise<void>;
28
+ export declare class MolyMemosServerClient {
29
+ private serverUrl;
30
+ private apiKey?;
31
+ private reconnectInterval;
32
+ private ws;
33
+ private connected;
34
+ private shouldReconnect;
35
+ private reconnectTimer;
36
+ private messageHandler;
37
+ private logger;
38
+ constructor(config: ServerConfig);
39
+ setLogger(logger: PluginLogger): void;
40
+ setMessageHandler(handler: MessageHandler): void;
41
+ connect(): Promise<boolean>;
42
+ private doConnect;
43
+ private handleMessage;
44
+ private scheduleReconnect;
45
+ disconnect(): Promise<void>;
46
+ isConnected(): boolean;
47
+ }
48
+ export {};
49
+ //# sourceMappingURL=server-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-client.d.ts","sourceRoot":"","sources":["../src/server-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,QAAA,MAAM,iBAAiB;;;;;;;;;;;;EAIrB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAErE,qBAAa,qBAAqB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,EAAE,YAAY;IAMhC,SAAS,CAAC,MAAM,EAAE,YAAY;IAI9B,iBAAiB,CAAC,OAAO,EAAE,cAAc;IAInC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IASjC,OAAO,CAAC,SAAS;IA4CjB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,iBAAiB;IAiBnB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBjC,WAAW,IAAI,OAAO;CAGvB"}
@@ -0,0 +1,124 @@
1
+ import { z } from "zod";
2
+ import WebSocket from "ws";
3
+ const memoMessageSchema = z.object({
4
+ type: z.literal("memo"),
5
+ content: z.string(),
6
+ filepath: z.string(),
7
+ });
8
+ export class MolyMemosServerClient {
9
+ serverUrl;
10
+ apiKey;
11
+ reconnectInterval;
12
+ ws = null;
13
+ connected = false;
14
+ shouldReconnect = false;
15
+ reconnectTimer = null;
16
+ messageHandler = null;
17
+ logger = null;
18
+ constructor(config) {
19
+ this.serverUrl = config.serverUrl.replace(/^http/, "ws").replace(/\/$/, "");
20
+ this.apiKey = config.apiKey;
21
+ this.reconnectInterval = config.reconnectInterval ?? 5000;
22
+ }
23
+ setLogger(logger) {
24
+ this.logger = logger;
25
+ }
26
+ setMessageHandler(handler) {
27
+ this.messageHandler = handler;
28
+ }
29
+ async connect() {
30
+ if (this.ws && this.connected) {
31
+ return true;
32
+ }
33
+ this.shouldReconnect = true;
34
+ return this.doConnect();
35
+ }
36
+ doConnect() {
37
+ return new Promise((resolve) => {
38
+ if (!this.shouldReconnect) {
39
+ resolve(false);
40
+ return;
41
+ }
42
+ try {
43
+ const url = this.apiKey
44
+ ? `${this.serverUrl}/ws?token=${encodeURIComponent(this.apiKey)}`
45
+ : `${this.serverUrl}/ws`;
46
+ this.logger?.info(`Connecting to WebSocket: ${this.serverUrl}/ws`);
47
+ this.ws = new WebSocket(url);
48
+ this.ws.on("open", () => {
49
+ this.connected = true;
50
+ this.logger?.info("WebSocket connected");
51
+ resolve(true);
52
+ });
53
+ this.ws.on("message", (data) => {
54
+ this.handleMessage(data);
55
+ });
56
+ this.ws.on("close", (code, reason) => {
57
+ this.connected = false;
58
+ this.logger?.info(`WebSocket closed: ${code} ${reason?.toString() || ""}`);
59
+ this.scheduleReconnect();
60
+ });
61
+ this.ws.on("error", (err) => {
62
+ this.logger?.error(`WebSocket error: ${err.message}`);
63
+ this.connected = false;
64
+ resolve(false);
65
+ });
66
+ }
67
+ catch (error) {
68
+ this.logger?.error(`Failed to create WebSocket: ${error}`);
69
+ this.connected = false;
70
+ resolve(false);
71
+ }
72
+ });
73
+ }
74
+ handleMessage(data) {
75
+ try {
76
+ const raw = typeof data === "string" ? data : data.toString();
77
+ const json = JSON.parse(raw);
78
+ const parsed = memoMessageSchema.safeParse(json);
79
+ if (parsed.success && this.messageHandler) {
80
+ this.logger?.debug?.(`Received memo: ${parsed.data.filepath}`);
81
+ this.messageHandler(parsed.data).catch((err) => {
82
+ this.logger?.error(`Error handling message: ${err}`);
83
+ });
84
+ }
85
+ else if (!parsed.success) {
86
+ this.logger?.debug?.(`Ignored message: ${raw.slice(0, 100)}`);
87
+ }
88
+ }
89
+ catch (error) {
90
+ this.logger?.error(`Failed to parse message: ${error}`);
91
+ }
92
+ }
93
+ scheduleReconnect() {
94
+ if (!this.shouldReconnect) {
95
+ return;
96
+ }
97
+ if (this.reconnectTimer) {
98
+ clearTimeout(this.reconnectTimer);
99
+ }
100
+ this.logger?.info(`Reconnecting in ${this.reconnectInterval}ms...`);
101
+ this.reconnectTimer = setTimeout(() => {
102
+ if (this.shouldReconnect) {
103
+ this.doConnect().catch(() => { });
104
+ }
105
+ }, this.reconnectInterval);
106
+ }
107
+ async disconnect() {
108
+ this.shouldReconnect = false;
109
+ if (this.reconnectTimer) {
110
+ clearTimeout(this.reconnectTimer);
111
+ this.reconnectTimer = null;
112
+ }
113
+ if (this.ws) {
114
+ this.ws.close();
115
+ this.ws = null;
116
+ }
117
+ this.connected = false;
118
+ this.logger?.info("WebSocket disconnected");
119
+ }
120
+ isConnected() {
121
+ return this.connected;
122
+ }
123
+ }
124
+ //# sourceMappingURL=server-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-client.js","sourceRoot":"","sources":["../src/server-client.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "openclaw-molymemos",
3
+ "version": "1.0.0",
4
+ "description": "OpenClaw plugin for MolyMemos - append content to memory folder",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "build": "tsc && cp openclaw.plugin.json dist/",
10
+ "dev": "tsc --watch",
11
+ "clean": "rm -rf dist",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "keywords": [
18
+ "openclaw",
19
+ "plugin",
20
+ "molymemos",
21
+ "memory"
22
+ ],
23
+ "dependencies": {
24
+ "ws": "^8.16.0",
25
+ "zod": "^3.22.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.10.0",
29
+ "@types/ws": "^8.5.10",
30
+ "typescript": "^5.3.0"
31
+ },
32
+ "peerDependencies": {
33
+ "openclaw": "*"
34
+ }
35
+ }