@kalera/munin-openclaw 1.0.1 → 1.1.2
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/.turbo/turbo-build.log +1 -1
- package/SKILL.md +7 -4
- package/dist/index.d.ts +8 -7
- package/dist/index.js +99 -7
- package/openclaw.plugin.json +22 -0
- package/package.json +9 -5
- package/postinstall.js +6 -0
- package/src/index.ts +111 -13
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -34
- package/src/cli.ts +0 -47
package/.turbo/turbo-build.log
CHANGED
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "@kalera/munin-openclaw"
|
|
3
3
|
description: "Munin - The Free (or $1.6/mo) Persistent Memory for OpenClaw. Stop your agent from having Alzheimer's."
|
|
4
|
-
version: "1.0.
|
|
4
|
+
version: "1.0.1"
|
|
5
5
|
metadata:
|
|
6
6
|
clawdbot:
|
|
7
7
|
type: "plugin"
|
|
@@ -50,9 +50,12 @@ If your Munin project has **E2EE with GraphRAG** enabled, standard E2EE rules ap
|
|
|
50
50
|
## 🚀 Setup (Fast & Honest)
|
|
51
51
|
|
|
52
52
|
1. **Get your Munin key:** Grab a **free** cloud key at [munin.kalera.dev](https://munin.kalera.dev).
|
|
53
|
-
2. **Configure OpenClaw:**
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
2. **Configure OpenClaw:** Once installed via `openclaw plugins install @kalera/munin-openclaw`, you can set your API key directly via the OpenClaw CLI without manually editing any config files:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
openclaw config set plugins.entries.munin-memory.config.apiKey "your-api-key-here"
|
|
57
|
+
```
|
|
58
|
+
*(Alternatively, you can just set `MUNIN_BASE_URL` and `MUNIN_API_KEY` environment variables).*
|
|
56
59
|
|
|
57
60
|
*(Note: Provide your agent with the `Context Core ID` in its system prompt so it knows which project to use when making tool calls).*
|
|
58
61
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
declare const _default: {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
kind: string;
|
|
6
|
+
configSchema: any;
|
|
7
|
+
register(api: any): void;
|
|
8
8
|
};
|
|
9
|
+
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,100 @@
|
|
|
1
1
|
import { MuninClient } from "@kalera/munin-sdk";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
export default {
|
|
5
|
+
id: "munin-memory",
|
|
6
|
+
name: "Munin ContextKeep",
|
|
7
|
+
description: "Persistent memory tools for OpenClaw agents.",
|
|
8
|
+
kind: "memory",
|
|
9
|
+
configSchema: z.object({
|
|
10
|
+
baseUrl: z
|
|
11
|
+
.string()
|
|
12
|
+
.default("https://munin.kalera.dev")
|
|
13
|
+
.describe("The base URL for your Munin ContextKeep server."),
|
|
14
|
+
apiKey: z.string().optional().describe("Your API key for Munin."),
|
|
15
|
+
}),
|
|
16
|
+
register(api) {
|
|
17
|
+
const baseUrl = api.pluginConfig?.baseUrl ||
|
|
18
|
+
process.env.MUNIN_BASE_URL ||
|
|
19
|
+
"https://munin.kalera.dev";
|
|
20
|
+
const apiKey = api.pluginConfig?.apiKey || process.env.MUNIN_API_KEY;
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
api.logger.warn("Munin API key is missing. ContextKeep tools will not be registered.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const client = new MuninClient({ baseUrl, apiKey });
|
|
26
|
+
api.registerTool({
|
|
27
|
+
name: "munin_store_memory",
|
|
28
|
+
label: "Store Munin Memory",
|
|
29
|
+
description: "Store a new memory or update an existing one in ContextKeep.",
|
|
30
|
+
parameters: Type.Object({
|
|
31
|
+
projectId: Type.String({
|
|
32
|
+
description: "The Context Core ID for isolation.",
|
|
33
|
+
}),
|
|
34
|
+
key: Type.String({ description: "Unique identifier for the memory." }),
|
|
35
|
+
content: Type.String({ description: "The content of the memory." }),
|
|
36
|
+
tags: Type.Optional(Type.String({ description: "Comma-separated list of tags." })),
|
|
37
|
+
title: Type.Optional(Type.String({ description: "Human-readable title." })),
|
|
38
|
+
}),
|
|
39
|
+
async execute(_toolCallId, params) {
|
|
40
|
+
const { projectId, ...payload } = params;
|
|
41
|
+
const res = await client.invoke(projectId, "store", payload);
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: JSON.stringify(res.data, null, 2),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
details: res.data,
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
api.registerTool({
|
|
54
|
+
name: "munin_retrieve_memory",
|
|
55
|
+
label: "Retrieve Munin Memory",
|
|
56
|
+
description: "Retrieve a memory by its key from ContextKeep.",
|
|
57
|
+
parameters: Type.Object({
|
|
58
|
+
projectId: Type.String({ description: "The Context Core ID." }),
|
|
59
|
+
key: Type.String({
|
|
60
|
+
description: "The unique identifier of the memory.",
|
|
61
|
+
}),
|
|
62
|
+
}),
|
|
63
|
+
async execute(_toolCallId, params) {
|
|
64
|
+
const { projectId, key } = params;
|
|
65
|
+
const res = await client.invoke(projectId, "retrieve", { key });
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify(res.data, null, 2),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
details: res.data,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
api.registerTool({
|
|
78
|
+
name: "munin_search_memories",
|
|
79
|
+
label: "Search Munin Memories",
|
|
80
|
+
description: "Search for memories by key, title, or content in ContextKeep.",
|
|
81
|
+
parameters: Type.Object({
|
|
82
|
+
projectId: Type.String({ description: "The Context Core ID." }),
|
|
83
|
+
query: Type.String({ description: "The search term." }),
|
|
84
|
+
}),
|
|
85
|
+
async execute(_toolCallId, params) {
|
|
86
|
+
const { projectId, query } = params;
|
|
87
|
+
const res = await client.invoke(projectId, "search", { query });
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: JSON.stringify(res.data, null, 2),
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
details: res.data,
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "munin-memory",
|
|
3
|
+
"name": "Munin ContextKeep",
|
|
4
|
+
"description": "Persistent memory and Context Core for OpenClaw agents.",
|
|
5
|
+
"kind": "memory",
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"baseUrl": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"default": "https://munin.kalera.dev",
|
|
13
|
+
"description": "The base URL for your Munin ContextKeep server."
|
|
14
|
+
},
|
|
15
|
+
"apiKey": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Your API key for Munin."
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"skills": ["."]
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kalera/munin-openclaw",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"openclaw": {
|
|
6
6
|
"extensions": [
|
|
7
|
-
"./dist/
|
|
7
|
+
"./dist/index.js"
|
|
8
8
|
],
|
|
9
9
|
"requires": {
|
|
10
10
|
"env": [
|
|
@@ -13,17 +13,21 @@
|
|
|
13
13
|
]
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
-
"bin": {
|
|
17
|
-
"munin-openclaw": "dist/cli.js"
|
|
18
|
-
},
|
|
19
16
|
"dependencies": {
|
|
17
|
+
"@sinclair/typebox": "^0.34.49",
|
|
18
|
+
"zod": "^4.3.6",
|
|
20
19
|
"@kalera/munin-sdk": "1.0.0",
|
|
21
20
|
"@kalera/munin-runtime": "1.0.0"
|
|
22
21
|
},
|
|
23
22
|
"devDependencies": {
|
|
23
|
+
"openclaw": "^2026.3.28",
|
|
24
24
|
"typescript": "^5.9.2"
|
|
25
25
|
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"openclaw": "^2026.3.0"
|
|
28
|
+
},
|
|
26
29
|
"scripts": {
|
|
30
|
+
"postinstall": "node ./postinstall.js",
|
|
27
31
|
"build": "tsc -p tsconfig.json",
|
|
28
32
|
"lint": "tsc -p tsconfig.json --noEmit",
|
|
29
33
|
"test": "echo 'adapter-openclaw tests: pending'"
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
console.log('\n\x1b[36m=================================================================\x1b[0m');
|
|
2
|
+
console.log('\x1b[36m\x1b[1m🐦 Munin ContextKeep successfully installed for OpenClaw!\x1b[0m');
|
|
3
|
+
console.log('\x1b[36m=================================================================\x1b[0m\n');
|
|
4
|
+
console.log('To activate your Munin Memory plugin, set your API key by running:\n');
|
|
5
|
+
console.log('\x1b[33m openclaw config set plugins.entries.munin-memory.config.apiKey "YOUR_API_KEY_HERE"\x1b[0m\n');
|
|
6
|
+
console.log('Get your free API key at: \x1b[32mhttps://munin.kalera.dev\x1b[0m\n');
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,114 @@
|
|
|
1
1
|
import { MuninClient } from "@kalera/munin-sdk";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { z } from "zod";
|
|
2
4
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
export default {
|
|
6
|
+
id: "munin-memory",
|
|
7
|
+
name: "Munin ContextKeep",
|
|
8
|
+
description: "Persistent memory tools for OpenClaw agents.",
|
|
9
|
+
kind: "memory",
|
|
10
|
+
configSchema: z.object({
|
|
11
|
+
baseUrl: z
|
|
12
|
+
.string()
|
|
13
|
+
.default("https://munin.kalera.dev")
|
|
14
|
+
.describe("The base URL for your Munin ContextKeep server."),
|
|
15
|
+
apiKey: z.string().optional().describe("Your API key for Munin."),
|
|
16
|
+
}) as any,
|
|
17
|
+
register(api: any) {
|
|
18
|
+
const baseUrl =
|
|
19
|
+
(api.pluginConfig?.baseUrl as string) ||
|
|
20
|
+
process.env.MUNIN_BASE_URL ||
|
|
21
|
+
"https://munin.kalera.dev";
|
|
22
|
+
const apiKey =
|
|
23
|
+
(api.pluginConfig?.apiKey as string) || process.env.MUNIN_API_KEY;
|
|
10
24
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
25
|
+
if (!apiKey) {
|
|
26
|
+
api.logger.warn(
|
|
27
|
+
"Munin API key is missing. ContextKeep tools will not be registered.",
|
|
28
|
+
);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const client = new MuninClient({ baseUrl, apiKey });
|
|
33
|
+
|
|
34
|
+
api.registerTool({
|
|
35
|
+
name: "munin_store_memory",
|
|
36
|
+
label: "Store Munin Memory",
|
|
37
|
+
description: "Store a new memory or update an existing one in ContextKeep.",
|
|
38
|
+
parameters: Type.Object({
|
|
39
|
+
projectId: Type.String({
|
|
40
|
+
description: "The Context Core ID for isolation.",
|
|
41
|
+
}),
|
|
42
|
+
key: Type.String({ description: "Unique identifier for the memory." }),
|
|
43
|
+
content: Type.String({ description: "The content of the memory." }),
|
|
44
|
+
tags: Type.Optional(
|
|
45
|
+
Type.String({ description: "Comma-separated list of tags." }),
|
|
46
|
+
),
|
|
47
|
+
title: Type.Optional(
|
|
48
|
+
Type.String({ description: "Human-readable title." }),
|
|
49
|
+
),
|
|
50
|
+
}),
|
|
51
|
+
async execute(_toolCallId: string, params: any) {
|
|
52
|
+
const { projectId, ...payload } = params;
|
|
53
|
+
const res = await client.invoke(projectId, "store", payload);
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: JSON.stringify(res.data, null, 2),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
details: res.data,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
api.registerTool({
|
|
67
|
+
name: "munin_retrieve_memory",
|
|
68
|
+
label: "Retrieve Munin Memory",
|
|
69
|
+
description: "Retrieve a memory by its key from ContextKeep.",
|
|
70
|
+
parameters: Type.Object({
|
|
71
|
+
projectId: Type.String({ description: "The Context Core ID." }),
|
|
72
|
+
key: Type.String({
|
|
73
|
+
description: "The unique identifier of the memory.",
|
|
74
|
+
}),
|
|
75
|
+
}),
|
|
76
|
+
async execute(_toolCallId: string, params: any) {
|
|
77
|
+
const { projectId, key } = params;
|
|
78
|
+
const res = await client.invoke(projectId, "retrieve", { key });
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: "text",
|
|
83
|
+
text: JSON.stringify(res.data, null, 2),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
details: res.data,
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
api.registerTool({
|
|
92
|
+
name: "munin_search_memories",
|
|
93
|
+
label: "Search Munin Memories",
|
|
94
|
+
description: "Search for memories by key, title, or content in ContextKeep.",
|
|
95
|
+
parameters: Type.Object({
|
|
96
|
+
projectId: Type.String({ description: "The Context Core ID." }),
|
|
97
|
+
query: Type.String({ description: "The search term." }),
|
|
98
|
+
}),
|
|
99
|
+
async execute(_toolCallId: string, params: any) {
|
|
100
|
+
const { projectId, query } = params;
|
|
101
|
+
const res = await client.invoke(projectId, "search", { query });
|
|
102
|
+
return {
|
|
103
|
+
content: [
|
|
104
|
+
{
|
|
105
|
+
type: "text",
|
|
106
|
+
text: JSON.stringify(res.data, null, 2),
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
details: res.data,
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
};
|
package/dist/cli.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/cli.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { executeWithRetry, loadCliEnv, parseCliArgs, safeError, startMcpServer, } from "@kalera/munin-runtime";
|
|
2
|
-
import { createOpenClawMuninAdapter } from "./index.js";
|
|
3
|
-
async function main() {
|
|
4
|
-
try {
|
|
5
|
-
const args = process.argv.slice(2);
|
|
6
|
-
// If no arguments, or 'mcp' is passed, start as MCP server
|
|
7
|
-
if (args.length === 0 || args[0] === 'mcp') {
|
|
8
|
-
await startMcpServer();
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
const { action, payload } = parseCliArgs(args, "Usage: munin-openclaw <action> [payload-json] OR munin-openclaw mcp");
|
|
12
|
-
const env = loadCliEnv();
|
|
13
|
-
const adapter = createOpenClawMuninAdapter({
|
|
14
|
-
baseUrl: env.baseUrl,
|
|
15
|
-
apiKey: env.apiKey,
|
|
16
|
-
timeoutMs: env.timeoutMs,
|
|
17
|
-
});
|
|
18
|
-
const result = await executeWithRetry(async () => {
|
|
19
|
-
if (action === "capabilities") {
|
|
20
|
-
return { ok: true, data: await adapter.capabilities() };
|
|
21
|
-
}
|
|
22
|
-
const { projectId, ...p } = payload;
|
|
23
|
-
if (!projectId)
|
|
24
|
-
throw new Error("projectId required in payload");
|
|
25
|
-
return adapter.execute(projectId, action, p);
|
|
26
|
-
}, env.retries, env.backoffMs);
|
|
27
|
-
console.log(JSON.stringify(result, null, 2));
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
console.error(JSON.stringify({ ok: false, error: safeError(error) }));
|
|
31
|
-
process.exitCode = 1;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
void main();
|
package/src/cli.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
executeWithRetry,
|
|
3
|
-
loadCliEnv,
|
|
4
|
-
parseCliArgs,
|
|
5
|
-
safeError,
|
|
6
|
-
startMcpServer,
|
|
7
|
-
} from "@kalera/munin-runtime";
|
|
8
|
-
import { createOpenClawMuninAdapter } from "./index.js";
|
|
9
|
-
|
|
10
|
-
async function main() {
|
|
11
|
-
try {
|
|
12
|
-
const args = process.argv.slice(2);
|
|
13
|
-
|
|
14
|
-
// If no arguments, or 'mcp' is passed, start as MCP server
|
|
15
|
-
if (args.length === 0 || args[0] === 'mcp') {
|
|
16
|
-
await startMcpServer();
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const { action, payload } = parseCliArgs(
|
|
21
|
-
args,
|
|
22
|
-
"Usage: munin-openclaw <action> [payload-json] OR munin-openclaw mcp",
|
|
23
|
-
);
|
|
24
|
-
const env = loadCliEnv();
|
|
25
|
-
|
|
26
|
-
const adapter = createOpenClawMuninAdapter({
|
|
27
|
-
baseUrl: env.baseUrl,
|
|
28
|
-
apiKey: env.apiKey,
|
|
29
|
-
|
|
30
|
-
timeoutMs: env.timeoutMs,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const result = await executeWithRetry(async () => {
|
|
34
|
-
if (action === "capabilities") {
|
|
35
|
-
return { ok: true, data: await adapter.capabilities() };
|
|
36
|
-
}
|
|
37
|
-
const { projectId, ...p } = payload; if (!projectId) throw new Error("projectId required in payload"); return adapter.execute(projectId as string, action, p);
|
|
38
|
-
}, env.retries, env.backoffMs);
|
|
39
|
-
|
|
40
|
-
console.log(JSON.stringify(result, null, 2));
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.error(JSON.stringify({ ok: false, error: safeError(error) }));
|
|
43
|
-
process.exitCode = 1;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
void main();
|